[automerger skipped] Import translations. DO NOT MERGE ANYWHERE am: 93dd0b3d50 -s ours
am skip reason: subject contains skip directive
Original change: https://android-review.googlesource.com/c/platform/packages/services/Car/+/2326507
Change-Id: I792df395e6068c4ed09ea8329431c8336e1ff8b8
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
diff --git a/PREUPLOAD.cfg b/PREUPLOAD.cfg
index 3da2dc9..889bae6 100644
--- a/PREUPLOAD.cfg
+++ b/PREUPLOAD.cfg
@@ -1,6 +1,7 @@
[Hook Scripts]
checkstyle_hook = ${REPO_ROOT}/prebuilts/checkstyle/checkstyle.py --sha ${PREUPLOAD_COMMIT}
ktlint_hook = ${REPO_ROOT}/prebuilts/ktlint/ktlint.py -f ${PREUPLOAD_FILES}
+overlayable_resource_hook = ${REPO_ROOT}/packages/apps/Car/systemlibs/tools/rro/verify-overlayable.py -r service/res -e service/res/values/overlayable.xml service/res/values/strings.xml service/res/values/attrs.xml service/res/xml/car_volume_groups.xml service/res/drawable/perm_group_car.xml service/res/values-h800dp/dimens.xml service/res/values-h1920dp/dimens.xml -o service/res/values/overlayable.xml -m 'service/res/values/overlayable.xml is not in sync with service/res/values/config.xml. You have added/removed config resources in config.xml. Please update Overlayable.xml so that it is sync with config.xml'
[Builtin Hooks]
commit_msg_changeid_field = true
diff --git a/car-builtin-lib/Android.bp b/car-builtin-lib/Android.bp
index 61f8c76..391855c 100644
--- a/car-builtin-lib/Android.bp
+++ b/car-builtin-lib/Android.bp
@@ -63,6 +63,7 @@
// Only allowed car modules only. Allowed to add tests here.
visibility: [
+ "//external/robolectric-shadows",
"//packages/services/Car/car-lib",
"//packages/services/Car/car-lib-module",
"//packages/services/Car/car-test-lib",
diff --git a/car-builtin-lib/api/module-lib-current.txt b/car-builtin-lib/api/module-lib-current.txt
index 989f3a2..84298ba 100644
--- a/car-builtin-lib/api/module-lib-current.txt
+++ b/car-builtin-lib/api/module-lib-current.txt
@@ -11,6 +11,16 @@
}
+package android.car.builtin.annotation {
+
+ public enum PlatformVersion {
+ enum_constant public static final android.car.builtin.annotation.PlatformVersion TIRAMISU_0;
+ enum_constant public static final android.car.builtin.annotation.PlatformVersion TIRAMISU_1;
+ enum_constant public static final android.car.builtin.annotation.PlatformVersion UPSIDE_DOWN_CAKE_0;
+ }
+
+}
+
package android.car.builtin.app {
public final class ActivityManagerHelper {
@@ -62,6 +72,32 @@
}
+package android.car.builtin.bluetooth.le {
+
+ public final class AdvertisingSetCallbackHelper {
+ method public static android.bluetooth.le.AdvertisingSetCallback createRealCallbackFromProxy(@NonNull android.car.builtin.bluetooth.le.AdvertisingSetCallbackHelper.Callback);
+ }
+
+ public abstract static class AdvertisingSetCallbackHelper.Callback {
+ ctor public AdvertisingSetCallbackHelper.Callback();
+ method public void onAdvertisingDataSet(android.bluetooth.le.AdvertisingSet, int);
+ method public void onAdvertisingEnabled(android.bluetooth.le.AdvertisingSet, boolean, int);
+ method public void onAdvertisingParametersUpdated(android.bluetooth.le.AdvertisingSet, int, int);
+ method public void onAdvertisingSetStarted(android.bluetooth.le.AdvertisingSet, int, int);
+ method public void onAdvertisingSetStopped(android.bluetooth.le.AdvertisingSet);
+ method public void onOwnAddressRead(android.bluetooth.le.AdvertisingSet, int, String);
+ method public void onPeriodicAdvertisingDataSet(android.bluetooth.le.AdvertisingSet, int);
+ method public void onPeriodicAdvertisingEnabled(android.bluetooth.le.AdvertisingSet, boolean, int);
+ method public void onPeriodicAdvertisingParametersUpdated(android.bluetooth.le.AdvertisingSet, int);
+ method public void onScanResponseDataSet(android.bluetooth.le.AdvertisingSet, int);
+ }
+
+ public final class AdvertisingSetHelper {
+ method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_ADVERTISE, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public static void getOwnAddress(@NonNull android.bluetooth.le.AdvertisingSet);
+ }
+
+}
+
package android.car.builtin.content {
public final class ContextHelper {
diff --git a/car-builtin-lib/src/android/car/builtin/CarBuiltin.java b/car-builtin-lib/src/android/car/builtin/CarBuiltin.java
index a45a40b..a0b2119 100644
--- a/car-builtin-lib/src/android/car/builtin/CarBuiltin.java
+++ b/car-builtin-lib/src/android/car/builtin/CarBuiltin.java
@@ -17,6 +17,8 @@
package android.car.builtin;
import android.annotation.SystemApi;
+import android.car.builtin.annotation.AddedIn;
+import android.car.builtin.annotation.PlatformVersion;
import android.os.SystemProperties;
/**
@@ -44,6 +46,7 @@
* the same {@link android.os.Build.VERSION#SDK_INT}. Client should check this version to use
* APIs which were added in a minor only version update.
*/
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static final int PLATFORM_VERSION_MINOR_INT = SystemProperties.getInt(
PROPERTY_PLATFORM_MINOR_VERSION, /* def= */ 0);
diff --git a/car-builtin-lib/src/android/car/builtin/PermissionHelper.java b/car-builtin-lib/src/android/car/builtin/PermissionHelper.java
index 6139ea5..b2dd553 100644
--- a/car-builtin-lib/src/android/car/builtin/PermissionHelper.java
+++ b/car-builtin-lib/src/android/car/builtin/PermissionHelper.java
@@ -17,6 +17,8 @@
package android.car.builtin;
import android.annotation.SystemApi;
+import android.car.builtin.annotation.AddedIn;
+import android.car.builtin.annotation.PlatformVersion;
/**
* Helper for Permissions
@@ -30,5 +32,6 @@
}
/** MONITOR_INPUT permission */
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static final String MONITOR_INPUT = android.Manifest.permission.MONITOR_INPUT;
}
diff --git a/car-builtin-lib/src/android/car/builtin/annotation/AddedIn.java b/car-builtin-lib/src/android/car/builtin/annotation/AddedIn.java
new file mode 100644
index 0000000..2a44a5a
--- /dev/null
+++ b/car-builtin-lib/src/android/car/builtin/annotation/AddedIn.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2022 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.builtin.annotation;
+
+import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.ElementType.TYPE;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+/**
+ * Defines in which version of platform this method / type / field was added.
+ *
+ * <p>Annotation should be used for APIs exposed to CarService module by {@code android.car.builtin}
+ *
+ * @hide
+ */
+@Retention(RUNTIME)
+@Target({ANNOTATION_TYPE, FIELD, TYPE, METHOD})
+public @interface AddedIn {
+ PlatformVersion value();
+}
diff --git a/car-builtin-lib/src/android/car/builtin/annotation/PlatformVersion.java b/car-builtin-lib/src/android/car/builtin/annotation/PlatformVersion.java
new file mode 100644
index 0000000..74bfd2b
--- /dev/null
+++ b/car-builtin-lib/src/android/car/builtin/annotation/PlatformVersion.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2022 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.builtin.annotation;
+
+import android.annotation.SystemApi;
+
+/**
+ * Platform version values to be used by {@code android.car.builtin} and
+ * {@code car-frameworks-service}
+ *
+ * @hide
+ */
+@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+@SuppressWarnings("Enum")
+public enum PlatformVersion {
+ TIRAMISU_0,
+ TIRAMISU_1,
+ UPSIDE_DOWN_CAKE_0,
+}
diff --git a/car-builtin-lib/src/android/car/builtin/app/ActivityManagerHelper.java b/car-builtin-lib/src/android/car/builtin/app/ActivityManagerHelper.java
index dc0da3c..b6dea62 100644
--- a/car-builtin-lib/src/android/car/builtin/app/ActivityManagerHelper.java
+++ b/car-builtin-lib/src/android/car/builtin/app/ActivityManagerHelper.java
@@ -25,6 +25,8 @@
import android.app.ActivityTaskManager.RootTaskInfo;
import android.app.IActivityManager;
import android.app.IProcessObserver;
+import android.car.builtin.annotation.AddedIn;
+import android.car.builtin.annotation.PlatformVersion;
import android.car.builtin.util.Slogf;
import android.os.Bundle;
import android.os.RemoteException;
@@ -39,6 +41,7 @@
public final class ActivityManagerHelper {
/** Invalid task ID. */
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static final int INVALID_TASK_ID = ActivityTaskManager.INVALID_TASK_ID;
private static final String TAG = "CAR.AM"; // CarLog.TAG_AM
@@ -61,6 +64,7 @@
*
* @throws IllegalStateException if ActivityManager binder throws RemoteException
*/
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static boolean startUserInBackground(@UserIdInt int userId) {
return runRemotely(() -> getActivityManager().startUserInBackground(userId),
"error while startUserInBackground %d", userId);
@@ -71,6 +75,7 @@
*
* @throws IllegalStateException if ActivityManager binder throws RemoteException
*/
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static boolean startUserInForeground(@UserIdInt int userId) {
return runRemotely(
() -> getActivityManager().startUserInForegroundWithListener(
@@ -83,6 +88,7 @@
*
* @throws IllegalStateException if ActivityManager binder throws RemoteException
*/
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static int stopUserWithDelayedLocking(@UserIdInt int userId, boolean force) {
return runRemotely(
() -> getActivityManager().stopUserWithDelayedLocking(
@@ -95,6 +101,7 @@
*
* @throws IllegalStateException if ActivityManager binder throws RemoteException
*/
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static boolean unlockUser(@UserIdInt int userId) {
return runRemotely(() -> getActivityManager().unlockUser(userId,
/* token= */ null, /* secret= */ null, /* listener= */ null),
@@ -106,6 +113,7 @@
*
* @throws IllegalStateException if ActivityManager binder throws RemoteException
*/
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static void stopAllTasksForUser(@UserIdInt int userId) {
try {
IActivityManager am = getActivityManager();
@@ -128,6 +136,7 @@
* Creates an ActivityOptions from the Bundle generated from ActivityOptions.
*/
@NonNull
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static ActivityOptions createActivityOptions(@NonNull Bundle bOptions) {
return new ActivityOptions(bOptions);
}
@@ -150,6 +159,7 @@
/**
* Makes the root task of the given taskId focused.
*/
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static void setFocusedRootTask(int taskId) {
try {
getActivityManager().setFocusedRootTask(taskId);
@@ -161,6 +171,7 @@
/**
* Removes the given task.
*/
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static boolean removeTask(int taskId) {
try {
return getActivityManager().removeTask(taskId);
@@ -175,11 +186,14 @@
*/
public abstract static class ProcessObserverCallback {
/** Called when the foreground Activities are changed. */
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public void onForegroundActivitiesChanged(int pid, int uid, boolean foregroundActivities) {
}
/** Called when the Process is died. */
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public void onProcessDied(int pid, int uid) {}
+ @AddedIn(PlatformVersion.TIRAMISU_0)
final IProcessObserver.Stub mIProcessObserver = new IProcessObserver.Stub() {
@Override
public void onForegroundActivitiesChanged(
@@ -205,6 +219,7 @@
* Registers a callback to be invoked when the process states are changed.
* @param callback a callback to register
*/
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static void registerProcessObserverCallback(ProcessObserverCallback callback) {
try {
getActivityManager().registerProcessObserver(callback.mIProcessObserver);
@@ -218,6 +233,7 @@
* Unregisters the given callback.
* @param callback a callback to unregister
*/
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static void unregisterProcessObserverCallback(ProcessObserverCallback callback) {
try {
getActivityManager().unregisterProcessObserver(callback.mIProcessObserver);
@@ -230,6 +246,7 @@
/**
* Same as {@link ActivityManager#checkComponentPermission(String, int, int, boolean).
*/
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static int checkComponentPermission(@NonNull String permission, int uid, int owningUid,
boolean exported) {
return ActivityManager.checkComponentPermission(permission, uid, owningUid, exported);
diff --git a/car-builtin-lib/src/android/car/builtin/app/KeyguardManagerHelper.java b/car-builtin-lib/src/android/car/builtin/app/KeyguardManagerHelper.java
index 4065933..5ecd6db 100644
--- a/car-builtin-lib/src/android/car/builtin/app/KeyguardManagerHelper.java
+++ b/car-builtin-lib/src/android/car/builtin/app/KeyguardManagerHelper.java
@@ -17,6 +17,8 @@
package android.car.builtin.app;
import android.annotation.SystemApi;
+import android.car.builtin.annotation.AddedIn;
+import android.car.builtin.annotation.PlatformVersion;
import android.car.builtin.util.Slogf;
import android.os.RemoteException;
import android.view.WindowManagerGlobal;
@@ -38,6 +40,7 @@
*
* @return {@code true} if keyguard is locked.
*/
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static boolean isKeyguardLocked() {
boolean locked = true;
try {
diff --git a/car-builtin-lib/src/android/car/builtin/app/TaskInfoHelper.java b/car-builtin-lib/src/android/car/builtin/app/TaskInfoHelper.java
index a1cb92e..5f8cabe 100644
--- a/car-builtin-lib/src/android/car/builtin/app/TaskInfoHelper.java
+++ b/car-builtin-lib/src/android/car/builtin/app/TaskInfoHelper.java
@@ -20,6 +20,8 @@
import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.app.TaskInfo;
+import android.car.builtin.annotation.AddedIn;
+import android.car.builtin.annotation.PlatformVersion;
/**
* Provides the access to the hidden fields of {@code android.app.TaskInfo}.
@@ -29,21 +31,25 @@
public class TaskInfoHelper {
/** Gets the id of the display this task is associated with. */
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static int getDisplayId(@NonNull TaskInfo task) {
return task.displayId;
}
/** Gets the id of the user the task was running as if this is a leaf task. */
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static int getUserId(@NonNull TaskInfo task) {
return task.userId;
}
/** Returns whether the task is actually visible or not */
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static boolean isVisible(@NonNull TaskInfo task) {
return task.isVisible && task.isRunning && !task.isSleeping;
}
/** Returns the string representation of the task */
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static String toString(@Nullable TaskInfo task) {
if (task == null) {
return "null";
diff --git a/car-builtin-lib/src/android/car/builtin/app/VoiceInteractionHelper.java b/car-builtin-lib/src/android/car/builtin/app/VoiceInteractionHelper.java
index 947d3c9..053654c 100644
--- a/car-builtin-lib/src/android/car/builtin/app/VoiceInteractionHelper.java
+++ b/car-builtin-lib/src/android/car/builtin/app/VoiceInteractionHelper.java
@@ -17,6 +17,8 @@
package android.car.builtin.app;
import android.annotation.SystemApi;
+import android.car.builtin.annotation.AddedIn;
+import android.car.builtin.annotation.PlatformVersion;
import android.car.builtin.os.ServiceManagerHelper;
import android.content.Context;
import android.os.RemoteException;
@@ -32,6 +34,7 @@
public final class VoiceInteractionHelper {
/** Checks if ${link VoiceInteractionManagerService} is available. */
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static boolean isAvailable() {
return getService() != null;
}
@@ -41,6 +44,7 @@
*
* @param enabled Whether to enable or disable voice interaction.
*/
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static void setEnabled(boolean enabled) throws RemoteException {
IVoiceInteractionManagerService service = getService();
if (service == null) {
diff --git a/car-builtin-lib/src/android/car/builtin/bluetooth/BluetoothHeadsetClientHelper.java b/car-builtin-lib/src/android/car/builtin/bluetooth/BluetoothHeadsetClientHelper.java
index 2ea8079..464e474 100644
--- a/car-builtin-lib/src/android/car/builtin/bluetooth/BluetoothHeadsetClientHelper.java
+++ b/car-builtin-lib/src/android/car/builtin/bluetooth/BluetoothHeadsetClientHelper.java
@@ -20,6 +20,8 @@
import android.annotation.SystemApi;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothHeadsetClient;
+import android.car.builtin.annotation.AddedIn;
+import android.car.builtin.annotation.PlatformVersion;
import android.os.Bundle;
import java.util.ArrayList;
@@ -44,6 +46,7 @@
* @param headsetClient Proxy object for controlling the Bluetooth HFP Client service.
* @return a list of connected devices that support BVRA.
*/
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static List<BluetoothDevice> getConnectedBvraDevices(
@NonNull BluetoothHeadsetClient headsetClient) {
List<BluetoothDevice> devices = headsetClient.getConnectedDevices();
@@ -66,6 +69,7 @@
* @param device The connected device whose voice recognition will be started.
* @return {@code true} if the command has been issued successfully; {@code false} otherwise.
*/
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static boolean startVoiceRecognition(@NonNull BluetoothHeadsetClient headsetClient,
BluetoothDevice device) {
return headsetClient.startVoiceRecognition(device);
@@ -78,6 +82,7 @@
* @param device The connected device whose voice recognition will be stopped.
* @return {@code true} if the command has been issued successfully; {@code false} otherwise.
*/
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static boolean stopVoiceRecognition(@NonNull BluetoothHeadsetClient headsetClient,
BluetoothDevice device) {
return headsetClient.stopVoiceRecognition(device);
diff --git a/car-builtin-lib/src/android/car/builtin/bluetooth/le/AdvertisingSetCallbackHelper.java b/car-builtin-lib/src/android/car/builtin/bluetooth/le/AdvertisingSetCallbackHelper.java
new file mode 100644
index 0000000..9ed4cf4
--- /dev/null
+++ b/car-builtin-lib/src/android/car/builtin/bluetooth/le/AdvertisingSetCallbackHelper.java
@@ -0,0 +1,242 @@
+/*
+ * Copyright (C) 2022 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.builtin.bluetooth.le;
+
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.bluetooth.le.AdvertisingSet;
+import android.bluetooth.le.AdvertisingSetCallback;
+import android.car.builtin.annotation.AddedIn;
+import android.car.builtin.annotation.PlatformVersion;
+
+/**
+ * Provides access to {@code onOwnAddressRead} in
+ * {@code android.bluetooth.le.AdvertisingSetCallback}.
+ * @hide
+ */
+@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+public final class AdvertisingSetCallbackHelper {
+
+ /**
+ * A proxy to {@code android.bluetooth.le.AdvertisingSetCallback}, since one of its methods
+ * is a hidden API. {@code AdvertisingSetCallback} is the Bluetooth LE advertising set
+ * callbacks, used to deliver advertising operation status.
+ */
+ public abstract static class Callback {
+
+ /**
+ * Callback triggered in response to {@link BluetoothLeAdvertiser#startAdvertisingSet}
+ * indicating result of the operation. If status is ADVERTISE_SUCCESS, then advertisingSet
+ * contains the started set and it is advertising. If error occurred, advertisingSet is
+ * null, and status will be set to proper error code.
+ *
+ * @param advertisingSet The advertising set that was started or null if error.
+ * @param txPower tx power that will be used for this set.
+ * @param status Status of the operation.
+ */
+ @AddedIn(PlatformVersion.TIRAMISU_1)
+ public void onAdvertisingSetStarted(AdvertisingSet advertisingSet, int txPower,
+ int status) {
+ }
+
+ /**
+ * Callback triggered in response to {@link BluetoothLeAdvertiser#stopAdvertisingSet}
+ * indicating advertising set is stopped.
+ *
+ * @param advertisingSet The advertising set.
+ */
+ @AddedIn(PlatformVersion.TIRAMISU_1)
+ public void onAdvertisingSetStopped(AdvertisingSet advertisingSet) {
+ }
+
+ /**
+ * Callback triggered in response to {@link BluetoothLeAdvertiser#startAdvertisingSet}
+ * indicating result of the operation. If status is ADVERTISE_SUCCESS, then advertising
+ * set is advertising.
+ *
+ * @param advertisingSet The advertising set.
+ * @param status Status of the operation.
+ */
+ @AddedIn(PlatformVersion.TIRAMISU_1)
+ public void onAdvertisingEnabled(AdvertisingSet advertisingSet, boolean enable,
+ int status) {
+ }
+
+ /**
+ * Callback triggered in response to {@link AdvertisingSet#setAdvertisingData} indicating
+ * result of the operation. If status is ADVERTISE_SUCCESS, then data was changed.
+ *
+ * @param advertisingSet The advertising set.
+ * @param status Status of the operation.
+ */
+ @AddedIn(PlatformVersion.TIRAMISU_1)
+ public void onAdvertisingDataSet(AdvertisingSet advertisingSet, int status) {
+ }
+
+ /**
+ * Callback triggered in response to {@link AdvertisingSet#setAdvertisingData} indicating
+ * result of the operation.
+ *
+ * @param advertisingSet The advertising set.
+ * @param status Status of the operation.
+ */
+ @AddedIn(PlatformVersion.TIRAMISU_1)
+ public void onScanResponseDataSet(AdvertisingSet advertisingSet, int status) {
+ }
+
+ /**
+ * Callback triggered in response to {@link AdvertisingSet#setAdvertisingParameters}
+ * indicating result of the operation.
+ *
+ * @param advertisingSet The advertising set.
+ * @param txPower tx power that will be used for this set.
+ * @param status Status of the operation.
+ */
+ @AddedIn(PlatformVersion.TIRAMISU_1)
+ public void onAdvertisingParametersUpdated(AdvertisingSet advertisingSet,
+ int txPower, int status) {
+ }
+
+ /**
+ * Callback triggered in response to {@link
+ * AdvertisingSet#setPeriodicAdvertisingParameters} indicating result of the operation.
+ *
+ * @param advertisingSet The advertising set.
+ * @param status Status of the operation.
+ */
+ @AddedIn(PlatformVersion.TIRAMISU_1)
+ public void onPeriodicAdvertisingParametersUpdated(AdvertisingSet advertisingSet,
+ int status) {
+ }
+
+ /**
+ * Callback triggered in response to {@link AdvertisingSet#setPeriodicAdvertisingData}
+ * indicating result of the operation.
+ *
+ * @param advertisingSet The advertising set.
+ * @param status Status of the operation.
+ */
+ @AddedIn(PlatformVersion.TIRAMISU_1)
+ public void onPeriodicAdvertisingDataSet(AdvertisingSet advertisingSet,
+ int status) {
+ }
+
+ /**
+ * Callback triggered in response to {@link AdvertisingSet#setPeriodicAdvertisingEnabled}
+ * indicating result of the operation.
+ *
+ * @param advertisingSet The advertising set.
+ * @param status Status of the operation.
+ */
+ @AddedIn(PlatformVersion.TIRAMISU_1)
+ public void onPeriodicAdvertisingEnabled(AdvertisingSet advertisingSet, boolean enable,
+ int status) {
+ }
+
+ /**
+ * Callback triggered in response to {@link AdvertisingSet#getOwnAddress()}
+ * indicating result of the operation. (In the real callback, this was hidden API).
+ *
+ * @param advertisingSet The advertising set.
+ * @param addressType type of address.
+ * @param address advertising set bluetooth address.
+ */
+ @AddedIn(PlatformVersion.TIRAMISU_1)
+ public void onOwnAddressRead(AdvertisingSet advertisingSet, int addressType,
+ String address) {
+ }
+ }
+
+ private AdvertisingSetCallbackHelper() {
+ throw new UnsupportedOperationException("contains only static members");
+ }
+
+ /**
+ * Creates a real {@link AdvertisingSetCallback} by wrapping a {@link Callback}.
+ * Wrapping is needed because some of the methods in {@link AdvertisingSetCallback} are
+ * hidden APIs, so cannot be overridden within a Mainline module.
+ *
+ * @param proxy The proxy of {@link AdvertisingSetCallback} that is to be wrapped into a
+ * real one.
+ * @return A real {@link AdvertisingSetCallback}.
+ */
+ @AddedIn(PlatformVersion.TIRAMISU_1)
+ public static AdvertisingSetCallback createRealCallbackFromProxy(
+ @NonNull Callback proxy) {
+
+ AdvertisingSetCallback realCallback = new AdvertisingSetCallback() {
+ @Override
+ public void onAdvertisingSetStarted(AdvertisingSet advertisingSet, int txPower,
+ int status) {
+ proxy.onAdvertisingSetStarted(advertisingSet, txPower, status);
+ }
+
+ @Override
+ public void onAdvertisingSetStopped(AdvertisingSet advertisingSet) {
+ proxy.onAdvertisingSetStopped(advertisingSet);
+ }
+
+ @Override
+ public void onAdvertisingEnabled(AdvertisingSet advertisingSet, boolean enable,
+ int status) {
+ proxy.onAdvertisingEnabled(advertisingSet, enable, status);
+ }
+
+ @Override
+ public void onAdvertisingDataSet(AdvertisingSet advertisingSet, int status) {
+ proxy.onAdvertisingDataSet(advertisingSet, status);
+ }
+
+ @Override
+ public void onScanResponseDataSet(AdvertisingSet advertisingSet, int status) {
+ proxy.onScanResponseDataSet(advertisingSet, status);
+ }
+
+ @Override
+ public void onAdvertisingParametersUpdated(AdvertisingSet advertisingSet,
+ int txPower, int status) {
+ proxy.onAdvertisingParametersUpdated(advertisingSet, txPower, status);
+ }
+
+ @Override
+ public void onPeriodicAdvertisingParametersUpdated(AdvertisingSet advertisingSet,
+ int status) {
+ proxy.onPeriodicAdvertisingParametersUpdated(advertisingSet, status);
+ }
+
+ @Override
+ public void onPeriodicAdvertisingDataSet(AdvertisingSet advertisingSet,
+ int status) {
+ proxy.onPeriodicAdvertisingDataSet(advertisingSet, status);
+ }
+
+ @Override
+ public void onPeriodicAdvertisingEnabled(AdvertisingSet advertisingSet, boolean enable,
+ int status) {
+ proxy.onPeriodicAdvertisingEnabled(advertisingSet, enable, status);
+ }
+
+ @Override
+ public void onOwnAddressRead(AdvertisingSet advertisingSet, int addressType,
+ String address) {
+ proxy.onOwnAddressRead(advertisingSet, addressType, address);
+ }
+ };
+
+ return realCallback;
+ }
+}
diff --git a/car-builtin-lib/src/android/car/builtin/bluetooth/le/AdvertisingSetHelper.java b/car-builtin-lib/src/android/car/builtin/bluetooth/le/AdvertisingSetHelper.java
new file mode 100644
index 0000000..2a4ffd1
--- /dev/null
+++ b/car-builtin-lib/src/android/car/builtin/bluetooth/le/AdvertisingSetHelper.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2022 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.builtin.bluetooth.le;
+
+import android.annotation.NonNull;
+import android.annotation.RequiresPermission;
+import android.annotation.SystemApi;
+import android.bluetooth.annotations.RequiresBluetoothAdvertisePermission;
+import android.bluetooth.le.AdvertisingSet;
+import android.car.builtin.annotation.AddedIn;
+import android.car.builtin.annotation.PlatformVersion;
+
+/**
+ * Provides access to hidden API {@code getOwnAddress()} in
+ * {@code android.bluetooth.le.AdvertisingSet}.
+ * @hide
+ */
+@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+public final class AdvertisingSetHelper {
+
+ private AdvertisingSetHelper() {
+ throw new UnsupportedOperationException("contains only static members");
+ }
+
+ /**
+ * Returns address associated with the provided advertising set.
+ *
+ * @param advertisingSet The advertising set.
+ */
+ @RequiresBluetoothAdvertisePermission
+ @RequiresPermission(allOf = {
+ android.Manifest.permission.BLUETOOTH_ADVERTISE,
+ android.Manifest.permission.BLUETOOTH_PRIVILEGED,
+ })
+ @AddedIn(PlatformVersion.TIRAMISU_1)
+ public static void getOwnAddress(@NonNull AdvertisingSet advertisingSet) {
+ advertisingSet.getOwnAddress();
+ }
+}
diff --git a/car-builtin-lib/src/android/car/builtin/content/ContextHelper.java b/car-builtin-lib/src/android/car/builtin/content/ContextHelper.java
index 14a8136..0e043c5 100644
--- a/car-builtin-lib/src/android/car/builtin/content/ContextHelper.java
+++ b/car-builtin-lib/src/android/car/builtin/content/ContextHelper.java
@@ -20,6 +20,8 @@
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
+import android.car.builtin.annotation.AddedIn;
+import android.car.builtin.annotation.PlatformVersion;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
@@ -39,6 +41,7 @@
}
/** Returns display id relevant for the context */
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static int getDisplayId(@NonNull Context context) {
return context.getDisplayId();
}
@@ -47,6 +50,7 @@
* Same as {@code context.startActivityAsUser(intent, options, user)}.
*/
@RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS)
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static void startActivityAsUser(@NonNull Context context, @NonNull Intent intent,
@Nullable Bundle options, @NonNull UserHandle user) {
Objects.requireNonNull(context, "context");
diff --git a/car-builtin-lib/src/android/car/builtin/content/pm/PackageManagerHelper.java b/car-builtin-lib/src/android/car/builtin/content/pm/PackageManagerHelper.java
index 873399d..a38230f 100644
--- a/car-builtin-lib/src/android/car/builtin/content/pm/PackageManagerHelper.java
+++ b/car-builtin-lib/src/android/car/builtin/content/pm/PackageManagerHelper.java
@@ -21,6 +21,8 @@
import android.annotation.SystemApi;
import android.annotation.UserIdInt;
import android.app.ActivityThread;
+import android.car.builtin.annotation.AddedIn;
+import android.car.builtin.annotation.PlatformVersion;
import android.content.ComponentName;
import android.content.Context;
import android.content.pm.ApplicationInfo;
@@ -47,6 +49,7 @@
* car service created from AOSP build. It can be set to the different package name depending on
* who is signing the car framework apex module.
*/
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static final String PROPERTY_CAR_SERVICE_PACKAGE_NAME =
"ro.android.car.carservice.package";
@@ -59,6 +62,7 @@
* all RROs to cover different {@code CarServiceUpdatable} package names but only those
* overriding the current {@code CarServiceUpdatable} package name will be selected.
*/
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static final String PROPERTY_CAR_SERVICE_OVERLAY_PACKAGES =
"ro.android.car.carservice.overlay.packages";
@@ -72,6 +76,7 @@
* @return
*/
@NonNull
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static String getSystemUiPackageName(@NonNull Context context) {
// TODO(157082995): This information can be taken from
// PackageManageInternalImpl.getSystemUiServiceComponent()
@@ -92,6 +97,7 @@
}
/** Check {@link PackageManager#getPackageInfoAsUser(String, int, int)}. */
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static PackageInfo getPackageInfoAsUser(@NonNull PackageManager pm,
@NonNull String packageName, int packageInfoFlags,
@UserIdInt int userId) throws PackageManager.NameNotFoundException {
@@ -99,6 +105,7 @@
}
/** Check {@link PackageManager#getPackageUidAsUser(String, int)}. */
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static int getPackageUidAsUser(@NonNull PackageManager pm, @NonNull String packageName,
@UserIdInt int userId) throws PackageManager.NameNotFoundException {
return pm.getPackageUidAsUser(packageName, userId);
@@ -106,11 +113,13 @@
/** Check {@link PackageManager#getNamesForUids(int[])}. */
@Nullable
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static String[] getNamesForUids(@NonNull PackageManager pm, int[] uids) {
return pm.getNamesForUids(uids);
}
/** Check {@link PackageManager#getApplicationEnabledSetting(String)}. */
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static int getApplicationEnabledSettingForUser(@NonNull String packageName,
@UserIdInt int userId) throws RemoteException {
IPackageManager pm = ActivityThread.getPackageManager();
@@ -118,6 +127,7 @@
}
/** Check {@link PackageManager#setApplicationEnabledSetting(String, int, int)}. */
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static void setApplicationEnabledSettingForUser(@NonNull String packageName,
@PackageManager.EnabledState int newState, @PackageManager.EnabledFlags int flags,
@UserIdInt int userId, @NonNull String callingPackage) throws RemoteException {
@@ -126,41 +136,49 @@
}
/** Tells if the passed app is OEM app or not. */
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static boolean isOemApp(@NonNull ApplicationInfo appInfo) {
return (appInfo.privateFlags & ApplicationInfo.PRIVATE_FLAG_OEM) != 0;
}
/** Tells if the passed app is ODM app or not. */
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static boolean isOdmApp(@NonNull ApplicationInfo appInfo) {
return (appInfo.privateFlags & ApplicationInfo.PRIVATE_FLAG_ODM) != 0;
}
/** Tells if the passed app is vendor app or not. */
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static boolean isVendorApp(@NonNull ApplicationInfo appInfo) {
return (appInfo.privateFlags & ApplicationInfo.PRIVATE_FLAG_VENDOR) != 0;
}
/** Tells if the passed app is system app or not. */
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static boolean isSystemApp(@NonNull ApplicationInfo appInfo) {
return (appInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0;
}
/** Tells if the passed app is updated system app or not. */
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static boolean isUpdatedSystemApp(@NonNull ApplicationInfo appInfo) {
return (appInfo.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0;
}
/** Tells if the passed app is product app or not. */
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static boolean isProductApp(@NonNull ApplicationInfo appInfo) {
return (appInfo.privateFlags & ApplicationInfo.PRIVATE_FLAG_PRODUCT) != 0;
}
/** Tells if the passed app is system ext vendor app or not. */
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static boolean isSystemExtApp(@NonNull ApplicationInfo appInfo) {
return (appInfo.privateFlags & ApplicationInfo.PRIVATE_FLAG_SYSTEM_EXT) != 0;
}
/** Check {@link ComponentInfo#getComponentName()}. */
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static ComponentName getComponentName(ComponentInfo info) {
return info.getComponentName();
}
diff --git a/car-builtin-lib/src/android/car/builtin/input/InputManagerHelper.java b/car-builtin-lib/src/android/car/builtin/input/InputManagerHelper.java
index 2b5d7bb..97a6105 100644
--- a/car-builtin-lib/src/android/car/builtin/input/InputManagerHelper.java
+++ b/car-builtin-lib/src/android/car/builtin/input/InputManagerHelper.java
@@ -18,6 +18,8 @@
import android.annotation.NonNull;
import android.annotation.SystemApi;
+import android.car.builtin.annotation.AddedIn;
+import android.car.builtin.annotation.PlatformVersion;
import android.hardware.input.InputManager;
/**
@@ -39,6 +41,7 @@
* @param event the event to inject
* @return {@code true} if injection succeeds
*/
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static boolean injectInputEvent(@NonNull InputManager inputManager,
@NonNull android.view.InputEvent event) {
return inputManager.injectInputEvent(event, InputManager.INJECT_INPUT_EVENT_MODE_ASYNC);
diff --git a/car-builtin-lib/src/android/car/builtin/job/JobSchedulerHelper.java b/car-builtin-lib/src/android/car/builtin/job/JobSchedulerHelper.java
index 7330877..ee5021d 100644
--- a/car-builtin-lib/src/android/car/builtin/job/JobSchedulerHelper.java
+++ b/car-builtin-lib/src/android/car/builtin/job/JobSchedulerHelper.java
@@ -20,6 +20,8 @@
import android.app.job.JobInfo;
import android.app.job.JobScheduler;
import android.app.job.JobSnapshot;
+import android.car.builtin.annotation.AddedIn;
+import android.car.builtin.annotation.PlatformVersion;
import android.content.Context;
import java.util.List;
@@ -37,6 +39,7 @@
}
/** Gets the number of running jobs which are executed when a device goes idle. */
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static int getNumberOfRunningJobsAtIdle(Context context) {
List<JobInfo> startedJobs = context.getSystemService(JobScheduler.class).getStartedJobs();
if (startedJobs == null) {
@@ -53,6 +56,7 @@
}
/** Gets the number of jobs which are scheduled for execution at idle but not finished. */
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static int getNumberOfPendingJobs(Context context) {
List<JobSnapshot> allScheduledJobs =
context.getSystemService(JobScheduler.class).getAllJobSnapshots();
diff --git a/car-builtin-lib/src/android/car/builtin/media/AudioManagerHelper.java b/car-builtin-lib/src/android/car/builtin/media/AudioManagerHelper.java
index 1e32455..c4c5583 100644
--- a/car-builtin-lib/src/android/car/builtin/media/AudioManagerHelper.java
+++ b/car-builtin-lib/src/android/car/builtin/media/AudioManagerHelper.java
@@ -25,6 +25,8 @@
import android.annotation.NonNull;
import android.annotation.SystemApi;
+import android.car.builtin.annotation.AddedIn;
+import android.car.builtin.annotation.PlatformVersion;
import android.car.builtin.util.Slogf;
import android.content.BroadcastReceiver;
import android.content.Context;
@@ -47,7 +49,6 @@
import java.util.ArrayList;
import java.util.Objects;
-
/**
* Helper for Audio related operations.
*
@@ -56,6 +57,7 @@
@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
public final class AudioManagerHelper {
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static final int UNDEFINED_STREAM_TYPE = -1;
private static final String TAG = "AudioServiceHelper";
@@ -71,6 +73,7 @@
* @param isOutput is the device an output device
* @return true if the gain was successfully set
*/
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static boolean setAudioDeviceGain(@NonNull AudioManager audioManager,
@NonNull String address, int gainInMillibels, boolean isOutput) {
Preconditions.checkNotNull(audioManager,
@@ -153,6 +156,7 @@
* @param deviceInfo
* @return
*/
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static AudioGainInfo getAudioGainInfo(@NonNull AudioDeviceInfo deviceInfo) {
Objects.requireNonNull(deviceInfo);
return new AudioGainInfo(getAudioGain(deviceInfo.getPort()));
@@ -165,6 +169,7 @@
* @param gainInMillibels gain to apply to the source device
* @return The audio patch information that was created
*/
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static AudioPatchInfo createAudioPatch(@NonNull AudioDeviceInfo sourceDevice,
@NonNull AudioDeviceInfo sinkDevice, int gainInMillibels) {
Preconditions.checkNotNull(sourceDevice,
@@ -232,6 +237,7 @@
* @param info patch information to release
* @return returns true if the patch was successfully removed
*/
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static boolean releaseAudioPatch(@NonNull AudioManager audioManager,
@NonNull AudioPatchInfo info) {
Preconditions.checkNotNull(audioManager,
@@ -265,6 +271,7 @@
*
* <p>See {@link android.media.AudioAttributes.usageToString}.
*/
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static String usageToString(@AttributeUsage int usage) {
return AudioAttributes.usageToString(usage);
}
@@ -275,6 +282,7 @@
*
* <p>See {@link android.media.AudioAttributes.usageToXsdString}.
*/
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static String usageToXsdString(@AttributeUsage int usage) {
return AudioAttributes.usageToXsdString(usage);
}
@@ -285,6 +293,7 @@
*
* <p>See {@link android.media.AudioAttributes.xsdStringToUsage}.
*/
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static int xsdStringToUsage(String usage) {
return AudioAttributes.xsdStringToUsage(usage);
}
@@ -293,6 +302,7 @@
* Returns {@link android.media.AudioAttributes.AttributeUsage} for
* {@link android.media.AudioAttributes.AttributeUsage.USAGE_VIRTUAL_SOURCE}.
*/
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static int getUsageVirtualSource() {
return USAGE_VIRTUAL_SOURCE;
}
@@ -302,6 +312,7 @@
*
* <p>See {@link android.media.AudioManager#adjustToString(int)}
*/
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static String adjustToString(int adjustment) {
return AudioManager.adjustToString(adjustment);
}
@@ -311,6 +322,7 @@
*
* <p>See {@link android.media.AudioManager#setMasterMute(boolean, int)}.
*/
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static void setMasterMute(@NonNull AudioManager audioManager, boolean mute, int flags) {
Objects.requireNonNull(audioManager, "AudioManager must not be null.");
audioManager.setMasterMute(mute, flags);
@@ -321,6 +333,7 @@
*
* <p>See {@link android.media.AudioManager#isMasterMute()}.
*/
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static boolean isMasterMute(@NonNull AudioManager audioManager) {
Objects.requireNonNull(audioManager, "AudioManager must not be null.");
return audioManager.isMasterMute();
@@ -329,6 +342,7 @@
/**
* Registers volume and mute receiver
*/
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static void registerVolumeAndMuteReceiver(Context context,
VolumeAndMuteReceiver audioAndMuteHelper) {
Objects.requireNonNull(context, "Context can not be null.");
@@ -344,6 +358,7 @@
/**
* Unregisters volume and mute receiver
*/
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static void unregisterVolumeAndMuteReceiver(Context context,
VolumeAndMuteReceiver audioAndMuteHelper) {
Objects.requireNonNull(context, "Context can not be null.");
@@ -355,6 +370,7 @@
/**
* Checks if the client id is equal to the telephony's focus client id.
*/
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static boolean isCallFocusRequestClientId(String clientId) {
return AudioSystem.IN_VOICE_COMM_FOCUS_ID.equals(clientId);
}
@@ -378,18 +394,22 @@
mStepValue = gain.stepValue();
}
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public int getMinGain() {
return mMinGain;
}
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public int getMaxGain() {
return mMaxGain;
}
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public int getDefaultGain() {
return mDefaultGain;
}
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public int getStepValue() {
return mStepValue;
}
@@ -415,19 +435,23 @@
mHandleId = handleId;
}
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public int getHandleId() {
return mHandleId;
}
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public String getSourceAddress() {
return mSourceAddress;
}
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public String getSinkAddress() {
return mSinkAddress;
}
@Override
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append("Source{ ");
@@ -475,11 +499,13 @@
* Called on volume changes
* @param streamType type of stream for the volume change
*/
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public abstract void onVolumeChanged(int streamType);
/**
* Called on mute changes
*/
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public abstract void onMuteChanged();
}
}
diff --git a/car-builtin-lib/src/android/car/builtin/os/BinderHelper.java b/car-builtin-lib/src/android/car/builtin/os/BinderHelper.java
index 58f9fe0..2e56d13 100644
--- a/car-builtin-lib/src/android/car/builtin/os/BinderHelper.java
+++ b/car-builtin-lib/src/android/car/builtin/os/BinderHelper.java
@@ -19,6 +19,8 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
+import android.car.builtin.annotation.AddedIn;
+import android.car.builtin.annotation.PlatformVersion;
import android.os.Binder;
import android.os.IBinder;
import android.os.Parcel;
@@ -47,6 +49,7 @@
public final class BinderHelper {
/** Dumps given {@link RemoteCallbackList} for debugging. */
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static void dumpRemoteCallbackList(@NonNull RemoteCallbackList<?> list,
@NonNull PrintWriter pw) {
list.dump(pw, /* prefix= */ "");
@@ -70,6 +73,7 @@
*
* @return linux error code for the binder call. {@code 0} means ok.
*/
+ @AddedIn(PlatformVersion.TIRAMISU_0)
int onShellCommand(@NonNull FileDescriptor in, @NonNull FileDescriptor out,
@NonNull FileDescriptor err, @NonNull String[] args);
}
@@ -92,6 +96,7 @@
*
* @throws RemoteException for binder call failure
*/
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static boolean onTransactForCmd(int code, @NonNull Parcel data,
@Nullable Parcel reply, int flags, @NonNull ShellCommandListener cmdListener)
throws RemoteException {
diff --git a/car-builtin-lib/src/android/car/builtin/os/BuildHelper.java b/car-builtin-lib/src/android/car/builtin/os/BuildHelper.java
index a19c8f4..c5fc43b 100644
--- a/car-builtin-lib/src/android/car/builtin/os/BuildHelper.java
+++ b/car-builtin-lib/src/android/car/builtin/os/BuildHelper.java
@@ -17,6 +17,8 @@
package android.car.builtin.os;
import android.annotation.SystemApi;
+import android.car.builtin.annotation.AddedIn;
+import android.car.builtin.annotation.PlatformVersion;
import android.os.Build;
/**
@@ -31,21 +33,25 @@
}
/** Tells if it is {@code user} build. */
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static boolean isUserBuild() {
return Build.IS_USER;
}
/** Tells if it is {@code eng} build. */
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static boolean isEngBuild() {
return Build.IS_ENG;
}
/** Tells if it is {@code userdebug} build. */
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static boolean isUserDebugBuild() {
return Build.IS_USERDEBUG;
}
/** Tells if the build is debuggable ({@code eng} or {@code userdebug}) */
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static boolean isDebuggableBuild() {
return Build.IS_DEBUGGABLE;
}
diff --git a/car-builtin-lib/src/android/car/builtin/os/ParcelHelper.java b/car-builtin-lib/src/android/car/builtin/os/ParcelHelper.java
index 006a018..a74a287 100644
--- a/car-builtin-lib/src/android/car/builtin/os/ParcelHelper.java
+++ b/car-builtin-lib/src/android/car/builtin/os/ParcelHelper.java
@@ -19,6 +19,8 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
+import android.car.builtin.annotation.AddedIn;
+import android.car.builtin.annotation.PlatformVersion;
import android.os.Parcel;
import android.util.ArraySet;
@@ -35,29 +37,34 @@
/** Reads array of string from the passed parcel */
@Nullable
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static String[] readStringArray(@NonNull Parcel parcel) {
return parcel.readStringArray();
}
/** Reads a Blob */
@Nullable
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static byte[] readBlob(@NonNull Parcel parcel) {
return parcel.readBlob();
}
/** Writes the byte array to the Parcel */
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static void writeBlob(@NonNull Parcel parcel, @Nullable byte[] b) {
parcel.writeBlob(b);
}
/** Reads ArraySet */
@Nullable
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static ArraySet<? extends Object> readArraySet(@NonNull Parcel parcel,
@Nullable ClassLoader loader) {
return parcel.readArraySet(loader);
}
/** Writes ArraySet */
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static void writeArraySet(@NonNull Parcel parcel,
@Nullable ArraySet<? extends Object> val) {
parcel.writeArraySet(val);
diff --git a/car-builtin-lib/src/android/car/builtin/os/ServiceManagerHelper.java b/car-builtin-lib/src/android/car/builtin/os/ServiceManagerHelper.java
index 92f93f5..ed64e9e 100644
--- a/car-builtin-lib/src/android/car/builtin/os/ServiceManagerHelper.java
+++ b/car-builtin-lib/src/android/car/builtin/os/ServiceManagerHelper.java
@@ -19,6 +19,8 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
+import android.car.builtin.annotation.AddedIn;
+import android.car.builtin.annotation.PlatformVersion;
import android.os.IBinder;
import android.os.ServiceManager;
@@ -36,23 +38,27 @@
/** Check {@link ServiceManager#getService(String)} */
@Nullable
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static IBinder getService(@NonNull String name) {
return ServiceManager.getService(name);
}
/** Check {@link ServiceManager#checkService(String)} */
@Nullable
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static IBinder checkService(@NonNull String name) {
return ServiceManager.checkService(name);
}
/** Check {@link ServiceManager#waitForDeclaredService(String)} */
@Nullable
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static IBinder waitForDeclaredService(@NonNull String name) {
return ServiceManager.waitForDeclaredService(name);
}
/** Check {@link ServiceManager#addService(String, IBinder)} */
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static void addService(@NonNull String name, @NonNull IBinder service) {
ServiceManager.addService(name, service);
}
diff --git a/car-builtin-lib/src/android/car/builtin/os/SharedMemoryHelper.java b/car-builtin-lib/src/android/car/builtin/os/SharedMemoryHelper.java
index e3bd3b1..cb00236 100644
--- a/car-builtin-lib/src/android/car/builtin/os/SharedMemoryHelper.java
+++ b/car-builtin-lib/src/android/car/builtin/os/SharedMemoryHelper.java
@@ -18,6 +18,8 @@
import android.annotation.NonNull;
import android.annotation.SystemApi;
+import android.car.builtin.annotation.AddedIn;
+import android.car.builtin.annotation.PlatformVersion;
import android.os.ParcelFileDescriptor;
import android.os.SharedMemory;
@@ -36,6 +38,7 @@
/** Returns the backing file for the shared memory wrapped in {@code ParcelFileDescriptor}*/
@NonNull
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static ParcelFileDescriptor createParcelFileDescriptor(
@NonNull SharedMemory memory) throws IOException {
// Must duplicate the file descriptor because it is currently owned by memory, and we also
diff --git a/car-builtin-lib/src/android/car/builtin/os/SystemPropertiesHelper.java b/car-builtin-lib/src/android/car/builtin/os/SystemPropertiesHelper.java
index 49d565a..dddbe22 100644
--- a/car-builtin-lib/src/android/car/builtin/os/SystemPropertiesHelper.java
+++ b/car-builtin-lib/src/android/car/builtin/os/SystemPropertiesHelper.java
@@ -19,6 +19,8 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
+import android.car.builtin.annotation.AddedIn;
+import android.car.builtin.annotation.PlatformVersion;
import android.os.SystemProperties;
/**
@@ -33,6 +35,7 @@
}
/** Check {@link SystemProperties#set(String, String)} */
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static void set(@NonNull String key, @Nullable String val) {
SystemProperties.set(key, val);
}
diff --git a/car-builtin-lib/src/android/car/builtin/os/TraceHelper.java b/car-builtin-lib/src/android/car/builtin/os/TraceHelper.java
index 35cc4c9..2c2d682 100644
--- a/car-builtin-lib/src/android/car/builtin/os/TraceHelper.java
+++ b/car-builtin-lib/src/android/car/builtin/os/TraceHelper.java
@@ -17,6 +17,8 @@
package android.car.builtin.os;
import android.annotation.SystemApi;
+import android.car.builtin.annotation.AddedIn;
+import android.car.builtin.annotation.PlatformVersion;
import android.os.Trace;
/**
@@ -35,5 +37,6 @@
* {@link Trace#TRACE_TAG_SYSTEM_SERVER}, so {code System Server} tracing should be enabled from
* trace tools to access these traces.
*/
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static final long TRACE_TAG_CAR_SERVICE = Trace.TRACE_TAG_SYSTEM_SERVER;
}
diff --git a/car-builtin-lib/src/android/car/builtin/os/UserManagerHelper.java b/car-builtin-lib/src/android/car/builtin/os/UserManagerHelper.java
index 305ce45..b78937d 100644
--- a/car-builtin-lib/src/android/car/builtin/os/UserManagerHelper.java
+++ b/car-builtin-lib/src/android/car/builtin/os/UserManagerHelper.java
@@ -20,6 +20,8 @@
import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.annotation.UserIdInt;
+import android.car.builtin.annotation.AddedIn;
+import android.car.builtin.annotation.PlatformVersion;
import android.content.Context;
import android.content.pm.UserInfo;
import android.os.UserHandle;
@@ -40,30 +42,46 @@
}
/** user id for invalid user */
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static final @UserIdInt int USER_NULL = UserHandle.USER_NULL;
/** A user id constant to indicate the "system" user of the device */
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static final @UserIdInt int USER_SYSTEM = UserHandle.USER_SYSTEM;
// Flags copied from UserInfo.
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static final int FLAG_PRIMARY = UserInfo.FLAG_PRIMARY;
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static final int FLAG_ADMIN = UserInfo.FLAG_ADMIN;
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static final int FLAG_GUEST = UserInfo.FLAG_GUEST;
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static final int FLAG_RESTRICTED = UserInfo.FLAG_RESTRICTED;
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static final int FLAG_INITIALIZED = UserInfo.FLAG_INITIALIZED;
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static final int FLAG_MANAGED_PROFILE = UserInfo.FLAG_MANAGED_PROFILE;
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static final int FLAG_DISABLED = UserInfo.FLAG_DISABLED;
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static final int FLAG_QUIET_MODE = UserInfo.FLAG_QUIET_MODE;
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static final int FLAG_EPHEMERAL = UserInfo.FLAG_EPHEMERAL;
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static final int FLAG_DEMO = UserInfo.FLAG_DEMO;
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static final int FLAG_FULL = UserInfo.FLAG_FULL;
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static final int FLAG_SYSTEM = UserInfo.FLAG_SYSTEM;
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static final int FLAG_PROFILE = UserInfo.FLAG_PROFILE;
/**
* Returns all users based on the boolean flags.
*/
@NonNull
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static List<UserHandle> getUserHandles(@NonNull UserManager userManager,
boolean excludePartial, boolean excludeDying, boolean excludePreCreated) {
List<UserInfo> users = userManager.getUsers(excludePartial, excludeDying,
@@ -79,6 +97,7 @@
/**
* Checks if a user is ephemeral.
*/
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static boolean isEphemeralUser(@NonNull UserManager userManager,
@NonNull UserHandle user) {
return userManager.isUserEphemeral(user.getIdentifier());
@@ -87,6 +106,7 @@
/**
* Checks if a user is enabled.
*/
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static boolean isEnabledUser(@NonNull UserManager userManager,
@NonNull UserHandle user) {
return userManager.getUserInfo(user.getIdentifier()).isEnabled();
@@ -95,6 +115,7 @@
/**
* Checks if a user is precreated.
*/
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static boolean isPreCreatedUser(@NonNull UserManager userManager,
@NonNull UserHandle user) {
return userManager.getUserInfo(user.getIdentifier()).preCreated;
@@ -103,6 +124,7 @@
/**
* Checks if a user is initialized.
*/
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static boolean isInitializedUser(@NonNull UserManager userManager,
@NonNull UserHandle user) {
return userManager.getUserInfo(user.getIdentifier()).isInitialized();
@@ -111,6 +133,7 @@
/**
* Gets DefaultUserType given userInfo flags.
*/
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static String getDefaultUserTypeForUserInfoFlags(int userInfoFlag) {
return UserInfo.getDefaultUserType(userInfoFlag);
}
@@ -119,6 +142,7 @@
* Precreates user based on user type
*/
@Nullable
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static UserHandle preCreateUser(@NonNull UserManager userManager, @NonNull String type) {
UserInfo userInfo = userManager.preCreateUser(type);
return userInfo == null ? null : userInfo.getUserHandle();
@@ -128,6 +152,7 @@
* Gets the default name for a user.
*/
@NonNull
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static String getDefaultUserName(@NonNull Context context) {
return context.getResources().getString(com.android.internal.R.string.owner_name);
}
@@ -135,6 +160,7 @@
/**
* Gets the maximum number of users that can be running at any given time.
*/
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static int getMaxRunningUsers(@NonNull Context context) {
return context.getResources()
.getInteger(com.android.internal.R.integer.config_multiuserMaxRunningUsers);
@@ -143,6 +169,7 @@
/**
* Marks guest for deletion
*/
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static boolean markGuestForDeletion(@NonNull UserManager userManager,
@NonNull UserHandle user) {
return userManager.markGuestForDeletion(user.getIdentifier());
@@ -151,6 +178,7 @@
/**
* Returns the user id for a given uid.
*/
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static @UserIdInt int getUserId(int uid) {
return UserHandle.getUserId(uid);
}
diff --git a/car-builtin-lib/src/android/car/builtin/power/PowerManagerHelper.java b/car-builtin-lib/src/android/car/builtin/power/PowerManagerHelper.java
index df65eaa..2ab4d9e 100644
--- a/car-builtin-lib/src/android/car/builtin/power/PowerManagerHelper.java
+++ b/car-builtin-lib/src/android/car/builtin/power/PowerManagerHelper.java
@@ -17,6 +17,8 @@
package android.car.builtin.power;
import android.annotation.SystemApi;
+import android.car.builtin.annotation.AddedIn;
+import android.car.builtin.annotation.PlatformVersion;
import android.content.Context;
import android.os.PowerManager;
@@ -39,6 +41,7 @@
* @param context Context to use.
* @return The maximum value that can be set by the user.
*/
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static int getMaximumScreenBrightnessSetting(Context context) {
return context.getSystemService(PowerManager.class).getMaximumScreenBrightnessSetting();
}
@@ -50,6 +53,7 @@
* @param context Context to use.
* @return The minimum value that can be set by the user.
*/
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static int getMinimumScreenBrightnessSetting(Context context) {
return context.getSystemService(PowerManager.class).getMinimumScreenBrightnessSetting();
}
@@ -63,6 +67,7 @@
* @param upTime The time when the request was issued, in the
* {@link SystemClock#uptimeMillis()} time base.
*/
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static void setDisplayState(Context context, boolean on, long upTime) {
PowerManager powerManager = context.getSystemService(PowerManager.class);
if (on) {
@@ -74,6 +79,7 @@
}
/** Turns off the device. */
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static void shutdown(Context context, boolean confirm, String reason, boolean wait) {
context.getSystemService(PowerManager.class).shutdown(confirm, reason, wait);
}
diff --git a/car-builtin-lib/src/android/car/builtin/provider/SettingsHelper.java b/car-builtin-lib/src/android/car/builtin/provider/SettingsHelper.java
index 949da5f..b805515 100644
--- a/car-builtin-lib/src/android/car/builtin/provider/SettingsHelper.java
+++ b/car-builtin-lib/src/android/car/builtin/provider/SettingsHelper.java
@@ -17,6 +17,8 @@
package android.car.builtin.provider;
import android.annotation.SystemApi;
+import android.car.builtin.annotation.AddedIn;
+import android.car.builtin.annotation.PlatformVersion;
/**
* Helper for hidden {@link android.provider.Settings} APIs.
@@ -30,6 +32,7 @@
/**
* Value of {@link android.provider.Settings.System#SYSTEM_LOCALES}.
*/
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static final String SYSTEM_LOCALES = "system_locales";
private SettingsHelper() {
diff --git a/car-builtin-lib/src/android/car/builtin/util/AssistUtilsHelper.java b/car-builtin-lib/src/android/car/builtin/util/AssistUtilsHelper.java
index fc9c162..bd2c786 100644
--- a/car-builtin-lib/src/android/car/builtin/util/AssistUtilsHelper.java
+++ b/car-builtin-lib/src/android/car/builtin/util/AssistUtilsHelper.java
@@ -21,6 +21,8 @@
import android.annotation.NonNull;
import android.annotation.SystemApi;
import android.app.ActivityManager;
+import android.car.builtin.annotation.AddedIn;
+import android.car.builtin.annotation.PlatformVersion;
import android.content.Context;
import android.os.Bundle;
import android.os.RemoteException;
@@ -42,6 +44,7 @@
private static final String TAG = AssistUtilsHelper.class.getSimpleName();
@VisibleForTesting
+ @AddedIn(PlatformVersion.TIRAMISU_0)
static final String EXTRA_CAR_PUSH_TO_TALK =
"com.android.car.input.EXTRA_CAR_PUSH_TO_TALK";
@@ -51,6 +54,7 @@
* @param context used to build the assist utils.
* @return {@code true} if a session is running, {@code false} otherwise.
*/
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static boolean isSessionRunning(@NonNull Context context) {
AssistUtils assistUtils = getAssistUtils(context);
@@ -62,6 +66,7 @@
*
* @param context used to build the assist utils.
*/
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static void hideCurrentSession(@NonNull Context context) {
AssistUtils assistUtils = getAssistUtils(context);
@@ -75,6 +80,7 @@
* @param sessionListener listener that will receive shown or hidden voice sessions callback.
*/
// TODO(b/221604866) : Add unregister method
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static void registerVoiceInteractionSessionListenerHelper(@NonNull Context context,
@NonNull VoiceInteractionSessionListenerHelper sessionListener) {
Objects.requireNonNull(sessionListener, "Session listener must not be null.");
@@ -91,6 +97,7 @@
*
* @return whether the assistant component is active for the current user.
*/
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static boolean showPushToTalkSessionForActiveService(@NonNull Context context,
@NonNull VoiceInteractionSessionShowCallbackHelper callback) {
Objects.requireNonNull(callback, "On shown callback must not be null.");
@@ -127,11 +134,13 @@
/**
* See {@link IVoiceInteractionSessionShowCallback#onFailed()}
*/
+ @AddedIn(PlatformVersion.TIRAMISU_1)
void onFailed();
/**
* See {@link IVoiceInteractionSessionShowCallback#onShow()}
*/
+ @AddedIn(PlatformVersion.TIRAMISU_1)
void onShown();
}
@@ -143,11 +152,13 @@
/**
* See {@link IVoiceInteractionSessionListener#onVoiceSessionShown()}
*/
+ @AddedIn(PlatformVersion.TIRAMISU_1)
void onVoiceSessionShown();
/**
* See {@link IVoiceInteractionSessionListener#onVoiceSessionHidden()}
*/
+ @AddedIn(PlatformVersion.TIRAMISU_1)
void onVoiceSessionHidden();
}
diff --git a/car-builtin-lib/src/android/car/builtin/util/AtomicFileHelper.java b/car-builtin-lib/src/android/car/builtin/util/AtomicFileHelper.java
index bdf2c64..65ed3e8 100644
--- a/car-builtin-lib/src/android/car/builtin/util/AtomicFileHelper.java
+++ b/car-builtin-lib/src/android/car/builtin/util/AtomicFileHelper.java
@@ -17,6 +17,8 @@
package android.car.builtin.util;
import android.annotation.SystemApi;
+import android.car.builtin.annotation.AddedIn;
+import android.car.builtin.annotation.PlatformVersion;
import android.util.AtomicFile;
/**
@@ -31,6 +33,7 @@
}
/** Check {@link AtomicFile#exists()} */
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static boolean exists(AtomicFile file) {
return file.exists();
}
diff --git a/car-builtin-lib/src/android/car/builtin/util/EventLogHelper.java b/car-builtin-lib/src/android/car/builtin/util/EventLogHelper.java
index 3f5aa51..2bb671e 100644
--- a/car-builtin-lib/src/android/car/builtin/util/EventLogHelper.java
+++ b/car-builtin-lib/src/android/car/builtin/util/EventLogHelper.java
@@ -18,6 +18,8 @@
import android.annotation.Nullable;
import android.annotation.SystemApi;
+import android.car.builtin.annotation.AddedIn;
+import android.car.builtin.annotation.PlatformVersion;
import android.util.EventLog;
/**
@@ -27,112 +29,138 @@
*/
@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
public final class EventLogHelper {
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static void writeCarHelperStart() {
EventLog.writeEvent(EventLogTags.CAR_HELPER_START);
}
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static void writeCarHelperBootPhase(int phase) {
EventLog.writeEvent(EventLogTags.CAR_HELPER_BOOT_PHASE, phase);
}
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static void writeCarHelperUserStarting(int userId) {
EventLog.writeEvent(EventLogTags.CAR_HELPER_USER_STARTING, userId);
}
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static void writeCarHelperUserSwitching(int fromUserId, int toUserId) {
EventLog.writeEvent(EventLogTags.CAR_HELPER_USER_SWITCHING, fromUserId, toUserId);
}
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static void writeCarHelperUserUnlocking(int userId) {
EventLog.writeEvent(EventLogTags.CAR_HELPER_USER_UNLOCKING, userId);
}
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static void writeCarHelperUserUnlocked(int userId) {
EventLog.writeEvent(EventLogTags.CAR_HELPER_USER_UNLOCKED, userId);
}
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static void writeCarHelperUserStopping(int userId) {
EventLog.writeEvent(EventLogTags.CAR_HELPER_USER_STOPPING, userId);
}
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static void writeCarHelperUserStopped(int userId) {
EventLog.writeEvent(EventLogTags.CAR_HELPER_USER_STOPPED, userId);
}
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static void writeCarHelperServiceConnected() {
EventLog.writeEvent(EventLogTags.CAR_HELPER_SVC_CONNECTED);
}
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static void writeCarServiceInit(int numberServices) {
EventLog.writeEvent(EventLogTags.CAR_SERVICE_INIT, numberServices);
}
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static void writeCarServiceVhalReconnected(int numberServices) {
EventLog.writeEvent(EventLogTags.CAR_SERVICE_VHAL_RECONNECTED, numberServices);
}
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static void writeCarServiceSetCarServiceHelper(int pid) {
EventLog.writeEvent(EventLogTags.CAR_SERVICE_SET_CAR_SERVICE_HELPER, pid);
}
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static void writeCarServiceOnUserLifecycle(int type, int fromUserId, int toUserId) {
EventLog.writeEvent(EventLogTags.CAR_SERVICE_ON_USER_LIFECYCLE, type, fromUserId, toUserId);
}
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static void writeCarServiceCreate(boolean hasVhal) {
EventLog.writeEvent(EventLogTags.CAR_SERVICE_CREATE, hasVhal ? 1 : 0);
}
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static void writeCarServiceConnected(@Nullable String interfaceName) {
EventLog.writeEvent(EventLogTags.CAR_SERVICE_CONNECTED, interfaceName);
}
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static void writeCarServiceDestroy(boolean hasVhal) {
EventLog.writeEvent(EventLogTags.CAR_SERVICE_DESTROY, hasVhal ? 1 : 0);
}
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static void writeCarServiceVhalDied(long cookie) {
EventLog.writeEvent(EventLogTags.CAR_SERVICE_VHAL_DIED, cookie);
}
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static void writeCarServiceInitBootUser() {
EventLog.writeEvent(EventLogTags.CAR_SERVICE_INIT_BOOT_USER);
}
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static void writeCarServiceOnUserRemoved(int userId) {
EventLog.writeEvent(EventLogTags.CAR_SERVICE_ON_USER_REMOVED, userId);
}
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static void writeCarUserServiceInitialUserInfoReq(int requestType, int timeout,
int currentUserId, int currentUserFlags, int numberExistingUsers) {
EventLog.writeEvent(EventLogTags.CAR_USER_SVC_INITIAL_USER_INFO_REQ, requestType, timeout,
currentUserId, currentUserFlags, numberExistingUsers);
}
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static void writeCarUserServiceInitialUserInfoResp(int status, int action, int userId,
int flags, @Nullable String safeName, @Nullable String userLocales) {
EventLog.writeEvent(EventLogTags.CAR_USER_SVC_INITIAL_USER_INFO_RESP, status, action,
userId, flags, safeName, userLocales);
}
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static void writeCarUserServiceSetInitialUser(int userId) {
EventLog.writeEvent(EventLogTags.CAR_USER_SVC_SET_INITIAL_USER, userId);
}
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static void writeCarUserServiceSetLifecycleListener(int uid,
@Nullable String packageName) {
EventLog.writeEvent(EventLogTags.CAR_USER_SVC_SET_LIFECYCLE_LISTENER, uid, packageName);
}
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static void writeCarUserServiceResetLifecycleListener(int uid,
@Nullable String packageName) {
EventLog.writeEvent(EventLogTags.CAR_USER_SVC_RESET_LIFECYCLE_LISTENER, uid, packageName);
}
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static void writeCarUserServiceSwitchUserReq(int userId, int timeout) {
EventLog.writeEvent(EventLogTags.CAR_USER_SVC_SWITCH_USER_REQ, userId, timeout);
}
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static void writeCarUserServiceSwitchUserResp(int halCallbackStatus,
int userSwitchStatus, @Nullable String errorMessage) {
EventLog.writeEvent(EventLogTags.CAR_USER_SVC_SWITCH_USER_RESP, halCallbackStatus,
@@ -142,6 +170,7 @@
/**
* Logs a {@code EventLogTags.CAR_USER_SVC_LOGOUT_USER_REQ} event.
*/
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static void writeCarUserServiceLogoutUserReq(int userId, int timeout) {
EventLog.writeEvent(EventLogTags.CAR_USER_SVC_LOGOUT_USER_REQ, userId, timeout);
}
@@ -149,93 +178,111 @@
/**
* Logs a {@code EventLogTags.CAR_USER_SVC_LOGOUT_USER_RESP} event.
*/
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static void writeCarUserServiceLogoutUserResp(int halCallbackStatus,
int userSwitchStatus, @Nullable String errorMessage) {
EventLog.writeEvent(EventLogTags.CAR_USER_SVC_LOGOUT_USER_RESP, halCallbackStatus,
userSwitchStatus, errorMessage);
}
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static void writeCarUserServicePostSwitchUserReq(int targetUserId, int currentUserId) {
EventLog.writeEvent(EventLogTags.CAR_USER_SVC_POST_SWITCH_USER_REQ, targetUserId,
currentUserId);
}
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static void writeCarUserServiceGetUserAuthReq(int uid, int userId, int numberTypes) {
EventLog.writeEvent(EventLogTags.CAR_USER_SVC_GET_USER_AUTH_REQ, uid, userId, numberTypes);
}
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static void writeCarUserServiceGetUserAuthResp(int numberValues) {
EventLog.writeEvent(EventLogTags.CAR_USER_SVC_GET_USER_AUTH_RESP, numberValues);
}
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static void writeCarUserServiceSwitchUserUiReq(int userId) {
EventLog.writeEvent(EventLogTags.CAR_USER_SVC_SWITCH_USER_UI_REQ, userId);
}
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static void writeCarUserServiceSwitchUserFromHalReq(int requestId, int uid) {
EventLog.writeEvent(EventLogTags.CAR_USER_SVC_SWITCH_USER_FROM_HAL_REQ, requestId, uid);
}
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static void writeCarUserServiceSetUserAuthReq(int uid, int userId,
int numberAssociations) {
EventLog.writeEvent(EventLogTags.CAR_USER_SVC_SET_USER_AUTH_REQ, uid, userId,
numberAssociations);
}
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static void writeCarUserServiceSetUserAuthResp(int numberValues,
@Nullable String errorMessage) {
EventLog.writeEvent(EventLogTags.CAR_USER_SVC_SET_USER_AUTH_RESP, numberValues,
errorMessage);
}
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static void writeCarUserServiceCreateUserReq(@Nullable String safeName,
@Nullable String userType, int flags, int timeout, int hasCallerRestrictions) {
EventLog.writeEvent(EventLogTags.CAR_USER_SVC_CREATE_USER_REQ, safeName, userType, flags,
timeout, hasCallerRestrictions);
}
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static void writeCarUserServiceCreateUserResp(int status, int result,
@Nullable String errorMessage) {
EventLog.writeEvent(EventLogTags.CAR_USER_SVC_CREATE_USER_RESP, status, result,
errorMessage);
}
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static void writeCarUserServiceCreateUserUserCreated(int userId,
@Nullable String safeName, @Nullable String userType, int flags) {
EventLog.writeEvent(EventLogTags.CAR_USER_SVC_CREATE_USER_USER_CREATED, userId, safeName,
userType, flags);
}
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static void writeCarUserServiceCreateUserUserRemoved(int userId,
@Nullable String reason) {
EventLog.writeEvent(EventLogTags.CAR_USER_SVC_CREATE_USER_USER_REMOVED, userId, reason);
}
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static void writeCarUserServiceRemoveUserReq(int userId, int hascallerrestrictions) {
EventLog.writeEvent(EventLogTags.CAR_USER_SVC_REMOVE_USER_REQ, userId,
hascallerrestrictions);
}
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static void writeCarUserServiceRemoveUserResp(int userId, int result) {
EventLog.writeEvent(EventLogTags.CAR_USER_SVC_REMOVE_USER_RESP, userId, result);
}
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static void writeCarUserServiceNotifyAppLifecycleListener(int uid,
@Nullable String packageName, int eventType, int fromUserId, int toUserId) {
EventLog.writeEvent(EventLogTags.CAR_USER_SVC_NOTIFY_APP_LIFECYCLE_LISTENER, uid,
packageName, eventType, fromUserId, toUserId);
}
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static void writeCarUserServiceNotifyInternalLifecycleListener(
@Nullable String listenerName, int eventType, int fromUserId, int toUserId) {
EventLog.writeEvent(EventLogTags.CAR_USER_SVC_NOTIFY_INTERNAL_LIFECYCLE_LISTENER,
listenerName, eventType, fromUserId, toUserId);
}
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static void writeCarUserServicePreCreationRequested(int numberUsers, int numberGuests) {
EventLog.writeEvent(EventLogTags.CAR_USER_SVC_PRE_CREATION_REQUESTED, numberUsers,
numberGuests);
}
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static void writeCarUserServicePreCreationStatus(int numberExistingUsers,
int numberUsersToAdd, int numberUsersToRemove, int numberExistingGuests,
int numberGuestsToAdd, int numberGuestsToRemove, int numberInvalidUsersToRemove) {
@@ -244,118 +291,142 @@
numberGuestsToRemove, numberInvalidUsersToRemove);
}
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static void writeCarUserServiceStartUserInBackgroundReq(int userId) {
EventLog.writeEvent(EventLogTags.CAR_USER_SVC_START_USER_IN_BACKGROUND_REQ, userId);
}
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static void writeCarUserServiceStartUserInBackgroundResp(int userId, int result) {
EventLog.writeEvent(EventLogTags.CAR_USER_SVC_START_USER_IN_BACKGROUND_RESP, userId,
result);
}
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static void writeCarUserServiceStopUserReq(int userId) {
EventLog.writeEvent(EventLogTags.CAR_USER_SVC_STOP_USER_REQ, userId);
}
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static void writeCarUserServiceStopUserResp(int userId, int result) {
EventLog.writeEvent(EventLogTags.CAR_USER_SVC_STOP_USER_RESP, userId, result);
}
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static void writeCarUserServiceInitialUserInfoReqComplete(int requestType) {
EventLog.writeEvent(EventLogTags.CAR_USER_SVC_INITIAL_USER_INFO_REQ_COMPLETE, requestType);
}
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static void writeCarUserHalInitialUserInfoReq(int requestId, int requestType,
int timeout) {
EventLog.writeEvent(EventLogTags.CAR_USER_HAL_INITIAL_USER_INFO_REQ, requestId, requestType,
timeout);
}
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static void writeCarUserHalInitialUserInfoResp(int requestId, int status, int action,
int userId, int flags, @Nullable String safeName, @Nullable String userLocales) {
EventLog.writeEvent(EventLogTags.CAR_USER_HAL_INITIAL_USER_INFO_RESP, requestId, status,
action, userId, flags, safeName, userLocales);
}
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static void writeCarUserHalSwitchUserReq(int requestId, int userId, int userFlags,
int timeout) {
EventLog.writeEvent(EventLogTags.CAR_USER_HAL_SWITCH_USER_REQ, requestId, userId, userFlags,
timeout);
}
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static void writeCarUserHalSwitchUserResp(int requestId, int status, int result,
@Nullable String errorMessage) {
EventLog.writeEvent(EventLogTags.CAR_USER_HAL_SWITCH_USER_RESP, requestId, status, result,
errorMessage);
}
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static void writeCarUserHalPostSwitchUserReq(int requestId, int targetUserId,
int currentUserId) {
EventLog.writeEvent(EventLogTags.CAR_USER_HAL_POST_SWITCH_USER_REQ, requestId, targetUserId,
currentUserId);
}
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static void writeCarUserHalGetUserAuthReq(@Nullable Object[] int32Values) {
EventLog.writeEvent(EventLogTags.CAR_USER_HAL_GET_USER_AUTH_REQ, int32Values);
}
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static void writeCarUserHalGetUserAuthResp(@Nullable Object[] valuesAndError) {
EventLog.writeEvent(EventLogTags.CAR_USER_HAL_GET_USER_AUTH_RESP, valuesAndError);
}
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static void writeCarUserHalLegacySwitchUserReq(int requestId, int targetUserId,
int currentUserId) {
EventLog.writeEvent(EventLogTags.CAR_USER_HAL_LEGACY_SWITCH_USER_REQ, requestId,
targetUserId, currentUserId);
}
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static void writeCarUserHalSetUserAuthReq(@Nullable Object[] int32Values) {
EventLog.writeEvent(EventLogTags.CAR_USER_HAL_SET_USER_AUTH_REQ, int32Values);
}
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static void writeCarUserHalSetUserAuthResp(@Nullable Object[] valuesAndError) {
EventLog.writeEvent(EventLogTags.CAR_USER_HAL_SET_USER_AUTH_RESP, valuesAndError);
}
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static void writeCarUserHalOemSwitchUserReq(int requestId, int targetUserId) {
EventLog.writeEvent(EventLogTags.CAR_USER_HAL_OEM_SWITCH_USER_REQ, requestId, targetUserId);
}
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static void writeCarUserHalCreateUserReq(int requestId, @Nullable String safeName,
int flags, int timeout) {
EventLog.writeEvent(EventLogTags.CAR_USER_HAL_CREATE_USER_REQ, requestId, safeName, flags,
timeout);
}
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static void writeCarUserHalCreateUserResp(int requestId, int status, int result,
@Nullable String errorMessage) {
EventLog.writeEvent(EventLogTags.CAR_USER_HAL_CREATE_USER_RESP, requestId, status, result,
errorMessage);
}
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static void writeCarUserHalRemoveUserReq(int targetUserId, int currentUserId) {
EventLog.writeEvent(EventLogTags.CAR_USER_HAL_REMOVE_USER_REQ, targetUserId, currentUserId);
}
/** Logs a {@code EventLogTags.CAR_USER_MGR_ADD_LISTENER} event. */
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static void writeCarUserManagerAddListener(int uid, @Nullable String packageName,
boolean hasFilter) {
EventLog.writeEvent(EventLogTags.CAR_USER_MGR_ADD_LISTENER, uid, packageName,
hasFilter ? 1 : 0);
}
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static void writeCarUserManagerRemoveListener(int uid, @Nullable String packageName) {
EventLog.writeEvent(EventLogTags.CAR_USER_MGR_REMOVE_LISTENER, uid, packageName);
}
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static void writeCarUserManagerDisconnected(int uid) {
EventLog.writeEvent(EventLogTags.CAR_USER_MGR_DISCONNECTED, uid);
}
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static void writeCarUserManagerSwitchUserReq(int uid, int userId) {
EventLog.writeEvent(EventLogTags.CAR_USER_MGR_SWITCH_USER_REQ, uid, userId);
}
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static void writeCarUserManagerSwitchUserResp(int uid, int status,
@Nullable String errorMessage) {
EventLog.writeEvent(EventLogTags.CAR_USER_MGR_SWITCH_USER_RESP, uid, status, errorMessage);
@@ -364,6 +435,7 @@
/**
* Logs a {@code EventLogTags.CAR_USER_MGR_LOGOUT_USER_REQ} event.
*/
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static void writeCarUserManagerLogoutUserReq(int uid) {
EventLog.writeEvent(EventLogTags.CAR_USER_MGR_LOGOUT_USER_REQ, uid);
}
@@ -371,101 +443,124 @@
/**
* Logs a {@code EventLogTags.CAR_USER_MGR_LOGOUT_USER_RESP} event.
*/
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static void writeCarUserManagerLogoutUserResp(int uid, int status,
@Nullable String errorMessage) {
EventLog.writeEvent(EventLogTags.CAR_USER_MGR_LOGOUT_USER_RESP, uid, status, errorMessage);
}
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static void writeCarUserManagerGetUserAuthReq(@Nullable Object[] types) {
EventLog.writeEvent(EventLogTags.CAR_USER_MGR_GET_USER_AUTH_REQ, types);
}
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static void writeCarUserManagerGetUserAuthResp(@Nullable Object[] values) {
EventLog.writeEvent(EventLogTags.CAR_USER_MGR_GET_USER_AUTH_RESP, values);
}
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static void writeCarUserManagerSetUserAuthReq(@Nullable Object[] typesAndValuesPairs) {
EventLog.writeEvent(EventLogTags.CAR_USER_MGR_SET_USER_AUTH_REQ, typesAndValuesPairs);
}
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static void writeCarUserManagerSetUserAuthResp(@Nullable Object[] values) {
EventLog.writeEvent(EventLogTags.CAR_USER_MGR_SET_USER_AUTH_RESP, values);
}
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static void writeCarUserManagerCreateUserReq(int uid, @Nullable String safeName,
@Nullable String userType, int flags) {
EventLog.writeEvent(EventLogTags.CAR_USER_MGR_CREATE_USER_REQ, uid, safeName, userType,
flags);
}
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static void writeCarUserManagerCreateUserResp(int uid, int status,
@Nullable String errorMessage) {
EventLog.writeEvent(EventLogTags.CAR_USER_MGR_CREATE_USER_RESP, uid, status, errorMessage);
}
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static void writeCarUserManagerRemoveUserReq(int uid, int userId) {
EventLog.writeEvent(EventLogTags.CAR_USER_MGR_REMOVE_USER_REQ, uid, userId);
}
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static void writeCarUserManagerRemoveUserResp(int uid, int status) {
EventLog.writeEvent(EventLogTags.CAR_USER_MGR_REMOVE_USER_RESP, uid, status);
}
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static void writeCarUserManagerNotifyLifecycleListener(int numberListeners,
int eventType, int fromUserId, int toUserId) {
EventLog.writeEvent(EventLogTags.CAR_USER_MGR_NOTIFY_LIFECYCLE_LISTENER, numberListeners,
eventType, fromUserId, toUserId);
}
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static void writeCarUserManagerPreCreateUserReq(int uid) {
EventLog.writeEvent(EventLogTags.CAR_USER_MGR_PRE_CREATE_USER_REQ, uid);
}
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static void writeCarDevicePolicyManagerRemoveUserReq(int uid, int userId) {
EventLog.writeEvent(EventLogTags.CAR_DP_MGR_REMOVE_USER_REQ, uid, userId);
}
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static void writeCarDevicePolicyManagerRemoveUserResp(int uid, int status) {
EventLog.writeEvent(EventLogTags.CAR_DP_MGR_REMOVE_USER_RESP, uid, status);
}
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static void writeCarDevicePolicyManagerCreateUserReq(int uid, @Nullable String safeName,
int flags) {
EventLog.writeEvent(EventLogTags.CAR_DP_MGR_CREATE_USER_REQ, uid, safeName, flags);
}
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static void writeCarDevicePolicyManagerCreateUserResp(int uid, int status) {
EventLog.writeEvent(EventLogTags.CAR_DP_MGR_CREATE_USER_RESP, uid, status);
}
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static void writeCarDevicePolicyManagerStartUserInBackgroundReq(int uid, int userId) {
EventLog.writeEvent(EventLogTags.CAR_DP_MGR_START_USER_IN_BACKGROUND_REQ, uid, userId);
}
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static void writeCarDevicePolicyManagerStartUserInBackgroundResp(int uid, int status) {
EventLog.writeEvent(EventLogTags.CAR_DP_MGR_START_USER_IN_BACKGROUND_RESP, uid, status);
}
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static void writeCarDevicePolicyManagerStopUserReq(int uid, int userId) {
EventLog.writeEvent(EventLogTags.CAR_DP_MGR_STOP_USER_REQ, uid, userId);
}
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static void writeCarDevicePolicyManagerStopUserResp(int uid, int status) {
EventLog.writeEvent(EventLogTags.CAR_DP_MGR_STOP_USER_RESP, uid, status);
}
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static void writePowerPolicyChange(String policy) {
EventLog.writeEvent(EventLogTags.CAR_PWR_MGR_PWR_POLICY_CHANGE, policy);
}
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static void writeCarPowerManagerStateChange(int state) {
EventLog.writeEvent(EventLogTags.CAR_PWR_MGR_STATE_CHANGE, state);
}
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static void writeCarPowerManagerStateRequest(int state, int param) {
EventLog.writeEvent(EventLogTags.CAR_PWR_MGR_STATE_REQ, state, param);
}
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static void writeGarageModeEvent(int status) {
EventLog.writeEvent(EventLogTags.CAR_PWR_MGR_GARAGE_MODE, status);
}
diff --git a/car-builtin-lib/src/android/car/builtin/util/Slogf.java b/car-builtin-lib/src/android/car/builtin/util/Slogf.java
index e3dec0f..078e03b 100644
--- a/car-builtin-lib/src/android/car/builtin/util/Slogf.java
+++ b/car-builtin-lib/src/android/car/builtin/util/Slogf.java
@@ -19,6 +19,8 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
+import android.car.builtin.annotation.AddedIn;
+import android.car.builtin.annotation.PlatformVersion;
import android.os.Trace;
import android.util.Log;
import android.util.Slog;
@@ -59,76 +61,91 @@
}
/** Same as {@link Log#isLoggable(String, int)}, but also checks for {@code CAR_TEST_TAG}. */
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static boolean isLoggable(@NonNull String tag, int level) {
return Log.isLoggable(tag, level) || Log.isLoggable(CAR_TEST_TAG, Log.VERBOSE);
}
/** Same as {@link Slog#v(String, String)}. */
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static int v(@NonNull String tag, @NonNull String msg) {
return Slog.v(tag, msg);
}
/** Same as {@link Slog#v(String, String, Throwable)}. */
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static int v(@NonNull String tag, @NonNull String msg, @NonNull Throwable tr) {
return Slog.v(tag, msg, tr);
}
/** Same as {@link Slog#d(String, String)}. */
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static int d(@NonNull String tag, @NonNull String msg) {
return Slog.d(tag, msg);
}
/** Same as {@link Slog#d(String, String, Throwable)}. */
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static int d(@NonNull String tag, @NonNull String msg, @NonNull Throwable tr) {
return Slog.d(tag, msg, tr);
}
/** Same as {@link Slog#i(String, String)}. */
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static int i(@NonNull String tag, @NonNull String msg) {
return Slog.i(tag, msg);
}
/** Same as {@link Slog#i(String, String, Throwable)}. */
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static int i(@NonNull String tag, @NonNull String msg, @NonNull Throwable tr) {
return Slog.i(tag, msg, tr);
}
/** Same as {@link Slog#w(String, String)}. */
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static int w(@NonNull String tag, @NonNull String msg) {
return Slog.w(tag, msg);
}
/** Same as {@link Slog#w(String, String, Throwable)}. */
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static int w(@NonNull String tag, @NonNull String msg, @NonNull Throwable tr) {
return Slog.w(tag, msg, tr);
}
/** Same as {@link Slog#w(String, String)}. */
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static int w(@NonNull String tag, @NonNull Throwable tr) {
return Slog.w(tag, tr);
}
/** Same as {@link Slog#e(String, String)}. */
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static int e(@NonNull String tag, @NonNull String msg) {
return Slog.e(tag, msg);
}
/** Same as {@link Slog#e(String, String, Throwable)}. */
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static int e(@NonNull String tag, @NonNull String msg, @NonNull Throwable tr) {
return Slog.e(tag, msg, tr);
}
/** Same as {@link Slog#wtf(String, String)}. */
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static int wtf(@NonNull String tag, @NonNull String msg) {
return Slog.wtf(tag, msg);
}
/** Same as {@link Slog#wtf(String, Throwable). */
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static int wtf(@NonNull String tag, @NonNull Throwable tr) {
return Slog.wtf(tag, tr);
}
/** Same as {@link Slog#wtf(String, String, Throwable)}. */
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static int wtf(@NonNull String tag, @NonNull String msg, @NonNull Throwable tr) {
return Slog.wtf(tag, msg, tr);
}
@@ -142,6 +159,7 @@
* calling this method in a critical path, make sure to explicitly do the check before calling
* it.
*/
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static void v(@NonNull String tag, @NonNull String format, @Nullable Object... args) {
if (!isLoggable(tag, Log.VERBOSE)) return;
@@ -157,6 +175,7 @@
* calling this method in a critical path, make sure to explicitly do the check before calling
* it.
*/
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static void d(@NonNull String tag, @NonNull String format, @Nullable Object... args) {
if (!isLoggable(tag, Log.DEBUG)) return;
@@ -172,6 +191,7 @@
* calling this method in a critical path, make sure to explicitly do the check before calling
* it.
*/
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static void i(@NonNull String tag, @NonNull String format, @Nullable Object... args) {
if (!isLoggable(tag, Log.INFO)) return;
@@ -187,6 +207,7 @@
* calling this method in a critical path, make sure to explicitly do the check before calling
* it.
*/
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static void w(@NonNull String tag, @NonNull String format, @Nullable Object... args) {
if (!isLoggable(tag, Log.WARN)) return;
@@ -202,6 +223,7 @@
* calling this method in a critical path, make sure to explicitly do the check before calling
* it.
*/
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static void w(@NonNull String tag, @NonNull Exception exception, @NonNull String format,
@Nullable Object... args) {
if (!isLoggable(tag, Log.WARN)) return;
@@ -218,6 +240,7 @@
* calling this method in a critical path, make sure to explicitly do the check before calling
* it.
*/
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static void e(@NonNull String tag, @NonNull String format, @Nullable Object... args) {
if (!isLoggable(tag, Log.ERROR)) return;
@@ -233,6 +256,7 @@
* calling this method in a critical path, make sure to explicitly do the check before calling
* it.
*/
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static void e(@NonNull String tag, @NonNull Exception exception, @NonNull String format,
@Nullable Object... args) {
if (!isLoggable(tag, Log.ERROR)) return;
@@ -243,6 +267,7 @@
/**
* Logs a {@code wtf} message.
*/
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static void wtf(@NonNull String tag, @NonNull String format, @Nullable Object... args) {
wtf(tag, getMessage(format, args));
}
@@ -250,6 +275,7 @@
/**
* Logs a {@code wtf} message with an exception.
*/
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static void wtf(@NonNull String tag, @NonNull Exception exception,
@NonNull String format, @Nullable Object... args) {
wtf(tag, getMessage(format, args), exception);
diff --git a/car-builtin-lib/src/android/car/builtin/util/TimeUtils.java b/car-builtin-lib/src/android/car/builtin/util/TimeUtils.java
index e9c1223..76c36e2 100644
--- a/car-builtin-lib/src/android/car/builtin/util/TimeUtils.java
+++ b/car-builtin-lib/src/android/car/builtin/util/TimeUtils.java
@@ -17,6 +17,8 @@
package android.car.builtin.util;
import android.annotation.SystemApi;
+import android.car.builtin.annotation.AddedIn;
+import android.car.builtin.annotation.PlatformVersion;
import java.io.PrintWriter;
@@ -28,11 +30,13 @@
public class TimeUtils {
/** Check {@code android.util.TimeUtils.dumpTime}. */
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static void dumpTime(PrintWriter pw, long time) {
android.util.TimeUtils.dumpTime(pw, time);
}
/** Check {@code android.util.TimeUtils.formatDuration}. */
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static void formatDuration(long duration, PrintWriter pw) {
android.util.TimeUtils.formatDuration(duration, pw);
}
diff --git a/car-builtin-lib/src/android/car/builtin/util/TimingsTraceLog.java b/car-builtin-lib/src/android/car/builtin/util/TimingsTraceLog.java
index d159667..0913367 100644
--- a/car-builtin-lib/src/android/car/builtin/util/TimingsTraceLog.java
+++ b/car-builtin-lib/src/android/car/builtin/util/TimingsTraceLog.java
@@ -18,6 +18,8 @@
import android.annotation.NonNull;
import android.annotation.SystemApi;
+import android.car.builtin.annotation.AddedIn;
+import android.car.builtin.annotation.PlatformVersion;
/**
* Wrapper class for {@code android.util.TimingsTraceLog}. Check the class for API documentation.
@@ -33,16 +35,19 @@
}
/** Check {@code android.util.Slog}. */
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public void traceBegin(@NonNull String name) {
mTimingsTraceLog.traceBegin(name);
}
/** Check {@code android.util.Slog}. */
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public void traceEnd() {
mTimingsTraceLog.traceEnd();
}
/** Check {@code android.util.Slog}. */
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public void logDuration(@NonNull String name, long timeMs) {
mTimingsTraceLog.logDuration(name, timeMs);
}
diff --git a/car-builtin-lib/src/android/car/builtin/util/ValidationHelper.java b/car-builtin-lib/src/android/car/builtin/util/ValidationHelper.java
index ff4bd28..c1f09d1 100644
--- a/car-builtin-lib/src/android/car/builtin/util/ValidationHelper.java
+++ b/car-builtin-lib/src/android/car/builtin/util/ValidationHelper.java
@@ -19,6 +19,8 @@
import android.annotation.AppIdInt;
import android.annotation.SystemApi;
import android.annotation.UserIdInt;
+import android.car.builtin.annotation.AddedIn;
+import android.car.builtin.annotation.PlatformVersion;
import android.os.UserHandle;
/**
@@ -33,12 +35,14 @@
}
/** Returns true if passed userId is valid */
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static boolean isUserIdValid(@UserIdInt int userId) {
return !((userId != UserHandle.USER_NULL && userId < UserHandle.USER_CURRENT_OR_SELF)
|| userId > Integer.MAX_VALUE / UserHandle.PER_USER_RANGE);
}
/** Returns true if passed appId is valid */
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static boolean isAppIdValid(@AppIdInt int appId) {
return !(appId / UserHandle.PER_USER_RANGE != 0 || appId < 0);
}
diff --git a/car-builtin-lib/src/android/car/builtin/view/DisplayHelper.java b/car-builtin-lib/src/android/car/builtin/view/DisplayHelper.java
index 2e69dcf..1b99870 100644
--- a/car-builtin-lib/src/android/car/builtin/view/DisplayHelper.java
+++ b/car-builtin-lib/src/android/car/builtin/view/DisplayHelper.java
@@ -17,6 +17,8 @@
package android.car.builtin.view;
import android.annotation.SystemApi;
+import android.car.builtin.annotation.AddedIn;
+import android.car.builtin.annotation.PlatformVersion;
import android.view.Display;
import android.view.DisplayAddress;
@@ -27,13 +29,17 @@
@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
public final class DisplayHelper {
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static final int INVALID_PORT = -1;
/** Display type: Physical display connected through an internal port. */
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static final int TYPE_INTERNAL = Display.TYPE_INTERNAL;
/** Display type: Physical display connected through an external port. */
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static final int TYPE_EXTERNAL = Display.TYPE_EXTERNAL;
/** Display type: Virtual display. */
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static final int TYPE_VIRTUAL = Display.TYPE_VIRTUAL;
private DisplayHelper() {
@@ -44,6 +50,7 @@
* @return the physical port number of the display, or {@code INVALID_PORT} if the display isn't
* the physical one.
*/
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static int getPhysicalPort(Display display) {
DisplayAddress address = display.getAddress();
if (address instanceof DisplayAddress.Physical) {
@@ -58,6 +65,7 @@
/**
* @return the uniqueId of the given display.
*/
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static String getUniqueId(Display display) {
return display.getUniqueId();
}
@@ -66,6 +74,7 @@
* Gets the display type.
* @see Display.getType()
*/
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static int getType(Display display) {
return display.getType();
}
diff --git a/car-builtin-lib/src/android/car/builtin/view/KeyEventHelper.java b/car-builtin-lib/src/android/car/builtin/view/KeyEventHelper.java
index d77b11a..6f461b9 100644
--- a/car-builtin-lib/src/android/car/builtin/view/KeyEventHelper.java
+++ b/car-builtin-lib/src/android/car/builtin/view/KeyEventHelper.java
@@ -18,6 +18,8 @@
import android.annotation.NonNull;
import android.annotation.SystemApi;
+import android.car.builtin.annotation.AddedIn;
+import android.car.builtin.annotation.PlatformVersion;
import android.view.KeyEvent;
/**
@@ -34,6 +36,7 @@
/**
* Sets the display id for the key event passed as argument.
*/
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static void setDisplayId(@NonNull KeyEvent keyEvent, int newDisplayId) {
keyEvent.setDisplayId(newDisplayId);
}
diff --git a/car-builtin-lib/src/android/car/builtin/widget/LockPatternHelper.java b/car-builtin-lib/src/android/car/builtin/widget/LockPatternHelper.java
index 2635cbf..79fb106 100644
--- a/car-builtin-lib/src/android/car/builtin/widget/LockPatternHelper.java
+++ b/car-builtin-lib/src/android/car/builtin/widget/LockPatternHelper.java
@@ -19,6 +19,8 @@
import android.annotation.NonNull;
import android.annotation.SystemApi;
import android.annotation.UserIdInt;
+import android.car.builtin.annotation.AddedIn;
+import android.car.builtin.annotation.PlatformVersion;
import android.content.Context;
import com.android.internal.widget.LockPatternUtils;
@@ -36,6 +38,7 @@
/**
* Checks if the given user has lock credentials.
*/
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static boolean isSecure(@NonNull Context context, @UserIdInt int userId) {
return new LockPatternUtils(context).isSecure(userId);
}
diff --git a/car-builtin-lib/src/android/car/builtin/window/DisplayAreaOrganizerHelper.java b/car-builtin-lib/src/android/car/builtin/window/DisplayAreaOrganizerHelper.java
index c23faf6..4eaed1e 100644
--- a/car-builtin-lib/src/android/car/builtin/window/DisplayAreaOrganizerHelper.java
+++ b/car-builtin-lib/src/android/car/builtin/window/DisplayAreaOrganizerHelper.java
@@ -17,6 +17,8 @@
package android.car.builtin.window;
import android.annotation.SystemApi;
+import android.car.builtin.annotation.AddedIn;
+import android.car.builtin.annotation.PlatformVersion;
import android.window.DisplayAreaOrganizer;
/**
@@ -29,5 +31,6 @@
/**
* The value in display area indicating that no value has been set.
*/
+ @AddedIn(PlatformVersion.TIRAMISU_0)
public static final int FEATURE_UNDEFINED = DisplayAreaOrganizer.FEATURE_UNDEFINED;
}
diff --git a/car-lib-module/api/current.txt b/car-lib-module/api/current.txt
index 38f60eb..05464e4 100644
--- a/car-lib-module/api/current.txt
+++ b/car-lib-module/api/current.txt
@@ -1,6 +1,13 @@
// Signature format: 2.0
package android.car {
+ public abstract class ApiVersion<T extends android.car.ApiVersion<?>> {
+ method public final int getMajorVersion();
+ method public final int getMinorVersion();
+ method public final boolean isAtLeast(@NonNull T);
+ method @NonNull public final String toString();
+ }
+
public final class Car {
method @Deprecated public void connect() throws java.lang.IllegalStateException;
method @Deprecated public static android.car.Car createCar(android.content.Context, android.content.ServiceConnection, @Nullable android.os.Handler);
@@ -11,15 +18,17 @@
method public void disconnect();
method @Deprecated public int getCarConnectionType();
method @Nullable public Object getCarManager(String);
- method public static boolean isApiAndPlatformVersionAtLeast(int, int);
- method public static boolean isApiAndPlatformVersionAtLeast(int, int, int);
- method public static boolean isApiVersionAtLeast(int);
- method public static boolean isApiVersionAtLeast(int, int);
+ method @NonNull public static android.car.CarVersion getCarVersion();
+ method @NonNull public static android.car.PlatformVersion getPlatformVersion();
+ method @Deprecated public static boolean isApiAndPlatformVersionAtLeast(int, int);
+ method @Deprecated public static boolean isApiAndPlatformVersionAtLeast(int, int, int);
+ method @Deprecated public static boolean isApiVersionAtLeast(int);
+ method @Deprecated public static boolean isApiVersionAtLeast(int, int);
method public boolean isConnected();
method public boolean isConnecting();
method public boolean isFeatureEnabled(@NonNull String);
- field public static final int API_VERSION_MAJOR_INT = 33; // 0x21
- field public static final int API_VERSION_MINOR_INT = 0; // 0x0
+ field @Deprecated public static final int API_VERSION_MAJOR_INT = 33; // 0x21
+ field @Deprecated public static final int API_VERSION_MINOR_INT = 1; // 0x1
field public static final String APP_FOCUS_SERVICE = "app_focus";
field public static final String AUDIO_SERVICE = "audio";
field public static final String CAR_EXTRA_BROWSE_SERVICE_FOR_SESSION = "android.media.session.BROWSE_SERVICE";
@@ -54,6 +63,7 @@
field public static final String PERMISSION_READ_INTERIOR_LIGHTS = "android.car.permission.READ_CAR_INTERIOR_LIGHTS";
field public static final String PERMISSION_READ_STEERING_STATE = "android.car.permission.READ_CAR_STEERING";
field public static final String PERMISSION_SPEED = "android.car.permission.CAR_SPEED";
+ field @Deprecated public static final int PLATFORM_VERSION_MINOR_INT;
field public static final String POWER_SERVICE = "power";
field public static final String PROPERTY_SERVICE = "property";
field @Deprecated public static final String SENSOR_SERVICE = "sensor";
@@ -143,6 +153,19 @@
field public int zoneId;
}
+ public final class CarVersion extends android.car.ApiVersion<android.car.CarVersion> implements android.os.Parcelable {
+ method public int describeContents();
+ method @NonNull public static android.car.CarVersion forMajorAndMinorVersions(int, int);
+ method @NonNull public static android.car.CarVersion forMajorVersion(int);
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.car.CarVersion> CREATOR;
+ }
+
+ public static class CarVersion.VERSION_CODES {
+ field @NonNull public static final android.car.CarVersion TIRAMISU_0;
+ field @NonNull public static final android.car.CarVersion TIRAMISU_1;
+ }
+
@Deprecated public final class EvConnectorType {
field @Deprecated public static final int CHADEMO = 3; // 0x3
field @Deprecated public static final int COMBO_1 = 4; // 0x4
@@ -175,6 +198,32 @@
field public static final int UNLEADED = 1; // 0x1
}
+ public final class GsrComplianceType {
+ field public static final int GSR_COMPLIANCE_TYPE_NOT_REQUIRED = 0; // 0x0
+ field public static final int GSR_COMPLIANCE_TYPE_REQUIRED_V1 = 1; // 0x1
+ }
+
+ public final class PlatformVersion extends android.car.ApiVersion<android.car.PlatformVersion> implements android.os.Parcelable {
+ method public int describeContents();
+ method @NonNull public static android.car.PlatformVersion forMajorAndMinorVersions(int, int);
+ method @NonNull public static android.car.PlatformVersion forMajorVersion(int);
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.car.PlatformVersion> CREATOR;
+ }
+
+ public static class PlatformVersion.VERSION_CODES {
+ field @NonNull public static final android.car.PlatformVersion TIRAMISU_0;
+ field @NonNull public static final android.car.PlatformVersion TIRAMISU_1;
+ }
+
+ public final class PlatformVersionMismatchException extends java.lang.UnsupportedOperationException implements android.os.Parcelable {
+ ctor public PlatformVersionMismatchException(@NonNull android.car.PlatformVersion);
+ method public int describeContents();
+ method @NonNull public android.car.PlatformVersion getMinimumPlatformApiVersion();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.car.PlatformVersionMismatchException> CREATOR;
+ }
+
public final class PortLocationType {
field public static final int FRONT = 5; // 0x5
field public static final int FRONT_LEFT = 1; // 0x1
@@ -288,6 +337,7 @@
field @RequiresPermission(android.car.Car.PERMISSION_ENERGY) public static final int FUEL_LEVEL_LOW = 287310853; // 0x11200405
field @RequiresPermission.Read(@androidx.annotation.RequiresPermission(android.car.Car.PERMISSION_READ_DISPLAY_UNITS)) @RequiresPermission.Write(@androidx.annotation.RequiresPermission(allOf={android.car.Car.PERMISSION_CONTROL_DISPLAY_UNITS, "android.car.permission.CAR_VENDOR_EXTENSION"})) public static final int FUEL_VOLUME_DISPLAY_UNITS = 289408513; // 0x11400601
field @RequiresPermission(android.car.Car.PERMISSION_POWERTRAIN) public static final int GEAR_SELECTION = 289408000; // 0x11400400
+ field @RequiresPermission.Read(@androidx.annotation.RequiresPermission(android.car.Car.PERMISSION_CAR_INFO)) public static final int GENERAL_SAFETY_REGULATION_COMPLIANCE = 289410887; // 0x11400f47
field @RequiresPermission("android.car.permission.CAR_EXTERIOR_LIGHTS") public static final int HAZARD_LIGHTS_STATE = 289410563; // 0x11400e03
field @RequiresPermission("android.car.permission.CONTROL_CAR_EXTERIOR_LIGHTS") public static final int HAZARD_LIGHTS_SWITCH = 289410579; // 0x11400e13
field @RequiresPermission("android.car.permission.CAR_EXTERIOR_LIGHTS") public static final int HEADLIGHTS_STATE = 289410560; // 0x11400e00
@@ -425,9 +475,11 @@
package android.car.content.pm {
public final class CarPackageManager {
+ method @NonNull public android.car.CarVersion getTargetCarVersion();
method public boolean isActivityDistractionOptimized(String, String);
method public boolean isPendingIntentDistractionOptimized(@NonNull android.app.PendingIntent);
method public boolean isServiceDistractionOptimized(String, String);
+ field public static final String MANIFEST_METADATA_TARGET_CAR_VERSION = "android.car.targetCarVersion";
}
}
diff --git a/car-lib-module/api/system-current.txt b/car-lib-module/api/system-current.txt
index 0730f08..2ffe202 100644
--- a/car-lib-module/api/system-current.txt
+++ b/car-lib-module/api/system-current.txt
@@ -20,12 +20,14 @@
field public static final String ACCESS_PRIVATE_DISPLAY_ID = "android.car.permission.ACCESS_PRIVATE_DISPLAY_ID";
field @Deprecated public static final String CABIN_SERVICE = "cabin";
field public static final String CAR_ACTIVITY_SERVICE = "car_activity_service";
+ field public static final String CAR_BUGREPORT_SERVICE = "car_bugreport";
field public static final String CAR_DEVICE_POLICY_SERVICE = "car_device_policy_service";
field public static final String CAR_DRIVING_STATE_SERVICE = "drivingstate";
field public static final String CAR_EVS_SERVICE = "car_evs_service";
field public static final String CAR_EXTRA_CLUSTER_ACTIVITY_STATE = "android.car.cluster.ClusterActivityState";
field public static final String CAR_INPUT_SERVICE = "android.car.input";
field public static final String CAR_MEDIA_SERVICE = "car_media";
+ field public static final String CAR_PERFORMANCE_SERVICE = "car_performance";
field public static final String CAR_TELEMETRY_SERVICE = "car_telemetry_service";
field public static final String CAR_USER_SERVICE = "car_user_service";
field public static final String DIAGNOSTIC_SERVICE = "diagnostic";
@@ -48,6 +50,7 @@
field public static final String PERMISSION_CAR_PROJECTION = "android.car.permission.CAR_PROJECTION";
field public static final String PERMISSION_CAR_PROJECTION_STATUS = "android.car.permission.ACCESS_CAR_PROJECTION_STATUS";
field public static final String PERMISSION_CAR_TEST_SERVICE = "android.car.permission.CAR_TEST_SERVICE";
+ field public static final String PERMISSION_CAR_UX_RESTRICTIONS_CONFIGURATION = "android.car.permission.CAR_UX_RESTRICTIONS_CONFIGURATION";
field public static final String PERMISSION_COLLECT_CAR_WATCHDOG_METRICS = "android.car.permission.COLLECT_CAR_WATCHDOG_METRICS";
field public static final String PERMISSION_CONTROL_APP_BLOCKING = "android.car.permission.CONTROL_APP_BLOCKING";
field public static final String PERMISSION_CONTROL_CAR_APP_LAUNCH = "android.car.permission.CONTROL_CAR_APP_LAUNCH";
@@ -65,6 +68,7 @@
field public static final String PERMISSION_CONTROL_EXTERIOR_LIGHTS = "android.car.permission.CONTROL_CAR_EXTERIOR_LIGHTS";
field public static final String PERMISSION_CONTROL_SHUTDOWN_PROCESS = "android.car.permission.CONTROL_SHUTDOWN_PROCESS";
field public static final String PERMISSION_EXTERIOR_LIGHTS = "android.car.permission.CAR_EXTERIOR_LIGHTS";
+ field public static final String PERMISSION_MANAGE_THREAD_PRIORITY = "android.car.permission.MANAGE_THREAD_PRIORITY";
field public static final String PERMISSION_MILEAGE = "android.car.permission.CAR_MILEAGE";
field @Deprecated public static final String PERMISSION_MOCK_VEHICLE_HAL = "android.car.permission.CAR_MOCK_VEHICLE_HAL";
field public static final String PERMISSION_MONITOR_CAR_EVS_STATUS = "android.car.permission.MONITOR_CAR_EVS_STATUS";
@@ -90,6 +94,22 @@
field @Deprecated public static final String VMS_SUBSCRIBER_SERVICE = "vehicle_map_subscriber_service";
}
+ public final class CarBugreportManager {
+ method @RequiresPermission(android.Manifest.permission.DUMP) public void cancelBugreport();
+ method @RequiresPermission(android.Manifest.permission.DUMP) public void requestBugreport(@NonNull android.os.ParcelFileDescriptor, @NonNull android.os.ParcelFileDescriptor, @NonNull android.car.CarBugreportManager.CarBugreportManagerCallback);
+ }
+
+ public abstract static class CarBugreportManager.CarBugreportManagerCallback {
+ ctor public CarBugreportManager.CarBugreportManagerCallback();
+ method public void onError(int);
+ method public void onFinished();
+ method public void onProgress(@FloatRange(from=0.0f, to=100.0f) float);
+ field public static final int CAR_BUGREPORT_DUMPSTATE_CONNECTION_FAILED = 3; // 0x3
+ field public static final int CAR_BUGREPORT_DUMPSTATE_FAILED = 1; // 0x1
+ field public static final int CAR_BUGREPORT_IN_PROGRESS = 2; // 0x2
+ field public static final int CAR_BUGREPORT_SERVICE_NOT_AVAILABLE = 4; // 0x4
+ }
+
public class CarOccupantZoneManager {
method @RequiresPermission(android.car.Car.PERMISSION_CAR_CONTROL_AUDIO_SETTINGS) public int getAudioZoneIdForOccupant(@NonNull android.car.CarOccupantZoneManager.OccupantZoneInfo);
method @RequiresPermission(android.car.Car.ACCESS_PRIVATE_DISPLAY_ID) public int getDisplayIdForDriver(int);
@@ -187,6 +207,10 @@
field public static final int WRITE = 2; // 0x2
}
+ public final class VehiclePropertyIds {
+ field @RequiresPermission(android.car.Car.PERMISSION_CONTROL_CAR_CLIMATE) public static final int HVAC_ELECTRIC_DEFROSTER_ON = 320865556; // 0x13200514
+ }
+
public final class VehicleUnit {
field public static final int DEGREES = 128; // 0x80
field public static final int HERTZ = 3; // 0x3
@@ -261,6 +285,18 @@
method @Deprecated public void onClusterActivityStateChanged(String, android.os.Bundle);
}
+ public final class ClusterActivityState {
+ method @NonNull public static android.car.cluster.ClusterActivityState create(boolean, @NonNull android.graphics.Rect);
+ method @NonNull public static android.car.cluster.ClusterActivityState fromBundle(@NonNull android.os.Bundle);
+ method @Nullable public android.os.Bundle getExtras();
+ method @Nullable public android.graphics.Rect getUnobscuredBounds();
+ method public boolean isVisible();
+ method @NonNull public android.car.cluster.ClusterActivityState setExtras(@NonNull android.os.Bundle);
+ method @NonNull public android.car.cluster.ClusterActivityState setUnobscuredBounds(@NonNull android.graphics.Rect);
+ method @NonNull public android.car.cluster.ClusterActivityState setVisible(boolean);
+ method @NonNull public android.os.Bundle toBundle();
+ }
+
}
package android.car.cluster.renderer {
@@ -285,6 +321,8 @@
method @MainThread public void onKeyEvent(@NonNull android.view.KeyEvent);
method @MainThread public void onNavigationComponentLaunched();
method @MainThread public void onNavigationComponentReleased();
+ method public void setClusterActivityLaunchOptions(@NonNull android.app.ActivityOptions);
+ method public void setClusterActivityState(@NonNull android.car.cluster.ClusterActivityState);
method public boolean startFixedActivityModeForDisplayAndUser(@NonNull android.content.Intent, @NonNull android.app.ActivityOptions, int);
method protected boolean startNavigationActivity(@NonNull android.content.ComponentName);
method public void stopFixedActivityMode(int);
@@ -334,6 +372,7 @@
}
public final class CarPackageManager {
+ method @NonNull @RequiresPermission(android.Manifest.permission.QUERY_ALL_PACKAGES) public android.car.CarVersion getTargetCarVersion(@NonNull String) throws android.content.pm.PackageManager.NameNotFoundException;
method public boolean isActivityBackedBySafeActivity(android.content.ComponentName);
method @Deprecated public void setAppBlockingPolicy(String, android.car.content.pm.CarAppBlockingPolicy, int);
field @Deprecated public static final int FLAG_SET_POLICY_ADD = 2; // 0x2
@@ -632,6 +671,28 @@
method public void onDrivingStateChanged(android.car.drivingstate.CarDrivingStateEvent);
}
+ public final class CarUxRestrictionsConfiguration implements android.os.Parcelable {
+ method public int describeContents();
+ method @Nullable public Integer getPhysicalPort();
+ method @NonNull public android.car.drivingstate.CarUxRestrictions getUxRestrictions(int, float);
+ method @NonNull public android.car.drivingstate.CarUxRestrictions getUxRestrictions(int, @FloatRange(from=0.0f) float, @NonNull String);
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.car.drivingstate.CarUxRestrictionsConfiguration> CREATOR;
+ }
+
+ public final class CarUxRestrictionsManager {
+ method @Nullable @RequiresPermission(android.car.Car.PERMISSION_CAR_UX_RESTRICTIONS_CONFIGURATION) public java.util.List<android.car.drivingstate.CarUxRestrictionsConfiguration> getConfigs();
+ method @Nullable public android.car.drivingstate.CarUxRestrictions getCurrentCarUxRestrictions(int);
+ method @NonNull @RequiresPermission(android.car.Car.PERMISSION_CAR_UX_RESTRICTIONS_CONFIGURATION) public String getRestrictionMode();
+ method @Nullable @RequiresPermission(android.car.Car.PERMISSION_CAR_UX_RESTRICTIONS_CONFIGURATION) public java.util.List<android.car.drivingstate.CarUxRestrictionsConfiguration> getStagedConfigs();
+ method public void onCarDisconnected();
+ method @RequiresPermission(android.car.Car.PERMISSION_CAR_UX_RESTRICTIONS_CONFIGURATION) public boolean saveUxRestrictionsConfigurationForNextBoot(@NonNull java.util.List<android.car.drivingstate.CarUxRestrictionsConfiguration>);
+ method @RequiresPermission(android.car.Car.PERMISSION_CAR_UX_RESTRICTIONS_CONFIGURATION) public boolean saveUxRestrictionsConfigurationForNextBoot(@NonNull android.car.drivingstate.CarUxRestrictionsConfiguration);
+ method public void setListener(int, @NonNull android.car.drivingstate.CarUxRestrictionsManager.OnUxRestrictionsChangedListener);
+ method @RequiresPermission(android.car.Car.PERMISSION_CAR_UX_RESTRICTIONS_CONFIGURATION) public boolean setRestrictionMode(@NonNull String);
+ field public static final String UX_RESTRICTION_MODE_BASELINE = "baseline";
+ }
+
}
package android.car.evs {
@@ -1076,6 +1137,32 @@
}
+package android.car.os {
+
+ public final class CarPerformanceManager {
+ method @NonNull @RequiresPermission(android.car.Car.PERMISSION_MANAGE_THREAD_PRIORITY) public android.car.os.ThreadPolicyWithPriority getThreadPriority();
+ method @RequiresPermission(android.car.Car.PERMISSION_MANAGE_THREAD_PRIORITY) public void setThreadPriority(@NonNull android.car.os.ThreadPolicyWithPriority) throws android.car.os.CarPerformanceManager.SetSchedulerFailedException;
+ }
+
+ public static final class CarPerformanceManager.SetSchedulerFailedException extends java.lang.Exception {
+ }
+
+ public final class ThreadPolicyWithPriority implements android.os.Parcelable {
+ ctor public ThreadPolicyWithPriority(int, @IntRange(from=0, to=99) int);
+ method public int describeContents();
+ method public int getPolicy();
+ method @IntRange(from=0, to=99) public int getPriority();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.car.os.ThreadPolicyWithPriority> CREATOR;
+ field public static final int PRIORITY_MAX = 99; // 0x63
+ field public static final int PRIORITY_MIN = 1; // 0x1
+ field public static final int SCHED_DEFAULT = 0; // 0x0
+ field public static final int SCHED_FIFO = 1; // 0x1
+ field public static final int SCHED_RR = 2; // 0x2
+ }
+
+}
+
package android.car.projection {
public class ProjectionOptions {
@@ -1316,6 +1403,8 @@
method @RequiresPermission(anyOf={android.Manifest.permission.INTERACT_ACROSS_USERS, android.Manifest.permission.INTERACT_ACROSS_USERS_FULL}) public void addListener(@NonNull java.util.concurrent.Executor, @NonNull android.car.user.CarUserManager.UserLifecycleListener);
method @RequiresPermission(anyOf={android.Manifest.permission.INTERACT_ACROSS_USERS, android.Manifest.permission.INTERACT_ACROSS_USERS_FULL}) public void addListener(@NonNull java.util.concurrent.Executor, @NonNull android.car.user.UserLifecycleEventFilter, @NonNull android.car.user.CarUserManager.UserLifecycleListener);
method @RequiresPermission(anyOf={android.Manifest.permission.INTERACT_ACROSS_USERS, android.Manifest.permission.INTERACT_ACROSS_USERS_FULL}) public void removeListener(@NonNull android.car.user.CarUserManager.UserLifecycleListener);
+ field public static final int USER_LIFECYCLE_EVENT_TYPE_CREATED = 8; // 0x8
+ field public static final int USER_LIFECYCLE_EVENT_TYPE_REMOVED = 9; // 0x9
field public static final int USER_LIFECYCLE_EVENT_TYPE_STARTING = 1; // 0x1
field public static final int USER_LIFECYCLE_EVENT_TYPE_STOPPED = 6; // 0x6
field public static final int USER_LIFECYCLE_EVENT_TYPE_STOPPING = 5; // 0x5
diff --git a/car-lib-module/api/test-current.txt b/car-lib-module/api/test-current.txt
index 8219404..bcbc685 100644
--- a/car-lib-module/api/test-current.txt
+++ b/car-lib-module/api/test-current.txt
@@ -5,6 +5,8 @@
field public static final String CAR_DEVICE_POLICY_SERVICE = "car_device_policy_service";
field public static final String CAR_TELEMETRY_SERVICE = "car_telemetry_service";
field public static final String CAR_USER_SERVICE = "car_user_service";
+ field @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.TIRAMISU_1, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.TIRAMISU_0) public static final String PROPERTY_EMULATED_PLATFORM_VERSION_MAJOR = "com.android.car.internal.debug.platform_major_version";
+ field @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.TIRAMISU_1, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.TIRAMISU_0) public static final String PROPERTY_EMULATED_PLATFORM_VERSION_MINOR = "com.android.car.internal.debug.platform_minor_version";
}
public final class CarAppFocusManager {
@@ -81,6 +83,27 @@
}
+package android.car.annotation {
+
+ @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.RUNTIME) @java.lang.annotation.Target({java.lang.annotation.ElementType.ANNOTATION_TYPE, java.lang.annotation.ElementType.FIELD, java.lang.annotation.ElementType.TYPE, java.lang.annotation.ElementType.METHOD}) public @interface ApiRequirements {
+ method public abstract android.car.annotation.ApiRequirements.CarVersion minCarVersion();
+ method public abstract android.car.annotation.ApiRequirements.PlatformVersion minPlatformVersion();
+ }
+
+ public enum ApiRequirements.CarVersion {
+ method public android.car.CarVersion get();
+ enum_constant public static final android.car.annotation.ApiRequirements.CarVersion TIRAMISU_0;
+ enum_constant public static final android.car.annotation.ApiRequirements.CarVersion TIRAMISU_1;
+ }
+
+ public enum ApiRequirements.PlatformVersion {
+ method public android.car.PlatformVersion get();
+ enum_constant public static final android.car.annotation.ApiRequirements.PlatformVersion TIRAMISU_0;
+ enum_constant public static final android.car.annotation.ApiRequirements.PlatformVersion TIRAMISU_1;
+ }
+
+}
+
package android.car.app {
public final class CarActivityManager {
diff --git a/car-lib/Android.bp b/car-lib/Android.bp
index cfa13f2..dbaf08a 100644
--- a/car-lib/Android.bp
+++ b/car-lib/Android.bp
@@ -186,7 +186,8 @@
name: "android.car-test-stubs-docs",
defaults: ["android.car-docs-default"],
args: "--hide HiddenSuperclass --hide UnavailableSymbol --stub-packages android.car* " +
- "--show-annotation android.annotation.TestApi ",
+ "--show-annotation android.annotation.TestApi " +
+ "--show-annotation android.annotation.SystemApi",
installable: false,
check_api: {
current: {
diff --git a/car-lib/OWNERS b/car-lib/OWNERS
new file mode 100644
index 0000000..8ce0d29
--- /dev/null
+++ b/car-lib/OWNERS
@@ -0,0 +1,36 @@
+# App
+per-file src/android/car/app/* = ycheo@google.com
+
+# AppFocus
+per-file src/android/car/app/IAppFocus* = ycheo@google.com
+
+# Audio
+per-file src/android/car/media/CarAudio*.java = oscarazu@google.com, ericjeong@google.com
+per-file src/android/car/media/ICarAudio.aidl = oscarazu@google.com, ericjeong@google.com
+per-file src/android/car/media/ICarVolumeCallback.aidl = oscarazu@google.com, ericjeong@google.com
+
+# Cluster
+per-file src/android/car/cluster/* = ycheo@google.com
+
+# Input
+per-file src/android/car/input/* = ycheo@google.com
+
+# Navigation
+per-file src/android/car/navigation/* = ycheo@google.com
+
+# OccupantZone
+per-file src/android/car/CarOccupantZoneManager.* = ycheo@google.com, oscarazu@google.com, ericjeong@google.com
+per-file src/android/car/ICarOccupantZone* = ycheo@google.com, oscarazu@google.com, ericjeong@google.com
+
+# PackageManager
+per-file src/android/car/content/pm/* = ycheo@google.com
+
+# Power
+per-file src/android/car/hardware/power/* = ericjeong@google.com
+
+# StorageMonitoring
+per-file src/android/car/storagemonitoring/* = lakshmana@google.com
+
+# Watchdog
+per-file src/android/car/watchdog/* = lakshmana@google.com
+per-file src/android/car/os/* = lakshmana@google.com
diff --git a/car-lib/api/current.txt b/car-lib/api/current.txt
index 38f60eb..05464e4 100644
--- a/car-lib/api/current.txt
+++ b/car-lib/api/current.txt
@@ -1,6 +1,13 @@
// Signature format: 2.0
package android.car {
+ public abstract class ApiVersion<T extends android.car.ApiVersion<?>> {
+ method public final int getMajorVersion();
+ method public final int getMinorVersion();
+ method public final boolean isAtLeast(@NonNull T);
+ method @NonNull public final String toString();
+ }
+
public final class Car {
method @Deprecated public void connect() throws java.lang.IllegalStateException;
method @Deprecated public static android.car.Car createCar(android.content.Context, android.content.ServiceConnection, @Nullable android.os.Handler);
@@ -11,15 +18,17 @@
method public void disconnect();
method @Deprecated public int getCarConnectionType();
method @Nullable public Object getCarManager(String);
- method public static boolean isApiAndPlatformVersionAtLeast(int, int);
- method public static boolean isApiAndPlatformVersionAtLeast(int, int, int);
- method public static boolean isApiVersionAtLeast(int);
- method public static boolean isApiVersionAtLeast(int, int);
+ method @NonNull public static android.car.CarVersion getCarVersion();
+ method @NonNull public static android.car.PlatformVersion getPlatformVersion();
+ method @Deprecated public static boolean isApiAndPlatformVersionAtLeast(int, int);
+ method @Deprecated public static boolean isApiAndPlatformVersionAtLeast(int, int, int);
+ method @Deprecated public static boolean isApiVersionAtLeast(int);
+ method @Deprecated public static boolean isApiVersionAtLeast(int, int);
method public boolean isConnected();
method public boolean isConnecting();
method public boolean isFeatureEnabled(@NonNull String);
- field public static final int API_VERSION_MAJOR_INT = 33; // 0x21
- field public static final int API_VERSION_MINOR_INT = 0; // 0x0
+ field @Deprecated public static final int API_VERSION_MAJOR_INT = 33; // 0x21
+ field @Deprecated public static final int API_VERSION_MINOR_INT = 1; // 0x1
field public static final String APP_FOCUS_SERVICE = "app_focus";
field public static final String AUDIO_SERVICE = "audio";
field public static final String CAR_EXTRA_BROWSE_SERVICE_FOR_SESSION = "android.media.session.BROWSE_SERVICE";
@@ -54,6 +63,7 @@
field public static final String PERMISSION_READ_INTERIOR_LIGHTS = "android.car.permission.READ_CAR_INTERIOR_LIGHTS";
field public static final String PERMISSION_READ_STEERING_STATE = "android.car.permission.READ_CAR_STEERING";
field public static final String PERMISSION_SPEED = "android.car.permission.CAR_SPEED";
+ field @Deprecated public static final int PLATFORM_VERSION_MINOR_INT;
field public static final String POWER_SERVICE = "power";
field public static final String PROPERTY_SERVICE = "property";
field @Deprecated public static final String SENSOR_SERVICE = "sensor";
@@ -143,6 +153,19 @@
field public int zoneId;
}
+ public final class CarVersion extends android.car.ApiVersion<android.car.CarVersion> implements android.os.Parcelable {
+ method public int describeContents();
+ method @NonNull public static android.car.CarVersion forMajorAndMinorVersions(int, int);
+ method @NonNull public static android.car.CarVersion forMajorVersion(int);
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.car.CarVersion> CREATOR;
+ }
+
+ public static class CarVersion.VERSION_CODES {
+ field @NonNull public static final android.car.CarVersion TIRAMISU_0;
+ field @NonNull public static final android.car.CarVersion TIRAMISU_1;
+ }
+
@Deprecated public final class EvConnectorType {
field @Deprecated public static final int CHADEMO = 3; // 0x3
field @Deprecated public static final int COMBO_1 = 4; // 0x4
@@ -175,6 +198,32 @@
field public static final int UNLEADED = 1; // 0x1
}
+ public final class GsrComplianceType {
+ field public static final int GSR_COMPLIANCE_TYPE_NOT_REQUIRED = 0; // 0x0
+ field public static final int GSR_COMPLIANCE_TYPE_REQUIRED_V1 = 1; // 0x1
+ }
+
+ public final class PlatformVersion extends android.car.ApiVersion<android.car.PlatformVersion> implements android.os.Parcelable {
+ method public int describeContents();
+ method @NonNull public static android.car.PlatformVersion forMajorAndMinorVersions(int, int);
+ method @NonNull public static android.car.PlatformVersion forMajorVersion(int);
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.car.PlatformVersion> CREATOR;
+ }
+
+ public static class PlatformVersion.VERSION_CODES {
+ field @NonNull public static final android.car.PlatformVersion TIRAMISU_0;
+ field @NonNull public static final android.car.PlatformVersion TIRAMISU_1;
+ }
+
+ public final class PlatformVersionMismatchException extends java.lang.UnsupportedOperationException implements android.os.Parcelable {
+ ctor public PlatformVersionMismatchException(@NonNull android.car.PlatformVersion);
+ method public int describeContents();
+ method @NonNull public android.car.PlatformVersion getMinimumPlatformApiVersion();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.car.PlatformVersionMismatchException> CREATOR;
+ }
+
public final class PortLocationType {
field public static final int FRONT = 5; // 0x5
field public static final int FRONT_LEFT = 1; // 0x1
@@ -288,6 +337,7 @@
field @RequiresPermission(android.car.Car.PERMISSION_ENERGY) public static final int FUEL_LEVEL_LOW = 287310853; // 0x11200405
field @RequiresPermission.Read(@androidx.annotation.RequiresPermission(android.car.Car.PERMISSION_READ_DISPLAY_UNITS)) @RequiresPermission.Write(@androidx.annotation.RequiresPermission(allOf={android.car.Car.PERMISSION_CONTROL_DISPLAY_UNITS, "android.car.permission.CAR_VENDOR_EXTENSION"})) public static final int FUEL_VOLUME_DISPLAY_UNITS = 289408513; // 0x11400601
field @RequiresPermission(android.car.Car.PERMISSION_POWERTRAIN) public static final int GEAR_SELECTION = 289408000; // 0x11400400
+ field @RequiresPermission.Read(@androidx.annotation.RequiresPermission(android.car.Car.PERMISSION_CAR_INFO)) public static final int GENERAL_SAFETY_REGULATION_COMPLIANCE = 289410887; // 0x11400f47
field @RequiresPermission("android.car.permission.CAR_EXTERIOR_LIGHTS") public static final int HAZARD_LIGHTS_STATE = 289410563; // 0x11400e03
field @RequiresPermission("android.car.permission.CONTROL_CAR_EXTERIOR_LIGHTS") public static final int HAZARD_LIGHTS_SWITCH = 289410579; // 0x11400e13
field @RequiresPermission("android.car.permission.CAR_EXTERIOR_LIGHTS") public static final int HEADLIGHTS_STATE = 289410560; // 0x11400e00
@@ -425,9 +475,11 @@
package android.car.content.pm {
public final class CarPackageManager {
+ method @NonNull public android.car.CarVersion getTargetCarVersion();
method public boolean isActivityDistractionOptimized(String, String);
method public boolean isPendingIntentDistractionOptimized(@NonNull android.app.PendingIntent);
method public boolean isServiceDistractionOptimized(String, String);
+ field public static final String MANIFEST_METADATA_TARGET_CAR_VERSION = "android.car.targetCarVersion";
}
}
diff --git a/car-lib/api/lint-baseline.txt b/car-lib/api/lint-baseline.txt
index f0531f5..3538be6 100644
--- a/car-lib/api/lint-baseline.txt
+++ b/car-lib/api/lint-baseline.txt
@@ -5,6 +5,10 @@
Callbacks must be abstract class instead of interface to enable extension in future API levels: CarPropertyEventCallback
+CompileTimeConstant: android.car.Car#PLATFORM_VERSION_MINOR_INT:
+ All constants must be defined at compile time: android.car.Car#PLATFORM_VERSION_MINOR_INT
+
+
ConcreteCollection: android.car.hardware.property.CarPropertyManager#getPropertyList(android.util.ArraySet<java.lang.Integer>) parameter #0:
Parameter type is concrete collection (`android.util.ArraySet`); must be higher-level interface
@@ -183,7 +187,7 @@
Fully-static utility classes must not have constructor
-VisiblySynchronized: PsiThisExpression:this:
+VisiblySynchronized: PsiThisExpression:
Internal locks must not be exposed (synchronizing on this or class is still externally observable): method android.car.CarAppFocusManager.addFocusListener(android.car.CarAppFocusManager.OnAppFocusChangedListener,int)
VisiblySynchronized: android.car.CarAppFocusManager#abandonAppFocus(android.car.CarAppFocusManager.OnAppFocusOwnershipCallback):
Internal locks must not be exposed (synchronizing on this or class is still externally observable): method android.car.CarAppFocusManager.abandonAppFocus(android.car.CarAppFocusManager.OnAppFocusOwnershipCallback)
diff --git a/car-lib/api/system-current.txt b/car-lib/api/system-current.txt
index 0730f08..2ffe202 100644
--- a/car-lib/api/system-current.txt
+++ b/car-lib/api/system-current.txt
@@ -20,12 +20,14 @@
field public static final String ACCESS_PRIVATE_DISPLAY_ID = "android.car.permission.ACCESS_PRIVATE_DISPLAY_ID";
field @Deprecated public static final String CABIN_SERVICE = "cabin";
field public static final String CAR_ACTIVITY_SERVICE = "car_activity_service";
+ field public static final String CAR_BUGREPORT_SERVICE = "car_bugreport";
field public static final String CAR_DEVICE_POLICY_SERVICE = "car_device_policy_service";
field public static final String CAR_DRIVING_STATE_SERVICE = "drivingstate";
field public static final String CAR_EVS_SERVICE = "car_evs_service";
field public static final String CAR_EXTRA_CLUSTER_ACTIVITY_STATE = "android.car.cluster.ClusterActivityState";
field public static final String CAR_INPUT_SERVICE = "android.car.input";
field public static final String CAR_MEDIA_SERVICE = "car_media";
+ field public static final String CAR_PERFORMANCE_SERVICE = "car_performance";
field public static final String CAR_TELEMETRY_SERVICE = "car_telemetry_service";
field public static final String CAR_USER_SERVICE = "car_user_service";
field public static final String DIAGNOSTIC_SERVICE = "diagnostic";
@@ -48,6 +50,7 @@
field public static final String PERMISSION_CAR_PROJECTION = "android.car.permission.CAR_PROJECTION";
field public static final String PERMISSION_CAR_PROJECTION_STATUS = "android.car.permission.ACCESS_CAR_PROJECTION_STATUS";
field public static final String PERMISSION_CAR_TEST_SERVICE = "android.car.permission.CAR_TEST_SERVICE";
+ field public static final String PERMISSION_CAR_UX_RESTRICTIONS_CONFIGURATION = "android.car.permission.CAR_UX_RESTRICTIONS_CONFIGURATION";
field public static final String PERMISSION_COLLECT_CAR_WATCHDOG_METRICS = "android.car.permission.COLLECT_CAR_WATCHDOG_METRICS";
field public static final String PERMISSION_CONTROL_APP_BLOCKING = "android.car.permission.CONTROL_APP_BLOCKING";
field public static final String PERMISSION_CONTROL_CAR_APP_LAUNCH = "android.car.permission.CONTROL_CAR_APP_LAUNCH";
@@ -65,6 +68,7 @@
field public static final String PERMISSION_CONTROL_EXTERIOR_LIGHTS = "android.car.permission.CONTROL_CAR_EXTERIOR_LIGHTS";
field public static final String PERMISSION_CONTROL_SHUTDOWN_PROCESS = "android.car.permission.CONTROL_SHUTDOWN_PROCESS";
field public static final String PERMISSION_EXTERIOR_LIGHTS = "android.car.permission.CAR_EXTERIOR_LIGHTS";
+ field public static final String PERMISSION_MANAGE_THREAD_PRIORITY = "android.car.permission.MANAGE_THREAD_PRIORITY";
field public static final String PERMISSION_MILEAGE = "android.car.permission.CAR_MILEAGE";
field @Deprecated public static final String PERMISSION_MOCK_VEHICLE_HAL = "android.car.permission.CAR_MOCK_VEHICLE_HAL";
field public static final String PERMISSION_MONITOR_CAR_EVS_STATUS = "android.car.permission.MONITOR_CAR_EVS_STATUS";
@@ -90,6 +94,22 @@
field @Deprecated public static final String VMS_SUBSCRIBER_SERVICE = "vehicle_map_subscriber_service";
}
+ public final class CarBugreportManager {
+ method @RequiresPermission(android.Manifest.permission.DUMP) public void cancelBugreport();
+ method @RequiresPermission(android.Manifest.permission.DUMP) public void requestBugreport(@NonNull android.os.ParcelFileDescriptor, @NonNull android.os.ParcelFileDescriptor, @NonNull android.car.CarBugreportManager.CarBugreportManagerCallback);
+ }
+
+ public abstract static class CarBugreportManager.CarBugreportManagerCallback {
+ ctor public CarBugreportManager.CarBugreportManagerCallback();
+ method public void onError(int);
+ method public void onFinished();
+ method public void onProgress(@FloatRange(from=0.0f, to=100.0f) float);
+ field public static final int CAR_BUGREPORT_DUMPSTATE_CONNECTION_FAILED = 3; // 0x3
+ field public static final int CAR_BUGREPORT_DUMPSTATE_FAILED = 1; // 0x1
+ field public static final int CAR_BUGREPORT_IN_PROGRESS = 2; // 0x2
+ field public static final int CAR_BUGREPORT_SERVICE_NOT_AVAILABLE = 4; // 0x4
+ }
+
public class CarOccupantZoneManager {
method @RequiresPermission(android.car.Car.PERMISSION_CAR_CONTROL_AUDIO_SETTINGS) public int getAudioZoneIdForOccupant(@NonNull android.car.CarOccupantZoneManager.OccupantZoneInfo);
method @RequiresPermission(android.car.Car.ACCESS_PRIVATE_DISPLAY_ID) public int getDisplayIdForDriver(int);
@@ -187,6 +207,10 @@
field public static final int WRITE = 2; // 0x2
}
+ public final class VehiclePropertyIds {
+ field @RequiresPermission(android.car.Car.PERMISSION_CONTROL_CAR_CLIMATE) public static final int HVAC_ELECTRIC_DEFROSTER_ON = 320865556; // 0x13200514
+ }
+
public final class VehicleUnit {
field public static final int DEGREES = 128; // 0x80
field public static final int HERTZ = 3; // 0x3
@@ -261,6 +285,18 @@
method @Deprecated public void onClusterActivityStateChanged(String, android.os.Bundle);
}
+ public final class ClusterActivityState {
+ method @NonNull public static android.car.cluster.ClusterActivityState create(boolean, @NonNull android.graphics.Rect);
+ method @NonNull public static android.car.cluster.ClusterActivityState fromBundle(@NonNull android.os.Bundle);
+ method @Nullable public android.os.Bundle getExtras();
+ method @Nullable public android.graphics.Rect getUnobscuredBounds();
+ method public boolean isVisible();
+ method @NonNull public android.car.cluster.ClusterActivityState setExtras(@NonNull android.os.Bundle);
+ method @NonNull public android.car.cluster.ClusterActivityState setUnobscuredBounds(@NonNull android.graphics.Rect);
+ method @NonNull public android.car.cluster.ClusterActivityState setVisible(boolean);
+ method @NonNull public android.os.Bundle toBundle();
+ }
+
}
package android.car.cluster.renderer {
@@ -285,6 +321,8 @@
method @MainThread public void onKeyEvent(@NonNull android.view.KeyEvent);
method @MainThread public void onNavigationComponentLaunched();
method @MainThread public void onNavigationComponentReleased();
+ method public void setClusterActivityLaunchOptions(@NonNull android.app.ActivityOptions);
+ method public void setClusterActivityState(@NonNull android.car.cluster.ClusterActivityState);
method public boolean startFixedActivityModeForDisplayAndUser(@NonNull android.content.Intent, @NonNull android.app.ActivityOptions, int);
method protected boolean startNavigationActivity(@NonNull android.content.ComponentName);
method public void stopFixedActivityMode(int);
@@ -334,6 +372,7 @@
}
public final class CarPackageManager {
+ method @NonNull @RequiresPermission(android.Manifest.permission.QUERY_ALL_PACKAGES) public android.car.CarVersion getTargetCarVersion(@NonNull String) throws android.content.pm.PackageManager.NameNotFoundException;
method public boolean isActivityBackedBySafeActivity(android.content.ComponentName);
method @Deprecated public void setAppBlockingPolicy(String, android.car.content.pm.CarAppBlockingPolicy, int);
field @Deprecated public static final int FLAG_SET_POLICY_ADD = 2; // 0x2
@@ -632,6 +671,28 @@
method public void onDrivingStateChanged(android.car.drivingstate.CarDrivingStateEvent);
}
+ public final class CarUxRestrictionsConfiguration implements android.os.Parcelable {
+ method public int describeContents();
+ method @Nullable public Integer getPhysicalPort();
+ method @NonNull public android.car.drivingstate.CarUxRestrictions getUxRestrictions(int, float);
+ method @NonNull public android.car.drivingstate.CarUxRestrictions getUxRestrictions(int, @FloatRange(from=0.0f) float, @NonNull String);
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.car.drivingstate.CarUxRestrictionsConfiguration> CREATOR;
+ }
+
+ public final class CarUxRestrictionsManager {
+ method @Nullable @RequiresPermission(android.car.Car.PERMISSION_CAR_UX_RESTRICTIONS_CONFIGURATION) public java.util.List<android.car.drivingstate.CarUxRestrictionsConfiguration> getConfigs();
+ method @Nullable public android.car.drivingstate.CarUxRestrictions getCurrentCarUxRestrictions(int);
+ method @NonNull @RequiresPermission(android.car.Car.PERMISSION_CAR_UX_RESTRICTIONS_CONFIGURATION) public String getRestrictionMode();
+ method @Nullable @RequiresPermission(android.car.Car.PERMISSION_CAR_UX_RESTRICTIONS_CONFIGURATION) public java.util.List<android.car.drivingstate.CarUxRestrictionsConfiguration> getStagedConfigs();
+ method public void onCarDisconnected();
+ method @RequiresPermission(android.car.Car.PERMISSION_CAR_UX_RESTRICTIONS_CONFIGURATION) public boolean saveUxRestrictionsConfigurationForNextBoot(@NonNull java.util.List<android.car.drivingstate.CarUxRestrictionsConfiguration>);
+ method @RequiresPermission(android.car.Car.PERMISSION_CAR_UX_RESTRICTIONS_CONFIGURATION) public boolean saveUxRestrictionsConfigurationForNextBoot(@NonNull android.car.drivingstate.CarUxRestrictionsConfiguration);
+ method public void setListener(int, @NonNull android.car.drivingstate.CarUxRestrictionsManager.OnUxRestrictionsChangedListener);
+ method @RequiresPermission(android.car.Car.PERMISSION_CAR_UX_RESTRICTIONS_CONFIGURATION) public boolean setRestrictionMode(@NonNull String);
+ field public static final String UX_RESTRICTION_MODE_BASELINE = "baseline";
+ }
+
}
package android.car.evs {
@@ -1076,6 +1137,32 @@
}
+package android.car.os {
+
+ public final class CarPerformanceManager {
+ method @NonNull @RequiresPermission(android.car.Car.PERMISSION_MANAGE_THREAD_PRIORITY) public android.car.os.ThreadPolicyWithPriority getThreadPriority();
+ method @RequiresPermission(android.car.Car.PERMISSION_MANAGE_THREAD_PRIORITY) public void setThreadPriority(@NonNull android.car.os.ThreadPolicyWithPriority) throws android.car.os.CarPerformanceManager.SetSchedulerFailedException;
+ }
+
+ public static final class CarPerformanceManager.SetSchedulerFailedException extends java.lang.Exception {
+ }
+
+ public final class ThreadPolicyWithPriority implements android.os.Parcelable {
+ ctor public ThreadPolicyWithPriority(int, @IntRange(from=0, to=99) int);
+ method public int describeContents();
+ method public int getPolicy();
+ method @IntRange(from=0, to=99) public int getPriority();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.car.os.ThreadPolicyWithPriority> CREATOR;
+ field public static final int PRIORITY_MAX = 99; // 0x63
+ field public static final int PRIORITY_MIN = 1; // 0x1
+ field public static final int SCHED_DEFAULT = 0; // 0x0
+ field public static final int SCHED_FIFO = 1; // 0x1
+ field public static final int SCHED_RR = 2; // 0x2
+ }
+
+}
+
package android.car.projection {
public class ProjectionOptions {
@@ -1316,6 +1403,8 @@
method @RequiresPermission(anyOf={android.Manifest.permission.INTERACT_ACROSS_USERS, android.Manifest.permission.INTERACT_ACROSS_USERS_FULL}) public void addListener(@NonNull java.util.concurrent.Executor, @NonNull android.car.user.CarUserManager.UserLifecycleListener);
method @RequiresPermission(anyOf={android.Manifest.permission.INTERACT_ACROSS_USERS, android.Manifest.permission.INTERACT_ACROSS_USERS_FULL}) public void addListener(@NonNull java.util.concurrent.Executor, @NonNull android.car.user.UserLifecycleEventFilter, @NonNull android.car.user.CarUserManager.UserLifecycleListener);
method @RequiresPermission(anyOf={android.Manifest.permission.INTERACT_ACROSS_USERS, android.Manifest.permission.INTERACT_ACROSS_USERS_FULL}) public void removeListener(@NonNull android.car.user.CarUserManager.UserLifecycleListener);
+ field public static final int USER_LIFECYCLE_EVENT_TYPE_CREATED = 8; // 0x8
+ field public static final int USER_LIFECYCLE_EVENT_TYPE_REMOVED = 9; // 0x9
field public static final int USER_LIFECYCLE_EVENT_TYPE_STARTING = 1; // 0x1
field public static final int USER_LIFECYCLE_EVENT_TYPE_STOPPED = 6; // 0x6
field public static final int USER_LIFECYCLE_EVENT_TYPE_STOPPING = 5; // 0x5
diff --git a/car-lib/api/system-lint-baseline.txt b/car-lib/api/system-lint-baseline.txt
index 3940fbd..cb1a48d 100644
--- a/car-lib/api/system-lint-baseline.txt
+++ b/car-lib/api/system-lint-baseline.txt
@@ -33,6 +33,12 @@
Must avoid boxed primitives (`java.lang.Integer`)
+BuilderSetStyle: android.car.diagnostic.CarDiagnosticEvent.Builder#newFreezeFrameBuilder():
+ Builder methods names should use setFoo() / addFoo() / clearFoo() style: method android.car.diagnostic.CarDiagnosticEvent.Builder.newFreezeFrameBuilder()
+BuilderSetStyle: android.car.diagnostic.CarDiagnosticEvent.Builder#newLiveFrameBuilder():
+ Builder methods names should use setFoo() / addFoo() / clearFoo() style: method android.car.diagnostic.CarDiagnosticEvent.Builder.newLiveFrameBuilder()
+
+
CallbackInterface: android.car.hardware.CarVendorExtensionManager.CarVendorExtensionCallback:
Callbacks must be abstract class instead of interface to enable extension in future API levels: CarVendorExtensionCallback
CallbackInterface: android.car.hardware.cabin.CarCabinManager.CarCabinEventCallback:
@@ -75,13 +81,16 @@
Registration methods should have overload that accepts delivery Executor: `registerCallback`
ExecutorRegistration: android.car.hardware.hvac.CarHvacManager#registerCallback(android.car.hardware.hvac.CarHvacManager.CarHvacEventCallback):
Registration methods should have overload that accepts delivery Executor: `registerCallback`
-
+ExecutorRegistration: android.car.media.CarMediaManager#addMediaSourceListener(android.car.media.CarMediaManager.MediaSourceChangedListener, int):
+ Registration methods should have overload that accepts delivery Executor: `addMediaSourceListener`
ExecutorRegistration: android.car.storagemonitoring.CarStorageMonitoringManager#registerListener(android.car.storagemonitoring.CarStorageMonitoringManager.IoStatsListener):
Registration methods should have overload that accepts delivery Executor: `registerListener`
ExecutorRegistration: android.car.trust.CarTrustAgentEnrollmentManager#setBleCallback(android.car.trust.CarTrustAgentEnrollmentManager.CarTrustAgentBleCallback):
Registration methods should have overload that accepts delivery Executor: `setBleCallback`
ExecutorRegistration: android.car.trust.CarTrustAgentEnrollmentManager#setEnrollmentCallback(android.car.trust.CarTrustAgentEnrollmentManager.CarTrustAgentEnrollmentCallback):
Registration methods should have overload that accepts delivery Executor: `setEnrollmentCallback`
+ExecutorRegistration: android.car.watchdog.CarWatchdogManager#tellClientAlive(android.car.watchdog.CarWatchdogManager.CarWatchdogClientCallback, int):
+ Registration methods should have overload that accepts delivery Executor: `tellClientAlive`
HiddenSuperclass: android.car.CarAppFocusManager:
@@ -138,6 +147,12 @@
Intent extra constant name must be EXTRA_FOO: AUDIOFOCUS_EXTRA_RECEIVE_DUCKING_EVENTS
+ListenerLast: android.car.watchdog.CarWatchdogManager#registerClient(java.util.concurrent.Executor, android.car.watchdog.CarWatchdogManager.CarWatchdogClientCallback, int) parameter #2:
+ Listeners should always be at end of argument list (method `registerClient`)
+ListenerLast: android.car.watchdog.CarWatchdogManager#tellClientAlive(android.car.watchdog.CarWatchdogManager.CarWatchdogClientCallback, int) parameter #1:
+ Listeners should always be at end of argument list (method `tellClientAlive`)
+
+
MinMaxConstant: android.car.diagnostic.IntegerSensorIndex#MAX_AIR_FLOW_RATE_FROM_MASS_AIR_FLOW_SENSOR:
If min/max could change in future, make them dynamic methods: android.car.diagnostic.IntegerSensorIndex#MAX_AIR_FLOW_RATE_FROM_MASS_AIR_FLOW_SENSOR
MinMaxConstant: android.car.diagnostic.IntegerSensorIndex#MAX_FUEL_AIR_EQUIVALENCE_RATIO:
@@ -150,6 +165,30 @@
If min/max could change in future, make them dynamic methods: android.car.diagnostic.IntegerSensorIndex#MAX_OXYGEN_SENSOR_VOLTAGE
+MissingGetterMatchingBuilder: android.car.diagnostic.CarDiagnosticEvent.Builder#setDtc(String):
+ android.car.diagnostic.CarDiagnosticEvent does not declare a `getDtc()` method matching method android.car.diagnostic.CarDiagnosticEvent.Builder.setDtc(String)
+MissingGetterMatchingBuilder: android.car.diagnostic.CarDiagnosticEvent.Builder#setFloatValue(int, float):
+ android.car.diagnostic.CarDiagnosticEvent does not declare a `getFloatValue()` method matching method android.car.diagnostic.CarDiagnosticEvent.Builder.setFloatValue(int,float)
+MissingGetterMatchingBuilder: android.car.diagnostic.CarDiagnosticEvent.Builder#setIntValue(int, int):
+ android.car.diagnostic.CarDiagnosticEvent does not declare a `getIntValue()` method matching method android.car.diagnostic.CarDiagnosticEvent.Builder.setIntValue(int,int)
+MissingGetterMatchingBuilder: android.car.diagnostic.CarDiagnosticEvent.Builder#setTimeStamp(long):
+ android.car.diagnostic.CarDiagnosticEvent does not declare a `getTimeStamp()` method matching method android.car.diagnostic.CarDiagnosticEvent.Builder.setTimeStamp(long)
+MissingGetterMatchingBuilder: android.car.hardware.CarPropertyConfig.Builder#addArea(int):
+ android.car.hardware.CarPropertyConfig does not declare a `getAreas()` method matching method android.car.hardware.CarPropertyConfig.Builder.addArea(int)
+MissingGetterMatchingBuilder: android.car.hardware.CarPropertyConfig.Builder#addAreaConfig(int, T, T):
+ android.car.hardware.CarPropertyConfig does not declare a `getAreaConfigs()` method matching method android.car.hardware.CarPropertyConfig.Builder.addAreaConfig(int,T,T)
+MissingGetterMatchingBuilder: android.car.hardware.CarPropertyConfig.Builder#addAreas(int[]):
+ android.car.hardware.CarPropertyConfig does not declare a getter method matching method android.car.hardware.CarPropertyConfig.Builder.addAreas(int[]) (expected one of: [getAreas(), getAreases()])
+MissingGetterMatchingBuilder: android.car.hardware.CarPropertyConfig.Builder#setConfigString(String):
+ android.car.hardware.CarPropertyConfig does not declare a `getConfigString()` method matching method android.car.hardware.CarPropertyConfig.Builder.setConfigString(String)
+MissingGetterMatchingBuilder: android.car.projection.ProjectionStatus.Builder#addMobileDevice(android.car.projection.ProjectionStatus.MobileDevice):
+ android.car.projection.ProjectionStatus does not declare a `getMobileDevices()` method matching method android.car.projection.ProjectionStatus.Builder.addMobileDevice(android.car.projection.ProjectionStatus.MobileDevice)
+MissingGetterMatchingBuilder: android.car.projection.ProjectionStatus.Builder#setProjectionTransport(int):
+ android.car.projection.ProjectionStatus does not declare a `getProjectionTransport()` method matching method android.car.projection.ProjectionStatus.Builder.setProjectionTransport(int)
+MissingGetterMatchingBuilder: android.car.projection.ProjectionStatus.MobileDevice.Builder#addTransport(int):
+ android.car.projection.ProjectionStatus.MobileDevice does not declare a `getTransports()` method matching method android.car.projection.ProjectionStatus.MobileDevice.Builder.addTransport(int)
+
+
MissingNullability: android.car.AoapService#dump(java.io.FileDescriptor, java.io.PrintWriter, String[]) parameter #0:
Missing nullability on parameter `fd` in method `dump`
MissingNullability: android.car.AoapService#dump(java.io.FileDescriptor, java.io.PrintWriter, String[]) parameter #1:
@@ -604,6 +643,14 @@
Missing nullability on parameter `out` in method `writeToParcel`
+NullableCollection: android.car.cluster.ClusterActivityState#getExtras():
+ Return type of method android.car.cluster.ClusterActivityState.getExtras() is a nullable collection (`android.os.Bundle`); must be non-null
+NullableCollection: android.car.telemetry.CarTelemetryManager.MetricsReportCallback#onResult(String, android.os.PersistableBundle, byte[], int) parameter #1:
+ Type of parameter report in android.car.telemetry.CarTelemetryManager.MetricsReportCallback.onResult(String metricsConfigName, android.os.PersistableBundle report, byte[] telemetryError, int status) is a nullable collection (`android.os.PersistableBundle`); must be non-null
+NullableCollection: android.car.watchdog.CarWatchdogManager#getResourceOveruseConfigurations(int):
+ Return type of method android.car.watchdog.CarWatchdogManager.getResourceOveruseConfigurations(int) is a nullable collection (`java.util.List`); must be non-null
+
+
OnNameExpected: android.car.AoapService#canSwitchToAoap(android.hardware.usb.UsbDevice):
If implemented by developer, should follow the on<Something> style; otherwise consider marking final
OnNameExpected: android.car.AoapService#dump(java.io.FileDescriptor, java.io.PrintWriter, String[]):
@@ -614,10 +661,20 @@
If implemented by developer, should follow the on<Something> style; otherwise consider marking final
OnNameExpected: android.car.cluster.renderer.InstrumentClusterRenderingService#getBitmap(android.net.Uri, int, int):
If implemented by developer, should follow the on<Something> style; otherwise consider marking final
+OnNameExpected: android.car.cluster.renderer.InstrumentClusterRenderingService#getBitmap(android.net.Uri, int, int, float):
+ If implemented by developer, should follow the on<Something> style; otherwise consider marking final
OnNameExpected: android.car.cluster.renderer.InstrumentClusterRenderingService#getNavigationRenderer():
Methods implemented by developers should follow the on<Something> style, was `getNavigationRenderer`
+OnNameExpected: android.car.cluster.renderer.InstrumentClusterRenderingService#setClusterActivityLaunchOptions(android.app.ActivityOptions):
+ If implemented by developer, should follow the on<Something> style; otherwise consider marking final
+OnNameExpected: android.car.cluster.renderer.InstrumentClusterRenderingService#setClusterActivityState(android.car.cluster.ClusterActivityState):
+ If implemented by developer, should follow the on<Something> style; otherwise consider marking final
+OnNameExpected: android.car.cluster.renderer.InstrumentClusterRenderingService#startFixedActivityModeForDisplayAndUser(android.content.Intent, android.app.ActivityOptions, int):
+ If implemented by developer, should follow the on<Something> style; otherwise consider marking final
OnNameExpected: android.car.cluster.renderer.InstrumentClusterRenderingService#startNavigationActivity(android.content.ComponentName):
If implemented by developer, should follow the on<Something> style; otherwise consider marking final
+OnNameExpected: android.car.cluster.renderer.InstrumentClusterRenderingService#stopFixedActivityMode(int):
+ If implemented by developer, should follow the on<Something> style; otherwise consider marking final
OnNameExpected: android.car.content.pm.CarAppBlockingPolicyService#getAppBlockingPolicy():
Methods implemented by developers should follow the on<Something> style, was `getAppBlockingPolicy`
@@ -694,6 +751,10 @@
SAM-compatible parameters (such as parameter 1, "listener", in android.car.CarProjectionManager.registerProjectionListener) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
SamShouldBeLast: android.car.diagnostic.CarDiagnosticManager#registerListener(android.car.diagnostic.CarDiagnosticManager.OnDiagnosticEventListener, int, int):
SAM-compatible parameters (such as parameter 1, "listener", in android.car.diagnostic.CarDiagnosticManager.registerListener) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
+SamShouldBeLast: android.car.media.CarMediaManager#addMediaSourceListener(android.car.media.CarMediaManager.MediaSourceChangedListener, int):
+ SAM-compatible parameters (such as parameter 1, "callback", in android.car.media.CarMediaManager.addMediaSourceListener) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
+SamShouldBeLast: android.car.media.CarMediaManager#removeMediaSourceListener(android.car.media.CarMediaManager.MediaSourceChangedListener, int):
+ SAM-compatible parameters (such as parameter 1, "callback", in android.car.media.CarMediaManager.removeMediaSourceListener) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
ServiceName: android.car.Car#CAR_DRIVING_STATE_SERVICE:
@@ -724,6 +785,22 @@
Non-static field EGR must be named using fooBar style
+StaticFinalBuilder: android.car.diagnostic.CarDiagnosticEvent.Builder:
+ Builder must be final: android.car.diagnostic.CarDiagnosticEvent.Builder
+StaticFinalBuilder: android.car.hardware.CarPropertyConfig.Builder:
+ Builder must be final: android.car.hardware.CarPropertyConfig.Builder
+
+
+UserHandle: android.car.admin.CarDevicePolicyManager#removeUser(android.os.UserHandle):
+ When a method overload is needed to target a specific UserHandle, callers should be directed to use Context.createPackageContextAsUser() and re-obtain the relevant Manager, and no new API should be added
+UserHandle: android.car.watchdog.CarWatchdogManager#getPackageKillableStatesAsUser(android.os.UserHandle):
+ When a method overload is needed to target a specific UserHandle, callers should be directed to use Context.createPackageContextAsUser() and re-obtain the relevant Manager, and no new API should be added
+UserHandle: android.car.watchdog.CarWatchdogManager#getResourceOveruseStatsForUserPackage(String, android.os.UserHandle, int, int):
+ When a method overload is needed to target a specific UserHandle, callers should be directed to use Context.createPackageContextAsUser() and re-obtain the relevant Manager, and no new API should be added
+UserHandle: android.car.watchdog.CarWatchdogManager#setKillablePackageAsUser(String, android.os.UserHandle, boolean):
+ When a method overload is needed to target a specific UserHandle, callers should be directed to use Context.createPackageContextAsUser() and re-obtain the relevant Manager, and no new API should be added
+
+
UserHandleName: android.car.projection.ProjectionOptions:
Classes holding a set of parameters should be called `FooParams`, was `ProjectionOptions`
diff --git a/car-lib/api/test-current.txt b/car-lib/api/test-current.txt
index e4d3f4c..0923067 100644
--- a/car-lib/api/test-current.txt
+++ b/car-lib/api/test-current.txt
@@ -1,16 +1,222 @@
// Signature format: 2.0
package android.car {
+ public abstract class AoapService extends android.app.Service {
+ ctor public AoapService();
+ method @MainThread public int canSwitchToAoap(@NonNull android.hardware.usb.UsbDevice);
+ method @MainThread public abstract int isDeviceSupported(@NonNull android.hardware.usb.UsbDevice);
+ method public android.os.IBinder onBind(android.content.Intent);
+ field public static final int RESULT_DEVICE_NOT_SUPPORTED = 1; // 0x1
+ field public static final int RESULT_DO_NOT_SWITCH_TO_AOAP = 2; // 0x2
+ field public static final int RESULT_OK = 0; // 0x0
+ }
+
public final class Car {
+ method @RequiresPermission(android.car.Car.PERMISSION_CONTROL_CAR_FEATURES) public int disableFeature(@NonNull String);
+ method @RequiresPermission(android.car.Car.PERMISSION_CONTROL_CAR_FEATURES) public int enableFeature(@NonNull String);
+ method @NonNull @RequiresPermission(android.car.Car.PERMISSION_CONTROL_CAR_FEATURES) public java.util.List<java.lang.String> getAllEnabledFeatures();
+ method @NonNull @RequiresPermission(android.car.Car.PERMISSION_CONTROL_CAR_FEATURES) public java.util.List<java.lang.String> getAllPendingDisabledFeatures();
+ method @NonNull @RequiresPermission(android.car.Car.PERMISSION_CONTROL_CAR_FEATURES) public java.util.List<java.lang.String> getAllPendingEnabledFeatures();
+ field public static final String ACCESS_PRIVATE_DISPLAY_ID = "android.car.permission.ACCESS_PRIVATE_DISPLAY_ID";
+ field @Deprecated public static final String CABIN_SERVICE = "cabin";
+ field public static final String CAR_ACTIVITY_SERVICE = "car_activity_service";
+ field public static final String CAR_BUGREPORT_SERVICE = "car_bugreport";
field public static final String CAR_DEVICE_POLICY_SERVICE = "car_device_policy_service";
+ field public static final String CAR_DRIVING_STATE_SERVICE = "drivingstate";
+ field public static final String CAR_EVS_SERVICE = "car_evs_service";
+ field public static final String CAR_EXTRA_CLUSTER_ACTIVITY_STATE = "android.car.cluster.ClusterActivityState";
+ field public static final String CAR_INPUT_SERVICE = "android.car.input";
+ field public static final String CAR_MEDIA_SERVICE = "car_media";
+ field public static final String CAR_PERFORMANCE_SERVICE = "car_performance";
field public static final String CAR_TELEMETRY_SERVICE = "car_telemetry_service";
field public static final String CAR_USER_SERVICE = "car_user_service";
+ field public static final String DIAGNOSTIC_SERVICE = "diagnostic";
+ field public static final int FEATURE_REQUEST_ALREADY_IN_THE_STATE = 1; // 0x1
+ field public static final int FEATURE_REQUEST_MANDATORY = 2; // 0x2
+ field public static final int FEATURE_REQUEST_NOT_EXISTING = 3; // 0x3
+ field public static final int FEATURE_REQUEST_SUCCESS = 0; // 0x0
+ field @Deprecated public static final String HVAC_SERVICE = "hvac";
+ field public static final String OCCUPANT_AWARENESS_SERVICE = "occupant_awareness";
+ field public static final String PERMISSION_ADJUST_RANGE_REMAINING = "android.car.permission.ADJUST_RANGE_REMAINING";
+ field public static final String PERMISSION_CAR_DIAGNOSTIC_CLEAR = "android.car.permission.CLEAR_CAR_DIAGNOSTICS";
+ field public static final String PERMISSION_CAR_DIAGNOSTIC_READ_ALL = "android.car.permission.CAR_DIAGNOSTICS";
+ field public static final String PERMISSION_CAR_DRIVING_STATE = "android.car.permission.CAR_DRIVING_STATE";
+ field public static final String PERMISSION_CAR_DYNAMICS_STATE = "android.car.permission.CAR_DYNAMICS_STATE";
+ field public static final String PERMISSION_CAR_ENGINE_DETAILED = "android.car.permission.CAR_ENGINE_DETAILED";
+ field public static final String PERMISSION_CAR_EPOCH_TIME = "android.car.permission.CAR_EPOCH_TIME";
+ field public static final String PERMISSION_CAR_INSTRUMENT_CLUSTER_CONTROL = "android.car.permission.CAR_INSTRUMENT_CLUSTER_CONTROL";
+ field public static final String PERMISSION_CAR_MONITOR_INPUT = "android.car.permission.CAR_MONITOR_INPUT";
+ field public static final String PERMISSION_CAR_POWER = "android.car.permission.CAR_POWER";
+ field public static final String PERMISSION_CAR_PROJECTION = "android.car.permission.CAR_PROJECTION";
+ field public static final String PERMISSION_CAR_PROJECTION_STATUS = "android.car.permission.ACCESS_CAR_PROJECTION_STATUS";
+ field public static final String PERMISSION_CAR_TEST_SERVICE = "android.car.permission.CAR_TEST_SERVICE";
+ field public static final String PERMISSION_CAR_UX_RESTRICTIONS_CONFIGURATION = "android.car.permission.CAR_UX_RESTRICTIONS_CONFIGURATION";
+ field public static final String PERMISSION_COLLECT_CAR_WATCHDOG_METRICS = "android.car.permission.COLLECT_CAR_WATCHDOG_METRICS";
+ field public static final String PERMISSION_CONTROL_APP_BLOCKING = "android.car.permission.CONTROL_APP_BLOCKING";
+ field public static final String PERMISSION_CONTROL_CAR_APP_LAUNCH = "android.car.permission.CONTROL_CAR_APP_LAUNCH";
+ field public static final String PERMISSION_CONTROL_CAR_CLIMATE = "android.car.permission.CONTROL_CAR_CLIMATE";
+ field public static final String PERMISSION_CONTROL_CAR_DOORS = "android.car.permission.CONTROL_CAR_DOORS";
+ field public static final String PERMISSION_CONTROL_CAR_EVS_ACTIVITY = "android.car.permission.CONTROL_CAR_EVS_ACTIVITY";
+ field public static final String PERMISSION_CONTROL_CAR_FEATURES = "android.car.permission.CONTROL_CAR_FEATURES";
+ field public static final String PERMISSION_CONTROL_CAR_MIRRORS = "android.car.permission.CONTROL_CAR_MIRRORS";
+ field @Deprecated public static final String PERMISSION_CONTROL_CAR_OCCUPANT_AWARENESS_SYSTEM = "android.car.permission.CONTROL_CAR_OCCUPANT_AWARENESS_SYSTEM";
+ field public static final String PERMISSION_CONTROL_CAR_POWER_POLICY = "android.car.permission.CONTROL_CAR_POWER_POLICY";
+ field public static final String PERMISSION_CONTROL_CAR_SEATS = "android.car.permission.CONTROL_CAR_SEATS";
+ field public static final String PERMISSION_CONTROL_CAR_WATCHDOG_CONFIG = "android.car.permission.CONTROL_CAR_WATCHDOG_CONFIG";
+ field public static final String PERMISSION_CONTROL_CAR_WINDOWS = "android.car.permission.CONTROL_CAR_WINDOWS";
+ field public static final String PERMISSION_CONTROL_ENERGY_PORTS = "android.car.permission.CONTROL_CAR_ENERGY_PORTS";
+ field public static final String PERMISSION_CONTROL_EXTERIOR_LIGHTS = "android.car.permission.CONTROL_CAR_EXTERIOR_LIGHTS";
+ field public static final String PERMISSION_CONTROL_SHUTDOWN_PROCESS = "android.car.permission.CONTROL_SHUTDOWN_PROCESS";
+ field public static final String PERMISSION_EXTERIOR_LIGHTS = "android.car.permission.CAR_EXTERIOR_LIGHTS";
+ field @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.TIRAMISU_1, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.TIRAMISU_1) public static final String PERMISSION_MANAGE_THREAD_PRIORITY = "android.car.permission.MANAGE_THREAD_PRIORITY";
+ field public static final String PERMISSION_MILEAGE = "android.car.permission.CAR_MILEAGE";
+ field @Deprecated public static final String PERMISSION_MOCK_VEHICLE_HAL = "android.car.permission.CAR_MOCK_VEHICLE_HAL";
+ field public static final String PERMISSION_MONITOR_CAR_EVS_STATUS = "android.car.permission.MONITOR_CAR_EVS_STATUS";
+ field public static final String PERMISSION_READ_CAR_OCCUPANT_AWARENESS_STATE = "android.car.permission.READ_CAR_OCCUPANT_AWARENESS_STATE";
+ field public static final String PERMISSION_READ_CAR_VENDOR_PERMISSION_INFO = "android.car.permission.READ_CAR_VENDOR_PERMISSION_INFO";
+ field public static final String PERMISSION_RECEIVE_CAR_AUDIO_DUCKING_EVENTS = "android.car.permission.RECEIVE_CAR_AUDIO_DUCKING_EVENTS";
+ field public static final String PERMISSION_REQUEST_CAR_EVS_ACTIVITY = "android.car.permission.REQUEST_CAR_EVS_ACTIVITY";
+ field public static final String PERMISSION_STORAGE_ENCRYPTION_BINDING_SEED = "android.car.permission.STORAGE_ENCRYPTION_BINDING_SEED";
+ field public static final String PERMISSION_STORAGE_MONITORING = "android.car.permission.STORAGE_MONITORING";
+ field public static final String PERMISSION_TEMPLATE_RENDERER = "android.car.permission.TEMPLATE_RENDERER";
+ field public static final String PERMISSION_TIRES = "android.car.permission.CAR_TIRES";
+ field public static final String PERMISSION_USE_CAR_EVS_CAMERA = "android.car.permission.USE_CAR_EVS_CAMERA";
+ field public static final String PERMISSION_USE_CAR_TELEMETRY_SERVICE = "android.car.permission.USE_CAR_TELEMETRY_SERVICE";
+ field public static final String PERMISSION_USE_CAR_WATCHDOG = "android.car.permission.USE_CAR_WATCHDOG";
+ field public static final String PERMISSION_VENDOR_EXTENSION = "android.car.permission.CAR_VENDOR_EXTENSION";
+ field public static final String PERMISSION_VMS_PUBLISHER = "android.car.permission.VMS_PUBLISHER";
+ field public static final String PERMISSION_VMS_SUBSCRIBER = "android.car.permission.VMS_SUBSCRIBER";
+ field public static final String PROJECTION_SERVICE = "projection";
+ field @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.TIRAMISU_1, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.TIRAMISU_0) public static final String PROPERTY_EMULATED_PLATFORM_VERSION_MAJOR = "com.android.car.internal.debug.platform_major_version";
+ field @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.TIRAMISU_1, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.TIRAMISU_0) public static final String PROPERTY_EMULATED_PLATFORM_VERSION_MINOR = "com.android.car.internal.debug.platform_minor_version";
+ field public static final String STORAGE_MONITORING_SERVICE = "storage_monitoring";
+ field public static final String TEST_SERVICE = "car-service-test";
+ field public static final String VEHICLE_MAP_SERVICE = "vehicle_map_service";
+ field @Deprecated public static final String VENDOR_EXTENSION_SERVICE = "vendor_extension";
+ field @Deprecated public static final String VMS_SUBSCRIBER_SERVICE = "vehicle_map_subscriber_service";
}
public final class CarAppFocusManager {
method public int[] getActiveAppTypes();
}
+ public final class CarBugreportManager {
+ method @RequiresPermission(android.Manifest.permission.DUMP) public void cancelBugreport();
+ method @RequiresPermission(android.Manifest.permission.DUMP) public void requestBugreport(@NonNull android.os.ParcelFileDescriptor, @NonNull android.os.ParcelFileDescriptor, @NonNull android.car.CarBugreportManager.CarBugreportManagerCallback);
+ }
+
+ public abstract static class CarBugreportManager.CarBugreportManagerCallback {
+ ctor public CarBugreportManager.CarBugreportManagerCallback();
+ method public void onError(int);
+ method public void onFinished();
+ method public void onProgress(@FloatRange(from=0.0f, to=100.0f) float);
+ field public static final int CAR_BUGREPORT_DUMPSTATE_CONNECTION_FAILED = 3; // 0x3
+ field public static final int CAR_BUGREPORT_DUMPSTATE_FAILED = 1; // 0x1
+ field public static final int CAR_BUGREPORT_IN_PROGRESS = 2; // 0x2
+ field public static final int CAR_BUGREPORT_SERVICE_NOT_AVAILABLE = 4; // 0x4
+ }
+
+ public class CarOccupantZoneManager {
+ method @RequiresPermission(android.car.Car.PERMISSION_CAR_CONTROL_AUDIO_SETTINGS) public int getAudioZoneIdForOccupant(@NonNull android.car.CarOccupantZoneManager.OccupantZoneInfo);
+ method @RequiresPermission(android.car.Car.ACCESS_PRIVATE_DISPLAY_ID) public int getDisplayIdForDriver(int);
+ method @Nullable @RequiresPermission(android.car.Car.PERMISSION_CAR_CONTROL_AUDIO_SETTINGS) public android.car.CarOccupantZoneManager.OccupantZoneInfo getOccupantForAudioZoneId(int);
+ }
+
+ public final class CarProjectionManager {
+ method @RequiresPermission(android.car.Car.PERMISSION_CAR_PROJECTION) public void addKeyEventHandler(@NonNull java.util.Set<java.lang.Integer>, @NonNull android.car.CarProjectionManager.ProjectionKeyEventHandler);
+ method @RequiresPermission(android.car.Car.PERMISSION_CAR_PROJECTION) public void addKeyEventHandler(@NonNull java.util.Set<java.lang.Integer>, @Nullable java.util.concurrent.Executor, @NonNull android.car.CarProjectionManager.ProjectionKeyEventHandler);
+ method @NonNull @RequiresPermission(android.car.Car.PERMISSION_CAR_PROJECTION) public java.util.List<java.lang.Integer> getAvailableWifiChannels(int);
+ method @NonNull @RequiresPermission(android.car.Car.PERMISSION_CAR_PROJECTION) public android.os.Bundle getProjectionOptions();
+ method @RequiresPermission(android.car.Car.PERMISSION_CAR_PROJECTION) public void registerProjectionListener(@NonNull android.car.CarProjectionManager.CarProjectionListener, int);
+ method @RequiresPermission(android.car.Car.PERMISSION_CAR_PROJECTION) public void registerProjectionRunner(@NonNull android.content.Intent);
+ method @RequiresPermission(android.car.Car.PERMISSION_CAR_PROJECTION_STATUS) public void registerProjectionStatusListener(@NonNull android.car.CarProjectionManager.ProjectionStatusListener);
+ method @RequiresPermission(android.car.Car.PERMISSION_CAR_PROJECTION) public boolean releaseBluetoothProfileInhibit(@NonNull android.bluetooth.BluetoothDevice, int);
+ method @RequiresPermission(android.car.Car.PERMISSION_CAR_PROJECTION) public void removeKeyEventHandler(@NonNull android.car.CarProjectionManager.ProjectionKeyEventHandler);
+ method @RequiresPermission(android.car.Car.PERMISSION_CAR_PROJECTION) public boolean requestBluetoothProfileInhibit(@NonNull android.bluetooth.BluetoothDevice, int);
+ method @RequiresPermission(android.car.Car.PERMISSION_CAR_PROJECTION) public void resetProjectionAccessPointCredentials();
+ method @RequiresPermission(android.car.Car.PERMISSION_CAR_PROJECTION) public void startProjectionAccessPoint(@NonNull android.car.CarProjectionManager.ProjectionAccessPointCallback);
+ method @RequiresPermission(android.car.Car.PERMISSION_CAR_PROJECTION) public void stopProjectionAccessPoint();
+ method @RequiresPermission(android.car.Car.PERMISSION_CAR_PROJECTION) public void unregisterProjectionListener();
+ method @RequiresPermission(android.car.Car.PERMISSION_CAR_PROJECTION) public void unregisterProjectionRunner(@NonNull android.content.Intent);
+ method @RequiresPermission(android.car.Car.PERMISSION_CAR_PROJECTION_STATUS) public void unregisterProjectionStatusListener(@NonNull android.car.CarProjectionManager.ProjectionStatusListener);
+ method @RequiresPermission(android.car.Car.PERMISSION_CAR_PROJECTION) public void updateProjectionStatus(@NonNull android.car.projection.ProjectionStatus);
+ field public static final int KEY_EVENT_CALL_KEY_DOWN = 4; // 0x4
+ field public static final int KEY_EVENT_CALL_LONG_PRESS_KEY_DOWN = 6; // 0x6
+ field public static final int KEY_EVENT_CALL_LONG_PRESS_KEY_UP = 7; // 0x7
+ field public static final int KEY_EVENT_CALL_SHORT_PRESS_KEY_UP = 5; // 0x5
+ field public static final int KEY_EVENT_VOICE_SEARCH_KEY_DOWN = 0; // 0x0
+ field public static final int KEY_EVENT_VOICE_SEARCH_LONG_PRESS_KEY_DOWN = 2; // 0x2
+ field public static final int KEY_EVENT_VOICE_SEARCH_LONG_PRESS_KEY_UP = 3; // 0x3
+ field public static final int KEY_EVENT_VOICE_SEARCH_SHORT_PRESS_KEY_UP = 1; // 0x1
+ field @Deprecated public static final int PROJECTION_LONG_PRESS_VOICE_SEARCH = 2; // 0x2
+ field @Deprecated public static final int PROJECTION_VOICE_SEARCH = 1; // 0x1
+ }
+
+ public static interface CarProjectionManager.CarProjectionListener {
+ method public void onVoiceAssistantRequest(boolean);
+ }
+
+ public abstract static class CarProjectionManager.ProjectionAccessPointCallback {
+ ctor public CarProjectionManager.ProjectionAccessPointCallback();
+ method public void onFailed(int);
+ method @Deprecated public void onStarted(@Nullable android.net.wifi.WifiConfiguration);
+ method public void onStarted(@NonNull android.net.wifi.SoftApConfiguration);
+ method public void onStopped();
+ field public static final int ERROR_GENERIC = 2; // 0x2
+ field public static final int ERROR_INCOMPATIBLE_MODE = 3; // 0x3
+ field public static final int ERROR_NO_CHANNEL = 1; // 0x1
+ field public static final int ERROR_TETHERING_DISALLOWED = 4; // 0x4
+ }
+
+ public static interface CarProjectionManager.ProjectionKeyEventHandler {
+ method public void onKeyEvent(int);
+ }
+
+ public static interface CarProjectionManager.ProjectionStatusListener {
+ method public void onProjectionStatusChanged(int, @Nullable String, @NonNull java.util.List<android.car.projection.ProjectionStatus>);
+ }
+
+ public final class VehicleAreaDoor {
+ field public static final int DOOR_HOOD = 268435456; // 0x10000000
+ field public static final int DOOR_REAR = 536870912; // 0x20000000
+ field public static final int DOOR_ROW_1_LEFT = 1; // 0x1
+ field public static final int DOOR_ROW_1_RIGHT = 4; // 0x4
+ field public static final int DOOR_ROW_2_LEFT = 16; // 0x10
+ field public static final int DOOR_ROW_2_RIGHT = 64; // 0x40
+ field public static final int DOOR_ROW_3_LEFT = 256; // 0x100
+ field public static final int DOOR_ROW_3_RIGHT = 1024; // 0x400
+ }
+
+ public final class VehicleAreaMirror {
+ field public static final int MIRROR_DRIVER_CENTER = 4; // 0x4
+ field public static final int MIRROR_DRIVER_LEFT = 1; // 0x1
+ field public static final int MIRROR_DRIVER_RIGHT = 2; // 0x2
+ }
+
+ public final class VehicleAreaWindow {
+ field public static final int WINDOW_FRONT_WINDSHIELD = 1; // 0x1
+ field public static final int WINDOW_REAR_WINDSHIELD = 2; // 0x2
+ field public static final int WINDOW_ROOF_TOP_1 = 65536; // 0x10000
+ field public static final int WINDOW_ROOF_TOP_2 = 131072; // 0x20000
+ field public static final int WINDOW_ROW_1_LEFT = 16; // 0x10
+ field public static final int WINDOW_ROW_1_RIGHT = 64; // 0x40
+ field public static final int WINDOW_ROW_2_LEFT = 256; // 0x100
+ field public static final int WINDOW_ROW_2_RIGHT = 1024; // 0x400
+ field public static final int WINDOW_ROW_3_LEFT = 4096; // 0x1000
+ field public static final int WINDOW_ROW_3_RIGHT = 16384; // 0x4000
+ }
+
+ public final class VehiclePropertyAccess {
+ field public static final int NONE = 0; // 0x0
+ field public static final int READ = 1; // 0x1
+ field public static final int READ_WRITE = 3; // 0x3
+ field public static final int WRITE = 2; // 0x2
+ }
+
+ public final class VehiclePropertyIds {
+ field @RequiresPermission(android.car.Car.PERMISSION_CONTROL_CAR_CLIMATE) public static final int HVAC_ELECTRIC_DEFROSTER_ON = 320865556; // 0x13200514
+ }
+
public class VehiclePropertyType {
field public static final int BOOLEAN = 2097152; // 0x200000
field public static final int BYTES = 7340032; // 0x700000
@@ -25,6 +231,20 @@
field public static final int STRING = 1048576; // 0x100000
}
+ public final class VehicleUnit {
+ field public static final int DEGREES = 128; // 0x80
+ field public static final int HERTZ = 3; // 0x3
+ field public static final int MILLIAMPERE = 97; // 0x61
+ field public static final int MILLIVOLT = 98; // 0x62
+ field public static final int MILLIWATTS = 99; // 0x63
+ field public static final int NANO_SECS = 80; // 0x50
+ field public static final int PERCENTILE = 16; // 0x10
+ field public static final int RPM = 2; // 0x2
+ field public static final int SECS = 83; // 0x53
+ field public static final int SHOULD_NOT_USE = 0; // 0x0
+ field public static final int YEAR = 89; // 0x59
+ }
+
}
package android.car.admin {
@@ -81,10 +301,31 @@
}
+package android.car.annotation {
+
+ @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.RUNTIME) @java.lang.annotation.Target({java.lang.annotation.ElementType.ANNOTATION_TYPE, java.lang.annotation.ElementType.FIELD, java.lang.annotation.ElementType.TYPE, java.lang.annotation.ElementType.METHOD}) public @interface ApiRequirements {
+ method public abstract android.car.annotation.ApiRequirements.CarVersion minCarVersion();
+ method public abstract android.car.annotation.ApiRequirements.PlatformVersion minPlatformVersion();
+ }
+
+ public enum ApiRequirements.CarVersion {
+ method public android.car.CarVersion get();
+ enum_constant public static final android.car.annotation.ApiRequirements.CarVersion TIRAMISU_0;
+ enum_constant public static final android.car.annotation.ApiRequirements.CarVersion TIRAMISU_1;
+ }
+
+ public enum ApiRequirements.PlatformVersion {
+ method public android.car.PlatformVersion get();
+ enum_constant public static final android.car.annotation.ApiRequirements.PlatformVersion TIRAMISU_0;
+ enum_constant public static final android.car.annotation.ApiRequirements.PlatformVersion TIRAMISU_1;
+ }
+
+}
+
package android.car.app {
public final class CarActivityManager {
- method @RequiresPermission("android.car.permission.CONTROL_CAR_APP_LAUNCH") public int setPersistentActivity(@NonNull android.content.ComponentName, int, int);
+ method @RequiresPermission(android.car.Car.PERMISSION_CONTROL_CAR_APP_LAUNCH) public int setPersistentActivity(@NonNull android.content.ComponentName, int, int);
field public static final int RESULT_FAILURE = -1; // 0xffffffff
field public static final int RESULT_INVALID_USER = -2; // 0xfffffffe
field public static final int RESULT_SUCCESS = 0; // 0x0
@@ -92,18 +333,642 @@
}
+package android.car.cluster {
+
+ @Deprecated public class CarInstrumentClusterManager {
+ method @Deprecated public void registerCallback(String, android.car.cluster.CarInstrumentClusterManager.Callback);
+ method @Deprecated public void startActivity(android.content.Intent);
+ method @Deprecated public void unregisterCallback(android.car.cluster.CarInstrumentClusterManager.Callback);
+ field @Deprecated public static final String CATEGORY_NAVIGATION = "android.car.cluster.NAVIGATION";
+ field @Deprecated public static final String KEY_EXTRA_ACTIVITY_STATE = "android.car.cluster.ClusterActivityState";
+ }
+
+ @Deprecated public static interface CarInstrumentClusterManager.Callback {
+ method @Deprecated public void onClusterActivityStateChanged(String, android.os.Bundle);
+ }
+
+ public final class ClusterActivityState {
+ method @NonNull public static android.car.cluster.ClusterActivityState create(boolean, @NonNull android.graphics.Rect);
+ method @NonNull public static android.car.cluster.ClusterActivityState fromBundle(@NonNull android.os.Bundle);
+ method @Nullable public android.os.Bundle getExtras();
+ method @Nullable public android.graphics.Rect getUnobscuredBounds();
+ method public boolean isVisible();
+ method @NonNull public android.car.cluster.ClusterActivityState setExtras(@NonNull android.os.Bundle);
+ method @NonNull public android.car.cluster.ClusterActivityState setUnobscuredBounds(@NonNull android.graphics.Rect);
+ method @NonNull public android.car.cluster.ClusterActivityState setVisible(boolean);
+ method @NonNull public android.os.Bundle toBundle();
+ }
+
+}
+
+package android.car.cluster.renderer {
+
+ @Deprecated public abstract class InstrumentClusterRenderer {
+ ctor @Deprecated public InstrumentClusterRenderer();
+ method @Deprecated protected abstract android.car.cluster.renderer.NavigationRenderer createNavigationRenderer();
+ method @Deprecated @Nullable public android.car.cluster.renderer.NavigationRenderer getNavigationRenderer();
+ method @Deprecated @UiThread public final void initialize();
+ method @Deprecated public abstract void onCreate(android.content.Context);
+ method @Deprecated public abstract void onStart();
+ method @Deprecated public abstract void onStop();
+ }
+
+ public abstract class InstrumentClusterRenderingService extends android.app.Service {
+ ctor public InstrumentClusterRenderingService();
+ method @Deprecated @Nullable public android.graphics.Bitmap getBitmap(android.net.Uri);
+ method @Nullable public android.graphics.Bitmap getBitmap(@NonNull android.net.Uri, int, int);
+ method @Nullable public android.graphics.Bitmap getBitmap(@NonNull android.net.Uri, int, int, float);
+ method @MainThread @Nullable public abstract android.car.cluster.renderer.NavigationRenderer getNavigationRenderer();
+ method @CallSuper public android.os.IBinder onBind(android.content.Intent);
+ method @MainThread public void onKeyEvent(@NonNull android.view.KeyEvent);
+ method @MainThread public void onNavigationComponentLaunched();
+ method @MainThread public void onNavigationComponentReleased();
+ method public void setClusterActivityLaunchOptions(@NonNull android.app.ActivityOptions);
+ method public void setClusterActivityState(@NonNull android.car.cluster.ClusterActivityState);
+ method public boolean startFixedActivityModeForDisplayAndUser(@NonNull android.content.Intent, @NonNull android.app.ActivityOptions, int);
+ method protected boolean startNavigationActivity(@NonNull android.content.ComponentName);
+ method public void stopFixedActivityMode(int);
+ }
+
+ @UiThread public abstract class NavigationRenderer {
+ ctor public NavigationRenderer();
+ method public abstract android.car.navigation.CarNavigationInstrumentCluster getNavigationProperties();
+ method public void onNavigationStateChanged(@Nullable android.os.Bundle);
+ }
+
+}
+
package android.car.content.pm {
+ public final class AppBlockingPackageInfo implements android.os.Parcelable {
+ ctor public AppBlockingPackageInfo(String, int, int, int, @Nullable android.content.pm.Signature[], @Nullable String[]);
+ ctor public AppBlockingPackageInfo(android.os.Parcel);
+ method public int describeContents();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.car.content.pm.AppBlockingPackageInfo> CREATOR;
+ field public static final int FLAG_SYSTEM_APP = 1; // 0x1
+ field public static final int FLAG_WHOLE_ACTIVITY = 2; // 0x2
+ field public final String[] activities;
+ field public final int flags;
+ field public final int maxRevisionCode;
+ field public final int minRevisionCode;
+ field public final String packageName;
+ field public final android.content.pm.Signature[] signatures;
+ }
+
+ public final class CarAppBlockingPolicy implements android.os.Parcelable {
+ ctor public CarAppBlockingPolicy(android.car.content.pm.AppBlockingPackageInfo[], android.car.content.pm.AppBlockingPackageInfo[]);
+ ctor public CarAppBlockingPolicy(android.os.Parcel);
+ method public int describeContents();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.car.content.pm.CarAppBlockingPolicy> CREATOR;
+ field public final android.car.content.pm.AppBlockingPackageInfo[] blacklists;
+ field public final android.car.content.pm.AppBlockingPackageInfo[] whitelists;
+ }
+
+ public abstract class CarAppBlockingPolicyService extends android.app.Service {
+ ctor public CarAppBlockingPolicyService();
+ method protected abstract android.car.content.pm.CarAppBlockingPolicy getAppBlockingPolicy();
+ method public android.os.IBinder onBind(android.content.Intent);
+ field public static final String SERVICE_INTERFACE = "android.car.content.pm.CarAppBlockingPolicyService";
+ }
+
public final class CarPackageManager {
+ method @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.TIRAMISU_1, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.TIRAMISU_0) @NonNull @RequiresPermission(android.Manifest.permission.QUERY_ALL_PACKAGES) public android.car.CarVersion getTargetCarVersion(@NonNull String) throws android.content.pm.PackageManager.NameNotFoundException;
+ method public boolean isActivityBackedBySafeActivity(android.content.ComponentName);
+ method @Deprecated public void setAppBlockingPolicy(String, android.car.content.pm.CarAppBlockingPolicy, int);
method public void setEnableActivityBlocking(boolean);
+ field @Deprecated public static final int FLAG_SET_POLICY_ADD = 2; // 0x2
+ field @Deprecated public static final int FLAG_SET_POLICY_REMOVE = 4; // 0x4
+ field @Deprecated public static final int FLAG_SET_POLICY_WAIT_FOR_CHANGE = 1; // 0x1
+ }
+
+}
+
+package android.car.diagnostic {
+
+ public final class CarDiagnosticEvent implements android.os.Parcelable {
+ ctor public CarDiagnosticEvent(android.os.Parcel);
+ method public int describeContents();
+ method @android.car.diagnostic.CarDiagnosticEvent.FuelSystemStatus.Status @Nullable public Integer getFuelSystemStatus();
+ method @android.car.diagnostic.CarDiagnosticEvent.FuelType.Type @Nullable public Integer getFuelType();
+ method @Nullable public android.car.diagnostic.CarDiagnosticEvent.CommonIgnitionMonitors getIgnitionMonitors();
+ method @android.car.diagnostic.CarDiagnosticEvent.SecondaryAirStatus.Status @Nullable public Integer getSecondaryAirStatus();
+ method public float getSystemFloatSensor(int, float);
+ method @Nullable public Float getSystemFloatSensor(int);
+ method public int getSystemIntegerSensor(int, int);
+ method @Nullable public Integer getSystemIntegerSensor(int);
+ method public float getVendorFloatSensor(int, float);
+ method @Nullable public Float getVendorFloatSensor(int);
+ method public int getVendorIntegerSensor(int, int);
+ method @Nullable public Integer getVendorIntegerSensor(int);
+ method public boolean isFreezeFrame();
+ method public boolean isLiveFrame();
+ method public void writeToJson(android.util.JsonWriter) throws java.io.IOException;
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.car.diagnostic.CarDiagnosticEvent> CREATOR;
+ field public final String dtc;
+ field public final int frameType;
+ field public final long timestamp;
+ }
+
+ public static class CarDiagnosticEvent.Builder {
+ method @Deprecated public android.car.diagnostic.CarDiagnosticEvent.Builder atTimestamp(long);
+ method public android.car.diagnostic.CarDiagnosticEvent build();
+ method public static android.car.diagnostic.CarDiagnosticEvent.Builder newFreezeFrameBuilder();
+ method public static android.car.diagnostic.CarDiagnosticEvent.Builder newLiveFrameBuilder();
+ method public android.car.diagnostic.CarDiagnosticEvent.Builder setDtc(String);
+ method public android.car.diagnostic.CarDiagnosticEvent.Builder setFloatValue(int, float);
+ method public android.car.diagnostic.CarDiagnosticEvent.Builder setIntValue(int, int);
+ method public android.car.diagnostic.CarDiagnosticEvent.Builder setTimeStamp(long);
+ method @Deprecated public android.car.diagnostic.CarDiagnosticEvent.Builder withDtc(String);
+ method @Deprecated public android.car.diagnostic.CarDiagnosticEvent.Builder withFloatValue(int, float);
+ method @Deprecated public android.car.diagnostic.CarDiagnosticEvent.Builder withIntValue(int, int);
+ }
+
+ public static class CarDiagnosticEvent.CommonIgnitionMonitors {
+ method @Nullable public android.car.diagnostic.CarDiagnosticEvent.CompressionIgnitionMonitors asCompressionIgnitionMonitors();
+ method @Nullable public android.car.diagnostic.CarDiagnosticEvent.SparkIgnitionMonitors asSparkIgnitionMonitors();
+ field public final android.car.diagnostic.CarDiagnosticEvent.IgnitionMonitor components;
+ field public final android.car.diagnostic.CarDiagnosticEvent.IgnitionMonitor fuelSystem;
+ field public final android.car.diagnostic.CarDiagnosticEvent.IgnitionMonitor misfire;
+ }
+
+ public static final class CarDiagnosticEvent.CompressionIgnitionMonitors extends android.car.diagnostic.CarDiagnosticEvent.CommonIgnitionMonitors {
+ field public final android.car.diagnostic.CarDiagnosticEvent.IgnitionMonitor EGROrVVT;
+ field public final android.car.diagnostic.CarDiagnosticEvent.IgnitionMonitor NMHCCatalyst;
+ field public final android.car.diagnostic.CarDiagnosticEvent.IgnitionMonitor NOxSCR;
+ field public final android.car.diagnostic.CarDiagnosticEvent.IgnitionMonitor PMFilter;
+ field public final android.car.diagnostic.CarDiagnosticEvent.IgnitionMonitor boostPressure;
+ field public final android.car.diagnostic.CarDiagnosticEvent.IgnitionMonitor exhaustGasSensor;
+ }
+
+ public static final class CarDiagnosticEvent.FuelSystemStatus {
+ field public static final int CLOSED_LOOP = 2; // 0x2
+ field public static final int CLOSED_LOOP_BUT_FEEDBACK_FAULT = 16; // 0x10
+ field public static final int OPEN_ENGINE_LOAD_OR_DECELERATION = 4; // 0x4
+ field public static final int OPEN_INSUFFICIENT_ENGINE_TEMPERATURE = 1; // 0x1
+ field public static final int OPEN_SYSTEM_FAILURE = 8; // 0x8
+ }
+
+ @IntDef({android.car.diagnostic.CarDiagnosticEvent.FuelSystemStatus.OPEN_INSUFFICIENT_ENGINE_TEMPERATURE, android.car.diagnostic.CarDiagnosticEvent.FuelSystemStatus.CLOSED_LOOP, android.car.diagnostic.CarDiagnosticEvent.FuelSystemStatus.OPEN_ENGINE_LOAD_OR_DECELERATION, android.car.diagnostic.CarDiagnosticEvent.FuelSystemStatus.OPEN_SYSTEM_FAILURE, android.car.diagnostic.CarDiagnosticEvent.FuelSystemStatus.CLOSED_LOOP_BUT_FEEDBACK_FAULT}) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface CarDiagnosticEvent.FuelSystemStatus.Status {
+ }
+
+ public static final class CarDiagnosticEvent.FuelType {
+ field public static final int BIFUEL_RUNNING_CNG = 13; // 0xd
+ field public static final int BIFUEL_RUNNING_DIESEL = 23; // 0x17
+ field public static final int BIFUEL_RUNNING_ELECTRIC = 15; // 0xf
+ field public static final int BIFUEL_RUNNING_ELECTRIC_AND_COMBUSTION = 16; // 0x10
+ field public static final int BIFUEL_RUNNING_ETHANOL = 11; // 0xb
+ field public static final int BIFUEL_RUNNING_GASOLINE = 9; // 0x9
+ field public static final int BIFUEL_RUNNING_LPG = 12; // 0xc
+ field public static final int BIFUEL_RUNNING_METHANOL = 10; // 0xa
+ field public static final int BIFUEL_RUNNING_PROPANE = 14; // 0xe
+ field public static final int CNG = 6; // 0x6
+ field public static final int DIESEL = 4; // 0x4
+ field public static final int ELECTRIC = 8; // 0x8
+ field public static final int ETHANOL = 3; // 0x3
+ field public static final int GASOLINE = 1; // 0x1
+ field public static final int HYBRID_DIESEL = 19; // 0x13
+ field public static final int HYBRID_ELECTRIC = 20; // 0x14
+ field public static final int HYBRID_ETHANOL = 18; // 0x12
+ field public static final int HYBRID_GASOLINE = 17; // 0x11
+ field public static final int HYBRID_REGENERATIVE = 22; // 0x16
+ field public static final int HYBRID_RUNNING_ELECTRIC_AND_COMBUSTION = 21; // 0x15
+ field public static final int LPG = 5; // 0x5
+ field public static final int METHANOL = 2; // 0x2
+ field public static final int NOT_AVAILABLE = 0; // 0x0
+ field public static final int PROPANE = 7; // 0x7
+ }
+
+ @IntDef({android.car.diagnostic.CarDiagnosticEvent.FuelType.NOT_AVAILABLE, android.car.diagnostic.CarDiagnosticEvent.FuelType.GASOLINE, android.car.diagnostic.CarDiagnosticEvent.FuelType.METHANOL, android.car.diagnostic.CarDiagnosticEvent.FuelType.ETHANOL, android.car.diagnostic.CarDiagnosticEvent.FuelType.DIESEL, android.car.diagnostic.CarDiagnosticEvent.FuelType.LPG, android.car.diagnostic.CarDiagnosticEvent.FuelType.CNG, android.car.diagnostic.CarDiagnosticEvent.FuelType.PROPANE, android.car.diagnostic.CarDiagnosticEvent.FuelType.ELECTRIC, android.car.diagnostic.CarDiagnosticEvent.FuelType.BIFUEL_RUNNING_GASOLINE, android.car.diagnostic.CarDiagnosticEvent.FuelType.BIFUEL_RUNNING_METHANOL, android.car.diagnostic.CarDiagnosticEvent.FuelType.BIFUEL_RUNNING_ETHANOL, android.car.diagnostic.CarDiagnosticEvent.FuelType.BIFUEL_RUNNING_LPG, android.car.diagnostic.CarDiagnosticEvent.FuelType.BIFUEL_RUNNING_CNG, android.car.diagnostic.CarDiagnosticEvent.FuelType.BIFUEL_RUNNING_PROPANE, android.car.diagnostic.CarDiagnosticEvent.FuelType.BIFUEL_RUNNING_ELECTRIC, android.car.diagnostic.CarDiagnosticEvent.FuelType.BIFUEL_RUNNING_ELECTRIC_AND_COMBUSTION, android.car.diagnostic.CarDiagnosticEvent.FuelType.HYBRID_GASOLINE, android.car.diagnostic.CarDiagnosticEvent.FuelType.HYBRID_ETHANOL, android.car.diagnostic.CarDiagnosticEvent.FuelType.HYBRID_DIESEL, android.car.diagnostic.CarDiagnosticEvent.FuelType.HYBRID_ELECTRIC, android.car.diagnostic.CarDiagnosticEvent.FuelType.HYBRID_RUNNING_ELECTRIC_AND_COMBUSTION, android.car.diagnostic.CarDiagnosticEvent.FuelType.HYBRID_REGENERATIVE, android.car.diagnostic.CarDiagnosticEvent.FuelType.BIFUEL_RUNNING_DIESEL}) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface CarDiagnosticEvent.FuelType.Type {
+ }
+
+ public static final class CarDiagnosticEvent.IgnitionMonitor {
+ field public final boolean available;
+ field public final boolean incomplete;
+ }
+
+ public static final class CarDiagnosticEvent.SecondaryAirStatus {
+ field public static final int DOWNSTREAM_OF_CATALYCIC_CONVERTER = 2; // 0x2
+ field public static final int FROM_OUTSIDE_OR_OFF = 4; // 0x4
+ field public static final int PUMP_ON_FOR_DIAGNOSTICS = 8; // 0x8
+ field public static final int UPSTREAM = 1; // 0x1
+ }
+
+ @IntDef({android.car.diagnostic.CarDiagnosticEvent.SecondaryAirStatus.UPSTREAM, android.car.diagnostic.CarDiagnosticEvent.SecondaryAirStatus.DOWNSTREAM_OF_CATALYCIC_CONVERTER, android.car.diagnostic.CarDiagnosticEvent.SecondaryAirStatus.FROM_OUTSIDE_OR_OFF, android.car.diagnostic.CarDiagnosticEvent.SecondaryAirStatus.PUMP_ON_FOR_DIAGNOSTICS}) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface CarDiagnosticEvent.SecondaryAirStatus.Status {
+ }
+
+ public static final class CarDiagnosticEvent.SparkIgnitionMonitors extends android.car.diagnostic.CarDiagnosticEvent.CommonIgnitionMonitors {
+ field public final android.car.diagnostic.CarDiagnosticEvent.IgnitionMonitor ACRefrigerant;
+ field public final android.car.diagnostic.CarDiagnosticEvent.IgnitionMonitor EGR;
+ field public final android.car.diagnostic.CarDiagnosticEvent.IgnitionMonitor catalyst;
+ field public final android.car.diagnostic.CarDiagnosticEvent.IgnitionMonitor evaporativeSystem;
+ field public final android.car.diagnostic.CarDiagnosticEvent.IgnitionMonitor heatedCatalyst;
+ field public final android.car.diagnostic.CarDiagnosticEvent.IgnitionMonitor oxygenSensor;
+ field public final android.car.diagnostic.CarDiagnosticEvent.IgnitionMonitor oxygenSensorHeater;
+ field public final android.car.diagnostic.CarDiagnosticEvent.IgnitionMonitor secondaryAirSystem;
+ }
+
+ public final class CarDiagnosticManager {
+ method public boolean clearFreezeFrames(long...);
+ method @Nullable public android.car.diagnostic.CarDiagnosticEvent getFreezeFrame(long);
+ method public long[] getFreezeFrameTimestamps();
+ method @Nullable public android.car.diagnostic.CarDiagnosticEvent getLatestLiveFrame();
+ method public boolean isClearFreezeFramesSupported();
+ method public boolean isFreezeFrameNotificationSupported();
+ method public boolean isGetFreezeFrameSupported();
+ method public boolean isLiveFrameSupported();
+ method public boolean isSelectiveClearFreezeFramesSupported();
+ method public void onCarDisconnected();
+ method public boolean registerListener(android.car.diagnostic.CarDiagnosticManager.OnDiagnosticEventListener, @android.car.diagnostic.CarDiagnosticManager.FrameType int, int);
+ method public void unregisterListener(android.car.diagnostic.CarDiagnosticManager.OnDiagnosticEventListener);
+ field public static final int FRAME_TYPE_FREEZE = 1; // 0x1
+ field public static final int FRAME_TYPE_LIVE = 0; // 0x0
+ }
+
+ @IntDef({android.car.diagnostic.CarDiagnosticManager.FRAME_TYPE_LIVE, android.car.diagnostic.CarDiagnosticManager.FRAME_TYPE_FREEZE}) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface CarDiagnosticManager.FrameType {
+ }
+
+ public static interface CarDiagnosticManager.OnDiagnosticEventListener {
+ method public void onDiagnosticEvent(android.car.diagnostic.CarDiagnosticEvent);
+ }
+
+ public final class FloatSensorIndex {
+ field public static final int ABSOLUTE_EVAPORATION_SYSTEM_VAPOR_PRESSURE = 58; // 0x3a
+ field public static final int ABSOLUTE_LOAD_VALUE = 48; // 0x30
+ field public static final int ABSOLUTE_THROTTLE_POSITION_B = 51; // 0x33
+ field public static final int ABSOLUTE_THROTTLE_POSITION_C = 52; // 0x34
+ field public static final int ACCELERATOR_PEDAL_POSITION_D = 53; // 0x35
+ field public static final int ACCELERATOR_PEDAL_POSITION_E = 54; // 0x36
+ field public static final int ACCELERATOR_PEDAL_POSITION_F = 55; // 0x37
+ field public static final int CALCULATED_ENGINE_LOAD = 0; // 0x0
+ field public static final int CATALYST_TEMPERATURE_BANK1_SENSOR1 = 44; // 0x2c
+ field public static final int CATALYST_TEMPERATURE_BANK1_SENSOR2 = 46; // 0x2e
+ field public static final int CATALYST_TEMPERATURE_BANK2_SENSOR1 = 45; // 0x2d
+ field public static final int CATALYST_TEMPERATURE_BANK2_SENSOR2 = 47; // 0x2f
+ field public static final int COMMANDED_EVAPORATIVE_PURGE = 41; // 0x29
+ field public static final int COMMANDED_EXHAUST_GAS_RECIRCULATION = 39; // 0x27
+ field public static final int COMMANDED_THROTTLE_ACTUATOR = 56; // 0x38
+ field public static final int ENGINE_COOLANT_TEMPERATURE = 1; // 0x1
+ field public static final int ENGINE_FUEL_RATE = 70; // 0x46
+ field public static final int ENGINE_RPM = 8; // 0x8
+ field public static final int ETHANOL_FUEL_PERCENTAGE = 57; // 0x39
+ field public static final int EVAPORATION_SYSTEM_VAPOR_PRESSURE = 43; // 0x2b
+ field public static final int EXHAUST_GAS_RECIRCULATION_ERROR = 40; // 0x28
+ field public static final int FUEL_AIR_COMMANDED_EQUIVALENCE_RATIO = 49; // 0x31
+ field public static final int FUEL_INJECTION_TIMING = 69; // 0x45
+ field public static final int FUEL_PRESSURE = 6; // 0x6
+ field public static final int FUEL_RAIL_GAUGE_PRESSURE = 38; // 0x26
+ field public static final int FUEL_RAIL_PRESSURE = 37; // 0x25
+ field public static final int FUEL_TANK_LEVEL_INPUT = 42; // 0x2a
+ field public static final int HYBRID_BATTERY_PACK_REMAINING_LIFE = 68; // 0x44
+ field public static final int INTAKE_MANIFOLD_ABSOLUTE_PRESSURE = 7; // 0x7
+ field public static final int LAST_SYSTEM = 70; // 0x46
+ field public static final int LONG_TERM_FUEL_TRIM_BANK1 = 3; // 0x3
+ field public static final int LONG_TERM_FUEL_TRIM_BANK2 = 5; // 0x5
+ field public static final int LONG_TERM_SECONDARY_OXYGEN_SENSOR_TRIM_BANK1 = 63; // 0x3f
+ field public static final int LONG_TERM_SECONDARY_OXYGEN_SENSOR_TRIM_BANK2 = 64; // 0x40
+ field public static final int LONG_TERM_SECONDARY_OXYGEN_SENSOR_TRIM_BANK3 = 65; // 0x41
+ field public static final int LONG_TERM_SECONDARY_OXYGEN_SENSOR_TRIM_BANK4 = 66; // 0x42
+ field public static final int MAF_AIR_FLOW_RATE = 11; // 0xb
+ field public static final int OXYGEN_SENSOR1_FUEL_AIR_EQUIVALENCE_RATIO = 15; // 0xf
+ field public static final int OXYGEN_SENSOR1_SHORT_TERM_FUEL_TRIM = 14; // 0xe
+ field public static final int OXYGEN_SENSOR1_VOLTAGE = 13; // 0xd
+ field public static final int OXYGEN_SENSOR2_FUEL_AIR_EQUIVALENCE_RATIO = 18; // 0x12
+ field public static final int OXYGEN_SENSOR2_SHORT_TERM_FUEL_TRIM = 17; // 0x11
+ field public static final int OXYGEN_SENSOR2_VOLTAGE = 16; // 0x10
+ field public static final int OXYGEN_SENSOR3_FUEL_AIR_EQUIVALENCE_RATIO = 21; // 0x15
+ field public static final int OXYGEN_SENSOR3_SHORT_TERM_FUEL_TRIM = 20; // 0x14
+ field public static final int OXYGEN_SENSOR3_VOLTAGE = 19; // 0x13
+ field public static final int OXYGEN_SENSOR4_FUEL_AIR_EQUIVALENCE_RATIO = 24; // 0x18
+ field public static final int OXYGEN_SENSOR4_SHORT_TERM_FUEL_TRIM = 23; // 0x17
+ field public static final int OXYGEN_SENSOR4_VOLTAGE = 22; // 0x16
+ field public static final int OXYGEN_SENSOR5_FUEL_AIR_EQUIVALENCE_RATIO = 27; // 0x1b
+ field public static final int OXYGEN_SENSOR5_SHORT_TERM_FUEL_TRIM = 26; // 0x1a
+ field public static final int OXYGEN_SENSOR5_VOLTAGE = 25; // 0x19
+ field public static final int OXYGEN_SENSOR6_FUEL_AIR_EQUIVALENCE_RATIO = 30; // 0x1e
+ field public static final int OXYGEN_SENSOR6_SHORT_TERM_FUEL_TRIM = 29; // 0x1d
+ field public static final int OXYGEN_SENSOR6_VOLTAGE = 28; // 0x1c
+ field public static final int OXYGEN_SENSOR7_FUEL_AIR_EQUIVALENCE_RATIO = 33; // 0x21
+ field public static final int OXYGEN_SENSOR7_SHORT_TERM_FUEL_TRIM = 32; // 0x20
+ field public static final int OXYGEN_SENSOR7_VOLTAGE = 31; // 0x1f
+ field public static final int OXYGEN_SENSOR8_FUEL_AIR_EQUIVALENCE_RATIO = 36; // 0x24
+ field public static final int OXYGEN_SENSOR8_SHORT_TERM_FUEL_TRIM = 35; // 0x23
+ field public static final int OXYGEN_SENSOR8_VOLTAGE = 34; // 0x22
+ field public static final int RELATIVE_ACCELERATOR_PEDAL_POSITION = 67; // 0x43
+ field public static final int RELATIVE_THROTTLE_POSITION = 50; // 0x32
+ field public static final int SHORT_TERM_FUEL_TRIM_BANK1 = 2; // 0x2
+ field public static final int SHORT_TERM_FUEL_TRIM_BANK2 = 4; // 0x4
+ field public static final int SHORT_TERM_SECONDARY_OXYGEN_SENSOR_TRIM_BANK1 = 59; // 0x3b
+ field public static final int SHORT_TERM_SECONDARY_OXYGEN_SENSOR_TRIM_BANK2 = 60; // 0x3c
+ field public static final int SHORT_TERM_SECONDARY_OXYGEN_SENSOR_TRIM_BANK3 = 61; // 0x3d
+ field public static final int SHORT_TERM_SECONDARY_OXYGEN_SENSOR_TRIM_BANK4 = 62; // 0x3e
+ field public static final int THROTTLE_POSITION = 12; // 0xc
+ field public static final int TIMING_ADVANCE = 10; // 0xa
+ field public static final int VEHICLE_SPEED = 9; // 0x9
+ field public static final int VENDOR_START = 71; // 0x47
+ }
+
+ public final class IntegerSensorIndex {
+ field public static final int ABSOLUTE_BAROMETRIC_PRESSURE = 11; // 0xb
+ field public static final int AMBIENT_AIR_TEMPERATURE = 13; // 0xd
+ field public static final int COMMANDED_SECONDARY_AIR_STATUS = 5; // 0x5
+ field public static final int CONTROL_MODULE_VOLTAGE = 12; // 0xc
+ field public static final int DISTANCE_TRAVELED_SINCE_CODES_CLEARED = 10; // 0xa
+ field public static final int DISTANCE_TRAVELED_WITH_MALFUNCTION_INDICATOR_LIGHT_ON = 8; // 0x8
+ field public static final int DRIVER_DEMAND_PERCENT_TORQUE = 24; // 0x18
+ field public static final int ENGINE_ACTUAL_PERCENT_TORQUE = 25; // 0x19
+ field public static final int ENGINE_OIL_TEMPERATURE = 23; // 0x17
+ field public static final int ENGINE_PERCENT_TORQUE_DATA_IDLE = 27; // 0x1b
+ field public static final int ENGINE_PERCENT_TORQUE_DATA_POINT1 = 28; // 0x1c
+ field public static final int ENGINE_PERCENT_TORQUE_DATA_POINT2 = 29; // 0x1d
+ field public static final int ENGINE_PERCENT_TORQUE_DATA_POINT3 = 30; // 0x1e
+ field public static final int ENGINE_PERCENT_TORQUE_DATA_POINT4 = 31; // 0x1f
+ field public static final int ENGINE_REFERENCE_PERCENT_TORQUE = 26; // 0x1a
+ field public static final int FUEL_RAIL_ABSOLUTE_PRESSURE = 22; // 0x16
+ field public static final int FUEL_SYSTEM_STATUS = 0; // 0x0
+ field public static final int FUEL_TYPE = 21; // 0x15
+ field public static final int IGNITION_MONITORS_SUPPORTED = 2; // 0x2
+ field public static final int IGNITION_SPECIFIC_MONITORS = 3; // 0x3
+ field public static final int INTAKE_AIR_TEMPERATURE = 4; // 0x4
+ field public static final int LAST_SYSTEM = 31; // 0x1f
+ field public static final int MALFUNCTION_INDICATOR_LIGHT_ON = 1; // 0x1
+ field public static final int MAX_AIR_FLOW_RATE_FROM_MASS_AIR_FLOW_SENSOR = 20; // 0x14
+ field public static final int MAX_FUEL_AIR_EQUIVALENCE_RATIO = 16; // 0x10
+ field public static final int MAX_INTAKE_MANIFOLD_ABSOLUTE_PRESSURE = 19; // 0x13
+ field public static final int MAX_OXYGEN_SENSOR_CURRENT = 18; // 0x12
+ field public static final int MAX_OXYGEN_SENSOR_VOLTAGE = 17; // 0x11
+ field public static final int NUM_OXYGEN_SENSORS_PRESENT = 6; // 0x6
+ field public static final int RUNTIME_SINCE_ENGINE_START = 7; // 0x7
+ field public static final int TIME_SINCE_TROUBLE_CODES_CLEARED = 15; // 0xf
+ field public static final int TIME_WITH_MALFUNCTION_LIGHT_ON = 14; // 0xe
+ field public static final int VENDOR_START = 32; // 0x20
+ field public static final int WARMUPS_SINCE_CODES_CLEARED = 9; // 0x9
}
}
package android.car.drivingstate {
+ public final class CarDrivingStateEvent implements android.os.Parcelable {
+ ctor public CarDrivingStateEvent(int, long);
+ method public int describeContents();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.car.drivingstate.CarDrivingStateEvent> CREATOR;
+ field public static final int DRIVING_STATE_IDLING = 1; // 0x1
+ field public static final int DRIVING_STATE_MOVING = 2; // 0x2
+ field public static final int DRIVING_STATE_PARKED = 0; // 0x0
+ field public static final int DRIVING_STATE_UNKNOWN = -1; // 0xffffffff
+ field public final int eventValue;
+ field public final long timeStamp;
+ }
+
public final class CarDrivingStateManager {
+ method @Nullable public android.car.drivingstate.CarDrivingStateEvent getCurrentCarDrivingState();
method public void injectDrivingState(int);
+ method public void registerListener(@NonNull android.car.drivingstate.CarDrivingStateManager.CarDrivingStateEventListener);
+ method public void unregisterListener();
+ }
+
+ public static interface CarDrivingStateManager.CarDrivingStateEventListener {
+ method public void onDrivingStateChanged(android.car.drivingstate.CarDrivingStateEvent);
+ }
+
+ public final class CarUxRestrictionsConfiguration implements android.os.Parcelable {
+ method public int describeContents();
+ method @Nullable public Integer getPhysicalPort();
+ method @NonNull public android.car.drivingstate.CarUxRestrictions getUxRestrictions(int, float);
+ method @NonNull public android.car.drivingstate.CarUxRestrictions getUxRestrictions(int, @FloatRange(from=0.0f) float, @NonNull String);
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.car.drivingstate.CarUxRestrictionsConfiguration> CREATOR;
+ }
+
+ public final class CarUxRestrictionsManager {
+ method @Nullable @RequiresPermission(android.car.Car.PERMISSION_CAR_UX_RESTRICTIONS_CONFIGURATION) public java.util.List<android.car.drivingstate.CarUxRestrictionsConfiguration> getConfigs();
+ method @Nullable public android.car.drivingstate.CarUxRestrictions getCurrentCarUxRestrictions(int);
+ method @NonNull @RequiresPermission(android.car.Car.PERMISSION_CAR_UX_RESTRICTIONS_CONFIGURATION) public String getRestrictionMode();
+ method @Nullable @RequiresPermission(android.car.Car.PERMISSION_CAR_UX_RESTRICTIONS_CONFIGURATION) public java.util.List<android.car.drivingstate.CarUxRestrictionsConfiguration> getStagedConfigs();
+ method public void onCarDisconnected();
+ method @RequiresPermission(android.car.Car.PERMISSION_CAR_UX_RESTRICTIONS_CONFIGURATION) public boolean saveUxRestrictionsConfigurationForNextBoot(@NonNull java.util.List<android.car.drivingstate.CarUxRestrictionsConfiguration>);
+ method @RequiresPermission(android.car.Car.PERMISSION_CAR_UX_RESTRICTIONS_CONFIGURATION) public boolean saveUxRestrictionsConfigurationForNextBoot(@NonNull android.car.drivingstate.CarUxRestrictionsConfiguration);
+ method public void setListener(int, @NonNull android.car.drivingstate.CarUxRestrictionsManager.OnUxRestrictionsChangedListener);
+ method @RequiresPermission(android.car.Car.PERMISSION_CAR_UX_RESTRICTIONS_CONFIGURATION) public boolean setRestrictionMode(@NonNull String);
+ field public static final String UX_RESTRICTION_MODE_BASELINE = "baseline";
+ }
+
+}
+
+package android.car.evs {
+
+ public final class CarEvsBufferDescriptor implements android.os.Parcelable {
+ ctor public CarEvsBufferDescriptor(int, @NonNull android.hardware.HardwareBuffer);
+ method public int describeContents();
+ method @NonNull public android.hardware.HardwareBuffer getHardwareBuffer();
+ method public int getId();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.car.evs.CarEvsBufferDescriptor> CREATOR;
+ }
+
+ public final class CarEvsManager {
+ method @RequiresPermission(android.car.Car.PERMISSION_MONITOR_CAR_EVS_STATUS) public void clearStatusListener();
+ method @NonNull @RequiresPermission(android.car.Car.PERMISSION_CONTROL_CAR_EVS_ACTIVITY) public android.os.IBinder generateSessionToken();
+ method @NonNull @RequiresPermission(android.car.Car.PERMISSION_MONITOR_CAR_EVS_STATUS) public android.car.evs.CarEvsStatus getCurrentStatus();
+ method @RequiresPermission(android.car.Car.PERMISSION_MONITOR_CAR_EVS_STATUS) public boolean isSupported(int);
+ method @RequiresPermission(android.car.Car.PERMISSION_USE_CAR_EVS_CAMERA) public void returnFrameBuffer(@NonNull android.car.evs.CarEvsBufferDescriptor);
+ method @RequiresPermission(android.car.Car.PERMISSION_MONITOR_CAR_EVS_STATUS) public void setStatusListener(@NonNull java.util.concurrent.Executor, @NonNull android.car.evs.CarEvsManager.CarEvsStatusListener);
+ method @RequiresPermission(android.car.Car.PERMISSION_REQUEST_CAR_EVS_ACTIVITY) public int startActivity(int);
+ method @RequiresPermission(android.car.Car.PERMISSION_USE_CAR_EVS_CAMERA) public int startVideoStream(int, @Nullable android.os.IBinder, @NonNull java.util.concurrent.Executor, @NonNull android.car.evs.CarEvsManager.CarEvsStreamCallback);
+ method @RequiresPermission(android.car.Car.PERMISSION_REQUEST_CAR_EVS_ACTIVITY) public void stopActivity();
+ method @RequiresPermission(android.car.Car.PERMISSION_USE_CAR_EVS_CAMERA) public void stopVideoStream();
+ field public static final int ERROR_BUSY = -2; // 0xfffffffe
+ field public static final int ERROR_NONE = 0; // 0x0
+ field public static final int ERROR_UNAVAILABLE = -1; // 0xffffffff
+ field public static final String EXTRA_SESSION_TOKEN = "android.car.evs.extra.SESSION_TOKEN";
+ field public static final int SERVICE_STATE_ACTIVE = 3; // 0x3
+ field public static final int SERVICE_STATE_INACTIVE = 1; // 0x1
+ field public static final int SERVICE_STATE_REQUESTED = 2; // 0x2
+ field public static final int SERVICE_STATE_UNAVAILABLE = 0; // 0x0
+ field public static final int SERVICE_TYPE_REARVIEW = 0; // 0x0
+ field public static final int SERVICE_TYPE_SURROUNDVIEW = 1; // 0x1
+ field public static final int STREAM_EVENT_FRAME_DROPPED = 3; // 0x3
+ field public static final int STREAM_EVENT_NONE = 0; // 0x0
+ field public static final int STREAM_EVENT_OTHER_ERRORS = 7; // 0x7
+ field public static final int STREAM_EVENT_PARAMETER_CHANGED = 5; // 0x5
+ field public static final int STREAM_EVENT_PRIMARY_OWNER_CHANGED = 6; // 0x6
+ field public static final int STREAM_EVENT_STREAM_STARTED = 1; // 0x1
+ field public static final int STREAM_EVENT_STREAM_STOPPED = 2; // 0x2
+ field public static final int STREAM_EVENT_TIMEOUT = 4; // 0x4
+ }
+
+ public static interface CarEvsManager.CarEvsStatusListener {
+ method public void onStatusChanged(@NonNull android.car.evs.CarEvsStatus);
+ }
+
+ public static interface CarEvsManager.CarEvsStreamCallback {
+ method public default void onNewFrame(@NonNull android.car.evs.CarEvsBufferDescriptor);
+ method public default void onStreamEvent(int);
+ }
+
+ public final class CarEvsStatus implements android.os.Parcelable {
+ ctor public CarEvsStatus(int, int);
+ method public int describeContents();
+ method public int getServiceType();
+ method public int getState();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.car.evs.CarEvsStatus> CREATOR;
+ }
+
+}
+
+package android.car.hardware {
+
+ public final class CarHvacFanDirection {
+ field public static final int DEFROST = 4; // 0x4
+ field public static final int DEFROST_AND_FLOOR = 6; // 0x6
+ field public static final int FACE = 1; // 0x1
+ field public static final int FACE_AND_FLOOR = 3; // 0x3
+ field public static final int FLOOR = 2; // 0x2
+ field public static final int UNKNOWN = 0; // 0x0
+ }
+
+ public final class CarPropertyConfig<T> implements android.os.Parcelable {
+ method public static <T> android.car.hardware.CarPropertyConfig.Builder<T> newBuilder(Class<T>, int, int, int);
+ }
+
+ public static class CarPropertyConfig.Builder<T> {
+ method public android.car.hardware.CarPropertyConfig.Builder<T> addArea(int);
+ method public android.car.hardware.CarPropertyConfig.Builder<T> addAreaConfig(int, T, T);
+ method public android.car.hardware.CarPropertyConfig.Builder<T> addAreas(int[]);
+ method public android.car.hardware.CarPropertyConfig<T> build();
+ method public android.car.hardware.CarPropertyConfig.Builder<T> setAccess(int);
+ method public android.car.hardware.CarPropertyConfig.Builder<T> setChangeMode(int);
+ method public android.car.hardware.CarPropertyConfig.Builder<T> setConfigArray(java.util.ArrayList<java.lang.Integer>);
+ method public android.car.hardware.CarPropertyConfig.Builder<T> setConfigString(String);
+ method public android.car.hardware.CarPropertyConfig.Builder<T> setMaxSampleRate(float);
+ method public android.car.hardware.CarPropertyConfig.Builder<T> setMinSampleRate(float);
+ }
+
+ @Deprecated public final class CarVendorExtensionManager {
+ method @Deprecated public <E> E getGlobalProperty(Class<E>, int);
+ method @Deprecated public java.util.List<android.car.hardware.CarPropertyConfig> getProperties();
+ method @Deprecated public <E> E getProperty(Class<E>, int, int);
+ method @Deprecated public boolean isPropertyAvailable(int, int);
+ method @Deprecated public void registerCallback(android.car.hardware.CarVendorExtensionManager.CarVendorExtensionCallback);
+ method @Deprecated public <E> void setGlobalProperty(Class<E>, int, E);
+ method @Deprecated public <E> void setProperty(Class<E>, int, int, E);
+ method @Deprecated public void unregisterCallback(android.car.hardware.CarVendorExtensionManager.CarVendorExtensionCallback);
+ }
+
+ @Deprecated public static interface CarVendorExtensionManager.CarVendorExtensionCallback {
+ method @Deprecated public void onChangeEvent(android.car.hardware.CarPropertyValue);
+ method @Deprecated public void onErrorEvent(int, int);
+ }
+
+}
+
+package android.car.hardware.cabin {
+
+ @Deprecated public final class CarCabinManager {
+ method @Deprecated public boolean getBooleanProperty(int, int);
+ method @Deprecated public float getFloatProperty(int, int);
+ method @Deprecated public int getIntProperty(int, int);
+ method @Deprecated public java.util.List<android.car.hardware.CarPropertyConfig> getPropertyList();
+ method @Deprecated public static boolean isZonedProperty(int);
+ method @Deprecated public void registerCallback(android.car.hardware.cabin.CarCabinManager.CarCabinEventCallback);
+ method @Deprecated public void setBooleanProperty(int, int, boolean);
+ method @Deprecated public void setFloatProperty(int, int, float);
+ method @Deprecated public void setIntProperty(int, int, int);
+ method @Deprecated public void unregisterCallback(android.car.hardware.cabin.CarCabinManager.CarCabinEventCallback);
+ field @Deprecated public static final int ID_DOOR_LOCK = 371198722; // 0x16200b02
+ field @Deprecated public static final int ID_DOOR_MOVE = 373295873; // 0x16400b01
+ field @Deprecated public static final int ID_DOOR_POS = 373295872; // 0x16400b00
+ field @Deprecated public static final int ID_MIRROR_FOLD = 287312709; // 0x11200b45
+ field @Deprecated public static final int ID_MIRROR_LOCK = 287312708; // 0x11200b44
+ field @Deprecated public static final int ID_MIRROR_Y_MOVE = 339741507; // 0x14400b43
+ field @Deprecated public static final int ID_MIRROR_Y_POS = 339741506; // 0x14400b42
+ field @Deprecated public static final int ID_MIRROR_Z_MOVE = 339741505; // 0x14400b41
+ field @Deprecated public static final int ID_MIRROR_Z_POS = 339741504; // 0x14400b40
+ field @Deprecated public static final int ID_SEAT_BACKREST_ANGLE_1_MOVE = 356518792; // 0x15400b88
+ field @Deprecated public static final int ID_SEAT_BACKREST_ANGLE_1_POS = 356518791; // 0x15400b87
+ field @Deprecated public static final int ID_SEAT_BACKREST_ANGLE_2_MOVE = 356518794; // 0x15400b8a
+ field @Deprecated public static final int ID_SEAT_BACKREST_ANGLE_2_POS = 356518793; // 0x15400b89
+ field @Deprecated public static final int ID_SEAT_BELT_BUCKLED = 354421634; // 0x15200b82
+ field @Deprecated public static final int ID_SEAT_BELT_HEIGHT_MOVE = 356518788; // 0x15400b84
+ field @Deprecated public static final int ID_SEAT_BELT_HEIGHT_POS = 356518787; // 0x15400b83
+ field @Deprecated public static final int ID_SEAT_DEPTH_MOVE = 356518798; // 0x15400b8e
+ field @Deprecated public static final int ID_SEAT_DEPTH_POS = 356518797; // 0x15400b8d
+ field @Deprecated public static final int ID_SEAT_FORE_AFT_MOVE = 356518790; // 0x15400b86
+ field @Deprecated public static final int ID_SEAT_FORE_AFT_POS = 356518789; // 0x15400b85
+ field @Deprecated public static final int ID_SEAT_HEADREST_ANGLE_MOVE = 356518808; // 0x15400b98
+ field @Deprecated public static final int ID_SEAT_HEADREST_ANGLE_POS = 356518807; // 0x15400b97
+ field @Deprecated public static final int ID_SEAT_HEADREST_FORE_AFT_MOVE = 356518810; // 0x15400b9a
+ field @Deprecated public static final int ID_SEAT_HEADREST_FORE_AFT_POS = 356518809; // 0x15400b99
+ field @Deprecated public static final int ID_SEAT_HEADREST_HEIGHT_MOVE = 356518806; // 0x15400b96
+ field @Deprecated public static final int ID_SEAT_HEADREST_HEIGHT_POS = 356518805; // 0x15400b95
+ field @Deprecated public static final int ID_SEAT_HEIGHT_MOVE = 356518796; // 0x15400b8c
+ field @Deprecated public static final int ID_SEAT_HEIGHT_POS = 356518795; // 0x15400b8b
+ field @Deprecated public static final int ID_SEAT_LUMBAR_FORE_AFT_MOVE = 356518802; // 0x15400b92
+ field @Deprecated public static final int ID_SEAT_LUMBAR_FORE_AFT_POS = 356518801; // 0x15400b91
+ field @Deprecated public static final int ID_SEAT_LUMBAR_SIDE_SUPPORT_MOVE = 356518804; // 0x15400b94
+ field @Deprecated public static final int ID_SEAT_LUMBAR_SIDE_SUPPORT_POS = 356518803; // 0x15400b93
+ field @Deprecated public static final int ID_SEAT_MEMORY_SELECT = 356518784; // 0x15400b80
+ field @Deprecated public static final int ID_SEAT_MEMORY_SET = 356518785; // 0x15400b81
+ field @Deprecated public static final int ID_SEAT_TILT_MOVE = 356518800; // 0x15400b90
+ field @Deprecated public static final int ID_SEAT_TILT_POS = 356518799; // 0x15400b8f
+ field @Deprecated public static final int ID_WINDOW_LOCK = 322964420; // 0x13400bc4
+ field @Deprecated public static final int ID_WINDOW_MOVE = 322964417; // 0x13400bc1
+ field @Deprecated public static final int ID_WINDOW_POS = 322964416; // 0x13400bc0
+ }
+
+ @Deprecated public static interface CarCabinManager.CarCabinEventCallback {
+ method @Deprecated public void onChangeEvent(android.car.hardware.CarPropertyValue);
+ method @Deprecated public void onErrorEvent(int, int);
+ }
+
+}
+
+package android.car.hardware.hvac {
+
+ @Deprecated public final class CarHvacManager {
+ method @Deprecated public boolean getBooleanProperty(int, int);
+ method @Deprecated public float getFloatProperty(int, int);
+ method @Deprecated public int getIntProperty(int, int);
+ method @Deprecated public java.util.List<android.car.hardware.CarPropertyConfig> getPropertyList();
+ method @Deprecated public boolean isPropertyAvailable(int, int);
+ method @Deprecated public void registerCallback(android.car.hardware.hvac.CarHvacManager.CarHvacEventCallback);
+ method @Deprecated public void setBooleanProperty(int, int, boolean);
+ method @Deprecated public void setFloatProperty(int, int, float);
+ method @Deprecated public void setIntProperty(int, int, int);
+ method @Deprecated public void unregisterCallback(android.car.hardware.hvac.CarHvacManager.CarHvacEventCallback);
+ field @Deprecated public static final int FAN_DIRECTION_DEFROST = 4; // 0x4
+ field @Deprecated public static final int FAN_DIRECTION_FACE = 1; // 0x1
+ field @Deprecated public static final int FAN_DIRECTION_FLOOR = 2; // 0x2
+ field @Deprecated public static final int ID_MIRROR_DEFROSTER_ON = 339739916; // 0x1440050c
+ field @Deprecated public static final int ID_OUTSIDE_AIR_TEMP = 291505923; // 0x11600703
+ field @Deprecated public static final int ID_STEERING_WHEEL_HEAT = 289408269; // 0x1140050d
+ field @Deprecated public static final int ID_TEMPERATURE_DISPLAY_UNITS = 289408270; // 0x1140050e
+ field @Deprecated public static final int ID_WINDOW_DEFROSTER_ON = 320865540; // 0x13200504
+ field @Deprecated public static final int ID_ZONED_AC_ON = 354419973; // 0x15200505
+ field @Deprecated public static final int ID_ZONED_AIR_RECIRCULATION_ON = 354419976; // 0x15200508
+ field @Deprecated public static final int ID_ZONED_AUTOMATIC_MODE_ON = 354419978; // 0x1520050a
+ field @Deprecated public static final int ID_ZONED_DUAL_ZONE_ON = 354419977; // 0x15200509
+ field @Deprecated public static final int ID_ZONED_FAN_DIRECTION = 356517121; // 0x15400501
+ field @Deprecated public static final int ID_ZONED_FAN_DIRECTION_AVAILABLE = 356582673; // 0x15410511
+ field @Deprecated public static final int ID_ZONED_FAN_SPEED_RPM = 356517135; // 0x1540050f
+ field @Deprecated public static final int ID_ZONED_FAN_SPEED_SETPOINT = 356517120; // 0x15400500
+ field @Deprecated public static final int ID_ZONED_HVAC_AUTO_RECIRC_ON = 354419986; // 0x15200512
+ field @Deprecated public static final int ID_ZONED_HVAC_POWER_ON = 354419984; // 0x15200510
+ field @Deprecated public static final int ID_ZONED_MAX_AC_ON = 354419974; // 0x15200506
+ field @Deprecated public static final int ID_ZONED_MAX_DEFROST_ON = 354419975; // 0x15200507
+ field @Deprecated public static final int ID_ZONED_SEAT_TEMP = 356517131; // 0x1540050b
+ field @Deprecated public static final int ID_ZONED_TEMP_ACTUAL = 358614274; // 0x15600502
+ field @Deprecated public static final int ID_ZONED_TEMP_SETPOINT = 358614275; // 0x15600503
+ }
+
+ @Deprecated public static interface CarHvacManager.CarHvacEventCallback {
+ method @Deprecated public void onChangeEvent(android.car.hardware.CarPropertyValue);
+ method @Deprecated public void onErrorEvent(int, int);
}
}
@@ -111,7 +976,146 @@
package android.car.hardware.power {
public class CarPowerManager {
+ method @RequiresPermission(android.car.Car.PERMISSION_CONTROL_CAR_POWER_POLICY) public void applyPowerPolicy(@NonNull String);
+ method @RequiresPermission(android.car.Car.PERMISSION_CAR_POWER) public void clearListener();
+ method @RequiresPermission(android.car.Car.PERMISSION_CAR_POWER) public int getPowerState();
method public static boolean isCompletionAllowed(int);
+ method @RequiresPermission(android.car.Car.PERMISSION_CAR_POWER) public void setListener(@NonNull java.util.concurrent.Executor, @NonNull android.car.hardware.power.CarPowerManager.CarPowerStateListener);
+ method @RequiresPermission(android.car.Car.PERMISSION_CONTROL_SHUTDOWN_PROCESS) public void setListenerWithCompletion(@NonNull java.util.concurrent.Executor, @NonNull android.car.hardware.power.CarPowerManager.CarPowerStateListenerWithCompletion);
+ method @RequiresPermission(android.car.Car.PERMISSION_CONTROL_CAR_POWER_POLICY) public void setPowerPolicyGroup(@NonNull String);
+ field public static final int STATE_HIBERNATION_ENTER = 9; // 0x9
+ field public static final int STATE_HIBERNATION_EXIT = 10; // 0xa
+ field public static final int STATE_INVALID = 0; // 0x0
+ field public static final int STATE_ON = 6; // 0x6
+ field public static final int STATE_POST_HIBERNATION_ENTER = 14; // 0xe
+ field public static final int STATE_POST_SHUTDOWN_ENTER = 13; // 0xd
+ field public static final int STATE_POST_SUSPEND_ENTER = 12; // 0xc
+ field public static final int STATE_PRE_SHUTDOWN_PREPARE = 11; // 0xb
+ field public static final int STATE_SHUTDOWN_CANCELLED = 8; // 0x8
+ field public static final int STATE_SHUTDOWN_ENTER = 5; // 0x5
+ field public static final int STATE_SHUTDOWN_PREPARE = 7; // 0x7
+ field public static final int STATE_SUSPEND_ENTER = 2; // 0x2
+ field public static final int STATE_SUSPEND_EXIT = 3; // 0x3
+ field public static final int STATE_WAIT_FOR_VHAL = 1; // 0x1
+ }
+
+ public static interface CarPowerManager.CarPowerStateListener {
+ method public void onStateChanged(int);
+ }
+
+ public static interface CarPowerManager.CarPowerStateListenerWithCompletion {
+ method public void onStateChanged(int, @Nullable android.car.hardware.power.CarPowerManager.CompletablePowerStateChangeFuture);
+ }
+
+ public static interface CarPowerManager.CompletablePowerStateChangeFuture {
+ method public void complete();
+ method public long getExpirationTime();
+ }
+
+}
+
+package android.car.hardware.property {
+
+ public final class VehicleVendorPermission {
+ field public static final String PERMISSION_GET_CAR_VENDOR_CATEGORY_1 = "android.car.permission.GET_CAR_VENDOR_CATEGORY_1";
+ field public static final String PERMISSION_GET_CAR_VENDOR_CATEGORY_10 = "android.car.permission.GET_CAR_VENDOR_CATEGORY_10";
+ field public static final String PERMISSION_GET_CAR_VENDOR_CATEGORY_2 = "android.car.permission.GET_CAR_VENDOR_CATEGORY_2";
+ field public static final String PERMISSION_GET_CAR_VENDOR_CATEGORY_3 = "android.car.permission.GET_CAR_VENDOR_CATEGORY_3";
+ field public static final String PERMISSION_GET_CAR_VENDOR_CATEGORY_4 = "android.car.permission.GET_CAR_VENDOR_CATEGORY_4";
+ field public static final String PERMISSION_GET_CAR_VENDOR_CATEGORY_5 = "android.car.permission.GET_CAR_VENDOR_CATEGORY_5";
+ field public static final String PERMISSION_GET_CAR_VENDOR_CATEGORY_6 = "android.car.permission.GET_CAR_VENDOR_CATEGORY_6";
+ field public static final String PERMISSION_GET_CAR_VENDOR_CATEGORY_7 = "android.car.permission.GET_CAR_VENDOR_CATEGORY_7";
+ field public static final String PERMISSION_GET_CAR_VENDOR_CATEGORY_8 = "android.car.permission.GET_CAR_VENDOR_CATEGORY_8";
+ field public static final String PERMISSION_GET_CAR_VENDOR_CATEGORY_9 = "android.car.permission.GET_CAR_VENDOR_CATEGORY_9";
+ field public static final String PERMISSION_GET_CAR_VENDOR_CATEGORY_DOOR = "android.car.permission.GET_CAR_VENDOR_CATEGORY_DOOR";
+ field public static final String PERMISSION_GET_CAR_VENDOR_CATEGORY_ENGINE = "android.car.permission.GET_CAR_VENDOR_CATEGORY_ENGINE";
+ field public static final String PERMISSION_GET_CAR_VENDOR_CATEGORY_HVAC = "android.car.permission.GET_CAR_VENDOR_CATEGORY_HVAC";
+ field public static final String PERMISSION_GET_CAR_VENDOR_CATEGORY_INFO = "android.car.permission.GET_CAR_VENDOR_CATEGORY_INFO";
+ field public static final String PERMISSION_GET_CAR_VENDOR_CATEGORY_LIGHT = "android.car.permission.GET_CAR_VENDOR_CATEGORY_LIGHT";
+ field public static final String PERMISSION_GET_CAR_VENDOR_CATEGORY_MIRROR = "android.car.permission.GET_CAR_VENDOR_CATEGORY_MIRROR";
+ field public static final String PERMISSION_GET_CAR_VENDOR_CATEGORY_SEAT = "android.car.permission.GET_CAR_VENDOR_CATEGORY_SEAT";
+ field public static final String PERMISSION_GET_CAR_VENDOR_CATEGORY_WINDOW = "android.car.permission.GET_CAR_VENDOR_CATEGORY_WINDOW";
+ field public static final String PERMISSION_SET_CAR_VENDOR_CATEGORY_1 = "android.car.permission.SET_CAR_VENDOR_CATEGORY_1";
+ field public static final String PERMISSION_SET_CAR_VENDOR_CATEGORY_10 = "android.car.permission.SET_CAR_VENDOR_CATEGORY_10";
+ field public static final String PERMISSION_SET_CAR_VENDOR_CATEGORY_2 = "android.car.permission.SET_CAR_VENDOR_CATEGORY_2";
+ field public static final String PERMISSION_SET_CAR_VENDOR_CATEGORY_3 = "android.car.permission.SET_CAR_VENDOR_CATEGORY_3";
+ field public static final String PERMISSION_SET_CAR_VENDOR_CATEGORY_4 = "android.car.permission.SET_CAR_VENDOR_CATEGORY_4";
+ field public static final String PERMISSION_SET_CAR_VENDOR_CATEGORY_5 = "android.car.permission.SET_CAR_VENDOR_CATEGORY_5";
+ field public static final String PERMISSION_SET_CAR_VENDOR_CATEGORY_6 = "android.car.permission.SET_CAR_VENDOR_CATEGORY_6";
+ field public static final String PERMISSION_SET_CAR_VENDOR_CATEGORY_7 = "android.car.permission.SET_CAR_VENDOR_CATEGORY_7";
+ field public static final String PERMISSION_SET_CAR_VENDOR_CATEGORY_8 = "android.car.permission.SET_CAR_VENDOR_CATEGORY_8";
+ field public static final String PERMISSION_SET_CAR_VENDOR_CATEGORY_9 = "android.car.permission.SET_CAR_VENDOR_CATEGORY_9";
+ field public static final String PERMISSION_SET_CAR_VENDOR_CATEGORY_DOOR = "android.car.permission.SET_CAR_VENDOR_CATEGORY_DOOR";
+ field public static final String PERMISSION_SET_CAR_VENDOR_CATEGORY_ENGINE = "android.car.permission.SET_CAR_VENDOR_CATEGORY_ENGINE";
+ field public static final String PERMISSION_SET_CAR_VENDOR_CATEGORY_HVAC = "android.car.permission.SET_CAR_VENDOR_CATEGORY_HVAC";
+ field public static final String PERMISSION_SET_CAR_VENDOR_CATEGORY_INFO = "android.car.permission.SET_CAR_VENDOR_CATEGORY_INFO";
+ field public static final String PERMISSION_SET_CAR_VENDOR_CATEGORY_LIGHT = "android.car.permission.SET_CAR_VENDOR_CATEGORY_LIGHT";
+ field public static final String PERMISSION_SET_CAR_VENDOR_CATEGORY_MIRROR = "android.car.permission.SET_CAR_VENDOR_CATEGORY_MIRROR";
+ field public static final String PERMISSION_SET_CAR_VENDOR_CATEGORY_SEAT = "android.car.permission.SET_CAR_VENDOR_CATEGORY_SEAT";
+ field public static final String PERMISSION_SET_CAR_VENDOR_CATEGORY_WINDOW = "android.car.permission.SET_CAR_VENDOR_CATEGORY_WINDOW";
+ }
+
+}
+
+package android.car.input {
+
+ public final class CarInputManager {
+ method @RequiresPermission(android.Manifest.permission.INJECT_EVENTS) public void injectKeyEvent(@NonNull android.view.KeyEvent, int);
+ method public void releaseInputEventCapture(int);
+ method @RequiresPermission(anyOf={"android.permission.MONITOR_INPUT", android.car.Car.PERMISSION_CAR_MONITOR_INPUT}) public int requestInputEventCapture(int, @NonNull int[], int, @NonNull android.car.input.CarInputManager.CarInputCaptureCallback);
+ method @RequiresPermission(anyOf={"android.permission.MONITOR_INPUT", android.car.Car.PERMISSION_CAR_MONITOR_INPUT}) public int requestInputEventCapture(int, @NonNull int[], int, @NonNull java.util.concurrent.Executor, @NonNull android.car.input.CarInputManager.CarInputCaptureCallback);
+ field public static final int CAPTURE_REQ_FLAGS_ALLOW_DELAYED_GRANT = 1; // 0x1
+ field public static final int CAPTURE_REQ_FLAGS_TAKE_ALL_EVENTS_FOR_DISPLAY = 2; // 0x2
+ field public static final int INPUT_CAPTURE_RESPONSE_DELAYED = 2; // 0x2
+ field public static final int INPUT_CAPTURE_RESPONSE_FAILED = 1; // 0x1
+ field public static final int INPUT_CAPTURE_RESPONSE_SUCCEEDED = 0; // 0x0
+ field public static final int INPUT_TYPE_ALL_INPUTS = 1; // 0x1
+ field public static final int INPUT_TYPE_CUSTOM_INPUT_EVENT = 200; // 0xc8
+ field public static final int INPUT_TYPE_DPAD_KEYS = 100; // 0x64
+ field public static final int INPUT_TYPE_NAVIGATE_KEYS = 101; // 0x65
+ field public static final int INPUT_TYPE_ROTARY_NAVIGATION = 10; // 0xa
+ field public static final int INPUT_TYPE_ROTARY_VOLUME = 11; // 0xb
+ field public static final int INPUT_TYPE_SYSTEM_NAVIGATE_KEYS = 102; // 0x66
+ }
+
+ public static interface CarInputManager.CarInputCaptureCallback {
+ method public default void onCaptureStateChanged(int, @NonNull int[]);
+ method public default void onCustomInputEvents(int, @NonNull java.util.List<android.car.input.CustomInputEvent>);
+ method public default void onKeyEvents(int, @NonNull java.util.List<android.view.KeyEvent>);
+ method public default void onRotaryEvents(int, @NonNull java.util.List<android.car.input.RotaryEvent>);
+ }
+
+ public final class CustomInputEvent implements android.os.Parcelable {
+ ctor public CustomInputEvent(int, int, int);
+ method public int describeContents();
+ method public int getInputCode();
+ method public int getRepeatCounter();
+ method public int getTargetDisplayType();
+ method @NonNull public static String inputCodeToString(int);
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.car.input.CustomInputEvent> CREATOR;
+ field public static final int INPUT_CODE_F1 = 1001; // 0x3e9
+ field public static final int INPUT_CODE_F10 = 1010; // 0x3f2
+ field public static final int INPUT_CODE_F2 = 1002; // 0x3ea
+ field public static final int INPUT_CODE_F3 = 1003; // 0x3eb
+ field public static final int INPUT_CODE_F4 = 1004; // 0x3ec
+ field public static final int INPUT_CODE_F5 = 1005; // 0x3ed
+ field public static final int INPUT_CODE_F6 = 1006; // 0x3ee
+ field public static final int INPUT_CODE_F7 = 1007; // 0x3ef
+ field public static final int INPUT_CODE_F8 = 1008; // 0x3f0
+ field public static final int INPUT_CODE_F9 = 1009; // 0x3f1
+ }
+
+ public final class RotaryEvent implements android.os.Parcelable {
+ ctor public RotaryEvent(int, boolean, @NonNull long[]);
+ method public int describeContents();
+ method public int getInputType();
+ method public int getNumberOfClicks();
+ method public long getUptimeMillisForClick(int);
+ method @NonNull public long[] getUptimeMillisForClicks();
+ method public boolean isClockwise();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.car.input.RotaryEvent> CREATOR;
}
}
@@ -119,7 +1123,305 @@
package android.car.media {
public final class CarAudioManager {
+ method @Deprecated @RequiresPermission(android.car.Car.PERMISSION_CAR_CONTROL_AUDIO_SETTINGS) public android.car.media.CarAudioPatchHandle createAudioPatch(String, int, int);
+ method @NonNull @RequiresPermission(android.car.Car.PERMISSION_CAR_CONTROL_AUDIO_SETTINGS) public java.util.List<java.lang.Integer> getAudioZoneIds();
+ method @Deprecated @NonNull @RequiresPermission(android.car.Car.PERMISSION_CAR_CONTROL_AUDIO_SETTINGS) public String[] getExternalSources();
+ method @RequiresPermission(android.car.Car.PERMISSION_CAR_CONTROL_AUDIO_VOLUME) public int getGroupMaxVolume(int);
+ method @RequiresPermission(android.car.Car.PERMISSION_CAR_CONTROL_AUDIO_VOLUME) public int getGroupMaxVolume(int, int);
+ method @RequiresPermission(android.car.Car.PERMISSION_CAR_CONTROL_AUDIO_VOLUME) public int getGroupMinVolume(int);
+ method @RequiresPermission(android.car.Car.PERMISSION_CAR_CONTROL_AUDIO_VOLUME) public int getGroupMinVolume(int, int);
+ method @RequiresPermission(android.car.Car.PERMISSION_CAR_CONTROL_AUDIO_VOLUME) public int getGroupVolume(int);
+ method @RequiresPermission(android.car.Car.PERMISSION_CAR_CONTROL_AUDIO_VOLUME) public int getGroupVolume(int, int);
+ method @NonNull @RequiresPermission(android.car.Car.PERMISSION_CAR_CONTROL_AUDIO_SETTINGS) public java.util.List<android.media.AudioDeviceInfo> getInputDevicesForZoneId(int);
+ method @Nullable @RequiresPermission(android.car.Car.PERMISSION_CAR_CONTROL_AUDIO_SETTINGS) public android.media.AudioDeviceInfo getOutputDeviceForUsage(int, int);
+ method @NonNull @RequiresPermission(android.car.Car.PERMISSION_CAR_CONTROL_AUDIO_VOLUME) public int[] getUsagesForVolumeGroupId(int);
+ method @NonNull @RequiresPermission(android.car.Car.PERMISSION_CAR_CONTROL_AUDIO_VOLUME) public int[] getUsagesForVolumeGroupId(int, int);
+ method @RequiresPermission(android.car.Car.PERMISSION_CAR_CONTROL_AUDIO_VOLUME) public int getVolumeGroupCount();
+ method @RequiresPermission(android.car.Car.PERMISSION_CAR_CONTROL_AUDIO_VOLUME) public int getVolumeGroupCount(int);
+ method @RequiresPermission(android.car.Car.PERMISSION_CAR_CONTROL_AUDIO_VOLUME) public int getVolumeGroupIdForUsage(int);
+ method @RequiresPermission(android.car.Car.PERMISSION_CAR_CONTROL_AUDIO_VOLUME) public int getVolumeGroupIdForUsage(int, int);
method @Deprecated public boolean isDynamicRoutingEnabled();
+ method @RequiresPermission(android.car.Car.PERMISSION_CAR_CONTROL_AUDIO_VOLUME) public boolean isPlaybackOnVolumeGroupActive(int, int);
+ method @RequiresPermission(android.car.Car.PERMISSION_CAR_CONTROL_AUDIO_VOLUME) public boolean isVolumeGroupMuted(int, int);
+ method @Deprecated @RequiresPermission(android.car.Car.PERMISSION_CAR_CONTROL_AUDIO_SETTINGS) public void releaseAudioPatch(android.car.media.CarAudioPatchHandle);
+ method @RequiresPermission(android.car.Car.PERMISSION_CAR_CONTROL_AUDIO_VOLUME) public void setBalanceTowardRight(float);
+ method @RequiresPermission(android.car.Car.PERMISSION_CAR_CONTROL_AUDIO_VOLUME) public void setFadeTowardFront(float);
+ method @RequiresPermission(android.car.Car.PERMISSION_CAR_CONTROL_AUDIO_VOLUME) public void setGroupVolume(int, int, int);
+ method @RequiresPermission(android.car.Car.PERMISSION_CAR_CONTROL_AUDIO_VOLUME) public void setGroupVolume(int, int, int, int);
+ method @RequiresPermission(android.car.Car.PERMISSION_CAR_CONTROL_AUDIO_VOLUME) public void setVolumeGroupMute(int, int, boolean, int);
+ field public static final String AUDIOFOCUS_EXTRA_RECEIVE_DUCKING_EVENTS = "android.car.media.AUDIOFOCUS_EXTRA_RECEIVE_DUCKING_EVENTS";
+ field public static final int INVALID_AUDIO_ZONE = -1; // 0xffffffff
+ field public static final int PRIMARY_AUDIO_ZONE = 0; // 0x0
+ }
+
+ public final class CarAudioPatchHandle implements android.os.Parcelable {
+ method public int describeContents();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.car.media.CarAudioPatchHandle> CREATOR;
+ }
+
+ public final class CarMediaManager {
+ method @RequiresPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL) public void addMediaSourceListener(@NonNull android.car.media.CarMediaManager.MediaSourceChangedListener, int);
+ method @NonNull @RequiresPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL) public java.util.List<android.content.ComponentName> getLastMediaSources(int);
+ method @NonNull @RequiresPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL) public android.content.ComponentName getMediaSource(int);
+ method @RequiresPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL) public void removeMediaSourceListener(@NonNull android.car.media.CarMediaManager.MediaSourceChangedListener, int);
+ method @RequiresPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL) public void setMediaSource(@NonNull android.content.ComponentName, int);
+ field public static final int MEDIA_SOURCE_MODE_BROWSE = 1; // 0x1
+ field public static final int MEDIA_SOURCE_MODE_PLAYBACK = 0; // 0x0
+ }
+
+ public static interface CarMediaManager.MediaSourceChangedListener {
+ method public void onMediaSourceChanged(@NonNull android.content.ComponentName);
+ }
+
+}
+
+package android.car.navigation {
+
+ public final class CarNavigationInstrumentCluster implements android.os.Parcelable {
+ ctor public CarNavigationInstrumentCluster(android.car.navigation.CarNavigationInstrumentCluster);
+ method public static android.car.navigation.CarNavigationInstrumentCluster createCluster(int);
+ method public static android.car.navigation.CarNavigationInstrumentCluster createCustomImageCluster(int, int, int, int);
+ method public int describeContents();
+ method public int getImageColorDepthBits();
+ method public int getImageHeight();
+ method public int getImageWidth();
+ method public int getMinIntervalMillis();
+ method public int getType();
+ method public boolean supportsCustomImages();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final int CLUSTER_TYPE_CUSTOM_IMAGES_SUPPORTED = 1; // 0x1
+ field public static final int CLUSTER_TYPE_IMAGE_CODES_ONLY = 2; // 0x2
+ field public static final android.os.Parcelable.Creator<android.car.navigation.CarNavigationInstrumentCluster> CREATOR;
+ }
+
+ public final class CarNavigationStatusManager {
+ method @RequiresPermission(android.car.Car.PERMISSION_CAR_NAVIGATION_MANAGER) public android.car.navigation.CarNavigationInstrumentCluster getInstrumentClusterInfo();
+ method @Deprecated @RequiresPermission(android.car.Car.PERMISSION_CAR_NAVIGATION_MANAGER) public void sendEvent(int, android.os.Bundle);
+ method @RequiresPermission(android.car.Car.PERMISSION_CAR_NAVIGATION_MANAGER) public void sendNavigationStateChange(android.os.Bundle);
+ }
+
+}
+
+package android.car.os {
+
+ public final class CarPerformanceManager {
+ method @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.TIRAMISU_1, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.TIRAMISU_1) @NonNull @RequiresPermission(android.car.Car.PERMISSION_MANAGE_THREAD_PRIORITY) public android.car.os.ThreadPolicyWithPriority getThreadPriority();
+ method @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.TIRAMISU_1, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.TIRAMISU_1) @RequiresPermission(android.car.Car.PERMISSION_MANAGE_THREAD_PRIORITY) public void setThreadPriority(@NonNull android.car.os.ThreadPolicyWithPriority) throws android.car.os.CarPerformanceManager.SetSchedulerFailedException;
+ }
+
+ @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.TIRAMISU_1, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.TIRAMISU_1) public static final class CarPerformanceManager.SetSchedulerFailedException extends java.lang.Exception {
+ }
+
+ public final class ThreadPolicyWithPriority implements android.os.Parcelable {
+ ctor public ThreadPolicyWithPriority(int, @IntRange(from=0, to=99) int);
+ method @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.TIRAMISU_1, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.TIRAMISU_1) public int describeContents();
+ method @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.TIRAMISU_1, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.TIRAMISU_1) public int getPolicy();
+ method @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.TIRAMISU_1, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.TIRAMISU_1) @IntRange(from=0, to=99) public int getPriority();
+ method @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.TIRAMISU_1, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.TIRAMISU_1) public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.TIRAMISU_1, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.TIRAMISU_1) @NonNull public static final android.os.Parcelable.Creator<android.car.os.ThreadPolicyWithPriority> CREATOR;
+ field @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.TIRAMISU_1, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.TIRAMISU_1) public static final int PRIORITY_MAX = 99; // 0x63
+ field @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.TIRAMISU_1, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.TIRAMISU_1) public static final int PRIORITY_MIN = 1; // 0x1
+ field @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.TIRAMISU_1, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.TIRAMISU_1) public static final int SCHED_DEFAULT = 0; // 0x0
+ field @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.TIRAMISU_1, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.TIRAMISU_1) public static final int SCHED_FIFO = 1; // 0x1
+ field @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.TIRAMISU_1, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.TIRAMISU_1) public static final int SCHED_RR = 2; // 0x2
+ }
+
+}
+
+package android.car.projection {
+
+ public class ProjectionOptions {
+ ctor public ProjectionOptions(android.os.Bundle);
+ method @Nullable public android.app.ActivityOptions getActivityOptions();
+ method @Nullable public android.content.ComponentName getConsentActivity();
+ method public int getProjectionAccessPointMode();
+ method public int getUiMode();
+ method @NonNull public android.os.Bundle toBundle();
+ field public static final int AP_MODE_LOHS_DYNAMIC_CREDENTIALS = 2; // 0x2
+ field public static final int AP_MODE_LOHS_STATIC_CREDENTIALS = 3; // 0x3
+ field public static final int AP_MODE_NOT_SPECIFIED = 0; // 0x0
+ field public static final int AP_MODE_TETHERED = 1; // 0x1
+ field public static final int UI_MODE_BLENDED = 1; // 0x1
+ field public static final int UI_MODE_FULL_SCREEN = 0; // 0x0
+ }
+
+ public final class ProjectionStatus implements android.os.Parcelable {
+ method @NonNull public static android.car.projection.ProjectionStatus.Builder builder(String, int);
+ method public int describeContents();
+ method @NonNull public java.util.List<android.car.projection.ProjectionStatus.MobileDevice> getConnectedMobileDevices();
+ method @NonNull public android.os.Bundle getExtras();
+ method @NonNull public String getPackageName();
+ method public int getState();
+ method public int getTransport();
+ method public boolean isActive();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.car.projection.ProjectionStatus> CREATOR;
+ field public static final int PROJECTION_STATE_ACTIVE_BACKGROUND = 3; // 0x3
+ field public static final int PROJECTION_STATE_ACTIVE_FOREGROUND = 2; // 0x2
+ field public static final int PROJECTION_STATE_INACTIVE = 0; // 0x0
+ field public static final int PROJECTION_STATE_READY_TO_PROJECT = 1; // 0x1
+ field public static final int PROJECTION_TRANSPORT_NONE = 0; // 0x0
+ field public static final int PROJECTION_TRANSPORT_USB = 1; // 0x1
+ field public static final int PROJECTION_TRANSPORT_WIFI = 2; // 0x2
+ }
+
+ public static final class ProjectionStatus.Builder {
+ method @NonNull public android.car.projection.ProjectionStatus.Builder addMobileDevice(android.car.projection.ProjectionStatus.MobileDevice);
+ method public android.car.projection.ProjectionStatus build();
+ method @NonNull public android.car.projection.ProjectionStatus.Builder setExtras(android.os.Bundle);
+ method @NonNull public android.car.projection.ProjectionStatus.Builder setProjectionTransport(int);
+ }
+
+ public static final class ProjectionStatus.MobileDevice implements android.os.Parcelable {
+ method @NonNull public static android.car.projection.ProjectionStatus.MobileDevice.Builder builder(int, String);
+ method public int describeContents();
+ method @NonNull public java.util.List<java.lang.Integer> getAvailableTransports();
+ method @NonNull public android.os.Bundle getExtras();
+ method public int getId();
+ method @NonNull public String getName();
+ method public boolean isProjecting();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.car.projection.ProjectionStatus.MobileDevice> CREATOR;
+ }
+
+ public static final class ProjectionStatus.MobileDevice.Builder {
+ method @NonNull public android.car.projection.ProjectionStatus.MobileDevice.Builder addTransport(int);
+ method @NonNull public android.car.projection.ProjectionStatus.MobileDevice build();
+ method @NonNull public android.car.projection.ProjectionStatus.MobileDevice.Builder setExtras(android.os.Bundle);
+ method @NonNull public android.car.projection.ProjectionStatus.MobileDevice.Builder setProjecting(boolean);
+ }
+
+}
+
+package android.car.settings {
+
+ public class CarSettings {
+ }
+
+ public static final class CarSettings.Secure {
+ field public static final String KEY_AUDIO_FOCUS_NAVIGATION_REJECTED_DURING_CALL = "android.car.KEY_AUDIO_FOCUS_NAVIGATION_REJECTED_DURING_CALL";
+ field public static final String KEY_AUDIO_PERSIST_VOLUME_GROUP_MUTE_STATES = "android.car.KEY_AUDIO_PERSIST_VOLUME_GROUP_MUTE_STATES";
+ field public static final String KEY_ENABLE_INITIAL_NOTICE_SCREEN_TO_USER = "android.car.ENABLE_INITIAL_NOTICE_SCREEN_TO_USER";
+ field public static final String KEY_PACKAGES_DISABLED_ON_RESOURCE_OVERUSE = "android.car.KEY_PACKAGES_DISABLED_ON_RESOURCE_OVERUSE";
+ field public static final String KEY_ROTARY_KEY_EVENT_FILTER = "android.car.ROTARY_KEY_EVENT_FILTER";
+ field public static final String KEY_SETUP_WIZARD_IN_PROGRESS = "android.car.SETUP_WIZARD_IN_PROGRESS";
+ }
+
+}
+
+package android.car.storagemonitoring {
+
+ public final class CarStorageMonitoringManager {
+ method @Deprecated @RequiresPermission(android.car.Car.PERMISSION_STORAGE_MONITORING) public java.util.List<android.car.storagemonitoring.IoStatsEntry> getAggregateIoStats();
+ method @Deprecated @RequiresPermission(android.car.Car.PERMISSION_STORAGE_MONITORING) public java.util.List<android.car.storagemonitoring.IoStatsEntry> getBootIoStats();
+ method @Deprecated @RequiresPermission(android.car.Car.PERMISSION_STORAGE_MONITORING) public java.util.List<android.car.storagemonitoring.IoStats> getIoStatsDeltas();
+ method @RequiresPermission(android.car.Car.PERMISSION_STORAGE_MONITORING) public int getPreEolIndicatorStatus();
+ method @Deprecated @RequiresPermission(android.car.Car.PERMISSION_STORAGE_MONITORING) public long getShutdownDiskWriteAmount();
+ method @Deprecated @RequiresPermission(android.car.Car.PERMISSION_STORAGE_MONITORING) public android.car.storagemonitoring.WearEstimate getWearEstimate();
+ method @Deprecated @RequiresPermission(android.car.Car.PERMISSION_STORAGE_MONITORING) public java.util.List<android.car.storagemonitoring.WearEstimateChange> getWearEstimateHistory();
+ method @Deprecated @RequiresPermission(android.car.Car.PERMISSION_STORAGE_MONITORING) public void registerListener(android.car.storagemonitoring.CarStorageMonitoringManager.IoStatsListener);
+ method @Deprecated @RequiresPermission(android.car.Car.PERMISSION_STORAGE_MONITORING) public void unregisterListener(android.car.storagemonitoring.CarStorageMonitoringManager.IoStatsListener);
+ field public static final String INTENT_EXCESSIVE_IO = "android.car.storagemonitoring.EXCESSIVE_IO";
+ field public static final int PRE_EOL_INFO_NORMAL = 1; // 0x1
+ field public static final int PRE_EOL_INFO_UNKNOWN = 0; // 0x0
+ field public static final int PRE_EOL_INFO_URGENT = 3; // 0x3
+ field public static final int PRE_EOL_INFO_WARNING = 2; // 0x2
+ field public static final long SHUTDOWN_COST_INFO_MISSING = -1L; // 0xffffffffffffffffL
+ }
+
+ @Deprecated public static interface CarStorageMonitoringManager.IoStatsListener {
+ method @Deprecated public void onSnapshot(android.car.storagemonitoring.IoStats);
+ }
+
+ @Deprecated public final class IoStats implements android.os.Parcelable {
+ ctor @Deprecated public IoStats(java.util.List<android.car.storagemonitoring.IoStatsEntry>, long);
+ ctor @Deprecated public IoStats(android.os.Parcel);
+ method @Deprecated public int describeContents();
+ method @Deprecated public android.car.storagemonitoring.IoStatsEntry.Metrics getBackgroundTotals();
+ method @Deprecated public android.car.storagemonitoring.IoStatsEntry.Metrics getForegroundTotals();
+ method @Deprecated public java.util.List<android.car.storagemonitoring.IoStatsEntry> getStats();
+ method @Deprecated public long getTimestamp();
+ method @Deprecated public android.car.storagemonitoring.IoStatsEntry.Metrics getTotals();
+ method @Deprecated public android.car.storagemonitoring.IoStatsEntry getUserIdStats(int);
+ method @Deprecated public void writeToParcel(android.os.Parcel, int);
+ field @Deprecated public static final android.os.Parcelable.Creator<android.car.storagemonitoring.IoStats> CREATOR;
+ }
+
+ @Deprecated public final class IoStatsEntry implements android.os.Parcelable {
+ ctor @Deprecated public IoStatsEntry(int, long, android.car.storagemonitoring.IoStatsEntry.Metrics, android.car.storagemonitoring.IoStatsEntry.Metrics);
+ ctor @Deprecated public IoStatsEntry(android.os.Parcel);
+ ctor @Deprecated public IoStatsEntry(android.car.storagemonitoring.UidIoRecord, long);
+ method @Deprecated public int describeContents();
+ method @Deprecated public void writeToParcel(android.os.Parcel, int);
+ field @Deprecated public static final android.os.Parcelable.Creator<android.car.storagemonitoring.IoStatsEntry> CREATOR;
+ field @Deprecated public final android.car.storagemonitoring.IoStatsEntry.Metrics background;
+ field @Deprecated public final android.car.storagemonitoring.IoStatsEntry.Metrics foreground;
+ field @Deprecated public final long runtimeMillis;
+ field @Deprecated public final int uid;
+ }
+
+ @Deprecated public static final class IoStatsEntry.Metrics implements android.os.Parcelable {
+ ctor @Deprecated public IoStatsEntry.Metrics(long, long, long, long, long);
+ ctor @Deprecated public IoStatsEntry.Metrics(android.os.Parcel);
+ method @Deprecated public int describeContents();
+ method @Deprecated public void writeToParcel(android.os.Parcel, int);
+ field @Deprecated public static final android.os.Parcelable.Creator<android.car.storagemonitoring.IoStatsEntry.Metrics> CREATOR;
+ field @Deprecated public final long bytesRead;
+ field @Deprecated public final long bytesReadFromStorage;
+ field @Deprecated public final long bytesWritten;
+ field @Deprecated public final long bytesWrittenToStorage;
+ field @Deprecated public final long fsyncCalls;
+ }
+
+ public final class LifetimeWriteInfo implements android.os.Parcelable {
+ ctor public LifetimeWriteInfo(String, String, long);
+ ctor public LifetimeWriteInfo(android.os.Parcel);
+ method public int describeContents();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.car.storagemonitoring.LifetimeWriteInfo> CREATOR;
+ field public final String fstype;
+ field public final String partition;
+ field public final long writtenBytes;
+ }
+
+ public final class UidIoRecord {
+ ctor public UidIoRecord(int, long, long, long, long, long, long, long, long, long, long);
+ field public final long background_fsync;
+ field public final long background_rchar;
+ field public final long background_read_bytes;
+ field public final long background_wchar;
+ field public final long background_write_bytes;
+ field public final long foreground_fsync;
+ field public final long foreground_rchar;
+ field public final long foreground_read_bytes;
+ field public final long foreground_wchar;
+ field public final long foreground_write_bytes;
+ field public final int uid;
+ }
+
+ public final class WearEstimate implements android.os.Parcelable {
+ ctor public WearEstimate(int, int);
+ ctor public WearEstimate(android.os.Parcel);
+ method public int describeContents();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.car.storagemonitoring.WearEstimate> CREATOR;
+ field public static final int UNKNOWN = -1; // 0xffffffff
+ field @IntRange(from=0xffffffff, to=100) public final int typeA;
+ field @IntRange(from=0xffffffff, to=100) public final int typeB;
+ }
+
+ public final class WearEstimateChange implements android.os.Parcelable {
+ ctor public WearEstimateChange(android.car.storagemonitoring.WearEstimate, android.car.storagemonitoring.WearEstimate, long, java.time.Instant, boolean);
+ ctor public WearEstimateChange(android.os.Parcel);
+ method public int describeContents();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.car.storagemonitoring.WearEstimateChange> CREATOR;
+ field @NonNull public final java.time.Instant dateAtChange;
+ field public final boolean isAcceptableDegradation;
+ field @NonNull public final android.car.storagemonitoring.WearEstimate newEstimate;
+ field @NonNull public final android.car.storagemonitoring.WearEstimate oldEstimate;
+ field public final long uptimeAtChange;
}
}
@@ -127,13 +1429,13 @@
package android.car.telemetry {
public final class CarTelemetryManager {
- method @RequiresPermission("android.car.permission.USE_CAR_TELEMETRY_SERVICE") public void addMetricsConfig(@NonNull String, @NonNull byte[], @NonNull java.util.concurrent.Executor, @NonNull android.car.telemetry.CarTelemetryManager.AddMetricsConfigCallback);
- method @RequiresPermission("android.car.permission.USE_CAR_TELEMETRY_SERVICE") public void clearReportReadyListener();
- method @RequiresPermission("android.car.permission.USE_CAR_TELEMETRY_SERVICE") public void getAllFinishedReports(@NonNull java.util.concurrent.Executor, @NonNull android.car.telemetry.CarTelemetryManager.MetricsReportCallback);
- method @RequiresPermission("android.car.permission.USE_CAR_TELEMETRY_SERVICE") public void getFinishedReport(@NonNull String, @NonNull java.util.concurrent.Executor, @NonNull android.car.telemetry.CarTelemetryManager.MetricsReportCallback);
- method @RequiresPermission("android.car.permission.USE_CAR_TELEMETRY_SERVICE") public void removeAllMetricsConfigs();
- method @RequiresPermission("android.car.permission.USE_CAR_TELEMETRY_SERVICE") public void removeMetricsConfig(@NonNull String);
- method @RequiresPermission("android.car.permission.USE_CAR_TELEMETRY_SERVICE") public void setReportReadyListener(@NonNull java.util.concurrent.Executor, @NonNull android.car.telemetry.CarTelemetryManager.ReportReadyListener);
+ method @RequiresPermission(android.car.Car.PERMISSION_USE_CAR_TELEMETRY_SERVICE) public void addMetricsConfig(@NonNull String, @NonNull byte[], @NonNull java.util.concurrent.Executor, @NonNull android.car.telemetry.CarTelemetryManager.AddMetricsConfigCallback);
+ method @RequiresPermission(android.car.Car.PERMISSION_USE_CAR_TELEMETRY_SERVICE) public void clearReportReadyListener();
+ method @RequiresPermission(android.car.Car.PERMISSION_USE_CAR_TELEMETRY_SERVICE) public void getAllFinishedReports(@NonNull java.util.concurrent.Executor, @NonNull android.car.telemetry.CarTelemetryManager.MetricsReportCallback);
+ method @RequiresPermission(android.car.Car.PERMISSION_USE_CAR_TELEMETRY_SERVICE) public void getFinishedReport(@NonNull String, @NonNull java.util.concurrent.Executor, @NonNull android.car.telemetry.CarTelemetryManager.MetricsReportCallback);
+ method @RequiresPermission(android.car.Car.PERMISSION_USE_CAR_TELEMETRY_SERVICE) public void removeAllMetricsConfigs();
+ method @RequiresPermission(android.car.Car.PERMISSION_USE_CAR_TELEMETRY_SERVICE) public void removeMetricsConfig(@NonNull String);
+ method @RequiresPermission(android.car.Car.PERMISSION_USE_CAR_TELEMETRY_SERVICE) public void setReportReadyListener(@NonNull java.util.concurrent.Executor, @NonNull android.car.telemetry.CarTelemetryManager.ReportReadyListener);
field public static final int STATUS_ADD_METRICS_CONFIG_ALREADY_EXISTS = 1; // 0x1
field public static final int STATUS_ADD_METRICS_CONFIG_PARSE_FAILED = 3; // 0x3
field public static final int STATUS_ADD_METRICS_CONFIG_SIGNATURE_VERIFICATION_FAILED = 4; // 0x4
@@ -165,8 +1467,8 @@
public final class CarTestManager {
ctor public CarTestManager(@NonNull android.car.Car, @NonNull android.os.IBinder);
- method @RequiresPermission("android.car.permission.CAR_TEST_SERVICE") public void startCarService(@NonNull android.os.IBinder);
- method @RequiresPermission("android.car.permission.CAR_TEST_SERVICE") public void stopCarService(@NonNull android.os.IBinder);
+ method @RequiresPermission(android.car.Car.PERMISSION_CAR_TEST_SERVICE) public void startCarService(@NonNull android.os.IBinder);
+ method @RequiresPermission(android.car.Car.PERMISSION_CAR_TEST_SERVICE) public void stopCarService(@NonNull android.os.IBinder);
}
}
@@ -179,6 +1481,8 @@
method public static String lifecycleEventTypeToString(int);
method @RequiresPermission(anyOf={android.Manifest.permission.INTERACT_ACROSS_USERS, android.Manifest.permission.INTERACT_ACROSS_USERS_FULL}) public void removeListener(@NonNull android.car.user.CarUserManager.UserLifecycleListener);
method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS}) public android.car.util.concurrent.AsyncFuture<android.car.user.UserSwitchResult> switchUser(int);
+ field @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.TIRAMISU_1, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.TIRAMISU_1) public static final int USER_LIFECYCLE_EVENT_TYPE_CREATED = 8; // 0x8
+ field @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.TIRAMISU_1, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.TIRAMISU_1) public static final int USER_LIFECYCLE_EVENT_TYPE_REMOVED = 9; // 0x9
field public static final int USER_LIFECYCLE_EVENT_TYPE_STARTING = 1; // 0x1
field public static final int USER_LIFECYCLE_EVENT_TYPE_STOPPED = 6; // 0x6
field public static final int USER_LIFECYCLE_EVENT_TYPE_STOPPING = 5; // 0x5
@@ -236,3 +1540,245 @@
}
+package android.car.vms {
+
+ public final class VmsAssociatedLayer implements android.os.Parcelable {
+ ctor public VmsAssociatedLayer(@NonNull android.car.vms.VmsLayer, @NonNull java.util.Set<java.lang.Integer>);
+ method public int describeContents();
+ method @NonNull public java.util.Set<java.lang.Integer> getProviderIds();
+ method @Deprecated @NonNull public java.util.Set<java.lang.Integer> getPublisherIds();
+ method @NonNull public android.car.vms.VmsLayer getVmsLayer();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.car.vms.VmsAssociatedLayer> CREATOR;
+ }
+
+ public final class VmsAvailableLayers implements android.os.Parcelable {
+ ctor @Deprecated public VmsAvailableLayers(@NonNull java.util.Set<android.car.vms.VmsAssociatedLayer>, int);
+ ctor public VmsAvailableLayers(int, @NonNull java.util.Set<android.car.vms.VmsAssociatedLayer>);
+ method public int describeContents();
+ method @NonNull public java.util.Set<android.car.vms.VmsAssociatedLayer> getAssociatedLayers();
+ method @Deprecated public int getSequence();
+ method public int getSequenceNumber();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.car.vms.VmsAvailableLayers> CREATOR;
+ }
+
+ public final class VmsClient {
+ method @NonNull @RequiresPermission(anyOf={android.car.Car.PERMISSION_VMS_PUBLISHER, android.car.Car.PERMISSION_VMS_SUBSCRIBER}) public android.car.vms.VmsAvailableLayers getAvailableLayers();
+ method @Nullable @RequiresPermission(anyOf={android.car.Car.PERMISSION_VMS_PUBLISHER, android.car.Car.PERMISSION_VMS_SUBSCRIBER}) public byte[] getProviderDescription(int);
+ method @NonNull @RequiresPermission(anyOf={android.car.Car.PERMISSION_VMS_PUBLISHER, android.car.Car.PERMISSION_VMS_SUBSCRIBER}) public android.car.vms.VmsSubscriptionState getSubscriptionState();
+ method @RequiresPermission(android.car.Car.PERMISSION_VMS_SUBSCRIBER) public boolean isMonitoringEnabled();
+ method @RequiresPermission(android.car.Car.PERMISSION_VMS_PUBLISHER) public void publishPacket(int, @NonNull android.car.vms.VmsLayer, @NonNull byte[]);
+ method @RequiresPermission(android.car.Car.PERMISSION_VMS_PUBLISHER) public int registerProvider(@NonNull byte[]);
+ method @RequiresPermission(android.car.Car.PERMISSION_VMS_SUBSCRIBER) public void setMonitoringEnabled(boolean);
+ method @RequiresPermission(android.car.Car.PERMISSION_VMS_PUBLISHER) public void setProviderOfferings(int, @NonNull java.util.Set<android.car.vms.VmsLayerDependency>);
+ method @RequiresPermission(android.car.Car.PERMISSION_VMS_SUBSCRIBER) public void setSubscriptions(@NonNull java.util.Set<android.car.vms.VmsAssociatedLayer>);
+ method @RequiresPermission(android.car.Car.PERMISSION_VMS_PUBLISHER) public void unregisterProvider(int);
+ }
+
+ public final class VmsClientManager {
+ method @RequiresPermission(anyOf={android.car.Car.PERMISSION_VMS_PUBLISHER, android.car.Car.PERMISSION_VMS_SUBSCRIBER}) public void registerVmsClientCallback(@NonNull java.util.concurrent.Executor, @NonNull android.car.vms.VmsClientManager.VmsClientCallback);
+ method @RequiresPermission(anyOf={android.car.Car.PERMISSION_VMS_PUBLISHER, android.car.Car.PERMISSION_VMS_SUBSCRIBER}) public void unregisterVmsClientCallback(@NonNull android.car.vms.VmsClientManager.VmsClientCallback);
+ }
+
+ public static interface VmsClientManager.VmsClientCallback {
+ method public void onClientConnected(@NonNull android.car.vms.VmsClient);
+ method public void onLayerAvailabilityChanged(@NonNull android.car.vms.VmsAvailableLayers);
+ method public void onPacketReceived(int, @NonNull android.car.vms.VmsLayer, @NonNull byte[]);
+ method public void onSubscriptionStateChanged(@NonNull android.car.vms.VmsSubscriptionState);
+ }
+
+ public final class VmsLayer implements android.os.Parcelable {
+ ctor public VmsLayer(int, int, int);
+ method public int describeContents();
+ method public int getChannel();
+ method @Deprecated public int getSubtype();
+ method public int getType();
+ method public int getVersion();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.car.vms.VmsLayer> CREATOR;
+ }
+
+ public final class VmsLayerDependency implements android.os.Parcelable {
+ ctor public VmsLayerDependency(@NonNull android.car.vms.VmsLayer);
+ ctor public VmsLayerDependency(@NonNull android.car.vms.VmsLayer, @NonNull java.util.Set<android.car.vms.VmsLayer>);
+ method public int describeContents();
+ method @NonNull public java.util.Set<android.car.vms.VmsLayer> getDependencies();
+ method @NonNull public android.car.vms.VmsLayer getLayer();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.car.vms.VmsLayerDependency> CREATOR;
+ }
+
+ @Deprecated public final class VmsLayersOffering implements android.os.Parcelable {
+ ctor @Deprecated public VmsLayersOffering(@NonNull java.util.Set<android.car.vms.VmsLayerDependency>, int);
+ method @Deprecated public int describeContents();
+ method @Deprecated @NonNull public java.util.Set<android.car.vms.VmsLayerDependency> getDependencies();
+ method @Deprecated public int getPublisherId();
+ method @Deprecated public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @Deprecated @NonNull public static final android.os.Parcelable.Creator<android.car.vms.VmsLayersOffering> CREATOR;
+ }
+
+ @Deprecated public final class VmsOperationRecorder {
+ method @Deprecated public void addHalSubscription(int, android.car.vms.VmsLayer);
+ method @Deprecated public void addPromiscuousSubscription(int);
+ method @Deprecated public void addSubscription(int, android.car.vms.VmsLayer);
+ method @Deprecated public static android.car.vms.VmsOperationRecorder get();
+ method @Deprecated public void getPublisherId(int);
+ method @Deprecated public void removeHalSubscription(int, android.car.vms.VmsLayer);
+ method @Deprecated public void removePromiscuousSubscription(int);
+ method @Deprecated public void removeSubscription(int, android.car.vms.VmsLayer);
+ method @Deprecated public void setHalPublisherLayersOffering(android.car.vms.VmsLayersOffering);
+ method @Deprecated public void setLayersOffering(android.car.vms.VmsLayersOffering);
+ method @Deprecated public void setPublisherLayersOffering(android.car.vms.VmsLayersOffering);
+ method @Deprecated public void startMonitoring();
+ method @Deprecated public void stopMonitoring();
+ method @Deprecated public void subscribe(android.car.vms.VmsLayer);
+ method @Deprecated public void subscribe(android.car.vms.VmsLayer, int);
+ method @Deprecated public void unsubscribe(android.car.vms.VmsLayer);
+ method @Deprecated public void unsubscribe(android.car.vms.VmsLayer, int);
+ }
+
+ @Deprecated public abstract class VmsPublisherClientService extends android.app.Service {
+ ctor @Deprecated public VmsPublisherClientService();
+ method @Deprecated public final int getPublisherId(byte[]);
+ method @Deprecated public final android.car.vms.VmsSubscriptionState getSubscriptions();
+ method @Deprecated public android.os.IBinder onBind(android.content.Intent);
+ method @Deprecated protected abstract void onVmsPublisherServiceReady();
+ method @Deprecated public abstract void onVmsSubscriptionChange(@NonNull android.car.vms.VmsSubscriptionState);
+ method @Deprecated public final void publish(@NonNull android.car.vms.VmsLayer, int, byte[]);
+ method @Deprecated public final void setLayersOffering(@NonNull android.car.vms.VmsLayersOffering);
+ }
+
+ @Deprecated public final class VmsSubscriberManager {
+ method @Deprecated public void clearVmsSubscriberClientCallback();
+ method @Deprecated @NonNull public android.car.vms.VmsAvailableLayers getAvailableLayers();
+ method @Deprecated @NonNull public byte[] getPublisherInfo(int);
+ method @Deprecated public void setVmsSubscriberClientCallback(@NonNull java.util.concurrent.Executor, @NonNull android.car.vms.VmsSubscriberManager.VmsSubscriberClientCallback);
+ method @Deprecated public void startMonitoring();
+ method @Deprecated public void stopMonitoring();
+ method @Deprecated public void subscribe(@NonNull android.car.vms.VmsLayer);
+ method @Deprecated public void subscribe(@NonNull android.car.vms.VmsLayer, int);
+ method @Deprecated public void unsubscribe(@NonNull android.car.vms.VmsLayer);
+ method @Deprecated public void unsubscribe(@NonNull android.car.vms.VmsLayer, int);
+ }
+
+ @Deprecated public static interface VmsSubscriberManager.VmsSubscriberClientCallback {
+ method @Deprecated public void onLayersAvailabilityChanged(@NonNull android.car.vms.VmsAvailableLayers);
+ method @Deprecated public void onVmsMessageReceived(@NonNull android.car.vms.VmsLayer, byte[]);
+ }
+
+ public final class VmsSubscriptionState implements android.os.Parcelable {
+ ctor public VmsSubscriptionState(int, @NonNull java.util.Set<android.car.vms.VmsLayer>, @NonNull java.util.Set<android.car.vms.VmsAssociatedLayer>);
+ method public int describeContents();
+ method @NonNull public java.util.Set<android.car.vms.VmsAssociatedLayer> getAssociatedLayers();
+ method @NonNull public java.util.Set<android.car.vms.VmsLayer> getLayers();
+ method public int getSequenceNumber();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.car.vms.VmsSubscriptionState> CREATOR;
+ }
+
+}
+
+package android.car.watchdog {
+
+ public final class CarWatchdogManager {
+ method @RequiresPermission(android.car.Car.PERMISSION_COLLECT_CAR_WATCHDOG_METRICS) public void addResourceOveruseListenerForSystem(@NonNull java.util.concurrent.Executor, int, @NonNull android.car.watchdog.CarWatchdogManager.ResourceOveruseListener);
+ method @NonNull @RequiresPermission(android.car.Car.PERMISSION_COLLECT_CAR_WATCHDOG_METRICS) public java.util.List<android.car.watchdog.ResourceOveruseStats> getAllResourceOveruseStats(int, int, int);
+ method @NonNull @RequiresPermission(android.car.Car.PERMISSION_CONTROL_CAR_WATCHDOG_CONFIG) public java.util.List<android.car.watchdog.PackageKillableState> getPackageKillableStatesAsUser(@NonNull android.os.UserHandle);
+ method @Nullable @RequiresPermission(anyOf={android.car.Car.PERMISSION_CONTROL_CAR_WATCHDOG_CONFIG, android.car.Car.PERMISSION_COLLECT_CAR_WATCHDOG_METRICS}) public java.util.List<android.car.watchdog.ResourceOveruseConfiguration> getResourceOveruseConfigurations(int);
+ method @NonNull @RequiresPermission(android.car.Car.PERMISSION_COLLECT_CAR_WATCHDOG_METRICS) public android.car.watchdog.ResourceOveruseStats getResourceOveruseStatsForUserPackage(@NonNull String, @NonNull android.os.UserHandle, int, int);
+ method @RequiresPermission(android.car.Car.PERMISSION_USE_CAR_WATCHDOG) public void registerClient(@NonNull java.util.concurrent.Executor, @NonNull android.car.watchdog.CarWatchdogManager.CarWatchdogClientCallback, int);
+ method @RequiresPermission(android.car.Car.PERMISSION_COLLECT_CAR_WATCHDOG_METRICS) public void removeResourceOveruseListenerForSystem(@NonNull android.car.watchdog.CarWatchdogManager.ResourceOveruseListener);
+ method @RequiresPermission(android.car.Car.PERMISSION_CONTROL_CAR_WATCHDOG_CONFIG) public void setKillablePackageAsUser(@NonNull String, @NonNull android.os.UserHandle, boolean);
+ method @RequiresPermission(android.car.Car.PERMISSION_CONTROL_CAR_WATCHDOG_CONFIG) public int setResourceOveruseConfigurations(@NonNull java.util.List<android.car.watchdog.ResourceOveruseConfiguration>, int);
+ method @RequiresPermission(android.car.Car.PERMISSION_USE_CAR_WATCHDOG) public void tellClientAlive(@NonNull android.car.watchdog.CarWatchdogManager.CarWatchdogClientCallback, int);
+ method @RequiresPermission(android.car.Car.PERMISSION_USE_CAR_WATCHDOG) public void unregisterClient(@NonNull android.car.watchdog.CarWatchdogManager.CarWatchdogClientCallback);
+ field public static final int FLAG_MINIMUM_STATS_IO_100_MB = 2; // 0x2
+ field public static final int FLAG_MINIMUM_STATS_IO_1_GB = 4; // 0x4
+ field public static final int FLAG_MINIMUM_STATS_IO_1_MB = 1; // 0x1
+ field public static final int RETURN_CODE_ERROR = -1; // 0xffffffff
+ field public static final int RETURN_CODE_SUCCESS = 0; // 0x0
+ field public static final int TIMEOUT_CRITICAL = 0; // 0x0
+ field public static final int TIMEOUT_MODERATE = 1; // 0x1
+ field public static final int TIMEOUT_NORMAL = 2; // 0x2
+ }
+
+ public abstract static class CarWatchdogManager.CarWatchdogClientCallback {
+ ctor public CarWatchdogManager.CarWatchdogClientCallback();
+ method public boolean onCheckHealthStatus(int, int);
+ method public void onPrepareProcessTermination();
+ }
+
+ public final class IoOveruseAlertThreshold implements android.os.Parcelable {
+ method public int describeContents();
+ method public long getDurationInSeconds();
+ method public long getWrittenBytesPerSecond();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.car.watchdog.IoOveruseAlertThreshold> CREATOR;
+ }
+
+ public final class IoOveruseConfiguration implements android.os.Parcelable {
+ method public int describeContents();
+ method @NonNull public java.util.Map<java.lang.String,android.car.watchdog.PerStateBytes> getAppCategorySpecificThresholds();
+ method @NonNull public android.car.watchdog.PerStateBytes getComponentLevelThresholds();
+ method @NonNull public java.util.Map<java.lang.String,android.car.watchdog.PerStateBytes> getPackageSpecificThresholds();
+ method @NonNull public java.util.List<android.car.watchdog.IoOveruseAlertThreshold> getSystemWideThresholds();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.car.watchdog.IoOveruseConfiguration> CREATOR;
+ }
+
+ public static final class IoOveruseConfiguration.Builder {
+ ctor public IoOveruseConfiguration.Builder(@NonNull android.car.watchdog.PerStateBytes, @NonNull java.util.Map<java.lang.String,android.car.watchdog.PerStateBytes>, @NonNull java.util.Map<java.lang.String,android.car.watchdog.PerStateBytes>, @NonNull java.util.List<android.car.watchdog.IoOveruseAlertThreshold>);
+ method @NonNull public android.car.watchdog.IoOveruseConfiguration.Builder addAppCategorySpecificThresholds(@NonNull String, @NonNull android.car.watchdog.PerStateBytes);
+ method @NonNull public android.car.watchdog.IoOveruseConfiguration.Builder addPackageSpecificThresholds(@NonNull String, @NonNull android.car.watchdog.PerStateBytes);
+ method @NonNull public android.car.watchdog.IoOveruseConfiguration.Builder addSystemWideThresholds(@NonNull android.car.watchdog.IoOveruseAlertThreshold);
+ method @NonNull public android.car.watchdog.IoOveruseConfiguration build();
+ method @NonNull public android.car.watchdog.IoOveruseConfiguration.Builder setAppCategorySpecificThresholds(@NonNull java.util.Map<java.lang.String,android.car.watchdog.PerStateBytes>);
+ method @NonNull public android.car.watchdog.IoOveruseConfiguration.Builder setComponentLevelThresholds(@NonNull android.car.watchdog.PerStateBytes);
+ method @NonNull public android.car.watchdog.IoOveruseConfiguration.Builder setPackageSpecificThresholds(@NonNull java.util.Map<java.lang.String,android.car.watchdog.PerStateBytes>);
+ method @NonNull public android.car.watchdog.IoOveruseConfiguration.Builder setSystemWideThresholds(@NonNull java.util.List<android.car.watchdog.IoOveruseAlertThreshold>);
+ }
+
+ public final class PackageKillableState implements android.os.Parcelable {
+ method public int describeContents();
+ method public int getKillableState();
+ method @NonNull public String getPackageName();
+ method public int getUserId();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.car.watchdog.PackageKillableState> CREATOR;
+ field public static final int KILLABLE_STATE_NEVER = 3; // 0x3
+ field public static final int KILLABLE_STATE_NO = 2; // 0x2
+ field public static final int KILLABLE_STATE_YES = 1; // 0x1
+ }
+
+ public final class ResourceOveruseConfiguration implements android.os.Parcelable {
+ method public int describeContents();
+ method public int getComponentType();
+ method @Nullable public android.car.watchdog.IoOveruseConfiguration getIoOveruseConfiguration();
+ method @NonNull public java.util.Map<java.lang.String,java.lang.String> getPackagesToAppCategoryTypes();
+ method @NonNull public java.util.List<java.lang.String> getSafeToKillPackages();
+ method @NonNull public java.util.List<java.lang.String> getVendorPackagePrefixes();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field public static final String APPLICATION_CATEGORY_TYPE_MAPS = "android.car.watchdog.app.category.MAPS";
+ field public static final String APPLICATION_CATEGORY_TYPE_MEDIA = "android.car.watchdog.app.category.MEDIA";
+ field public static final int COMPONENT_TYPE_SYSTEM = 1; // 0x1
+ field public static final int COMPONENT_TYPE_THIRD_PARTY = 3; // 0x3
+ field public static final int COMPONENT_TYPE_VENDOR = 2; // 0x2
+ field @NonNull public static final android.os.Parcelable.Creator<android.car.watchdog.ResourceOveruseConfiguration> CREATOR;
+ }
+
+ public static final class ResourceOveruseConfiguration.Builder {
+ ctor public ResourceOveruseConfiguration.Builder(int, @NonNull java.util.List<java.lang.String>, @NonNull java.util.List<java.lang.String>, @NonNull java.util.Map<java.lang.String,java.lang.String>);
+ method @NonNull public android.car.watchdog.ResourceOveruseConfiguration.Builder addPackagesToAppCategoryTypes(@NonNull String, @NonNull String);
+ method @NonNull public android.car.watchdog.ResourceOveruseConfiguration.Builder addSafeToKillPackages(@NonNull String);
+ method @NonNull public android.car.watchdog.ResourceOveruseConfiguration.Builder addVendorPackagePrefixes(@NonNull String);
+ method @NonNull public android.car.watchdog.ResourceOveruseConfiguration build();
+ method @NonNull public android.car.watchdog.ResourceOveruseConfiguration.Builder setComponentType(int);
+ method @NonNull public android.car.watchdog.ResourceOveruseConfiguration.Builder setIoOveruseConfiguration(@NonNull android.car.watchdog.IoOveruseConfiguration);
+ method @NonNull public android.car.watchdog.ResourceOveruseConfiguration.Builder setPackagesToAppCategoryTypes(@NonNull java.util.Map<java.lang.String,java.lang.String>);
+ method @NonNull public android.car.watchdog.ResourceOveruseConfiguration.Builder setSafeToKillPackages(@NonNull java.util.List<java.lang.String>);
+ method @NonNull public android.car.watchdog.ResourceOveruseConfiguration.Builder setVendorPackagePrefixes(@NonNull java.util.List<java.lang.String>);
+ }
+
+}
+
diff --git a/car-lib/api/test-removed.txt b/car-lib/api/test-removed.txt
index d802177..bca7216 100644
--- a/car-lib/api/test-removed.txt
+++ b/car-lib/api/test-removed.txt
@@ -1 +1,30 @@
// Signature format: 2.0
+package android.car.cluster.renderer {
+
+ @UiThread public abstract class NavigationRenderer {
+ method public void onEvent(int, android.os.Bundle);
+ }
+
+}
+
+package android.car.input {
+
+ @Deprecated public abstract class CarInputHandlingService extends android.app.Service {
+ ctor protected CarInputHandlingService(android.car.input.CarInputHandlingService.InputFilter[]);
+ method @CallSuper public android.os.IBinder onBind(android.content.Intent);
+ method @MainThread protected abstract void onKeyEvent(android.view.KeyEvent, int);
+ field public static final int INPUT_CALLBACK_BINDER_CODE = 1; // 0x1
+ field public static final String INPUT_CALLBACK_BINDER_KEY = "callback_binder";
+ }
+
+ public static final class CarInputHandlingService.InputFilter implements android.os.Parcelable {
+ ctor public CarInputHandlingService.InputFilter(int, int);
+ method public int describeContents();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator CREATOR;
+ field public final int mKeyCode;
+ field public final int mTargetDisplay;
+ }
+
+}
+
diff --git a/car-lib/src/android/car/ApiVersion.java b/car-lib/src/android/car/ApiVersion.java
new file mode 100644
index 0000000..45b9849
--- /dev/null
+++ b/car-lib/src/android/car/ApiVersion.java
@@ -0,0 +1,202 @@
+/*
+ * Copyright (C) 2022 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;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.car.annotation.ApiRequirements;
+import android.car.annotation.ApiRequirements.CarVersion;
+import android.car.annotation.ApiRequirements.PlatformVersion;
+import android.os.Parcel;
+import android.text.TextUtils;
+
+import java.util.Objects;
+
+/**
+ * Abstraction of Android APIs.
+ *
+ * <p>This class is used to represent a pair of major / minor API versions: the "major" version
+ * represents a "traditional" Android SDK release, while the "minor" is used to indicate incremental
+ * releases for that major.
+ *
+ * <p>This class is needed because the standard Android SDK API versioning only supports major
+ * releases, but {@code Car} APIs can now (starting on
+ * {@link android.os.Build.Build.VERSION_CODES#TIRAMISU Android 13}) be updated on minor releases
+ * as well.
+ *
+ * @param <T> implementation type
+ */
+@ApiRequirements(minCarVersion = CarVersion.TIRAMISU_1,
+ minPlatformVersion = PlatformVersion.TIRAMISU_0)
+public abstract class ApiVersion<T extends ApiVersion<?>> {
+
+ /**
+ * When set, it's used on {@link #toString()} - useful for versions that are pre-defined
+ * (like {@code TIRAMISU_1}).
+ */
+ @Nullable
+ private final String mVersionName;
+
+ private final int mMajorVersion;
+ private final int mMinorVersion;
+
+ ApiVersion(int majorVersion, int minorVersion) {
+ this(/* name= */ null, majorVersion, minorVersion);
+ }
+
+ ApiVersion(String name, int majorVersion, int minorVersion) {
+ mVersionName = name;
+ mMajorVersion = majorVersion;
+ mMinorVersion = minorVersion;
+ }
+
+ /**
+ * Checks if this API version meets the required version.
+ *
+ * @param requiredApiVersionMajor Required major version number.
+ * @param requiredApiVersionMinor Required minor version number.
+ * @return {@code true} if the {@link #getMajorVersion() major version} is newer than the
+ * {@code requiredVersion}'s major or if the {@link #getMajorVersion() major version} is
+ * the same as {@code requiredVersion}'s major with the {@link #getMinorVersion() minor
+ * version} the same or newer than {@code requiredVersion}'s minor.
+ * @throws IllegalArgumentException if {@code requiredVersion} is not an instance of the same
+ * class as this object.
+ */
+ @ApiRequirements(minCarVersion = CarVersion.TIRAMISU_1,
+ minPlatformVersion = PlatformVersion.TIRAMISU_0)
+ public final boolean isAtLeast(@NonNull T requiredVersion) {
+ Objects.requireNonNull(requiredVersion);
+
+ if (!this.getClass().isInstance(requiredVersion)) {
+ throw new IllegalArgumentException("Cannot compare " + this.getClass().getName()
+ + " against " + requiredVersion.getClass().getName());
+ }
+
+ int requiredApiVersionMajor = requiredVersion.getMajorVersion();
+ int requiredApiVersionMinor = requiredVersion.getMinorVersion();
+
+ return (mMajorVersion > requiredApiVersionMajor)
+ || (mMajorVersion == requiredApiVersionMajor
+ && mMinorVersion >= requiredApiVersionMinor);
+ }
+
+ /**
+ * Gets the major version of the API represented by this object.
+ */
+ @ApiRequirements(minCarVersion = CarVersion.TIRAMISU_1,
+ minPlatformVersion = PlatformVersion.TIRAMISU_0)
+ public final int getMajorVersion() {
+ return mMajorVersion;
+ }
+
+ /**
+ * Gets the minor version change of API for the same {@link #getMajorVersion()}.
+ *
+ * <p>It will reset to {@code 0} whenever {@link #getMajorVersion()} is updated
+ * and will increase by {@code 1} if car builtin or other car platform part is changed with the
+ * same {@link #getMajorVersion()}.
+ *
+ * <p>Client should check this version to use APIs which were added in a minor-only version
+ * update.
+ */
+ @ApiRequirements(minCarVersion = CarVersion.TIRAMISU_1,
+ minPlatformVersion = PlatformVersion.TIRAMISU_0)
+ public final int getMinorVersion() {
+ return mMinorVersion;
+ }
+
+ /**
+ * @hide
+ */
+ @Override
+ @ApiRequirements(minCarVersion = CarVersion.TIRAMISU_1,
+ minPlatformVersion = PlatformVersion.TIRAMISU_0)
+ public boolean equals(Object obj) {
+ if (this == obj) return true;
+ if (obj == null) return false;
+ if (getClass() != obj.getClass()) return false;
+ @SuppressWarnings("unchecked")
+ ApiVersion<T> other = (ApiVersion<T>) obj;
+ if (mMajorVersion != other.mMajorVersion) return false;
+ if (mMinorVersion != other.mMinorVersion) return false;
+ return true;
+ }
+
+ /**
+ * @hide
+ */
+ @Override
+ @ApiRequirements(minCarVersion = CarVersion.TIRAMISU_1,
+ minPlatformVersion = PlatformVersion.TIRAMISU_0)
+ public int hashCode() {
+ int prime = 31;
+ int result = 1;
+ result = prime * result + mMajorVersion;
+ result = prime * result + mMinorVersion;
+ return result;
+ }
+
+ /**
+ * @hide
+ */
+ @Override
+ @NonNull
+ @ApiRequirements(minCarVersion = CarVersion.TIRAMISU_1,
+ minPlatformVersion = PlatformVersion.TIRAMISU_0)
+ public final String toString() {
+ StringBuilder builder = new StringBuilder(getClass().getSimpleName()).append('[');
+ if (!TextUtils.isEmpty(mVersionName)) {
+ builder.append("name=").append(mVersionName).append(", ");
+ }
+ return builder
+ .append("major=").append(mMajorVersion)
+ .append(", minor=").append(mMinorVersion)
+ .append(']').toString();
+ }
+
+ /**
+ * @hide
+ */
+ @ApiRequirements(minCarVersion = CarVersion.TIRAMISU_1,
+ minPlatformVersion = PlatformVersion.TIRAMISU_0)
+ protected void writeToParcel(Parcel dest) {
+ dest.writeString(mVersionName);
+ dest.writeInt(getMajorVersion());
+ dest.writeInt(getMinorVersion());
+ }
+
+ /**
+ * @hide
+ */
+ @ApiRequirements(minCarVersion = CarVersion.TIRAMISU_1,
+ minPlatformVersion = PlatformVersion.TIRAMISU_0)
+ protected static <T extends ApiVersion<?>> T readFromParcel(Parcel source,
+ ApiVersionFactory<T> factory) {
+ String name = source.readString();
+ int major = source.readInt();
+ int minor = source.readInt();
+ return factory.newInstance(name, major, minor);
+ }
+
+ /**
+ * @hide
+ */
+ @ApiRequirements(minCarVersion = CarVersion.TIRAMISU_1,
+ minPlatformVersion = PlatformVersion.TIRAMISU_0)
+ interface ApiVersionFactory<T extends ApiVersion<?>> {
+ T newInstance(String name, int major, int minor);
+ }
+}
diff --git a/car-lib/src/android/car/Car.java b/car-lib/src/android/car/Car.java
index 0ee969e..12955ee 100644
--- a/car-lib/src/android/car/Car.java
+++ b/car-lib/src/android/car/Car.java
@@ -31,11 +31,11 @@
import android.app.Service;
import android.car.admin.CarDevicePolicyManager;
import android.car.annotation.AddedInOrBefore;
-import android.car.annotation.ExperimentalFeature;
+import android.car.annotation.ApiRequirements;
import android.car.annotation.MandatoryFeature;
import android.car.annotation.OptionalFeature;
import android.car.app.CarActivityManager;
-import android.car.builtin.CarBuiltin;
+import android.car.builtin.os.BuildHelper;
import android.car.builtin.os.ServiceManagerHelper;
import android.car.cluster.CarInstrumentClusterManager;
import android.car.cluster.ClusterActivityState;
@@ -58,6 +58,7 @@
import android.car.media.CarMediaManager;
import android.car.navigation.CarNavigationStatusManager;
import android.car.occupantawareness.OccupantAwarenessManager;
+import android.car.os.CarPerformanceManager;
import android.car.storagemonitoring.CarStorageMonitoringManager;
import android.car.telemetry.CarTelemetryManager;
import android.car.test.CarTestManager;
@@ -78,6 +79,7 @@
import android.os.Looper;
import android.os.Process;
import android.os.RemoteException;
+import android.os.SystemProperties;
import android.os.TransactionTooLargeException;
import android.util.Log;
@@ -105,38 +107,76 @@
public final class Car {
/**
- * Represents the platform SDK_INT version with which this car API is developed.
- * <p>Note that new car APIs can be used in older platform releases and clients
- * should check both this and {@link android.os.Build.VERSION#SDK_INT} before using
- * an API added in a specific car API version.
+ * System property to define platform minor version.
+ *
+ * <p>Value is int string. Check {@link #PROPERTY_PLATFORM_MINOR_INT} for further details.
+ * If not set, default value of {@code 0} is assumed.
*/
- @AddedInOrBefore(majorVersion = 33)
+ private static final String PROPERTY_PLATFORM_MINOR_VERSION =
+ "ro.android.car.version.platform_minor";
+
+ /**
+ * @deprecated - use {@code getCarApiVersion().getMajorVersion()} instead
+ */
+ @Deprecated
+ @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_0,
+ minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
public static final int API_VERSION_MAJOR_INT = 33;
/**
- * Represents a minor version change for the same {@link #API_VERSION_MAJOR_INT}.
- * <p>It will reset to {@code 0} whenever {@link #API_VERSION_MAJOR_INT} is updated and will
- * increase by {@code 1} if car API is changed with the same {@link #API_VERSION_MAJOR_INT}.
- * Client should check this version to use APIs which were added in a minor only version
- * update.
+ * @deprecated - use {@code getCarApiVersion().getMinorVersion()} instead
*/
- @AddedInOrBefore(majorVersion = 33)
- public static final int API_VERSION_MINOR_INT = 0;
+ @Deprecated
+ @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_0,
+ minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+ public static final int API_VERSION_MINOR_INT = 1;
/**
- * Represents a minor version change of car platform for the same
- * {@link android.os.Build.VERSION#SDK_INT}.
- *
- * <p>It will reset to {@code 0} whenever {@link android.os.Build.VERSION#SDK_INT} is updated
- * and will increase by {@code 1} if car builtin or other car platform part is changed with the
- * same {@link android.os.Build.VERSION#SDK_INT}. Client should check this version to use APIs
- * which were added in a minor only version update.
- *
- * TODO(b/224982783) Remove "hide" in future release.
+ * @deprecated - use {@code getPlatformApiVersion().getMinorVersion()} instead
+ */
+ @Deprecated
+ @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_0,
+ minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+ public static final int PLATFORM_VERSION_MINOR_INT = SystemProperties
+ .getInt(PROPERTY_PLATFORM_MINOR_VERSION, /* def= */ 0);
+
+ private static final CarVersion CAR_VERSION = CarVersion.newInstance("Car.CAR_VERSION",
+ API_VERSION_MAJOR_INT, API_VERSION_MINOR_INT);
+
+ private static final PlatformVersion PLATFORM_VERSION;
+
+ /**
* @hide
*/
- @AddedInOrBefore(majorVersion = 33)
- public static final int PLATFORM_VERSION_MINOR_INT = CarBuiltin.PLATFORM_VERSION_MINOR_INT;
+ @TestApi
+ @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_1,
+ minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+ public static final String PROPERTY_EMULATED_PLATFORM_VERSION_MAJOR =
+ "com.android.car.internal.debug.platform_major_version";
+ /**
+ * @hide
+ */
+ @TestApi
+ @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_1,
+ minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+ public static final String PROPERTY_EMULATED_PLATFORM_VERSION_MINOR =
+ "com.android.car.internal.debug.platform_minor_version";
+
+ static {
+ PlatformVersion emulated = null;
+ if (!BuildHelper.isUserBuild()) {
+ int major = SystemProperties.getInt(PROPERTY_EMULATED_PLATFORM_VERSION_MAJOR, -1);
+ if (major != -1) {
+ int minor = SystemProperties.getInt(PROPERTY_EMULATED_PLATFORM_VERSION_MINOR,
+ PLATFORM_VERSION_MINOR_INT);
+ emulated = android.car.PlatformVersion.newInstance("EMULATED", major, minor);
+ Log.i(TAG_CAR, "Emulating PLATFORM_VERSION version: " + emulated);
+ }
+ }
+ PLATFORM_VERSION = emulated != null ? emulated : PlatformVersion
+ .newInstance("Car.PLATFORM_VERSION",
+ Build.VERSION.SDK_INT, PLATFORM_VERSION_MINOR_INT);
+ }
/**
* Binder service name of car service registered to service manager.
@@ -389,6 +429,7 @@
* @hide
*/
@MandatoryFeature
+ @SystemApi
@AddedInOrBefore(majorVersion = 33)
public static final String CAR_BUGREPORT_SERVICE = "car_bugreport";
@@ -412,7 +453,8 @@
*
* @hide
*/
- @ExperimentalFeature
+ @MandatoryFeature
+ @SystemApi
@AddedInOrBefore(majorVersion = 33)
public static final String CAR_PERFORMANCE_SERVICE = "car_performance";
@@ -902,6 +944,7 @@
*/
@VisibleForHiddenApiCheck
@AddedInOrBefore(majorVersion = 33)
+ @SystemApi
public static final String PERMISSION_CAR_UX_RESTRICTIONS_CONFIGURATION =
"android.car.permission.CAR_UX_RESTRICTIONS_CONFIGURATION";
@@ -1086,6 +1129,17 @@
"android.car.permission.CONTROL_CAR_APP_LAUNCH";
/**
+ * Permission necessary to setting and getting thread scheduling policy and priority.
+ *
+ * @hide
+ */
+ @SystemApi
+ @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_1,
+ minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_1)
+ public static final String PERMISSION_MANAGE_THREAD_PRIORITY =
+ "android.car.permission.MANAGE_THREAD_PRIORITY";
+
+ /**
* Intent for connecting to the template renderer. Services that handle this intent must also
* hold {@link #PERMISSION_TEMPLATE_RENDERER}. Applications would not bind to this service
* directly, but instead they would use
@@ -1373,68 +1427,90 @@
private final CarFeatures mFeatures = new CarFeatures();
/**
- * Checks if the current car API version is meeting the required version number.
+ * Defines the {@link CarVersion version} of the {@code Car} APIs in the device.
*
- * @param requiredApiVersionMajor Required major version number. Minor version is not checked.
- * @return true if car API version in the system is same or newer than
- * {@code requiredApiVersionMajor}.
+ * <p>Starting on {@link Build.VERSION_CODES#TIRAMISU Android 13}, the {@code Car} APIs can be
+ * upgraded without an OTA, so it's possible that these APIs are higher than the
+ * {@link #getPlatformVersion() platform's}.
*/
- @AddedInOrBefore(majorVersion = 33)
- public static boolean isApiVersionAtLeast(int requiredApiVersionMajor) {
- return API_VERSION_MAJOR_INT >= requiredApiVersionMajor;
+ @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_1,
+ minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+ @NonNull
+ public static android.car.CarVersion getCarVersion() {
+ return CAR_VERSION;
}
/**
- * Checks if the current car API version is meeting the required version number.
+ * Defines the {@link PlatformVersion version} of the standard {@code SDK} APIs in the
+ * device.
*
- * @param requiredApiVersionMajor Required major version number.
- * @param requiredApiVersionMinor Required minor version number.
- * @return true if car Major API version in the system is newer than
- * {@code requiredApiVersionMajor} or car Major API version in the system is same as
- * {@code requiredApiVersionMajor} with minor version same or newer than
- * {@code requiredApiVersionMinor}.
+ * <p>Its {@link ApiVersion#getMajorVersion() major version} will always be the same as
+ * {@link Build.VERSION#SDK_INT}, but its {@link ApiVersion#getMinorVersion() minor version}
+ * will reflect the incremental, quarterly releases.
*/
- @AddedInOrBefore(majorVersion = 33)
+ @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_1,
+ minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+ @NonNull
+ public static android.car.PlatformVersion getPlatformVersion() {
+ return PLATFORM_VERSION;
+ }
+
+ /**
+ * @deprecated - use {@code getCarApiVersion().isAtLeast(CarVersion.forMajorAndMinorVersions(
+ * requiredApiVersionMajor))} instead
+ */
+ @Deprecated
+ @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_0,
+ minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+ public static boolean isApiVersionAtLeast(int requiredApiVersionMajor) {
+ return getCarVersion().isAtLeast(CarVersion.forMajorVersion(requiredApiVersionMajor));
+ }
+
+ /**
+ * @deprecated - use {@code getCarVersion().isAtLeast(CarVersion.forMajorAndMinorVersions(
+ * requiredApiVersionMajor, requiredApiVersionMinor)} instead
+ */
+ @Deprecated
+ @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_0,
+ minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
public static boolean isApiVersionAtLeast(int requiredApiVersionMajor,
int requiredApiVersionMinor) {
- return (API_VERSION_MAJOR_INT > requiredApiVersionMajor)
- || (API_VERSION_MAJOR_INT == requiredApiVersionMajor
- && API_VERSION_MINOR_INT >= requiredApiVersionMinor);
+ return getCarVersion()
+ .isAtLeast(CarVersion.forMajorAndMinorVersions(requiredApiVersionMajor,
+ requiredApiVersionMinor));
}
/**
- * Checks if the current car API version and platform version are meeting the required version
- * numbers.
- *
- * @param requiredApiVersionMajor Required major version number. Minor version is not checked.
- * @param minPlatformSdkInt Required platform version.
- * @return true if car API version in the system is same or newer than
- * {@code requiredApiVersionMajor}.
+ * @deprecated - use
+ * {@code getCarVersion().isAtLeast(CarVersion.forMajorVersion(requiredApiVersionMajor))
+ * && getPlatformVersion().isAtLeast(PlatformVersion.forMajorVersion(minPlatformSdkInt))}
+ * instead.
*/
- @AddedInOrBefore(majorVersion = 33)
+ @Deprecated
+ @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_0,
+ minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
public static boolean isApiAndPlatformVersionAtLeast(int requiredApiVersionMajor,
int minPlatformSdkInt) {
- return API_VERSION_MAJOR_INT >= requiredApiVersionMajor
- && Build.VERSION.SDK_INT >= minPlatformSdkInt;
+ return getCarVersion().isAtLeast(CarVersion.forMajorVersion(requiredApiVersionMajor))
+ && getPlatformVersion()
+ .isAtLeast(PlatformVersion.forMajorVersion(minPlatformSdkInt));
}
/**
- * Checks if the current car API version and platform version are meeting the required version
- * numbers.
- *
- * @param requiredApiVersionMajor Required major version number.
- * @param requiredApiVersionMinor Required minor version number.
- * @param minPlatformSdkInt Required platform version.
- * @return true if car API version in the system is same or newer than
- * {@code requiredApiVersionMajor}.
+ * @deprecated - use {@code getCarVersion().isAtLeast(CarVersion.forMajorAndMinorVersions(
+ * requiredApiVersionMajor, requiredApiVersionMinor)) && getPlatformVersion().isAtLeast(
+ * PlatformVersion.forMajorVersion(minPlatformSdkInt))} instead.
*/
- @AddedInOrBefore(majorVersion = 33)
+ @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_0,
+ minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+ @Deprecated
public static boolean isApiAndPlatformVersionAtLeast(int requiredApiVersionMajor,
- int requiredApiVersionMinor,
- int minPlatformSdkInt) {
- return API_VERSION_MAJOR_INT >= requiredApiVersionMajor
- && API_VERSION_MINOR_INT >= requiredApiVersionMinor
- && Build.VERSION.SDK_INT >= minPlatformSdkInt;
+ int requiredApiVersionMinor, int minPlatformSdkInt) {
+ return getCarVersion()
+ .isAtLeast(CarVersion.forMajorAndMinorVersions(requiredApiVersionMajor,
+ requiredApiVersionMinor))
+ && getPlatformVersion()
+ .isAtLeast(PlatformVersion.forMajorVersion(minPlatformSdkInt));
}
/**
@@ -2246,6 +2322,9 @@
case CAR_ACTIVITY_SERVICE:
manager = new CarActivityManager(this, binder);
break;
+ case CAR_PERFORMANCE_SERVICE:
+ manager = new CarPerformanceManager(this, binder);
+ break;
default:
// Experimental or non-existing
String className = null;
diff --git a/car-lib/src/android/car/CarBugreportManager.java b/car-lib/src/android/car/CarBugreportManager.java
index 10da90e..0bca6ef 100644
--- a/car-lib/src/android/car/CarBugreportManager.java
+++ b/car-lib/src/android/car/CarBugreportManager.java
@@ -20,6 +20,7 @@
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.RequiresPermission;
+import android.annotation.SystemApi;
import android.car.annotation.AddedInOrBefore;
import android.os.Handler;
import android.os.IBinder;
@@ -37,9 +38,9 @@
/**
* Car specific bugreport manager. Only available for userdebug and eng builds.
- *
* @hide
*/
+@SystemApi
public final class CarBugreportManager extends CarManagerBase {
private final ICarBugreportService mService;
@@ -48,7 +49,9 @@
* Callback from carbugreport manager. Callback methods are always called on the main thread.
*/
public abstract static class CarBugreportManagerCallback {
-
+ /**
+ * @hide
+ */
@Retention(RetentionPolicy.SOURCE)
@IntDef(prefix = {"CAR_BUGREPORT_ERROR_"}, value = {
CAR_BUGREPORT_DUMPSTATE_FAILED,
@@ -60,7 +63,8 @@
public @interface CarBugreportErrorCode {
}
- /** Dumpstate failed to generate bugreport. */
+ /** Dumpstate failed to generate bugreport.
+ */
@AddedInOrBefore(majorVersion = 33)
public static final int CAR_BUGREPORT_DUMPSTATE_FAILED = 1;
@@ -70,11 +74,13 @@
@AddedInOrBefore(majorVersion = 33)
public static final int CAR_BUGREPORT_IN_PROGRESS = 2;
- /** Cannot connect to dumpstate */
+ /** Cannot connect to dumpstate
+ */
@AddedInOrBefore(majorVersion = 33)
public static final int CAR_BUGREPORT_DUMPSTATE_CONNECTION_FAILED = 3;
- /** Car bugreport service is not available (true for user builds) */
+ /** Car bugreport service is not available (true for user builds)
+ */
@AddedInOrBefore(majorVersion = 33)
public static final int CAR_BUGREPORT_SERVICE_NOT_AVAILABLE = 4;
@@ -108,6 +114,7 @@
/**
* Internal wrapper class to service.
+ * @hide
*/
private static final class CarBugreportManagerCallbackWrapper extends
ICarBugreportCallback.Stub {
@@ -159,6 +166,7 @@
* Get an instance of the CarBugreportManager
*
* Should not be obtained directly by clients, use {@link Car#getCarManager(String)} instead.
+ * @hide
*/
public CarBugreportManager(Car car, IBinder service) {
super(car);
@@ -249,6 +257,9 @@
}
}
+ /**
+ * @hide
+ */
@Override
@AddedInOrBefore(majorVersion = 33)
public void onCarDisconnected() {
diff --git a/car-lib/src/android/car/CarProjectionManager.java b/car-lib/src/android/car/CarProjectionManager.java
index 3d6d200..1c86c20 100644
--- a/car-lib/src/android/car/CarProjectionManager.java
+++ b/car-lib/src/android/car/CarProjectionManager.java
@@ -692,11 +692,17 @@
} else {
// Already subscribed to Car Service, immediately notify listener with the current
// projection status in the event handler thread.
+ int currentProjectionState = mCarProjectionStatusListener.mCurrentState;
+ String currentProjectionPackageName =
+ mCarProjectionStatusListener.mCurrentPackageName;
+ List<ProjectionStatus> projectionStatusDetails =
+ Collections.unmodifiableList(mCarProjectionStatusListener.mDetails);
+
getEventHandler().post(() ->
listener.onProjectionStatusChanged(
- mCarProjectionStatusListener.mCurrentState,
- mCarProjectionStatusListener.mCurrentPackageName,
- mCarProjectionStatusListener.mDetails));
+ currentProjectionState,
+ currentProjectionPackageName,
+ projectionStatusDetails));
}
}
}
diff --git a/car-lib/src/android/car/CarVersion.aidl b/car-lib/src/android/car/CarVersion.aidl
new file mode 100644
index 0000000..8319daa
--- /dev/null
+++ b/car-lib/src/android/car/CarVersion.aidl
@@ -0,0 +1,18 @@
+/*
+ * Copyright (C) 2022 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;
+
+parcelable CarVersion;
diff --git a/car-lib/src/android/car/CarVersion.java b/car-lib/src/android/car/CarVersion.java
new file mode 100644
index 0000000..8723bd3
--- /dev/null
+++ b/car-lib/src/android/car/CarVersion.java
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2022 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;
+
+import android.annotation.NonNull;
+import android.car.annotation.ApiRequirements;
+import android.car.annotation.ApiRequirements.PlatformVersion;
+import android.os.Build;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * Represents the API version of the {@code Car} SDK.
+ */
+@ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_1,
+ minPlatformVersion = PlatformVersion.TIRAMISU_0)
+public final class CarVersion extends ApiVersion<CarVersion> implements Parcelable {
+
+ /**
+ * Contains pre-defined versions matching Car releases.
+ */
+ @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_1,
+ minPlatformVersion = PlatformVersion.TIRAMISU_0)
+ public static class VERSION_CODES {
+
+ /**
+ * Helper object for main version of Android 13.
+ */
+ @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_1,
+ minPlatformVersion = PlatformVersion.TIRAMISU_0)
+ @NonNull
+ public static final CarVersion TIRAMISU_0 =
+ new CarVersion("TIRAMISU_0", Build.VERSION_CODES.TIRAMISU, 0);
+
+ /**
+ * Helper object for first minor upgrade of Android 13.
+ */
+ @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_1,
+ minPlatformVersion = PlatformVersion.TIRAMISU_0)
+ @NonNull
+ public static final CarVersion TIRAMISU_1 =
+ new CarVersion("TIRAMISU_1", Build.VERSION_CODES.TIRAMISU, 1);
+
+ private VERSION_CODES() {
+ throw new UnsupportedOperationException("Only provide constants");
+ }
+ }
+
+ /**
+ * Creates a named instance with the given major and minor versions.
+ */
+ // TODO(b/243429779): should not need @ApiRequirements as it's package-protected
+ @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_1,
+ minPlatformVersion = PlatformVersion.TIRAMISU_0)
+ static CarVersion newInstance(String versionName, int majorVersion, int minorVersion) {
+ return new CarVersion(versionName, majorVersion, minorVersion);
+ }
+
+ /**
+ * Creates a new instance with the given major and minor versions.
+ */
+ @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_1,
+ minPlatformVersion = PlatformVersion.TIRAMISU_0)
+ @NonNull
+ public static CarVersion forMajorAndMinorVersions(int majorVersion, int minorVersion) {
+ return new CarVersion(majorVersion, minorVersion);
+ }
+
+ /**
+ * Creates a new instance for a major version (i.e., the minor version will be {@code 0}.
+ */
+ @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_1,
+ minPlatformVersion = PlatformVersion.TIRAMISU_0)
+ @NonNull
+ public static CarVersion forMajorVersion(int majorVersion) {
+ return new CarVersion(majorVersion, /* minorVersion= */ 0);
+ }
+
+ private CarVersion(String name, int majorVersion, int minorVersion) {
+ super(name, majorVersion, minorVersion);
+ }
+
+ private CarVersion(int majorVersion, int minorVersion) {
+ super(majorVersion, minorVersion);
+ }
+
+ @Override
+ @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_1,
+ minPlatformVersion = PlatformVersion.TIRAMISU_0)
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_1,
+ minPlatformVersion = PlatformVersion.TIRAMISU_0)
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ writeToParcel(dest);
+ }
+
+ @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_1,
+ minPlatformVersion = PlatformVersion.TIRAMISU_0)
+ @NonNull
+ public static final Parcelable.Creator<CarVersion> CREATOR =
+ new Parcelable.Creator<CarVersion>() {
+
+ @Override
+ public CarVersion createFromParcel(Parcel source) {
+ return ApiVersion.readFromParcel(source,
+ (name, major, minor) -> new CarVersion(name, major, minor));
+ }
+
+ @Override
+ public CarVersion[] newArray(int size) {
+ return new CarVersion[size];
+ }
+ };
+}
diff --git a/car-lib/src/android/car/GsrComplianceType.java b/car-lib/src/android/car/GsrComplianceType.java
new file mode 100644
index 0000000..6ecda1f
--- /dev/null
+++ b/car-lib/src/android/car/GsrComplianceType.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2022 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;
+
+import android.annotation.IntDef;
+import android.car.annotation.ApiRequirements;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Used by
+ * {@link VehicleProperty.GENERAL_SAFETY_REGULATION_COMPLIANCE} to
+ * indicate what kind of general safety regulation compliance requirement is
+ * enforced.
+ */
+public final class GsrComplianceType {
+ /**
+ * GSR compliance is not required.
+ */
+ @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_1,
+ minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+ public static final int GSR_COMPLIANCE_TYPE_NOT_REQUIRED = 0;
+ /**
+ * GSR compliance is required and the requirement solution version is 1.
+ */
+ @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_1,
+ minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+ public static final int GSR_COMPLIANCE_TYPE_REQUIRED_V1 = 1;
+
+ /** @hide */
+ @IntDef({
+ GSR_COMPLIANCE_TYPE_NOT_REQUIRED,
+ GSR_COMPLIANCE_TYPE_REQUIRED_V1
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface Enum {}
+
+ private GsrComplianceType() {}
+}
diff --git a/car-lib/src/android/car/PlatformVersion.java b/car-lib/src/android/car/PlatformVersion.java
new file mode 100644
index 0000000..6e360fe
--- /dev/null
+++ b/car-lib/src/android/car/PlatformVersion.java
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2022 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;
+
+import android.annotation.NonNull;
+import android.car.annotation.ApiRequirements;
+import android.car.annotation.ApiRequirements.CarVersion;
+import android.os.Build;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * Represents the API version of the standard Android SDK.
+ */
+@ApiRequirements(minCarVersion = CarVersion.TIRAMISU_1,
+ minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+public final class PlatformVersion extends ApiVersion<PlatformVersion> implements Parcelable {
+
+ /**
+ * Contains pre-defined versions matching Car releases.
+ */
+ @ApiRequirements(minCarVersion = CarVersion.TIRAMISU_1,
+ minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+ public static class VERSION_CODES {
+
+ /**
+ * Helper object for main version of Android 13.
+ */
+ @ApiRequirements(minCarVersion = CarVersion.TIRAMISU_1,
+ minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+ @NonNull
+ public static final PlatformVersion TIRAMISU_0 =
+ new PlatformVersion("TIRAMISU_0", Build.VERSION_CODES.TIRAMISU, 0);
+
+ /**
+ * Helper object for first minor upgrade of Android 13.
+ */
+ @ApiRequirements(minCarVersion = CarVersion.TIRAMISU_1,
+ minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+ @NonNull
+ public static final PlatformVersion TIRAMISU_1 =
+ new PlatformVersion("TIRAMISU_1", Build.VERSION_CODES.TIRAMISU, 1);
+
+ private VERSION_CODES() {
+ throw new UnsupportedOperationException("Only provide constants");
+ }
+ }
+
+ /**
+ * Creates a named instance with the given major and minor versions.
+ */
+ // TODO(b/243429779): should not need @ApiRequirements as it's package-protected
+ @ApiRequirements(minCarVersion = CarVersion.TIRAMISU_1,
+ minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+ static PlatformVersion newInstance(String versionName, int majorVersion, int minorVersion) {
+ return new PlatformVersion(versionName, majorVersion, minorVersion);
+ }
+
+ /**
+ * Creates a new instance with the given major and minor versions.
+ */
+ @ApiRequirements(minCarVersion = CarVersion.TIRAMISU_1,
+ minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+ @NonNull
+ public static PlatformVersion forMajorAndMinorVersions(int majorVersion, int minorVersion) {
+ return new PlatformVersion(majorVersion, minorVersion);
+ }
+
+ /**
+ * Creates a new instance for a major version (i.e., the minor version will be {@code 0}.
+ */
+ @ApiRequirements(minCarVersion = CarVersion.TIRAMISU_1,
+ minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+ @NonNull
+ public static PlatformVersion forMajorVersion(int majorVersion) {
+ return new PlatformVersion(majorVersion, /* minorVersion= */ 0);
+ }
+
+ private PlatformVersion(String name, int majorVersion, int minorVersion) {
+ super(name, majorVersion, minorVersion);
+ }
+
+ private PlatformVersion(int majorVersion, int minorVersion) {
+ super(majorVersion, minorVersion);
+ }
+
+ @ApiRequirements(minCarVersion = CarVersion.TIRAMISU_1,
+ minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @ApiRequirements(minCarVersion = CarVersion.TIRAMISU_1,
+ minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+ @Override
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ writeToParcel(dest);
+ }
+
+ @ApiRequirements(minCarVersion = CarVersion.TIRAMISU_1,
+ minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+ @NonNull
+ public static final Parcelable.Creator<PlatformVersion> CREATOR =
+ new Parcelable.Creator<PlatformVersion>() {
+
+ @Override
+ public PlatformVersion createFromParcel(Parcel source) {
+ return ApiVersion.readFromParcel(source,
+ (name, major, minor) -> new PlatformVersion(name, major, minor));
+ }
+
+ @Override
+ public PlatformVersion[] newArray(int size) {
+ return new PlatformVersion[size];
+ }
+ };
+}
diff --git a/car-lib/src/android/car/PlatformVersionMismatchException.aidl b/car-lib/src/android/car/PlatformVersionMismatchException.aidl
new file mode 100644
index 0000000..4c3839b
--- /dev/null
+++ b/car-lib/src/android/car/PlatformVersionMismatchException.aidl
@@ -0,0 +1,18 @@
+/*
+ * Copyright (C) 2022 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;
+
+parcelable PlatformVersionMismatchException;
diff --git a/car-lib/src/android/car/PlatformVersionMismatchException.java b/car-lib/src/android/car/PlatformVersionMismatchException.java
new file mode 100644
index 0000000..1abef1c
--- /dev/null
+++ b/car-lib/src/android/car/PlatformVersionMismatchException.java
@@ -0,0 +1,150 @@
+/*
+ * Copyright (C) 2022 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;
+
+import static com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport.BOILERPLATE_CODE;
+
+import android.annotation.NonNull;
+import android.car.annotation.ApiRequirements;
+import android.car.annotation.MinimumPlatformSdkVersion;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport;
+import com.android.car.internal.util.AnnotationValidations;
+import com.android.car.internal.util.DataClass;
+
+/**
+ * Exception thrown when an App tries to calls an API not supported in the platform version.
+ *
+ * <p>Apps are expected to check the {@link MinimumPlatformSdkVersion} for each API. If the API is
+ * not supported for the current platform, the API should not be called. Apps can use
+ * {@link Car#getPlatformVersion()} to get the current platform version.
+ */
+@DataClass()
+public final class PlatformVersionMismatchException extends UnsupportedOperationException
+ implements Parcelable {
+
+ @NonNull
+ private final PlatformVersion mExpectedPlatformApiVersion;
+
+ @Override
+ @NonNull
+ @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_1,
+ minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+ public String getMessage() {
+ return "Expected version: "
+ + mExpectedPlatformApiVersion + ", Current version: " + Car.getPlatformVersion();
+ }
+
+
+ // Code below generated by codegen v1.0.23.
+ //
+ // DO NOT MODIFY!
+ // CHECKSTYLE:OFF Generated code
+ //
+ // To regenerate run:
+ // $ codegen $ANDROID_BUILD_TOP/packages/services/Car/car-lib/src/android/car/PlatformVersionMismatchException.java
+ //
+ // To exclude the generated code from IntelliJ auto-formatting enable (one-time):
+ // Settings > Editor > Code Style > Formatter Control
+ //@formatter:off
+
+
+ @DataClass.Generated.Member
+ public PlatformVersionMismatchException(
+ @NonNull PlatformVersion expectedPlatformApiVersion) {
+ this.mExpectedPlatformApiVersion = expectedPlatformApiVersion;
+ AnnotationValidations.validate(
+ NonNull.class, null, mExpectedPlatformApiVersion);
+
+ // onConstructed(); // You can define this method to get a callback
+ }
+
+ /**
+ * Gets expected platform API version.
+ */
+ @DataClass.Generated.Member
+ @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_1,
+ minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+ public @NonNull PlatformVersion getMinimumPlatformApiVersion() {
+ return mExpectedPlatformApiVersion;
+ }
+
+ @Override
+ @DataClass.Generated.Member
+ @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_1,
+ minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ // You can override field parcelling by defining methods like:
+ // void parcelFieldName(Parcel dest, int flags) { ... }
+
+ dest.writeTypedObject(mExpectedPlatformApiVersion, flags);
+ }
+
+ @Override
+ @DataClass.Generated.Member
+ @ExcludeFromCodeCoverageGeneratedReport(reason = BOILERPLATE_CODE)
+ @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_1,
+ minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+ public int describeContents() { return 0; }
+
+ /** @hide */
+ @SuppressWarnings({"unchecked", "RedundantCast"})
+ @DataClass.Generated.Member
+ /* package-private */ PlatformVersionMismatchException(@NonNull Parcel in) {
+ // You can override field unparcelling by defining methods like:
+ // static FieldType unparcelFieldName(Parcel in) { ... }
+
+ PlatformVersion expectedPlatformApiVersion = (PlatformVersion) in
+ .readTypedObject(PlatformVersion.CREATOR);
+
+ this.mExpectedPlatformApiVersion = expectedPlatformApiVersion;
+ AnnotationValidations.validate(
+ NonNull.class, null, mExpectedPlatformApiVersion);
+
+ // onConstructed(); // You can define this method to get a callback
+ }
+
+ @DataClass.Generated.Member
+ @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_1,
+ minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+ public static final @NonNull Parcelable.Creator<PlatformVersionMismatchException> CREATOR
+ = new Parcelable.Creator<PlatformVersionMismatchException>() {
+ @Override
+ public PlatformVersionMismatchException[] newArray(int size) {
+ return new PlatformVersionMismatchException[size];
+ }
+
+ @Override
+ public PlatformVersionMismatchException createFromParcel(@NonNull Parcel in) {
+ return new PlatformVersionMismatchException(in);
+ }
+ };
+
+ @DataClass.Generated(
+ time = 1658181489415L,
+ codegenVersion = "1.0.23",
+ sourceFile = "packages/services/Car/car-lib/src/android/car/PlatformVersionMismatchException.java",
+ inputSignatures = "private final @android.annotation.NonNull android.car.PlatformApiVersion mExpectedPlatformApiVersion\npublic @java.lang.Override @android.annotation.NonNull @android.car.annotation.AddedIn java.lang.String getMessage()\nclass PlatformVersionMismatchException extends java.lang.UnsupportedOperationException implements [android.os.Parcelable]\n@com.android.car.internal.util.DataClass()")
+ @Deprecated
+ private void __metadata() {}
+
+
+ //@formatter:on
+ // End of generated code
+
+}
diff --git a/car-lib/src/android/car/VehiclePropertyIds.java b/car-lib/src/android/car/VehiclePropertyIds.java
index 0698bef..1531ff1 100644
--- a/car-lib/src/android/car/VehiclePropertyIds.java
+++ b/car-lib/src/android/car/VehiclePropertyIds.java
@@ -19,7 +19,9 @@
import static com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport.BOILERPLATE_CODE;
import android.annotation.RequiresPermission;
+import android.annotation.SystemApi;
import android.car.annotation.AddedInOrBefore;
+import android.car.annotation.ApiRequirements;
import android.car.hardware.CarPropertyValue;
import android.car.hardware.property.VehicleElectronicTollCollectionCardStatus;
import android.car.hardware.property.VehicleElectronicTollCollectionCardType;
@@ -33,9 +35,10 @@
import java.util.concurrent.atomic.AtomicReference;
/**
- * Copy from android.hardware.automotive.vehicle-V2.0-java_gen_java/gen/android/hardware/automotive
- * /vehicle/V2_0. Need to update this file when vehicle propertyId is changed in VHAL.
- * Use it as PropertyId in getProperty() and setProperty() in
+ * Based on {@code VehicleProperty.java} generated based on {@code VehicleProperty.aidl} in VHAL
+ * interface.
+ * Need to update this file when vehicle propertyId is changed in VHAL. Use it as PropertyId in
+ * getProperty() and setProperty() in
* {@link android.car.hardware.property.CarPropertyManager}
*/
public final class VehiclePropertyIds {
@@ -1024,13 +1027,14 @@
public static final int HVAC_SEAT_VENTILATION = 356517139;
/**
* ELECTRIC DEFROSTER
- * The property is protected by the signature permission:
+ * The property is a read and write controllable and is protected by the signature permission:
* android.car.permission.CONTROL_CAR_CLIMATE.
*
* @hide
*/
@RequiresPermission(Car.PERMISSION_CONTROL_CAR_CLIMATE)
@AddedInOrBefore(majorVersion = 33)
+ @SystemApi
public static final int HVAC_ELECTRIC_DEFROSTER_ON = 320865556;
/**
* Distance units for display.
@@ -2240,6 +2244,19 @@
@AddedInOrBefore(majorVersion = 33)
public static final int TRAILER_PRESENT = 289410885;
+ /**
+ * EU's General security regulation compliance requirement.
+ *
+ * <p>Returns whether general security regulation compliance is required, if
+ * so, what type of requirement. See {@link GsrComplianceType} for possible enums.
+ *
+ * <p>Requires permission: {@link Car#PERMISSION_CAR_INFO}.
+ */
+ @RequiresPermission.Read(@RequiresPermission(Car.PERMISSION_CAR_INFO))
+ @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_1,
+ minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+ public static final int GENERAL_SAFETY_REGULATION_COMPLIANCE = 289410887;
+
/*
* Used to cache the mapping of property Id integer values into property name strings. This
* will be initialized during the first call to {@link VehiclePropertyIds#toString(int)}.
diff --git a/car-lib/src/android/car/annotation/AddedIn.java b/car-lib/src/android/car/annotation/AddedIn.java
index e5d3b4b..962284f 100644
--- a/car-lib/src/android/car/annotation/AddedIn.java
+++ b/car-lib/src/android/car/annotation/AddedIn.java
@@ -31,10 +31,13 @@
* {@link android.car.Car#API_VERSION_MAJOR_INT} for major version and
* {@link android.car.Car#API_VERSION_MINOR_INT} for minor version.
*
+ * @deprecated use {@link ApiRequirements} instead.
+ *
* @hide
*/
@Retention(RUNTIME)
@Target({ANNOTATION_TYPE, FIELD, TYPE, METHOD})
+@Deprecated
public @interface AddedIn {
int majorVersion();
int minorVersion() default 0;
diff --git a/car-lib/src/android/car/annotation/AddedInOrBefore.java b/car-lib/src/android/car/annotation/AddedInOrBefore.java
index 2e4c065..08fbbf4 100644
--- a/car-lib/src/android/car/annotation/AddedInOrBefore.java
+++ b/car-lib/src/android/car/annotation/AddedInOrBefore.java
@@ -30,10 +30,14 @@
*
* <p> For items marked with this, the client need to make sure to check car API version using
* {@link android.car.Car#API_VERSION_MAJOR_INT} for major version and
- * {@link android.car.Car#API_VERSION_MINOR_INT} for minor version.
+ * {@link android.car.Car#API_VERSION_MINOR_INT} for minor version. Should only be used for
+ * {@code majorVersion = 33, minorVersion = 0}.
+ *
+ * @deprecated - use {@code AddedIn} instead.
*
* @hide
*/
+@Deprecated
@Retention(RUNTIME)
@Target({ANNOTATION_TYPE, FIELD, TYPE, METHOD})
public @interface AddedInOrBefore {
diff --git a/car-lib/src/android/car/annotation/ApiRequirements.java b/car-lib/src/android/car/annotation/ApiRequirements.java
new file mode 100644
index 0000000..f5cfcda
--- /dev/null
+++ b/car-lib/src/android/car/annotation/ApiRequirements.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2022 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.annotation;
+
+import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.ElementType.TYPE;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+import android.annotation.TestApi;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+/**
+ * Defines in which version of Car and platform SDK the annotated API is supported.
+ *
+ * @hide
+ */
+@Retention(RUNTIME)
+@Target({ANNOTATION_TYPE, FIELD, TYPE, METHOD})
+@TestApi
+public @interface ApiRequirements {
+
+ /**
+ * Indicates the minimum Car SDK version required for the annotated API.
+ *
+ * <p>Clients can check it calling {@code Car.getCarApiVersion.isAtLeast(
+ * CarApiVersion.VERSION_CODES.VERSION_DEFINED_IN_THIS_ANNOTATION)}.
+ */
+ CarVersion minCarVersion();
+
+ /**
+ * Indicates the minimum Platform SDK version required for the annotated API.
+ *
+ * <p>Clients can check it calling {@code Car.getPlatformApiVersion.isAtLeast(
+ * PlatformApiVersion.VERSION_CODES.VERSION_DEFINED_IN_THIS_ANNOTATION)}.
+ */
+ PlatformVersion minPlatformVersion();
+
+ @SuppressWarnings("Enum")
+ enum CarVersion {
+
+ TIRAMISU_0(android.car.CarVersion.VERSION_CODES.TIRAMISU_0),
+ TIRAMISU_1(android.car.CarVersion.VERSION_CODES.TIRAMISU_1);
+
+ private final android.car.CarVersion mVersion;
+
+ CarVersion(android.car.CarVersion version) {
+ mVersion = version;
+ }
+
+ /**
+ * Gets the {@link CarVersion} associated with it.
+ */
+ public android.car.CarVersion get() {
+ return mVersion;
+ }
+ }
+
+ @SuppressWarnings("Enum")
+ enum PlatformVersion {
+
+ TIRAMISU_0(android.car.PlatformVersion.VERSION_CODES.TIRAMISU_0),
+ TIRAMISU_1(android.car.PlatformVersion.VERSION_CODES.TIRAMISU_1);
+
+ private final android.car.PlatformVersion mVersion;
+
+ PlatformVersion(android.car.PlatformVersion version) {
+ mVersion = version;
+ }
+
+ /**
+ * Gets the {@link PlatformVersion} associated with it.
+ */
+ public android.car.PlatformVersion get() {
+ return mVersion;
+ }
+ }
+}
diff --git a/car-lib/src/android/car/annotation/MinimumPlatformSdkVersion.java b/car-lib/src/android/car/annotation/MinimumPlatformSdkVersion.java
index b2d2f0a..7f55df3 100644
--- a/car-lib/src/android/car/annotation/MinimumPlatformSdkVersion.java
+++ b/car-lib/src/android/car/annotation/MinimumPlatformSdkVersion.java
@@ -26,13 +26,35 @@
import java.lang.annotation.Target;
/**
- * Represents minimum platform sdk int {@link android.os.Build.VERSION#SDK_INT} this method / type
- * / field can be used.
+ * Minimum platform sdk version this method / type / field can be used.
+ *
+ * @deprecated use {@link ApiRequirements} instead.
*
* @hide
*/
@Retention(SOURCE)
@Target({ANNOTATION_TYPE, FIELD, TYPE, METHOD})
+@Deprecated
public @interface MinimumPlatformSdkVersion {
- int value();
+
+ /**
+ * Represents the minimum version of Android Platform required to call this API.
+ *
+ * <p> Represents the minimum version of the Android platform (as defined by
+ * {@link android.os.Build.VERSION#SDK_INT}) that is required to call this API.
+ */
+ int majorVersion();
+
+ /**
+ * Represents the minor version of the Android platform required to call this API.
+ *
+ * <p> Represents the minimum minor version of the Android platform (as defined by
+ * {@link android.car.Car#PLATFORM_VERSION_MINOR_INT}) that is required to call this API.
+ *
+ * <p> The standard Android SDK doesn't provide an API to check incremental versions of the
+ * platform, but Car needs them as the Car APIs can be updated separately from the platform, and
+ * in some cases some APIs might depend on services that are not updatable by Car. This version
+ * would be incresed when Car API version is changed with the same {@link #majorVersion}.
+ */
+ int minorVersion() default 0;
}
diff --git a/car-lib/src/android/car/app/CarActivityManager.java b/car-lib/src/android/car/app/CarActivityManager.java
index 9f8e6f0..509ea9d 100644
--- a/car-lib/src/android/car/app/CarActivityManager.java
+++ b/car-lib/src/android/car/app/CarActivityManager.java
@@ -26,6 +26,7 @@
import android.car.Car;
import android.car.CarManagerBase;
import android.car.annotation.AddedInOrBefore;
+import android.car.annotation.ApiRequirements;
import android.car.user.CarUserManager;
import android.content.ActivityNotFoundException;
import android.content.ComponentName;
@@ -41,6 +42,8 @@
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
+import java.util.Collections;
+import java.util.List;
/**
* API to manage {@link android.app.Activity} in Car.
@@ -234,6 +237,23 @@
}
}
+ /**
+ * Returns all the visible tasks. The order is not guaranteed.
+ * @hide
+ */
+ @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS)
+ @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_1,
+ minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+ @NonNull
+ public List<ActivityManager.RunningTaskInfo> getVisibleTasks() {
+ try {
+ return mService.getVisibleTasks();
+ } catch (RemoteException e) {
+ handleRemoteExceptionFromCarService(e);
+ }
+ return Collections.emptyList();
+ }
+
private boolean hasValidToken() {
boolean valid = mTaskMonitorToken != null;
if (!valid) {
diff --git a/car-lib/src/android/car/app/ICarActivityService.aidl b/car-lib/src/android/car/app/ICarActivityService.aidl
index 823cdd7..49133f5 100644
--- a/car-lib/src/android/car/app/ICarActivityService.aidl
+++ b/car-lib/src/android/car/app/ICarActivityService.aidl
@@ -18,6 +18,8 @@
import android.app.ActivityManager.RunningTaskInfo;
import android.content.ComponentName;
+import java.util.List;
+
/** @hide */
interface ICarActivityService {
@@ -53,5 +55,10 @@
* Unregisters the caller from TaskMonitor.
*/
void unregisterTaskMonitor(in IBinder token) = 5;
+
+ /**
+ * Returns all the visible tasks ordered in top to bottom manner.
+ */
+ List<RunningTaskInfo> getVisibleTasks() = 6;
}
diff --git a/car-lib/src/android/car/cluster/ClusterActivityState.java b/car-lib/src/android/car/cluster/ClusterActivityState.java
index 5311078..bb5d397 100644
--- a/car-lib/src/android/car/cluster/ClusterActivityState.java
+++ b/car-lib/src/android/car/cluster/ClusterActivityState.java
@@ -16,7 +16,9 @@
package android.car.cluster;
+import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.SystemApi;
import android.car.annotation.AddedInOrBefore;
import android.graphics.Rect;
import android.os.Bundle;
@@ -27,7 +29,8 @@
*
* @hide
*/
-public class ClusterActivityState {
+@SystemApi
+public final class ClusterActivityState {
private static final String KEY_VISIBLE = "android.car:activityState.visible";
private static final String KEY_UNOBSCURED_BOUNDS = "android.car:activityState.unobscured";
private static final String KEY_EXTRAS = "android.car:activityState.extras";
@@ -74,7 +77,7 @@
* @return this instance for chaining.
*/
@AddedInOrBefore(majorVersion = 33)
- public ClusterActivityState setVisible(boolean visible) {
+ @NonNull public ClusterActivityState setVisible(boolean visible) {
mVisible = visible;
return this;
}
@@ -90,7 +93,7 @@
* @return this instance for chaining.
*/
@AddedInOrBefore(majorVersion = 33)
- public ClusterActivityState setUnobscuredBounds(Rect unobscuredBounds) {
+ @NonNull public ClusterActivityState setUnobscuredBounds(@NonNull Rect unobscuredBounds) {
mUnobscuredBounds = unobscuredBounds;
return this;
}
@@ -101,7 +104,7 @@
* @return this instance for chaining.
*/
@AddedInOrBefore(majorVersion = 33)
- public ClusterActivityState setExtras(Bundle bundle) {
+ @NonNull public ClusterActivityState setExtras(@NonNull Bundle bundle) {
mExtras = bundle;
return this;
}
@@ -114,7 +117,8 @@
* {@link #setVisible(boolean)} and {@link #setUnobscuredBounds(Rect)} for more details)
*/
@AddedInOrBefore(majorVersion = 33)
- public static ClusterActivityState create(boolean visible, Rect unobscuredBounds) {
+ @NonNull public static ClusterActivityState create(
+ boolean visible, @NonNull Rect unobscuredBounds) {
return new ClusterActivityState()
.setVisible(visible)
.setUnobscuredBounds(unobscuredBounds);
@@ -124,7 +128,7 @@
* Reconstructs a {@link ClusterActivityState} from a {@link Bundle}
*/
@AddedInOrBefore(majorVersion = 33)
- public static ClusterActivityState fromBundle(Bundle bundle) {
+ @NonNull public static ClusterActivityState fromBundle(@NonNull Bundle bundle) {
return new ClusterActivityState()
.setVisible(bundle.getBoolean(KEY_VISIBLE, true))
.setUnobscuredBounds((Rect) bundle.getParcelable(KEY_UNOBSCURED_BOUNDS))
@@ -136,7 +140,7 @@
* deserialized using {@link #fromBundle(Bundle)}.
*/
@AddedInOrBefore(majorVersion = 33)
- public Bundle toBundle() {
+ @NonNull public Bundle toBundle() {
Bundle b = new Bundle();
b.putBoolean(KEY_VISIBLE, mVisible);
b.putParcelable(KEY_UNOBSCURED_BOUNDS, mUnobscuredBounds);
diff --git a/car-lib/src/android/car/cluster/renderer/InstrumentClusterRenderingService.java b/car-lib/src/android/car/cluster/renderer/InstrumentClusterRenderingService.java
index 9632af2..c48b5b6 100644
--- a/car-lib/src/android/car/cluster/renderer/InstrumentClusterRenderingService.java
+++ b/car-lib/src/android/car/cluster/renderer/InstrumentClusterRenderingService.java
@@ -469,10 +469,9 @@
*
* @param activityOptions contains information of how to start cluster activity (on what display
* or activity stack).
- * @hide
*/
@AddedInOrBefore(majorVersion = 33)
- public void setClusterActivityLaunchOptions(ActivityOptions activityOptions) {
+ public void setClusterActivityLaunchOptions(@NonNull ActivityOptions activityOptions) {
mActivityOptions = activityOptions;
updateNavigationActivity();
}
@@ -493,10 +492,9 @@
*
* @param state pass information about activity state, see
* {@link android.car.cluster.ClusterActivityState}
- * @hide
*/
@AddedInOrBefore(majorVersion = 33)
- public void setClusterActivityState(ClusterActivityState state) {
+ public void setClusterActivityState(@NonNull ClusterActivityState state) {
mActivityState = state;
updateNavigationActivity();
}
diff --git a/car-lib/src/android/car/content/pm/CarPackageManager.java b/car-lib/src/android/car/content/pm/CarPackageManager.java
index bfb4565..9f2e016 100644
--- a/car-lib/src/android/car/content/pm/CarPackageManager.java
+++ b/car-lib/src/android/car/content/pm/CarPackageManager.java
@@ -17,7 +17,9 @@
package android.car.content.pm;
import static android.car.Car.PERMISSION_CONTROL_APP_BLOCKING;
+import static android.car.CarLibLog.TAG_CAR;
+import android.Manifest;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.RequiresPermission;
@@ -27,13 +29,19 @@
import android.app.PendingIntent;
import android.car.Car;
import android.car.CarManagerBase;
+import android.car.CarVersion;
import android.car.annotation.AddedInOrBefore;
+import android.car.annotation.ApiRequirements;
import android.content.ComponentName;
import android.content.pm.PackageManager.NameNotFoundException;
import android.os.IBinder;
import android.os.Looper;
+import android.os.Process;
import android.os.RemoteException;
import android.os.ServiceSpecificException;
+import android.util.Log;
+
+import com.android.internal.annotations.VisibleForTesting;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -44,7 +52,9 @@
* Provides car specific API related with package management.
*/
public final class CarPackageManager extends CarManagerBase {
- private static final String TAG = "CarPackageManager";
+
+ private static final String TAG = CarPackageManager.class.getSimpleName();
+ private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
/**
* Flag for {@link #setAppBlockingPolicy(String, CarAppBlockingPolicy, int)}. When this
@@ -160,6 +170,29 @@
@AddedInOrBefore(majorVersion = 33)
public static final int ERROR_CODE_NO_PACKAGE = -100;
+ /**
+ * Manifest metadata used to specify the minimum major and minor Car API version an app is
+ * targeting.
+ *
+ * <p>Format is in the form {@code major:minor} or {@code major}.
+ *
+ * <p>For example, for {@link Build.VERSION_CODES#TIRAMISU Android 13}, it would be:
+ * <code><meta-data android:name="android.car.targetCarVersion" android:value="33"/></code>
+ *
+ * <p>Or:
+ *
+ * <code><meta-data android:name="android.car.targetCarVersion" android:value="33:0"/></code>
+ *
+ * <p>And for {@link Build.VERSION_CODES#TIRAMISU Android 13} first update:
+ *
+ * <code><meta-data android:name="android.car.targetCarVersion" android:value="33:1"/></code>
+ */
+ @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_1,
+ minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+ public static final String MANIFEST_METADATA_TARGET_CAR_VERSION =
+ "android.car.targetCarVersion";
+
+
/** @hide */
@IntDef(flag = true,
value = {FLAG_SET_POLICY_WAIT_FOR_CHANGE, FLAG_SET_POLICY_ADD, FLAG_SET_POLICY_REMOVE})
@@ -170,8 +203,14 @@
/** @hide */
public CarPackageManager(Car car, IBinder service) {
+ this(car, ICarPackageManager.Stub.asInterface(service));
+ }
+
+ /** @hide */
+ @VisibleForTesting
+ public CarPackageManager(Car car, ICarPackageManager service) {
super(car);
- mService = ICarPackageManager.Stub.asInterface(service);
+ mService = service;
}
/** @hide */
@@ -429,7 +468,79 @@
return Collections.EMPTY_LIST; // cannot reach here but the compiler complains.
}
+ /**
+ * Gets the Car API version targeted by the given package (as defined by
+ * {@link #MANIFEST_METADATA_TARGET_CAR_VERSION}.
+ *
+ * <p>If the app manifest doesn't contain the {@link #MANIFEST_METADATA_TARGET_CAR_VERSION}
+ * metadata attribute or if the attribute format is invalid, the returned {@code CarVersion}
+ * will be using the
+ * {@link android.content.pm.ApplicationInfo#targetSdkVersion target platform version} as major
+ * and {@code 0} as minor instead.
+ *
+ * <p><b>Note: </b>to get the target {@link CarVersion} for your own app, use
+ * {@link #getTargetCarVersion()} instead.
+ * @return Car API version targeted by the given package (as described above).
+ *
+ * @throws NameNotFoundException If the given package does not exist for the user.
+ *
+ * @hide
+ */
+ @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_1,
+ minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+ @SystemApi
+ @RequiresPermission(Manifest.permission.QUERY_ALL_PACKAGES)
+ @NonNull
+ public CarVersion getTargetCarVersion(@NonNull String packageName)
+ throws NameNotFoundException {
+ try {
+ return mService.getTargetCarVersion(packageName);
+ } catch (ServiceSpecificException e) {
+ Log.w(TAG, "Failed to get CarVersion for " + packageName, e);
+ handleServiceSpecificFromCarService(e, packageName);
+ } catch (RemoteException e) {
+ e.rethrowFromSystemServer();
+ }
+ return null; // cannot reach here but the compiler complains.
+ }
+
+ /**
+ * Gets the Car API version targeted by app (as defined by
+ * {@link #MANIFEST_METADATA_TARGET_CAR_VERSION}.
+ *
+ * <p>If the app manifest doesn't contain the {@link #MANIFEST_METADATA_TARGET_CAR_VERSION}
+ * metadata attribute or if the attribute format is invalid, the returned {@code CarVersion}
+ * will be using the {@link android.content.pm.ApplicationInfo#targetSdkVersion target platform
+ * version} as major and {@code 0} as minor instead.
+ *
+ * @return targeted Car API version (as defined above)
+ */
+ @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_1,
+ minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+ @NonNull
+ public CarVersion getTargetCarVersion() {
+ String pkgName = mCar.getContext().getPackageName();
+ try {
+ return mService.getSelfTargetCarVersion(pkgName);
+ } catch (RemoteException e) {
+ Log.w(TAG_CAR, "Car service threw exception calling getTargetCarVersion(" + pkgName
+ + ")", e);
+ e.rethrowFromSystemServer();
+ return null;
+ }
+ }
+
private void handleServiceSpecificFromCarService(ServiceSpecificException e,
+ String packageName) throws NameNotFoundException {
+ if (e.errorCode == ERROR_CODE_NO_PACKAGE) {
+ throw new NameNotFoundException(
+ "cannot find " + packageName + " for user " + Process.myUserHandle());
+ }
+ // don't know what this is
+ throw new IllegalStateException(e);
+ }
+
+ private static void handleServiceSpecificFromCarService(ServiceSpecificException e,
String packageName, String activityClassName, @UserIdInt int userId)
throws NameNotFoundException {
if (e.errorCode == ERROR_CODE_NO_PACKAGE) {
diff --git a/car-lib/src/android/car/content/pm/ICarPackageManager.aidl b/car-lib/src/android/car/content/pm/ICarPackageManager.aidl
index b0bdc7c..69f6b7e 100644
--- a/car-lib/src/android/car/content/pm/ICarPackageManager.aidl
+++ b/car-lib/src/android/car/content/pm/ICarPackageManager.aidl
@@ -17,6 +17,7 @@
package android.car.content.pm;
import android.app.PendingIntent;
+import android.car.CarVersion;
import android.car.content.pm.CarAppBlockingPolicy;
import android.content.ComponentName;
@@ -34,4 +35,6 @@
boolean bypass, int userId) = 8;
List<String> getSupportedDrivingSafetyRegionsForActivityAsUser(String packageName,
String activityClassName, int userId) = 9;
+ CarVersion getTargetCarVersion(String packageName) = 10;
+ CarVersion getSelfTargetCarVersion(in String packageName) = 11;
}
diff --git a/car-lib/src/android/car/drivingstate/CarUxRestrictionsConfiguration.java b/car-lib/src/android/car/drivingstate/CarUxRestrictionsConfiguration.java
index e514f9a..b20e9ed 100644
--- a/car-lib/src/android/car/drivingstate/CarUxRestrictionsConfiguration.java
+++ b/car-lib/src/android/car/drivingstate/CarUxRestrictionsConfiguration.java
@@ -27,6 +27,8 @@
import android.annotation.FloatRange;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.SuppressLint;
+import android.annotation.SystemApi;
import android.car.annotation.AddedInOrBefore;
import android.car.builtin.os.BuildHelper;
import android.car.drivingstate.CarDrivingStateEvent.CarDrivingState;
@@ -56,6 +58,7 @@
*
* @hide
*/
+@SystemApi
public final class CarUxRestrictionsConfiguration implements Parcelable {
private static final String TAG = "CarUxRConfig";
@@ -118,6 +121,7 @@
* @param currentSpeed Current speed in meter per second.
*/
@AddedInOrBefore(majorVersion = 33)
+ @NonNull
public CarUxRestrictions getUxRestrictions(
@CarDrivingState int drivingState, float currentSpeed) {
return getUxRestrictions(drivingState, currentSpeed, UX_RESTRICTION_MODE_BASELINE);
@@ -135,6 +139,7 @@
* @param mode Current UX Restriction mode.
*/
@AddedInOrBefore(majorVersion = 33)
+ @NonNull
public CarUxRestrictions getUxRestrictions(@CarDrivingState int drivingState,
@FloatRange(from = 0f) float currentSpeed, @NonNull String mode) {
Objects.requireNonNull(mode, "mode must not be null");
@@ -184,6 +189,7 @@
* to default display {@link android.view.Display#DEFAULT_DISPLAY}.
*/
@Nullable
+ @SuppressLint("AutoBoxing")
@AddedInOrBefore(majorVersion = 33)
public Integer getPhysicalPort() {
return mPhysicalPort;
@@ -246,6 +252,7 @@
/**
* Writes current configuration as Json.
+ * @hide
*/
@AddedInOrBefore(majorVersion = 33)
public void writeJson(@NonNull JsonWriter writer) throws IOException {
@@ -333,8 +340,10 @@
*
* <p>Supports reading files persisted in multiple JSON schemas, including the pre-R version 1
* format, and the R format version 2.
+ * @hide
*/
@AddedInOrBefore(majorVersion = 33)
+ @NonNull
public static CarUxRestrictionsConfiguration readJson(@NonNull JsonReader reader,
int schemaVersion) throws IOException {
Objects.requireNonNull(reader, "reader must not be null");
@@ -560,6 +569,7 @@
/**
* Compares {@code this} configuration object with {@code other} on restriction parameters.
+ * @hide
*/
@AddedInOrBefore(majorVersion = 33)
public boolean hasSameParameters(@NonNull CarUxRestrictionsConfiguration other) {
@@ -571,6 +581,7 @@
/**
* Dump the driving state to UX restrictions mapping.
+ * @hide
*/
@ExcludeFromCodeCoverageGeneratedReport(reason = DUMP_INFO)
@AddedInOrBefore(majorVersion = 33)
@@ -635,6 +646,7 @@
};
@AddedInOrBefore(majorVersion = 33)
+ @NonNull
public static final Parcelable.Creator<CarUxRestrictionsConfiguration> CREATOR =
new Parcelable.Creator<CarUxRestrictionsConfiguration>() {
@@ -680,7 +692,7 @@
@Override
@AddedInOrBefore(majorVersion = 33)
- public void writeToParcel(Parcel dest, int flags) {
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
dest.writeInt(mRestrictionModes.size());
for (Map.Entry<String, RestrictionModeContainer> entry : mRestrictionModes.entrySet()) {
dest.writeString(entry.getKey());
diff --git a/car-lib/src/android/car/drivingstate/CarUxRestrictionsManager.java b/car-lib/src/android/car/drivingstate/CarUxRestrictionsManager.java
index d1a4adc..6e0f30f 100644
--- a/car-lib/src/android/car/drivingstate/CarUxRestrictionsManager.java
+++ b/car-lib/src/android/car/drivingstate/CarUxRestrictionsManager.java
@@ -19,6 +19,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
+import android.annotation.SystemApi;
import android.car.Car;
import android.car.CarManagerBase;
import android.car.annotation.AddedInOrBefore;
@@ -54,6 +55,7 @@
* @hide
*/
@AddedInOrBefore(majorVersion = 33)
+ @SystemApi
public static final String UX_RESTRICTION_MODE_BASELINE = "baseline";
private final Object mLock = new Object();
@@ -67,7 +69,7 @@
private CarUxRestrictionsChangeListenerToService mListenerToService;
/** @hide */
- public CarUxRestrictionsManager(Car car, IBinder service) {
+ public CarUxRestrictionsManager(@NonNull Car car, @NonNull IBinder service) {
super(car);
mUxRService = ICarUxRestrictionsManager.Stub.asInterface(service);
mEventCallbackHandler = new EventCallbackHandler(this,
@@ -77,6 +79,7 @@
/** @hide */
@Override
@AddedInOrBefore(majorVersion = 33)
+ @SystemApi
public void onCarDisconnected() {
synchronized (mLock) {
mListenerToService = null;
@@ -116,7 +119,16 @@
* @hide
*/
@AddedInOrBefore(majorVersion = 33)
+ @Deprecated
public void registerListener(@NonNull OnUxRestrictionsChangedListener listener, int displayId) {
+ setListener(displayId, listener);
+ }
+ /**
+ * @hide
+ */
+ @AddedInOrBefore(majorVersion = 33)
+ @SystemApi
+ public void setListener(int displayId, @NonNull OnUxRestrictionsChangedListener listener) {
CarUxRestrictionsChangeListenerToService serviceListener;
synchronized (mLock) {
// Check if the listener has been already registered.
@@ -182,8 +194,9 @@
*/
@RequiresPermission(value = Car.PERMISSION_CAR_UX_RESTRICTIONS_CONFIGURATION)
@AddedInOrBefore(majorVersion = 33)
+ @SystemApi
public boolean saveUxRestrictionsConfigurationForNextBoot(
- List<CarUxRestrictionsConfiguration> configs) {
+ @NonNull List<CarUxRestrictionsConfiguration> configs) {
try {
return mUxRService.saveUxRestrictionsConfigurationForNextBoot(configs);
} catch (RemoteException e) {
@@ -207,6 +220,7 @@
*/
@Nullable
@AddedInOrBefore(majorVersion = 33)
+ @SystemApi
public CarUxRestrictions getCurrentCarUxRestrictions(int displayId) {
try {
return mUxRService.getCurrentUxRestrictions(displayId);
@@ -233,6 +247,7 @@
*/
@RequiresPermission(value = Car.PERMISSION_CAR_UX_RESTRICTIONS_CONFIGURATION)
@AddedInOrBefore(majorVersion = 33)
+ @SystemApi
public boolean setRestrictionMode(@NonNull String mode) {
Objects.requireNonNull(mode, "mode must not be null");
try {
@@ -255,6 +270,7 @@
@RequiresPermission(value = Car.PERMISSION_CAR_UX_RESTRICTIONS_CONFIGURATION)
@NonNull
@AddedInOrBefore(majorVersion = 33)
+ @SystemApi
public String getRestrictionMode() {
try {
return mUxRService.getRestrictionMode();
@@ -275,8 +291,9 @@
*/
@RequiresPermission(value = Car.PERMISSION_CAR_UX_RESTRICTIONS_CONFIGURATION)
@AddedInOrBefore(majorVersion = 33)
+ @SystemApi
public boolean saveUxRestrictionsConfigurationForNextBoot(
- CarUxRestrictionsConfiguration config) {
+ @NonNull CarUxRestrictionsConfiguration config) {
return saveUxRestrictionsConfigurationForNextBoot(Arrays.asList(config));
}
@@ -295,6 +312,7 @@
@Nullable
@RequiresPermission(value = Car.PERMISSION_CAR_UX_RESTRICTIONS_CONFIGURATION)
@AddedInOrBefore(majorVersion = 33)
+ @SystemApi
public List<CarUxRestrictionsConfiguration> getStagedConfigs() {
try {
return mUxRService.getStagedConfigs();
@@ -309,8 +327,10 @@
* @return current configurations that is in effect.
* @hide
*/
+ @Nullable
@RequiresPermission(value = Car.PERMISSION_CAR_UX_RESTRICTIONS_CONFIGURATION)
@AddedInOrBefore(majorVersion = 33)
+ @SystemApi
public List<CarUxRestrictionsConfiguration> getConfigs() {
try {
return mUxRService.getConfigs();
diff --git a/car-lib/src/android/car/evs/CarEvsManager.java b/car-lib/src/android/car/evs/CarEvsManager.java
index 5b3c084..9249fd7 100644
--- a/car-lib/src/android/car/evs/CarEvsManager.java
+++ b/car-lib/src/android/car/evs/CarEvsManager.java
@@ -503,6 +503,9 @@
mService.returnFrameBuffer(buffer.getId());
} catch (RemoteException err) {
handleRemoteExceptionFromCarService(err);
+ } finally {
+ // We are done with this HardwareBuffer object.
+ buffer.getHardwareBuffer().close();
}
}
diff --git a/car-lib/src/android/car/hardware/hvac/CarHvacManager.java b/car-lib/src/android/car/hardware/hvac/CarHvacManager.java
index 94dd383..c8698f3 100644
--- a/car-lib/src/android/car/hardware/hvac/CarHvacManager.java
+++ b/car-lib/src/android/car/hardware/hvac/CarHvacManager.java
@@ -62,8 +62,8 @@
* HVAC property IDs for get/set methods
*/
/**
- * Mirror defrosters state, bool type
- * true indicates mirror defroster is on
+ * Mirror defrosters state, int type
+ * Positive values indicate mirror defroster is on
*/
@AddedInOrBefore(majorVersion = 33)
public static final int ID_MIRROR_DEFROSTER_ON = 0x1440050c;
diff --git a/car-lib/src/android/car/hardware/power/CarPowerManager.java b/car-lib/src/android/car/hardware/power/CarPowerManager.java
index 6318dc1..4e43c7f 100644
--- a/car-lib/src/android/car/hardware/power/CarPowerManager.java
+++ b/car-lib/src/android/car/hardware/power/CarPowerManager.java
@@ -455,7 +455,7 @@
// Updates listener
mListener = listener;
mExecutor = executor;
- setServiceForListenerLocked(false);
+ setServiceForListenerLocked(/* useCompletion= */ false);
}
}
@@ -489,7 +489,7 @@
// Updates listener
mListenerWithCompletion = listener;
mExecutor = executor;
- setServiceForListenerLocked(true);
+ setServiceForListenerLocked(/* useCompletion= */ true);
}
}
@@ -691,6 +691,7 @@
public static boolean isCompletionAllowed(@CarPowerState int state) {
switch (state) {
case CarPowerManager.STATE_PRE_SHUTDOWN_PREPARE:
+ case CarPowerManager.STATE_SHUTDOWN_PREPARE:
case CarPowerManager.STATE_SHUTDOWN_ENTER:
case CarPowerManager.STATE_SUSPEND_ENTER:
case CarPowerManager.STATE_HIBERNATION_ENTER:
diff --git a/car-lib/src/android/car/hardware/property/CarPropertyManager.java b/car-lib/src/android/car/hardware/property/CarPropertyManager.java
index e00b4a3..3320319 100644
--- a/car-lib/src/android/car/hardware/property/CarPropertyManager.java
+++ b/car-lib/src/android/car/hardware/property/CarPropertyManager.java
@@ -17,6 +17,7 @@
package android.car.hardware.property;
import static java.lang.Integer.toHexString;
+import static java.util.Objects.requireNonNull;
import android.annotation.FloatRange;
import android.annotation.IntDef;
@@ -37,8 +38,9 @@
import android.util.Log;
import android.util.SparseArray;
-import com.android.car.internal.CarRatedFloatListeners;
+import com.android.car.internal.CarPropertyEventCallbackController;
import com.android.car.internal.SingleMessageHandler;
+import com.android.internal.annotations.GuardedBy;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -59,11 +61,40 @@
private final ICarProperty mService;
private final int mAppTargetSdk;
- private CarPropertyEventListenerToService mCarPropertyEventToService;
+ private final CarPropertyEventListenerToService mCarPropertyEventToService =
+ new CarPropertyEventListenerToService(this);
- /** Record of locally active properties. Key is propertyId */
- private final SparseArray<CarPropertyListeners> mActivePropertyListener =
- new SparseArray<>();
+ // This lock is shared with all CarPropertyEventCallbackController instances to prevent
+ // potential deadlock.
+ private final Object mLock = new Object();
+ @GuardedBy("mLock")
+ private final SparseArray<CarPropertyEventCallbackController>
+ mPropertyIdToCarPropertyEventCallbackController = new SparseArray<>();
+
+ private final CarPropertyEventCallbackController.RegistrationUpdateCallback
+ mRegistrationUpdateCallback =
+ new CarPropertyEventCallbackController.RegistrationUpdateCallback() {
+ @Override
+ public boolean register(int propertyId, float updateRateHz) {
+ try {
+ mService.registerListener(propertyId, updateRateHz,
+ mCarPropertyEventToService);
+ } catch (RemoteException e) {
+ handleRemoteExceptionFromCarService(e);
+ return false;
+ }
+ return true;
+ }
+
+ @Override
+ public void unregister(int propertyId) {
+ try {
+ mService.unregisterListener(propertyId, mCarPropertyEventToService);
+ } catch (RemoteException e) {
+ handleRemoteExceptionFromCarService(e);
+ }
+ }
+ };
/**
* Application registers {@link CarPropertyEventCallback} object to receive updates and changes
@@ -191,33 +222,35 @@
mHandler = new SingleMessageHandler<CarPropertyEvent>(eventHandler.getLooper(),
MSG_GENERIC_EVENT) {
@Override
- protected void handleEvent(CarPropertyEvent event) {
- CarPropertyListeners listeners;
- synchronized (mActivePropertyListener) {
- listeners = mActivePropertyListener.get(
- event.getCarPropertyValue().getPropertyId());
+ protected void handleEvent(CarPropertyEvent carPropertyEvent) {
+ CarPropertyEventCallbackController carPropertyEventCallbackController;
+ synchronized (mLock) {
+ carPropertyEventCallbackController =
+ mPropertyIdToCarPropertyEventCallbackController.get(
+ carPropertyEvent.getCarPropertyValue().getPropertyId());
}
- if (listeners != null) {
- switch (event.getEventType()) {
- case CarPropertyEvent.PROPERTY_EVENT_PROPERTY_CHANGE:
- listeners.onPropertyChanged(event);
- break;
- case CarPropertyEvent.PROPERTY_EVENT_ERROR:
- listeners.onErrorEvent(event);
- break;
- default:
- throw new IllegalArgumentException();
- }
+ if (carPropertyEventCallbackController == null) {
+ return;
+ }
+ switch (carPropertyEvent.getEventType()) {
+ case CarPropertyEvent.PROPERTY_EVENT_PROPERTY_CHANGE:
+ carPropertyEventCallbackController.forwardPropertyChanged(carPropertyEvent);
+ break;
+ case CarPropertyEvent.PROPERTY_EVENT_ERROR:
+ carPropertyEventCallbackController.forwardErrorEvent(carPropertyEvent);
+ break;
+ default:
+ throw new IllegalArgumentException();
}
}
};
}
/**
- * Register {@link CarPropertyEventCallback} to get property updates. Multiple listeners
- * can be registered for a single property or the same listener can be used for different
- * properties. If the same listener is registered again for the same property, it will be
- * updated to new rate.
+ * Register {@link CarPropertyEventCallback} to get property updates. Multiple callbacks
+ * can be registered for a single property or the same callback can be used for different
+ * properties. If the same callback is registered again for the same property, it will be
+ * updated to new updateRateHz.
* <p>Rate could be one of the following:
* <ul>
* <li>{@link CarPropertyManager#SENSOR_RATE_ONCHANGE}</li>
@@ -236,132 +269,113 @@
* {@link CarPropertyConfig#VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE} property, it will receive the
* property's current value upon registration.
* See {@link CarPropertyConfig#getChangeMode()} for details.
- * If rate is higher than {@link CarPropertyConfig#getMaxSampleRate()}, it will be registered
- * with max sample rate.
- * If rate is lower than {@link CarPropertyConfig#getMinSampleRate()}, it will be registered
- * with min sample rate.
+ * If updateRateHz is higher than {@link CarPropertyConfig#getMaxSampleRate()}, it will be
+ * registered with max sample updateRateHz.
+ * If updateRateHz is lower than {@link CarPropertyConfig#getMinSampleRate()}, it will be
+ * registered with min sample updateRateHz.
*
- * @param callback CarPropertyEventCallback to be registered.
- * @param propertyId PropertyId to subscribe
- * @param rate how fast the property events are delivered in Hz.
+ * @param carPropertyEventCallback CarPropertyEventCallback to be registered.
+ * @param propertyId PropertyId to subscribe
+ * @param updateRateHz how fast the property events are delivered in Hz.
* @return true if the listener is successfully registered.
* @throws SecurityException if missing the appropriate permission.
*/
@AddedInOrBefore(majorVersion = 33)
- public boolean registerCallback(@NonNull CarPropertyEventCallback callback,
- int propertyId, @FloatRange(from = 0.0, to = 100.0) float rate) {
- synchronized (mActivePropertyListener) {
- if (mCarPropertyEventToService == null) {
- mCarPropertyEventToService = new CarPropertyEventListenerToService(this);
- }
- CarPropertyConfig config = getCarPropertyConfig(propertyId);
- if (config == null) {
- Log.e(TAG, "registerListener: propId is not in config list: " + propertyId);
- return false;
- }
- if (config.getChangeMode() == CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE) {
- rate = SENSOR_RATE_ONCHANGE;
- }
- boolean needsServerUpdate = false;
- CarPropertyListeners listeners;
- listeners = mActivePropertyListener.get(propertyId);
- if (listeners == null) {
- listeners = new CarPropertyListeners(rate);
- mActivePropertyListener.put(propertyId, listeners);
- needsServerUpdate = true;
- }
- if (listeners.addAndUpdateRate(callback, rate)) {
- needsServerUpdate = true;
- }
- if (needsServerUpdate) {
- if (!registerOrUpdatePropertyListener(propertyId, rate)) {
- return false;
- }
+ public boolean registerCallback(@NonNull CarPropertyEventCallback carPropertyEventCallback,
+ int propertyId, @FloatRange(from = 0.0, to = 100.0) float updateRateHz) {
+ requireNonNull(carPropertyEventCallback);
+ CarPropertyConfig<?> carPropertyConfig = getCarPropertyConfig(propertyId);
+ if (carPropertyConfig == null) {
+ Log.e(TAG, "registerListener: propId is not in carPropertyConfig list: "
+ + VehiclePropertyIds.toString(propertyId));
+ return false;
+ }
+ if (carPropertyConfig.getChangeMode()
+ != CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_CONTINUOUS) {
+ updateRateHz = SENSOR_RATE_ONCHANGE;
+ } else if (updateRateHz > carPropertyConfig.getMaxSampleRate()) {
+ updateRateHz = carPropertyConfig.getMaxSampleRate();
+ } else if (updateRateHz < carPropertyConfig.getMinSampleRate()) {
+ updateRateHz = carPropertyConfig.getMinSampleRate();
+ }
+ CarPropertyEventCallbackController carPropertyEventCallbackController;
+ synchronized (mLock) {
+ carPropertyEventCallbackController =
+ mPropertyIdToCarPropertyEventCallbackController.get(propertyId);
+ if (carPropertyEventCallbackController == null) {
+ carPropertyEventCallbackController = new CarPropertyEventCallbackController(
+ propertyId, mLock, mRegistrationUpdateCallback);
+ mPropertyIdToCarPropertyEventCallbackController.put(propertyId,
+ carPropertyEventCallbackController);
}
}
- return true;
+ return carPropertyEventCallbackController.add(carPropertyEventCallback, updateRateHz);
}
- private boolean registerOrUpdatePropertyListener(int propertyId, float rate) {
- try {
- mService.registerListener(propertyId, rate, mCarPropertyEventToService);
- } catch (RemoteException e) {
- return handleRemoteExceptionFromCarService(e, false);
- }
- return true;
- }
+ private static class CarPropertyEventListenerToService extends ICarPropertyEventListener.Stub {
+ private final WeakReference<CarPropertyManager> mCarPropertyManager;
- private static class CarPropertyEventListenerToService extends ICarPropertyEventListener.Stub{
- private final WeakReference<CarPropertyManager> mMgr;
-
- CarPropertyEventListenerToService(CarPropertyManager mgr) {
- mMgr = new WeakReference<>(mgr);
+ CarPropertyEventListenerToService(CarPropertyManager carPropertyManager) {
+ mCarPropertyManager = new WeakReference<>(carPropertyManager);
}
@Override
- public void onEvent(List<CarPropertyEvent> events) throws RemoteException {
- CarPropertyManager manager = mMgr.get();
- if (manager != null) {
- manager.handleEvent(events);
+ public void onEvent(List<CarPropertyEvent> carPropertyEvents) throws RemoteException {
+ CarPropertyManager carPropertyManager = mCarPropertyManager.get();
+ if (carPropertyManager != null) {
+ carPropertyManager.handleEvents(carPropertyEvents);
}
}
}
- private void handleEvent(List<CarPropertyEvent> events) {
+ private void handleEvents(List<CarPropertyEvent> carPropertyEvents) {
if (mHandler != null) {
- mHandler.sendEvents(events);
+ mHandler.sendEvents(carPropertyEvents);
}
}
/**
- * Stop getting property update for the given callback. If there are multiple registrations for
- * this callback, all listening will be stopped.
- * @param callback CarPropertyEventCallback to be unregistered.
+ * Stop getting property updates for the given {@link CarPropertyEventCallback}. If there are
+ * multiple registrations for this {@link CarPropertyEventCallback}, all listening will be
+ * stopped.
*/
@AddedInOrBefore(majorVersion = 33)
- public void unregisterCallback(@NonNull CarPropertyEventCallback callback) {
- synchronized (mActivePropertyListener) {
- int [] propertyIds = new int[mActivePropertyListener.size()];
- for (int i = 0; i < mActivePropertyListener.size(); i++) {
- propertyIds[i] = mActivePropertyListener.keyAt(i);
+ public void unregisterCallback(@NonNull CarPropertyEventCallback carPropertyEventCallback) {
+ requireNonNull(carPropertyEventCallback);
+ int[] propertyIds;
+ synchronized (mLock) {
+ propertyIds = new int[mPropertyIdToCarPropertyEventCallbackController.size()];
+ for (int i = 0; i < mPropertyIdToCarPropertyEventCallbackController.size(); i++) {
+ propertyIds[i] = mPropertyIdToCarPropertyEventCallbackController.keyAt(i);
}
- for (int prop : propertyIds) {
- doUnregisterListenerLocked(callback, prop);
- }
+ }
+ for (int propertyId : propertyIds) {
+ unregisterCallback(carPropertyEventCallback, propertyId);
}
}
/**
- * Stop getting property update for the given callback and property. If the same callback is
- * used for other properties, those subscriptions will not be affected.
- *
- * @param callback CarPropertyEventCallback to be unregistered.
- * @param propertyId PropertyId to be unregistered.
+ * Stop getting update for {@code propertyId} to the given {@link CarPropertyEventCallback}. If
+ * the same {@link CarPropertyEventCallback} is used for other properties, those subscriptions
+ * will not be affected.
*/
@AddedInOrBefore(majorVersion = 33)
- public void unregisterCallback(@NonNull CarPropertyEventCallback callback, int propertyId) {
- synchronized (mActivePropertyListener) {
- doUnregisterListenerLocked(callback, propertyId);
+ public void unregisterCallback(@NonNull CarPropertyEventCallback carPropertyEventCallback,
+ int propertyId) {
+ requireNonNull(carPropertyEventCallback);
+ CarPropertyEventCallbackController carPropertyEventCallbackController;
+ synchronized (mLock) {
+ carPropertyEventCallbackController =
+ mPropertyIdToCarPropertyEventCallbackController.get(propertyId);
}
- }
-
- private void doUnregisterListenerLocked(CarPropertyEventCallback listener, int propertyId) {
- CarPropertyListeners listeners = mActivePropertyListener.get(propertyId);
- if (listeners != null) {
- boolean needsServerUpdate = false;
- if (listeners.contains(listener)) {
- needsServerUpdate = listeners.remove(listener);
- }
- if (listeners.isEmpty()) {
- try {
- mService.unregisterListener(propertyId, mCarPropertyEventToService);
- } catch (RemoteException e) {
- handleRemoteExceptionFromCarService(e);
- // continue for local clean-up
- }
- mActivePropertyListener.remove(propertyId);
- } else if (needsServerUpdate) {
- registerOrUpdatePropertyListener(propertyId, listeners.getRate());
+ if (carPropertyEventCallbackController == null) {
+ return;
+ }
+ boolean allCallbacksRemoved = carPropertyEventCallbackController.remove(
+ carPropertyEventCallback);
+ if (allCallbacksRemoved) {
+ synchronized (mLock) {
+ mPropertyIdToCarPropertyEventCallbackController.remove(propertyId);
}
}
}
@@ -877,9 +891,6 @@
}
checkSupportedProperty(propId);
try {
- if (mCarPropertyEventToService == null) {
- mCarPropertyEventToService = new CarPropertyEventListenerToService(this);
- }
mService.setProperty(new CarPropertyValue<>(propId, areaId, val),
mCarPropertyEventToService);
} catch (RemoteException e) {
@@ -987,62 +998,12 @@
}
}
- private final class CarPropertyListeners
- extends CarRatedFloatListeners<CarPropertyEventCallback> {
- CarPropertyListeners(float rate) {
- super(rate);
- }
- void onPropertyChanged(final CarPropertyEvent event) {
- // throw away old sensor data as oneway binder call can change order.
- long updateTime = event.getCarPropertyValue().getTimestamp();
- int areaId = event.getCarPropertyValue().getAreaId();
- if (!needUpdateForAreaId(areaId, updateTime)) {
- if (DBG) {
- Log.w(TAG, "Dropping a stale event: " + event.toString());
- }
- return;
- }
- List<CarPropertyEventCallback> listeners;
- synchronized (mActivePropertyListener) {
- listeners = new ArrayList<>(getListeners());
- }
- listeners.forEach(listener -> {
- if (contains(listener)
- && needUpdateForSelectedListener(listener, updateTime)) {
- listener.onChangeEvent(event.getCarPropertyValue());
- }
- });
- }
-
- void onErrorEvent(final CarPropertyEvent event) {
- List<CarPropertyEventCallback> listeners;
- CarPropertyValue value = event.getCarPropertyValue();
- synchronized (mActivePropertyListener) {
- listeners = new ArrayList<>(getListeners());
- }
- listeners.forEach(listener -> {
- if (contains(listener)) {
- if (DBG) {
- Log.d(TAG, new StringBuilder().append("onErrorEvent for ")
- .append("property: ").append(value.getPropertyId())
- .append(" areaId: ").append(value.getAreaId())
- .append(" errorCode: ").append(event.getErrorCode())
- .toString());
- }
- listener.onErrorEvent(value.getPropertyId(), value.getAreaId(),
- event.getErrorCode());
- }
- });
- }
- }
-
/** @hide */
@Override
@AddedInOrBefore(majorVersion = 33)
public void onCarDisconnected() {
- synchronized (mActivePropertyListener) {
- mActivePropertyListener.clear();
- mCarPropertyEventToService = null;
+ synchronized (mLock) {
+ mPropertyIdToCarPropertyEventCallbackController.clear();
}
}
}
diff --git a/car-lib/src/android/car/os/CarPerformanceManager.java b/car-lib/src/android/car/os/CarPerformanceManager.java
index 36d8ba1..9b727f8 100644
--- a/car-lib/src/android/car/os/CarPerformanceManager.java
+++ b/car-lib/src/android/car/os/CarPerformanceManager.java
@@ -19,12 +19,17 @@
import android.annotation.CallbackExecutor;
import android.annotation.NonNull;
import android.annotation.RequiresPermission;
+import android.annotation.SystemApi;
import android.car.Car;
import android.car.CarManagerBase;
import android.car.annotation.AddedInOrBefore;
-import android.car.annotation.ExperimentalFeature;
+import android.car.annotation.ApiRequirements;
+import android.car.annotation.ApiRequirements.CarVersion;
+import android.car.annotation.ApiRequirements.PlatformVersion;
import android.os.IBinder;
-import android.util.Log;
+import android.os.Process;
+import android.os.RemoteException;
+import android.os.ServiceSpecificException;
import java.util.Objects;
import java.util.concurrent.Executor;
@@ -33,17 +38,27 @@
* CarPerformanceManager allows applications to tweak performance settings for their
* processes/threads and listen for CPU available change notifications.
*
- * <p>This feature is still under development and will not be available for user builds.
- *
* @hide
*/
-@ExperimentalFeature
+@SystemApi
public final class CarPerformanceManager extends CarManagerBase {
- private static final String TAG = CarPerformanceManager.class.getSimpleName();
- private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
private final ICarPerformanceService mService;
+ /**
+ * An exception type thrown when {@link setThreadPriority} failed.
+ *
+ * @hide
+ */
+ @SystemApi
+ @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_1,
+ minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_1)
+ public static final class SetSchedulerFailedException extends Exception {
+ SetSchedulerFailedException(Throwable cause) {
+ super(cause);
+ }
+ }
+
/** @hide */
public CarPerformanceManager(Car car, IBinder service) {
super(car);
@@ -70,6 +85,8 @@
* <li>Handle the CPU availability timeout.
* </ul>
* </p>
+ *
+ * @hide
*/
public interface CpuAvailabilityChangeListener {
/**
@@ -99,6 +116,8 @@
* interface.
*
* @throws IllegalStateException if {@code listener} is already added.
+ *
+ * @hide
*/
@RequiresPermission(Car.PERMISSION_COLLECT_CAR_CPU_INFO)
@AddedInOrBefore(majorVersion = 33)
@@ -119,6 +138,8 @@
*
* @param listener Listener implementing {@link CpuAvailabilityChangeListener}
* interface.
+ *
+ * @hide
*/
@RequiresPermission(Car.PERMISSION_COLLECT_CAR_CPU_INFO)
@AddedInOrBefore(majorVersion = 33)
@@ -131,5 +152,68 @@
// TODO(b/217422127): Implement the API.
throw new UnsupportedOperationException("Not yet implemented");
}
-}
+ /**
+ * Sets the thread scheduling policy with priority for the current thread.
+ *
+ * For {@link ThreadPolicyWithPriority#SCHED_DEFAULT} scheduling algorithm, the standard
+ * round-robin time-sharing algorithm will be used and the priority field will be ignored.
+ * Please use {@link Process#setThreadPriority} to adjust the priority for the default
+ * scheduling.
+ *
+ * @param policyWithPriority A thread scheduling policy with priority.
+ * @throws IllegalArgumentException If the policy is not supported or the priority is not within
+ * {@link ThreadPolicyWithPriority#PRIORITY_MIN} and
+ * {@link ThreadPolicyWithPriority#PRIORITY_MAX}.
+ * @throws SetSchedulerFailedException If failed to set the scheduling policy and priority.
+ * @throws SecurityException If permission check failed.
+ *
+ * @hide
+ */
+ @SystemApi
+ @ApiRequirements(minCarVersion = CarVersion.TIRAMISU_1,
+ minPlatformVersion = PlatformVersion.TIRAMISU_1)
+ @RequiresPermission(Car.PERMISSION_MANAGE_THREAD_PRIORITY)
+ public void setThreadPriority(@NonNull ThreadPolicyWithPriority policyWithPriority)
+ throws SetSchedulerFailedException {
+ int tid = Process.myTid();
+ try {
+ mService.setThreadPriority(tid, policyWithPriority);
+ } catch (ServiceSpecificException e) {
+ throw new SetSchedulerFailedException(e);
+ } catch (RemoteException e) {
+ handleRemoteExceptionFromCarService(e);
+ }
+ }
+
+ /**
+ * Gets the thread scheduling policy with priority for the current thread.
+ *
+ * For {@link ThreadPolicyWithPriority#SCHED_FIFO} or
+ * {@link ThreadPolicyWithPriority#SCHED_RR}, this function returns the priority for the
+ * scheduling algorithm. For {@link ThreadPolicyWithPriority#SCHED_DEFAULT} which is the
+ * standard round-robin time-sharing algorithm, this function always return 0 for priority. The
+ * priority for the default algorithm can be fetched by {@link Process#getThreadPriority}.
+ *
+ * @throws IllegalStateException If failed to get policy or priority.
+ * @throws SecurityException If permission check failed.
+ *
+ * @hide
+ */
+ @SystemApi
+ @ApiRequirements(minCarVersion = CarVersion.TIRAMISU_1,
+ minPlatformVersion = PlatformVersion.TIRAMISU_1)
+ @RequiresPermission(Car.PERMISSION_MANAGE_THREAD_PRIORITY)
+ public @NonNull ThreadPolicyWithPriority getThreadPriority() {
+ int tid = Process.myTid();
+ try {
+ return mService.getThreadPriority(tid);
+ } catch (RemoteException e) {
+ handleRemoteExceptionFromCarService(e);
+ // Car service has crashed, return a default value since we do not
+ // want to crash the client.
+ return new ThreadPolicyWithPriority(
+ ThreadPolicyWithPriority.SCHED_DEFAULT, /* priority= */ 0);
+ }
+ }
+}
diff --git a/car-lib/src/android/car/os/ICarPerformanceService.aidl b/car-lib/src/android/car/os/ICarPerformanceService.aidl
index 16b4daf..90c31f5 100644
--- a/car-lib/src/android/car/os/ICarPerformanceService.aidl
+++ b/car-lib/src/android/car/os/ICarPerformanceService.aidl
@@ -18,6 +18,7 @@
import android.car.os.ICpuAvailabilityChangeListener;
import android.car.os.CpuAvailabilityMonitoringConfig;
+import android.car.os.ThreadPolicyWithPriority;
/** @hide */
interface ICarPerformanceService {
@@ -25,4 +26,26 @@
void addCpuAvailabilityChangeListener(
in CpuAvailabilityMonitoringConfig config, in ICpuAvailabilityChangeListener listener);
oneway void removeCpuAvailabilityChangeListener(in ICpuAvailabilityChangeListener listener);
+
+ /**
+ * Sets the thread priority for a specific thread.
+ *
+ * The thread must belong to the calling process.
+ *
+ * @throws SecurityException If permission check failed.
+ * @throws ServiceSpecificException If the operation failed.
+ * @throws IllegalArgumentException If the provided tid does not belong to the calling process.
+ */
+ void setThreadPriority(int tid, in ThreadPolicyWithPriority policyWithPriority);
+
+ /**
+ * Gets the thread priority for a specific thread.
+ *
+ * The thread must belong to the calling process.
+ *
+ * @throws SecurityException If permission check failed.
+ * @throws ServiceSpecificException If the operation failed.
+ * @throws IllegalArgumentException If the provided tid does not belong to the calling process.
+ */
+ ThreadPolicyWithPriority getThreadPriority(int tid);
}
diff --git a/car-lib/src/android/car/os/ThreadPolicyWithPriority.aidl b/car-lib/src/android/car/os/ThreadPolicyWithPriority.aidl
new file mode 100644
index 0000000..281fc37
--- /dev/null
+++ b/car-lib/src/android/car/os/ThreadPolicyWithPriority.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2022 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.os;
+
+parcelable ThreadPolicyWithPriority;
diff --git a/car-lib/src/android/car/os/ThreadPolicyWithPriority.java b/car-lib/src/android/car/os/ThreadPolicyWithPriority.java
new file mode 100644
index 0000000..e83d94d
--- /dev/null
+++ b/car-lib/src/android/car/os/ThreadPolicyWithPriority.java
@@ -0,0 +1,277 @@
+/*
+ * Copyright (C) 2022 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.os;
+
+import android.annotation.IntDef;
+import android.annotation.IntRange;
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.car.annotation.ApiRequirements;
+import android.os.Parcelable;
+
+import com.android.car.internal.util.AnnotationValidations;
+import com.android.car.internal.util.DataClass;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Defines the thread scheduling policy and priority.
+ *
+ * <p>This API supports real-time scheduling polices:
+ * ({@code SCHED_FIFO}, {@code SCHED_RR}) with a {@code sched_priority} value in the range within
+ * [{@link PRIORITY_MIN}, {@link PRIORITY_MAX}]. This API also supports the default round-robin
+ * time-sharing scheduling algorithm: {@code SCHED_DEFAULT}.
+ *
+ * @hide
+ */
+@SystemApi
+@DataClass(genConstructor = false, genHiddenConstDefs = true)
+public final class ThreadPolicyWithPriority implements Parcelable {
+
+ /**
+ * Min supported thread priority.
+ */
+ @Priority
+ @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_1,
+ minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_1)
+ public static final int PRIORITY_MIN = 1;
+
+ /**
+ * Max supported thread priority.
+ */
+ @Priority
+ @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_1,
+ minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_1)
+ public static final int PRIORITY_MAX = 99;
+
+ /** @hide */
+ @IntDef({SCHED_DEFAULT, SCHED_FIFO, SCHED_RR})
+ @Retention(RetentionPolicy.SOURCE)
+ @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_1,
+ minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_1)
+ public @interface SchedPolicy {}
+
+ /**
+ * Default round-robin time-sharing scheduling policy.
+ *
+ * <p> Same as {@code SCHED_OTHER} defined in {@code /include/uapi/linux/sched.h}.
+ */
+ @Sched
+ @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_1,
+ minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_1)
+ public static final int SCHED_DEFAULT = 0;
+
+ /**
+ * First-in-first-out scheduling policy. See definition for Linux {@code sched(7)}.
+ *
+ * <p>Same as {@code SCHED_FIFO} defined in {@code /include/uapi/linux/sched.h}.
+ */
+ @Sched
+ @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_1,
+ minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_1)
+ public static final int SCHED_FIFO = 1;
+
+ /**
+ * Round robin scheduling policy. See definition for Linux {@code sched(7)}.
+ *
+ * <p>Same as {@code SCHED_RR} defined in {@code /include/uapi/linux/sched.h}.
+ */
+ @Sched
+ @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_1,
+ minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_1)
+ public static final int SCHED_RR = 2;
+
+ @SchedPolicy
+ private final int mPolicy;
+
+ @IntRange(from = 0, to = 99)
+ private final int mPriority;
+
+ /**
+ * Creates a new thread policy with priority.
+ *
+ * @param policy The scheduling policy, must be one of {@link SchedPolicy}.
+ * @param priority The priority, must be within [{@link PRIORITY_MIN}, {@link PRIORITY_MAX}].
+ */
+ public ThreadPolicyWithPriority(
+ @SchedPolicy int policy, @IntRange(from = 0, to = 99) int priority) {
+ if (policy != SCHED_FIFO && policy != SCHED_RR && policy != SCHED_DEFAULT) {
+ throw new IllegalArgumentException("invalid policy");
+ }
+ // priority is ignored for SCHED_DEFAULT
+ if (policy == SCHED_DEFAULT) {
+ priority = 0;
+ } else if (priority < PRIORITY_MIN || priority > PRIORITY_MAX) {
+ throw new IllegalArgumentException("invalid priority");
+ }
+ mPolicy = policy;
+ mPriority = priority;
+ }
+
+
+
+ // Code below generated by codegen v1.0.23.
+ //
+ // DO NOT MODIFY!
+ // CHECKSTYLE:OFF Generated code
+ //
+ // The generated code is patched with adding "AddedIn" annotation to all public
+ // methods/interfaces.
+ //
+ // To regenerate run:
+ // $ codegen $ANDROID_BUILD_TOP/packages/services/Car/car-lib/src/android/car/os/ThreadPolicyWithPriority.java
+ //
+ // To exclude the generated code from IntelliJ auto-formatting enable (one-time):
+ // Settings > Editor > Code Style > Formatter Control
+ //@formatter:off
+
+
+ /** @hide */
+ @IntDef(prefix = "PRIORITY_", value = {
+ PRIORITY_MIN,
+ PRIORITY_MAX
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ @DataClass.Generated.Member
+ @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_1,
+ minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_1)
+ public @interface Priority {}
+
+ /** @hide */
+ @DataClass.Generated.Member
+ public static String priorityToString(@Priority int value) {
+ switch (value) {
+ case PRIORITY_MIN:
+ return "PRIORITY_MIN";
+ case PRIORITY_MAX:
+ return "PRIORITY_MAX";
+ default: return Integer.toHexString(value);
+ }
+ }
+
+ /** @hide */
+ @IntDef(prefix = "SCHED_", value = {
+ SCHED_DEFAULT,
+ SCHED_FIFO,
+ SCHED_RR
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ @DataClass.Generated.Member
+ @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_1,
+ minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_1)
+ public @interface Sched {}
+
+ /** @hide */
+ @DataClass.Generated.Member
+ @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_1,
+ minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_1)
+ public static String schedToString(@Sched int value) {
+ switch (value) {
+ case SCHED_DEFAULT:
+ return "SCHED_DEFAULT";
+ case SCHED_FIFO:
+ return "SCHED_FIFO";
+ case SCHED_RR:
+ return "SCHED_RR";
+ default: return Integer.toHexString(value);
+ }
+ }
+
+ @DataClass.Generated.Member
+ @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_1,
+ minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_1)
+ public @SchedPolicy int getPolicy() {
+ return mPolicy;
+ }
+
+ @DataClass.Generated.Member
+ @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_1,
+ minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_1)
+ public @IntRange(from = 0, to = 99) int getPriority() {
+ return mPriority;
+ }
+
+ @Override
+ @DataClass.Generated.Member
+ @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_1,
+ minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_1)
+ public void writeToParcel(@NonNull android.os.Parcel dest, int flags) {
+ // You can override field parcelling by defining methods like:
+ // void parcelFieldName(Parcel dest, int flags) { ... }
+
+ dest.writeInt(mPolicy);
+ dest.writeInt(mPriority);
+ }
+
+ @Override
+ @DataClass.Generated.Member
+ @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_1,
+ minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_1)
+ public int describeContents() { return 0; }
+
+ /** @hide */
+ @SuppressWarnings({"unchecked", "RedundantCast"})
+ @DataClass.Generated.Member
+ /* package-private */ ThreadPolicyWithPriority(@NonNull android.os.Parcel in) {
+ // You can override field unparcelling by defining methods like:
+ // static FieldType unparcelFieldName(Parcel in) { ... }
+
+ int policy = in.readInt();
+ int priority = in.readInt();
+
+ this.mPolicy = policy;
+ AnnotationValidations.validate(
+ SchedPolicy.class, null, mPolicy);
+ this.mPriority = priority;
+ AnnotationValidations.validate(
+ IntRange.class, null, mPriority,
+ "from", 0,
+ "to", 99);
+
+ // onConstructed(); // You can define this method to get a callback
+ }
+
+ @DataClass.Generated.Member
+ @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_1,
+ minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_1)
+ public static final @NonNull Parcelable.Creator<ThreadPolicyWithPriority> CREATOR
+ = new Parcelable.Creator<ThreadPolicyWithPriority>() {
+ @Override
+ public ThreadPolicyWithPriority[] newArray(int size) {
+ return new ThreadPolicyWithPriority[size];
+ }
+
+ @Override
+ public ThreadPolicyWithPriority createFromParcel(@NonNull android.os.Parcel in) {
+ return new ThreadPolicyWithPriority(in);
+ }
+ };
+
+ @DataClass.Generated(
+ time = 1657845707744L,
+ codegenVersion = "1.0.23",
+ sourceFile = "packages/services/Car/car-lib/src/android/car/os/ThreadPolicyWithPriority.java",
+ inputSignatures = "public static final @android.car.os.ThreadPolicyWithPriority.Priority @android.car.annotation.AddedIn int PRIORITY_MIN\npublic static final @android.car.os.ThreadPolicyWithPriority.Priority @android.car.annotation.AddedIn int PRIORITY_MAX\npublic static final @android.car.os.ThreadPolicyWithPriority.Sched @android.car.annotation.AddedIn int SCHED_DEFAULT\npublic static final @android.car.os.ThreadPolicyWithPriority.Sched @android.car.annotation.AddedIn int SCHED_FIFO\npublic static final @android.car.os.ThreadPolicyWithPriority.Sched @android.car.annotation.AddedIn int SCHED_RR\nprivate final @android.car.os.ThreadPolicyWithPriority.SchedPolicy int mPolicy\nprivate final @android.annotation.IntRange int mPriority\nclass ThreadPolicyWithPriority extends java.lang.Object implements [android.os.Parcelable]\n@com.android.car.internal.util.DataClass(genConstructor=false, genHiddenConstDefs=true)")
+ @Deprecated
+ private void __metadata() {}
+
+
+ //@formatter:on
+ // End of generated code
+
+}
diff --git a/car-lib/src/android/car/telemetry/CarTelemetryManager.java b/car-lib/src/android/car/telemetry/CarTelemetryManager.java
index 58b9426..fe0caf0 100644
--- a/car-lib/src/android/car/telemetry/CarTelemetryManager.java
+++ b/car-lib/src/android/car/telemetry/CarTelemetryManager.java
@@ -30,13 +30,23 @@
import android.car.builtin.util.Slogf;
import android.os.Bundle;
import android.os.IBinder;
+import android.os.ParcelFileDescriptor;
import android.os.PersistableBundle;
import android.os.RemoteException;
import android.os.ResultReceiver;
+import libcore.io.IoUtils;
+
+import java.io.ByteArrayInputStream;
+import java.io.DataInputStream;
+import java.io.EOFException;
+import java.io.IOException;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.ref.WeakReference;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
import java.util.concurrent.Executor;
import java.util.concurrent.atomic.AtomicReference;
@@ -55,7 +65,7 @@
private static final int METRICS_CONFIG_MAX_SIZE_BYTES = 10 * 1024; // 10 kb
private final ICarTelemetryService mService;
- private final AtomicReference<Executor> mExecutor;
+ private final AtomicReference<Executor> mReportReadyListenerExecutor;
private final AtomicReference<ReportReadyListener> mReportReadyListener;
/** Status to indicate that MetricsConfig was added successfully. */
@@ -232,7 +242,7 @@
public CarTelemetryManager(Car car, IBinder service) {
super(car);
mService = ICarTelemetryService.Stub.asInterface(service);
- mExecutor = new AtomicReference<>(null);
+ mReportReadyListenerExecutor = new AtomicReference<>(null);
mReportReadyListener = new AtomicReference<>(null);
if (DEBUG) {
Slogf.d(TAG, "starting car telemetry manager");
@@ -349,17 +359,8 @@
@CallbackExecutor @NonNull Executor executor,
@NonNull MetricsReportCallback callback) {
try {
- mService.getFinishedReport(metricsConfigName, new ICarTelemetryReportListener.Stub() {
- @Override
- public void onResult(
- @NonNull String metricsConfigName,
- @Nullable PersistableBundle report,
- @Nullable byte[] telemetryError,
- int status) {
- executor.execute(() ->
- callback.onResult(metricsConfigName, report, telemetryError, status));
- }
- });
+ mService.getFinishedReport(
+ metricsConfigName, new CarTelemetryReportListenerImpl(executor, callback));
} catch (RemoteException e) {
handleRemoteExceptionFromCarService(e);
}
@@ -382,17 +383,7 @@
public void getAllFinishedReports(
@CallbackExecutor @NonNull Executor executor, @NonNull MetricsReportCallback callback) {
try {
- mService.getAllFinishedReports(new ICarTelemetryReportListener.Stub() {
- @Override
- public void onResult(
- @NonNull String metricsConfigName,
- @Nullable PersistableBundle report,
- @Nullable byte[] telemetryError,
- int status) {
- executor.execute(() ->
- callback.onResult(metricsConfigName, report, telemetryError, status));
- }
- });
+ mService.getAllFinishedReports(new CarTelemetryReportListenerImpl(executor, callback));
} catch (RemoteException e) {
handleRemoteExceptionFromCarService(e);
}
@@ -424,7 +415,7 @@
if (mReportReadyListener.get() != null) {
throw new IllegalStateException("ReportReadyListener is already set.");
}
- mExecutor.set(executor);
+ mReportReadyListenerExecutor.set(executor);
mReportReadyListener.set(listener);
try {
mService.setReportReadyListener(new CarTelemetryReportReadyListenerImpl(this));
@@ -443,7 +434,7 @@
@RequiresPermission(Car.PERMISSION_USE_CAR_TELEMETRY_SERVICE)
@AddedInOrBefore(majorVersion = 33)
public void clearReportReadyListener() {
- mExecutor.set(null);
+ mReportReadyListenerExecutor.set(null);
mReportReadyListener.set(null);
try {
mService.clearReportReadyListener();
@@ -452,6 +443,14 @@
}
}
+ /** Listens for report ready notifications.
+ * Atomic variables (mReportReadyListenerExecutor and mReportReadyListener)
+ * can be accessed from different threads simultaneously.
+ * Both of these variables can be set to null by {@link #clearReportReadyListener()}
+ * and simultaneously {@link #onReady(String)} may try to access the null value.
+ * So, to avoid possible NullPointerException due to this race condition,
+ * these atomic variables are needed to be retrieved in local variables
+ * and verified those are not null before accessing. */
private static final class CarTelemetryReportReadyListenerImpl
extends ICarTelemetryReportReadyListener.Stub {
private final WeakReference<CarTelemetryManager> mManager;
@@ -466,8 +465,105 @@
if (manager == null) {
return;
}
- manager.mExecutor.get().execute(
- () -> manager.mReportReadyListener.get().onReady(metricsConfigName));
+ Executor executor = manager.mReportReadyListenerExecutor.get();
+ if (executor == null) {
+ return;
+ }
+ ReportReadyListener reportReadyListener = manager.mReportReadyListener.get();
+ if (reportReadyListener == null) {
+ return;
+ }
+ executor.execute(
+ () -> reportReadyListener.onReady(metricsConfigName));
+ }
+ }
+
+ /**
+ * Receives responses to {@link #getFinishedReport(String, Executor, MetricsReportCallback)}
+ * requests.
+ */
+ private static final class CarTelemetryReportListenerImpl
+ extends ICarTelemetryReportListener.Stub {
+
+ private final Executor mExecutor;
+ private final MetricsReportCallback mMetricsReportCallback;
+
+ private CarTelemetryReportListenerImpl(Executor executor, MetricsReportCallback callback) {
+ Objects.requireNonNull(executor);
+ Objects.requireNonNull(callback);
+ mExecutor = executor;
+ mMetricsReportCallback = callback;
+ }
+
+ @Override
+ public void onResult(
+ @NonNull String metricsConfigName,
+ @Nullable ParcelFileDescriptor reportFileDescriptor,
+ @Nullable byte[] telemetryError,
+ @MetricsReportStatus int status) {
+ // return early if no need to stream reports
+ if (reportFileDescriptor == null) {
+ mExecutor.execute(() -> mMetricsReportCallback.onResult(
+ metricsConfigName, null, telemetryError, status));
+ return;
+ }
+ // getting to this line means the reportFileDescriptor is non-null
+ ParcelFileDescriptor dup = null;
+ try {
+ dup = reportFileDescriptor.dup();
+ } catch (IOException e) {
+ Slogf.w(TAG, "Could not dup ParcelFileDescriptor", e);
+ return;
+ } finally {
+ IoUtils.closeQuietly(reportFileDescriptor);
+ }
+ final ParcelFileDescriptor readFd = dup;
+ mExecutor.execute(() -> {
+ // read PersistableBundles from the pipe, this method will also close the fd
+ List<PersistableBundle> reports = parseReports(readFd);
+ // if a readFd is non-null, CarTelemetryService will write at least 1 report
+ // to the pipe, so something must have gone wrong to get 0 report
+ if (reports.size() == 0) {
+ mMetricsReportCallback.onResult(metricsConfigName, null, null,
+ STATUS_GET_METRICS_CONFIG_RUNTIME_ERROR);
+ return;
+ }
+ for (PersistableBundle report : reports) {
+ mMetricsReportCallback
+ .onResult(metricsConfigName, report, telemetryError, status);
+ }
+ });
+ }
+
+ /** Helper method to parse reports (PersistableBundles) from the file descriptor. */
+ private List<PersistableBundle> parseReports(ParcelFileDescriptor reportFileDescriptor) {
+ List<PersistableBundle> reports = new ArrayList<>();
+ try (DataInputStream dataInputStream = new DataInputStream(
+ new ParcelFileDescriptor.AutoCloseInputStream(reportFileDescriptor))) {
+ while (true) {
+ // read integer which tells us how many bytes to read for the PersistableBundle
+ int size = dataInputStream.readInt();
+ byte[] bundleBytes = dataInputStream.readNBytes(size);
+ if (bundleBytes.length != size) {
+ Slogf.e(TAG, "Expected to read " + size
+ + " bytes from the pipe, but only read "
+ + bundleBytes.length + " bytes");
+ break;
+ }
+ PersistableBundle report = PersistableBundle.readFromStream(
+ new ByteArrayInputStream(bundleBytes));
+ reports.add(report);
+ }
+ } catch (EOFException e) {
+ // a graceful exit from the while true loop, thrown by DataInputStream#readInt(),
+ // every successful parse should naturally reach this line
+ if (DEBUG) {
+ Slogf.d(TAG, "parseReports reached end of file");
+ }
+ } catch (IOException e) {
+ Slogf.e(TAG, "Failed to read metrics reports from pipe", e);
+ }
+ return reports;
}
}
}
diff --git a/car-lib/src/android/car/telemetry/ICarTelemetryReportListener.aidl b/car-lib/src/android/car/telemetry/ICarTelemetryReportListener.aidl
index 53c27df..86f4bfc 100644
--- a/car-lib/src/android/car/telemetry/ICarTelemetryReportListener.aidl
+++ b/car-lib/src/android/car/telemetry/ICarTelemetryReportListener.aidl
@@ -31,13 +31,13 @@
* The parameter will no longer be stored in {@code CarTelemetryService}.
*
* @param metricsConfigName the metrics config name that the report is associated with.
- * @param report script execution report.
+ * @param reportFileDescriptor the metrics reports can be read from this fd.
* @param telemetryError the serialized bytes of the telemetry error object.
* @param status of the metrics report.
*/
void onResult(
in String metricsConfigName,
- in PersistableBundle report,
+ in ParcelFileDescriptor reportFileDescriptor,
in byte[] telemetryError,
in int status);
}
\ No newline at end of file
diff --git a/car-lib/src/android/car/telemetry/telemetry.proto b/car-lib/src/android/car/telemetry/telemetry.proto
index ddb4c2d..48b4c77 100644
--- a/car-lib/src/android/car/telemetry/telemetry.proto
+++ b/car-lib/src/android/car/telemetry/telemetry.proto
@@ -161,9 +161,11 @@
// Specifies publisher with its parameters and the handler function that's invoked
// when data is received. The format of the data depends on the Publisher.
message Subscriber {
- // Required.
+ // Optional.
// Name of the function that handles the published data. Must be defined
// in the script.
+ // Leaving the field unset signals that the data from the specified publisher
+ // should bypass ScriptExecutor and be uploaded directly in its original form.
optional string handler = 1;
// Required.
diff --git a/car-lib/src/android/car/user/CarUserManager.java b/car-lib/src/android/car/user/CarUserManager.java
index 7c604c5..9effc85 100644
--- a/car-lib/src/android/car/user/CarUserManager.java
+++ b/car-lib/src/android/car/user/CarUserManager.java
@@ -35,6 +35,7 @@
import android.car.ICarResultReceiver;
import android.car.ICarUserService;
import android.car.annotation.AddedInOrBefore;
+import android.car.annotation.ApiRequirements;
import android.car.builtin.os.UserManagerHelper;
import android.car.builtin.util.EventLogHelper;
import android.car.util.concurrent.AndroidAsyncFuture;
@@ -193,6 +194,28 @@
public static final int USER_LIFECYCLE_EVENT_TYPE_STOPPED =
CommonConstants.USER_LIFECYCLE_EVENT_TYPE_STOPPED;
+ /**
+ * {@link UserLifecycleEvent} called after an existing user is created.
+ *
+ * @hide
+ */
+ @SystemApi
+ @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_1,
+ minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_1)
+ public static final int USER_LIFECYCLE_EVENT_TYPE_CREATED =
+ CommonConstants.USER_LIFECYCLE_EVENT_TYPE_CREATED;
+
+ /**
+ * {@link UserLifecycleEvent} called after an existing user is removed.
+ *
+ * @hide
+ */
+ @SystemApi
+ @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_1,
+ minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_1)
+ public static final int USER_LIFECYCLE_EVENT_TYPE_REMOVED =
+ CommonConstants.USER_LIFECYCLE_EVENT_TYPE_REMOVED;
+
/** @hide */
@AddedInOrBefore(majorVersion = 33)
public static final String BUNDLE_PARAM_ACTION = "action";
@@ -997,6 +1020,12 @@
return "STOPPING";
case USER_LIFECYCLE_EVENT_TYPE_STOPPED:
return "STOPPED";
+ case USER_LIFECYCLE_EVENT_TYPE_POST_UNLOCKED:
+ return "POST_UNLOCKED";
+ case USER_LIFECYCLE_EVENT_TYPE_CREATED:
+ return "CREATED";
+ case USER_LIFECYCLE_EVENT_TYPE_REMOVED:
+ return "REMOVED";
default:
return "UNKNOWN-" + type;
}
@@ -1063,8 +1092,14 @@
* {@link CarUserManager#USER_LIFECYCLE_EVENT_TYPE_SWITCHING},
* {@link CarUserManager#USER_LIFECYCLE_EVENT_TYPE_UNLOCKING},
* {@link CarUserManager#USER_LIFECYCLE_EVENT_TYPE_UNLOCKED},
- * {@link CarUserManager#USER_LIFECYCLE_EVENT_TYPE_STOPPING}, or
- * {@link CarUserManager#USER_LIFECYCLE_EVENT_TYPE_STOPPED}.
+ * {@link CarUserManager#USER_LIFECYCLE_EVENT_TYPE_STOPPING} or
+ * {@link CarUserManager#USER_LIFECYCLE_EVENT_TYPE_STOPPED} for all apps;
+ * for apps {@link CarPackageManager#getTargetCarVersion() targeting car version}
+ * {@link CarVersion.VERSION_CODES#TIRAMISU_1} or higher, it could be new types
+ * added on later releases, such as
+ * {@link CarUserManager#USER_LIFECYCLE_EVENT_TYPE_CREATED},
+ * {@link CarUserManager#USER_LIFECYCLE_EVENT_TYPE_REMOVED} and possibly others.
+ *
*/
@UserLifecycleEventType
@AddedInOrBefore(majorVersion = 33)
diff --git a/car-lib/src/com/android/car/internal/CarPropertyEventCallbackController.java b/car-lib/src/com/android/car/internal/CarPropertyEventCallbackController.java
new file mode 100644
index 0000000..1510884
--- /dev/null
+++ b/car-lib/src/com/android/car/internal/CarPropertyEventCallbackController.java
@@ -0,0 +1,259 @@
+/*
+ * Copyright (C) 2022 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.internal;
+
+import static java.util.Objects.requireNonNull;
+
+import android.annotation.Nullable;
+import android.car.VehiclePropertyIds;
+import android.car.hardware.CarPropertyValue;
+import android.car.hardware.property.CarPropertyEvent;
+import android.car.hardware.property.CarPropertyManager.CarPropertyEventCallback;
+import android.util.ArrayMap;
+import android.util.Log;
+import android.util.SparseLongArray;
+
+import com.android.internal.annotations.GuardedBy;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+
+/**
+ * Manages a group of {@link CarPropertyEventCallback} instances registered for the same {@link
+ * #mPropertyId} at possibly different update rates.
+ *
+ * @hide
+ */
+public final class CarPropertyEventCallbackController {
+ // Abbreviating TAG because class name is longer than the 23 character Log tag limit.
+ private static final String TAG = "CPECallbackController";
+ private static final boolean DBG = Log.isLoggable(TAG, Log.DEBUG);
+ private static final float NANOSECOND_PER_SECOND = 1000 * 1000 * 1000;
+ // Since this class is internal to CarPropertyManager, it shares the same lock to avoid
+ // potential deadlock.
+ private final Object mCarPropertyManagerLock;
+ @GuardedBy("mCarPropertyManagerLock")
+ private final Map<CarPropertyEventCallback, Float> mCarPropertyEventCallbackToUpdateRateHz =
+ new ArrayMap<>();
+ @GuardedBy("mCarPropertyManagerLock")
+ private final Map<CarPropertyEventCallback, SparseLongArray>
+ mCarPropertyEventCallbackToAreaIdToNextUpdateTimeNanos = new ArrayMap<>();
+ private final int mPropertyId;
+ private final RegistrationUpdateCallback mRegistrationUpdateCallback;
+ @GuardedBy("mCarPropertyManagerLock")
+ private Float mMaxUpdateRateHz = null;
+
+ public CarPropertyEventCallbackController(int propertyId, Object carPropertyManagerLock,
+ RegistrationUpdateCallback registrationUpdateCallback) {
+ requireNonNull(registrationUpdateCallback);
+ mPropertyId = propertyId;
+ mCarPropertyManagerLock = carPropertyManagerLock;
+ mRegistrationUpdateCallback = registrationUpdateCallback;
+ }
+
+ /**
+ * Forward a successful {@link CarPropertyEvent} to the registered {@link
+ * CarPropertyEventCallback} instances if the {@link CarPropertyEventCallback} instance's update
+ * rate threshold is met.
+ */
+ public void forwardPropertyChanged(CarPropertyEvent carPropertyEvent) {
+ requireNonNull(carPropertyEvent);
+ List<CarPropertyEventCallback> carPropertyEventCallbacks = getCallbacksForCarPropertyEvent(
+ carPropertyEvent);
+ CarPropertyValue<?> carPropertyValue = carPropertyEvent.getCarPropertyValue();
+ for (int i = 0; i < carPropertyEventCallbacks.size(); i++) {
+ carPropertyEventCallbacks.get(i).onChangeEvent(carPropertyValue);
+ }
+ }
+
+ /**
+ * Forward an error {@link CarPropertyEvent} to the registered {@link CarPropertyEventCallback}
+ * instances.
+ */
+ public void forwardErrorEvent(CarPropertyEvent carPropertyEvent) {
+ requireNonNull(carPropertyEvent);
+ CarPropertyValue<?> carPropertyValue = carPropertyEvent.getCarPropertyValue();
+ if (DBG) {
+ Log.d(TAG, "onErrorEvent for property: " + VehiclePropertyIds.toString(
+ carPropertyValue.getPropertyId()) + " areaId: " + carPropertyValue.getAreaId()
+ + " errorCode: " + carPropertyEvent.getErrorCode());
+ }
+ List<CarPropertyEventCallback> carPropertyEventCallbacks;
+ synchronized (mCarPropertyManagerLock) {
+ carPropertyEventCallbacks = new ArrayList<>(
+ mCarPropertyEventCallbackToUpdateRateHz.keySet());
+ }
+ for (int i = 0; i < carPropertyEventCallbacks.size(); i++) {
+ carPropertyEventCallbacks.get(i).onErrorEvent(carPropertyValue.getPropertyId(),
+ carPropertyValue.getAreaId(), carPropertyEvent.getErrorCode());
+
+ }
+ }
+
+ /**
+ * Add given {@link CarPropertyEventCallback} to the list and update registration if necessary.
+ *
+ * @return true is registration was successful, otherwise false.
+ */
+ public boolean add(CarPropertyEventCallback carPropertyEventCallback, float updateRateHz) {
+ requireNonNull(carPropertyEventCallback);
+ Float previousUpdateRateHz;
+ SparseLongArray previousAreaIdToNextUpdateTimeNanos;
+ synchronized (mCarPropertyManagerLock) {
+ previousUpdateRateHz = mCarPropertyEventCallbackToUpdateRateHz.put(
+ carPropertyEventCallback, updateRateHz);
+ previousAreaIdToNextUpdateTimeNanos =
+ mCarPropertyEventCallbackToAreaIdToNextUpdateTimeNanos.put(
+ carPropertyEventCallback, new SparseLongArray());
+ }
+ boolean registerSuccessful = updateMaxUpdateRateHzAndRegistration();
+ if (!registerSuccessful) {
+ synchronized (mCarPropertyManagerLock) {
+ if (previousUpdateRateHz != null && previousAreaIdToNextUpdateTimeNanos != null) {
+ mCarPropertyEventCallbackToUpdateRateHz.put(carPropertyEventCallback,
+ previousUpdateRateHz);
+ mCarPropertyEventCallbackToAreaIdToNextUpdateTimeNanos.put(
+ carPropertyEventCallback, previousAreaIdToNextUpdateTimeNanos);
+ } else {
+ mCarPropertyEventCallbackToUpdateRateHz.remove(carPropertyEventCallback);
+ mCarPropertyEventCallbackToAreaIdToNextUpdateTimeNanos.remove(
+ carPropertyEventCallback);
+ }
+ mMaxUpdateRateHz = calculateMaxUpdateRateHzLocked();
+ }
+ }
+ return registerSuccessful;
+ }
+
+ /**
+ * Remove given {@link CarPropertyEventCallback} from the list and update registration if
+ * necessary.
+ *
+ * @return true if all {@link CarPropertyEventCallback} instances are removed, otherwise false.
+ */
+ public boolean remove(CarPropertyEventCallback carPropertyEventCallback) {
+ requireNonNull(carPropertyEventCallback);
+ synchronized (mCarPropertyManagerLock) {
+ mCarPropertyEventCallbackToUpdateRateHz.remove(carPropertyEventCallback);
+ mCarPropertyEventCallbackToAreaIdToNextUpdateTimeNanos.remove(carPropertyEventCallback);
+ }
+ updateMaxUpdateRateHzAndRegistration();
+ synchronized (mCarPropertyManagerLock) {
+ return mCarPropertyEventCallbackToUpdateRateHz.isEmpty();
+ }
+ }
+
+
+ private List<CarPropertyEventCallback> getCallbacksForCarPropertyEvent(
+ CarPropertyEvent carPropertyEvent) {
+ List<CarPropertyEventCallback> carPropertyEventCallbacks = new ArrayList<>();
+ synchronized (mCarPropertyManagerLock) {
+ for (CarPropertyEventCallback carPropertyEventCallback :
+ mCarPropertyEventCallbackToUpdateRateHz.keySet()) {
+ if (shouldCallbackBeInvokedLocked(carPropertyEventCallback, carPropertyEvent)) {
+ carPropertyEventCallbacks.add(carPropertyEventCallback);
+ }
+ }
+ }
+ return carPropertyEventCallbacks;
+ }
+
+ @GuardedBy("mCarPropertyManagerLock")
+ private boolean shouldCallbackBeInvokedLocked(CarPropertyEventCallback carPropertyEventCallback,
+ CarPropertyEvent carPropertyEvent) {
+ SparseLongArray areaIdToNextUpdateTimeNanos =
+ mCarPropertyEventCallbackToAreaIdToNextUpdateTimeNanos.get(
+ carPropertyEventCallback);
+ Float updateRateHz = mCarPropertyEventCallbackToUpdateRateHz.get(carPropertyEventCallback);
+ if (areaIdToNextUpdateTimeNanos == null || updateRateHz == null) {
+ CarPropertyValue<?> carPropertyValue = carPropertyEvent.getCarPropertyValue();
+ Log.w(TAG, "callback was not found for property: " + VehiclePropertyIds.toString(
+ carPropertyValue.getPropertyId()) + " areaId: " + carPropertyValue.getAreaId()
+ + " timestampNanos: " + carPropertyValue.getTimestamp());
+ return false;
+ }
+
+ CarPropertyValue<?> carPropertyValue = carPropertyEvent.getCarPropertyValue();
+ long nextUpdateTimeNanos = areaIdToNextUpdateTimeNanos.get(carPropertyValue.getAreaId(),
+ 0L);
+
+ if (carPropertyValue.getTimestamp() >= nextUpdateTimeNanos) {
+ long updatePeriodNanos =
+ updateRateHz > 0 ? ((long) ((1.0 / updateRateHz) * NANOSECOND_PER_SECOND)) : 0;
+ areaIdToNextUpdateTimeNanos.put(carPropertyValue.getAreaId(),
+ carPropertyValue.getTimestamp() + updatePeriodNanos);
+ mCarPropertyEventCallbackToAreaIdToNextUpdateTimeNanos.put(carPropertyEventCallback,
+ areaIdToNextUpdateTimeNanos);
+ return true;
+ }
+
+ if (DBG) {
+ Log.d(TAG, "Dropping carPropertyEvent - propId: " + carPropertyValue.getPropertyId()
+ + " areaId: " + carPropertyValue.getAreaId() + " because getTimestamp(): "
+ + carPropertyValue.getTimestamp() + " < nextUpdateTimeNanos: "
+ + nextUpdateTimeNanos);
+ }
+ return false;
+ }
+
+ private boolean updateMaxUpdateRateHzAndRegistration() {
+ Float newMaxUpdateRateHz;
+ synchronized (mCarPropertyManagerLock) {
+ newMaxUpdateRateHz = calculateMaxUpdateRateHzLocked();
+ if (Objects.equals(mMaxUpdateRateHz, newMaxUpdateRateHz)) {
+ return true;
+ }
+ mMaxUpdateRateHz = newMaxUpdateRateHz;
+ }
+ if (newMaxUpdateRateHz == null) {
+ mRegistrationUpdateCallback.unregister(mPropertyId);
+ return true;
+ }
+ return mRegistrationUpdateCallback.register(mPropertyId, newMaxUpdateRateHz);
+ }
+
+ @GuardedBy("mCarPropertyManagerLock")
+ @Nullable
+ private Float calculateMaxUpdateRateHzLocked() {
+ if (mCarPropertyEventCallbackToUpdateRateHz.isEmpty()) {
+ return null;
+ }
+ return Collections.max(mCarPropertyEventCallbackToUpdateRateHz.values());
+ }
+
+ /**
+ * Interface that receives updates to register or unregister property with {@link
+ * com.android.car.CarPropertyService}.
+ */
+ public interface RegistrationUpdateCallback {
+ /**
+ * Called when {@code propertyId} registration needs to be updated.
+ *
+ * @return true is registration was successful, otherwise false.
+ */
+ boolean register(int propertyId, float updateRateHz);
+
+ /**
+ * Called when {@code propertyId} needs to be unregistered.
+ */
+ void unregister(int propertyId);
+ }
+}
+
diff --git a/car-lib/src/com/android/car/internal/CarRatedFloatListeners.java b/car-lib/src/com/android/car/internal/CarRatedFloatListeners.java
deleted file mode 100644
index 2c6c95a..0000000
--- a/car-lib/src/com/android/car/internal/CarRatedFloatListeners.java
+++ /dev/null
@@ -1,151 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.car.internal;
-
-import android.util.SparseArray;
-
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Map;
-
-/**
- * Represent listeners for a property grouped by their rate.
- * T is a type of EventListener such as CarPropertyEventCallback
- * in {@link android.car.hardware.property.CarPropertyManager}
- * @param <T>
- * @hide
- */
-public class CarRatedFloatListeners<T> {
- private static final float NANOSECOND_PER_SECOND = 1000 * 1000 * 1000;
- private final Map<T, Float> mListenersToRate = new HashMap<>(4);
-
- private final Map<T, Long> mListenersUpdateTime = new HashMap<>(4);
-
- private float mUpdateRate;
-
- // key: areaId, value: lastUpdateTime in nanosecond
- protected SparseArray<Long> mAreaIdToLastUpdateTime = new SparseArray<>();
-
- protected CarRatedFloatListeners(float rate) {
- mUpdateRate = rate;
- }
-
- /** Check listener */
- public boolean contains(T listener) {
- return mListenersToRate.containsKey(listener);
- }
- /** Return current rate after updating */
- public float getRate() {
- return mUpdateRate;
- }
-
- /**
- * Remove given listener from the list and update rate if necessary.
- *
- * @param listener
- * @return true if rate was updated. Otherwise, returns false.
- */
- public boolean remove(T listener) {
- mListenersToRate.remove(listener);
- mListenersUpdateTime.remove(listener);
- if (mListenersToRate.isEmpty()) {
- return false;
- }
- Float updateRate = Collections.max(mListenersToRate.values());
- if (updateRate != mUpdateRate) {
- mUpdateRate = updateRate;
- return true;
- }
- return false;
- }
-
- public boolean isEmpty() {
- return mListenersToRate.isEmpty();
- }
-
- /**
- * Add given listener to the list and update rate if necessary.
- *
- * @param listener if null, add part is skipped.
- * @param updateRate
- * @return true if rate was updated. Otherwise, returns false.
- */
- public boolean addAndUpdateRate(T listener, float updateRate) {
- Float oldUpdateRate = mListenersToRate.put(listener, updateRate);
- mListenersUpdateTime.put(listener, 0L);
- if (mUpdateRate < updateRate) {
- mUpdateRate = updateRate;
- return true;
- } else if (oldUpdateRate != null && oldUpdateRate == mUpdateRate) {
- Float newUpdateRate = Collections.max(mListenersToRate.values());
- if (newUpdateRate != mUpdateRate) {
- mUpdateRate = newUpdateRate;
- return true;
- }
- }
- return false;
- }
-
- /**
- * Check whether listener should be notified by events.
- *
- * @param listener
- * @param eventTimeStamp
- * @return true if listener need to be notified.
- */
- public boolean needUpdateForSelectedListener(T listener, long eventTimeStamp) {
- Long nextUpdateTime = mListenersUpdateTime.get(listener);
- Float updateRate = mListenersToRate.get(listener);
- // Can not find listener in maps.
- if (nextUpdateTime == null || updateRate == null) {
- return false;
- }
-
- /** Update ON_CHANGE property. */
- if (updateRate == 0) {
- return true;
- }
- if (nextUpdateTime <= eventTimeStamp) {
- Float cycle = NANOSECOND_PER_SECOND / updateRate;
- nextUpdateTime = eventTimeStamp + cycle.longValue();
- mListenersUpdateTime.put(listener, nextUpdateTime);
- return true;
- }
- return false;
- }
-
- /**
- * @param areaId AreaId in CarPropertyValue
- * @param eventTime TimeStamp in CarPropertyValue
- * @return true if eventTime is greater than the last event time for the same areaId.
- */
- public boolean needUpdateForAreaId(int areaId, long eventTime) {
- long lastUpdateTime = mAreaIdToLastUpdateTime.get(areaId, 0L);
- if (eventTime >= lastUpdateTime) {
- mAreaIdToLastUpdateTime.put(areaId, eventTime);
- return true;
- }
- return false;
- }
-
-
- public Collection<T> getListeners() {
- return mListenersToRate.keySet();
- }
-}
-
diff --git a/car-lib/src/com/android/car/internal/common/CommonConstants.java b/car-lib/src/com/android/car/internal/common/CommonConstants.java
index 2c808f4..c19cbb5 100644
--- a/car-lib/src/com/android/car/internal/common/CommonConstants.java
+++ b/car-lib/src/com/android/car/internal/common/CommonConstants.java
@@ -46,6 +46,8 @@
public static final int USER_LIFECYCLE_EVENT_TYPE_STOPPING = 5;
public static final int USER_LIFECYCLE_EVENT_TYPE_STOPPED = 6;
public static final int USER_LIFECYCLE_EVENT_TYPE_POST_UNLOCKED = 7;
+ public static final int USER_LIFECYCLE_EVENT_TYPE_CREATED = 8;
+ public static final int USER_LIFECYCLE_EVENT_TYPE_REMOVED = 9;
// CarService Constants
public static final String CAR_SERVICE_INTERFACE = "android.car.ICar";
@@ -58,6 +60,8 @@
USER_LIFECYCLE_EVENT_TYPE_STOPPING,
USER_LIFECYCLE_EVENT_TYPE_STOPPED,
USER_LIFECYCLE_EVENT_TYPE_POST_UNLOCKED,
+ USER_LIFECYCLE_EVENT_TYPE_CREATED,
+ USER_LIFECYCLE_EVENT_TYPE_REMOVED,
})
@Retention(RetentionPolicy.SOURCE)
public @interface UserLifecycleEventType{}
diff --git a/car-lib/src/com/android/car/internal/util/VersionUtils.java b/car-lib/src/com/android/car/internal/util/VersionUtils.java
new file mode 100644
index 0000000..c50b431
--- /dev/null
+++ b/car-lib/src/com/android/car/internal/util/VersionUtils.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2022 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.internal.util;
+
+import android.car.Car;
+import android.car.PlatformVersion;
+import android.car.PlatformVersionMismatchException;
+
+/**
+ * Utility class for platform and car API version check.
+ *
+ * @hide
+ */
+public final class VersionUtils {
+
+ /**
+ * Asserts if the current platform version is at least expected platform version.
+ *
+ * @throws PlatformVersionMismatchException if current platform version is not equal to or
+ * greater than expected platform version.
+ */
+ public static void assertPlatformVersionAtLeast(PlatformVersion expectedPlatformApiVersion) {
+ PlatformVersion currentPlatformVersion = Car.getPlatformVersion();
+ if (!currentPlatformVersion.isAtLeast(expectedPlatformApiVersion)) {
+ throw new PlatformVersionMismatchException(expectedPlatformApiVersion);
+ }
+ }
+
+ /**
+ * Checks if the current platform version is at least expected platform version.
+ */
+ public static boolean isPlatformVersionAtLeast(PlatformVersion expectedPlatformVersion) {
+ PlatformVersion currentPlatformVersion = Car.getPlatformVersion();
+ return currentPlatformVersion.isAtLeast(expectedPlatformVersion);
+ }
+
+ private VersionUtils() {
+ throw new UnsupportedOperationException("contains only static method methods");
+ }
+}
diff --git a/car-maps-placeholder/res/values-or/strings.xml b/car-maps-placeholder/res/values-or/strings.xml
index 09fa691..286fb8a 100644
--- a/car-maps-placeholder/res/values-or/strings.xml
+++ b/car-maps-placeholder/res/values-or/strings.xml
@@ -17,5 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_name" msgid="6575346965016311017">"Maps"</string>
- <string name="error_text" msgid="5575174711944349180">"କୌଣସି ମ୍ୟାପ୍ସ ଆପ୍ଲିକେସନ ଇନଷ୍ଟଲ କରାଯାଇନାହିଁ। ଆପଣଙ୍କ କାରର ଉତ୍ପାଦକଙ୍କ ସହ କଣ୍ଟାକ୍ଟ କରନ୍ତୁ।"</string>
+ <string name="error_text" msgid="5575174711944349180">"କୌଣସି ମ୍ୟାପ୍ସ ଆପ୍ଲିକେସନ୍ ଇନ୍ଷ୍ଟଲ୍ କରାଯାଇନାହିଁ। ଆପଣଙ୍କ କାର୍ର ଉତ୍ପାଦକଙ୍କ ସହ ଯୋଗାଯୋଗ କରନ୍ତୁ।"</string>
</resources>
diff --git a/car-test-lib/src/android/car/test/AbstractExpectableTestCase.java b/car-test-lib/src/android/car/test/AbstractExpectableTestCase.java
new file mode 100644
index 0000000..c2e5583
--- /dev/null
+++ b/car-test-lib/src/android/car/test/AbstractExpectableTestCase.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2022 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.test;
+
+import com.google.common.truth.BooleanSubject;
+import com.google.common.truth.Expect;
+import com.google.common.truth.StandardSubjectBuilder;
+
+import org.junit.Rule;
+
+// NOTE: it could be a more generic AbstractTruthTestCase that provide similar methods
+// for assertThat() / assertWithMessage(), but then we'd need to remove all static import imports
+// from classes that indirectly extend it.
+/**
+ * Base class to make it easier to use {@code Truth} {@link Expect} assertions.
+ */
+public abstract class AbstractExpectableTestCase {
+
+ @Rule
+ public final Expect mExpect = Expect.create();
+
+ protected final StandardSubjectBuilder expectWithMessage(String msg) {
+ return mExpect.withMessage(msg);
+ }
+
+ protected final StandardSubjectBuilder expectWithMessage(String format, Object...args) {
+ return mExpect.withMessage(format, args);
+ }
+
+ // NOTE: Expect has dozens of that() methods; the'll be added "on demand".
+
+ protected final BooleanSubject expectThat(Boolean actual) {
+ return mExpect.that(actual);
+ }
+}
diff --git a/car-test-lib/src/android/car/test/ApiCheckerRule.java b/car-test-lib/src/android/car/test/ApiCheckerRule.java
new file mode 100644
index 0000000..8536610
--- /dev/null
+++ b/car-test-lib/src/android/car/test/ApiCheckerRule.java
@@ -0,0 +1,816 @@
+/*
+ * Copyright (C) 2022 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.test;
+
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.ElementType.TYPE;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+import android.annotation.Nullable;
+import android.car.Car;
+import android.car.CarVersion;
+import android.car.PlatformVersion;
+import android.car.PlatformVersionMismatchException;
+import android.car.annotation.AddedInOrBefore;
+import android.car.annotation.ApiRequirements;
+import android.car.test.ApiCheckerRule.UnsupportedVersionTest.Behavior;
+import android.text.TextUtils;
+import android.util.Log;
+import android.util.Pair;
+
+import com.android.compatibility.common.util.ApiTest;
+import com.android.compatibility.common.util.CddTest;
+
+import org.junit.AssumptionViolatedException;
+import org.junit.rules.TestRule;
+import org.junit.runner.Description;
+import org.junit.runners.model.Statement;
+
+import java.lang.annotation.Annotation;
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+import java.lang.reflect.Field;
+import java.lang.reflect.Member;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * Rule used to validate Car API requirements on CTS tests.
+ *
+ * <p>This rule is used to verify that all tests in a class:
+ *
+ * <ol>
+ * <li>Indicate which API / CDD is being tested.
+ * <li>Properly behave on supported and unsupported versions.
+ * </ol>
+ *
+ * <p>For the former, the test must be annoted with either {@link ApiTest} or {@link CddTest} (in
+ * which case it also need to be annotated with {@link ApiRequirements}, otherwise the test will
+ * fail (unless the rule was created with {@link Builder#disableAnnotationsCheck()}. An in the case
+ * of {@link ApiTest}, the rule will also asser that the underlying APIs are annotated with either
+ * {@link ApiRequirements} or {@link AddedInOrBefore}.
+ *
+ * <p>For the latter, if the API declares {@link ApiRequirements}, the rule by default will make
+ * sure the test behaves properly in the supported and unsupported platform versions:
+ * <ol>
+ * <li>If the platform is supported, the test shold pass as usual.
+ * <li>If the platform is not supported, the rule will assert that the test throws a
+ * {@link PlatformVersionMismatchException}.
+ * </ol>
+ *
+ * <p>There are corner cases where the default rule behavior cannot be applied for the test, like:
+ * <ol>
+ * <li>The test logic is too complex (or takes time) and should be simplified when running on
+ * unsupported versions.
+ * <li>The API being tested should behave different on supported or unsupported versions.
+ * </ol>
+ *
+ * <p>In these cases, the test should be split in 2 tests, one for the supported version and another
+ * for the unsupported version, and annotated with {@link SupportedVersionTest} or
+ * {@link UnsupportedVersionTest} respectively; these tests <b>MUST</b> be provided in pair (in
+ * fact, these annotations take an argument pointing to the pair) and they will behave this way:
+ *
+ * <ol>
+ * <li>{@link SupportedVersionTest}: should pass on supported platform and will be ignored on
+ * unsupported platforms (by throwing an {@link ExpectedVersionAssumptionViolationException}).
+ * <li>{@link UnsupportedVersionTest}: by default, it will be ignored on supported platforms
+ * (by throwing an {@link ExpectedVersionAssumptionViolationException}), but can be changed
+ * to run on unsupported platforms as well (by setting its
+ * {@link UnsupportedVersionTest#behavior()} to {@link Behavior#EXPECT_PASS}.
+ * </ol>
+ *
+ * <p>So, back to the examples above, the tests would be:
+ * <pre><code>
+
+ @Test
+ @ApiTest(apis = {"com.acme.Car#foo"})
+ @SupportedVersionTest(unsupportedVersionTest="testFoo_unsupported")
+ public void testFoo_supported() {
+ baz(); // takes a long time
+ foo();
+ }
+
+ @Test
+ @ApiTest(apis = {"com.acme.Car#foo"})
+ @UnsupportedVersionTest(supportedVersionTest="testFoo_supported")
+ public void testFoo_unsupported() {
+ foo(); // should throw PlatformViolationException
+ }
+
+ @Test
+ @ApiTest(apis = {"com.acme.Car#bar"})
+ @SupportedVersionTest(unsupportedVersionTest="testBar_unsupported")
+ public void testBar_supported() {
+ assertWithMessage("bar()").that(bar()).isEqualTo("BehaviorOnSupportedPlatform");
+ }
+
+ @Test
+ @ApiTest(apis = {"com.acme.Car#bar"})
+ @UnsupportedVersionTest(supportedVersionTest="testBar_supported", behavior=EXPECT_PASS)
+ public void testFoo_unsupported() {
+ assertWithMessage("bar()").that(bar()).isEqualTo("BehaviorOnUnsupportedPlatform");
+ }
+
+ * </code></pre>
+ */
+public final class ApiCheckerRule implements TestRule {
+
+ public static final String TAG = ApiCheckerRule.class.getSimpleName();
+
+ private static final boolean DBG = Log.isLoggable(TAG, Log.DEBUG);
+
+ private final boolean mEnforceTestApiAnnotations;
+
+ /**
+ * Builder.
+ */
+ public static final class Builder {
+ private boolean mEnforceTestApiAnnotations = true;
+
+ /**
+ * Creates a new rule.
+ */
+ public ApiCheckerRule build() {
+ return new ApiCheckerRule(this);
+ }
+
+ /**
+ * Don't fail the test if the required annotations (like {@link ApiTest}) are missing.
+ */
+ public Builder disableAnnotationsCheck() {
+ mEnforceTestApiAnnotations = false;
+ return this;
+ }
+ }
+
+ private ApiCheckerRule(Builder builder) {
+ mEnforceTestApiAnnotations = builder.mEnforceTestApiAnnotations;
+ }
+
+ /**
+ * Checks whether the test is running in an environment that supports the given API.
+ *
+ * @param api API as defined by {@link ApiTest}.
+ * @return whether the test is running in an environment that supports the
+ * {@link ApiRequirements} defined in such API.
+ */
+ public boolean isApiSupported(String api) {
+ ApiRequirements apiRequirements = getApiRequirements(api);
+
+ if (apiRequirements == null) {
+ throw new IllegalArgumentException("No @ApiRequirements on " + api);
+ }
+
+ return isSupported(apiRequirements);
+ }
+
+ private boolean isSupported(ApiRequirements apiRequirements) {
+ PlatformVersion platformVersion = Car.getPlatformVersion();
+ boolean isSupported = platformVersion
+ .isAtLeast(apiRequirements.minPlatformVersion().get());
+ if (DBG) {
+ Log.d(TAG, "isSupported(" + apiRequirements + "): platformVersion=" + platformVersion
+ + ",supported=" + isSupported);
+ }
+ return isSupported;
+ }
+
+ private static ApiRequirements getApiRequirements(String api) {
+ Member member = ApiHelper.resolve(api);
+ if (member == null) {
+ throw new IllegalArgumentException("API not found: " + api);
+ }
+ return getApiRequirements(member);
+ }
+
+ private static ApiRequirements getApiRequirements(Member member) {
+ return getAnnotation(ApiRequirements.class, member);
+ }
+
+ @SuppressWarnings("deprecation")
+ private static AddedInOrBefore getAddedInOrBefore(Member member) {
+ return getAnnotation(AddedInOrBefore.class, member);
+ }
+
+ private static <T extends Annotation> T getAnnotation(Class<T> annotationClass, Member member) {
+ if (member instanceof Field) {
+ return ((Field) member).getAnnotation(annotationClass);
+ }
+ if (member instanceof Method) {
+ return ((Method) member).getAnnotation(annotationClass);
+ }
+ throw new UnsupportedOperationException("Invalid member type for API: " + member);
+ }
+
+ @Override
+ public Statement apply(Statement base, Description description) {
+ return new Statement() {
+ @Override
+ public void evaluate() throws Throwable {
+ if (DBG) {
+ Log.d(TAG, "evaluating " + description.getDisplayName());
+ }
+
+ // Variables below are used to validate that all ApiRequirements are compatible
+ ApiTest apiTest = null;
+ ApiRequirements apiRequirementsOnApiUnderTest = null;
+ IgnoreInvalidApi ignoreInvalidApi = null;
+
+ // Optional annotations that change the behavior of the rule
+ SupportedVersionTest supportedVersionTest = null;
+ UnsupportedVersionTest unsupportedVersionTest = null;
+
+ // Other relevant annotations
+ @SuppressWarnings("deprecation")
+ AddedInOrBefore addedInOrBefore = null;
+ CddTest cddTest = null;
+ ApiRequirements apiRequirementsOnTest = null; // user only with CddTest
+ ApiRequirements effectiveApiRequirementsOnTest = null;
+
+ for (Annotation annotation : description.getAnnotations()) {
+ if (DBG) {
+ Log.d(TAG, "Annotation: " + annotation);
+ }
+ if (annotation instanceof ApiTest) {
+ apiTest = (ApiTest) annotation;
+ continue;
+ }
+ if (annotation instanceof ApiRequirements) {
+ apiRequirementsOnTest = (ApiRequirements) annotation;
+ continue;
+ }
+ if (annotation instanceof CddTest) {
+ cddTest = (CddTest) annotation;
+ continue;
+ }
+ if (annotation instanceof SupportedVersionTest) {
+ supportedVersionTest = (SupportedVersionTest) annotation;
+ continue;
+ }
+ if (annotation instanceof UnsupportedVersionTest) {
+ unsupportedVersionTest = (UnsupportedVersionTest) annotation;
+ continue;
+ }
+ if (annotation instanceof IgnoreInvalidApi) {
+ ignoreInvalidApi = (IgnoreInvalidApi) annotation;
+ continue;
+ }
+ }
+
+ if (DBG) {
+ Log.d(TAG, "Relevant annotations on test: "
+ + "ApiTest=" + apiTest
+ + " CddTest=" + cddTest
+ + " ApiRequirements=" + apiRequirementsOnTest
+ + " SupportedVersionTest=" + supportedVersionTest
+ + " UnsupportedVersionTest=" + unsupportedVersionTest
+ + " IgnoreInvalidApi=" + ignoreInvalidApi);
+ }
+
+ validateOptionalAnnotations(description.getTestClass(), description.getMethodName(),
+ supportedVersionTest, unsupportedVersionTest);
+
+ if (apiTest == null && cddTest != null) {
+ validateCddAnnotations(cddTest, apiRequirementsOnTest);
+ effectiveApiRequirementsOnTest = apiRequirementsOnTest;
+ }
+
+ if (apiTest == null && cddTest == null) {
+ if (mEnforceTestApiAnnotations) {
+ throw new IllegalArgumentException("Test is missing @ApiTest or @CddTest "
+ + "annotation");
+ } else {
+ Log.w(TAG, "Test " + description + " doesn't have @ApiTest or @CddTest,"
+ + "but rule is not enforcing it");
+ }
+ }
+
+ if (apiTest != null) {
+ Pair<ApiRequirements, AddedInOrBefore> pair = getApiRequirementsFromApis(
+ description, apiTest, ignoreInvalidApi);
+ apiRequirementsOnApiUnderTest = pair.first;
+ if (effectiveApiRequirementsOnTest == null) {
+ // not set by CddTest
+ effectiveApiRequirementsOnTest = apiRequirementsOnApiUnderTest;
+ }
+ if (effectiveApiRequirementsOnTest == null && ignoreInvalidApi != null) {
+ effectiveApiRequirementsOnTest = apiRequirementsOnTest;
+ }
+ addedInOrBefore = pair.second;
+ }
+
+ if (DBG) {
+ Log.d(TAG, "Relevant annotations on APIs: "
+ + "ApiRequirements=" + apiRequirementsOnApiUnderTest
+ + ", AddedInOrBefore: " + addedInOrBefore);
+ }
+
+ if (apiRequirementsOnApiUnderTest != null && apiRequirementsOnTest != null) {
+ throw new IllegalArgumentException("Test cannot be annotated with both "
+ + "@ApiTest and @ApiRequirements");
+ }
+
+ if (effectiveApiRequirementsOnTest == null) {
+ if (ignoreInvalidApi != null) {
+ if (mEnforceTestApiAnnotations) {
+ throw new IllegalArgumentException("Test contains @IgnoreInvalidApi but"
+ + " is missing @ApiRequirements");
+ } else {
+ Log.w(TAG, "Test " + description + " contains @IgnoreInvalidApi and is "
+ + "missing @ApiRequirements, but rule is not enforcing them");
+ }
+ } else if (addedInOrBefore == null) {
+ if (mEnforceTestApiAnnotations) {
+ throw new IllegalArgumentException("Missing @ApiRequirements "
+ + "or @AddedInOrBefore");
+ } else {
+ Log.w(TAG, "Test " + description + " doesn't have required "
+ + "@ApiRequirements or @AddedInOrBefore but rule is not "
+ + "enforcing them");
+ }
+ }
+ base.evaluate();
+ return;
+ }
+
+ // Finally, run the test and assert results depending on whether it's supported or
+ // not
+ apply(base, description, effectiveApiRequirementsOnTest, supportedVersionTest,
+ unsupportedVersionTest);
+ }
+ };
+ } // apply
+
+ private void validateCddAnnotations(CddTest cddTest,
+ @Nullable ApiRequirements apiRequirements) {
+ @SuppressWarnings("deprecation")
+ String deprecatedRequirement = cddTest.requirement();
+
+ if (!TextUtils.isEmpty(deprecatedRequirement)) {
+ throw new IllegalArgumentException("Test contains " + cddTest.annotationType()
+ + " annotation (" + cddTest + "), but it's using the"
+ + " deprecated 'requirement' field (value=" + deprecatedRequirement + "); it "
+ + "should use 'requirements' instead");
+ }
+
+ String[] requirements = cddTest.requirements();
+
+ if (requirements == null || requirements.length == 0) {
+ throw new IllegalArgumentException("Test contains " + cddTest.annotationType()
+ + " annotation (" + cddTest + "), but it's 'requirements' field is empty (value="
+ + Arrays.toString(requirements) + ")");
+ }
+ for (String requirement : requirements) {
+ String trimmedRequirement = requirement == null ? "" : requirement.trim();
+ if (TextUtils.isEmpty(trimmedRequirement)) {
+ throw new IllegalArgumentException("Test contains " + cddTest.annotationType()
+ + " annotation (" + cddTest + "), but it contains an empty requirement"
+ + "(requirements=" + Arrays.toString(requirements) + ")");
+ }
+ }
+
+ // CddTest itself is valid, must have ApiRequirements
+ if (apiRequirements == null) {
+ throw new IllegalArgumentException("Test contains " + cddTest.annotationType()
+ + " annotation (" + cddTest + "), but it's missing @ApiRequirements)");
+ }
+ }
+
+ @SuppressWarnings("deprecation")
+ private Pair<ApiRequirements, AddedInOrBefore> getApiRequirementsFromApis(
+ Description description, ApiTest apiTest, @Nullable IgnoreInvalidApi ignoreInvalidApi) {
+ ApiRequirements firstApiRequirements = null;
+ AddedInOrBefore addedInOrBefore = null;
+ List<String> allApis = new ArrayList<>();
+ List<ApiRequirements> allApiRequirements = new ArrayList<>();
+ boolean compatibleApis = true;
+
+ String[] apis = apiTest.apis();
+ if (apis == null || apis.length == 0) {
+ throw new IllegalArgumentException("empty @ApiTest annotation");
+ }
+ List<String> invalidApis = new ArrayList<>();
+ for (String api : apis) {
+ allApis.add(api);
+ Member member = ApiHelper.resolve(api);
+ if (member == null) {
+ invalidApis.add(api);
+ continue;
+ }
+ ApiRequirements apiRequirements = getApiRequirements(member);
+ if (apiRequirements == null && addedInOrBefore == null) {
+ addedInOrBefore = getAddedInOrBefore(member);
+ if (DBG) {
+ Log.d(TAG, "No @ApiRequirements on " + api + "; trying "
+ + "@AddedInOrBefore instead: " + addedInOrBefore);
+ }
+ continue;
+ }
+ allApiRequirements.add(apiRequirements);
+ if (firstApiRequirements == null) {
+ firstApiRequirements = apiRequirements;
+ continue;
+ }
+ // Make sure all ApiRequirements are compatible
+ if (!apiRequirements.minCarVersion()
+ .equals(firstApiRequirements.minCarVersion())
+ || !apiRequirements.minPlatformVersion()
+ .equals(firstApiRequirements.minPlatformVersion())) {
+ Log.w(TAG, "Found incompatible API requirement (" + apiRequirements
+ + ") on " + api + "(first ApiRequirements is "
+ + firstApiRequirements + ")");
+ compatibleApis = false;
+ } else {
+ Log.d(TAG, "Multiple @ApiRequirements found but they're compatible");
+ }
+ }
+ if (!invalidApis.isEmpty()) {
+ if (ignoreInvalidApi != null) {
+ Log.i(TAG, "Could not resolve some APIs (" + invalidApis + ") on annotation ("
+ + apiTest + "), but letting it go due to " + ignoreInvalidApi);
+ } else {
+ throw new IllegalArgumentException("Could not resolve some APIs ("
+ + invalidApis + ") on annotation (" + apiTest + ")");
+ }
+ } else if (!compatibleApis) {
+ throw new IncompatibleApiRequirementsException(allApis, allApiRequirements);
+ }
+ return new Pair<>(firstApiRequirements, addedInOrBefore);
+ }
+
+ private void validateOptionalAnnotations(Class<?> testClass, String testMethodName,
+ @Nullable SupportedVersionTest supportedVersionAnnotationOnTestMethod,
+ @Nullable UnsupportedVersionTest unsupportedVersionAnnotationOnTestMethod) {
+ if (unsupportedVersionAnnotationOnTestMethod != null
+ && supportedVersionAnnotationOnTestMethod != null) {
+ throw new IllegalArgumentException("test must be annotated with either "
+ + "supportedVersionTest or unsupportedVersionTest, not both");
+ }
+ if (unsupportedVersionAnnotationOnTestMethod != null) {
+ validateUnsupportedVersionTest(testClass, testMethodName,
+ unsupportedVersionAnnotationOnTestMethod);
+ return;
+ }
+ if (supportedVersionAnnotationOnTestMethod != null) {
+ validateSupportedVersionTest(testClass, testMethodName,
+ supportedVersionAnnotationOnTestMethod);
+ return;
+ }
+ }
+
+ private void validateUnsupportedVersionTest(Class<?> testClass, String testMethodName,
+ @Nullable UnsupportedVersionTest unsupportedVersionAnnotationOnTestMethod) {
+ // Test class must have a counterpart supportedVersionTest
+ String supportedVersionMethodName = unsupportedVersionAnnotationOnTestMethod
+ .supportedVersionTest();
+ if (TextUtils.isEmpty(supportedVersionMethodName)) {
+ throw new IllegalArgumentException("missing supportedVersionTest on "
+ + unsupportedVersionAnnotationOnTestMethod);
+ }
+
+ Method supportedVersionMethod = null;
+ Class<?>[] noParams = {};
+ try {
+ supportedVersionMethod = testClass.getDeclaredMethod(supportedVersionMethodName,
+ noParams);
+ } catch (Exception e) {
+ Log.w(TAG, "Error getting method named " + supportedVersionMethodName
+ + " on class " + testClass, e);
+ throw new IllegalArgumentException("invalid supportedVersionTest on "
+ + unsupportedVersionAnnotationOnTestMethod + ": " + e);
+ }
+ // And it must be annotated with @SupportedVersionTest
+ SupportedVersionTest supportedVersionAnnotationOnUnsupportedMethod =
+ supportedVersionMethod.getAnnotation(SupportedVersionTest.class);
+ if (supportedVersionAnnotationOnUnsupportedMethod == null) {
+ throw new IllegalArgumentException(
+ "invalid supportedVersionTest method (" + supportedVersionMethodName
+ + " on " + unsupportedVersionAnnotationOnTestMethod
+ + ": it's not annotated with @SupportedVersionTest");
+ }
+
+ // which in turn must point to the UnsupportedVersionTest itself
+ String unsupportedVersionMethodOnSupportedAnnotation =
+ supportedVersionAnnotationOnUnsupportedMethod.unsupportedVersionTest();
+ if (!testMethodName.equals(unsupportedVersionMethodOnSupportedAnnotation)) {
+ throw new IllegalArgumentException(
+ "invalid unsupportedVersionTest on "
+ + supportedVersionAnnotationOnUnsupportedMethod
+ + " annotation on method " + supportedVersionMethodName
+ + ": it should be " + testMethodName);
+ }
+ }
+
+ private void validateSupportedVersionTest(Class<?> testClass, String testMethodName,
+ @Nullable SupportedVersionTest supportedVersionAnnotationOnTestMethod) {
+ // Test class must have a counterpart unsupportedVersionTest
+ String unsupportedVersionMethodName = supportedVersionAnnotationOnTestMethod
+ .unsupportedVersionTest();
+ if (TextUtils.isEmpty(unsupportedVersionMethodName)) {
+ throw new IllegalArgumentException("missing unsupportedVersionTest on "
+ + supportedVersionAnnotationOnTestMethod);
+ }
+
+ Method unsupportedVersionMethod = null;
+ Class<?>[] noParams = {};
+ try {
+ unsupportedVersionMethod = testClass.getDeclaredMethod(unsupportedVersionMethodName,
+ noParams);
+ } catch (Exception e) {
+ Log.w(TAG, "Error getting method named " + unsupportedVersionMethodName
+ + " on class " + testClass, e);
+ throw new IllegalArgumentException("invalid supportedVersionTest on "
+ + supportedVersionAnnotationOnTestMethod + ": " + e);
+ }
+ // And it must be annotated with @UnupportedVersionTest
+ UnsupportedVersionTest unsupportedVersionAnnotationOnUnsupportedMethod =
+ unsupportedVersionMethod.getAnnotation(UnsupportedVersionTest.class);
+ if (unsupportedVersionAnnotationOnUnsupportedMethod == null) {
+ throw new IllegalArgumentException(
+ "invalid supportedVersionTest method (" + unsupportedVersionMethodName
+ + " on " + supportedVersionAnnotationOnTestMethod
+ + ": it's not annotated with @UnsupportedVersionTest");
+ }
+
+ // which in turn must point to the UnsupportedVersionTest itself
+ String supportedVersionMethodOnSupportedAnnotation =
+ unsupportedVersionAnnotationOnUnsupportedMethod.supportedVersionTest();
+ if (!testMethodName.equals(supportedVersionMethodOnSupportedAnnotation)) {
+ throw new IllegalArgumentException(
+ "invalid supportedVersionTest on "
+ + unsupportedVersionAnnotationOnUnsupportedMethod
+ + " annotation on method " + unsupportedVersionMethodName
+ + ": it should be " + testMethodName);
+ }
+ }
+
+ private void apply(Statement base, Description description,
+ @Nullable ApiRequirements apiRequirements,
+ @Nullable SupportedVersionTest supportedVersionTest,
+ @Nullable UnsupportedVersionTest unsupportedVersionTest)
+ throws Throwable {
+ if (DBG) {
+ Log.d(TAG, "Applying rule using ApiRequirements=" + apiRequirements);
+ }
+ if (apiRequirements == null) {
+ Log.w(TAG, "No @ApiRequirements on " + description.getDisplayName()
+ + " (most likely it's annotated with @AddedInOrBefore), running it always");
+ base.evaluate();
+ return;
+ }
+ if (isSupported(apiRequirements)) {
+ applyOnSupportedVersion(base, description, apiRequirements, unsupportedVersionTest);
+ return;
+ }
+
+ applyOnUnsupportedVersion(base, description, apiRequirements, supportedVersionTest,
+ unsupportedVersionTest);
+ }
+
+ private void applyOnSupportedVersion(Statement base, Description description,
+ ApiRequirements apiRequirements,
+ @Nullable UnsupportedVersionTest unsupportedVersionTest)
+ throws Throwable {
+ if (unsupportedVersionTest == null) {
+ if (DBG) {
+ Log.d(TAG, "Car / Platform combo is supported, running "
+ + description.getDisplayName());
+ }
+ base.evaluate();
+ return;
+ }
+
+ Log.i(TAG, "Car / Platform combo IS supported, but ignoring "
+ + description.getDisplayName() + " because it's annotated with "
+ + unsupportedVersionTest);
+
+ throw new ExpectedVersionAssumptionViolationException(unsupportedVersionTest,
+ Car.getCarVersion(), Car.getPlatformVersion(), apiRequirements);
+ }
+
+ private void applyOnUnsupportedVersion(Statement base, Description description,
+ ApiRequirements apiRequirements, @Nullable SupportedVersionTest supportedVersionTest,
+ @Nullable UnsupportedVersionTest unsupportedVersionTest)
+ throws Throwable {
+ Behavior behavior = unsupportedVersionTest == null ? null
+ : unsupportedVersionTest.behavior();
+ if (supportedVersionTest == null && !Behavior.EXPECT_PASS.equals(behavior)) {
+ Log.i(TAG, "Car / Platform combo is NOT supported, running "
+ + description.getDisplayName() + " but expecting "
+ + "PlatformVersionMismatchException");
+ try {
+ base.evaluate();
+ throw new PlatformVersionMismatchExceptionNotThrownException(
+ Car.getCarVersion(), Car.getPlatformVersion(), apiRequirements);
+ } catch (PlatformVersionMismatchException e) {
+ if (DBG) {
+ Log.d(TAG, "Exception thrown as expected: " + e);
+ }
+ }
+ return;
+ }
+
+ if (supportedVersionTest != null) {
+ Log.i(TAG, "Car / Platform combo is NOT supported, but ignoring "
+ + description.getDisplayName() + " because it's annotated with "
+ + supportedVersionTest);
+
+ throw new ExpectedVersionAssumptionViolationException(supportedVersionTest,
+ Car.getCarVersion(), Car.getPlatformVersion(), apiRequirements);
+ }
+
+ // At this point, it's annotated with RUN_ALWAYS
+ Log.i(TAG, "Car / Platform combo is NOT supported but running anyways becaucase test is"
+ + " annotated with " + unsupportedVersionTest);
+ base.evaluate();
+ }
+
+ /**
+ * Defines the behavior of a test when it's run in an unsupported device (when it's run in a
+ * supported device, the rule will throw a {@link ExpectedVersionAssumptionViolationException}
+ * exception).
+ *
+ * <p>Without this annotation, a test is expected to throw a
+ * {@link PlatformVersionMismatchException} when running in an unsupported version.
+ *
+ * <p><b>Note: </b>a test annotated with this annotation <b>MUST</b> have a counterpart test
+ * annotated with {@link SupportedVersionTest}.
+ */
+ @Retention(RUNTIME)
+ @Target({TYPE, METHOD})
+ public @interface UnsupportedVersionTest {
+
+ /**
+ * Name of the counterpart test should be run on supported versions; such test must be
+ * annoted with {@link SupportedVersionTest}, whith its {@code unsupportedVersionTest}
+ * value point to the test being annotated with this annotation.
+ */
+ String supportedVersionTest();
+
+ /**
+ * Behavior of the test when it's run on unsupported versions.
+ */
+ Behavior behavior() default Behavior.EXPECT_THROWS_VERSION_MISMATCH_EXCEPTION;
+
+ @SuppressWarnings("Enum")
+ enum Behavior {
+ /**
+ * Rule will run the test and assert it throws a
+ * {@link PlatformVersionMismatchException}.
+ */
+ EXPECT_THROWS_VERSION_MISMATCH_EXCEPTION,
+
+ /** Rule will run the test and assume it will pass.*/
+ EXPECT_PASS
+ }
+ }
+
+ /**
+ * Defines a test to be a counterpart of a test annotated with {@link UnsupportedVersionTest}.
+ *
+ * <p>Such test will be run as usual on supported devices, but will throw a
+ * {@link ExpectedVersionAssumptionViolationException} when running on unsupported devices.
+ *
+ */
+ @Retention(RUNTIME)
+ @Target({TYPE, METHOD})
+ public @interface SupportedVersionTest {
+
+ /**
+ * Name of the counterpart test should be run on unsupported versions; such test must be
+ * annoted with {@link UnsupportedVersionTest}, whith its {@code supportedVersionTest}
+ * value point to the test being annotated with this annotation.
+ */
+ String unsupportedVersionTest();
+
+ }
+
+ /***
+ * Tells the rule to ignore an invalid API passed to {@link ApiTest}.
+ *
+ * <p>Should be used in cases where the API is being indirectly tested (for example, through a
+ * shell command) and hence is not available in the test's classpath.
+ *
+ * <p>Should be used in conjunction with {@link ApiRequirements}.
+ *
+ */
+ @Retention(RUNTIME)
+ @Target({TYPE, METHOD})
+ public @interface IgnoreInvalidApi {
+
+ /**
+ * Reason why the invalid API should be ignored.
+ */
+ String reason();
+ }
+
+ public static final class ExpectedVersionAssumptionViolationException
+ extends AssumptionViolatedException {
+
+ private static final long serialVersionUID = 1L;
+
+ private final CarVersion mCarVersion;
+ private final PlatformVersion mPlatformVersion;
+ private final ApiRequirements mApiRequirements;
+
+ ExpectedVersionAssumptionViolationException(Annotation annotation, CarVersion carVersion,
+ PlatformVersion platformVersion, ApiRequirements apiRequirements) {
+ super("Test annotated with @" + annotation.annotationType().getCanonicalName()
+ + " when running on unsupported platform: CarVersion=" + carVersion
+ + ", PlatformVersion=" + platformVersion
+ + ", ApiRequirements=" + apiRequirements);
+
+ mCarVersion = carVersion;
+ mPlatformVersion = platformVersion;
+ mApiRequirements = apiRequirements;
+ }
+
+ public CarVersion getCarVersion() {
+ return mCarVersion;
+ }
+
+ public PlatformVersion getPlatformVersion() {
+ return mPlatformVersion;
+ }
+
+ public ApiRequirements getApiRequirements() {
+ return mApiRequirements;
+ }
+ }
+
+ public static final class PlatformVersionMismatchExceptionNotThrownException
+ extends IllegalStateException {
+
+ private static final long serialVersionUID = 1L;
+
+ private final CarVersion mCarVersion;
+ private final PlatformVersion mPlatformVersion;
+ private final ApiRequirements mApiRequirements;
+
+ PlatformVersionMismatchExceptionNotThrownException(CarVersion carVersion,
+ PlatformVersion platformVersion, ApiRequirements apiRequirements) {
+ super("Test should throw " + PlatformVersionMismatchException.class.getSimpleName()
+ + " when running on unsupported platform: CarVersion=" + carVersion
+ + ", PlatformVersion=" + platformVersion
+ + ", ApiRequirements=" + apiRequirements);
+
+ mCarVersion = carVersion;
+ mPlatformVersion = platformVersion;
+ mApiRequirements = apiRequirements;
+ }
+
+ public CarVersion getCarVersion() {
+ return mCarVersion;
+ }
+
+ public PlatformVersion getPlatformVersion() {
+ return mPlatformVersion;
+ }
+
+ public ApiRequirements getApiRequirements() {
+ return mApiRequirements;
+ }
+ }
+
+ public static final class IncompatibleApiRequirementsException
+ extends IllegalArgumentException {
+
+ private static final long serialVersionUID = 1L;
+
+ private final List<String> mApis;
+ private final List<ApiRequirements> mApiRequirements;
+
+ IncompatibleApiRequirementsException(List<String> apis,
+ List<ApiRequirements> apiRequirements) {
+ super("Incompatible API requirements (apis=" + apis + ", apiRequirements="
+ + apiRequirements + ") on test, consider splitting it into multiple methods");
+
+ mApis = apis;
+ mApiRequirements = apiRequirements;
+ }
+
+ public List<String> getApis() {
+ return mApis;
+ }
+
+ public List<ApiRequirements> getApiRequirements() {
+ return mApiRequirements;
+ }
+ }
+}
diff --git a/car-test-lib/src/android/car/test/ApiHelper.java b/car-test-lib/src/android/car/test/ApiHelper.java
new file mode 100644
index 0000000..8444e96
--- /dev/null
+++ b/car-test-lib/src/android/car/test/ApiHelper.java
@@ -0,0 +1,213 @@
+/*
+ * Copyright (C) 2022 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.test;
+
+import android.annotation.Nullable;
+import android.util.Log;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Member;
+import java.lang.reflect.Method;
+import java.util.Arrays;
+import java.util.Objects;
+
+// TODO(b/242571576): move this class to com.android.compatibility.common.util
+
+/**
+ * Helper class used primarily to validate values used on
+ * {code @com.android.compatibility.common.util.ApiTest}.
+ */
+public final class ApiHelper {
+
+ private static final String TAG = ApiHelper.class.getSimpleName();
+ private static final boolean DBG = false;
+
+ /**
+ * Resolves an API to the proper member (method or field).
+ */
+ @Nullable
+ public static Member resolve(String api) {
+ Objects.requireNonNull(api);
+
+ // Try method first, as it's the most common case...
+ Member member = getMethod(api);
+
+ // ...then field
+ if (member == null) {
+ if (api.contains("$")) {
+ // See note below
+ return null;
+ }
+ member = getField(api);
+ }
+
+ // ...then special cases
+ if (member == null && api.contains("#")) {
+ // TODO(b/242571576): From Java's point of view, a field from an inner class like:
+ // android.car.CarVersion$VERSION_CODES#TIRAMISU_0
+ // is valid, but the python API parser is expecting
+ // android.car.CarVersion.VERSION_CODES#TIRAMISU_0
+ int index = api.lastIndexOf('.');
+ // TODO(b/242571576): it would fail if API was like Class.INNER_1.INNER_2.Field
+ String fixed = api.substring(0, index) + "$" + api.substring(index + 1, api.length());
+ member = getField(fixed);
+ }
+
+ if (member == null) {
+ Log.w(TAG, "Could not resolve API: " + api);
+ }
+
+ return member;
+ }
+
+ @Nullable
+ private static Method getMethod(String fullyQualifiedMethodName) {
+ // TODO(b/242571576): improve it to:
+ // - use regex
+ // - handle methods from CREATOR
+ // - support fields from inner classes like car.PlatformVersion$VERSION_CODES#TIRAMISU_0
+
+ int classSeparator = fullyQualifiedMethodName.indexOf('#');
+ if (classSeparator == -1) {
+ return null;
+ }
+ String className = fullyQualifiedMethodName.substring(0, classSeparator);
+ String methodSignature = fullyQualifiedMethodName.substring(classSeparator + 1,
+ fullyQualifiedMethodName.length());
+ if (DBG) {
+ Log.d(TAG, "getMethod(" + fullyQualifiedMethodName + "): class=" + className
+ + ", signature=" + methodSignature);
+ }
+
+ try {
+ Class<?> clazz = Class.forName(className);
+ String methodName = methodSignature;
+ if (clazz != null) {
+ if (methodSignature.contains("(") && methodSignature.endsWith(")")) {
+ int openingIndex = methodSignature.indexOf('(');
+ methodName = methodSignature.substring(0, openingIndex);
+ String types = methodSignature.substring(openingIndex + 1,
+ methodSignature.length() - 1);
+ String[] paramTypesNames = types.split(",");
+ if (DBG) {
+ Log.d(TAG, "Method name after stripping (): " + methodName + ". Types: "
+ + Arrays.toString(paramTypesNames));
+ }
+ return getMethodWithParameters(clazz, methodName, paramTypesNames);
+ } // methodSignature.contains....
+ if (DBG) {
+ Log.d(TAG, "Getting method without params: " + methodName);
+ }
+ Class<?>[] noParams = {};
+ return clazz.getDeclaredMethod(methodName, noParams);
+ } // clazz != null
+ } catch (Exception e) {
+ if (DBG) {
+ Log.d(TAG, "getMethod(" + fullyQualifiedMethodName + ") failed: " + e);
+ }
+ }
+ return null;
+ }
+
+ @Nullable
+ private static Method getMethodWithParameters(Class<?> clazz, String methodName,
+ String[] paramTypesNames) {
+ if (DBG) {
+ Log.d(TAG, "getMethod(" + clazz + ", " + methodName + ", "
+ + Arrays.toString(paramTypesNames) + ")");
+ }
+ // Need to interact trough all methods, otherwise it would be harder to handle java.lang
+ // param types. For example:
+ // - classes like String would need to be prefixed by "java.lang."
+ // - primitive types would need to be handled case by case
+ // Besides, the ApiTest syntax doesn't check for FQCN (for example, it should be just
+ // "Handler" instead of "android.os.Handler");
+ for (String paramTypeName : paramTypesNames) {
+ if (paramTypeName.contains(".")) {
+ return null;
+ }
+ }
+
+ try {
+ Method[] allMethods = clazz.getDeclaredMethods();
+ method:
+ for (Method method : allMethods) {
+ if (DBG) {
+ Log.v(TAG, "Trying method :" + method);
+ }
+ if (!method.getName().equals(methodName)) {
+ continue;
+ }
+ Class<?>[] paramTypes = method.getParameterTypes();
+ if (paramTypes.length != paramTypesNames.length) {
+ continue;
+ }
+ for (int i = 0; i < paramTypes.length; i++) {
+ String expected = paramTypesNames[i].trim();
+ String actual = paramTypes[i].getCanonicalName();
+ if (DBG) {
+ Log.d(TAG, "Checking param #" + i + ": expected=" + expected + ", actual="
+ + actual);
+ }
+ if (!actual.endsWith(expected)) {
+ continue method;
+ }
+ }
+ if (DBG) {
+ Log.d(TAG, "Found method :" + method);
+ }
+ return method;
+ }
+
+ } catch (Exception e) {
+ Log.w(TAG, "getMethod(" + clazz + ", " + Arrays.toString(paramTypesNames)
+ + ") failed: " + e);
+ }
+ return null;
+ }
+
+ @Nullable
+ private static Field getField(String fullyQualifiedFieldName) {
+ int classSeparator = fullyQualifiedFieldName.indexOf('#');
+ if (classSeparator == -1) {
+ return null;
+ }
+ String className = fullyQualifiedFieldName.substring(0, classSeparator);
+ String fieldName = fullyQualifiedFieldName.substring(classSeparator + 1,
+ fullyQualifiedFieldName.length());
+ if (DBG) {
+ Log.d(TAG, "getField(" + fullyQualifiedFieldName + "): class=" + className
+ + ", field=" + fieldName);
+ }
+ Class<?> clazz;
+ try {
+ clazz = Class.forName(className);
+ if (clazz != null) {
+ return clazz.getDeclaredField(fieldName);
+ }
+ } catch (Exception e) {
+ if (DBG) {
+ Log.d(TAG, "getField(" + fullyQualifiedFieldName + ") failed: " + e);
+ }
+ }
+ return null;
+ }
+
+ private ApiHelper() {
+ throw new UnsupportedOperationException("provides only static methods");
+ }
+}
diff --git a/car-test-lib/src/android/car/test/mocks/AbstractExtendedMockitoTestCase.java b/car-test-lib/src/android/car/test/mocks/AbstractExtendedMockitoTestCase.java
index 7e0920f..7427a1c 100644
--- a/car-test-lib/src/android/car/test/mocks/AbstractExtendedMockitoTestCase.java
+++ b/car-test-lib/src/android/car/test/mocks/AbstractExtendedMockitoTestCase.java
@@ -170,14 +170,27 @@
@After
public final void finishSession() {
- beginTrace("finishSession()");
- completeAllHandlerThreadTasks();
- if (mSession != null) {
- beginTrace("finishMocking()");
- mSession.finishMocking();
- endTrace();
- } else {
+ // mSession.finishMocking() must ALWAYS be called (hence the over-protective try/finally
+ // statements), otherwise it would cause failures on future tests as mockito
+ // cannot start a session when a previous one is not finished
+ try {
+ beginTrace("finishSession()");
+ completeAllHandlerThreadTasks();
+ } finally {
+ finishSessionMocking();
+ }
+ endTrace();
+ }
+
+ private void finishSessionMocking() {
+ if (mSession == null) {
Log.w(TAG, getClass().getSimpleName() + ".finishSession(): no session");
+ return;
+ }
+ try {
+ beginTrace("finishMocking()");
+ } finally {
+ mSession.finishMocking();
}
endTrace();
}
@@ -361,6 +374,9 @@
}).when(() -> Slog.wtf(anyString(), anyString()));
doAnswer((invocation) -> {
return addWtf(invocation);
+ }).when(() -> Slog.wtf(anyString(), any(Throwable.class)));
+ doAnswer((invocation) -> {
+ return addWtf(invocation);
}).when(() -> Slog.wtf(anyString(), anyString(), any(Throwable.class)));
// NOTE: android.car.builtin.util.Slogf calls android.util.Slog behind the scenes, so no
// need to check for calls of the former...
@@ -373,7 +389,7 @@
if (mLogTags != null && mLogTags.contains(actualTag)) {
mWtfs.add(new IllegalStateException(message));
} else if (VERBOSE) {
- Log.v(TAG, "ignoring WTF invocation on tag " + actualTag);
+ Log.v(TAG, "ignoring WTF invocation on tag " + actualTag + ". mLogTags=" + mLogTags);
}
return null;
}
@@ -384,6 +400,9 @@
private void verifyWtfNeverLogged() {
int size = mWtfs.size();
+ if (VERBOSE) {
+ Log.v(TAG, "verifyWtfNeverLogged(): mWtfs=" + mWtfs);
+ }
switch (size) {
case 0:
diff --git a/car-test-lib/src/android/car/test/mocks/AndroidMockitoHelper.java b/car-test-lib/src/android/car/test/mocks/AndroidMockitoHelper.java
index 001df1b..3acdbaa 100644
--- a/car-test-lib/src/android/car/test/mocks/AndroidMockitoHelper.java
+++ b/car-test-lib/src/android/car/test/mocks/AndroidMockitoHelper.java
@@ -30,6 +30,9 @@
import android.app.Activity;
import android.app.ActivityManager;
import android.app.admin.DevicePolicyManager;
+import android.car.Car;
+import android.car.CarVersion;
+import android.car.PlatformVersion;
import android.car.builtin.app.ActivityManagerHelper;
import android.car.builtin.os.UserManagerHelper;
import android.car.test.util.UserTestingHelper;
@@ -413,6 +416,22 @@
}
/**
+ * Mocks a call to {@link Car#getCarVersion()
+ */
+ public static void mockCarGetCarVersion(CarVersion version) {
+ Log.d(TAG, "mockCarGetCarVersion(): " + version);
+ doReturn(version).when(() -> Car.getCarVersion());
+ }
+
+ /**
+ * Mocks a call to {@link Car#getPlatformVersion()
+ */
+ public static void mockCarGetPlatformVersion(PlatformVersion version) {
+ Log.d(TAG, "mockCarGetPlatformVersion(): " + version);
+ doReturn(version).when(() -> Car.getPlatformVersion());
+ }
+
+ /**
* Mocks a call to {@link Context#getSystemService(Class)}.
*/
public static <T> void mockContextGetService(Context context,
diff --git a/car-test-lib/src/android/car/test/util/AnnotationHelper.java b/car-test-lib/src/android/car/test/util/AnnotationHelper.java
new file mode 100644
index 0000000..203ad2e
--- /dev/null
+++ b/car-test-lib/src/android/car/test/util/AnnotationHelper.java
@@ -0,0 +1,142 @@
+/*
+ * Copyright (C) 2022 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.test.util;
+
+import static com.google.common.truth.Truth.assertWithMessage;
+
+import android.car.annotation.AddedInOrBefore;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.ArrayList;
+import java.util.List;
+
+
+// TODO(b/237565347): Refactor this class so that 'field' and 'method' code is not repeated.
+public class AnnotationHelper {
+
+ public static void checkForAnnotation(String[] classes, Class... annotationClasses)
+ throws Exception {
+ List<String> errorsNoAnnotation = new ArrayList<>();
+ List<String> errorsExtraAnnotation = new ArrayList<>();
+
+ for (int i = 0; i < classes.length; i++) {
+ String className = classes[i];
+ Field[] fields = Class.forName(className).getDeclaredFields();
+ for (int j = 0; j < fields.length; j++) {
+ Field field = fields[j];
+ boolean isAnnotated = containsAddedInAnnotation(field, annotationClasses);
+ boolean isPrivate = Modifier.isPrivate(field.getModifiers());
+
+ if (isPrivate && isAnnotated) {
+ errorsExtraAnnotation.add(className + " FIELD: " + field.getName());
+ }
+
+ if (!isPrivate && !isAnnotated) {
+ errorsNoAnnotation.add(className + " FIELD: " + field.getName());
+ }
+ }
+
+ Method[] methods = Class.forName(className).getDeclaredMethods();
+ for (int j = 0; j < methods.length; j++) {
+ Method method = methods[j];
+
+ // These are some internal methods
+ if (method.getName().contains("$")) continue;
+
+ boolean isAnnotated = containsAddedInAnnotation(method, annotationClasses);
+ boolean isPrivate = Modifier.isPrivate(method.getModifiers());
+
+ if (isPrivate && isAnnotated) {
+ errorsExtraAnnotation.add(className + " METHOD: " + method.getName());
+ }
+
+ if (!isPrivate && !isAnnotated) {
+ errorsNoAnnotation.add(className + " METHOD: " + method.getName());
+ }
+ }
+ }
+
+ StringBuilder errorFlatten = new StringBuilder();
+ if (!errorsNoAnnotation.isEmpty()) {
+ // TODO(b/240343308): remove @AddedIn once all usages have been replaced
+ errorFlatten.append("Errors:\nMissing ApiRequirements (or AddedIn) annotation for-\n");
+ errorFlatten.append(String.join("\n", errorsNoAnnotation));
+ }
+
+ if (!errorsExtraAnnotation.isEmpty()) {
+ // TODO(b/240343308): remove @AddedIn once all usages have been replaced
+ errorFlatten.append("\nErrors:\nApiRequirements (or AddedIn) annotation used for "
+ + "private members/methods-\n");
+ errorFlatten.append(String.join("\n", errorsExtraAnnotation));
+ }
+
+ assertWithMessage(errorFlatten.toString())
+ .that(errorsExtraAnnotation.size() + errorsNoAnnotation.size()).isEqualTo(0);
+ }
+
+ @SuppressWarnings("unchecked")
+ private static boolean containsAddedInAnnotation(Field field, Class... annotationClasses) {
+ for (int i = 0; i < annotationClasses.length; i++) {
+ if (field.getAnnotation(annotationClasses[i]) != null) {
+ validatedAddInOrBeforeAnnotation(field);
+ return true;
+ }
+ }
+ return false;
+ }
+
+ @SuppressWarnings("unchecked")
+ private static boolean containsAddedInAnnotation(Method method, Class... annotationClasses) {
+ for (int i = 0; i < annotationClasses.length; i++) {
+ if (method.getAnnotation(annotationClasses[i]) != null) {
+ validatedAddInOrBeforeAnnotation(method);
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private static void validatedAddInOrBeforeAnnotation(Field field) {
+ AddedInOrBefore annotation = field.getAnnotation(AddedInOrBefore.class);
+ if (annotation != null) {
+ assertWithMessage(field.getDeclaringClass() + ", field:" + field.getName()
+ + " should not use AddedInOrBefore annotation. The annotation was reserved only"
+ + " for APIs added in or before majorVersion:33, minorVersion:0")
+ .that(annotation.majorVersion()).isEqualTo(33);
+ assertWithMessage(field.getDeclaringClass() + ", field:" + field.getName()
+ + " should not use AddedInOrBefore annotation. The annotation was reserved only"
+ + " for APIs added in or before majorVersion:33, minorVersion:0")
+ .that(annotation.minorVersion()).isEqualTo(0);
+ }
+ }
+
+ private static void validatedAddInOrBeforeAnnotation(Method method) {
+ AddedInOrBefore annotation = method.getAnnotation(AddedInOrBefore.class);
+ if (annotation != null) {
+ assertWithMessage(method.getDeclaringClass() + ", method:" + method.getName()
+ + " should not use AddedInOrBefore annotation. The annotation was reserved only"
+ + " for APIs added in or before majorVersion:33, minorVersion:0")
+ .that(annotation.majorVersion()).isEqualTo(33);
+ assertWithMessage(method.getDeclaringClass() + ", method:" + method.getName()
+ + " should not use AddedInOrBefore annotation. The annotation was reserved only"
+ + " for APIs added in or before majorVersion:33, minorVersion:0")
+ .that(annotation.minorVersion()).isEqualTo(0);
+ }
+ }
+}
diff --git a/car-test-lib/src/android/car/test/util/ExceptionalFunction.java b/car-test-lib/src/android/car/test/util/ExceptionalFunction.java
new file mode 100644
index 0000000..609158d3
--- /dev/null
+++ b/car-test-lib/src/android/car/test/util/ExceptionalFunction.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2022 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.test.util;
+
+/**
+ * Similar to Java's {@link java.util.function.Function}, but for methods that throw.
+ *
+ * @param <T> the type of the input to the function
+ * @param <R> the type of the result of the function
+ * @param <E> the type of the exception of the function
+ */
+public interface ExceptionalFunction<T, R, E extends Exception> {
+
+ /**
+ * Applies this function to the given argument.
+ *
+ * @param t the function argument
+ * @return the function result
+ * @throws E the exception it can throw
+ */
+ R apply(T t) throws E;
+}
diff --git a/car-test-lib/src/android/car/testapi/CarMockitoHelper.java b/car-test-lib/src/android/car/testapi/CarMockitoHelper.java
index 13c5361..88aab4e 100644
--- a/car-test-lib/src/android/car/testapi/CarMockitoHelper.java
+++ b/car-test-lib/src/android/car/testapi/CarMockitoHelper.java
@@ -38,8 +38,9 @@
public static void mockHandleRemoteExceptionFromCarServiceWithDefaultValue(
@NonNull Car car) {
doAnswer((invocation) -> {
+ Log.v(TAG, "mocking handleRemoteExceptionFromCarService(): args=" + invocation);
Object returnValue = invocation.getArguments()[1];
- Log.v(TAG, "mocking handleRemoteExceptionFromCarService(): " + returnValue);
+ Log.v(TAG, "returning " + returnValue);
return returnValue;
}).when(car).handleRemoteExceptionFromCarService(isA(RemoteException.class), any());
}
diff --git a/car-usb-handler/res/values-gu/strings.xml b/car-usb-handler/res/values-gu/strings.xml
index e2f5f5b..8e3b581 100644
--- a/car-usb-handler/res/values-gu/strings.xml
+++ b/car-usb-handler/res/values-gu/strings.xml
@@ -17,7 +17,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_name" msgid="6963366455471441257">"USB હૅન્ડલર"</string>
- <string name="usb_saved_devices" msgid="2829442070749964872">"સાચવેલા ડિવાઇસ"</string>
+ <string name="usb_saved_devices" msgid="2829442070749964872">"સાચવેલ ડિવાઇસ"</string>
<string name="usb_pref_delete_title" msgid="3885061814853467483">"USB ડિવાઇસ માટે હૅન્ડલિંગ ઍપ કાઢી નાખો"</string>
<string name="usb_pref_delete_message" msgid="5849493572520646218">"શું તમે ખરેખર ડિફૉલ્ટ હેન્ડલિંગ ઍપ્લિકેશન %1$s માટે કાઢી નાખવા માગો છો?"</string>
<string name="usb_pref_delete_yes" msgid="7803356145103146036">"હા"</string>
diff --git a/car-usb-handler/res/values-ne/strings.xml b/car-usb-handler/res/values-ne/strings.xml
index 6d4c70a..6fde11f 100644
--- a/car-usb-handler/res/values-ne/strings.xml
+++ b/car-usb-handler/res/values-ne/strings.xml
@@ -17,7 +17,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_name" msgid="6963366455471441257">"USB ह्यान्ड्लर"</string>
- <string name="usb_saved_devices" msgid="2829442070749964872">"सेभ गरिएका डिभाइस"</string>
+ <string name="usb_saved_devices" msgid="2829442070749964872">"सुरक्षित गरिएका यन्त्रहरू"</string>
<string name="usb_pref_delete_title" msgid="3885061814853467483">"USB डिभाइसको व्यवस्थापन गर्ने एप हटाउनुहोस्"</string>
<string name="usb_pref_delete_message" msgid="5849493572520646218">"तपाईंले %1$s को व्यवस्थापन गर्ने डिफल्ट एप मेट्न खोज्नुभएकै हो?"</string>
<string name="usb_pref_delete_yes" msgid="7803356145103146036">"हो"</string>
diff --git a/car-usb-handler/res/values-or/strings.xml b/car-usb-handler/res/values-or/strings.xml
index 97c08e4..9642ba7 100644
--- a/car-usb-handler/res/values-or/strings.xml
+++ b/car-usb-handler/res/values-or/strings.xml
@@ -21,7 +21,7 @@
<string name="usb_pref_delete_title" msgid="3885061814853467483">"USB ଡିଭାଇସ୍ ପାଇଁ ହ୍ୟାଣ୍ଡଲିଂ ଆପ୍କୁ କାଢ଼ିଦିଅନ୍ତୁ"</string>
<string name="usb_pref_delete_message" msgid="5849493572520646218">"ଆପଣ କ\'ଣ ନିଶ୍ଚିତ ଭାବରେ %1$s ପାଇଁ ଡିଫଲ୍ଟ ହ୍ୟାଣ୍ଡଲିଂ ଆପ୍କୁ ଡିଲିଟ୍ କରିବାକୁ ଚାହୁଁଛନ୍ତି?"</string>
<string name="usb_pref_delete_yes" msgid="7803356145103146036">"ହଁ"</string>
- <string name="usb_pref_delete_cancel" msgid="5999791462730255929">"ବାତିଲ କରନ୍ତୁ"</string>
+ <string name="usb_pref_delete_cancel" msgid="5999791462730255929">"ବାତିଲ୍ କରନ୍ତୁ"</string>
<string name="usb_resolving_handlers" msgid="1943100136172948686">"ସମର୍ଥିତ ହ୍ୟାଣ୍ଡଲର୍ ପ୍ରାପ୍ତ କରାଯାଉଛି"</string>
<string name="usb_unknown_device" msgid="4211439272338937095">"ଅଜଣା USB ଡିଭାଇସ୍"</string>
<string name="usb_boot_service_notification" msgid="8519949189071048797">"USB ଡିଭାଇସ୍ଗୁଡ଼ିକର ବିଶ୍ଲେଷଣ କରୁଛି"</string>
diff --git a/car_product/app_overlays/car-ui-customizations/res/color/car_ui_switch_track_background_selector.xml b/car_product/app_overlays/car-ui-customizations/res/color/car_ui_switch_track_background_selector.xml
index e3e5e22..8f47dac 100644
--- a/car_product/app_overlays/car-ui-customizations/res/color/car_ui_switch_track_background_selector.xml
+++ b/car_product/app_overlays/car-ui-customizations/res/color/car_ui_switch_track_background_selector.xml
@@ -24,7 +24,7 @@
android:color="#75757575" />
<item
android:state_checked="true" android:state_enabled="false"
- android:color="#7566B5" />
+ android:color="#7566B5FF" />
<item
android:state_enabled="false"
android:color="#75757575" />
diff --git a/car_product/app_overlays/car-ui-customizations/res/layout/car_ui_preference_two_action_icon.xml b/car_product/app_overlays/car-ui-customizations/res/layout/car_ui_preference_two_action_icon.xml
new file mode 100644
index 0000000..f32af91
--- /dev/null
+++ b/car_product/app_overlays/car-ui-customizations/res/layout/car_ui_preference_two_action_icon.xml
@@ -0,0 +1,116 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal"
+ android:minHeight="?android:attr/listPreferredItemHeightSmall"
+ android:tag="carUiPreference">
+
+ <com.android.car.ui.uxr.DrawableStateConstraintLayout
+ android:id="@+id/car_ui_first_action_container"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_gravity="center_vertical"
+ android:layout_weight = "1"
+ android:background="?android:attr/selectableItemBackground"
+ android:paddingStart="?android:attr/listPreferredItemPaddingStart"
+ android:paddingEnd="?android:attr/listPreferredItemPaddingEnd">
+
+ <RelativeLayout
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent">
+ <com.android.car.ui.uxr.DrawableStateImageView
+ android:id="@android:id/icon"
+ android:layout_width="44dp"
+ android:layout_height="44dp"
+ android:layout_marginEnd="32dp"
+ app:layout_goneMarginEnd="0dp"
+ android:layout_alignParentStart="true"
+ android:layout_centerVertical="true"
+ android:scaleType="fitCenter" />
+
+ <LinearLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ android:layout_toEndOf="@android:id/icon"
+ android:layout_centerVertical="true">
+
+ <com.android.car.ui.uxr.DrawableStateTextView
+ android:id="@android:id/title"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textAlignment="viewStart"
+ android:singleLine="true"
+ android:textAppearance="@style/TextAppearance.CarUi.PreferenceTitle"/>
+
+ <com.android.car.ui.uxr.DrawableStateTextView
+ android:id="@android:id/summary"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textAlignment="viewStart"
+ android:textAppearance="@style/TextAppearance.CarUi.PreferenceSummary"
+ android:maxLines="2"/>
+ </LinearLayout>
+ </RelativeLayout>
+ </com.android.car.ui.uxr.DrawableStateConstraintLayout>
+
+ <RelativeLayout
+ android:id="@+id/car_ui_second_action_container"
+ android:layout_height="match_parent"
+ android:layout_width="wrap_content"
+ android:layout_weight = "0"
+ android:layout_gravity="center_vertical">
+
+ <View
+ android:id="@+id/car_ui_divider"
+ android:layout_width="1dp"
+ android:layout_height="match_parent"
+ android:layout_gravity="center_vertical"
+ android:layout_marginBottom="16dp"
+ android:layout_marginTop="16dp"
+ android:background="#75ffffff"/>
+
+ <com.android.car.ui.uxr.DrawableStateFrameLayout
+ android:id="@+id/car_ui_secondary_action"
+ android:layout_width="?android:attr/listPreferredItemHeightSmall"
+ android:layout_height="match_parent"
+ android:background="?android:attr/selectableItemBackground">
+
+ <com.android.car.ui.uxr.DrawableStateImageView
+ android:id="@+id/car_ui_secondary_action_concrete"
+ android:layout_width="48dp"
+ android:layout_height="48dp"
+ android:layout_gravity="center"
+ android:tintMode="src_in"
+ android:tint="@color/car_ui_text_color_primary"/>
+ </com.android.car.ui.uxr.DrawableStateFrameLayout>
+
+ <!-- The widget frame is required for androidx preferences, but we won't use it. -->
+ <FrameLayout
+ android:id="@android:id/widget_frame"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:layout_alignParentEnd="true"
+ android:layout_toEndOf="@+id/car_ui_secondary_action" />
+ </RelativeLayout>
+
+</LinearLayout>
diff --git a/car_product/app_overlays/car-ui-customizations/res/layout/car_ui_preference_two_action_switch.xml b/car_product/app_overlays/car-ui-customizations/res/layout/car_ui_preference_two_action_switch.xml
index ef6f991..1907b85 100644
--- a/car_product/app_overlays/car-ui-customizations/res/layout/car_ui_preference_two_action_switch.xml
+++ b/car_product/app_overlays/car-ui-customizations/res/layout/car_ui_preference_two_action_switch.xml
@@ -24,95 +24,96 @@
android:minHeight="?android:attr/listPreferredItemHeightSmall"
android:tag="carUiPreference">
- <com.android.car.ui.uxr.DrawableStateConstraintLayout
- android:id="@+id/car_ui_first_action_container"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:layout_gravity="center_vertical"
- android:layout_weight = "1"
- android:paddingStart="?android:attr/listPreferredItemPaddingStart"
- android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
- android:background="?android:attr/selectableItemBackground">
-
- <RelativeLayout
- android:layout_width="wrap_content"
- android:layout_height="match_parent">
-
- <com.android.car.ui.uxr.DrawableStateImageView
- android:id="@android:id/icon"
- android:layout_width="44dp"
- android:layout_height="44dp"
- android:layout_alignParentStart="true"
- android:layout_centerVertical="true"
- android:scaleType="fitCenter" />
-
- <LinearLayout
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:orientation="vertical"
- android:layout_marginStart="16dp"
- android:layout_toEndOf="@android:id/icon"
- android:layout_centerVertical="true">
-
- <com.android.car.ui.uxr.DrawableStateTextView
- android:id="@android:id/title"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:singleLine="true"
- android:textAlignment="viewStart"
- android:textAppearance="@style/TextAppearance.CarUi.PreferenceTitle" />
-
- <com.android.car.ui.uxr.DrawableStateTextView
- android:id="@android:id/summary"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:maxLines="2"
- android:textAlignment="viewStart"
- android:textAppearance="@style/TextAppearance.CarUi.PreferenceSummary" />
- </LinearLayout>
- </RelativeLayout>
- </com.android.car.ui.uxr.DrawableStateConstraintLayout>
-
- <RelativeLayout
- android:id="@+id/car_ui_second_action_container"
- android:layout_height="match_parent"
- android:layout_width="wrap_content"
- android:layout_weight = "0"
- android:layout_gravity="center_vertical">
-
- <View
- android:id="@+id/car_ui_divider"
- android:layout_width="1dp"
- android:layout_height="match_parent"
- android:layout_gravity="center_vertical"
- android:layout_marginBottom="16dp"
- android:layout_marginTop="16dp"
- android:background="#75ffffff"/>
-
- <com.android.car.ui.uxr.DrawableStateFrameLayout
- android:id="@+id/car_ui_secondary_action"
- android:layout_width="?android:attr/listPreferredItemHeightSmall"
+ <com.android.car.ui.uxr.DrawableStateConstraintLayout
+ android:id="@+id/car_ui_first_action_container"
+ android:layout_width="match_parent"
android:layout_height="match_parent"
- android:layout_alignParentStart="true"
+ android:layout_gravity="center_vertical"
+ android:layout_weight = "1"
+ android:paddingStart="?android:attr/listPreferredItemPaddingStart"
+ android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
android:background="?android:attr/selectableItemBackground">
- <com.android.car.ui.uxr.DrawableStateSwitch
- android:id="@+id/car_ui_secondary_action_concrete"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center"
- android:clickable="false"
- android:focusable="false"
- style="@style/Widget.CarUi.SwitchPreference.Switch"/>
- </com.android.car.ui.uxr.DrawableStateFrameLayout>
+ <RelativeLayout
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent">
- <!-- The widget frame is required for androidx preferences, but we won't use it. -->
- <FrameLayout
- android:id="@android:id/widget_frame"
- android:layout_width="wrap_content"
+ <com.android.car.ui.uxr.DrawableStateImageView
+ android:id="@android:id/icon"
+ android:layout_width="44dp"
+ android:layout_height="44dp"
+ android:layout_marginEnd="32dp"
+ app:layout_goneMarginEnd="0dp"
+ android:layout_alignParentStart="true"
+ android:layout_centerVertical="true"
+ android:scaleType="fitCenter" />
+
+ <LinearLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ android:layout_toEndOf="@android:id/icon"
+ android:layout_centerVertical="true">
+
+ <com.android.car.ui.uxr.DrawableStateTextView
+ android:id="@android:id/title"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:singleLine="true"
+ android:textAlignment="viewStart"
+ android:textAppearance="@style/TextAppearance.CarUi.PreferenceTitle" />
+
+ <com.android.car.ui.uxr.DrawableStateTextView
+ android:id="@android:id/summary"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:maxLines="2"
+ android:textAlignment="viewStart"
+ android:textAppearance="@style/TextAppearance.CarUi.PreferenceSummary" />
+ </LinearLayout>
+ </RelativeLayout>
+ </com.android.car.ui.uxr.DrawableStateConstraintLayout>
+
+ <RelativeLayout
+ android:id="@+id/car_ui_second_action_container"
android:layout_height="match_parent"
- android:layout_alignParentEnd="true"
- android:layout_toEndOf="@+id/car_ui_secondary_action" />
- </RelativeLayout>
+ android:layout_width="wrap_content"
+ android:layout_weight = "0"
+ android:layout_gravity="center_vertical">
+
+ <View
+ android:id="@+id/car_ui_divider"
+ android:layout_width="1dp"
+ android:layout_height="match_parent"
+ android:layout_gravity="center_vertical"
+ android:layout_marginBottom="16dp"
+ android:layout_marginTop="16dp"
+ android:background="#75ffffff"/>
+
+ <com.android.car.ui.uxr.DrawableStateFrameLayout
+ android:id="@+id/car_ui_secondary_action"
+ android:layout_width="?android:attr/listPreferredItemHeightSmall"
+ android:layout_height="match_parent"
+ android:layout_alignParentStart="true"
+ android:background="?android:attr/selectableItemBackground">
+
+ <com.android.car.ui.uxr.DrawableStateSwitch
+ android:id="@+id/car_ui_secondary_action_concrete"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ android:clickable="false"
+ android:focusable="false"
+ style="@style/Widget.CarUi.SwitchPreference.Switch"/>
+ </com.android.car.ui.uxr.DrawableStateFrameLayout>
+
+ <!-- The widget frame is required for androidx preferences, but we won't use it. -->
+ <FrameLayout
+ android:id="@android:id/widget_frame"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:layout_alignParentEnd="true"
+ android:layout_toEndOf="@+id/car_ui_secondary_action" />
+ </RelativeLayout>
</LinearLayout>
diff --git a/car_product/app_overlays/car-ui-customizations/res/layout/car_ui_preference_two_action_text.xml b/car_product/app_overlays/car-ui-customizations/res/layout/car_ui_preference_two_action_text.xml
new file mode 100644
index 0000000..cde0c0f
--- /dev/null
+++ b/car_product/app_overlays/car-ui-customizations/res/layout/car_ui_preference_two_action_text.xml
@@ -0,0 +1,106 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal"
+ android:minHeight="?android:attr/listPreferredItemHeightSmall"
+ android:tag="carUiPreference">
+ <com.android.car.ui.uxr.DrawableStateConstraintLayout
+ android:id="@+id/car_ui_first_action_container"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_gravity="center_vertical"
+ android:layout_weight = "1"
+ android:background="?android:attr/selectableItemBackground"
+ android:paddingStart="?android:attr/listPreferredItemPaddingStart"
+ android:paddingEnd="?android:attr/listPreferredItemPaddingEnd">
+
+ <RelativeLayout
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent">
+
+ <com.android.car.ui.uxr.DrawableStateImageView
+ android:id="@android:id/icon"
+ android:layout_width="44dp"
+ android:layout_height="44dp"
+ android:layout_marginEnd="32dp"
+ app:layout_goneMarginEnd="0dp"
+ android:layout_alignParentStart="true"
+ android:layout_centerVertical="true"
+ android:scaleType="fitCenter" />
+
+ <LinearLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ android:layout_toEndOf="@android:id/icon"
+ android:layout_centerVertical="true">
+
+ <com.android.car.ui.uxr.DrawableStateTextView
+ android:id="@android:id/title"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textAlignment="viewStart"
+ android:singleLine="true"
+ android:textAppearance="@style/TextAppearance.CarUi.PreferenceTitle"/>
+
+ <com.android.car.ui.uxr.DrawableStateTextView
+ android:id="@android:id/summary"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textAlignment="viewStart"
+ android:textAppearance="@style/TextAppearance.CarUi.PreferenceSummary"
+ android:maxLines="2"/>
+ </LinearLayout>
+ </RelativeLayout>
+ </com.android.car.ui.uxr.DrawableStateConstraintLayout>
+
+ <View
+ android:id="@+id/car_ui_divider"
+ android:layout_width="1dp"
+ android:layout_height="match_parent"
+ android:layout_gravity="center_vertical"
+ android:layout_marginBottom="16dp"
+ android:layout_marginTop="16dp"
+ android:background="#75ffffff"/>
+
+ <LinearLayout
+ android:id="@+id/car_ui_second_action_container"
+ android:layout_height="match_parent"
+ android:layout_width="wrap_content"
+ android:paddingHorizontal="?android:attr/listPreferredItemPaddingEnd"
+ android:layout_weight = "0">
+
+ <com.android.car.ui.uxr.DrawableStateButton
+ android:id="@+id/car_ui_secondary_action"
+ android:layout_width="wrap_content"
+ android:layout_height="56dp"
+ android:layout_gravity="center"/>
+
+ <!-- The widget frame is required for androidx preferences, but we won't use it. -->
+ <FrameLayout
+ android:id="@android:id/widget_frame"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:layout_alignParentEnd="true"
+ android:layout_toEndOf="@+id/car_ui_secondary_action"/>
+ </LinearLayout>
+</LinearLayout>
diff --git a/car_product/app_overlays/car-ui-customizations/res/layout/car_ui_preference_two_action_text_borderless.xml b/car_product/app_overlays/car-ui-customizations/res/layout/car_ui_preference_two_action_text_borderless.xml
new file mode 100644
index 0000000..2084de2
--- /dev/null
+++ b/car_product/app_overlays/car-ui-customizations/res/layout/car_ui_preference_two_action_text_borderless.xml
@@ -0,0 +1,107 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal"
+ android:minHeight="?android:attr/listPreferredItemHeightSmall"
+ android:tag="carUiPreference">
+ <com.android.car.ui.uxr.DrawableStateConstraintLayout
+ android:id="@+id/car_ui_first_action_container"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_gravity="center_vertical"
+ android:layout_weight = "1"
+ android:background="?android:attr/selectableItemBackground"
+ android:paddingStart="?android:attr/listPreferredItemPaddingStart"
+ android:paddingEnd="?android:attr/listPreferredItemPaddingEnd">
+
+ <RelativeLayout
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent">
+
+ <com.android.car.ui.uxr.DrawableStateImageView
+ android:id="@android:id/icon"
+ android:layout_width="44dp"
+ android:layout_height="44dp"
+ android:layout_marginEnd="32dp"
+ app:layout_goneMarginEnd="0dp"
+ android:layout_alignParentStart="true"
+ android:layout_centerVertical="true"
+ android:scaleType="fitCenter" />
+
+ <LinearLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ android:layout_toEndOf="@android:id/icon"
+ android:layout_centerVertical="true">
+
+ <com.android.car.ui.uxr.DrawableStateTextView
+ android:id="@android:id/title"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textAlignment="viewStart"
+ android:singleLine="true"
+ android:textAppearance="@style/TextAppearance.CarUi.PreferenceTitle"/>
+
+ <com.android.car.ui.uxr.DrawableStateTextView
+ android:id="@android:id/summary"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textAlignment="viewStart"
+ android:textAppearance="@style/TextAppearance.CarUi.PreferenceSummary"
+ android:maxLines="2"/>
+ </LinearLayout>
+ </RelativeLayout>
+ </com.android.car.ui.uxr.DrawableStateConstraintLayout>
+
+ <View
+ android:id="@+id/car_ui_divider"
+ android:layout_width="1dp"
+ android:layout_height="match_parent"
+ android:layout_gravity="center_vertical"
+ android:layout_marginBottom="16dp"
+ android:layout_marginTop="16dp"
+ android:background="#75ffffff"/>
+
+ <LinearLayout
+ android:id="@+id/car_ui_second_action_container"
+ android:layout_height="match_parent"
+ android:layout_width="wrap_content"
+ android:paddingHorizontal="?android:attr/listPreferredItemPaddingEnd"
+ android:layout_weight = "0">
+
+ <com.android.car.ui.uxr.DrawableStateButton
+ android:id="@+id/car_ui_secondary_action"
+ android:layout_width="wrap_content"
+ android:layout_height="56dp"
+ android:layout_gravity="center"
+ style="?android:attr/borderlessButtonStyle"/>
+
+ <!-- The widget frame is required for androidx preferences, but we won't use it. -->
+ <FrameLayout
+ android:id="@android:id/widget_frame"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:layout_alignParentEnd="true"
+ android:layout_toEndOf="@+id/car_ui_secondary_action"/>
+ </LinearLayout>
+</LinearLayout>
diff --git a/car_product/app_overlays/car-ui-customizations/res/values/bools.xml b/car_product/app_overlays/car-ui-customizations/res/values/bools.xml
new file mode 100644
index 0000000..27964ec
--- /dev/null
+++ b/car_product/app_overlays/car-ui-customizations/res/values/bools.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2022 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<resources>
+ <!-- Whether two action switch preference's secondary action focus should outline the switch-->
+ <!-- true outlines switch, false outlines surrounding container (car_ui_secondary_action) -->
+ <bool name="car_ui_preference_two_action_switch_widget_focusable">true</bool>
+</resources>
+
diff --git a/car_product/app_overlays/car-ui-customizations/res/xml/overlays.xml b/car_product/app_overlays/car-ui-customizations/res/xml/overlays.xml
index c0982db..85a6598 100644
--- a/car_product/app_overlays/car-ui-customizations/res/xml/overlays.xml
+++ b/car_product/app_overlays/car-ui-customizations/res/xml/overlays.xml
@@ -37,6 +37,7 @@
<item target="attr/layout_goneMarginTop" value="@attr/layout_goneMarginTop"/>
<item target="attr/state_ux_restricted" value="@attr/state_ux_restricted"/>
+ <item target="bool/car_ui_preference_two_action_switch_widget_focusable" value="@bool/car_ui_preference_two_action_switch_widget_focusable" />
<item target="bool/car_ui_toolbar_logo_fills_nav_icon_space" value="@bool/car_ui_toolbar_logo_fills_nav_icon_space" />
<item target="bool/car_ui_toolbar_menuitem_individual_click_listeners" value="@bool/car_ui_toolbar_menuitem_individual_click_listeners" />
<item target="bool/car_ui_toolbar_nav_icon_reserve_space" value="@bool/car_ui_toolbar_nav_icon_reserve_space" />
@@ -87,7 +88,10 @@
<item target="layout/car_ui_alert_dialog_list" value="@layout/car_ui_alert_dialog_list"/>
<item target="layout/car_ui_base_layout_toolbar" value="@layout/car_ui_base_layout_toolbar"/>
+ <item target="layout/car_ui_preference_two_action_icon" value="@layout/car_ui_preference_two_action_icon"/>
<item target="layout/car_ui_preference_two_action_switch" value="@layout/car_ui_preference_two_action_switch"/>
+ <item target="layout/car_ui_preference_two_action_text" value="@layout/car_ui_preference_two_action_text"/>
+ <item target="layout/car_ui_preference_two_action_text_borderless" value="@layout/car_ui_preference_two_action_text_borderless"/>
<item target="layout/car_ui_preference_widget_switch" value="@layout/car_ui_preference_widget_switch"/>
<item target="layout/car_ui_preference_widget_seekbar" value="@layout/car_ui_preference_widget_seekbar"/>
<item target="layout/car_ui_toolbar_menu_item_primary" value="@layout/car_ui_toolbar_menu_item_primary"/>
diff --git a/car_product/build/car.mk b/car_product/build/car.mk
index 0fc754a..7d5367c 100644
--- a/car_product/build/car.mk
+++ b/car_product/build/car.mk
@@ -18,6 +18,9 @@
PRODUCT_PUBLIC_SEPOLICY_DIRS += packages/services/Car/car_product/sepolicy/public
PRODUCT_PRIVATE_SEPOLICY_DIRS += packages/services/Car/car_product/sepolicy/private
+ifeq ($(ENABLE_CARTELEMETRY_SERVICE), true)
+PRODUCT_PRIVATE_SEPOLICY_DIRS += packages/services/Car/car_product/sepolicy/cartelemetry
+endif
PRODUCT_PACKAGES += \
Bluetooth \
@@ -29,7 +32,6 @@
StatementService \
SystemUpdater
-
PRODUCT_PACKAGES += \
pppd \
screenrecord
@@ -132,7 +134,7 @@
ro.android.car.carservice.package?=com.android.car.updatable
# Update with PLATFORM_VERSION_MINOR_INT update
-PRODUCT_SYSTEM_PROPERTIES += ro.android.car.version.platform_minor=0
+PRODUCT_SYSTEM_PROPERTIES += ro.android.car.version.platform_minor=1
# Automotive specific packages
PRODUCT_PACKAGES += \
diff --git a/car_product/build/preinstalled-packages-product-car-base.xml b/car_product/build/preinstalled-packages-product-car-base.xml
index 7426e5c..8a8fff1 100644
--- a/car_product/build/preinstalled-packages-product-car-base.xml
+++ b/car_product/build/preinstalled-packages-product-car-base.xml
@@ -357,6 +357,7 @@
</install-in-user-type>
<install-in-user-type package="com.android.uwb.resources">
<install-in user-type="FULL" />
+ <install-in user-type="SYSTEM" />
</install-in-user-type>
<!-- Provides ability to configure network preferences. -->
<install-in-user-type package="com.google.android.car.networking.preferenceupdater">
@@ -377,6 +378,7 @@
</install-in-user-type>
<install-in-user-type package="com.android.sdksandbox">
<install-in user-type="FULL" />
+ <install-in user-type="SYSTEM" />
</install-in-user-type>
<!-- Mainline module -->
<install-in-user-type package="com.android.adservices.api">
diff --git a/car_product/car_ui_portrait/OWNERS b/car_product/car_ui_portrait/OWNERS
index 1542e3b..a23e8d3 100644
--- a/car_product/car_ui_portrait/OWNERS
+++ b/car_product/car_ui_portrait/OWNERS
@@ -1,5 +1,8 @@
# Car UI Portrait Reference OWNERS
+abhijoy@google.com
+babakbo@google.com
+calhuang@google.com
priyanksingh@google.com
-juliakawano@google.com
+snekkalapudi@google.com
stenning@google.com
igorr@google.com
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSettings/res/layout/preference_dialog_password_edittext.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSettings/res/layout/preference_dialog_password_edittext.xml
new file mode 100644
index 0000000..677d880
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSettings/res/layout/preference_dialog_password_edittext.xml
@@ -0,0 +1,55 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_marginBottom="@dimen/alert_dialog_margin_bottom"
+ android:layout_marginTop="@dimen/alert_dialog_margin_top"
+ android:orientation="vertical">
+
+ <TextView
+ android:id="@android:id/message"
+ style="?android:attr/textAppearanceSmall"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginBottom="@dimen/alert_dialog_title_margin_bottom"
+ android:layout_marginEnd="@dimen/alert_dialog_title_margin_end"
+ android:layout_marginStart="@dimen/alert_dialog_title_margin_start"
+ android:textColor="?android:attr/textColorSecondary"
+ android:visibility="gone"/>
+
+ <EditText
+ android:id="@android:id/edit"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:textAlignment="viewStart"
+ android:layout_marginEnd="@dimen/alert_dialog_edit_text_margin_end"
+ android:layout_marginStart="@dimen/alert_dialog_edit_text_margin_start"/>
+
+ <CheckBox
+ android:id="@+id/checkbox"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginEnd="@dimen/alert_dialog_password_checkbox_margin_end"
+ android:layout_marginStart="@dimen/alert_dialog_password_checkbox_margin_start"
+ android:layout_marginTop="@dimen/alert_dialog_password_checkbox_margin_top"
+ android:textColor="?android:attr/textColorSecondary"
+ android:text="@string/show_password"/>
+
+</LinearLayout>
\ No newline at end of file
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/AndroidManifest.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/AndroidManifest.xml
index ada5d3f..94fe634 100644
--- a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/AndroidManifest.xml
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/AndroidManifest.xml
@@ -17,12 +17,22 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
package="com.android.systemui"
android:sharedUserId="android.uid.systemui"
coreApp="true">
<!-- Permission to assign Activity to TDA -->
<uses-permission android:name="android.car.permission.CONTROL_CAR_APP_LAUNCH"/>
+ <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
<!-- System permission to call AM.getRunningAppProcesses().
TODO: change this to REAL_GET_TASKS. -->
<uses-permission android:name="android.permission.GET_TASKS"/>
+
+ <!-- Permission to get car driving state -->
+ <uses-permission android:name="android.car.permission.CAR_DRIVING_STATE"/>
+
+ <application
+ tools:replace="android:appComponentFactory"
+ android:appComponentFactory="com.android.systemui.CarUiPortraitSystemUIAppComponentFactory">
+ </application>
</manifest>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/proguard.flags b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/proguard.flags
index 3de0064..1b08c62 100644
--- a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/proguard.flags
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/proguard.flags
@@ -1,4 +1,4 @@
--keep class com.android.systemui.CarUiPortraitSystemUIFactory
+-keep class com.android.systemui.CarUiPortraitSystemUIInitializer
-keep class com.android.systemui.DaggerCarUiPortraitGlobalRootComponent { *; }
-keep class com.android.systemui.DaggerCarUiPortraitGlobalRootComponent$CarUiPortraitSysUIComponentImpl { *; }
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_chevron_down.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_chevron_down.xml
new file mode 100644
index 0000000..c465c7d
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_chevron_down.xml
@@ -0,0 +1,25 @@
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="60dp"
+ android:height="24dp"
+ android:viewportWidth="44"
+ android:viewportHeight="14">
+ <path
+ android:pathData="m 22.000008,13.059101 20.4472,-10.2235994 c 0.494,-0.247 0.6942,-0.8476 0.4472,-1.3416 -0.247,-0.49399998 -0.8476,-0.69419998 -1.3416,-0.4472 L 22.000008,10.823101 2.4472279,1.0467016 c -0.49398,-0.24699998 -1.09466,-0.0468 -1.34165,0.4472 -0.24698503,0.494 -0.04676,1.0946 0.44722,1.3416 z"
+ android:fillColor="@color/immersive_chevron_icon_color"
+ android:fillType="evenOdd"/>
+</vector>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_chevron_up.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_chevron_up.xml
new file mode 100644
index 0000000..acef52c
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_chevron_up.xml
@@ -0,0 +1,25 @@
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="60dp"
+ android:height="24dp"
+ android:viewportWidth="44"
+ android:viewportHeight="14">
+ <path
+ android:pathData="m 22.000008,0.94089839 20.4472,10.22359961 c 0.494,0.247 0.6942,0.8476 0.4472,1.3416 -0.247,0.494 -0.8476,0.6942 -1.3416,0.4472 L 22.000008,3.1768984 2.4472279,12.953298 c -0.49398,0.247 -1.09466,0.0468 -1.34165,-0.4472 -0.24698503,-0.494 -0.04676,-1.0946 0.44722,-1.3416 z"
+ android:fillColor="@color/immersive_chevron_icon_color"
+ android:fillType="evenOdd"/>
+</vector>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/layout/car_bottom_system_bar.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/layout/car_bottom_system_bar.xml
index 984d302..f3bfc3f 100644
--- a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/layout/car_bottom_system_bar.xml
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/layout/car_bottom_system_bar.xml
@@ -48,25 +48,23 @@
android:gravity="center"
android:layoutDirection="ltr">
- <com.android.systemui.car.systembar.CarUiPortraitSystemBarButton
+ <com.android.systemui.car.systembar.CarSystemBarButton
android:id="@+id/grid_nav"
style="@style/SystemBarButton"
android:background="@drawable/nav_bar_app_grid_button_background"
systemui:componentNames="com.android.car.carlauncher/.AppGridActivity"
systemui:icon="@android:color/transparent"
systemui:highlightWhenSelected="true"
- systemui:toggleSelected="true"
systemui:intent="intent:#Intent;action=com.android.car.carlauncher.ACTION_APP_GRID;package=com.android.car.carlauncher;launchFlags=0x24000000;end"
systemui:clearBackStack="true"/>
- <com.android.systemui.car.systembar.CarUiPortraitSystemBarButton
+ <com.android.systemui.car.systembar.CarSystemBarButton
android:id="@+id/standalone_notifications"
style="@style/SystemBarButton"
systemui:componentNames="com.android.car.notification/.CarNotificationCenterActivity"
systemui:packages="com.android.car.notification"
systemui:icon="@drawable/car_ic_notification"
systemui:highlightWhenSelected="true"
- systemui:toggleSelected="true"
systemui:intent="intent:#Intent;component=com.android.car.notification/.CarNotificationCenterActivity;launchFlags=0x24000000;end"
systemui:longIntent="intent:#Intent;action=com.android.car.bugreport.action.START_AUDIO_FIRST;component=com.android.car.bugreport/.BugReportActivity;end"/>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/layout/hvac_panel.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/layout/hvac_panel.xml
new file mode 100644
index 0000000..048ee98
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/layout/hvac_panel.xml
@@ -0,0 +1,185 @@
+<!--
+ ~ Copyright (C) 2022 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.
+ -->
+
+<com.android.systemui.car.hvac.HvacPanelView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ xmlns:systemui="http://schemas.android.com/apk/res-auto"
+ android:id="@+id/hvac_panel"
+ android:orientation="vertical"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:background="@drawable/hvac_panel_bg">
+
+ <androidx.constraintlayout.widget.Guideline
+ android:id="@+id/top_guideline"
+ android:layout_width="match_parent"
+ android:layout_height="1dp"
+ android:orientation="horizontal"
+ app:layout_constraintGuide_begin="@dimen/hvac_panel_buttons_guideline"/>
+
+ <!-- ************************ -->
+ <!-- First group of buttons. -->
+ <!-- ************************ -->
+
+ <com.android.systemui.car.hvac.toggle.HvacBooleanToggleButton
+ android:id="@+id/cooling_on_off"
+ android:layout_width="@dimen/hvac_panel_button_dimen"
+ android:layout_height="@dimen/hvac_panel_long_button_dimen"
+ android:layout_marginLeft="@dimen/hvac_panel_button_external_margin"
+ android:layout_marginTop="@dimen/hvac_panel_button_external_top_margin"
+ android:background="@drawable/hvac_default_background"
+ app:layout_constraintLeft_toLeftOf="parent"
+ app:layout_constraintTop_toBottomOf="@+id/top_guideline"
+ systemui:hvacAreaId="117"
+ systemui:hvacPropertyId="354419973"
+ systemui:hvacToggleOffButtonDrawable="@drawable/ic_ac_off"
+ systemui:hvacToggleOnButtonDrawable="@drawable/ic_ac_on"
+ systemui:hvacTurnOffIfAutoOn="true"/>
+
+ <com.android.systemui.car.hvac.SeatTemperatureLevelButton
+ android:id="@+id/seat_heater_driver_on_off"
+ android:layout_width="@dimen/hvac_panel_button_dimen"
+ android:layout_height="@dimen/hvac_panel_long_button_dimen"
+ android:layout_marginLeft="@dimen/hvac_panel_button_internal_margin"
+ android:layout_marginTop="@dimen/hvac_panel_button_external_top_margin"
+ android:background="@drawable/hvac_heat_background"
+ app:layout_constraintRight_toRightOf="@+id/hvac_on_off"
+ app:layout_constraintTop_toBottomOf="@+id/top_guideline"
+ systemui:hvacAreaId="1"
+ systemui:seatTemperatureType="heating"
+ systemui:seatTemperatureIconDrawableList="@array/hvac_driver_seat_heat_icons"/>
+
+ <com.android.systemui.car.hvac.toggle.HvacBooleanToggleButton
+ android:id="@+id/hvac_on_off"
+ android:layout_width="@dimen/hvac_panel_long_button_dimen"
+ android:layout_height="@dimen/hvac_panel_button_dimen"
+ android:layout_marginBottom="@dimen/hvac_panel_button_external_bottom_margin"
+ android:layout_marginLeft="@dimen/hvac_panel_button_external_margin"
+ android:layout_marginTop="@dimen/hvac_panel_button_internal_margin"
+ android:background="@drawable/hvac_default_background"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintLeft_toLeftOf="parent"
+ app:layout_constraintTop_toBottomOf="@+id/cooling_on_off"
+ systemui:hvacAreaId="117"
+ systemui:hvacPropertyId="354419984"
+ systemui:hvacToggleOffButtonDrawable="@drawable/ic_power_off"
+ systemui:hvacToggleOnButtonDrawable="@drawable/ic_power_on"
+ systemui:hvacTurnOffIfPowerOff="false"/>
+
+ <!-- ************************ -->
+ <!-- Second group of buttons. -->
+ <!-- ************************ -->
+
+ <LinearLayout
+ android:id="@+id/airflow_group"
+ android:layout_width="@dimen/hvac_panel_slider_width"
+ android:layout_height="0dp"
+ android:layout_marginLeft="@dimen/hvac_panel_button_internal_margin"
+ android:layout_marginRight="@dimen/hvac_panel_button_internal_margin"
+ android:layout_marginTop="@dimen/hvac_panel_button_external_top_margin"
+ android:orientation="vertical"
+ app:layout_constraintLeft_toRightOf="@+id/seat_heater_driver_on_off"
+ app:layout_constraintRight_toLeftOf="@+id/seat_heater_passenger_on_off"
+ app:layout_constraintTop_toBottomOf="@+id/top_guideline">
+ <include layout="@layout/fan_direction"/>
+ </LinearLayout>
+
+ <com.android.systemui.car.hvac.custom.FanSpeedSeekBar
+ android:id="@+id/fan_speed_control"
+ android:layout_width="@dimen/hvac_panel_slider_width"
+ android:layout_height="@dimen/hvac_panel_button_dimen"
+ android:layout_marginBottom="@dimen/hvac_panel_button_external_bottom_margin"
+ android:layout_marginLeft="@dimen/hvac_panel_button_internal_margin"
+ android:layout_marginRight="@dimen/hvac_panel_button_internal_margin"
+ android:layout_marginTop="@dimen/hvac_panel_button_internal_margin"
+ android:progressDrawable="@drawable/fan_speed_seek_bar"
+ android:thumb="@drawable/fan_speed_seek_bar_thumb"
+ android:maxHeight="@dimen/hvac_panel_button_dimen"
+ android:minHeight="@dimen/hvac_panel_button_dimen"
+ android:background="@drawable/fan_speed_seek_bar_background"
+ android:splitTrack="false"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintLeft_toLeftOf="@+id/airflow_group"
+ app:layout_constraintRight_toRightOf="@+id/airflow_group"
+ app:layout_constraintTop_toBottomOf="@+id/airflow_group"/>
+
+ <!-- ************************* -->
+ <!-- Third group of buttons. -->
+ <!-- ************************* -->
+
+ <com.android.systemui.car.hvac.SeatTemperatureLevelButton
+ android:id="@+id/seat_heater_passenger_on_off"
+ android:layout_width="@dimen/hvac_panel_button_dimen"
+ android:layout_height="@dimen/hvac_panel_long_button_dimen"
+ android:layout_marginRight="@dimen/hvac_panel_button_internal_margin"
+ android:layout_marginTop="@dimen/hvac_panel_button_external_top_margin"
+ android:background="@drawable/hvac_heat_background"
+ app:layout_constraintLeft_toLeftOf="@+id/hvac_driver_passenger_sync"
+ app:layout_constraintTop_toBottomOf="@+id/top_guideline"
+ systemui:hvacAreaId="4"
+ systemui:seatTemperatureType="heating"
+ systemui:seatTemperatureIconDrawableList="@array/hvac_passenger_seat_heat_icons"/>
+
+ <com.android.systemui.car.hvac.toggle.HvacBooleanToggleButton
+ android:id="@+id/recycle_air_on_off"
+ android:layout_width="@dimen/hvac_panel_button_dimen"
+ android:layout_height="@dimen/hvac_panel_button_dimen"
+ android:layout_marginRight="@dimen/hvac_panel_button_external_margin"
+ android:layout_marginTop="@dimen/hvac_panel_button_external_top_margin"
+ android:background="@drawable/hvac_default_background"
+ app:layout_constraintRight_toRightOf="parent"
+ app:layout_constraintTop_toBottomOf="@+id/top_guideline"
+ systemui:hvacAreaId="117"
+ systemui:hvacPropertyId="354419976"
+ systemui:hvacTurnOffIfAutoOn="true"
+ systemui:hvacToggleOnButtonDrawable="@drawable/ic_recirculate_on"
+ systemui:hvacToggleOffButtonDrawable="@drawable/ic_recirculate_off"/>
+
+ <com.android.systemui.car.hvac.toggle.HvacBooleanToggleButton
+ android:id="@+id/auto_temperature_on_off"
+ android:layout_width="@dimen/hvac_panel_button_dimen"
+ android:layout_height="@dimen/hvac_panel_button_dimen"
+ android:layout_marginRight="@dimen/hvac_panel_button_external_margin"
+ android:layout_marginTop="@dimen/hvac_panel_button_internal_margin"
+ android:background="@drawable/hvac_default_background"
+ app:layout_constraintRight_toRightOf="parent"
+ app:layout_constraintTop_toBottomOf="@+id/recycle_air_on_off"
+ systemui:hvacAreaId="117"
+ systemui:hvacPropertyId="354419978"
+ systemui:hvacToggleOnButtonDrawable="@drawable/ic_auto_on"
+ systemui:hvacToggleOffButtonDrawable="@drawable/ic_auto_off"/>
+
+ <com.android.systemui.car.hvac.toggle.HvacBooleanToggleButton
+ android:id="@+id/hvac_driver_passenger_sync"
+ android:layout_width="@dimen/hvac_panel_long_button_dimen"
+ android:layout_height="@dimen/hvac_panel_button_dimen"
+ android:layout_marginBottom="@dimen/hvac_panel_button_external_bottom_margin"
+ android:layout_marginRight="@dimen/hvac_panel_button_external_margin"
+ android:layout_marginTop="@dimen/hvac_panel_button_internal_margin"
+ android:background="@drawable/hvac_default_background"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintRight_toRightOf="parent"
+ app:layout_constraintTop_toBottomOf="@+id/auto_temperature_on_off"
+ systemui:hvacAreaId="117"
+ systemui:hvacPropertyId="354419977"
+ systemui:hvacToggleOffButtonDrawable="@drawable/ic_sync_off"
+ systemui:hvacToggleOnButtonDrawable="@drawable/ic_sync_on"
+ systemui:hvacTurnOffIfAutoOn="true"/>
+
+ <include
+ layout="@layout/hvac_panel_handle_bar"/>
+</com.android.systemui.car.hvac.HvacPanelView>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/layout/hvac_panel_container.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/layout/hvac_panel_container.xml
deleted file mode 100644
index 86df240..0000000
--- a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/layout/hvac_panel_container.xml
+++ /dev/null
@@ -1,192 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ~ Copyright (C) 2021 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.
- -->
-
-<com.android.car.ui.FocusArea
- xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:app="http://schemas.android.com/apk/res-auto"
- xmlns:systemui="http://schemas.android.com/apk/res-auto"
- android:id="@+id/hvac_panel_container"
- android:layout_width="match_parent"
- android:layout_height="@dimen/hvac_panel_full_expanded_height"
- android:layout_gravity="bottom">
- <com.android.systemui.car.hvac.HvacPanelView
- android:id="@+id/hvac_panel"
- android:orientation="vertical"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:background="@drawable/hvac_panel_bg">
-
- <androidx.constraintlayout.widget.Guideline
- android:id="@+id/top_guideline"
- android:layout_width="match_parent"
- android:layout_height="1dp"
- android:orientation="horizontal"
- app:layout_constraintGuide_begin="@dimen/hvac_panel_buttons_guideline"/>
-
- <!-- ************************ -->
- <!-- First group of buttons. -->
- <!-- ************************ -->
-
- <com.android.systemui.car.hvac.toggle.HvacBooleanToggleButton
- android:id="@+id/cooling_on_off"
- android:layout_width="@dimen/hvac_panel_button_dimen"
- android:layout_height="@dimen/hvac_panel_long_button_dimen"
- android:layout_marginLeft="@dimen/hvac_panel_button_external_margin"
- android:layout_marginTop="@dimen/hvac_panel_button_external_top_margin"
- android:background="@drawable/hvac_default_background"
- app:layout_constraintLeft_toLeftOf="parent"
- app:layout_constraintTop_toBottomOf="@+id/top_guideline"
- systemui:hvacAreaId="117"
- systemui:hvacPropertyId="354419973"
- systemui:hvacToggleOffButtonDrawable="@drawable/ic_ac_off"
- systemui:hvacToggleOnButtonDrawable="@drawable/ic_ac_on"
- systemui:hvacTurnOffIfAutoOn="true"/>
-
- <com.android.systemui.car.hvac.SeatTemperatureLevelButton
- android:id="@+id/seat_heater_driver_on_off"
- android:layout_width="@dimen/hvac_panel_button_dimen"
- android:layout_height="@dimen/hvac_panel_long_button_dimen"
- android:layout_marginLeft="@dimen/hvac_panel_button_internal_margin"
- android:layout_marginTop="@dimen/hvac_panel_button_external_top_margin"
- android:background="@drawable/hvac_heat_background"
- app:layout_constraintRight_toRightOf="@+id/hvac_on_off"
- app:layout_constraintTop_toBottomOf="@+id/top_guideline"
- systemui:hvacAreaId="1"
- systemui:seatTemperatureType="heating"
- systemui:seatTemperatureIconDrawableList="@array/hvac_driver_seat_heat_icons"/>
-
- <com.android.systemui.car.hvac.toggle.HvacBooleanToggleButton
- android:id="@+id/hvac_on_off"
- android:layout_width="@dimen/hvac_panel_long_button_dimen"
- android:layout_height="@dimen/hvac_panel_button_dimen"
- android:layout_marginBottom="@dimen/hvac_panel_button_external_bottom_margin"
- android:layout_marginLeft="@dimen/hvac_panel_button_external_margin"
- android:layout_marginTop="@dimen/hvac_panel_button_internal_margin"
- android:background="@drawable/hvac_default_background"
- app:layout_constraintBottom_toBottomOf="parent"
- app:layout_constraintLeft_toLeftOf="parent"
- app:layout_constraintTop_toBottomOf="@+id/cooling_on_off"
- systemui:hvacAreaId="117"
- systemui:hvacPropertyId="354419984"
- systemui:hvacToggleOffButtonDrawable="@drawable/ic_power_off"
- systemui:hvacToggleOnButtonDrawable="@drawable/ic_power_on"
- systemui:hvacTurnOffIfPowerOff="false"/>
-
- <!-- ************************ -->
- <!-- Second group of buttons. -->
- <!-- ************************ -->
-
- <LinearLayout
- android:id="@+id/airflow_group"
- android:layout_width="@dimen/hvac_panel_slider_width"
- android:layout_height="0dp"
- android:layout_marginLeft="@dimen/hvac_panel_button_internal_margin"
- android:layout_marginRight="@dimen/hvac_panel_button_internal_margin"
- android:layout_marginTop="@dimen/hvac_panel_button_external_top_margin"
- android:orientation="vertical"
- app:layout_constraintLeft_toRightOf="@+id/seat_heater_driver_on_off"
- app:layout_constraintRight_toLeftOf="@+id/seat_heater_passenger_on_off"
- app:layout_constraintTop_toBottomOf="@+id/top_guideline">
- <include layout="@layout/fan_direction"/>
- </LinearLayout>
-
- <com.android.systemui.car.hvac.custom.FanSpeedSeekBar
- android:id="@+id/fan_speed_control"
- android:layout_width="@dimen/hvac_panel_slider_width"
- android:layout_height="@dimen/hvac_panel_button_dimen"
- android:layout_marginBottom="@dimen/hvac_panel_button_external_bottom_margin"
- android:layout_marginLeft="@dimen/hvac_panel_button_internal_margin"
- android:layout_marginRight="@dimen/hvac_panel_button_internal_margin"
- android:layout_marginTop="@dimen/hvac_panel_button_internal_margin"
- android:progressDrawable="@drawable/fan_speed_seek_bar"
- android:thumb="@drawable/fan_speed_seek_bar_thumb"
- android:maxHeight="@dimen/hvac_panel_button_dimen"
- android:minHeight="@dimen/hvac_panel_button_dimen"
- android:background="@drawable/fan_speed_seek_bar_background"
- android:splitTrack="false"
- app:layout_constraintBottom_toBottomOf="parent"
- app:layout_constraintLeft_toLeftOf="@+id/airflow_group"
- app:layout_constraintRight_toRightOf="@+id/airflow_group"
- app:layout_constraintTop_toBottomOf="@+id/airflow_group"/>
-
- <!-- ************************* -->
- <!-- Third group of buttons. -->
- <!-- ************************* -->
-
- <com.android.systemui.car.hvac.SeatTemperatureLevelButton
- android:id="@+id/seat_heater_passenger_on_off"
- android:layout_width="@dimen/hvac_panel_button_dimen"
- android:layout_height="@dimen/hvac_panel_long_button_dimen"
- android:layout_marginRight="@dimen/hvac_panel_button_internal_margin"
- android:layout_marginTop="@dimen/hvac_panel_button_external_top_margin"
- android:background="@drawable/hvac_heat_background"
- app:layout_constraintLeft_toLeftOf="@+id/hvac_driver_passenger_sync"
- app:layout_constraintTop_toBottomOf="@+id/top_guideline"
- systemui:hvacAreaId="4"
- systemui:seatTemperatureType="heating"
- systemui:seatTemperatureIconDrawableList="@array/hvac_passenger_seat_heat_icons"/>
-
- <com.android.systemui.car.hvac.toggle.HvacBooleanToggleButton
- android:id="@+id/recycle_air_on_off"
- android:layout_width="@dimen/hvac_panel_button_dimen"
- android:layout_height="@dimen/hvac_panel_button_dimen"
- android:layout_marginRight="@dimen/hvac_panel_button_external_margin"
- android:layout_marginTop="@dimen/hvac_panel_button_external_top_margin"
- android:background="@drawable/hvac_default_background"
- app:layout_constraintRight_toRightOf="parent"
- app:layout_constraintTop_toBottomOf="@+id/top_guideline"
- systemui:hvacAreaId="117"
- systemui:hvacPropertyId="354419976"
- systemui:hvacTurnOffIfAutoOn="true"
- systemui:hvacToggleOnButtonDrawable="@drawable/ic_recirculate_on"
- systemui:hvacToggleOffButtonDrawable="@drawable/ic_recirculate_off"/>
-
- <com.android.systemui.car.hvac.toggle.HvacBooleanToggleButton
- android:id="@+id/auto_temperature_on_off"
- android:layout_width="@dimen/hvac_panel_button_dimen"
- android:layout_height="@dimen/hvac_panel_button_dimen"
- android:layout_marginRight="@dimen/hvac_panel_button_external_margin"
- android:layout_marginTop="@dimen/hvac_panel_button_internal_margin"
- android:background="@drawable/hvac_default_background"
- app:layout_constraintRight_toRightOf="parent"
- app:layout_constraintTop_toBottomOf="@+id/recycle_air_on_off"
- systemui:hvacAreaId="117"
- systemui:hvacPropertyId="354419978"
- systemui:hvacToggleOnButtonDrawable="@drawable/ic_auto_on"
- systemui:hvacToggleOffButtonDrawable="@drawable/ic_auto_off"/>
-
- <com.android.systemui.car.hvac.toggle.HvacBooleanToggleButton
- android:id="@+id/hvac_driver_passenger_sync"
- android:layout_width="@dimen/hvac_panel_long_button_dimen"
- android:layout_height="@dimen/hvac_panel_button_dimen"
- android:layout_marginBottom="@dimen/hvac_panel_button_external_bottom_margin"
- android:layout_marginRight="@dimen/hvac_panel_button_external_margin"
- android:layout_marginTop="@dimen/hvac_panel_button_internal_margin"
- android:background="@drawable/hvac_default_background"
- app:layout_constraintBottom_toBottomOf="parent"
- app:layout_constraintRight_toRightOf="parent"
- app:layout_constraintTop_toBottomOf="@+id/auto_temperature_on_off"
- systemui:hvacAreaId="117"
- systemui:hvacPropertyId="354419977"
- systemui:hvacToggleOffButtonDrawable="@drawable/ic_sync_off"
- systemui:hvacToggleOnButtonDrawable="@drawable/ic_sync_on"
- systemui:hvacTurnOffIfAutoOn="true"/>
-
- <include
- layout="@layout/hvac_panel_handle_bar"/>
- </com.android.systemui.car.hvac.HvacPanelView>
-</com.android.car.ui.FocusArea>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/layout/title_bar_display_area_view.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/layout/title_bar_display_area_view.xml
index 8fc40b3..e9bd7dc 100644
--- a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/layout/title_bar_display_area_view.xml
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/layout/title_bar_display_area_view.xml
@@ -22,11 +22,19 @@
android:layout_height="@dimen/title_bar_display_area_height"
android:background="@color/title_bar_display_area_background_color">
<View
+ android:id="@+id/title_handle_bar"
android:layout_width="160dp"
android:layout_height="6dp"
android:background="@color/title_bar_display_area_handle_bar_color"
android:layout_marginTop="25dp"
android:layout_centerInParent="true" />
+ <ImageView
+ android:id="@+id/immersive_button"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_centerInParent="true"
+ android:visibility="gone"
+ />
<TextView
android:id="@+id/title"
android:layout_width="wrap_content"
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-night/colors.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-night/colors.xml
index 4e537ba..5bb1983 100644
--- a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-night/colors.xml
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values-night/colors.xml
@@ -21,4 +21,7 @@
<color name="title_bar_display_area_handle_bar_color">#5f6368</color>
<color name="title_bar_display_area_background_color">#000000</color>
+
+ <color name="privacy_chip_light_icon_color">#ffffff</color>
+ <color name="privacy_chip_dark_icon_color">#000000</color>
</resources>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values/colors.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values/colors.xml
index 6992853..a99c825 100644
--- a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values/colors.xml
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values/colors.xml
@@ -27,6 +27,7 @@
<color name="system_bar_background_pill_color">#fff</color>
<color name="status_icon_panel_bg_color">#fff</color>
<color name="status_icon_not_highlighted_color">#202124</color>
+ <color name="status_icon_selected_button_color">#6BF0FF</color>
<color name="status_bar_background_color">#00000000</color>
<drawable name="status_bar_background">@color/status_bar_background_color</drawable>
@@ -46,4 +47,8 @@
<color name="title_bar_display_area_handle_bar_color">#9aa0a6</color>
<color name="title_bar_display_area_background_color">#ffffff</color>
+ <color name="immersive_chevron_icon_color">@color/title_bar_display_area_handle_bar_color</color>
+
+ <color name="privacy_chip_light_icon_color">#000000</color>
+ <color name="privacy_chip_dark_icon_color">#ffffff</color>
</resources>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values/config.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values/config.xml
index fb5c727..43a611b 100644
--- a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values/config.xml
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values/config.xml
@@ -16,10 +16,6 @@
-->
<resources>
- <string name="config_systemUIFactoryComponent" translatable="false">
- com.android.systemui.CarUiPortraitSystemUIFactory
- </string>
-
<!-- Car System UI's OverlayViewsMediator.
Whenever a new class is added, make sure to also add that class to OverlayWindowModule. -->
<string-array name="config_carSystemUIOverlayViewsMediators" translatable="false">
@@ -56,22 +52,21 @@
<item>com.android.car.settings/.FallbackHome</item>
<item>android.car.usb.handler/android.car.usb.handler.UsbHostManagementActivity</item>
<item>com.google.android.car.setupwizard/.CarSetupWizardActivity</item>
+ <item>com.google.android.car.setupwizard/.welcome.WelcomeActivity</item>
<item>com.google.android.car.setupwizard/.libs.uicommon.TrampolineActivity</item>
<item>com.google.android.apps.maps/com.google.android.apps.gmm.car.embedded.auxiliarymap.EmbeddedClusterActivity</item>
</string-array>
- <!-- TODO(b/202413464): Move GAS components to the separate RRO. -->
- <!-- The ComponentName of Assistant VoicePlate Activity, the Activity will be placed in
- VoicePlate TDA -->
- <string name="config_assistantVoicePlateActivity" translatable="false">
- com.google.android.carassistant/com.google.android.libraries.assistant.auto.tng.assistant.ui.activity.AutoAssistantActivity
- </string>
<string name="config_controlBarActivity" translatable="false">
com.android.car.carlauncher/.ControlBarActivity
</string>
+ <string name="config_notificationCenterActivity" translatable="false">
+ com.android.car.notification/.CarNotificationCenterActivity
+ </string>
<!-- default relaunch will be the first item -->
<string-array name="config_backgroundActivities" translatable="false">
<item>com.google.android.apps.maps/com.google.android.maps.MapsActivity</item>
<item>com.android.car.ui.paintbooth/.MainActivity</item>
+ <item>android.accessibilityservice.cts/android.accessibilityservice.cts.AccessibilityGestureDispatchTest$GestureDispatchActivity</item>
</string-array>
</resources>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/CarUiPortraitSysUIComponent.java b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/CarUiPortraitSysUIComponent.java
index 417003f..f1e558d 100644
--- a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/CarUiPortraitSysUIComponent.java
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/CarUiPortraitSysUIComponent.java
@@ -19,6 +19,7 @@
import com.android.systemui.dagger.DependencyProvider;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.SystemUIModule;
+import com.android.systemui.wm.CarUiPortraitDisplaySystemBarsController;
import com.android.wm.shell.RootTaskDisplayAreaOrganizer;
import java.util.Optional;
@@ -47,6 +48,10 @@
CarUiPortraitSysUIComponent.Builder setRootTaskDisplayAreaOrganizer(
Optional<RootTaskDisplayAreaOrganizer> r);
+ @BindsInstance
+ CarUiPortraitSysUIComponent.Builder setCarUiPortraitDisplaySystemBarsController(
+ CarUiPortraitDisplaySystemBarsController c);
+
CarUiPortraitSysUIComponent build();
}
}
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/CarUiPortraitSystemUIAppComponentFactory.java b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/CarUiPortraitSystemUIAppComponentFactory.java
new file mode 100644
index 0000000..104707f
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/CarUiPortraitSystemUIAppComponentFactory.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2022 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.systemui;
+
+import android.content.Context;
+
+/**
+ * Starts up SystemUI using {@link CarSystemUIInitializer}.
+ *
+ * The {@link SystemUIAppComponentFactoryBase} is required for proper SystemUI functionality.
+ *
+ * @see SystemUIAppComponentFactoryBase
+ */
+public class CarUiPortraitSystemUIAppComponentFactory extends SystemUIAppComponentFactoryBase {
+ @Override
+ protected SystemUIInitializer createSystemUIInitializer(Context context) {
+ return new CarUiPortraitSystemUIInitializer(context);
+ }
+}
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/CarUiPortraitSystemUIBinder.java b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/CarUiPortraitSystemUIBinder.java
index 416266a..9d3e21a 100644
--- a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/CarUiPortraitSystemUIBinder.java
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/CarUiPortraitSystemUIBinder.java
@@ -18,6 +18,7 @@
import com.android.systemui.car.displayarea.CarDisplayAreaModule;
import com.android.systemui.car.displayarea.DisplayAreaComponent;
+import com.android.systemui.car.systembar.CarUiPortraitSystemBarModule;
import com.android.systemui.car.window.ExtendedOverlayWindowModule;
import dagger.Binds;
@@ -26,7 +27,8 @@
import dagger.multibindings.IntoMap;
/** Binder for AAECarSystemUI specific {@link CoreStartable} modules and components. */
-@Module(includes = {ExtendedOverlayWindowModule.class, CarDisplayAreaModule.class})
+@Module(includes = {ExtendedOverlayWindowModule.class, CarDisplayAreaModule.class,
+ CarUiPortraitSystemBarModule.class})
abstract class CarUiPortraitSystemUIBinder extends CarSystemUIBinder {
/** Inject into ClusterDisplayController. */
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/CarUiPortraitSystemUIFactory.java b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/CarUiPortraitSystemUIInitializer.java
similarity index 75%
rename from car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/CarUiPortraitSystemUIFactory.java
rename to car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/CarUiPortraitSystemUIInitializer.java
index efc4714..b7e5463 100644
--- a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/CarUiPortraitSystemUIFactory.java
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/CarUiPortraitSystemUIInitializer.java
@@ -30,10 +30,14 @@
/**
* Class factory to provide AAECarSystemUI specific SystemUI components.
*/
-public class CarUiPortraitSystemUIFactory extends CarSystemUIFactory {
+public class CarUiPortraitSystemUIInitializer extends CarSystemUIInitializer {
+ public CarUiPortraitSystemUIInitializer(Context context) {
+ super(context);
+ }
+
@Override
- protected GlobalRootComponent buildGlobalRootComponent(Context context) {
- return DaggerCarUiPortraitGlobalRootComponent.builder().context(context).build();
+ protected GlobalRootComponent.Builder getGlobalRootComponentBuilder() {
+ return DaggerCarUiPortraitGlobalRootComponent.builder();
}
@Override
@@ -43,6 +47,8 @@
boolean isSystemUser = UserHandle.myUserId() == UserHandle.USER_SYSTEM;
return ((CarUiPortraitSysUIComponent.Builder) sysUIBuilder).setRootTaskDisplayAreaOrganizer(
isSystemUser ? Optional.of(carWm.getRootTaskDisplayAreaOrganizer())
- : Optional.empty());
+ : Optional.empty())
+ .setCarUiPortraitDisplaySystemBarsController(
+ carWm.getCarUiPortraitDisplaySystemBarsController());
}
}
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/car/displayarea/CarDisplayAreaAnimationController.java b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/car/displayarea/CarDisplayAreaAnimationController.java
index 58f1855..5000ebc 100644
--- a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/car/displayarea/CarDisplayAreaAnimationController.java
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/car/displayarea/CarDisplayAreaAnimationController.java
@@ -19,7 +19,6 @@
import android.animation.Animator;
import android.animation.ValueAnimator;
import android.content.Context;
-import android.graphics.Rect;
import android.util.ArrayMap;
import android.view.SurfaceControl;
import android.window.WindowContainerToken;
@@ -56,19 +55,19 @@
@SuppressWarnings("unchecked")
CarDisplayAreaTransitionAnimator getAnimator(
WindowContainerToken token, SurfaceControl leash,
- float startPos, float endPos, Rect displayBounds) {
+ float startPos, float endPos) {
CarDisplayAreaTransitionAnimator animator = mAnimatorMap.get(token);
if (animator == null) {
mAnimatorMap.put(token, setupDisplayAreaTransitionAnimator(
CarDisplayAreaTransitionAnimator.ofYOffset(
- token, leash, startPos, endPos, displayBounds)));
+ token, leash, startPos, endPos)));
} else if (animator.isRunning()) {
animator.updateEndValue(endPos);
} else {
animator.cancel();
mAnimatorMap.put(token, setupDisplayAreaTransitionAnimator(
CarDisplayAreaTransitionAnimator.ofYOffset(
- token, leash, startPos, endPos, displayBounds)));
+ token, leash, startPos, endPos)));
}
return mAnimatorMap.get(token);
}
@@ -228,13 +227,11 @@
@VisibleForTesting
static CarDisplayAreaTransitionAnimator ofYOffset(
WindowContainerToken token,
- SurfaceControl leash, float startValue, float endValue, Rect displayBounds) {
+ SurfaceControl leash, float startValue, float endValue) {
return new CarDisplayAreaTransitionAnimator(
token, leash, startValue, endValue) {
- private final Rect mTmpRect = new Rect(displayBounds);
-
private float getCastedFractionValue(float start, float end, float fraction) {
return ((end - start) * fraction) + start;
}
@@ -245,14 +242,8 @@
float start = getStartValue();
float end = getEndValue();
float currentValue = getCastedFractionValue(start, end, fraction);
- mTmpRect.set(
- mTmpRect.left,
- mTmpRect.top + Math.round(currentValue),
- mTmpRect.right,
- mTmpRect.bottom + Math.round(currentValue));
setCurrentValue(currentValue);
getSurfaceTransactionHelper()
- .crop(tx, leash, mTmpRect)
.round(tx, leash)
.translate(tx, leash, currentValue);
tx.apply();
@@ -261,7 +252,6 @@
@Override
void onStartTransaction(SurfaceControl leash, SurfaceControl.Transaction tx) {
getSurfaceTransactionHelper()
- .crop(tx, leash, mTmpRect)
.round(tx, leash)
.translate(tx, leash, getStartValue());
tx.apply();
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/car/displayarea/CarDisplayAreaController.java b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/car/displayarea/CarDisplayAreaController.java
index 6d1bc6b..038de27 100644
--- a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/car/displayarea/CarDisplayAreaController.java
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/car/displayarea/CarDisplayAreaController.java
@@ -30,20 +30,28 @@
import static com.android.systemui.car.displayarea.DisplayAreaComponent.DISPLAY_AREA_VISIBILITY_CHANGED;
import static com.android.systemui.car.displayarea.DisplayAreaComponent.FOREGROUND_DA_STATE.CONTROL_BAR;
import static com.android.systemui.car.displayarea.DisplayAreaComponent.FOREGROUND_DA_STATE.DEFAULT;
+import static com.android.systemui.car.displayarea.DisplayAreaComponent.FOREGROUND_DA_STATE.FULL;
+import static com.android.systemui.car.displayarea.DisplayAreaComponent.FOREGROUND_DA_STATE.FULL_TO_DEFAULT;
import static com.android.systemui.car.displayarea.DisplayAreaComponent.INTENT_EXTRA_IS_DISPLAY_AREA_VISIBLE;
import static com.android.wm.shell.ShellTaskOrganizer.TASK_LISTENER_TYPE_FULLSCREEN;
+import static com.android.wm.shell.ShellTaskOrganizer.TASK_LISTENER_TYPE_MULTI_WINDOW;
import android.app.ActivityManager;
import android.app.ActivityTaskManager;
import android.app.TaskStackListener;
import android.app.UiModeManager;
+import android.car.Car;
+import android.car.app.CarActivityManager;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.graphics.PixelFormat;
import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
import android.os.Binder;
import android.os.Build;
import android.os.Bundle;
@@ -63,6 +71,7 @@
import android.view.WindowInsets;
import android.view.WindowManager;
import android.view.WindowManagerGlobal;
+import android.widget.ImageView;
import android.window.DisplayAreaAppearedInfo;
import android.window.DisplayAreaInfo;
import android.window.WindowContainerToken;
@@ -73,8 +82,13 @@
import com.android.internal.app.AssistUtils;
import com.android.systemui.R;
+import com.android.systemui.car.CarDeviceProvisionedController;
+import com.android.systemui.car.CarDeviceProvisionedListener;
+import com.android.systemui.car.CarServiceProvider;
import com.android.systemui.qs.QSHost;
+import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.policy.ConfigurationController;
+import com.android.systemui.wm.CarUiPortraitDisplaySystemBarsController;
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.common.HandlerExecutor;
import com.android.wm.shell.common.ShellExecutor;
@@ -84,6 +98,7 @@
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
+import java.util.Set;
import javax.inject.Inject;
@@ -91,11 +106,13 @@
* Controls the bounds of the home background, audio bar and application displays. This is a
* singleton class as there should be one controller used to register and control the DA's
*/
-public class CarDisplayAreaController implements ConfigurationController.ConfigurationListener {
+public class CarDisplayAreaController implements ConfigurationController.ConfigurationListener,
+ CommandQueue.Callbacks {
// Layer index of how display areas should be placed. Keeping a gap of 100 if we want to
// add some other display area layers in between in the future.
static final int FOREGROUND_LAYER_INDEX = 0;
+ static final int TITLE_BAR_LAYER_INDEX = 10;
static final int BACKGROUND_LAYER_INDEX = 100;
static final int CONTROL_BAR_LAYER_INDEX = 200;
static final int VOICE_PLATE_LAYER_SHOWN_INDEX = 300;
@@ -116,6 +133,8 @@
private final CarDisplayAreaOrganizer mOrganizer;
private final CarFullscreenTaskListener mCarFullscreenTaskListener;
private final ComponentName mControlBarActivityComponent;
+ private final CarUiPortraitDisplaySystemBarsController mCarUiDisplaySystemBarsController;
+ private final CarDeviceProvisionedController mCarDeviceProvisionedController;
private final List<ComponentName> mBackgroundActivityComponent;
private final HashMap<String, Boolean> mForegroundDAComponentsVisibilityMap;
private final ArraySet<ComponentName> mIgnoreOpeningForegroundDAComponentsSet;
@@ -124,7 +143,6 @@
private final int mEnterExitAnimationDurationMs;
// height of DA hosting the control bar.
private final int mControlBarDisplayHeight;
- private final ComponentName mAssistantVoicePlateActivityName;
private final int mDpiDensity;
private final int mTotalScreenWidth;
// height of DA hosting default apps and covering the maps fully.
@@ -134,6 +152,7 @@
private final int mTitleBarHeight;
private final int mScreenHeightWithoutNavBar;
private final int mTotalScreenHeight;
+ private final ComponentName mNotificationCenterComponent;
private final CarDisplayAreaTouchHandler mCarDisplayAreaTouchHandler;
private final Context mApplicationContext;
private final int mForegroundDisplayTop;
@@ -151,9 +170,26 @@
private boolean mIsHostingDefaultApplicationDisplayAreaVisible;
private WindowManager mTitleBarWindowManager;
private View mTitleBarView;
+ private View mTitleHandleBarView;
+ private ImageView mImmersiveButtonView;
+ private Drawable mChevronUpDrawable;
+ private Drawable mChevronDownDrawable;
private boolean mIsForegroundDaVisible = false;
private boolean mIsForegroundDaFullScreen = false;
+ private boolean mIsForegroundAppRequestingImmersiveMode = false;
private boolean mIsUiModeNight = false;
+ private boolean mIsUserSetupInProgress;
+ // contains the list of activities that will be displayed on feature {@link
+ // CarDisplayAreaOrganizer.FEATURE_VOICE_PLATE)
+ private final Set<ComponentName> mVoicePlateActivitySet;
+ // true if there are activities still pending to be mapped to the voice plate DA as
+ // Car object was not created.
+ private boolean mIsPendingVoicePlateActivityMappingToDA;
+ private boolean mIsControlBarDisplayAreaEmpty = true;
+ private int mControlBarTaskId = -1;
+ private final CarServiceProvider mCarServiceProvider;
+ private Car mCar;
+
/**
* The WindowContext that is registered with {@link #mTitleBarWindowManager} with options to
* specify the {@link RootDisplayArea} to attach the confirmation window.
@@ -166,7 +202,7 @@
boolean homeTaskVisible, boolean clearedTask, boolean wasVisible)
throws RemoteException {
super.onActivityRestartAttempt(task, homeTaskVisible, clearedTask, wasVisible);
- logIfDebuggable("onActivityRestartAttempt " + task);
+ logIfDebuggable("onActivityRestartAttempt: " + task);
updateForegroundDaVisibility(task);
}
@@ -174,26 +210,57 @@
public void onTaskMovedToFront(ActivityManager.RunningTaskInfo taskInfo)
throws RemoteException {
super.onTaskMovedToFront(taskInfo);
- logIfDebuggable("onTaskMovedToFront " + taskInfo);
+ logIfDebuggable("onTaskMovedToFront: " + taskInfo);
updateForegroundDaVisibility(taskInfo);
}
+
+ @Override
+ public void onTaskRemoved(int taskId) throws RemoteException {
+ super.onTaskRemoved(taskId);
+ Log.e(TAG, " onTaskRemoved: " + taskId);
+ // maybe recover
+ if (mActiveTasksOnBackgroundDA != null
+ && mActiveTasksOnBackgroundDA.isEmpty()) {
+ // re launch background app
+ relaunchBackgroundApp();
+ }
+
+ if (mIsControlBarDisplayAreaEmpty && taskId == mControlBarTaskId) {
+ relaunchControlBarApp();
+ }
+ }
};
private final CarFullscreenTaskListener.OnTaskChangeListener mOnTaskChangeListener =
new CarFullscreenTaskListener.OnTaskChangeListener() {
@Override
public void onTaskAppeared(ActivityManager.RunningTaskInfo taskInfo) {
- logIfDebuggable("onTaskAppeared" + taskInfo);
+ logIfDebuggable("onTaskAppeared: " + taskInfo);
updateForegroundDaVisibility(taskInfo);
+ ComponentName componentName = null;
+ if (taskInfo.baseIntent != null) {
+ componentName = taskInfo.baseIntent.getComponent();
+ }
+
+ boolean isBackgroundApp = mBackgroundActivityComponent.contains(componentName);
+ if (isBackgroundApp) {
+ addActiveTaskToBackgroundDAMap(taskInfo.taskId);
+ }
+
+ boolean isControlBarApp = mControlBarActivityComponent.equals(componentName);
+ if (isControlBarApp) {
+ mIsControlBarDisplayAreaEmpty = false;
+ }
}
@Override
public void onTaskVanished(ActivityManager.RunningTaskInfo taskInfo) {
- Log.e(TAG, " onTaskVanished" + taskInfo);
+ Log.e(TAG, " onTaskVanished: " + taskInfo);
boolean isBackgroundApp = false;
boolean isControlBarApp = false;
+ ComponentName cmp = null;
if (taskInfo.baseIntent != null) {
- ComponentName cmp = taskInfo.baseIntent.getComponent();
+ cmp = taskInfo.baseIntent.getComponent();
if (cmp != null) {
isBackgroundApp = mBackgroundActivityComponent.contains(cmp);
isControlBarApp = cmp.equals(mControlBarActivityComponent);
@@ -210,23 +277,19 @@
if (isBackgroundApp && mActiveTasksOnBackgroundDA != null
&& mActiveTasksOnBackgroundDA.isEmpty()) {
// re launch background app
- logIfDebuggable("relaunching background app...");
- Intent mapsIntent = new Intent();
- mapsIntent.setComponent(mBackgroundActivityComponent.get(0));
- mApplicationContext.startActivityAsUser(mapsIntent, UserHandle.CURRENT);
+ relaunchBackgroundApp();
}
if (isControlBarApp) {
// re launch controlbar app
- logIfDebuggable("relaunching controlbar app...");
- Intent controlBarIntent = new Intent();
- controlBarIntent.setComponent(mControlBarActivityComponent);
- mApplicationContext.startActivityAsUser(controlBarIntent,
- UserHandle.CURRENT);
+ mIsControlBarDisplayAreaEmpty = true;
+ relaunchControlBarApp();
}
+
if (taskInfo.displayAreaFeatureId == FEATURE_VOICE_PLATE) {
resetVoicePlateDisplayArea();
}
+
if (mActiveTasksOnForegroundDA == null) {
return;
}
@@ -245,6 +308,65 @@
}
};
+ private final CarUiPortraitDisplaySystemBarsController.Callback
+ mCarUiPortraitDisplaySystemBarsControllerCallback =
+ new CarUiPortraitDisplaySystemBarsController.Callback() {
+ @Override
+ public void onImmersiveRequestedChanged(ComponentName componentName,
+ boolean requested) {
+ // If the requesting application is a voice plate, background, or ignored
+ // package, ignore immersive requests.
+ if (mVoicePlateActivitySet != null && mVoicePlateActivitySet.contains(
+ componentName)) {
+ return;
+ }
+ if (mBackgroundActivityComponent != null
+ && mBackgroundActivityComponent.contains(componentName)) {
+ return;
+ }
+ if (mIgnoreOpeningForegroundDAComponentsSet != null
+ && mIgnoreOpeningForegroundDAComponentsSet.contains(componentName)) {
+ return;
+ }
+
+ if (mTitleHandleBarView != null) {
+ mTitleHandleBarView.setVisibility(requested ? View.GONE : View.VISIBLE);
+ }
+ if (mImmersiveButtonView != null) {
+ mImmersiveButtonView.setVisibility(requested ? View.VISIBLE : View.GONE);
+ }
+ mIsForegroundAppRequestingImmersiveMode = requested;
+ }
+
+ @Override
+ public void onImmersiveStateChanged(boolean immersive) {
+ setImmersive(immersive);
+ }
+ };
+
+ private final CarDeviceProvisionedListener mCarDeviceProvisionedListener =
+ new CarDeviceProvisionedListener() {
+ @Override
+ public void onUserSetupInProgressChanged() {
+ updateUserSetupState();
+ }
+ };
+
+ private void relaunchBackgroundApp() {
+ logIfDebuggable("relaunching background app...");
+ Intent mapsIntent = new Intent();
+ mapsIntent.setComponent(mBackgroundActivityComponent.get(0));
+ mApplicationContext.startActivityAsUser(mapsIntent, UserHandle.CURRENT);
+ }
+
+ private void relaunchControlBarApp() {
+ logIfDebuggable("relaunching controlbar app...");
+ Intent controlBarIntent = new Intent();
+ controlBarIntent.setComponent(mControlBarActivityComponent);
+ mApplicationContext.startActivityAsUser(controlBarIntent,
+ UserHandle.CURRENT);
+ }
+
/**
* Initializes the controller
*/
@@ -254,45 +376,57 @@
ShellExecutor shellExecutor,
ConfigurationController configurationController,
QSHost host,
- CarDisplayAreaOrganizer organizer) {
+ CarServiceProvider carServiceProvider,
+ CarDisplayAreaOrganizer organizer,
+ CarUiPortraitDisplaySystemBarsController carUiPortraitDisplaySystemBarsController,
+ CommandQueue commandQueue,
+ CarDeviceProvisionedController deviceProvisionedController) {
mApplicationContext = applicationContext;
mSyncQueue = syncQueue;
mOrganizer = organizer;
mShellExecutor = shellExecutor;
mCarFullscreenTaskListener = carFullscreenTaskListener;
mConfigurationController = configurationController;
+ mCarServiceProvider = carServiceProvider;
+ mCarUiDisplaySystemBarsController = carUiPortraitDisplaySystemBarsController;
+ mCarDeviceProvisionedController = deviceProvisionedController;
+ mCarUiDisplaySystemBarsController.registerCallback(mApplicationContext.getDisplayId(),
+ mCarUiPortraitDisplaySystemBarsControllerCallback);
mUiModeManager = host.getUserContext().getSystemService(UiModeManager.class);
mConfigurationController.addCallback(this);
mDpiDensity = mOrganizer.getDpiDensity();
- mTotalScreenHeight = applicationContext.getResources().getDimensionPixelSize(
+ Resources resources = applicationContext.getResources();
+ mTotalScreenHeight = resources.getDimensionPixelSize(
R.dimen.total_screen_height);
- mTotalScreenWidth = applicationContext.getResources().getDimensionPixelSize(
+ mTotalScreenWidth = resources.getDimensionPixelSize(
R.dimen.total_screen_width);
- mControlBarDisplayHeight = applicationContext.getResources().getDimensionPixelSize(
+ mControlBarDisplayHeight = resources.getDimensionPixelSize(
R.dimen.control_bar_height);
- mFullDisplayHeight = applicationContext.getResources().getDimensionPixelSize(
+ mFullDisplayHeight = resources.getDimensionPixelSize(
R.dimen.full_app_display_area_height);
- mDefaultDisplayHeight = applicationContext.getResources().getDimensionPixelSize(
+ mDefaultDisplayHeight = resources.getDimensionPixelSize(
R.dimen.default_app_display_area_height);
+ mChevronUpDrawable = resources.getDrawable(R.drawable.ic_chevron_up);
+ mChevronDownDrawable = resources.getDrawable(R.drawable.ic_chevron_down);
mCarDisplayAreaTouchHandler = new CarDisplayAreaTouchHandler(
new HandlerExecutor(applicationContext.getMainThreadHandler()));
mControlBarActivityComponent = ComponentName.unflattenFromString(
- applicationContext.getResources().getString(
+ resources.getString(
R.string.config_controlBarActivity));
+ mNotificationCenterComponent = ComponentName.unflattenFromString(resources.getString(
+ R.string.config_notificationCenterActivity));
mBackgroundActivityComponent = new ArrayList<>();
+ mVoicePlateActivitySet = new ArraySet<>();
String[] backgroundActivities = mApplicationContext.getResources().getStringArray(
R.array.config_backgroundActivities);
for (String backgroundActivity : backgroundActivities) {
mBackgroundActivityComponent
.add(ComponentName.unflattenFromString(backgroundActivity));
}
- mAssistantVoicePlateActivityName = ComponentName.unflattenFromString(
- applicationContext.getResources().getString(
- R.string.config_assistantVoicePlateActivity));
mAssistUtils = new AssistUtils(applicationContext);
+ commandQueue.addCallback(this);
// Get bottom nav bar height.
- Resources resources = applicationContext.getResources();
int navBarHeight = resources.getDimensionPixelSize(
com.android.internal.R.dimen.navigation_bar_height);
if (navBarHeight > 0) {
@@ -321,9 +455,9 @@
mScreenHeightWithoutNavBar = mTotalScreenHeight - mNavBarBounds.height();
mTitleBarHeight = resources.getDimensionPixelSize(R.dimen.title_bar_display_area_height);
- mEnterExitAnimationDurationMs = applicationContext.getResources().getInteger(
+ mEnterExitAnimationDurationMs = resources.getInteger(
R.integer.enter_exit_animation_foreground_display_area_duration_ms);
- mTitleBarDragThreshold = applicationContext.getResources().getDimensionPixelSize(
+ mTitleBarDragThreshold = resources.getDimensionPixelSize(
R.dimen.title_bar_display_area_touch_drag_threshold);
mForegroundDisplayTop = mScreenHeightWithoutNavBar - mDefaultDisplayHeight;
@@ -342,6 +476,31 @@
}
}
+ @Override
+ public void animateExpandNotificationsPanel() {
+ String name = mNotificationCenterComponent.flattenToShortString();
+ if (isHostingDefaultApplicationDisplayAreaVisible()
+ && mForegroundDAComponentsVisibilityMap.containsKey(name)
+ && mForegroundDAComponentsVisibilityMap.get(name)) {
+ // notifications activity already visible
+ return;
+ }
+ Intent intent = new Intent();
+ intent.setComponent(mNotificationCenterComponent);
+ mApplicationContext.startActivityAsUser(intent, UserHandle.CURRENT);
+ }
+
+ @Override
+ public void animateCollapsePanels(int flags, boolean force) {
+ if (mIsForegroundDaFullScreen) {
+ return;
+ }
+ Intent homeActivityIntent = new Intent(Intent.ACTION_MAIN);
+ homeActivityIntent.addCategory(Intent.CATEGORY_HOME);
+ homeActivityIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ mApplicationContext.startActivityAsUser(homeActivityIntent, UserHandle.CURRENT);
+ }
+
/**
* Returns options that specify the {@link RootDisplayArea} to attach the confirmation window.
* {@code null} if the {@code rootDisplayAreaId} is {@link FEATURE_UNDEFINED}.
@@ -369,6 +528,19 @@
taskInfo.baseIntent.getComponent());
}
+ void setControlBarVisibility(boolean show) {
+ SurfaceControl.Transaction tx = new SurfaceControl.Transaction();
+ // Reset the layer for voice plate. This is needed as when the tasks are launched on
+ // other DA's those are brought to the top.
+ tx.setLayer(mControlBarDisplay.getLeash(), CONTROL_BAR_LAYER_INDEX);
+ if (show) {
+ tx.show(mControlBarDisplay.getLeash());
+ } else {
+ tx.hide(mControlBarDisplay.getLeash());
+ }
+ tx.apply(true);
+ }
+
/**
* Show the title bar within a targeted display area using the rootDisplayAreaId.
*/
@@ -377,7 +549,6 @@
mTitleBarView.setVisibility(View.VISIBLE);
return;
}
-
hideTitleBar();
createTitleBar();
}
@@ -386,12 +557,42 @@
LayoutInflater inflater = LayoutInflater.from(mApplicationContext);
mTitleBarView = inflater.inflate(R.layout.title_bar_display_area_view, null, true);
mTitleBarView.setVisibility(View.VISIBLE);
+ mTitleHandleBarView = mTitleBarView.findViewById(R.id.title_handle_bar);
+ mImmersiveButtonView = mTitleBarView.findViewById(R.id.immersive_button);
+ if (mImmersiveButtonView != null) {
+ mImmersiveButtonView.setImageDrawable(
+ mIsForegroundDaFullScreen ? mChevronDownDrawable
+ : mChevronUpDrawable);
+ mImmersiveButtonView.setOnClickListener(v -> {
+ mCarUiDisplaySystemBarsController.requestImmersiveMode(
+ mApplicationContext.getDisplayId(), !mIsForegroundDaFullScreen);
+ });
+ }
// Show the confirmation.
WindowManager.LayoutParams lp = getTitleBarWindowLayoutParams();
getWindowManager().addView(mTitleBarView, lp);
}
+ private void setImmersive(boolean immersive) {
+ if (mIsForegroundDaFullScreen == immersive) {
+ return;
+ }
+ mIsForegroundDaFullScreen = immersive;
+ if (mIsForegroundDaFullScreen) {
+ if (!isForegroundDaVisible()) {
+ makeForegroundDaVisible(true);
+ }
+ startAnimation(FULL);
+ } else {
+ startAnimation(FULL_TO_DEFAULT);
+ }
+ if (mImmersiveButtonView != null) {
+ mImmersiveButtonView.setImageDrawable(
+ mIsForegroundDaFullScreen ? mChevronDownDrawable : mChevronUpDrawable);
+ }
+ }
+
private WindowManager getWindowManager() {
Bundle options = getOptionWithRootDisplayArea(FOREGROUND_DISPLAY_AREA_ROOT);
if (mTitleBarWindowManager == null || mTitleBarWindowContext == null) {
@@ -467,9 +668,13 @@
public void register() {
logIfDebuggable("register organizer and set default bounds");
- ShellTaskOrganizer taskOrganizer = new ShellTaskOrganizer(mShellExecutor,
- mApplicationContext);
+ ShellTaskOrganizer taskOrganizer = new ShellTaskOrganizer(mShellExecutor);
taskOrganizer.addListenerForType(mCarFullscreenTaskListener, TASK_LISTENER_TYPE_FULLSCREEN);
+ // Use the same TaskListener for MULTI_WINDOW windowing mode as there is nothing that has
+ // to be done differently. This is because the tasks are still running in 'fullscreen'
+ // within a DisplayArea.
+ taskOrganizer.addListenerForType(mCarFullscreenTaskListener,
+ TASK_LISTENER_TYPE_MULTI_WINDOW);
taskOrganizer.registerOrganizer();
// Register DA organizer.
@@ -503,6 +708,9 @@
@Override
public void onMove(float x, float y) {
+ if (mIsForegroundAppRequestingImmersiveMode) {
+ return;
+ }
if (y <= mScreenHeightWithoutNavBar - mDefaultDisplayHeight
- mControlBarDisplayHeight) {
return;
@@ -513,14 +721,13 @@
@Override
public void onFinish(float x, float y) {
+ if (mIsForegroundAppRequestingImmersiveMode) {
+ return;
+ }
if (y >= mTitleBarDragThreshold) {
animateToControlBarState((int) y,
mScreenHeightWithoutNavBar + mTitleBarHeight, 0);
mCarDisplayAreaTouchHandler.updateTitleBarVisibility(false);
- Intent intent = new Intent(DISPLAY_AREA_VISIBILITY_CHANGED);
- intent.putExtra(INTENT_EXTRA_IS_DISPLAY_AREA_VISIBLE, false);
- LocalBroadcastManager.getInstance(mApplicationContext).sendBroadcast(
- intent);
} else {
animateToDefaultState((int) y,
mScreenHeightWithoutNavBar - mDefaultDisplayHeight
@@ -530,10 +737,48 @@
});
mCarDisplayAreaTouchHandler.enable(true);
+ mCarServiceProvider.addListener(car -> {
+ mCar = car;
+ if (mIsPendingVoicePlateActivityMappingToDA) {
+ mIsPendingVoicePlateActivityMappingToDA = false;
+ updateVoicePlateActivityMap();
+ }
+ });
+
ActivityTaskManager.getInstance().registerTaskStackListener(
mOnActivityRestartAttemptListener);
// add CarFullscreenTaskListener to control the foreground DA when the task appears.
mCarFullscreenTaskListener.registerOnTaskChangeListener(mOnTaskChangeListener);
+
+ updateUserSetupState();
+ mCarDeviceProvisionedController.addCallback(mCarDeviceProvisionedListener);
+ }
+
+ void updateVoicePlateActivityMap() {
+ Context currentUserContext = mApplicationContext.createContextAsUser(
+ UserHandle.of(ActivityManager.getCurrentUser()), /* flags= */ 0);
+
+ Intent voiceIntent = new Intent(Intent.ACTION_VOICE_ASSIST, /* uri= */ null);
+ List<ResolveInfo> result = currentUserContext.getPackageManager().queryIntentActivities(
+ voiceIntent, PackageManager.MATCH_ALL);
+ if (!result.isEmpty() && mCar == null) {
+ mIsPendingVoicePlateActivityMappingToDA = true;
+ return;
+ } else if (result.isEmpty()) {
+ return;
+ }
+
+ CarActivityManager carAm = (CarActivityManager) mCar.getCarManager(
+ Car.CAR_ACTIVITY_SERVICE);
+ for (ResolveInfo info : result) {
+ if (mVoicePlateActivitySet.add(info.activityInfo.getComponentName())) {
+ logIfDebuggable("adding the following component to voice plate: "
+ + info.activityInfo.getComponentName());
+ CarDisplayAreaUtils.setPersistentActivity(carAm,
+ info.activityInfo.getComponentName(),
+ FEATURE_VOICE_PLATE, "VoicePlate");
+ }
+ }
}
@Override
@@ -562,7 +807,7 @@
// Voice plate will be shown as the top most layer. Also, we don't want to change the
// state of the DA's when voice plate is shown.
- boolean isVoicePlate = componentName.equals(mAssistantVoicePlateActivityName);
+ boolean isVoicePlate = mVoicePlateActivitySet.contains(componentName);
if (isVoicePlate) {
showVoicePlateDisplayArea();
return;
@@ -573,13 +818,13 @@
if (isBackgroundApp) {
// we don't want to change the state of the foreground DA when background
// apps are launched.
- addActiveTaskToBackgroundDAMap(taskInfo.taskId);
return;
}
if (isControlBar) {
// we don't want to change the state of the foreground DA when
// controlbar apps are launched.
+ mControlBarTaskId = taskInfo.taskId;
return;
}
@@ -717,7 +962,7 @@
// TODO(b/188102153): replace to set mForegroundApplicationsDisplay to top.
tx.setLayer(mBackgroundApplicationDisplay.getLeash(), BACKGROUND_LAYER_INDEX);
tx.setLayer(mForegroundApplicationsDisplay.getLeash(), FOREGROUND_LAYER_INDEX);
- tx.setLayer(mTitleBarDisplay.getLeash(), FOREGROUND_LAYER_INDEX);
+ tx.setLayer(mTitleBarDisplay.getLeash(), TITLE_BAR_LAYER_INDEX);
tx.setLayer(mVoicePlateDisplay.getLeash(), VOICE_PLATE_LAYER_SHOWN_INDEX);
tx.setLayer(mControlBarDisplay.getLeash(), CONTROL_BAR_LAYER_INDEX);
@@ -739,6 +984,7 @@
mCarDisplayAreaTouchHandler.enable(false);
ActivityTaskManager.getInstance()
.unregisterTaskStackListener(mOnActivityRestartAttemptListener);
+ mCarDeviceProvisionedController.removeCallback(mCarDeviceProvisionedListener);
mTitleBarView.setVisibility(View.GONE);
}
@@ -749,6 +995,10 @@
* foreground DA hosting default applications will animate to the default set height.
*/
public void startAnimation(DisplayAreaComponent.FOREGROUND_DA_STATE toState) {
+ if (mIsUserSetupInProgress) {
+ // No animations while in setup
+ return;
+ }
// TODO: currently the animations are only bottom/up. Make it more generic animations here.
int fromPos = 0;
int toPos = 0;
@@ -763,7 +1013,17 @@
mCarDisplayAreaTouchHandler.updateTitleBarVisibility(false);
break;
case FULL:
- // TODO: Implement this.
+ fromPos =
+ isForegroundDaVisible() ? mScreenHeightWithoutNavBar - mDefaultDisplayHeight
+ - mControlBarDisplayHeight
+ : mScreenHeightWithoutNavBar + mTitleBarHeight;
+ toPos = mTitleBarHeight;
+ animateToFullState(fromPos, toPos, mEnterExitAnimationDurationMs);
+ break;
+ case FULL_TO_DEFAULT:
+ toPos = mScreenHeightWithoutNavBar - mDefaultDisplayHeight
+ - mControlBarDisplayHeight;
+ animateFullToDefaultState(fromPos, toPos, mEnterExitAnimationDurationMs);
break;
default:
// Foreground DA opens to default height.
@@ -781,6 +1041,7 @@
mScreenHeightWithoutNavBar - mControlBarDisplayHeight;
animate(fromPos, toPos, CONTROL_BAR, durationMs);
mIsHostingDefaultApplicationDisplayAreaVisible = false;
+ broadcastForegroundDAVisibilityChange(false);
}
private void animateToDefaultState(int fromPos, int toPos, int durationMs) {
@@ -791,17 +1052,44 @@
mBackgroundApplicationDisplayBounds.bottom = toPos - mTitleBarHeight;
animate(fromPos, toPos, DEFAULT, durationMs);
mIsHostingDefaultApplicationDisplayAreaVisible = true;
+ broadcastForegroundDAVisibilityChange(true);
if (mCarDisplayAreaTouchHandler != null) {
mCarDisplayAreaTouchHandler.updateTitleBarVisibility(true);
}
}
+ private void animateFullToDefaultState(int fromPos, int toPos, int durationMs) {
+ mBackgroundApplicationDisplayBounds.bottom = toPos - mTitleBarHeight;
+ mIsForegroundDaFullScreen = false;
+ animate(fromPos, toPos, FULL_TO_DEFAULT, durationMs);
+ mIsHostingDefaultApplicationDisplayAreaVisible = true;
+ showTitleBar();
+ setControlBarVisibility(true);
+ if (mCarDisplayAreaTouchHandler != null) {
+ mCarDisplayAreaTouchHandler.updateTitleBarVisibility(true);
+ }
+ }
+
+ private void animateToFullState(int fromPos, int toPos, int durationMs) {
+ if (!isForegroundDaVisible()) {
+ makeForegroundDaVisible(true);
+ }
+ setControlBarVisibility(false);
+ mBackgroundApplicationDisplayBounds.bottom = mTotalScreenHeight;
+ makeForegroundDAFullScreen(/* setFullPosition= */ false, /* showTitleBar= */ true);
+ animate(fromPos, toPos, FULL, durationMs);
+ mIsHostingDefaultApplicationDisplayAreaVisible = true;
+ if (mCarDisplayAreaTouchHandler != null) {
+ mCarDisplayAreaTouchHandler.updateTitleBarVisibility(false);
+ }
+ }
+
private void animate(int fromPos, int toPos, DisplayAreaComponent.FOREGROUND_DA_STATE toState,
int durationMs) {
if (mOrganizer != null) {
mOrganizer.scheduleOffset(fromPos, toPos, mBackgroundApplicationDisplayBounds,
- mBackgroundApplicationDisplay, mForegroundApplicationsDisplay,
- mControlBarDisplay, toState, durationMs);
+ mForegroundApplicationDisplayBounds, mBackgroundApplicationDisplay,
+ mForegroundApplicationsDisplay, mControlBarDisplay, toState, durationMs);
}
}
@@ -816,7 +1104,6 @@
mIsForegroundDaVisible = false;
}
tx.apply(true);
-
}
boolean isForegroundDaVisible() {
@@ -868,14 +1155,14 @@
mCarDisplayAreaTouchHandler.setTitleBarBounds(titleBarBounds);
// Set the initial bounds for first and second displays.
- WindowContainerTransaction wct = new WindowContainerTransaction();
- updateBounds(wct);
- mOrganizer.applyTransaction(wct);
+ updateBounds();
mIsForegroundDaFullScreen = false;
}
/** Updates the default and background display bounds for the given config. */
- private void updateBounds(WindowContainerTransaction wct) {
+ private void updateBounds() {
+ WindowContainerTransaction wct = new WindowContainerTransaction();
+
Rect foregroundApplicationDisplayBound = mForegroundApplicationDisplayBounds;
Rect titleBarDisplayBounds = mTitleBarDisplayBounds;
Rect voicePlateDisplayBounds = mVoicePlateDisplayBounds;
@@ -960,35 +1247,74 @@
wct.setScreenSizeDp(controlBarDisplayToken, controlBarDisplayWidthDp,
controlBarDisplayHeightDp);
wct.setSmallestScreenWidthDp(controlBarDisplayToken, controlBarDisplayWidthDp);
+ mSyncQueue.queue(wct);
mSyncQueue.runInSync(t -> {
+ Rect foregroundApplicationAndTitleBarDisplayBound = new Rect(0, -mTitleBarHeight,
+ foregroundApplicationDisplayBound.width(),
+ foregroundApplicationDisplayBound.height());
+ t.setCrop(mForegroundApplicationsDisplay.getLeash(),
+ foregroundApplicationAndTitleBarDisplayBound);
t.setPosition(mForegroundApplicationsDisplay.getLeash(),
foregroundApplicationDisplayBound.left,
foregroundApplicationDisplayBound.top);
+
+ t.setWindowCrop(mVoicePlateDisplay.getLeash(),
+ voicePlateDisplayBounds.width(), voicePlateDisplayBounds.height());
t.setPosition(mVoicePlateDisplay.getLeash(),
voicePlateDisplayBounds.left,
voicePlateDisplayBounds.top);
+
+ t.setWindowCrop(mTitleBarDisplay.getLeash(),
+ titleBarDisplayBounds.width(), titleBarDisplayBounds.height());
t.setPosition(mTitleBarDisplay.getLeash(),
titleBarDisplayBounds.left, -mTitleBarHeight);
+
+ t.setWindowCrop(mBackgroundApplicationDisplay.getLeash(),
+ backgroundApplicationDisplayBound.width(),
+ backgroundApplicationDisplayBound.height());
t.setPosition(mBackgroundApplicationDisplay.getLeash(),
backgroundApplicationDisplayBound.left,
backgroundApplicationDisplayBound.top);
+
+ t.setWindowCrop(mImeContainerDisplayArea.getLeash(),
+ backgroundApplicationDisplayBound.width(),
+ backgroundApplicationDisplayBound.height());
t.setPosition(mImeContainerDisplayArea.getLeash(),
backgroundApplicationDisplayBound.left,
backgroundApplicationDisplayBound.top);
+
+ t.setWindowCrop(mControlBarDisplay.getLeash(),
+ controlBarDisplayBound.width(), controlBarDisplayBound.height());
t.setPosition(mControlBarDisplay.getLeash(),
controlBarDisplayBound.left,
controlBarDisplayBound.top);
});
}
+ /** Bypass the typical fullscreen flow specifically for SUW */
+ void immersiveForSUW(boolean immersive) {
+ if (immersive) {
+ makeForegroundDAFullScreen(/* setFullPosition= */ true, /* showTitleBar= */ false);
+ } else {
+ setDefaultBounds();
+ }
+ mCarUiDisplaySystemBarsController.requestImmersiveModeForSUW(
+ mApplicationContext.getDisplayId(), immersive);
+ }
+
/**
* Update the bounds of foreground DA to cover full screen.
+ *
+ * @param setFullPosition whether or not the surface's position should be set to the full
+ * position. Setting this to true will set the position to the full
+ * screen while setting to false will use the default display bounds.
*/
- void makeForegroundDAFullScreen() {
+ void makeForegroundDAFullScreen(boolean setFullPosition, boolean showTitleBar) {
logIfDebuggable("make foregroundDA fullscreen");
WindowContainerTransaction wct = new WindowContainerTransaction();
- Rect foregroundApplicationDisplayBounds = new Rect(0, 0, mTotalScreenWidth,
+ int topBound = showTitleBar ? mTitleBarHeight : 0;
+ Rect foregroundApplicationDisplayBounds = new Rect(0, topBound, mTotalScreenWidth,
mTotalScreenHeight);
WindowContainerToken foregroundDisplayToken =
mForegroundApplicationsDisplay.getDisplayAreaInfo().token;
@@ -1004,12 +1330,48 @@
foregroundDisplayHeightDp);
wct.setSmallestScreenWidthDp(foregroundDisplayToken,
Math.min(foregroundDisplayWidthDp, foregroundDisplayHeightDp));
+ mSyncQueue.queue(wct);
mSyncQueue.runInSync(t -> {
- t.setPosition(mForegroundApplicationsDisplay.getLeash(), 0, 0);
+ Rect foregroundApplicationAndTitleBarDisplayBound = new Rect(0, -topBound,
+ foregroundApplicationDisplayBounds.width(),
+ foregroundApplicationDisplayBounds.height());
+ t.setWindowCrop(mForegroundApplicationsDisplay.getLeash(),
+ foregroundApplicationAndTitleBarDisplayBound);
+ if (setFullPosition) {
+ t.setPosition(mForegroundApplicationsDisplay.getLeash(), 0, 0);
+ }
});
- mOrganizer.applyTransaction(wct);
mIsForegroundDaFullScreen = true;
}
+
+ private void broadcastForegroundDAVisibilityChange(boolean visible) {
+ Intent intent = new Intent(DISPLAY_AREA_VISIBILITY_CHANGED);
+ intent.putExtra(INTENT_EXTRA_IS_DISPLAY_AREA_VISIBLE, visible);
+ LocalBroadcastManager.getInstance(mApplicationContext).sendBroadcast(
+ intent);
+ }
+
+ private void updateUserSetupState() {
+ boolean userSetupInProgress = mCarDeviceProvisionedController
+ .isCurrentUserSetupInProgress();
+ if (mIsUserSetupInProgress == userSetupInProgress) {
+ return;
+ }
+ mIsUserSetupInProgress = userSetupInProgress;
+ if (mIsUserSetupInProgress) {
+ if (!isForegroundDaVisible()) {
+ hideTitleBar();
+ makeForegroundDaVisible(true);
+ }
+ setControlBarVisibility(false);
+ immersiveForSUW(true);
+ } else {
+ makeForegroundDaVisible(false);
+ immersiveForSUW(false);
+ showTitleBar();
+ setControlBarVisibility(true);
+ }
+ }
}
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/car/displayarea/CarDisplayAreaModule.java b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/car/displayarea/CarDisplayAreaModule.java
index baf454f..f9753f8 100644
--- a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/car/displayarea/CarDisplayAreaModule.java
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/car/displayarea/CarDisplayAreaModule.java
@@ -19,9 +19,13 @@
import android.content.Context;
import android.os.Handler;
+import com.android.systemui.car.CarDeviceProvisionedController;
+import com.android.systemui.car.CarServiceProvider;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.qs.QSHost;
+import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.policy.ConfigurationController;
+import com.android.systemui.wm.CarUiPortraitDisplaySystemBarsController;
import com.android.wm.shell.common.HandlerExecutor;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.SyncTransactionQueue;
@@ -49,9 +53,14 @@
static CarDisplayAreaController provideCarDisplayAreaController(Context context,
SyncTransactionQueue syncQueue, CarFullscreenTaskListener carFullscreenTaskListener,
ConfigurationController configurationController, QSHost host,
- ShellExecutor mainExecutor, CarDisplayAreaOrganizer organizer) {
+ ShellExecutor mainExecutor, CarServiceProvider carServiceProvider,
+ CarDisplayAreaOrganizer organizer, CarUiPortraitDisplaySystemBarsController
+ carUiPortraitDisplaySystemBarsController, CommandQueue commandQueue,
+ CarDeviceProvisionedController deviceProvisionedController) {
return new CarDisplayAreaController(context, syncQueue, carFullscreenTaskListener,
- mainExecutor, configurationController, host, organizer);
+ mainExecutor, configurationController, host, carServiceProvider, organizer,
+ carUiPortraitDisplaySystemBarsController, commandQueue,
+ deviceProvisionedController);
}
@Provides
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/car/displayarea/CarDisplayAreaOrganizer.java b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/car/displayarea/CarDisplayAreaOrganizer.java
index 390ec38..a883ed3 100644
--- a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/car/displayarea/CarDisplayAreaOrganizer.java
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/car/displayarea/CarDisplayAreaOrganizer.java
@@ -32,7 +32,6 @@
import android.os.Handler;
import android.util.ArrayMap;
import android.util.DisplayMetrics;
-import android.util.Log;
import android.view.Display;
import android.view.SurfaceControl;
import android.window.DisplayAreaAppearedInfo;
@@ -71,16 +70,15 @@
public static final int FEATURE_TITLE_BAR = FEATURE_VENDOR_FIRST + 5;
static final int FEATURE_VOICE_PLATE = FEATURE_VENDOR_FIRST + 6;
private static final String TAG = "CarDisplayAreaOrganizer";
- private final ComponentName mAssistantVoicePlateActivityName;
private final ComponentName mControlBarActivityName;
private final List<ComponentName> mBackGroundActivities;
private final Context mContext;
private final SyncTransactionQueue mTransactionQueue;
+ private final Rect mForegroundApplicationDisplayBounds = new Rect();
private final Rect mBackgroundApplicationDisplayBounds = new Rect();
private final CarDisplayAreaAnimationController mAnimationController;
private final Handler mHandlerForAnimation;
- private final Rect mLastVisualDisplayBounds = new Rect();
private final ArrayMap<WindowContainerToken, SurfaceControl> mDisplayAreaTokenMap =
new ArrayMap();
private final Car.CarServiceLifecycleListener mCarServiceLifecycleListener =
@@ -91,12 +89,10 @@
CarActivityManager carAm = (CarActivityManager) car.getCarManager(
Car.CAR_ACTIVITY_SERVICE);
for (ComponentName backgroundCmp : mBackGroundActivities) {
- setPersistentActivity(carAm, backgroundCmp,
+ CarDisplayAreaUtils.setPersistentActivity(carAm, backgroundCmp,
BACKGROUND_TASK_CONTAINER, "Background");
}
- setPersistentActivity(carAm, mAssistantVoicePlateActivityName,
- FEATURE_VOICE_PLATE, "VoicePlate");
- setPersistentActivity(carAm, mControlBarActivityName,
+ CarDisplayAreaUtils.setPersistentActivity(carAm, mControlBarActivityName,
CONTROL_BAR_DISPLAY_AREA, "ControlBar");
}
}
@@ -119,16 +115,17 @@
.CarDisplayAreaTransitionAnimator animator) {
mIsDisplayAreaAnimating = true;
- SurfaceControl.Transaction tx = new SurfaceControl.Transaction();
- // Update the foreground panel layer index to animate on top of the
- // background DA.
- tx.setLayer(mBackgroundApplicationDisplay.getLeash(),
- BACKGROUND_LAYER_INDEX);
- tx.setLayer(mForegroundApplicationDisplay.getLeash(),
- BACKGROUND_LAYER_INDEX + 1);
- tx.setLayer(mControlBarDisplay.getLeash(),
- CONTROL_BAR_LAYER_INDEX);
- tx.apply(true);
+
+ mTransactionQueue.runInSync(tx -> {
+ // Update the foreground panel layer index to animate on top of the
+ // background DA.
+ tx.setLayer(mBackgroundApplicationDisplay.getLeash(),
+ BACKGROUND_LAYER_INDEX);
+ tx.setLayer(mForegroundApplicationDisplay.getLeash(),
+ BACKGROUND_LAYER_INDEX + 1);
+ tx.setLayer(mControlBarDisplay.getLeash(),
+ CONTROL_BAR_LAYER_INDEX);
+ });
}
@Override
@@ -139,10 +136,13 @@
mAnimationController.removeAnimator(animator.getToken());
if (mAnimationController.isAnimatorsConsumed()) {
WindowContainerTransaction wct = new WindowContainerTransaction();
-
if (mToState == DisplayAreaComponent.FOREGROUND_DA_STATE.DEFAULT) {
// Foreground DA opens to default height.
updateBackgroundDisplayBounds(wct);
+ } else if (mToState
+ == DisplayAreaComponent.FOREGROUND_DA_STATE.FULL_TO_DEFAULT) {
+ updateForegroundDisplayBounds(wct);
+ updateBackgroundDisplayBounds(wct);
}
}
}
@@ -161,9 +161,6 @@
super(executor);
mContext = context;
mTransactionQueue = tx;
- // TODO(b/201712747): Gets the Assistant Activity by resolving the indirect Intent.
- mAssistantVoicePlateActivityName = ComponentName.unflattenFromString(
- context.getResources().getString(R.string.config_assistantVoicePlateActivity));
mControlBarActivityName = ComponentName.unflattenFromString(
context.getResources().getString(R.string.config_controlBarActivity));
mBackGroundActivities = new ArrayList<>();
@@ -180,19 +177,6 @@
mCarServiceLifecycleListener);
}
- private static void setPersistentActivity(CarActivityManager am,
- ComponentName activity, int featureId, String featureName) {
- if (activity == null) {
- Log.e(TAG, "Empty activity for " + featureName + " (" + featureId + ")");
- return;
- }
- int ret = am.setPersistentActivity(activity, DEFAULT_DISPLAY, featureId);
- if (ret != CarActivityManager.RESULT_SUCCESS) {
- Log.e(TAG, "Failed to set PersistentActivity: activity=" + activity
- + ", ret=" + ret);
- }
- }
-
int getDpiDensity() {
if (mDpiDensity != -1) {
return mDpiDensity;
@@ -210,6 +194,25 @@
return mIsDisplayAreaAnimating;
}
+ // WCT will be queued in updateBackgroundDisplayBounds().
+ private void updateForegroundDisplayBounds(WindowContainerTransaction wct) {
+ Rect foregroundApplicationDisplayBound = mForegroundApplicationDisplayBounds;
+ WindowContainerToken foregroundDisplayToken =
+ mForegroundApplicationDisplay.getDisplayAreaInfo().token;
+
+ int foregroundDisplayWidthDp =
+ foregroundApplicationDisplayBound.width() * DisplayMetrics.DENSITY_DEFAULT
+ / getDpiDensity();
+ int foregroundDisplayHeightDp =
+ foregroundApplicationDisplayBound.height() * DisplayMetrics.DENSITY_DEFAULT
+ / getDpiDensity();
+ wct.setBounds(foregroundDisplayToken, foregroundApplicationDisplayBound);
+ wct.setScreenSizeDp(foregroundDisplayToken, foregroundDisplayWidthDp,
+ foregroundDisplayHeightDp);
+ wct.setSmallestScreenWidthDp(foregroundDisplayToken,
+ Math.min(foregroundDisplayWidthDp, foregroundDisplayHeightDp));
+ }
+
private void updateBackgroundDisplayBounds(WindowContainerTransaction wct) {
Rect backgroundApplicationDisplayBound = mBackgroundApplicationDisplayBounds;
WindowContainerToken backgroundDisplayToken =
@@ -226,14 +229,15 @@
backgroundDisplayHeightDp);
wct.setSmallestScreenWidthDp(backgroundDisplayToken,
Math.min(backgroundDisplayWidthDp, backgroundDisplayHeightDp));
+ mTransactionQueue.queue(wct);
mTransactionQueue.runInSync(t -> {
+ // Do not set window crop on backgroundApplicationDisplay. Its windowCrop should remain
+ // full screen so that IME doesn't get cropped.
t.setPosition(mBackgroundApplicationDisplay.getLeash(),
backgroundApplicationDisplayBound.left,
backgroundApplicationDisplayBound.top);
});
-
- applyTransaction(wct);
}
void resetWindowsOffset() {
@@ -256,7 +260,8 @@
* Offsets the windows by a given offset on Y-axis, triggered also from screen rotation.
* Directly perform manipulation/offset on the leash.
*/
- void scheduleOffset(int fromPos, int toPos, Rect finalBackgroundBounds,
+ void scheduleOffset(int fromPos, int toPos,
+ Rect finalBackgroundBounds, Rect finalForegroundBounds,
DisplayAreaAppearedInfo backgroundApplicationDisplay,
DisplayAreaAppearedInfo foregroundDisplay,
DisplayAreaAppearedInfo controlBarDisplay,
@@ -271,6 +276,7 @@
if (token == mBackgroundDisplayToken) {
mBackgroundApplicationDisplayBounds.set(finalBackgroundBounds);
} else if (token == mForegroundDisplayToken) {
+ mForegroundApplicationDisplayBounds.set(finalForegroundBounds);
animateWindows(token, leash, fromPos, toPos, durationMs);
}
});
@@ -285,8 +291,7 @@
float toPos, int durationMs) {
CarDisplayAreaAnimationController.CarDisplayAreaTransitionAnimator
animator =
- mAnimationController.getAnimator(token, leash, fromPos, toPos,
- mLastVisualDisplayBounds);
+ mAnimationController.getAnimator(token, leash, fromPos, toPos);
if (animator != null) {
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/car/displayarea/CarDisplayAreaUtils.java b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/car/displayarea/CarDisplayAreaUtils.java
index 98f29b4..e254f23 100644
--- a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/car/displayarea/CarDisplayAreaUtils.java
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/car/displayarea/CarDisplayAreaUtils.java
@@ -16,6 +16,10 @@
package com.android.systemui.car.displayarea;
+import static android.view.Display.DEFAULT_DISPLAY;
+
+import android.car.app.CarActivityManager;
+import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.res.Resources;
@@ -52,4 +56,17 @@
}
return customPolicyName != null && !customPolicyName.isEmpty();
}
+
+ static void setPersistentActivity(CarActivityManager am,
+ ComponentName activity, int featureId, String featureName) {
+ if (activity == null) {
+ Log.e(TAG, "Empty activity for " + featureName + " (" + featureId + ")");
+ return;
+ }
+ int ret = am.setPersistentActivity(activity, DEFAULT_DISPLAY, featureId);
+ if (ret != CarActivityManager.RESULT_SUCCESS) {
+ Log.e(TAG, "Failed to set PersistentActivity: activity=" + activity
+ + ", ret=" + ret);
+ }
+ }
}
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/car/displayarea/CarFullscreenTaskListener.java b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/car/displayarea/CarFullscreenTaskListener.java
index 3ad4e02..0bedfa5 100644
--- a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/car/displayarea/CarFullscreenTaskListener.java
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/car/displayarea/CarFullscreenTaskListener.java
@@ -38,7 +38,7 @@
@Inject
public CarFullscreenTaskListener(SyncTransactionQueue syncQueue) {
- super(syncQueue, Optional.empty());
+ super(syncQueue);
mOnTaskChangeListeners = new ArrayList<>();
}
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/car/displayarea/DisplayAreaComponent.java b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/car/displayarea/DisplayAreaComponent.java
index 59a41f8..d14287b 100644
--- a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/car/displayarea/DisplayAreaComponent.java
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/car/displayarea/DisplayAreaComponent.java
@@ -16,16 +16,13 @@
package com.android.systemui.car.displayarea;
-import static android.car.settings.CarSettings.Secure.KEY_SETUP_WIZARD_IN_PROGRESS;
-
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Build;
import android.os.Handler;
-import android.os.UserHandle;
-import android.provider.Settings;
+import android.os.Looper;
import android.util.Log;
import com.android.systemui.CoreStartable;
@@ -47,10 +44,8 @@
"EXTRA_IS_DISPLAY_AREA_VISIBLE";
private final CarDisplayAreaController mCarDisplayAreaController;
-
private final Context mContext;
- private int mCurrentUser;
- private boolean mIsDefaultTdaFullScreen;
+ final Handler mHandler = new Handler(Looper.myLooper());
@Inject
public DisplayAreaComponent(Context context,
@@ -67,59 +62,18 @@
// Register the DA's
mCarDisplayAreaController.register();
- // add a receiver to listen to ACTION_USER_SWITCHED when user is switching. We would
- // make the default foreground DA full screen when SUW is being presented to the user.
- IntentFilter filter = new IntentFilter();
- filter.addAction(Intent.ACTION_USER_SWITCHED);
- // When SUW is in progress, make foregroundDA fullscreen.
- final Handler handler = new Handler();
- Runnable runnable = new Runnable() {
- @Override
- public void run() {
- try {
- // ignore user 0 -> USER_SYSTEM and USER_ALL for suw
- if (mCurrentUser != UserHandle.USER_ALL
- && mCurrentUser != UserHandle.USER_SYSTEM) {
- int res = Settings.Secure.getIntForUser(mContext.getContentResolver(),
- KEY_SETUP_WIZARD_IN_PROGRESS, mCurrentUser);
- logIfDebuggable("SUW in progress: " + (res == 1));
- // res == 1 -> SUW in progress
- if (res == 1 && !mIsDefaultTdaFullScreen) {
- if (!mCarDisplayAreaController.isForegroundDaVisible()) {
- mCarDisplayAreaController.hideTitleBar();
- mCarDisplayAreaController.makeForegroundDaVisible(true);
- }
- mCarDisplayAreaController.makeForegroundDAFullScreen();
- mIsDefaultTdaFullScreen = true;
- } else if (res == 0 && mIsDefaultTdaFullScreen) {
- // reset
- mCarDisplayAreaController.makeForegroundDaVisible(false);
- mCarDisplayAreaController.setDefaultBounds();
- mCarDisplayAreaController.showTitleBar();
- mIsDefaultTdaFullScreen = false;
- }
- }
- } catch (Exception e) {
- Log.e(TAG, " error finding SETUP_WIZARD_IN_PROGRESS ", e);
- } finally {
- if (mIsDefaultTdaFullScreen) {
- // only poll this when default TDA is full screen. We want to check
- // the progress of suw every second until the user exits the suw.
- handler.postDelayed(this, 1000);
- }
- }
- }
- };
-
+ IntentFilter packageChangeFilter = new IntentFilter();
+ // add a receiver to listen to ACTION_PACKAGE_ADDED to perform any action when a new
+ // application is installed on the system.
+ packageChangeFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
+ packageChangeFilter.addAction(Intent.ACTION_PACKAGE_REPLACED);
+ packageChangeFilter.addDataScheme("package");
mContext.registerReceiverForAllUsers(new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
- mCurrentUser = intent.getIntExtra(Intent.EXTRA_USER_HANDLE,
- UserHandle.USER_ALL);
- logIfDebuggable("ACTION_USER_SWITCHED received current user: " + mCurrentUser);
- handler.post(runnable);
+ mCarDisplayAreaController.updateVoicePlateActivityMap();
}
- }, filter, null, null);
+ }, packageChangeFilter, null, null);
}
}
@@ -130,7 +84,7 @@
* DEFAULT state where maps are shown above DA for default apps.
*/
public enum FOREGROUND_DA_STATE {
- CONTROL_BAR, DEFAULT, FULL
+ CONTROL_BAR, DEFAULT, FULL, FULL_TO_DEFAULT
}
private static void logIfDebuggable(String message) {
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/car/hvac/AutoDismissHvacPanelOverlayViewController.java b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/car/hvac/AutoDismissHvacPanelOverlayViewController.java
index c710c7b..83a19a8 100644
--- a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/car/hvac/AutoDismissHvacPanelOverlayViewController.java
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/car/hvac/AutoDismissHvacPanelOverlayViewController.java
@@ -19,6 +19,7 @@
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ObjectAnimator;
+import android.app.UiModeManager;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Rect;
@@ -32,6 +33,7 @@
import com.android.systemui.car.window.OverlayViewGlobalStateController;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.wm.shell.animation.FlingAnimationUtils;
import javax.inject.Inject;
@@ -66,9 +68,12 @@
OverlayViewGlobalStateController overlayViewGlobalStateController,
FlingAnimationUtils.Builder flingAnimationUtilsBuilder,
CarDeviceProvisionedController carDeviceProvisionedController,
- @Main Handler handler) {
+ @Main Handler handler,
+ ConfigurationController configurationController,
+ UiModeManager uiModeManager) {
super(context, resources, hvacController, overlayViewGlobalStateController,
- flingAnimationUtilsBuilder, carDeviceProvisionedController);
+ flingAnimationUtilsBuilder, carDeviceProvisionedController, configurationController,
+ uiModeManager);
mResources = resources;
mHandler = handler;
mContext = context;
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/car/hvac/CarUiPortraitTemperatureControlView.java b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/car/hvac/CarUiPortraitTemperatureControlView.java
index 078414d..d8a0b21 100644
--- a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/car/hvac/CarUiPortraitTemperatureControlView.java
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/car/hvac/CarUiPortraitTemperatureControlView.java
@@ -20,7 +20,6 @@
import static android.car.VehiclePropertyIds.HVAC_TEMPERATURE_SET;
import static com.android.systemui.car.hvac.HvacUtils.celsiusToFahrenheit;
-import static com.android.systemui.car.hvac.HvacUtils.fahrenheitToCelsius;
import android.car.hardware.CarPropertyValue;
import android.content.Context;
@@ -60,8 +59,8 @@
private float mMaxTempC;
private String mTemperatureFormatCelsius;
private String mTemperatureFormatFahrenheit;
- private int mTemperatureIncrementFractionCelsius;
- private int mTemperatureIncrementFractionFahrenheit;
+ private float mTemperatureRoundCelsius;
+ private float mTemperatureRoundFahrenheit;
private float mTemperatureIncrementCelsius;
private float mTemperatureIncrementFahrenheit;
private float mCurrentTempC;
@@ -75,14 +74,14 @@
R.string.hvac_temperature_format_celsius);
mTemperatureFormatFahrenheit = getResources().getString(
R.string.hvac_temperature_format_fahrenheit);
- mTemperatureIncrementFractionCelsius = getResources().getInteger(
- R.integer.celsius_increment_fraction);
- mTemperatureIncrementFractionFahrenheit = getResources().getInteger(
- R.integer.fahrenheit_increment_fraction);
- mTemperatureIncrementCelsius =
- 1f / mTemperatureIncrementFractionCelsius;
- mTemperatureIncrementFahrenheit =
- 1f / mTemperatureIncrementFractionFahrenheit;
+ mTemperatureIncrementCelsius = getResources().getFloat(
+ R.fraction.celsius_temperature_increment);
+ mTemperatureIncrementFahrenheit = getResources().getFloat(
+ R.fraction.fahrenheit_temperature_increment);
+ mTemperatureRoundCelsius = getResources().getFloat(
+ R.fraction.celsius_temperature_round);
+ mTemperatureRoundFahrenheit = getResources().getFloat(
+ R.fraction.fahrenheit_temperature_round);
mMinTempC = getResources().getFloat(R.dimen.hvac_min_value_celsius);
mMaxTempC = getResources().getFloat(R.dimen.hvac_max_value_celsius);
@@ -169,12 +168,12 @@
}
@VisibleForTesting
- float getTemperatureIncrementInCelsius() {
+ float getCelsiusTemperatureIncrement() {
return mTemperatureIncrementCelsius;
}
@VisibleForTesting
- float getTemperatureIncrementInFahrenheit() {
+ float getFahrenheitTemperatureIncrement() {
return mTemperatureIncrementFahrenheit;
}
@@ -188,18 +187,12 @@
private void incrementTemperature(boolean increment) {
if (!mPowerOn) return;
- float newTempC;
- if (mDisplayInFahrenheit) {
- float currentTempF = celsiusToFahrenheit(mCurrentTempC);
- float newTempF = increment
- ? currentTempF + mTemperatureIncrementFahrenheit
- : currentTempF - mTemperatureIncrementFahrenheit;
- newTempC = fahrenheitToCelsius(newTempF);
- } else {
- newTempC = increment
- ? mCurrentTempC + mTemperatureIncrementCelsius
- : mCurrentTempC - mTemperatureIncrementCelsius;
- }
+ float tempIncrement = mDisplayInFahrenheit
+ ? mTemperatureIncrementFahrenheit
+ : mTemperatureIncrementCelsius;
+ float newTempC = increment
+ ? mCurrentTempC + tempIncrement
+ : mCurrentTempC - tempIncrement;
setTemperature(newTempC);
}
@@ -207,11 +200,6 @@
private void updateTemperatureView() {
float tempToDisplayUnformatted = roundToClosestFraction(
mDisplayInFahrenheit ? celsiusToFahrenheit(mCurrentTempC) : mCurrentTempC);
- // Set mCurrentTempC value to tempToDisplayUnformatted so their values sync in the next
- // setTemperature call.
- mCurrentTempC = mDisplayInFahrenheit
- ? fahrenheitToCelsius(tempToDisplayUnformatted)
- : tempToDisplayUnformatted;
mTempInDisplay = String.format(
mDisplayInFahrenheit ? mTemperatureFormatFahrenheit : mTemperatureFormatCelsius,
@@ -260,8 +248,8 @@
private float roundToClosestFraction(float rawFloat) {
float incrementFraction = mDisplayInFahrenheit
- ? mTemperatureIncrementFractionFahrenheit
- : mTemperatureIncrementFractionCelsius;
- return Math.round(rawFloat * incrementFraction) / incrementFraction;
+ ? mTemperatureRoundFahrenheit
+ : mTemperatureRoundCelsius;
+ return Math.round(rawFloat / incrementFraction) * incrementFraction;
}
}
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/car/systembar/CarUiPortraitButtonSelectionStateController.java b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/car/systembar/CarUiPortraitButtonSelectionStateController.java
new file mode 100644
index 0000000..0bbd51c
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/car/systembar/CarUiPortraitButtonSelectionStateController.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2022 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.systemui.car.systembar;
+
+import android.app.ActivityTaskManager;
+import android.content.ComponentName;
+import android.content.Context;
+
+import com.android.systemui.dagger.SysUISingleton;
+
+/**
+ * CarSystemBarButtons can optionally have selection state that toggles certain visual indications
+ * based on whether the active application on screen is associated with it. This is basically a
+ * similar concept to a radio button group.
+ *
+ * This class controls the selection state of CarSystemBarButtons that have opted in to have such
+ * selection state-dependent visual indications.
+ */
+@SysUISingleton
+public class CarUiPortraitButtonSelectionStateController extends ButtonSelectionStateController {
+
+ public CarUiPortraitButtonSelectionStateController(Context context) {
+ super(context);
+ }
+
+ @Override
+ protected ComponentName getTopActivity(
+ ActivityTaskManager.RootTaskInfo validTaskInfo) {
+ return validTaskInfo.topActivity;
+ }
+}
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/car/systembar/CarUiPortraitButtonSelectionStateListener.java b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/car/systembar/CarUiPortraitButtonSelectionStateListener.java
new file mode 100644
index 0000000..93dc33c
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/car/systembar/CarUiPortraitButtonSelectionStateListener.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2022 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.systemui.car.systembar;
+
+import static android.view.Display.DEFAULT_DISPLAY;
+
+import static com.android.systemui.car.displayarea.DisplayAreaComponent.DISPLAY_AREA_VISIBILITY_CHANGED;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+
+import androidx.localbroadcastmanager.content.LocalBroadcastManager;
+
+import com.android.systemui.car.displayarea.CarDisplayAreaController;
+
+class CarUiPortraitButtonSelectionStateListener extends ButtonSelectionStateListener {
+
+ private final CarDisplayAreaController mDisplayAreaController;
+
+ CarUiPortraitButtonSelectionStateListener(Context context,
+ ButtonSelectionStateController carSystemButtonController,
+ CarDisplayAreaController displayAreaController) {
+ super(carSystemButtonController);
+ mDisplayAreaController = displayAreaController;
+
+ BroadcastReceiver displayAreaVisibilityReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ onTaskStackChanged();
+ }
+ };
+ LocalBroadcastManager.getInstance(context).registerReceiver(displayAreaVisibilityReceiver,
+ new IntentFilter(DISPLAY_AREA_VISIBILITY_CHANGED));
+ }
+
+ @Override
+ public void onTaskStackChanged() {
+ if (!mDisplayAreaController.isHostingDefaultApplicationDisplayAreaVisible()) {
+ mButtonSelectionStateController.clearAllSelectedButtons(DEFAULT_DISPLAY);
+ return;
+ }
+ super.onTaskStackChanged();
+ }
+}
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/car/systembar/CarUiPortraitSystemBarButton.java b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/car/systembar/CarUiPortraitSystemBarButton.java
deleted file mode 100644
index 0bd70f6..0000000
--- a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/car/systembar/CarUiPortraitSystemBarButton.java
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Copyright (C) 2022 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.systemui.car.systembar;
-
-import static com.android.systemui.car.displayarea.DisplayAreaComponent.DISPLAY_AREA_VISIBILITY_CHANGED;
-import static com.android.systemui.car.displayarea.DisplayAreaComponent.INTENT_EXTRA_IS_DISPLAY_AREA_VISIBLE;
-
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.util.AttributeSet;
-
-import androidx.localbroadcastmanager.content.LocalBroadcastManager;
-
-/** A CarSystemBarButton that controls a display area. */
-public class CarUiPortraitSystemBarButton extends CarSystemBarButton {
-
- public CarUiPortraitSystemBarButton(Context context, AttributeSet attrs) {
- super(context, attrs);
- BroadcastReceiver displayAreaVisibilityReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- boolean isDefaultDAVisible = intent.getBooleanExtra(
- INTENT_EXTRA_IS_DISPLAY_AREA_VISIBLE, true);
- if (getSelected() && !isDefaultDAVisible) {
- context.getMainExecutor().execute(() -> setSelected(/* selected= */ false));
- }
- setSelected(isDefaultDAVisible);
- }
- };
- LocalBroadcastManager.getInstance(context).registerReceiver(displayAreaVisibilityReceiver,
- new IntentFilter(DISPLAY_AREA_VISIBILITY_CHANGED));
- }
-}
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/car/systembar/CarUiPortraitSystemBarModule.java b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/car/systembar/CarUiPortraitSystemBarModule.java
new file mode 100644
index 0000000..5363e13
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/car/systembar/CarUiPortraitSystemBarModule.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2022 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.systemui.car.systembar;
+
+import android.content.Context;
+
+import com.android.systemui.car.dagger.CarSysUIDynamicOverride;
+import com.android.systemui.car.displayarea.CarDisplayAreaController;
+import com.android.systemui.dagger.SysUISingleton;
+
+import dagger.Module;
+import dagger.Provides;
+
+/**
+ * Dagger injection module for {@link CarSystemBar} in CarUiPortraitSystemUI.
+ */
+@Module(includes = {CarSystemBarModule.class})
+public abstract class CarUiPortraitSystemBarModule {
+ @SysUISingleton
+ @Provides
+ @CarSysUIDynamicOverride
+ static ButtonSelectionStateListener provideButtonSelectionStateListener(Context context,
+ ButtonSelectionStateController buttonSelectionStateController,
+ CarDisplayAreaController displayAreaController) {
+ return new CarUiPortraitButtonSelectionStateListener(context,
+ buttonSelectionStateController, displayAreaController);
+ }
+
+ @SysUISingleton
+ @Provides
+ @CarSysUIDynamicOverride
+ static ButtonSelectionStateController provideButtonSelectionStateController(Context context) {
+ return new CarUiPortraitButtonSelectionStateController(context);
+ }
+}
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/wm/CarUiPortraitDisplaySystemBarsController.java b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/wm/CarUiPortraitDisplaySystemBarsController.java
new file mode 100644
index 0000000..e95526b
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/wm/CarUiPortraitDisplaySystemBarsController.java
@@ -0,0 +1,302 @@
+/*
+ * Copyright (C) 2022 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.systemui.wm;
+
+import static android.car.drivingstate.CarDrivingStateEvent.DRIVING_STATE_MOVING;
+import static android.car.drivingstate.CarDrivingStateEvent.DRIVING_STATE_UNKNOWN;
+import static android.view.InsetsState.ITYPE_NAVIGATION_BAR;
+import static android.view.InsetsState.ITYPE_STATUS_BAR;
+
+import android.car.Car;
+import android.car.drivingstate.CarDrivingStateEvent;
+import android.car.drivingstate.CarDrivingStateManager;
+import android.content.ComponentName;
+import android.content.Context;
+import android.os.Handler;
+import android.os.RemoteException;
+import android.util.Slog;
+import android.util.SparseArray;
+import android.view.IWindowManager;
+import android.view.InsetsVisibilities;
+import android.view.WindowInsets;
+import android.widget.Toast;
+
+import com.android.car.ui.R;
+import com.android.wm.shell.common.DisplayController;
+import com.android.wm.shell.common.DisplayInsetsController;
+import com.android.wm.shell.dagger.WMSingleton;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * Controller that expands upon {@link DisplaySystemBarsController} but allows for immersive
+ * mode overrides and notification in other SystemUI classes via the provided methods and callbacks.
+ */
+@WMSingleton
+public class CarUiPortraitDisplaySystemBarsController extends DisplaySystemBarsController {
+ private static final String TAG = "CarUiPortraitDisplaySystemBarsController";
+ private SparseArray<CarUiPortraitPerDisplay> mCarUiPerDisplaySparseArray;
+
+ private int mCurrentDrivingState = DRIVING_STATE_UNKNOWN;
+
+ private final CarDrivingStateManager.CarDrivingStateEventListener mDrivingStateEventListener =
+ this::handleDrivingStateChange;
+
+ public CarUiPortraitDisplaySystemBarsController(Context context,
+ IWindowManager wmService,
+ DisplayController displayController,
+ DisplayInsetsController displayInsetsController,
+ Handler mainHandler) {
+ super(context, wmService, displayController, displayInsetsController, mainHandler);
+
+ Car car = Car.createCar(context);
+ if (car != null) {
+ CarDrivingStateManager mDrivingStateManager =
+ (CarDrivingStateManager) car.getCarManager(Car.CAR_DRIVING_STATE_SERVICE);
+ mDrivingStateManager.registerListener(mDrivingStateEventListener);
+ mDrivingStateEventListener.onDrivingStateChanged(
+ mDrivingStateManager.getCurrentCarDrivingState());
+ } else {
+ Slog.e(TAG, "Failed to initialize car");
+ }
+ }
+
+ @Override
+ public void onDisplayAdded(int displayId) {
+ CarUiPortraitPerDisplay pd = new CarUiPortraitPerDisplay(displayId);
+ pd.register();
+ if (mCarUiPerDisplaySparseArray == null) {
+ mCarUiPerDisplaySparseArray = new SparseArray<>();
+ BarControlPolicy.reloadFromSetting(mContext);
+ BarControlPolicy.registerContentObserver(mContext, mHandler, () -> {
+ int size = mCarUiPerDisplaySparseArray.size();
+ for (int i = 0; i < size; i++) {
+ mCarUiPerDisplaySparseArray.valueAt(i)
+ .updateDisplayWindowRequestedVisibilities();
+ }
+ });
+ }
+ mCarUiPerDisplaySparseArray.put(displayId, pd);
+ }
+
+ @Override
+ public void onDisplayRemoved(int displayId) {
+ CarUiPortraitPerDisplay pd = mCarUiPerDisplaySparseArray.get(displayId);
+ pd.unregister();
+ mCarUiPerDisplaySparseArray.remove(displayId);
+ }
+
+ /**
+ * Request an immersive mode override for a particular display id. This request will override
+ * the usual BarControlPolicy until the package or requested visibilites change.
+ */
+ public void requestImmersiveMode(int displayId, boolean immersive) {
+ CarUiPortraitPerDisplay display = mCarUiPerDisplaySparseArray.get(displayId);
+ if (display == null) {
+ return;
+ }
+ display.setImmersiveMode(immersive);
+ }
+
+ /**
+ * Request an immersive mode override for a particular display id specifically for setup wizard.
+ * This request will override the usual BarControlPolicy and will persist until explicitly
+ * revoked.
+ */
+ public void requestImmersiveModeForSUW(int displayId, boolean immersive) {
+ CarUiPortraitPerDisplay display = mCarUiPerDisplaySparseArray.get(displayId);
+ if (display == null) {
+ return;
+ }
+ display.setImmersiveModeForSUW(immersive);
+ }
+
+ /**
+ * Register an immersive mode callback for a particular display.
+ */
+ public void registerCallback(int displayId, Callback callback) {
+ CarUiPortraitPerDisplay display = mCarUiPerDisplaySparseArray.get(displayId);
+ if (display == null) {
+ return;
+ }
+ display.addCallbackForDisplay(callback);
+ }
+
+ /**
+ * Unregister an immersive mode callback for a particular display.
+ */
+ public void unregisterCallback(int displayId, Callback callback) {
+ CarUiPortraitPerDisplay display = mCarUiPerDisplaySparseArray.get(displayId);
+ if (display == null) {
+ return;
+ }
+ display.removeCallbackForDisplay(callback);
+ }
+
+ private void handleDrivingStateChange(CarDrivingStateEvent event) {
+ mCurrentDrivingState = event.eventValue;
+ if (mCarUiPerDisplaySparseArray != null) {
+ for (int i = 0; i < mCarUiPerDisplaySparseArray.size(); i++) {
+ mCarUiPerDisplaySparseArray.valueAt(i).onDrivingStateChanged();
+ }
+ }
+ }
+
+ class CarUiPortraitPerDisplay extends DisplaySystemBarsController.PerDisplay {
+ private final int[] mImmersiveVisibilities = new int[] {0, WindowInsets.Type.systemBars()};
+ private final List<Callback> mCallbacks = new ArrayList<>();
+ private InsetsVisibilities mWindowRequestedVisibilities;
+ private InsetsVisibilities mAppliedVisibilities = new InsetsVisibilities();
+ private boolean mImmersiveOverride = false;
+ private boolean mImmersiveForSUW = false;
+
+ CarUiPortraitPerDisplay(int displayId) {
+ super(displayId);
+ }
+
+ @Override
+ public void topFocusedWindowChanged(ComponentName component,
+ InsetsVisibilities requestedVisibilities) {
+ boolean requestedVisibilitiesChanged = false;
+ if (requestedVisibilities != null) {
+ if (!requestedVisibilities.equals(mWindowRequestedVisibilities)) {
+ mWindowRequestedVisibilities = requestedVisibilities;
+ boolean immersive = !mWindowRequestedVisibilities.getVisibility(
+ ITYPE_STATUS_BAR) && !mWindowRequestedVisibilities.getVisibility(
+ ITYPE_NAVIGATION_BAR);
+ notifyOnImmersiveRequestedChanged(component, immersive);
+ if (!immersive) {
+ mImmersiveOverride = false;
+ requestedVisibilitiesChanged = true;
+ }
+ }
+ } else if (mWindowRequestedVisibilities != null) {
+ mWindowRequestedVisibilities = null;
+ notifyOnImmersiveRequestedChanged(component, false);
+ requestedVisibilitiesChanged = true;
+ }
+ String packageName = component != null ? component.getPackageName() : null;
+ if (Objects.equals(mPackageName, packageName) && !requestedVisibilitiesChanged) {
+ return;
+ }
+ mPackageName = packageName;
+ mImmersiveOverride = false; // reset override when changing application
+ updateDisplayWindowRequestedVisibilities();
+ }
+
+ @Override
+ protected void updateDisplayWindowRequestedVisibilities() {
+ if (mPackageName == null && !mImmersiveOverride && !mImmersiveForSUW) {
+ return;
+ }
+ int[] barVisibilities = mImmersiveOverride || mImmersiveForSUW
+ ? mImmersiveVisibilities
+ : BarControlPolicy.getBarVisibilities(mPackageName);
+ updateRequestedVisibilities(barVisibilities[0], /* visible= */ true);
+ updateRequestedVisibilities(barVisibilities[1], /* visible= */ false);
+
+ // Return if the requested visibility is already applied.
+ if (mAppliedVisibilities.equals(mRequestedVisibilities)) {
+ return;
+ }
+ mAppliedVisibilities.set(mRequestedVisibilities);
+
+ showInsets(barVisibilities[0], /* fromIme= */ false);
+ hideInsets(barVisibilities[1], /* fromIme= */ false);
+
+ boolean immersiveState = mImmersiveOverride || mImmersiveForSUW || (
+ (barVisibilities[1] & (WindowInsets.Type.statusBars()
+ | WindowInsets.Type.navigationBars())) == (
+ WindowInsets.Type.statusBars() | WindowInsets.Type.navigationBars()));
+ notifyOnImmersiveStateChanged(immersiveState);
+
+ try {
+ mWmService.updateDisplayWindowRequestedVisibilities(mDisplayId,
+ mRequestedVisibilities);
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Unable to update window manager service.");
+ }
+ }
+
+ void setImmersiveMode(boolean immersive) {
+ if (mImmersiveOverride == immersive) {
+ return;
+ }
+ if (immersive && mCurrentDrivingState == DRIVING_STATE_MOVING) {
+ Toast.makeText(mContext,
+ R.string.car_ui_restricted_while_driving, Toast.LENGTH_LONG).show();
+ return;
+ }
+ mImmersiveOverride = immersive;
+ updateDisplayWindowRequestedVisibilities();
+ }
+
+ void setImmersiveModeForSUW(boolean immersive) {
+ if (mImmersiveForSUW == immersive) {
+ return;
+ }
+ mImmersiveForSUW = immersive;
+ updateDisplayWindowRequestedVisibilities();
+ }
+
+ void addCallbackForDisplay(Callback callback) {
+ if (mCallbacks.contains(callback)) return;
+ mCallbacks.add(callback);
+ }
+
+ void removeCallbackForDisplay(Callback callback) {
+ mCallbacks.remove(callback);
+ }
+
+ void notifyOnImmersiveStateChanged(boolean immersive) {
+ for (Callback callback : mCallbacks) {
+ callback.onImmersiveStateChanged(immersive);
+ }
+ }
+
+ void notifyOnImmersiveRequestedChanged(ComponentName component, boolean requested) {
+ for (Callback callback : mCallbacks) {
+ callback.onImmersiveRequestedChanged(component, requested);
+ }
+ }
+
+ void onDrivingStateChanged() {
+ if (mImmersiveOverride && mCurrentDrivingState == DRIVING_STATE_MOVING) {
+ mImmersiveOverride = false;
+ updateDisplayWindowRequestedVisibilities();
+ }
+ }
+ }
+
+ /**
+ * Callback for notifying changes to the immersive and immersive request states.
+ */
+ public interface Callback {
+ /**
+ * Callback triggered when the current package's requested visibilities change has caused
+ * an immersive request change.
+ */
+ void onImmersiveRequestedChanged(ComponentName component, boolean requested);
+
+ /**
+ * Callback triggered when the immersive override state changes.
+ */
+ void onImmersiveStateChanged(boolean immersive);
+ }
+}
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/wmshell/CarUiPortraitWMComponent.java b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/wmshell/CarUiPortraitWMComponent.java
index 4aec44c..6a6f46d 100644
--- a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/wmshell/CarUiPortraitWMComponent.java
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/wmshell/CarUiPortraitWMComponent.java
@@ -16,6 +16,7 @@
package com.android.systemui.wmshell;
+import com.android.systemui.wm.CarUiPortraitDisplaySystemBarsController;
import com.android.wm.shell.RootTaskDisplayAreaOrganizer;
import com.android.wm.shell.dagger.WMSingleton;
@@ -40,4 +41,10 @@
*/
@WMSingleton
RootTaskDisplayAreaOrganizer getRootTaskDisplayAreaOrganizer();
+
+ /**
+ * get CarUiPortraitDisplaySystemBarsController
+ */
+ @WMSingleton
+ CarUiPortraitDisplaySystemBarsController getCarUiPortraitDisplaySystemBarsController();
}
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/wmshell/CarUiPortraitWMShellModule.java b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/wmshell/CarUiPortraitWMShellModule.java
index 0652a98..fdc14c4 100644
--- a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/wmshell/CarUiPortraitWMShellModule.java
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/wmshell/CarUiPortraitWMShellModule.java
@@ -16,16 +16,44 @@
package com.android.systemui.wmshell;
+import android.content.Context;
+import android.os.Handler;
+import android.view.IWindowManager;
+
+import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.wm.CarUiPortraitDisplaySystemBarsController;
+import com.android.systemui.wm.DisplaySystemBarsController;
+import com.android.wm.shell.common.DisplayController;
+import com.android.wm.shell.common.DisplayInsetsController;
import com.android.wm.shell.dagger.WMShellBaseModule;
+import com.android.wm.shell.dagger.WMSingleton;
import com.android.wm.shell.pip.Pip;
import dagger.BindsOptionalOf;
import dagger.Module;
+import dagger.Provides;
/** Provides dependencies from {@link com.android.wm.shell} for CarSystemUI. */
@Module(includes = WMShellBaseModule.class)
public abstract class CarUiPortraitWMShellModule {
+ @WMSingleton
+ @Provides
+ static DisplaySystemBarsController bindDisplaySystemBarsController(
+ CarUiPortraitDisplaySystemBarsController controller) {
+ return controller;
+ }
+
+ @WMSingleton
+ @Provides
+ static CarUiPortraitDisplaySystemBarsController bindCarUiPortraitDisplaySystemBarsController(
+ Context context, IWindowManager wmService, DisplayController displayController,
+ DisplayInsetsController displayInsetsController,
+ @Main Handler mainHandler) {
+ return new CarUiPortraitDisplaySystemBarsController(context, wmService, displayController,
+ displayInsetsController, mainHandler);
+ }
+
@BindsOptionalOf
abstract Pip optionalPip();
}
diff --git a/car_product/car_ui_portrait/rro/CarEvsCameraPreviewAppRRO/Android.bp b/car_product/car_ui_portrait/rro/CarEvsCameraPreviewAppRRO/Android.bp
index 2a4357c..9241b5b 100644
--- a/car_product/car_ui_portrait/rro/CarEvsCameraPreviewAppRRO/Android.bp
+++ b/car_product/car_ui_portrait/rro/CarEvsCameraPreviewAppRRO/Android.bp
@@ -17,7 +17,7 @@
android_app {
name: "CarEvsCameraPreviewAppRRO",
resource_dirs: ["res"],
- platform_apis: true,
+ sdk_version: "current",
certificate: "platform",
aaptflags: [
"--no-resource-deduping",
diff --git a/car_product/car_ui_portrait/rro/CarEvsCameraPreviewAppRRO/AndroidManifest.xml b/car_product/car_ui_portrait/rro/CarEvsCameraPreviewAppRRO/AndroidManifest.xml
index c878ee1..538f066 100644
--- a/car_product/car_ui_portrait/rro/CarEvsCameraPreviewAppRRO/AndroidManifest.xml
+++ b/car_product/car_ui_portrait/rro/CarEvsCameraPreviewAppRRO/AndroidManifest.xml
@@ -21,5 +21,6 @@
android:targetName="CarEvsCameraPreviewApp"
android:targetPackage="com.google.android.car.evs"
android:resourcesMap="@xml/overlays"
- android:isStatic="true"/>
+ android:category="caruiportrait.carevs"
+ android:isStatic="false" />
</manifest>
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitAppsCommonLauncherRRO/Android.bp b/car_product/car_ui_portrait/rro/CarUiPortraitAppsCommonLauncherRRO/Android.bp
new file mode 100644
index 0000000..252f3d9
--- /dev/null
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitAppsCommonLauncherRRO/Android.bp
@@ -0,0 +1,25 @@
+// Copyright (C) 2022 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 {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+android_app {
+ name: "CarUiPortraitLauncherAppsRRO",
+ resource_dirs: ["res"],
+ sdk_version: "current",
+ aaptflags: [
+ "--no-resource-deduping",
+ "--no-resource-removal"
+ ],
+}
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitAppsCommonLauncherRRO/AndroidManifest.xml b/car_product/car_ui_portrait/rro/CarUiPortraitAppsCommonLauncherRRO/AndroidManifest.xml
new file mode 100644
index 0000000..56c2ebd
--- /dev/null
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitAppsCommonLauncherRRO/AndroidManifest.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2022 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.carlauncher.apps.caruiportrait.rro">
+ <application android:hasCode="false"/>
+ <overlay android:priority="20"
+ android:targetName="CarAppsCommon"
+ android:targetPackage="com.android.car.carlauncher"
+ android:resourcesMap="@xml/overlays"
+ android:category="caruiportrait.carappscommon"
+ android:isStatic="false" />
+</manifest>
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitAppsCommonLauncherRRO/res/values/colors.xml b/car_product/car_ui_portrait/rro/CarUiPortraitAppsCommonLauncherRRO/res/values/colors.xml
new file mode 100644
index 0000000..893bb05
--- /dev/null
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitAppsCommonLauncherRRO/res/values/colors.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<resources>
+ <color name="icon_color">#202124</color>
+ <color name="disabled_icon_color">#9AA0A6</color>
+ <color name="action_button_icon_tint">@android:color/transparent</color>
+</resources>
\ No newline at end of file
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitAppsCommonLauncherRRO/res/values/dimens.xml b/car_product/car_ui_portrait/rro/CarUiPortraitAppsCommonLauncherRRO/res/values/dimens.xml
new file mode 100644
index 0000000..cddeded
--- /dev/null
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitAppsCommonLauncherRRO/res/values/dimens.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<resources>
+ <dimen name="control_bar_button_size">84dp</dimen>
+ <dimen name="play_pause_image_size">128dp</dimen>
+</resources>
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitAppsCommonLauncherRRO/res/xml/overlays.xml b/car_product/car_ui_portrait/rro/CarUiPortraitAppsCommonLauncherRRO/res/xml/overlays.xml
new file mode 100644
index 0000000..ff80ddc
--- /dev/null
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitAppsCommonLauncherRRO/res/xml/overlays.xml
@@ -0,0 +1,22 @@
+<!--
+ ~ Copyright (C) 2022 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.
+ -->
+
+<overlay>
+ <item target="dimen/control_bar_button_size" value="@dimen/control_bar_button_size"/>
+ <item target="dimen/play_pause_image_size" value="@dimen/play_pause_image_size"/>
+
+ <item target="color/action_button_icon_tint" value="@color/action_button_icon_tint"/>
+</overlay>
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitCarServiceRRO/Android.bp b/car_product/car_ui_portrait/rro/CarUiPortraitCarServiceRRO/Android.bp
index 28a8c0c..b501dbb 100644
--- a/car_product/car_ui_portrait/rro/CarUiPortraitCarServiceRRO/Android.bp
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitCarServiceRRO/Android.bp
@@ -17,7 +17,7 @@
android_app {
name: "CarUiPortraitCarServiceRRO",
resource_dirs: ["res"],
- platform_apis: true,
+ sdk_version: "current",
aaptflags: [
"--no-resource-deduping",
"--no-resource-removal"
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitCarServiceRRO/AndroidManifest.xml b/car_product/car_ui_portrait/rro/CarUiPortraitCarServiceRRO/AndroidManifest.xml
index 3831ee7..0caf74e 100644
--- a/car_product/car_ui_portrait/rro/CarUiPortraitCarServiceRRO/AndroidManifest.xml
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitCarServiceRRO/AndroidManifest.xml
@@ -20,5 +20,6 @@
<overlay android:priority="20"
android:targetPackage="com.android.car"
android:resourcesMap="@xml/overlays"
- android:isStatic="true" />
+ android:category="caruiportrait.car"
+ android:isStatic="false" />
</manifest>
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitDialerRRO/Android.bp b/car_product/car_ui_portrait/rro/CarUiPortraitDialerRRO/Android.bp
index 92bd722..3041353 100644
--- a/car_product/car_ui_portrait/rro/CarUiPortraitDialerRRO/Android.bp
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitDialerRRO/Android.bp
@@ -17,7 +17,7 @@
android_app {
name: "CarUiPortraitDialerRRO",
resource_dirs: ["res"],
- platform_apis: true,
+ sdk_version: "current",
aaptflags: [
"--no-resource-deduping",
"--no-resource-removal"
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitDialerRRO/AndroidManifest.xml b/car_product/car_ui_portrait/rro/CarUiPortraitDialerRRO/AndroidManifest.xml
index fea65f9..fb99fe0 100644
--- a/car_product/car_ui_portrait/rro/CarUiPortraitDialerRRO/AndroidManifest.xml
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitDialerRRO/AndroidManifest.xml
@@ -21,5 +21,6 @@
android:targetName="CarDialerApp"
android:targetPackage="com.android.car.dialer"
android:resourcesMap="@xml/overlays"
- android:isStatic="true" />
+ android:category="caruiportrait.cardialer"
+ android:isStatic="false" />
</manifest>
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/Android.bp b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/Android.bp
index 255b1cb..a0ee94f 100644
--- a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/Android.bp
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/Android.bp
@@ -17,7 +17,7 @@
android_app {
name: "CarUiPortraitLauncherRRO",
resource_dirs: ["res"],
- platform_apis: true,
+ sdk_version: "current",
aaptflags: [
"--no-resource-deduping",
"--no-resource-removal"
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/AndroidManifest.xml b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/AndroidManifest.xml
index 1969da8..4e0df99 100644
--- a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/AndroidManifest.xml
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/AndroidManifest.xml
@@ -21,5 +21,6 @@
android:targetName="CarLauncher"
android:targetPackage="com.android.car.carlauncher"
android:resourcesMap="@xml/overlays"
- android:isStatic="true" />
+ android:category="caruiportrait.carlauncher"
+ android:isStatic="false" />
</manifest>
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/drawable/default_audio_background.xml b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/drawable/default_audio_background.xml
index c1fd0e9..404d656 100644
--- a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/drawable/default_audio_background.xml
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/drawable/default_audio_background.xml
@@ -21,6 +21,8 @@
<solid android:color="@color/default_audio_background_color"/>
</shape>
</item>
+ <item android:gravity="bottom|right"
+ android:drawable="@drawable/default_audio_background_gradient"/>
<item android:bottom="@dimen/default_audio_icon_padding"
android:top="@dimen/default_audio_icon_padding"
android:right="@dimen/default_audio_icon_padding"
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/drawable/default_audio_background_gradient.xml b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/drawable/default_audio_background_gradient.xml
new file mode 100644
index 0000000..eb9b20f
--- /dev/null
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/drawable/default_audio_background_gradient.xml
@@ -0,0 +1,38 @@
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:aapt="http://schemas.android.com/aapt"
+ android:width="90dp"
+ android:height="91dp"
+ android:viewportWidth="90"
+ android:viewportHeight="91">
+ <path
+ android:pathData="M92.1,35.2L44.4,0.4L22.8,2.5L13.539,6.981C7.683,9.814 3.572,15.318 2.515,21.737L0.3,35.2L8.1,56.5L54.9,94.6H92.1V35.2Z"
+ android:fillAlpha="0.16">
+ <aapt:attr name="android:fillColor">
+ <gradient
+ android:startX="29.7"
+ android:startY="30.7"
+ android:endX="87.6"
+ android:endY="87.1"
+ android:type="linear">
+ <item android:offset="0" android:color="@color/default_audio_background_gradient_start_color"/>
+ <item android:offset="1" android:color="@color/default_audio_background_gradient_end_color"/>
+ </gradient>
+ </aapt:attr>
+ </path>
+</vector>
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/layout/descriptive_text.xml b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/layout/descriptive_text.xml
index 1c55cca..4fa30fd 100644
--- a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/layout/descriptive_text.xml
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/layout/descriptive_text.xml
@@ -15,10 +15,12 @@
~ limitations under the License.
-->
-<RelativeLayout
+<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="vertical"
+ android:layout_width="match_parent"
android:layout_height="match_parent"
- android:layout_width="match_parent">
+ android:gravity="center_vertical">
<!-- optional_image is required by the HomeCardFragment. Intentionally not shown by setting
0 height and width. -->
@@ -32,42 +34,37 @@
<TextView
android:id="@+id/primary_text"
android:layout_height="wrap_content"
- android:layout_width="0dp"
- android:singleLine="true"
- android:textAppearance="?android:attr/textAppearanceLarge"
- android:layout_alignParentStart="true"
- android:layout_alignParentEnd="true"
- android:layout_alignParentTop="true"
- android:layout_marginTop="@dimen/descriptive_text_vertical_margin"/>
-
- <Chronometer
- android:id="@+id/optional_timer"
- android:visibility="gone"
- android:layout_height="wrap_content"
- android:layout_width="wrap_content"
- android:textAppearance="?android:attr/textAppearanceSmall"
- android:layout_alignParentStart="true"
- android:layout_alignParentBottom="true"
- android:layout_marginBottom="@dimen/descriptive_text_vertical_margin"/>
-
- <TextView
- android:id="@+id/optional_timer_separator"
- android:visibility="gone"
- android:layout_height="wrap_content"
- android:layout_width="wrap_content"
- android:text="@string/ongoing_call_duration_text_separator"
- android:textAppearance="?android:attr/textAppearanceSmall"
- android:layout_toEndOf="@id/optional_timer"
- android:layout_alignParentBottom="true"
- android:layout_marginBottom="@dimen/descriptive_text_vertical_margin"/>
-
- <TextView
- android:id="@+id/secondary_text"
- android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:singleLine="true"
- android:textAppearance="?android:attr/textAppearanceSmall"
- android:layout_toEndOf="@id/optional_timer_separator"
- android:layout_alignParentBottom="true"
- android:layout_marginBottom="@dimen/descriptive_text_vertical_margin"/>
-</RelativeLayout>
\ No newline at end of file
+ android:textAppearance="?android:attr/textAppearanceLarge"/>
+
+ <LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_height="wrap_content"
+ android:layout_width="match_parent"
+ android:orientation="horizontal"
+ android:gravity="start">
+
+ <Chronometer
+ android:id="@+id/optional_timer"
+ android:visibility="gone"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:textAppearance="?android:attr/textAppearanceSmall"/>
+
+ <TextView
+ android:id="@+id/optional_timer_separator"
+ android:visibility="gone"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:text="@string/ongoing_call_duration_text_separator"
+ android:textAppearance="?android:attr/textAppearanceSmall"/>
+
+ <TextView
+ android:id="@+id/secondary_text"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:singleLine="true"
+ android:textAppearance="?android:attr/textAppearanceSmall"/>
+ </LinearLayout>
+</LinearLayout>
\ No newline at end of file
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-night/colors.xml b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-night/colors.xml
index 5b43fa3..6b5e340 100644
--- a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-night/colors.xml
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values-night/colors.xml
@@ -18,6 +18,8 @@
<resources>
<color name="default_audio_background_image_color">#515355</color>
<color name="default_audio_background_color">#1E2125</color>
+ <color name="default_audio_background_gradient_start_color">#99000000</color>
+ <color name="default_audio_background_gradient_end_color">#00000000</color>
<color name="icon_tint">#e8eaed</color>
</resources>
\ No newline at end of file
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values/colors.xml b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values/colors.xml
index 562b43e..479c929 100644
--- a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values/colors.xml
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values/colors.xml
@@ -18,6 +18,8 @@
<resources>
<color name="default_audio_background_image_color">#DADCE0</color>
<color name="default_audio_background_color">#BDC1C6</color>
+ <color name="default_audio_background_gradient_start_color">#FF000000</color>
+ <color name="default_audio_background_gradient_end_color">#00000000</color>
<color name="icon_tint">#000000</color>
<color name="media_button_tint">@color/icon_tint</color>
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values/strings.xml b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values/strings.xml
index 2c0a471..70257fd 100644
--- a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values/strings.xml
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values/strings.xml
@@ -17,4 +17,5 @@
<resources>
<string name="ongoing_call_duration_text_separator"> • </string>
+ <string name="default_media_song_title">Select media</string>
</resources>
\ No newline at end of file
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/xml/overlays.xml b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/xml/overlays.xml
index ccdf76d..fba0f2c 100644
--- a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/xml/overlays.xml
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/xml/overlays.xml
@@ -60,4 +60,6 @@
<item target="drawable/default_audio_background" value="@drawable/default_audio_background"/>
<item target="array/config_homeCardModuleClasses" value="@array/config_homeCardModuleClasses"/>
+
+ <item target="string/default_media_song_title" value="@string/default_media_song_title"/>
</overlay>
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitMediaCommonLauncherRRO/Android.bp b/car_product/car_ui_portrait/rro/CarUiPortraitMediaCommonLauncherRRO/Android.bp
new file mode 100644
index 0000000..e4345e9
--- /dev/null
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitMediaCommonLauncherRRO/Android.bp
@@ -0,0 +1,25 @@
+// Copyright (C) 2022 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 {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+android_app {
+ name: "CarUiPortraitLauncherMediaRRO",
+ resource_dirs: ["res"],
+ sdk_version: "current",
+ aaptflags: [
+ "--no-resource-deduping",
+ "--no-resource-removal"
+ ],
+}
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitMediaCommonLauncherRRO/AndroidManifest.xml b/car_product/car_ui_portrait/rro/CarUiPortraitMediaCommonLauncherRRO/AndroidManifest.xml
new file mode 100644
index 0000000..1b2d157
--- /dev/null
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitMediaCommonLauncherRRO/AndroidManifest.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2022 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.carlauncher.media.caruiportrait.rro">
+ <application android:hasCode="false"/>
+ <overlay android:priority="20"
+ android:targetName="CarMediaCommon"
+ android:targetPackage="com.android.car.carlauncher"
+ android:resourcesMap="@xml/overlays"
+ android:category="caruiportrait.launcher.mediacommon"
+ android:isStatic="false" />
+</manifest>
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitMediaCommonLauncherRRO/res/drawable/ic_pause.xml b/car_product/car_ui_portrait/rro/CarUiPortraitMediaCommonLauncherRRO/res/drawable/ic_pause.xml
new file mode 100644
index 0000000..ca033a9
--- /dev/null
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitMediaCommonLauncherRRO/res/drawable/ic_pause.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+ ~ Copyright (C) 2022 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.
+ -->
+
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
+ <item>
+ <shape android:shape="oval">
+ <solid android:color="@color/play_pause_ic_bg_color"/>
+ </shape>
+ </item>
+ <item android:gravity="center"
+ android:drawable="@drawable/pause_icon"/>
+</layer-list>
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitMediaCommonLauncherRRO/res/drawable/ic_play_arrow.xml b/car_product/car_ui_portrait/rro/CarUiPortraitMediaCommonLauncherRRO/res/drawable/ic_play_arrow.xml
new file mode 100644
index 0000000..fb114fd
--- /dev/null
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitMediaCommonLauncherRRO/res/drawable/ic_play_arrow.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+ ~ Copyright (C) 2022 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.
+ -->
+
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
+ <item>
+ <shape android:shape="rectangle">
+ <solid android:color="@color/play_pause_ic_bg_color"/>
+ <corners android:radius="@dimen/play_pause_button_bg_radius"/>
+ </shape>
+ </item>
+ <item android:gravity="center"
+ android:drawable="@drawable/play_arrow_icon"/>
+</layer-list>
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitMediaCommonLauncherRRO/res/drawable/ic_play_arrow_off.xml b/car_product/car_ui_portrait/rro/CarUiPortraitMediaCommonLauncherRRO/res/drawable/ic_play_arrow_off.xml
new file mode 100644
index 0000000..3f006bf
--- /dev/null
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitMediaCommonLauncherRRO/res/drawable/ic_play_arrow_off.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+ ~ Copyright (C) 2022 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.
+ -->
+
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
+ <item>
+ <shape android:shape="rectangle">
+ <solid android:color="@color/play_pause_ic_bg_color"/>
+ <corners android:radius="@dimen/play_pause_button_bg_radius"/>
+ </shape>
+ </item>
+ <item android:gravity="center"
+ android:drawable="@drawable/play_arrow_off_icon"/>
+</layer-list>
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitMediaCommonLauncherRRO/res/drawable/ic_skip_next.xml b/car_product/car_ui_portrait/rro/CarUiPortraitMediaCommonLauncherRRO/res/drawable/ic_skip_next.xml
new file mode 100644
index 0000000..f3c2743
--- /dev/null
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitMediaCommonLauncherRRO/res/drawable/ic_skip_next.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:drawable="@drawable/skip_next_icon" android:state_enabled="true" />
+ <item android:drawable="@drawable/skip_next_off_icon" android:state_enabled="false" />
+ <item android:drawable="@drawable/skip_next_icon" />
+</selector>
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitMediaCommonLauncherRRO/res/drawable/ic_skip_previous.xml b/car_product/car_ui_portrait/rro/CarUiPortraitMediaCommonLauncherRRO/res/drawable/ic_skip_previous.xml
new file mode 100644
index 0000000..e17f9ec
--- /dev/null
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitMediaCommonLauncherRRO/res/drawable/ic_skip_previous.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:drawable="@drawable/skip_previous_icon" android:state_enabled="true" />
+ <item android:drawable="@drawable/skip_previous_off_icon" android:state_enabled="false" />
+ <item android:drawable="@drawable/skip_previous_icon" />
+</selector>
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitMediaCommonLauncherRRO/res/drawable/ic_stop.xml b/car_product/car_ui_portrait/rro/CarUiPortraitMediaCommonLauncherRRO/res/drawable/ic_stop.xml
new file mode 100644
index 0000000..972e148
--- /dev/null
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitMediaCommonLauncherRRO/res/drawable/ic_stop.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+ ~ Copyright (C) 2022 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.
+ -->
+
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
+ <item>
+ <shape android:shape="oval">
+ <solid android:color="@color/play_pause_ic_bg_color"/>
+ </shape>
+ </item>
+ <item android:gravity="center"
+ android:drawable="@drawable/stop_icon"/>
+</layer-list>
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitMediaCommonLauncherRRO/res/drawable/pause_icon.xml b/car_product/car_ui_portrait/rro/CarUiPortraitMediaCommonLauncherRRO/res/drawable/pause_icon.xml
new file mode 100644
index 0000000..470bbf0
--- /dev/null
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitMediaCommonLauncherRRO/res/drawable/pause_icon.xml
@@ -0,0 +1,25 @@
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="88dp"
+ android:height="88dp"
+ android:viewportWidth="88"
+ android:viewportHeight="88">
+ <path
+ android:pathData="M58,58H46V30H58V58ZM50,54H54V34H50V54ZM42,58H30V30H42V58ZM34,54H38V34H34V54Z"
+ android:fillColor="@color/icon_color"/>
+</vector>
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitMediaCommonLauncherRRO/res/drawable/play_arrow_icon.xml b/car_product/car_ui_portrait/rro/CarUiPortraitMediaCommonLauncherRRO/res/drawable/play_arrow_icon.xml
new file mode 100644
index 0000000..3524d17
--- /dev/null
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitMediaCommonLauncherRRO/res/drawable/play_arrow_icon.xml
@@ -0,0 +1,25 @@
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="88dp"
+ android:height="88dp"
+ android:viewportWidth="88"
+ android:viewportHeight="88">
+ <path
+ android:pathData="M60,44L32,62V26L60,44ZM50.52,44L37.1,35.36V52.64L50.52,44Z"
+ android:fillColor="@color/icon_color"/>
+</vector>
\ No newline at end of file
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitMediaCommonLauncherRRO/res/drawable/play_arrow_off_icon.xml b/car_product/car_ui_portrait/rro/CarUiPortraitMediaCommonLauncherRRO/res/drawable/play_arrow_off_icon.xml
new file mode 100644
index 0000000..50937ba
--- /dev/null
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitMediaCommonLauncherRRO/res/drawable/play_arrow_off_icon.xml
@@ -0,0 +1,25 @@
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="88dp"
+ android:height="88dp"
+ android:viewportWidth="88"
+ android:viewportHeight="88">
+ <path
+ android:pathData="M60,44L32,62V26L60,44ZM50.52,44L37.1,35.36V52.64L50.52,44Z"
+ android:fillColor="@color/disabled_icon_color"/>
+</vector>
\ No newline at end of file
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitMediaCommonLauncherRRO/res/drawable/skip_next_icon.xml b/car_product/car_ui_portrait/rro/CarUiPortraitMediaCommonLauncherRRO/res/drawable/skip_next_icon.xml
new file mode 100644
index 0000000..9652e08
--- /dev/null
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitMediaCommonLauncherRRO/res/drawable/skip_next_icon.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24">
+ <path
+ android:pathData="M0,24L17,12L0,0V24ZM4,7.72L10.06,12L4,16.28V7.72ZM24,0H20V24H24V0Z"
+ android:fillColor="@color/icon_color"/>
+</vector>
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitMediaCommonLauncherRRO/res/drawable/skip_next_off_icon.xml b/car_product/car_ui_portrait/rro/CarUiPortraitMediaCommonLauncherRRO/res/drawable/skip_next_off_icon.xml
new file mode 100644
index 0000000..70ec180
--- /dev/null
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitMediaCommonLauncherRRO/res/drawable/skip_next_off_icon.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24">
+ <path
+ android:pathData="M0,24L17,12L0,0V24ZM4,7.72L10.06,12L4,16.28V7.72ZM24,0H20V24H24V0Z"
+ android:fillColor="@color/disabled_icon_color"/>
+</vector>
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitMediaCommonLauncherRRO/res/drawable/skip_previous_icon.xml b/car_product/car_ui_portrait/rro/CarUiPortraitMediaCommonLauncherRRO/res/drawable/skip_previous_icon.xml
new file mode 100644
index 0000000..1e0fa56
--- /dev/null
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitMediaCommonLauncherRRO/res/drawable/skip_previous_icon.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24">
+ <path
+ android:pathData="M0,0H4V24H0V0ZM7,12L24,24V0L7,12ZM13.94,12L20,16.28V7.72L13.94,12Z"
+ android:fillColor="@color/icon_color"
+ android:fillType="evenOdd"/>
+</vector>
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitMediaCommonLauncherRRO/res/drawable/skip_previous_off_icon.xml b/car_product/car_ui_portrait/rro/CarUiPortraitMediaCommonLauncherRRO/res/drawable/skip_previous_off_icon.xml
new file mode 100644
index 0000000..3388f97
--- /dev/null
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitMediaCommonLauncherRRO/res/drawable/skip_previous_off_icon.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24">
+ <path
+ android:pathData="M0,0H4V24H0V0ZM7,12L24,24V0L7,12ZM13.94,12L20,16.28V7.72L13.94,12Z"
+ android:fillColor="@color/disabled_icon_color"
+ android:fillType="evenOdd"/>
+</vector>
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitMediaCommonLauncherRRO/res/drawable/stop_icon.xml b/car_product/car_ui_portrait/rro/CarUiPortraitMediaCommonLauncherRRO/res/drawable/stop_icon.xml
new file mode 100644
index 0000000..e296f77
--- /dev/null
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitMediaCommonLauncherRRO/res/drawable/stop_icon.xml
@@ -0,0 +1,26 @@
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<vector
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="48dp"
+ android:height="48dp"
+ android:viewportWidth="48"
+ android:viewportHeight="48">
+ <path
+ android:fillColor="@color/icon_color"
+ android:pathData="M15,15V33ZM12,36V12H36V36ZM15,33H33V15H15Z"/>
+</vector>
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitMediaCommonLauncherRRO/res/values-night/colors.xml b/car_product/car_ui_portrait/rro/CarUiPortraitMediaCommonLauncherRRO/res/values-night/colors.xml
new file mode 100644
index 0000000..ecf7fbb
--- /dev/null
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitMediaCommonLauncherRRO/res/values-night/colors.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<resources>
+ <color name="icon_color">#E8EAED</color>
+ <color name="disabled_icon_color">#80868B</color>
+ <color name="play_pause_ic_bg_color">#000000</color>
+</resources>
\ No newline at end of file
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitMediaCommonLauncherRRO/res/values/bools.xml b/car_product/car_ui_portrait/rro/CarUiPortraitMediaCommonLauncherRRO/res/values/bools.xml
new file mode 100644
index 0000000..7efb325
--- /dev/null
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitMediaCommonLauncherRRO/res/values/bools.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<resources>
+ <!-- Whether to show a linear progress bar in minimized control bar or not. -->
+ <bool name="show_linear_progress_bar">false</bool>
+ <!-- Whether to show a circular progress bar in control bar and minimized control bar or not. -->
+ <bool name="show_circular_progress_bar">true</bool>
+ <!-- Whether to show circular progress bar only when progress is active. -->
+ <bool name="show_circular_progress_bar_only_when_active">true</bool>
+</resources>
\ No newline at end of file
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitMediaCommonLauncherRRO/res/values/colors.xml b/car_product/car_ui_portrait/rro/CarUiPortraitMediaCommonLauncherRRO/res/values/colors.xml
new file mode 100644
index 0000000..c9c4c1c
--- /dev/null
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitMediaCommonLauncherRRO/res/values/colors.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<resources>
+ <color name="icon_color">#202124</color>
+ <color name="disabled_icon_color">#9AA0A6</color>
+ <color name="play_pause_ic_bg_color">#ffffff</color>
+</resources>
\ No newline at end of file
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitMediaCommonLauncherRRO/res/values/dimens.xml b/car_product/car_ui_portrait/rro/CarUiPortraitMediaCommonLauncherRRO/res/values/dimens.xml
new file mode 100644
index 0000000..6273724
--- /dev/null
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitMediaCommonLauncherRRO/res/values/dimens.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<resources>
+ <dimen name="play_pause_button_bg_radius">24dp</dimen>
+</resources>
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitMediaCommonLauncherRRO/res/xml/overlays.xml b/car_product/car_ui_portrait/rro/CarUiPortraitMediaCommonLauncherRRO/res/xml/overlays.xml
new file mode 100644
index 0000000..c45ceb5
--- /dev/null
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitMediaCommonLauncherRRO/res/xml/overlays.xml
@@ -0,0 +1,28 @@
+<!--
+ ~ Copyright (C) 2022 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.
+ -->
+
+<overlay>
+ <item target="bool/show_linear_progress_bar" value="@bool/show_linear_progress_bar" />
+ <item target="bool/show_circular_progress_bar" value="@bool/show_circular_progress_bar" />
+ <item target="bool/show_circular_progress_bar_only_when_active" value="@bool/show_circular_progress_bar_only_when_active" />
+
+ <item target="drawable/ic_stop" value="@drawable/ic_stop"/>
+ <item target="drawable/ic_pause" value="@drawable/ic_pause"/>
+ <item target="drawable/ic_play_arrow" value="@drawable/ic_play_arrow"/>
+ <item target="drawable/ic_play_arrow_off" value="@drawable/ic_play_arrow_off"/>
+ <item target="drawable/ic_skip_next" value="@drawable/ic_skip_next"/>
+ <item target="drawable/ic_skip_previous" value="@drawable/ic_skip_previous"/>
+</overlay>
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitMediaCommonRRO/Android.bp b/car_product/car_ui_portrait/rro/CarUiPortraitMediaCommonRRO/Android.bp
index 1511086..74aa569 100644
--- a/car_product/car_ui_portrait/rro/CarUiPortraitMediaCommonRRO/Android.bp
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitMediaCommonRRO/Android.bp
@@ -17,7 +17,7 @@
android_app {
name: "CarUiPortraitMediaCommonRRO",
resource_dirs: ["res"],
- platform_apis: true,
+ sdk_version: "current",
aaptflags: [
"--no-resource-deduping",
"--no-resource-removal"
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitMediaCommonRRO/AndroidManifest.xml b/car_product/car_ui_portrait/rro/CarUiPortraitMediaCommonRRO/AndroidManifest.xml
index e9dd47b..82dfa4d 100644
--- a/car_product/car_ui_portrait/rro/CarUiPortraitMediaCommonRRO/AndroidManifest.xml
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitMediaCommonRRO/AndroidManifest.xml
@@ -21,5 +21,6 @@
android:targetName="CarMediaCommon"
android:targetPackage="com.android.car.media"
android:resourcesMap="@xml/overlays"
- android:isStatic="true" />
+ android:category="caruiportrait.media.common"
+ android:isStatic="false" />
</manifest>
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitMediaRRO/Android.bp b/car_product/car_ui_portrait/rro/CarUiPortraitMediaRRO/Android.bp
index a6beaa0..1b268ad 100644
--- a/car_product/car_ui_portrait/rro/CarUiPortraitMediaRRO/Android.bp
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitMediaRRO/Android.bp
@@ -17,14 +17,15 @@
android_app {
name: "CarUiPortraitMediaRRO",
resource_dirs: ["res"],
- platform_apis: true,
+ sdk_version: "current",
aaptflags: [
"--no-resource-deduping",
"--no-resource-removal"
],
static_libs: [
"androidx-constraintlayout_constraintlayout",
+ "androidx-constraintlayout_constraintlayout-solver",
"car-apps-common",
-
+ "car-ui-lib",
],
}
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitMediaRRO/AndroidManifest.xml b/car_product/car_ui_portrait/rro/CarUiPortraitMediaRRO/AndroidManifest.xml
index fa12e4f..0dd1622 100644
--- a/car_product/car_ui_portrait/rro/CarUiPortraitMediaRRO/AndroidManifest.xml
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitMediaRRO/AndroidManifest.xml
@@ -21,5 +21,6 @@
android:targetName="CarMediaApp"
android:targetPackage="com.android.car.media"
android:resourcesMap="@xml/overlays"
- android:isStatic="true" />
+ android:category="caruiportrait.media"
+ android:isStatic="false" />
</manifest>
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitMediaRRO/res/layout/fragment_error.xml b/car_product/car_ui_portrait/rro/CarUiPortraitMediaRRO/res/layout/fragment_error.xml
index dc03e18..6b8f9c6 100644
--- a/car_product/car_ui_portrait/rro/CarUiPortraitMediaRRO/res/layout/fragment_error.xml
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitMediaRRO/res/layout/fragment_error.xml
@@ -14,75 +14,80 @@
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
-<RelativeLayout
+<com.android.car.ui.FocusArea
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
+ android:id="@+id/focus_area"
android:layout_width="match_parent"
android:layout_height="match_parent">
- <androidx.constraintlayout.widget.ConstraintLayout
- android:layout_width="0dp"
- android:layout_height="0dp">
- <Space
- android:id="@+id/ui_content_start_guideline"
+ <RelativeLayout
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="0dp"
- android:layout_height="match_parent"
- android:layout_marginLeft="0dp"
- app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintTop_toTopOf="parent"
- app:layout_constraintBottom_toBottomOf="parent"
- />
+ android:layout_height="0dp">
+ <Space
+ android:id="@+id/ui_content_start_guideline"
+ android:layout_width="0dp"
+ android:layout_height="match_parent"
+ android:layout_marginLeft="0dp"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toTopOf="parent"
+ app:layout_constraintBottom_toBottomOf="parent"
+ />
- <Space
- android:id="@+id/ui_content_top_guideline"
- android:layout_width="match_parent"
- android:layout_height="0dp"
- android:layout_marginTop="96dp"
- app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintEnd_toEndOf="parent"
- app:layout_constraintTop_toTopOf="parent"
- />
+ <Space
+ android:id="@+id/ui_content_top_guideline"
+ android:layout_width="match_parent"
+ android:layout_height="0dp"
+ android:layout_marginTop="96dp"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintTop_toTopOf="parent"
+ />
- <Space
- android:id="@+id/ui_content_end_guideline"
- android:layout_width="0dp"
- android:layout_height="match_parent"
- android:layout_marginRight="0dp"
- app:layout_constraintEnd_toEndOf="parent"
- app:layout_constraintTop_toTopOf="parent"
- app:layout_constraintBottom_toBottomOf="parent"
- />
+ <Space
+ android:id="@+id/ui_content_end_guideline"
+ android:layout_width="0dp"
+ android:layout_height="match_parent"
+ android:layout_marginRight="0dp"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintTop_toTopOf="parent"
+ app:layout_constraintBottom_toBottomOf="parent"
+ />
- <Space
- android:id="@+id/ui_content_bottom_guideline"
- android:layout_width="match_parent"
- android:layout_height="0dp"
- android:layout_marginBottom="0dp"
- app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintEnd_toEndOf="parent"
- app:layout_constraintBottom_toBottomOf="parent"
- />
+ <Space
+ android:id="@+id/ui_content_bottom_guideline"
+ android:layout_width="match_parent"
+ android:layout_height="0dp"
+ android:layout_marginBottom="0dp"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintBottom_toBottomOf="parent"
+ />
- </androidx.constraintlayout.widget.ConstraintLayout>
+ </androidx.constraintlayout.widget.ConstraintLayout>
- <com.android.car.apps.common.UxrTextView
- android:id="@+id/error_message"
- android:layout_width="520dp"
- android:layout_height="44dp"
- android:gravity="center"
- android:layout_marginTop="440dp"
- android:layout_alignParentTop="true"
- android:layout_centerHorizontal="true"/>
+ <com.android.car.apps.common.UxrTextView
+ android:id="@+id/error_message"
+ android:layout_width="520dp"
+ android:layout_height="44dp"
+ android:gravity="center"
+ android:layout_marginTop="440dp"
+ android:layout_alignParentTop="true"
+ android:layout_centerHorizontal="true"/>
- <com.android.car.apps.common.UxrButton
- android:id="@+id/error_button"
- android:layout_width="760dp"
- android:layout_height="88dp"
- android:background="@color/button_background_color"
- android:textAlignment="center"
- android:gravity="center"
- android:layout_marginTop="120dp"
- android:layout_centerHorizontal="true"
- android:layout_below="@id/error_message"/>
-
-</RelativeLayout>
\ No newline at end of file
+ <com.android.car.apps.common.UxrButton
+ android:id="@+id/error_button"
+ android:layout_width="760dp"
+ android:layout_height="88dp"
+ android:background="@color/button_background_color"
+ android:textAlignment="center"
+ android:gravity="center"
+ android:layout_marginTop="120dp"
+ android:layout_centerHorizontal="true"
+ android:layout_below="@id/error_message"/>
+ </RelativeLayout>
+</com.android.car.ui.FocusArea>
\ No newline at end of file
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitMediaRRO/res/xml/overlays.xml b/car_product/car_ui_portrait/rro/CarUiPortraitMediaRRO/res/xml/overlays.xml
index 533df51..ac0c0c3 100644
--- a/car_product/car_ui_portrait/rro/CarUiPortraitMediaRRO/res/xml/overlays.xml
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitMediaRRO/res/xml/overlays.xml
@@ -51,6 +51,7 @@
<item target="id/explicit_icon_with_subtitle" value="@id/explicit_icon_with_subtitle" />
<item target="id/subtitle" value="@id/subtitle" />
<item target="id/right_arrow" value="@id/right_arrow" />
+ <item target="id/focus_area" value="@id/focus_area" />
<item target="layout/fragment_error" value="@layout/fragment_error"/>
<item target="layout/media_browse_grid_icons_item" value="@layout/media_browse_grid_icons_item"/>
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitNotificationRRO/AndroidManifest.xml b/car_product/car_ui_portrait/rro/CarUiPortraitNotificationRRO/AndroidManifest.xml
index 47e6a4a..b1a8065 100644
--- a/car_product/car_ui_portrait/rro/CarUiPortraitNotificationRRO/AndroidManifest.xml
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitNotificationRRO/AndroidManifest.xml
@@ -22,5 +22,6 @@
android:targetName="CarNotification"
android:targetPackage="com.android.car.notification"
android:resourcesMap="@xml/overlays"
- android:isStatic="true" />
+ android:category="caruiportrait.notifications"
+ android:isStatic="false" />
</manifest>
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitSettingsProviderEmuRRO/Android.bp b/car_product/car_ui_portrait/rro/CarUiPortraitSettingsProviderEmuRRO/Android.bp
new file mode 100644
index 0000000..d8625fe
--- /dev/null
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitSettingsProviderEmuRRO/Android.bp
@@ -0,0 +1,25 @@
+// Copyright (C) 2022 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 {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+android_app {
+ name: "CarUiPortraitSettingsProviderEmuRRO",
+ resource_dirs: ["res"],
+ sdk_version: "current",
+ aaptflags: [
+ "--no-resource-deduping",
+ "--no-resource-removal"
+ ],
+}
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitSettingsProviderEmuRRO/AndroidManifest.xml b/car_product/car_ui_portrait/rro/CarUiPortraitSettingsProviderEmuRRO/AndroidManifest.xml
new file mode 100644
index 0000000..deafc8b
--- /dev/null
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitSettingsProviderEmuRRO/AndroidManifest.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2022 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.providers.settings.caruiportrait.emu.rro">
+ <application android:hasCode="false" />
+ <overlay android:priority="20"
+ android:targetName="SettingsProvider"
+ android:targetPackage="com.android.providers.settings"
+ android:resourcesMap="@xml/overlays"
+ android:category="caruiportrait.settings.provider.emu"
+ android:isStatic="false" />
+</manifest>
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitSettingsProviderEmuRRO/res/values/defaults.xml b/car_product/car_ui_portrait/rro/CarUiPortraitSettingsProviderEmuRRO/res/values/defaults.xml
new file mode 100644
index 0000000..4526ba4
--- /dev/null
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitSettingsProviderEmuRRO/res/values/defaults.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<resources>
+ <bool name="def_user_setup_complete">false</bool>
+ <bool name="def_device_provisioned">false</bool>
+</resources>
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitSettingsProviderEmuRRO/res/xml/overlays.xml b/car_product/car_ui_portrait/rro/CarUiPortraitSettingsProviderEmuRRO/res/xml/overlays.xml
new file mode 100644
index 0000000..b48e0f9
--- /dev/null
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitSettingsProviderEmuRRO/res/xml/overlays.xml
@@ -0,0 +1,19 @@
+<!--
+ ~ Copyright (C) 2022 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.
+ -->
+<overlay>
+ <item target="bool/def_device_provisioned" value="@bool/def_device_provisioned"/>
+ <item target="bool/def_user_setup_complete" value="@bool/def_user_setup_complete"/>
+</overlay>
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitSettingsProviderRRO/Android.bp b/car_product/car_ui_portrait/rro/CarUiPortraitSettingsProviderRRO/Android.bp
index b63e2fe..c7d3af1 100644
--- a/car_product/car_ui_portrait/rro/CarUiPortraitSettingsProviderRRO/Android.bp
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitSettingsProviderRRO/Android.bp
@@ -17,7 +17,7 @@
android_app {
name: "CarUiPortraitSettingsProviderRRO",
resource_dirs: ["res"],
- platform_apis: true,
+ sdk_version: "current",
aaptflags: [
"--no-resource-deduping",
"--no-resource-removal"
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitSettingsProviderRRO/AndroidManifest.xml b/car_product/car_ui_portrait/rro/CarUiPortraitSettingsProviderRRO/AndroidManifest.xml
index 807a91a..2814770 100644
--- a/car_product/car_ui_portrait/rro/CarUiPortraitSettingsProviderRRO/AndroidManifest.xml
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitSettingsProviderRRO/AndroidManifest.xml
@@ -21,5 +21,6 @@
android:targetName="SettingsProvider"
android:targetPackage="com.android.providers.settings"
android:resourcesMap="@xml/overlays"
- android:isStatic="true" />
+ android:category="caruiportrait.settings.provider"
+ android:isStatic="false" />
</manifest>
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitSettingsRRO/Android.bp b/car_product/car_ui_portrait/rro/CarUiPortraitSettingsRRO/Android.bp
index 5b9f206..001ca5a 100644
--- a/car_product/car_ui_portrait/rro/CarUiPortraitSettingsRRO/Android.bp
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitSettingsRRO/Android.bp
@@ -17,7 +17,7 @@
android_app {
name: "CarUiPortraitSettingsRRO",
resource_dirs: ["res"],
- platform_apis: true,
+ sdk_version: "current",
aaptflags: [
"--no-resource-deduping",
"--no-resource-removal"
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitSettingsRRO/AndroidManifest.xml b/car_product/car_ui_portrait/rro/CarUiPortraitSettingsRRO/AndroidManifest.xml
index 8d15347..a05c53f 100644
--- a/car_product/car_ui_portrait/rro/CarUiPortraitSettingsRRO/AndroidManifest.xml
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitSettingsRRO/AndroidManifest.xml
@@ -21,5 +21,6 @@
android:targetName="CarSettings"
android:targetPackage="com.android.car.settings"
android:resourcesMap="@xml/overlays"
- android:isStatic="true" />
+ android:category="caruiportrait.settings"
+ android:isStatic="false" />
</manifest>
diff --git a/car_product/car_ui_portrait/rro/android/res/values/config.xml b/car_product/car_ui_portrait/rro/android/res/values/config.xml
index c1395ae..8f536b0 100644
--- a/car_product/car_ui_portrait/rro/android/res/values/config.xml
+++ b/car_product/car_ui_portrait/rro/android/res/values/config.xml
@@ -19,6 +19,9 @@
<!-- IME should not hide nav bar -->
<bool name="config_hideNavBarForKeyboard">false</bool>
+ <!-- Uses customized system bar controls -->
+ <bool name="config_remoteInsetsControllerControlsSystemBars">true</bool>
+
<!-- Device supports Sustained Performance Mode-->
<bool name="config_sustainedPerformanceModeSupported">false</bool>
diff --git a/car_product/car_ui_portrait/rro/car_ui_portrait_rro.mk b/car_product/car_ui_portrait/rro/car_ui_portrait_rro.mk
index de7a46c..6d19699 100644
--- a/car_product/car_ui_portrait/rro/car_ui_portrait_rro.mk
+++ b/car_product/car_ui_portrait/rro/car_ui_portrait_rro.mk
@@ -28,9 +28,20 @@
CarUiPortraitNotificationRRO \
CarUiPortraitCarServiceRRO \
CarUiPortraitFrameworkResRRO \
- CarUiPortraitFrameworkResRROTest
+ CarUiPortraitFrameworkResRROTest \
+ CarUiPortraitLauncherMediaRRO \
+ CarUiPortraitLauncherAppsRRO
ifneq ($(INCLUDE_SEAHAWK_ONLY_RROS),)
PRODUCT_PACKAGES += \
CarUiPortraitSettingsProviderRRO
endif
+
+# Set necessary framework configs for SUW to run at boot.
+ifneq ($(filter $(TARGET_PRODUCT), gcar_ui_portrait_suw),)
+PRODUCT_PACKAGES += \
+ CarUiPortraitSettingsProviderEmuRRO
+endif
+
+PRODUCT_PROPERTY_OVERRIDES += \
+ ro.boot.vendor.overlay.theme=com.android.car.carlauncher.caruiportrait.rro;com.android.car.dialer.caruiportrait.rro;com.google.android.car.evs.caruiportrait.rro;com.android.car.carlauncher.apps.caruiportrait.rro;com.android.car.caruiportrait.rro;com.android.car.carlauncher.media.caruiportrait.rro;com.android.car.media.common.caruiportrait.rro;com.android.car.media.caruiportrait.rro;com.android.car.notification.caruiportrait.rro;com.android.providers.settings.caruiportrait.emu.rro;com.android.providers.settings.caruiportrait.rro;com.android.car.settings.caruiportrait.rro
diff --git a/car_product/overlay-visual/frameworks/base/core/res/res/values/dimens.xml b/car_product/overlay-visual/frameworks/base/core/res/res/values/dimens.xml
index c44ae09..14ee3f9 100644
--- a/car_product/overlay-visual/frameworks/base/core/res/res/values/dimens.xml
+++ b/car_product/overlay-visual/frameworks/base/core/res/res/values/dimens.xml
@@ -18,6 +18,7 @@
-->
<resources>
<dimen name="status_bar_height">76dp</dimen>
+ <dimen name="status_bar_height_default">76dp</dimen>
<dimen name="status_bar_height_landscape">76dp</dimen>
<dimen name="status_bar_height_portrait">76dp</dimen>
<dimen name="car_qs_header_system_icons_area_height">76dp</dimen>
diff --git a/car_product/sepolicy/cartelemetry/cartelemetryd.te b/car_product/sepolicy/cartelemetry/cartelemetryd.te
new file mode 100644
index 0000000..cdae5a3
--- /dev/null
+++ b/car_product/sepolicy/cartelemetry/cartelemetryd.te
@@ -0,0 +1,5 @@
+# Allow Car service to access cartelemetryd service.
+allow carservice_app cartelemetryd_service:service_manager find;
+
+# Allow binder calls with cartelemetryd.
+allow carservice_app cartelemetryd:binder call;
diff --git a/cpp/evs/apps/sepolicy/private/evs_app.te b/cpp/evs/apps/sepolicy/private/evs_app.te
index 686549c..60f2a92 100644
--- a/cpp/evs/apps/sepolicy/private/evs_app.te
+++ b/cpp/evs/apps/sepolicy/private/evs_app.te
@@ -25,5 +25,5 @@
binder_use(evs_app);
allow evs_app surfaceflinger_service:service_manager find;
-# Allow use of cartelemetry service
-allow evs_app cartelemetryd_service:service_manager find;
+# Allow get a list of available services
+allow evs_app servicemanager:service_manager list;
diff --git a/cpp/evs/apps/sepolicy/private/servicemanager.te b/cpp/evs/apps/sepolicy/private/servicemanager.te
deleted file mode 100644
index da102a8..0000000
--- a/cpp/evs/apps/sepolicy/private/servicemanager.te
+++ /dev/null
@@ -1,2 +0,0 @@
-# Allow evs_app to use Binder IPC
-binder_use(evs_app)
diff --git a/cpp/evs/manager/aidl/include/Enumerator.h b/cpp/evs/manager/aidl/include/Enumerator.h
index 4b85758..779f824 100644
--- a/cpp/evs/manager/aidl/include/Enumerator.h
+++ b/cpp/evs/manager/aidl/include/Enumerator.h
@@ -27,6 +27,7 @@
#include <system/camera_metadata.h>
#include <list>
+#include <shared_mutex>
#include <unordered_map>
#include <unordered_set>
@@ -125,11 +126,10 @@
std::shared_ptr<EvsDeviceStatusCallbackImpl> mDeviceStatusCallback;
// Mutex to protect resources related with a device status callback
- mutable std::mutex mLock;
+ mutable std::shared_mutex mLock;
// Clients to forward device status callback messages
- std::set<std::shared_ptr<aidlevs::IEvsEnumeratorStatusCallback>> mDeviceStatusCallbacks
- GUARDED_BY(mLock);
+ std::set<std::shared_ptr<aidlevs::IEvsEnumeratorStatusCallback>> mDeviceStatusCallbacks;
};
} // namespace aidl::android::automotive::evs::implementation
diff --git a/cpp/evs/manager/aidl/src/Enumerator.cpp b/cpp/evs/manager/aidl/src/Enumerator.cpp
index ecac33e..2ed7992 100644
--- a/cpp/evs/manager/aidl/src/Enumerator.cpp
+++ b/cpp/evs/manager/aidl/src/Enumerator.cpp
@@ -209,7 +209,7 @@
camera_metadata_ro_entry_t entry;
int rc =
find_camera_metadata_ro_entry(metadata, ANDROID_REQUEST_AVAILABLE_CAPABILITIES, &entry);
- if (rc != 0) {
+ if (rc != ::android::OK) {
// No capabilities are found in metadata.
LOG(DEBUG) << "No capability is found";
return false;
@@ -244,7 +244,7 @@
camera_metadata_ro_entry entry;
int rc = find_camera_metadata_ro_entry(metadata, ANDROID_LOGICAL_MULTI_CAMERA_PHYSICAL_IDS,
&entry);
- if (rc != 0) {
+ if (rc != ::android::OK) {
LOG(ERROR) << "No physical camera ID is found for a logical camera device " << id;
return physicalCameras;
}
@@ -277,17 +277,21 @@
return Utils::buildScopedAStatusFromEvsResult(EvsResult::PERMISSION_DENIED);
}
+ std::lock_guard lock(mLock);
auto status = mHwEnumerator->getCameraList(_aidl_return);
- if (status.isOk()) {
- for (auto&& desc : *_aidl_return) {
- mCameraDevices.insert_or_assign(desc.id, desc);
- }
+ if (!status.isOk()) {
+ return status;
+ }
+
+ for (auto&& desc : *_aidl_return) {
+ mCameraDevices.insert_or_assign(desc.id, desc);
}
return status;
}
ScopedAStatus Enumerator::getStreamList(const CameraDesc& desc, std::vector<Stream>* _aidl_return) {
+ std::shared_lock lock(mLock);
return mHwEnumerator->getStreamList(desc, _aidl_return);
}
@@ -302,6 +306,7 @@
return Utils::buildScopedAStatusFromEvsResult(EvsResult::INVALID_ARG);
}
+ std::lock_guard lock(mLock);
// All our client cameras are actually VirtualCamera objects
VirtualCamera* virtualCamera = reinterpret_cast<VirtualCamera*>(cameraObj.get());
@@ -348,6 +353,7 @@
std::vector<std::shared_ptr<HalCamera>> sourceCameras;
bool success = true;
+ std::lock_guard lock(mLock);
// 1. Try to open inactive camera devices.
for (auto&& id : physicalCameras) {
auto it = mActiveCameras.find(id);
@@ -418,7 +424,8 @@
}
}
- // Send the virtual camera object back to the client by strong pointer which will keep it alive
+ // Send the virtual camera object back to the client by strong pointer which will keep it
+ // alive
*cameraObj = std::move(clientCamera);
return ScopedAStatus::ok();
}
@@ -429,6 +436,7 @@
return Utils::buildScopedAStatusFromEvsResult(EvsResult::PERMISSION_DENIED);
}
+ std::lock_guard lock(mLock);
if (mDisplayOwnedExclusively) {
if (!mActiveDisplay.expired()) {
LOG(ERROR) << "Display is owned exclusively by another client.";
@@ -474,18 +482,25 @@
ScopedAStatus Enumerator::closeDisplay(const std::shared_ptr<IEvsDisplay>& displayObj) {
LOG(DEBUG) << __FUNCTION__;
+ if (!displayObj) {
+ LOG(WARNING) << "Ignoring a call with an invalid display object";
+ return Utils::buildScopedAStatusFromEvsResult(EvsResult::INVALID_ARG);
+ }
+
+ std::lock_guard lock(mLock);
// Drop the active display
std::shared_ptr<IEvsDisplay> pActiveDisplay = mActiveDisplay.lock();
if (pActiveDisplay != displayObj) {
LOG(WARNING) << "Ignoring call to closeDisplay with unrecognized display object.";
- } else {
- // Pass this request through to the hardware layer
- HalDisplay* halDisplay = reinterpret_cast<HalDisplay*>(pActiveDisplay.get());
- mHwEnumerator->closeDisplay(halDisplay->getHwDisplay());
- mActiveDisplay.reset();
- mDisplayOwnedExclusively = false;
+ return ScopedAStatus::ok();
}
+ // Pass this request through to the hardware layer
+ HalDisplay* halDisplay = reinterpret_cast<HalDisplay*>(pActiveDisplay.get());
+ mHwEnumerator->closeDisplay(halDisplay->getHwDisplay());
+ mActiveDisplay.reset();
+ mDisplayOwnedExclusively = false;
+
return ScopedAStatus::ok();
}
@@ -495,6 +510,7 @@
return Utils::buildScopedAStatusFromEvsResult(EvsResult::PERMISSION_DENIED);
}
+ std::lock_guard lock(mLock);
// Do we have a display object we think should be active?
std::shared_ptr<IEvsDisplay> pActiveDisplay = mActiveDisplay.lock();
if (pActiveDisplay) {
@@ -508,6 +524,7 @@
}
ScopedAStatus Enumerator::getDisplayIdList(std::vector<uint8_t>* _aidl_return) {
+ std::shared_lock lock(mLock);
return mHwEnumerator->getDisplayIdList(_aidl_return);
}
diff --git a/cpp/evs/manager/aidl/utils/include/Utils.h b/cpp/evs/manager/aidl/utils/include/Utils.h
index d2c4bfb..a6fd4cd 100644
--- a/cpp/evs/manager/aidl/utils/include/Utils.h
+++ b/cpp/evs/manager/aidl/utils/include/Utils.h
@@ -98,7 +98,7 @@
static aidlevs::EvsEventType makeFromHidl(const hidlevs::V1_1::EvsEventType& type);
- static hidlevs::V1_1::EvsEventDesc makeToHidl(const aidlevs::EvsEventDesc& type);
+ static bool makeToHidl(const aidlevs::EvsEventDesc& in, hidlevs::V1_1::EvsEventDesc* out);
static aidlevs::EvsEventDesc makeFromHidl(const hidlevs::V1_1::EvsEventDesc& desc);
diff --git a/cpp/evs/manager/aidl/utils/src/Utils.cpp b/cpp/evs/manager/aidl/utils/src/Utils.cpp
index 888c6b2..596698f 100644
--- a/cpp/evs/manager/aidl/utils/src/Utils.cpp
+++ b/cpp/evs/manager/aidl/utils/src/Utils.cpp
@@ -493,19 +493,22 @@
return std::move(aidlDesc);
}
-hidlevs::V1_1::EvsEventDesc Utils::makeToHidl(const EvsEventDesc& aidlDesc) {
- hidlevs::V1_1::EvsEventDesc hidlDesc = {
- .aType = makeToHidl(aidlDesc.aType),
- .deviceId = aidlDesc.deviceId,
- };
+bool Utils::makeToHidl(const EvsEventDesc& in, hidlevs::V1_1::EvsEventDesc* out) {
+ if (in.payload.size() > out->payload.size()) {
+ LOG(ERROR) << "The size of the event payload must not exceed "
+ << out->payload.size() * sizeof(out->payload[0]) << " bytes.";
- if (aidlDesc.payload.size() > 0) {
- for (int i = 0; i < hidlDesc.payload.size(); ++i) {
- hidlDesc.payload[i] = aidlDesc.payload[i];
- }
+ return false;
}
- return std::move(hidlDesc);
+ out->aType = makeToHidl(in.aType);
+ out->deviceId = in.deviceId;
+
+ for (int i = 0; i < in.payload.size(); ++i) {
+ out->payload[i] = in.payload[i];
+ }
+
+ return true;
}
bool Utils::validateNativeHandle(const NativeHandle& handle) {
diff --git a/cpp/evs/manager/aidl/wrappers/src/AidlCameraStream.cpp b/cpp/evs/manager/aidl/wrappers/src/AidlCameraStream.cpp
index 06f7591..224c378 100644
--- a/cpp/evs/manager/aidl/wrappers/src/AidlCameraStream.cpp
+++ b/cpp/evs/manager/aidl/wrappers/src/AidlCameraStream.cpp
@@ -30,6 +30,7 @@
using ::aidl::android::hardware::automotive::evs::BufferDesc;
using ::aidl::android::hardware::automotive::evs::EvsEventDesc;
using ::aidl::android::hardware::automotive::evs::EvsEventType;
+using ::aidl::android::hardware::automotive::evs::EvsResult;
using ::ndk::ScopedAStatus;
AidlCameraStream::AidlCameraStream(
@@ -124,7 +125,12 @@
}
ScopedAStatus AidlCameraStream::ImplV1::notify(const EvsEventDesc& event) {
- if (auto status = mStream->notify(Utils::makeToHidl(event)); !status.isOk()) {
+ hidlevs::V1_1::EvsEventDesc hidlEvent;
+ if (!Utils::makeToHidl(event, &hidlEvent)) {
+ return ScopedAStatus::fromServiceSpecificError(static_cast<int>(EvsResult::INVALID_ARG));
+ }
+
+ if (auto status = mStream->notify(hidlEvent); !status.isOk()) {
LOG(ERROR) << "Failed to forward an event, " << Utils::toString(event.aType);
return ScopedAStatus::fromExceptionCode(EX_TRANSACTION_FAILED);
}
diff --git a/cpp/evs/manager/aidl/wrappers/src/AidlEnumerator.cpp b/cpp/evs/manager/aidl/wrappers/src/AidlEnumerator.cpp
index baa0364..02dee26 100644
--- a/cpp/evs/manager/aidl/wrappers/src/AidlEnumerator.cpp
+++ b/cpp/evs/manager/aidl/wrappers/src/AidlEnumerator.cpp
@@ -89,11 +89,24 @@
std::vector<Stream>* _aidl_return) {
LOG(DEBUG) << __FUNCTION__;
+ if (desc.metadata.empty()) {
+ LOG(DEBUG) << "Camera metadata is empty.";
+ return ScopedAStatus::ok();
+ }
+
camera_metadata_t* pMetadata = const_cast<camera_metadata_t*>(
reinterpret_cast<const camera_metadata_t*>(desc.metadata.data()));
+ const size_t expectedSize = desc.metadata.size();
+ if (validate_camera_metadata_structure(pMetadata, &expectedSize) != ::android::OK) {
+ LOG(WARNING) << "Camera metadata is invalid.";
+ return ScopedAStatus::fromServiceSpecificError(static_cast<int>(EvsResult::INVALID_ARG));
+ }
+
camera_metadata_entry_t streamConfig;
if (find_camera_metadata_entry(pMetadata, ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS,
- &streamConfig)) {
+ &streamConfig) != ::android::OK) {
+ LOG(DEBUG) << "ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS does not exist in the camera "
+ "metadata.";
return ScopedAStatus::ok();
}
diff --git a/cpp/libsysfsmonitor/OWNERS b/cpp/libsysfsmonitor/OWNERS
new file mode 100644
index 0000000..88671a1
--- /dev/null
+++ b/cpp/libsysfsmonitor/OWNERS
@@ -0,0 +1 @@
+ericjeong@google.com
diff --git a/cpp/powerpolicy/OWNERS b/cpp/powerpolicy/OWNERS
new file mode 100644
index 0000000..88671a1
--- /dev/null
+++ b/cpp/powerpolicy/OWNERS
@@ -0,0 +1 @@
+ericjeong@google.com
diff --git a/cpp/powerpolicy/server/src/PolicyManager.cpp b/cpp/powerpolicy/server/src/PolicyManager.cpp
index bf64685..33a8f80 100644
--- a/cpp/powerpolicy/server/src/PolicyManager.cpp
+++ b/cpp/powerpolicy/server/src/PolicyManager.cpp
@@ -451,7 +451,7 @@
}
void PolicyManager::init() {
- initRegularPowerPolicy();
+ initRegularPowerPolicy(/*override=*/true);
mPolicyGroups.clear();
initPreemptivePowerPolicy();
readPowerPolicyConfiguration();
@@ -586,6 +586,7 @@
}
mRegisteredPowerPolicies = registeredPoliciesMap;
+ initRegularPowerPolicy(/*override=*/false);
mPolicyGroups = *policyGroups;
reconstructNoUserInteractionPolicy(*systemPolicyOverrides);
}
@@ -601,8 +602,10 @@
}
}
-void PolicyManager::initRegularPowerPolicy() {
- mRegisteredPowerPolicies.clear();
+void PolicyManager::initRegularPowerPolicy(bool override) {
+ if (override) {
+ mRegisteredPowerPolicies.clear();
+ }
mRegisteredPowerPolicies.emplace(kSystemPolicyIdAllOn,
createPolicy(kSystemPolicyIdAllOn, kAllComponents,
kNoComponents));
diff --git a/cpp/powerpolicy/server/src/PolicyManager.h b/cpp/powerpolicy/server/src/PolicyManager.h
index 5793ffc..7c1e7fa 100644
--- a/cpp/powerpolicy/server/src/PolicyManager.h
+++ b/cpp/powerpolicy/server/src/PolicyManager.h
@@ -85,7 +85,7 @@
android::base::Result<void> dump(int fd, const android::Vector<String16>& args);
private:
- void initRegularPowerPolicy();
+ void initRegularPowerPolicy(bool override);
void initPreemptivePowerPolicy();
void readPowerPolicyConfiguration();
void readPowerPolicyFromXml(const tinyxml2::XMLDocument& xmlDoc);
diff --git a/cpp/powerpolicy/server/tests/PolicyManagerTest.cpp b/cpp/powerpolicy/server/tests/PolicyManagerTest.cpp
index e4994b2..40837df 100644
--- a/cpp/powerpolicy/server/tests/PolicyManagerTest.cpp
+++ b/cpp/powerpolicy/server/tests/PolicyManagerTest.cpp
@@ -66,6 +66,9 @@
constexpr const char* kValidPowerPolicyGroupId = "mixed_policy_group";
constexpr const char* kInvalidPowerPolicyGroupId = "invalid_policy_group";
constexpr const char* kSystemPolicyIdNoUserInteraction = "system_power_policy_no_user_interaction";
+constexpr const char* kSystemPolicyIdInitialOn = "system_power_policy_initial_on";
+constexpr const char* kSystemPolicyIdInitialAllOn = "system_power_policy_all_on";
+constexpr const char* kSystemPolicyIdSuspendPrep = "system_power_policy_suspend_prep";
const VehicleApPowerStateReport kExistingTransition = VehicleApPowerStateReport::WAIT_FOR_VHAL;
const VehicleApPowerStateReport kNonExistingTransition = static_cast<VehicleApPowerStateReport>(-1);
@@ -217,6 +220,13 @@
ASSERT_TRUE(isEqual(*policyMeta->powerPolicy, kSystemPowerPolicyNoUserInteraction));
}
+void assertDefaultPolicies(const PolicyManager& policyManager) {
+ ASSERT_TRUE(policyManager.getPowerPolicy(kSystemPolicyIdSuspendPrep).ok());
+ ASSERT_TRUE(policyManager.getPowerPolicy(kSystemPolicyIdNoUserInteraction).ok());
+ ASSERT_TRUE(policyManager.getPowerPolicy(kSystemPolicyIdInitialOn).ok());
+ ASSERT_TRUE(policyManager.getPowerPolicy(kSystemPolicyIdInitialAllOn).ok());
+}
+
} // namespace
namespace internal {
@@ -224,7 +234,7 @@
class PolicyManagerPeer {
public:
explicit PolicyManagerPeer(PolicyManager* manager) : mManager(manager) {
- manager->initRegularPowerPolicy();
+ manager->initRegularPowerPolicy(/*override=*/true);
manager->initPreemptivePowerPolicy();
}
@@ -334,6 +344,21 @@
checkSystemPowerPolicy(policyManager, kModifiedSystemPowerPolicy);
}
+TEST_F(PolicyManagerTest, TestDefaultPowerPolicies) {
+ PolicyManager policyManager;
+ internal::PolicyManagerPeer policyManagerPeer(&policyManager);
+
+ assertDefaultPolicies(policyManager);
+}
+
+TEST_F(PolicyManagerTest, TestValidXml_DefaultPowerPolicies) {
+ PolicyManager policyManager;
+ internal::PolicyManagerPeer policyManagerPeer(&policyManager);
+ policyManagerPeer.expectValidPowerPolicyXML(kValidPowerPolicyXmlFile);
+
+ assertDefaultPolicies(policyManager);
+}
+
TEST_F(PolicyManagerTest, TestInvalidPowerPolicyXml) {
for (const auto& filename : kInvalidPowerPolicyXmlFiles) {
PolicyManager policyManager;
diff --git a/cpp/telemetry/cartelemetryd/Android.bp b/cpp/telemetry/cartelemetryd/Android.bp
index 0e9292a..5ced617 100644
--- a/cpp/telemetry/cartelemetryd/Android.bp
+++ b/cpp/telemetry/cartelemetryd/Android.bp
@@ -24,7 +24,7 @@
"-Wno-unused-parameter",
],
shared_libs: [
- "android.automotive.telemetry.internal-V1-ndk",
+ "android.automotive.telemetry.internal-V2-ndk",
"android.frameworks.automotive.telemetry-V1-ndk",
"libbase",
"libbinder_ndk",
@@ -73,7 +73,7 @@
// Statically link only in tests, for portability reason.
static_libs: [
"android.automotive.telemetryd@1.0-impl",
- "android.automotive.telemetry.internal-V1-ndk",
+ "android.automotive.telemetry.internal-V2-ndk",
"android.frameworks.automotive.telemetry-V1-ndk",
"libgmock",
"libgtest",
diff --git a/cpp/telemetry/cartelemetryd/README.md b/cpp/telemetry/cartelemetryd/README.md
index 792c285..6a15e21 100644
--- a/cpp/telemetry/cartelemetryd/README.md
+++ b/cpp/telemetry/cartelemetryd/README.md
@@ -6,7 +6,9 @@
**Dumping the service information**
-`adb shell dumpsys android.automotive.telemetry.internal.ICarTelemetryInternal/default`
+```
+adb shell dumpsys android.automotive.telemetry.internal.ICarTelemetryInternal/default
+```
**Enabling VERBOSE logs**
@@ -17,13 +19,19 @@
**Starting emulator with cold boot**
-`emulator -verbose -show-kernel -selinux permissive -writable-system -no-snapshot -wipe-data`
+```
+emulator -verbose -show-kernel -selinux permissive -writable-system -no-snapshot -wipe-data
+```
**Running the tests**
-`atest cartelemetryd_impl_test:CarTelemetryInternalImplTest#TestSetListenerReturnsOk`
+```
+# run a specific test
+atest cartelemetryd_impl_test:CarTelemetryInternalImplTest#TestSetListenerReturnsOk
-`atest cartelemetryd_impl_test`
+# run all tests
+atest cartelemetryd_impl_test
+```
## Enabling cartelemetryd
@@ -32,14 +40,25 @@
```
# Enable Automotive Telemetry Services (cartelemetryd) only on specific devices.
-ifneq ($(filter $(TARGET_PRODUCT), TARGET1 TARGET2),)
-include packages/services/Car/cpp/telemetry/cartelemetryd/products/telemetry.mk
-endif
+ENABLE_CARTELEMETRY_SERVICE ?= true
```
To find where the service was included, run this from `$ANDROID_BUILD_TOP`:
```
grep -rH --color --exclude-dir='**/.*' --exclude-dir='out' --include='*.mk' \
- 'cartelemetryd/products/telemetry.mk' device/ vendor/
+ 'ENABLE_CARTELEMETRY_SERVICE' device/ vendor/
+```
+
+## Updating cartelemetryd
+
+If AIDL interface were updated, run `m -j` and re-flash.
+
+If implementation were updated, run:
+
+```
+m -j android.automotive.telemetryd@1.0
+adb root && adb remount && adb push $ANDROID_PRODUCT_OUT/system/bin/android.automotive.telemetryd@1.0 /system/bin && adb shell /system/bin/android.automotive.telemetryd@1.0
+Ctrl+C
+adb reboot
```
diff --git a/cpp/telemetry/cartelemetryd/aidl/Android.bp b/cpp/telemetry/cartelemetryd/aidl/Android.bp
index fde24cd..0aa4dfe 100644
--- a/cpp/telemetry/cartelemetryd/aidl/Android.bp
+++ b/cpp/telemetry/cartelemetryd/aidl/Android.bp
@@ -20,6 +20,7 @@
// to learn how to use it.
aidl_interface {
name: "android.automotive.telemetry.internal",
+ owner: "google",
srcs: [
"android/automotive/telemetry/internal/*.aidl",
],
diff --git a/cpp/telemetry/cartelemetryd/aidl/aidl_api/android.automotive.telemetry.internal/current/android/automotive/telemetry/internal/ICarTelemetryInternal.aidl b/cpp/telemetry/cartelemetryd/aidl/aidl_api/android.automotive.telemetry.internal/current/android/automotive/telemetry/internal/ICarTelemetryInternal.aidl
index 38ecf4c..8e690c9 100644
--- a/cpp/telemetry/cartelemetryd/aidl/aidl_api/android.automotive.telemetry.internal/current/android/automotive/telemetry/internal/ICarTelemetryInternal.aidl
+++ b/cpp/telemetry/cartelemetryd/aidl/aidl_api/android.automotive.telemetry.internal/current/android/automotive/telemetry/internal/ICarTelemetryInternal.aidl
@@ -35,4 +35,6 @@
interface ICarTelemetryInternal {
void setListener(in android.automotive.telemetry.internal.ICarDataListener listener);
void clearListener();
+ void addCarDataIds(in int[] ids);
+ void removeCarDataIds(in int[] ids);
}
diff --git a/cpp/telemetry/cartelemetryd/aidl/android/automotive/telemetry/internal/ICarTelemetryInternal.aidl b/cpp/telemetry/cartelemetryd/aidl/android/automotive/telemetry/internal/ICarTelemetryInternal.aidl
index b8938ff..559a5b2 100644
--- a/cpp/telemetry/cartelemetryd/aidl/android/automotive/telemetry/internal/ICarTelemetryInternal.aidl
+++ b/cpp/telemetry/cartelemetryd/aidl/android/automotive/telemetry/internal/ICarTelemetryInternal.aidl
@@ -35,4 +35,14 @@
* Clears the listener if exists. Silently ignores if there is no listener.
*/
void clearListener();
+
+ /**
+ * Adds CarData IDs that a MetricsConfig subscribes to. Can be used for filtering purposes.
+ */
+ void addCarDataIds(in int[] ids);
+
+ /**
+ * Removes CarData IDs.
+ */
+ void removeCarDataIds(in int[] ids);
}
diff --git a/cpp/telemetry/cartelemetryd/products/telemetry.mk b/cpp/telemetry/cartelemetryd/products/telemetry.mk
index 8d27dad..86161bd 100644
--- a/cpp/telemetry/cartelemetryd/products/telemetry.mk
+++ b/cpp/telemetry/cartelemetryd/products/telemetry.mk
@@ -12,11 +12,11 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-# Selinux public policies for cartelemetry
-PRODUCT_PUBLIC_SEPOLICY_DIRS += packages/services/Car/cpp/telemetry/cartelemetryd/sepolicy/public
-
# cartelemetryd service
PRODUCT_PACKAGES += android.automotive.telemetryd@1.0
+# Selinux public policies for cartelemetry
+PRODUCT_PUBLIC_SEPOLICY_DIRS += packages/services/Car/cpp/telemetry/cartelemetryd/sepolicy/public
+
# Selinux private policies for cartelemetry
PRODUCT_PRIVATE_SEPOLICY_DIRS += packages/services/Car/cpp/telemetry/cartelemetryd/sepolicy/private
diff --git a/cpp/telemetry/cartelemetryd/sampleclient/README.md b/cpp/telemetry/cartelemetryd/sampleclient/README.md
index ae86300..2e62072 100644
--- a/cpp/telemetry/cartelemetryd/sampleclient/README.md
+++ b/cpp/telemetry/cartelemetryd/sampleclient/README.md
@@ -9,6 +9,7 @@
```
m -j android.automotive.telemetryd-sampleclient
+adb root
adb remount # make sure run "adb disable-verity" before remounting
adb push $ANDROID_PRODUCT_OUT/vendor/bin/android.automotive.telemetryd-sampleclient /system/bin/
diff --git a/cpp/telemetry/cartelemetryd/sepolicy/private/cartelemetryd.te b/cpp/telemetry/cartelemetryd/sepolicy/private/cartelemetryd.te
index adc3cff..4150e4d 100644
--- a/cpp/telemetry/cartelemetryd/sepolicy/private/cartelemetryd.te
+++ b/cpp/telemetry/cartelemetryd/sepolicy/private/cartelemetryd.te
@@ -8,3 +8,5 @@
add_service(cartelemetryd, cartelemetryd_service)
init_daemon_domain(cartelemetryd)
+
+allow cartelemetryd carservice_app:binder call;
diff --git a/cpp/telemetry/cartelemetryd/src/CarTelemetryInternalImpl.cpp b/cpp/telemetry/cartelemetryd/src/CarTelemetryInternalImpl.cpp
index 2abf4fc..f33d5b4 100644
--- a/cpp/telemetry/cartelemetryd/src/CarTelemetryInternalImpl.cpp
+++ b/cpp/telemetry/cartelemetryd/src/CarTelemetryInternalImpl.cpp
@@ -40,12 +40,7 @@
ndk::ScopedAStatus CarTelemetryInternalImpl::setListener(
const std::shared_ptr<ICarDataListener>& listener) {
LOG(VERBOSE) << "Received a setListener call";
- auto result = mTelemetryServer->setListener(listener);
- if (!result.ok()) {
- LOG(WARNING) << __func__ << ": " << result.error().message();
- return ndk::ScopedAStatus::fromExceptionCodeWithMessage(result.error().code(),
- result.error().message().c_str());
- }
+ mTelemetryServer->setListener(listener);
// If passed a local binder, AIBinder_linkToDeath will do nothing and return
// STATUS_INVALID_OPERATION. We ignore this case because we only use local binders in tests
@@ -81,6 +76,16 @@
return ndk::ScopedAStatus::ok();
}
+ndk::ScopedAStatus CarTelemetryInternalImpl::addCarDataIds(const std::vector<int32_t>& ids) {
+ mTelemetryServer->addCarDataIds(ids);
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus CarTelemetryInternalImpl::removeCarDataIds(const std::vector<int32_t>& ids) {
+ mTelemetryServer->removeCarDataIds(ids);
+ return ndk::ScopedAStatus::ok();
+}
+
binder_status_t CarTelemetryInternalImpl::dump(int fd, const char** args, uint32_t numArgs) {
dprintf(fd, "ICarTelemetryInternal:\n");
mTelemetryServer->dump(fd);
diff --git a/cpp/telemetry/cartelemetryd/src/CarTelemetryInternalImpl.h b/cpp/telemetry/cartelemetryd/src/CarTelemetryInternalImpl.h
index f9710b4..069ab51 100644
--- a/cpp/telemetry/cartelemetryd/src/CarTelemetryInternalImpl.h
+++ b/cpp/telemetry/cartelemetryd/src/CarTelemetryInternalImpl.h
@@ -44,6 +44,10 @@
ndk::ScopedAStatus clearListener() override;
+ ndk::ScopedAStatus addCarDataIds(const std::vector<int32_t>& ids) override;
+
+ ndk::ScopedAStatus removeCarDataIds(const std::vector<int32_t>& ids) override;
+
binder_status_t dump(int fd, const char** args, uint32_t numArgs) override;
private:
diff --git a/cpp/telemetry/cartelemetryd/src/TelemetryServer.cpp b/cpp/telemetry/cartelemetryd/src/TelemetryServer.cpp
index 0a124e5..fea2f5f 100644
--- a/cpp/telemetry/cartelemetryd/src/TelemetryServer.cpp
+++ b/cpp/telemetry/cartelemetryd/src/TelemetryServer.cpp
@@ -24,6 +24,7 @@
#include <inttypes.h> // for PRIu64 and friends
+#include <cstdint>
#include <memory>
namespace android {
@@ -38,9 +39,7 @@
using ::android::base::Error;
using ::android::base::Result;
-enum {
- MSG_PUSH_CAR_DATA_TO_LISTENER = 1,
-};
+constexpr int kMsgPushCarDataToListener = 1;
// If ICarDataListener cannot accept data, the next push should be delayed little bit to allow
// the listener to recover.
@@ -55,15 +54,11 @@
mRingBuffer(maxBufferSize),
mMessageHandler(new MessageHandlerImpl(this)) {}
-Result<void> TelemetryServer::setListener(const std::shared_ptr<ICarDataListener>& listener) {
+void TelemetryServer::setListener(const std::shared_ptr<ICarDataListener>& listener) {
const std::scoped_lock<std::mutex> lock(mMutex);
- if (mCarDataListener != nullptr) {
- return Error(::EX_ILLEGAL_STATE) << "ICarDataListener is already set";
- }
mCarDataListener = listener;
mLooper->sendMessageDelayed(mPushCarDataDelayNs.count(), mMessageHandler,
- MSG_PUSH_CAR_DATA_TO_LISTENER);
- return {};
+ kMsgPushCarDataToListener);
}
void TelemetryServer::clearListener() {
@@ -72,7 +67,19 @@
return;
}
mCarDataListener = nullptr;
- mLooper->removeMessages(mMessageHandler, MSG_PUSH_CAR_DATA_TO_LISTENER);
+ mLooper->removeMessages(mMessageHandler, kMsgPushCarDataToListener);
+}
+
+void TelemetryServer::addCarDataIds(const std::vector<int32_t>& ids) {
+ const std::scoped_lock<std::mutex> lock(mMutex);
+ mCarDataIds.insert(ids.cbegin(), ids.cend());
+}
+
+void TelemetryServer::removeCarDataIds(const std::vector<int32_t>& ids) {
+ const std::scoped_lock<std::mutex> lock(mMutex);
+ for (int32_t id : ids) {
+ mCarDataIds.erase(id);
+ }
}
std::shared_ptr<ICarDataListener> TelemetryServer::getListener() {
@@ -91,6 +98,11 @@
const std::scoped_lock<std::mutex> lock(mMutex);
bool bufferWasEmptyBefore = mRingBuffer.size() == 0;
for (auto&& data : dataList) {
+ // ignore data that has no subscribers in CarTelemetryService
+ if (mCarDataIds.find(data.id) == mCarDataIds.end()) {
+ LOG(VERBOSE) << "Ignoring CarData with ID=" << data.id;
+ continue;
+ }
mRingBuffer.push({.mId = data.id,
.mContent = std::move(data.content),
.mPublisherUid = publisherUid});
@@ -99,22 +111,20 @@
// too many unnecessary idendical messages in the looper.
if (mCarDataListener != nullptr && bufferWasEmptyBefore && mRingBuffer.size() > 0) {
mLooper->sendMessageDelayed(mPushCarDataDelayNs.count(), mMessageHandler,
- MSG_PUSH_CAR_DATA_TO_LISTENER);
+ kMsgPushCarDataToListener);
}
}
// Runs on the main thread.
void TelemetryServer::pushCarDataToListeners() {
- std::shared_ptr<ICarDataListener> listener;
std::vector<CarDataInternal> pendingCarDataInternals;
{
const std::scoped_lock<std::mutex> lock(mMutex);
// Remove extra messages.
- mLooper->removeMessages(mMessageHandler, MSG_PUSH_CAR_DATA_TO_LISTENER);
+ mLooper->removeMessages(mMessageHandler, kMsgPushCarDataToListener);
if (mCarDataListener == nullptr || mRingBuffer.size() == 0) {
return;
}
- listener = mCarDataListener;
// Push elements to pendingCarDataInternals in reverse order so we can send data
// from the back of the pendingCarDataInternals vector.
while (mRingBuffer.size() > 0) {
@@ -126,12 +136,21 @@
}
}
- // Now the mutex is unlocked, we can do the heavy work.
-
// TODO(b/186477983): send data in batch to improve performance, but careful sending too
// many data at once, as it could clog the Binder - it has <1MB limit.
while (!pendingCarDataInternals.empty()) {
- auto status = listener->onCarDataReceived({pendingCarDataInternals.back()});
+ ndk::ScopedAStatus status = ndk::ScopedAStatus::ok();
+ {
+ const std::scoped_lock<std::mutex> lock(mMutex);
+ if (mCarDataListener != nullptr) {
+ status = mCarDataListener->onCarDataReceived({pendingCarDataInternals.back()});
+ } else {
+ status = ndk::ScopedAStatus::
+ fromServiceSpecificErrorWithMessage(EX_NULL_POINTER,
+ "mCarDataListener is currently set to "
+ "null, will try again.");
+ }
+ }
if (!status.isOk()) {
LOG(WARNING) << "Failed to push CarDataInternal, will try again: "
<< status.getMessage();
@@ -147,7 +166,7 @@
void TelemetryServer::MessageHandlerImpl::handleMessage(const Message& message) {
switch (message.what) {
- case MSG_PUSH_CAR_DATA_TO_LISTENER:
+ case kMsgPushCarDataToListener:
mTelemetryServer->pushCarDataToListeners();
break;
default:
diff --git a/cpp/telemetry/cartelemetryd/src/TelemetryServer.h b/cpp/telemetry/cartelemetryd/src/TelemetryServer.h
index 61263db..b4dc4c3 100644
--- a/cpp/telemetry/cartelemetryd/src/TelemetryServer.h
+++ b/cpp/telemetry/cartelemetryd/src/TelemetryServer.h
@@ -29,6 +29,7 @@
#include <utils/Looper.h>
#include <memory>
+#include <unordered_set>
namespace android {
namespace automotive {
@@ -48,27 +49,57 @@
explicit TelemetryServer(LooperWrapper* looper,
const std::chrono::nanoseconds& pushCarDataDelayNs, int maxBufferSize);
- // Dumps the current state for dumpsys.
- // Expected to be called from a binder thread pool.
+ /**
+ * Dumps the current state for dumpsys.
+ *
+ * <p>Expected to be called from a binder thread pool.
+ */
void dump(int fd);
- // Writes incoming CarData to the RingBuffer.
- // Expected to be called from a binder thread pool.
+ /**
+ * Writes incoming CarData to the RingBuffer.
+ *
+ * <p>Expected to be called from a binder thread pool.
+ */
void writeCarData(
const std::vector<aidl::android::frameworks::automotive::telemetry::CarData>& dataList,
uid_t publisherUid);
- // Sets the listener. If the listener already set, it returns an error.
- // Expected to be called from a binder thread pool.
- android::base::Result<void> setListener(
+ /**
+ * Sets the listener and overrides the previous listener if it exists.
+ *
+ * <p>Expected to be called from a binder thread pool.
+ */
+ void setListener(
const std::shared_ptr<aidl::android::automotive::telemetry::internal::ICarDataListener>&
listener);
- // Clears the listener and returns it.
- // Expected to be called from a binder thread pool.
+ /**
+ * Clears the ICarDataListener.
+ *
+ * <p>Expected to be called from a binder thread pool.
+ */
void clearListener();
- // Expected to be called from a binder thread pool.
+ /**
+ * Adds active CarData IDs, called by CarTelemetrydPublisher when the IDs
+ * has active subscribers.
+ *
+ * <p>Expected to be called from a binder thread pool.
+ */
+ void addCarDataIds(const std::vector<int32_t>& ids);
+
+ /**
+ * Removes CarData IDs, called by CarTelemetrydPublisher when the IDs
+ * no longer has subscribers.
+ *
+ * <p>Expected to be called from a binder thread pool.
+ */
+ void removeCarDataIds(const std::vector<int32_t>& ids);
+
+ /**
+ * Expected to be called from a binder thread pool.
+ */
std::shared_ptr<aidl::android::automotive::telemetry::internal::ICarDataListener> getListener();
private:
@@ -92,15 +123,27 @@
// A single mutex for all the sensitive operations. Threads must not lock it for long time,
// as clients will be writing CarData to the ring buffer under this mutex.
std::mutex mMutex;
+
+ // Buffers vendor written CarData.
RingBuffer mRingBuffer GUARDED_BY(mMutex);
+
+ // Notifies listener when CarData is written.
std::shared_ptr<aidl::android::automotive::telemetry::internal::ICarDataListener>
mCarDataListener GUARDED_BY(mMutex);
- android::sp<MessageHandlerImpl> mMessageHandler; // Handler for mLooper.
+
+ // Stores a set of CarData IDs that have subscribers in CarTelemetryService.
+ // Used for filtering data.
+ std::unordered_set<int32_t> mCarDataIds GUARDED_BY(mMutex);
+
+ // Handler for mLooper.
+ android::sp<MessageHandlerImpl> mMessageHandler;
// Friends are simplest way of testing if `pushCarDataToListeners()` can handle edge cases.
friend class TelemetryServerTest;
FRIEND_TEST(TelemetryServerTest, NoListenerButMultiplePushes);
FRIEND_TEST(TelemetryServerTest, NoDataButMultiplePushes);
+ // The following test accesses `mCarDataIds` to check its contents
+ FRIEND_TEST(TelemetryServerTest, RemoveCarDataIdsReturnsOk);
};
} // namespace telemetry
diff --git a/cpp/telemetry/cartelemetryd/tests/TelemetryServerTest.cpp b/cpp/telemetry/cartelemetryd/tests/TelemetryServerTest.cpp
index 8a6fab5..8a81af9 100644
--- a/cpp/telemetry/cartelemetryd/tests/TelemetryServerTest.cpp
+++ b/cpp/telemetry/cartelemetryd/tests/TelemetryServerTest.cpp
@@ -35,6 +35,7 @@
#include <unistd.h>
#include <memory>
+#include <unordered_set>
namespace android {
namespace automotive {
@@ -115,18 +116,35 @@
EXPECT_TRUE(status.isOk()) << status.getMessage();
}
+TEST_F(TelemetryServerTest, addCarDataIdsReturnsOk) {
+ auto status = mTelemetryInternal->addCarDataIds({101});
+
+ EXPECT_TRUE(status.isOk()) << status.getMessage();
+}
+
+TEST_F(TelemetryServerTest, RemoveCarDataIdsReturnsOk) {
+ mTelemetryInternal->addCarDataIds({101, 102, 103});
+ EXPECT_EQ(3, mTelemetryServer.mCarDataIds.size());
+
+ auto status = mTelemetryInternal->removeCarDataIds({101, 103});
+
+ EXPECT_TRUE(status.isOk()) << status.getMessage();
+ EXPECT_EQ(1, mTelemetryServer.mCarDataIds.size());
+ EXPECT_NE(mTelemetryServer.mCarDataIds.end(), mTelemetryServer.mCarDataIds.find(102));
+}
+
TEST_F(TelemetryServerTest, SetListenerReturnsOk) {
auto status = mTelemetryInternal->setListener(mMockCarDataListener);
EXPECT_TRUE(status.isOk()) << status.getMessage();
}
-TEST_F(TelemetryServerTest, SetListenerFailsWhenAlreadySubscribed) {
+TEST_F(TelemetryServerTest, SetListenerAllowedWhenAlreadySubscribed) {
mTelemetryInternal->setListener(mMockCarDataListener);
auto status = mTelemetryInternal->setListener(ndk::SharedRefBase::make<MockCarDataListener>());
- EXPECT_EQ(status.getExceptionCode(), ::EX_ILLEGAL_STATE) << status.getMessage();
+ EXPECT_TRUE(status.isOk()) << status.getMessage();
}
TEST_F(TelemetryServerTest, ClearListenerWorks) {
@@ -174,6 +192,7 @@
std::vector<CarData> dataList1 = {buildCarData(10, {1, 2}), buildCarData(11, {2, 3})};
std::vector<CarData> dataList2 = {buildCarData(101, {1, 2}), buildCarData(102, {2, 3}),
buildCarData(103, {3, 4}), buildCarData(104, {4, 5})};
+ mTelemetryInternal->addCarDataIds({10, 11, 101, 102, 103, 104});
mTelemetry->write(dataList1);
mTelemetry->write(dataList2);
@@ -189,9 +208,22 @@
mFakeLooper.poll();
}
-// First sets the listener, then writes CarData.
-TEST_F(TelemetryServerTest, WhenListenerIsAlreadyItPushesData) {
+// Data is filtered out when mTelemetryInternal->addCarDataIds() is not called
+TEST_F(TelemetryServerTest, WriteFiltersDataBasedOnId) {
std::vector<CarData> dataList = {buildCarData(101, {1})};
+ mTelemetryInternal->setListener(mMockCarDataListener);
+
+ mTelemetry->write(dataList);
+
+ expectMockListenerToReceive({buildCarDataInternal(101, {1})}).Times(0);
+
+ mFakeLooper.poll();
+}
+
+// First sets the listener, then writes CarData.
+TEST_F(TelemetryServerTest, WhenListenerIsAlreadySetItPushesData) {
+ std::vector<CarData> dataList = {buildCarData(101, {1})};
+ mTelemetryInternal->addCarDataIds({101});
mTelemetryInternal->setListener(mMockCarDataListener);
mTelemetry->write(dataList);
@@ -204,6 +236,7 @@
// First writes CarData, only then sets the listener.
TEST_F(TelemetryServerTest, WhenListenerIsSetLaterItPushesData) {
std::vector<CarData> dataList = {buildCarData(101, {1})};
+ mTelemetryInternal->addCarDataIds({101});
mTelemetry->write(dataList);
mTelemetryInternal->setListener(mMockCarDataListener);
@@ -214,6 +247,7 @@
}
TEST_F(TelemetryServerTest, WriteDuringPushingDataToListener) {
+ mTelemetryInternal->addCarDataIds({101, 102, 103});
std::vector<CarData> dataList = {buildCarData(101, {1}), buildCarData(102, {1})};
std::vector<CarData> dataList2 = {buildCarData(103, {1})};
mTelemetryInternal->setListener(mMockCarDataListener);
@@ -232,6 +266,7 @@
TEST_F(TelemetryServerTest, ClearListenerDuringPushingDataToListener) {
std::vector<CarData> dataList = {buildCarData(101, {1})};
+ mTelemetryInternal->addCarDataIds({101});
mTelemetryInternal->setListener(mMockCarDataListener);
mTelemetry->write(dataList);
@@ -245,6 +280,7 @@
TEST_F(TelemetryServerTest, RetriesPushAgainIfListenerFails) {
std::vector<CarData> dataList = {buildCarData(101, {1})};
+ mTelemetryInternal->addCarDataIds({101});
mTelemetryInternal->setListener(mMockCarDataListener);
mTelemetry->write(dataList);
@@ -260,6 +296,7 @@
// is handled properly when transaction fails and clearListener() is called.
TEST_F(TelemetryServerTest, ClearListenerDuringPushingDataAndSetListenerAgain) {
std::vector<CarData> dataList = {buildCarData(101, {1})};
+ mTelemetryInternal->addCarDataIds({101});
mTelemetryInternal->setListener(mMockCarDataListener);
mTelemetry->write(dataList);
@@ -277,6 +314,7 @@
// Directly calls pushCarDataToListeners() to make sure it can handle edge-cases.
TEST_F(TelemetryServerTest, NoListenerButMultiplePushes) {
std::vector<CarData> dataList = {buildCarData(101, {1})};
+ mTelemetryInternal->addCarDataIds({101});
mTelemetry->write(dataList);
mTelemetryServer.pushCarDataToListeners();
diff --git a/cpp/vhal/OWNERS b/cpp/vhal/OWNERS
new file mode 100644
index 0000000..88671a1
--- /dev/null
+++ b/cpp/vhal/OWNERS
@@ -0,0 +1 @@
+ericjeong@google.com
diff --git a/cpp/vhal/client/src/IVhalClient.cpp b/cpp/vhal/client/src/IVhalClient.cpp
index 66c55ad..23b0849 100644
--- a/cpp/vhal/client/src/IVhalClient.cpp
+++ b/cpp/vhal/client/src/IVhalClient.cpp
@@ -72,8 +72,8 @@
std::lock_guard<std::mutex> lockGuard(s.lock);
s.result = std::move(r);
s.gotResult = true;
+ s.cv.notify_one();
}
- s.cv.notify_one();
});
getValue(requestValue, callback);
@@ -97,8 +97,8 @@
std::lock_guard<std::mutex> lockGuard(s.lock);
s.result = std::move(r);
s.gotResult = true;
+ s.cv.notify_one();
}
- s.cv.notify_one();
});
setValue(requestValue, callback);
diff --git a/cpp/watchdog/OWNERS b/cpp/watchdog/OWNERS
new file mode 100644
index 0000000..bd4e0cc
--- /dev/null
+++ b/cpp/watchdog/OWNERS
@@ -0,0 +1 @@
+lakshmana@google.com
diff --git a/cpp/watchdog/aidl/Android.bp b/cpp/watchdog/aidl/Android.bp
index 15fce1d..e6532e4 100644
--- a/cpp/watchdog/aidl/Android.bp
+++ b/cpp/watchdog/aidl/Android.bp
@@ -66,5 +66,5 @@
imports: ["android.automotive.watchdog-V3"],
},
],
-
+ owner: "google",
}
diff --git a/cpp/watchdog/aidl/aidl_api/android.automotive.watchdog.internal/current/android/automotive/watchdog/internal/ICarWatchdog.aidl b/cpp/watchdog/aidl/aidl_api/android.automotive.watchdog.internal/current/android/automotive/watchdog/internal/ICarWatchdog.aidl
index 82a9ea7..8eb7900 100644
--- a/cpp/watchdog/aidl/aidl_api/android.automotive.watchdog.internal/current/android/automotive/watchdog/internal/ICarWatchdog.aidl
+++ b/cpp/watchdog/aidl/aidl_api/android.automotive.watchdog.internal/current/android/automotive/watchdog/internal/ICarWatchdog.aidl
@@ -43,4 +43,6 @@
void updateResourceOveruseConfigurations(in List<android.automotive.watchdog.internal.ResourceOveruseConfiguration> configs);
List<android.automotive.watchdog.internal.ResourceOveruseConfiguration> getResourceOveruseConfigurations();
void controlProcessHealthCheck(in boolean enable);
+ void setThreadPriority(int pid, int tid, int uid, int policy, int priority);
+ android.automotive.watchdog.internal.ThreadPolicyWithPriority getThreadPriority(int pid, int tid, int uid);
}
diff --git a/cpp/watchdog/aidl/aidl_api/android.automotive.watchdog.internal/current/android/automotive/watchdog/internal/ThreadPolicyWithPriority.aidl b/cpp/watchdog/aidl/aidl_api/android.automotive.watchdog.internal/current/android/automotive/watchdog/internal/ThreadPolicyWithPriority.aidl
new file mode 100644
index 0000000..e554b9e
--- /dev/null
+++ b/cpp/watchdog/aidl/aidl_api/android.automotive.watchdog.internal/current/android/automotive/watchdog/internal/ThreadPolicyWithPriority.aidl
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.automotive.watchdog.internal;
+parcelable ThreadPolicyWithPriority {
+ int policy;
+ int priority;
+}
diff --git a/cpp/watchdog/aidl/aidl_api/android.automotive.watchdog.internal/current/android/automotive/watchdog/internal/UserState.aidl b/cpp/watchdog/aidl/aidl_api/android.automotive.watchdog.internal/current/android/automotive/watchdog/internal/UserState.aidl
index 52ccfe6..5f1a1c4 100644
--- a/cpp/watchdog/aidl/aidl_api/android.automotive.watchdog.internal/current/android/automotive/watchdog/internal/UserState.aidl
+++ b/cpp/watchdog/aidl/aidl_api/android.automotive.watchdog.internal/current/android/automotive/watchdog/internal/UserState.aidl
@@ -37,5 +37,12 @@
USER_STATE_STARTED = 0,
USER_STATE_STOPPED = 1,
USER_STATE_REMOVED = 2,
+ /**
+ * @deprecated Value of enum no longer reflects the true amount of user states. Enum should not be used.
+ */
NUM_USER_STATES = 3,
+ USER_STATE_SWITCHING = 4,
+ USER_STATE_UNLOCKING = 5,
+ USER_STATE_UNLOCKED = 6,
+ USER_STATE_POST_UNLOCKED = 7,
}
diff --git a/cpp/watchdog/aidl/android/automotive/watchdog/internal/ICarWatchdog.aidl b/cpp/watchdog/aidl/android/automotive/watchdog/internal/ICarWatchdog.aidl
index f9dd5d5..f1f5f76 100644
--- a/cpp/watchdog/aidl/android/automotive/watchdog/internal/ICarWatchdog.aidl
+++ b/cpp/watchdog/aidl/android/automotive/watchdog/internal/ICarWatchdog.aidl
@@ -22,6 +22,7 @@
import android.automotive.watchdog.internal.ProcessIdentifier;
import android.automotive.watchdog.internal.ResourceOveruseConfiguration;
import android.automotive.watchdog.internal.StateType;
+import android.automotive.watchdog.internal.ThreadPolicyWithPriority;
/**
* ICarWatchdog is an interface implemented by the watchdog server. This interface is used only by
@@ -132,4 +133,44 @@
* Otherwise, it is disabled.
*/
void controlProcessHealthCheck(in boolean enable);
+
+ /**
+ * Set thread scheduling policy and priority.
+ *
+ * <p> This function would check whether the {@code tid} belongs to {@code pid} and {@code uid}.
+ * If so, it sets the scheduling policy and priority. Otherwise, it returns errors.
+ *
+ * <p>This function may return one of the following error codes:
+ * <ul>
+ * <li> {@code EX_ILLEGAL_STATE} If the given {@code tid} does not belong to {@code pid} and
+ * {@code uid}.
+ * <li> {@code EX_SERVICE_SPECIFIC} if failed to set thread scheduling policy and priority.
+ * <li> {@code EX_INVALID_ARGUMENT} If the provided policy or priority is not valid.
+ *
+ * @param pid The process id.
+ * @param tid The thread id.
+ * @param uid The package uid (aka linux real user ID).
+ * @param policy The scheduling policy.
+ * @param priority The scheduling priority.
+ */
+ void setThreadPriority(int pid, int tid, int uid, int policy, int priority);
+
+ /**
+ * Get thread scheduling policy and priority.
+ *
+ * <p> This function would check whether the {@code tid} belongs to {@code pid} and {@code uid}.
+ * If so, it gets the scheduling policy and priority. Otherwise, it returns error.
+ *
+ * <p>This function may return one of the following error codes:
+ * <ul>
+ * <li> {@code EX_ILLEGAL_STATE} If the given {@code tid} does not belong to {@code pid} and
+ * {@code uid}.
+ * <li> {@code EX_SERVICE_SPECIFIC} if failed to get thread scheduling policy and priority.
+ *
+ * @param pid The process id.
+ * @param tid The thread id.
+ * @param uid The package uid (aka linux real user ID).
+ * @return The policy with priority.
+ */
+ ThreadPolicyWithPriority getThreadPriority(int pid, int tid, int uid);
}
diff --git a/cpp/watchdog/aidl/android/automotive/watchdog/internal/ThreadPolicyWithPriority.aidl b/cpp/watchdog/aidl/android/automotive/watchdog/internal/ThreadPolicyWithPriority.aidl
new file mode 100644
index 0000000..b720254
--- /dev/null
+++ b/cpp/watchdog/aidl/android/automotive/watchdog/internal/ThreadPolicyWithPriority.aidl
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2022 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.automotive.watchdog.internal;
+
+/**
+ * Structure that includes a thread scheduling policy and priority.
+ */
+parcelable ThreadPolicyWithPriority {
+ /**
+ * The thread scheduling policy.
+ *
+ * This is the 'policy' passed to the system call 'sched_setscheduler'..
+ */
+ int policy;
+ /**
+ * The thread scheduling priority.
+ *
+ * This is the 'sched_priority' field in 'sched_param' passed to the system call
+ * 'sched_setscheduler'.
+ */
+ int priority;
+}
diff --git a/cpp/watchdog/aidl/android/automotive/watchdog/internal/UserState.aidl b/cpp/watchdog/aidl/android/automotive/watchdog/internal/UserState.aidl
index 95461eb..04b9333 100644
--- a/cpp/watchdog/aidl/android/automotive/watchdog/internal/UserState.aidl
+++ b/cpp/watchdog/aidl/android/automotive/watchdog/internal/UserState.aidl
@@ -38,6 +38,29 @@
/**
* Number of available user states.
+ *
+ * @deprecated Value of enum no longer reflects the true amount of user states.
+ * Enum should not be used.
*/
NUM_USER_STATES,
+
+ /**
+ * The user is switching.
+ */
+ USER_STATE_SWITCHING,
+
+ /**
+ * The user is unlocking.
+ */
+ USER_STATE_UNLOCKING,
+
+ /**
+ * The user is unlocked.
+ */
+ USER_STATE_UNLOCKED,
+
+ /**
+ * The user has been unlocked and system is in idle state.
+ */
+ USER_STATE_POST_UNLOCKED,
}
diff --git a/cpp/watchdog/car-watchdog-lib/Android.bp b/cpp/watchdog/car-watchdog-lib/Android.bp
index 08794aa..93cbf36 100644
--- a/cpp/watchdog/car-watchdog-lib/Android.bp
+++ b/cpp/watchdog/car-watchdog-lib/Android.bp
@@ -40,7 +40,7 @@
"com.android.car.framework"
],
static_libs: [
- "android.automotive.watchdog.internal-V1-java",
+ "android.automotive.watchdog.internal-V2-java",
],
libs: [
diff --git a/cpp/watchdog/car-watchdog-lib/src/android/car/watchdoglib/CarWatchdogDaemonHelper.java b/cpp/watchdog/car-watchdog-lib/src/android/car/watchdoglib/CarWatchdogDaemonHelper.java
index 5675c49..d4d95ce 100644
--- a/cpp/watchdog/car-watchdog-lib/src/android/car/watchdoglib/CarWatchdogDaemonHelper.java
+++ b/cpp/watchdog/car-watchdog-lib/src/android/car/watchdoglib/CarWatchdogDaemonHelper.java
@@ -23,6 +23,7 @@
import android.automotive.watchdog.internal.ICarWatchdogServiceForSystem;
import android.automotive.watchdog.internal.ProcessIdentifier;
import android.automotive.watchdog.internal.ResourceOveruseConfiguration;
+import android.automotive.watchdog.internal.ThreadPolicyWithPriority;
import android.car.builtin.os.ServiceManagerHelper;
import android.os.Handler;
import android.os.IBinder;
@@ -288,7 +289,49 @@
invokeDaemonMethod((daemon) -> daemon.controlProcessHealthCheck(enable));
}
+ /**
+ * Set the thread scheduling policy and priority.
+ *
+ * @param pid The process ID.
+ * @param tid The thread ID.
+ * @param uid The user ID for the thread.
+ * @param policy The scheduling policy.
+ * @param priority The scheduling priority.
+ */
+ public void setThreadPriority(int pid, int tid, int uid, int policy, int priority)
+ throws RemoteException {
+ invokeDaemonMethodForVersionAtLeast(
+ (daemon) -> daemon.setThreadPriority(pid, tid, uid, policy, priority),
+ /* expectedDaemonVersion= */ 2);
+ }
+
+ /**
+ * Get the thread scheduling policy and priority.
+ *
+ * @param pid The process ID.
+ * @param tid The thread ID.
+ * @param uid The user ID for the thread.
+ */
+ public int[] getThreadPriority(int pid, int tid, int uid)
+ throws RemoteException {
+ // resultValues stores policy as first element and priority as second element.
+ int[] resultValues = new int[2];
+
+ invokeDaemonMethodForVersionAtLeast((daemon) -> {
+ ThreadPolicyWithPriority t = daemon.getThreadPriority(pid, tid, uid);
+ resultValues[0] = t.policy;
+ resultValues[1] = t.priority;
+ }, /* expectedDaemonVersion= */ 2);
+
+ return resultValues;
+ }
+
private void invokeDaemonMethod(Invokable r) throws RemoteException {
+ invokeDaemonMethodForVersionAtLeast(r, /* expectedDaemonVersion= */ -1);
+ }
+
+ private void invokeDaemonMethodForVersionAtLeast(Invokable r, int expectedDaemonVersion)
+ throws RemoteException {
ICarWatchdog daemon;
synchronized (mLock) {
if (mCarWatchdogDaemon == null) {
@@ -296,6 +339,13 @@
}
daemon = mCarWatchdogDaemon;
}
+ int actualDaemonVersion = daemon.getInterfaceVersion();
+ if (actualDaemonVersion < expectedDaemonVersion) {
+ // TODO(b/238328234): Replace this with a special exception type.
+ throw new UnsupportedOperationException(
+ "Require car watchdog daemon version: " + expectedDaemonVersion
+ + ", actual version: " + actualDaemonVersion);
+ }
r.invoke(daemon);
}
diff --git a/cpp/watchdog/sepolicy/private/carwatchdog.te b/cpp/watchdog/sepolicy/private/carwatchdog.te
index 5b18ebf..5f2d304 100644
--- a/cpp/watchdog/sepolicy/private/carwatchdog.te
+++ b/cpp/watchdog/sepolicy/private/carwatchdog.te
@@ -26,9 +26,16 @@
# Read /proc/diskstats file.
allow carwatchdogd proc_diskstats:file r_file_perms;
+# Read /proc/uid_cputime/show_uid_stat file.
+allow carwatchdogd proc_uid_cputime_showstat:file r_file_perms;
+
# List HALs to get pid of vehicle HAL.
allow carwatchdogd hwservicemanager:hwservice_manager list;
# R/W /data/system/car for resource overuse configurations.
allow carwatchdogd system_car_data_file:dir create_dir_perms;
allow carwatchdogd system_car_data_file:{ file lnk_file } create_file_perms;
+
+# Allow carwatchdogd to set thread scheduling policy and priority.
+allow carwatchdogd self:capability sys_nice;
+allow carwatchdogd appdomain:process { setsched getsched };
diff --git a/cpp/watchdog/server/Android.bp b/cpp/watchdog/server/Android.bp
index cf98d5f..2eb41f0 100644
--- a/cpp/watchdog/server/Android.bp
+++ b/cpp/watchdog/server/Android.bp
@@ -38,7 +38,7 @@
"packagemanager_aidl-cpp",
],
static_libs: [
- "android.automotive.watchdog.internal-V1-cpp",
+ "android.automotive.watchdog.internal-V2-cpp",
"android.automotive.watchdog-V3-cpp",
"libvhalclient",
],
@@ -91,6 +91,7 @@
"src/OveruseConfigurationXmlHelper.cpp",
"src/ProcDiskStatsCollector.cpp",
"src/ProcStatCollector.cpp",
+ "src/UidCpuStatsCollector.cpp",
"src/UidIoStatsCollector.cpp",
"src/UidProcStatsCollector.cpp",
"src/UidStatsCollector.cpp",
@@ -120,6 +121,7 @@
"carwatchdogd_defaults",
"libwatchdog_perf_service_defaults",
"libwatchdog_process_service_defaults",
+ "libwatchdog_service_manager_defaults",
],
test_suites: ["general-tests"],
tidy_disabled_srcs: [
@@ -144,6 +146,7 @@
"tests/ProcStatCollectorTest.cpp",
"tests/UidIoStatsCollectorTest.cpp",
"tests/UidProcStatsCollectorTest.cpp",
+ "tests/UidCpuStatsCollectorTest.cpp",
"tests/UidStatsCollectorTest.cpp",
"tests/WatchdogBinderMediatorTest.cpp",
"tests/WatchdogInternalHandlerTest.cpp",
@@ -152,15 +155,16 @@
"tests/WatchdogServiceHelperTest.cpp",
],
static_libs: [
+ "android.hardware.automotive.vehicle@2.0",
"libgmock",
"libgtest",
"libwatchdog_binder_mediator",
"libwatchdog_perf_service",
"libwatchdog_process_service",
+ "libwatchdog_service_manager",
],
whole_static_libs: [
"libwatchdog_package_info_resolver",
- "android.hardware.automotive.vehicle@2.0",
],
data: [":watchdog_test_xml_files"],
}
@@ -172,14 +176,14 @@
],
}
-cc_library {
+cc_library_static {
name: "libwatchdog_process_service",
srcs: [
"src/WatchdogProcessService.cpp",
],
defaults: [
"carwatchdogd_defaults",
- "libwatchdog_process_service_defaults"
+ "libwatchdog_process_service_defaults",
],
shared_libs: [
"android.hardware.automotive.vehicle@2.0",
@@ -194,6 +198,7 @@
"libwatchdog_process_service_defaults",
],
srcs: [
+ "src/ThreadPriorityController.cpp",
"src/WatchdogBinderMediator.cpp",
"src/WatchdogInternalHandler.cpp",
"src/WatchdogServiceHelper.cpp",
@@ -210,28 +215,46 @@
],
}
+cc_defaults {
+ name: "libwatchdog_service_manager_defaults",
+ defaults: [
+ "libwatchdog_perf_service_defaults",
+ "libwatchdog_process_service_defaults",
+ ],
+ static_libs: [
+ "libwatchdog_binder_mediator",
+ "libwatchdog_package_info_resolver",
+ "libwatchdog_perf_service",
+ "libwatchdog_process_service",
+ ],
+}
+
+cc_library {
+ name: "libwatchdog_service_manager",
+ defaults: [
+ "carwatchdogd_defaults",
+ "libwatchdog_service_manager_defaults",
+ ],
+ srcs: [
+ "src/ServiceManager.cpp",
+ ],
+}
+
cc_binary {
name: "carwatchdogd",
defaults: [
"carwatchdogd_defaults",
- "libwatchdog_perf_service_defaults",
- "libwatchdog_process_service_defaults",
+ "libwatchdog_service_manager_defaults",
],
srcs: [
"src/main.cpp",
- "src/ServiceManager.cpp",
],
init_rc: ["carwatchdogd.rc"],
shared_libs: [
"android.hardware.automotive.vehicle@2.0",
],
static_libs: [
- "libwatchdog_binder_mediator",
- "libwatchdog_perf_service",
- "libwatchdog_process_service",
- ],
- whole_static_libs: [
- "libwatchdog_package_info_resolver",
+ "libwatchdog_service_manager",
],
vintf_fragments: ["carwatchdogd.xml"],
required: [
diff --git a/cpp/watchdog/server/carwatchdogd.rc b/cpp/watchdog/server/carwatchdogd.rc
index 410ac4b..1fd121b 100644
--- a/cpp/watchdog/server/carwatchdogd.rc
+++ b/cpp/watchdog/server/carwatchdogd.rc
@@ -16,26 +16,39 @@
class core
user system
group system readproc
+ capabilities SYS_NICE
disabled
on early-init && property:ro.build.type=userdebug
# Below intervals are in seconds
- setprop ro.carwatchdog.boottime_collection_interval 1
+ setprop ro.carwatchdog.system_event_collection_interval 1
setprop ro.carwatchdog.periodic_collection_interval 60
setprop ro.carwatchdog.periodic_monitor_interval 5
+ # Below durations are in seconds
+ setprop ro.carwatchdog.post_system_event_duration 30
+ setprop ro.carwatchdog.user_switch_timeout 30
+
on early-init && property:ro.build.type=eng
# Below intervals are in seconds
- setprop ro.carwatchdog.boottime_collection_interval 1
+ setprop ro.carwatchdog.system_event_collection_interval 1
setprop ro.carwatchdog.periodic_collection_interval 60
setprop ro.carwatchdog.periodic_monitor_interval 5
+ # Below durations are in seconds
+ setprop ro.carwatchdog.post_system_event_duration 30
+ setprop ro.carwatchdog.user_switch_timeout 30
+
on early-init && property:ro.build.type=user
# Below intervals are in seconds
- setprop ro.carwatchdog.boottime_collection_interval 20
+ setprop ro.carwatchdog.system_event_collection_interval 20
setprop ro.carwatchdog.periodic_collection_interval 120
setprop ro.carwatchdog.periodic_monitor_interval 5
+ # Below durations are in seconds
+ setprop ro.carwatchdog.post_system_event_duration 30
+ setprop ro.carwatchdog.user_switch_timeout 30
+
on init
# Number of top stats per category
setprop ro.carwatchdog.top_n_stats_per_category 10
@@ -43,6 +56,9 @@
# Number of top stats per sub-category
setprop ro.carwatchdog.top_n_stats_per_subcategory 5
+ # Cache size for the user switch events
+ setprop ro.carwatchdog.max_user_switch_events 5
+
# Cache size for the periodically collected records
setprop ro.carwatchdog.periodic_collection_buffer_size 180
diff --git a/cpp/watchdog/server/src/IoOveruseMonitor.cpp b/cpp/watchdog/server/src/IoOveruseMonitor.cpp
index 05a5bea..f18d96c 100644
--- a/cpp/watchdog/server/src/IoOveruseMonitor.cpp
+++ b/cpp/watchdog/server/src/IoOveruseMonitor.cpp
@@ -514,25 +514,37 @@
}
Result<void> IoOveruseMonitor::addIoOveruseListener(const sp<IResourceOveruseListener>& listener) {
+ if (listener == nullptr) {
+ return Error(Status::EX_ILLEGAL_ARGUMENT) << "Must provide non-null listener";
+ }
pid_t callingPid = IPCThreadState::self()->getCallingPid();
uid_t callingUid = IPCThreadState::self()->getCallingUid();
- std::unique_lock writeLock(mRwMutex);
- if (!isInitializedLocked()) {
- // mBinderDeathRecipient is initialized inside init.
- return Error(Status::EX_ILLEGAL_STATE) << "Service is not initialized";
- }
auto binder = BnResourceOveruseListener::asBinder(listener);
- if (findListenerAndProcessLocked(binder, nullptr)) {
- ALOGW("Failed to register the I/O overuse listener (pid: %d, uid: %d) as it is already "
- "registered",
- callingPid, callingUid);
- return {};
+ sp<BinderDeathRecipient> binderDeathRecipient;
+ {
+ std::unique_lock writeLock(mRwMutex);
+ if (mBinderDeathRecipient == nullptr) {
+ return Error(Status::EX_ILLEGAL_STATE) << "Service is not initialized";
+ }
+ if (findListenerAndProcessLocked(binder, nullptr)) {
+ ALOGW("Failed to register the I/O overuse listener (pid: %d, uid: %d) as it is already "
+ "registered",
+ callingPid, callingUid);
+ return {};
+ }
+ mOveruseListenersByUid[callingUid] = listener;
+ binderDeathRecipient = mBinderDeathRecipient;
}
- if (const auto status = binder->linkToDeath(mBinderDeathRecipient); status != OK) {
+ if (const auto status = binder->linkToDeath(binderDeathRecipient); status != OK) {
+ std::unique_lock writeLock(mRwMutex);
+ if (const auto& it = mOveruseListenersByUid.find(callingUid);
+ it != mOveruseListenersByUid.end() &&
+ BnResourceOveruseListener::asBinder(it->second) == binder) {
+ mOveruseListenersByUid.erase(it);
+ }
return Error(Status::EX_ILLEGAL_STATE)
<< "(pid " << callingPid << ", uid: " << callingUid << ") is dead";
}
- mOveruseListenersByUid[callingUid] = listener;
if (DEBUG) {
ALOGD("Added I/O overuse listener for uid: %d", callingUid);
}
@@ -541,9 +553,11 @@
Result<void> IoOveruseMonitor::removeIoOveruseListener(
const sp<IResourceOveruseListener>& listener) {
+ if (listener == nullptr) {
+ return Error(Status::EX_ILLEGAL_ARGUMENT) << "Must provide non-null listener";
+ }
std::unique_lock writeLock(mRwMutex);
- if (!isInitializedLocked()) {
- // mBinderDeathRecipient is initialized inside init.
+ if (mBinderDeathRecipient == nullptr) {
return Error(Status::EX_ILLEGAL_STATE) << "Service is not initialized";
}
const auto processor = [&](ListenersByUidMap& listeners, ListenersByUidMap::const_iterator it) {
diff --git a/cpp/watchdog/server/src/IoOveruseMonitor.h b/cpp/watchdog/server/src/IoOveruseMonitor.h
index 1b6c0e0..3a858a8 100644
--- a/cpp/watchdog/server/src/IoOveruseMonitor.h
+++ b/cpp/watchdog/server/src/IoOveruseMonitor.h
@@ -122,6 +122,16 @@
return {};
}
+ android::base::Result<void> onUserSwitchCollection(
+ [[maybe_unused]] time_t time, [[maybe_unused]] userid_t from,
+ [[maybe_unused]] userid_t to,
+ [[maybe_unused]] const android::wp<UidStatsCollectorInterface>& uidStatsCollector,
+ [[maybe_unused]] const android::wp<ProcStatCollectorInterface>& procStatCollector)
+ override {
+ // No I/O overuse monitoring during user switch.
+ return {};
+ }
+
android::base::Result<void> onPeriodicCollection(
time_t time, SystemState systemState,
const android::wp<UidStatsCollectorInterface>& uidStatsCollector,
@@ -268,7 +278,7 @@
mLatestIoOveruseStats;
ListenersByUidMap mOveruseListenersByUid GUARDED_BY(mRwMutex);
- android::sp<BinderDeathRecipient> mBinderDeathRecipient;
+ android::sp<BinderDeathRecipient> mBinderDeathRecipient GUARDED_BY(mRwMutex);
friend class WatchdogPerfService;
diff --git a/cpp/watchdog/server/src/IoPerfCollection.cpp b/cpp/watchdog/server/src/IoPerfCollection.cpp
index a844fa2..a7e26ca 100644
--- a/cpp/watchdog/server/src/IoPerfCollection.cpp
+++ b/cpp/watchdog/server/src/IoPerfCollection.cpp
@@ -47,15 +47,23 @@
constexpr int32_t kDefaultTopNStatsPerCategory = 10;
constexpr int32_t kDefaultTopNStatsPerSubcategory = 5;
-constexpr const char kBootTimeCollectionTitle[] = "%s\nBoot-time I/O performance report:\n%s\n";
-constexpr const char kPeriodicCollectionTitle[] =
- "%s\nLast N minutes I/O performance report:\n%s\n";
-constexpr const char kCustomCollectionTitle[] = "%s\nCustom I/O performance data report:\n%s\n";
+constexpr int32_t kDefaultMaxUserSwitchEvents = 5;
+constexpr const char kBootTimeCollectionTitle[] = "%s\nBoot-time performance report:\n%s\n";
+constexpr const char kPeriodicCollectionTitle[] = "%s\nLast N minutes performance report:\n%s\n";
+constexpr const char kUserSwitchCollectionTitle[] =
+ "%s\nUser-switch events performance report:\n%s\n";
+constexpr const char kUserSwitchCollectionSubtitle[] = "Number of user switch events: %zu\n";
+constexpr const char kCustomCollectionTitle[] = "%s\nCustom performance data report:\n%s\n";
+constexpr const char kUserSwitchEventTitle[] = "\nEvent %zu: From: %d To: %d\n%s\n";
constexpr const char kCollectionTitle[] =
"Collection duration: %.f seconds\nNumber of collections: %zu\n";
constexpr const char kRecordTitle[] = "\nCollection %zu: <%s>\n%s\n%s";
-constexpr const char kIoReadsTitle[] = "\nTop N Reads:\n%s\n";
-constexpr const char kIoWritesTitle[] = "\nTop N Writes:\n%s\n";
+constexpr const char kCpuTimeTitle[] = "\nTop N CPU Times:\n%s\n";
+constexpr const char kCpuTimeHeader[] =
+ "Android User ID, Package Name, CPU Time (ms), Percentage of total CPU time\n\tCommand, "
+ "CPU Time (ms), Percentage of UID's CPU Time\n";
+constexpr const char kIoReadsTitle[] = "\nTop N Storage I/O Reads:\n%s\n";
+constexpr const char kIoWritesTitle[] = "\nTop N Storage I/O Writes:\n%s\n";
constexpr const char kIoStatsHeader[] =
"Android User ID, Package Name, Foreground Bytes, Foreground Bytes %%, Foreground Fsync, "
"Foreground Fsync %%, Background Bytes, Background Bytes %%, Background Fsync, "
@@ -138,22 +146,24 @@
enum ProcStatType {
IO_BLOCKED_TASKS_COUNT = 0,
MAJOR_FAULTS,
+ CPU_TIME,
PROC_STAT_TYPES,
};
bool cacheTopNProcessStats(ProcStatType procStatType, const ProcessStats& processStats,
- std::vector<UserPackageStats::ProcStats::ProcessCount>* topNProcesses) {
- uint64_t count = procStatType == IO_BLOCKED_TASKS_COUNT ? processStats.ioBlockedTasksCount
- : processStats.totalMajorFaults;
- if (count == 0) {
+ std::vector<UserPackageStats::ProcStats::ProcessValue>* topNProcesses) {
+ uint64_t value = procStatType == CPU_TIME ? processStats.cpuTimeMillis
+ : procStatType == IO_BLOCKED_TASKS_COUNT ? processStats.ioBlockedTasksCount
+ : processStats.totalMajorFaults;
+ if (value == 0) {
return false;
}
for (auto it = topNProcesses->begin(); it != topNProcesses->end(); ++it) {
- if (count > it->count) {
+ if (value > it->value) {
topNProcesses->emplace(it,
- UserPackageStats::ProcStats::ProcessCount{
+ UserPackageStats::ProcStats::ProcessValue{
.comm = processStats.comm,
- .count = count,
+ .value = value,
});
topNProcesses->pop_back();
return true;
@@ -164,12 +174,13 @@
UserPackageStats toUserPackageStats(ProcStatType procStatType, const UidStats& uidStats,
int topNProcessCount) {
- uint64_t count = procStatType == IO_BLOCKED_TASKS_COUNT ? uidStats.procStats.ioBlockedTasksCount
- : uidStats.procStats.totalMajorFaults;
+ uint64_t value = procStatType == CPU_TIME ? uidStats.cpuTimeMillis
+ : procStatType == IO_BLOCKED_TASKS_COUNT ? uidStats.procStats.ioBlockedTasksCount
+ : uidStats.procStats.totalMajorFaults;
UserPackageStats userPackageStats = {
.uid = uidStats.uid(),
.genericPackageName = uidStats.genericPackageName(),
- .stats = UserPackageStats::ProcStats{.count = count},
+ .stats = UserPackageStats::ProcStats{.value = value},
};
auto& procStats = std::get<UserPackageStats::ProcStats>(userPackageStats.stats);
procStats.topNProcesses.resize(topNProcessCount);
@@ -188,14 +199,15 @@
bool cacheTopNProcStats(ProcStatType procStatType, const UidStats& uidStats, int topNProcessCount,
std::vector<UserPackageStats>* topNProcStats) {
- uint64_t count = procStatType == IO_BLOCKED_TASKS_COUNT ? uidStats.procStats.ioBlockedTasksCount
- : uidStats.procStats.totalMajorFaults;
- if (count == 0) {
+ uint64_t value = procStatType == CPU_TIME ? uidStats.cpuTimeMillis
+ : procStatType == IO_BLOCKED_TASKS_COUNT ? uidStats.procStats.ioBlockedTasksCount
+ : uidStats.procStats.totalMajorFaults;
+ if (value == 0) {
return false;
}
for (auto it = topNProcStats->begin(); it != topNProcStats->end(); ++it) {
if (const auto* procStats = std::get_if<UserPackageStats::ProcStats>(&it->stats);
- procStats == nullptr || count > procStats->count) {
+ procStats == nullptr || value > procStats->value) {
topNProcStats->emplace(it,
toUserPackageStats(procStatType, uidStats, topNProcessCount));
topNProcStats->pop_back();
@@ -238,23 +250,30 @@
return buffer;
}
-std::string UserPackageStats::toString(int64_t totalCount) const {
+std::string UserPackageStats::toString(int64_t totalValue) const {
std::string buffer;
const auto& procStats = std::get<UserPackageStats::ProcStats>(stats);
StringAppendF(&buffer, "%" PRIu32 ", %s, %" PRIu64 ", %.2f%%\n", multiuser_get_user_id(uid),
- genericPackageName.c_str(), procStats.count,
- percentage(procStats.count, totalCount));
- for (const auto& processCount : procStats.topNProcesses) {
- StringAppendF(&buffer, "\t%s, %" PRIu64 ", %.2f%%\n", processCount.comm.c_str(),
- processCount.count, percentage(processCount.count, procStats.count));
+ genericPackageName.c_str(), procStats.value,
+ percentage(procStats.value, totalValue));
+ for (const auto& processValue : procStats.topNProcesses) {
+ StringAppendF(&buffer, "\t%s, %" PRIu64 ", %.2f%%\n", processValue.comm.c_str(),
+ processValue.value, percentage(processValue.value, procStats.value));
}
return buffer;
}
std::string UserPackageSummaryStats::toString() const {
std::string buffer;
+ if (!topNCpuTimes.empty()) {
+ StringAppendF(&buffer, kCpuTimeTitle, std::string(16, '-').c_str());
+ StringAppendF(&buffer, kCpuTimeHeader);
+ for (const auto& stats : topNCpuTimes) {
+ StringAppendF(&buffer, "%s", stats.toString(totalCpuTimeMillis).c_str());
+ }
+ }
if (!topNIoReads.empty()) {
- StringAppendF(&buffer, kIoReadsTitle, std::string(12, '-').c_str());
+ StringAppendF(&buffer, kIoReadsTitle, std::string(24, '-').c_str());
StringAppendF(&buffer, kIoStatsHeader);
for (const auto& stats : topNIoReads) {
StringAppendF(&buffer, "%s",
@@ -262,7 +281,7 @@
}
}
if (!topNIoWrites.empty()) {
- StringAppendF(&buffer, kIoWritesTitle, std::string(13, '-').c_str());
+ StringAppendF(&buffer, kIoWritesTitle, std::string(25, '-').c_str());
StringAppendF(&buffer, kIoStatsHeader);
for (const auto& stats : topNIoWrites) {
StringAppendF(&buffer, "%s",
@@ -293,8 +312,12 @@
std::string SystemSummaryStats::toString() const {
std::string buffer;
- StringAppendF(&buffer, "CPU I/O wait time/percent: %" PRIu64 " / %.2f%%\n", cpuIoWaitTime,
- percentage(cpuIoWaitTime, totalCpuTime));
+ StringAppendF(&buffer, "Total CPU time (ms): %" PRIu64 "\n", totalCpuTimeMillis);
+ StringAppendF(&buffer, "Total idle CPU time (ms)/percent: %" PRIu64 " / %.2f%%\n",
+ cpuIdleTimeMillis, percentage(cpuIdleTimeMillis, totalCpuTimeMillis));
+ StringAppendF(&buffer, "CPU I/O wait time (ms)/percent: %" PRIu64 " / %.2f%%\n",
+ cpuIoWaitTimeMillis, percentage(cpuIoWaitTimeMillis, totalCpuTimeMillis));
+ StringAppendF(&buffer, "Number of context switches: %" PRIu64 "\n", contextSwitchesCount);
StringAppendF(&buffer, "Number of I/O blocked processes/percent: %" PRIu32 " / %.2f%%\n",
ioBlockedProcessCount, percentage(ioBlockedProcessCount, totalProcessCount));
return buffer;
@@ -333,6 +356,8 @@
sysprop::topNStatsPerCategory().value_or(kDefaultTopNStatsPerCategory));
mTopNStatsPerSubcategory = static_cast<int>(
sysprop::topNStatsPerSubcategory().value_or(kDefaultTopNStatsPerSubcategory));
+ mMaxUserSwitchEvents = static_cast<size_t>(
+ sysprop::maxUserSwitchEvents().value_or(kDefaultMaxUserSwitchEvents));
size_t periodicCollectionBufferSize = static_cast<size_t>(
sysprop::periodicCollectionBufferSize().value_or(kDefaultPeriodicCollectionBufferSize));
mBoottimeCollection = {
@@ -361,6 +386,8 @@
mPeriodicCollection.records.clear();
mPeriodicCollection = {};
+ mUserSwitchCollections.clear();
+
mCustomCollection.records.clear();
mCustomCollection = {};
}
@@ -370,13 +397,17 @@
if (!WriteStringToFd(StringPrintf(kBootTimeCollectionTitle, std::string(75, '-').c_str(),
std::string(33, '=').c_str()),
fd) ||
- !WriteStringToFd(mBoottimeCollection.toString(), fd) ||
- !WriteStringToFd(StringPrintf(kPeriodicCollectionTitle, std::string(75, '-').c_str(),
+ !WriteStringToFd(mBoottimeCollection.toString(), fd)) {
+ return Error(FAILED_TRANSACTION) << "Failed to dump the boot-time collection report.";
+ }
+ if (const auto& result = onUserSwitchCollectionDump(fd); !result.ok()) {
+ return result.error();
+ }
+ if (!WriteStringToFd(StringPrintf(kPeriodicCollectionTitle, std::string(75, '-').c_str(),
std::string(38, '=').c_str()),
fd) ||
!WriteStringToFd(mPeriodicCollection.toString(), fd)) {
- return Error(FAILED_TRANSACTION)
- << "Failed to dump the boot-time and periodic collection reports.";
+ return Error(FAILED_TRANSACTION) << "Failed to dump the periodic collection report.";
}
return {};
}
@@ -431,6 +462,36 @@
procStatCollectorSp, &mPeriodicCollection);
}
+Result<void> IoPerfCollection::onUserSwitchCollection(
+ time_t time, userid_t from, userid_t to,
+ const android::wp<UidStatsCollectorInterface>& uidStatsCollector,
+ const android::wp<ProcStatCollectorInterface>& procStatCollector) {
+ const sp<UidStatsCollectorInterface> uidStatsCollectorSp = uidStatsCollector.promote();
+ const sp<ProcStatCollectorInterface> procStatCollectorSp = procStatCollector.promote();
+ auto result = checkDataCollectors(uidStatsCollectorSp, procStatCollectorSp);
+ if (!result.ok()) {
+ return result;
+ }
+ Mutex::Autolock lock(mMutex);
+ if (mUserSwitchCollections.empty() || mUserSwitchCollections.back().from != from ||
+ mUserSwitchCollections.back().to != to) {
+ UserSwitchCollectionInfo userSwitchCollection = {
+ {
+ .maxCacheSize = std::numeric_limits<std::size_t>::max(),
+ .records = {},
+ },
+ .from = from,
+ .to = to,
+ };
+ mUserSwitchCollections.push_back(userSwitchCollection);
+ }
+ if (mUserSwitchCollections.size() > mMaxUserSwitchEvents) {
+ mUserSwitchCollections.erase(mUserSwitchCollections.begin());
+ }
+ return processLocked(time, std::unordered_set<std::string>(), uidStatsCollectorSp,
+ procStatCollectorSp, &mUserSwitchCollections.back());
+}
+
Result<void> IoPerfCollection::onCustomCollection(
time_t time, [[maybe_unused]] SystemState systemState,
const std::unordered_set<std::string>& filterPackages,
@@ -459,6 +520,8 @@
};
processUidStatsLocked(filterPackages, uidStatsCollector, &record.userPackageSummaryStats);
processProcStatLocked(procStatCollector, &record.systemSummaryStats);
+ record.userPackageSummaryStats.totalCpuTimeMillis =
+ record.systemSummaryStats.totalCpuTimeMillis;
if (collectionInfo->records.size() > collectionInfo->maxCacheSize) {
collectionInfo->records.erase(collectionInfo->records.begin()); // Erase the oldest record.
}
@@ -475,6 +538,7 @@
return;
}
if (filterPackages.empty()) {
+ userPackageSummaryStats->topNCpuTimes.resize(mTopNStatsPerCategory);
userPackageSummaryStats->topNIoReads.resize(mTopNStatsPerCategory);
userPackageSummaryStats->topNIoWrites.resize(mTopNStatsPerCategory);
userPackageSummaryStats->topNIoBlocked.resize(mTopNStatsPerCategory);
@@ -489,6 +553,8 @@
&userPackageSummaryStats->topNIoReads);
cacheTopNIoStats(MetricType::WRITE_BYTES, curUidStats,
&userPackageSummaryStats->topNIoWrites);
+ cacheTopNProcStats(CPU_TIME, curUidStats, mTopNStatsPerSubcategory,
+ &userPackageSummaryStats->topNCpuTimes);
if (cacheTopNProcStats(IO_BLOCKED_TASKS_COUNT, curUidStats, mTopNStatsPerSubcategory,
&userPackageSummaryStats->topNIoBlocked)) {
userPackageSummaryStats->taskCountByUid[uid] =
@@ -503,6 +569,8 @@
toUserPackageStats(MetricType::READ_BYTES, curUidStats));
userPackageSummaryStats->topNIoWrites.emplace_back(
toUserPackageStats(MetricType::WRITE_BYTES, curUidStats));
+ userPackageSummaryStats->topNCpuTimes.emplace_back(
+ toUserPackageStats(CPU_TIME, curUidStats, mTopNStatsPerSubcategory));
userPackageSummaryStats->topNIoBlocked.emplace_back(
toUserPackageStats(IO_BLOCKED_TASKS_COUNT, curUidStats,
mTopNStatsPerSubcategory));
@@ -529,6 +597,7 @@
}
}
};
+ removeEmptyStats(userPackageSummaryStats->topNCpuTimes);
removeEmptyStats(userPackageSummaryStats->topNIoReads);
removeEmptyStats(userPackageSummaryStats->topNIoWrites);
removeEmptyStats(userPackageSummaryStats->topNIoBlocked);
@@ -539,12 +608,40 @@
const sp<ProcStatCollectorInterface>& procStatCollector,
SystemSummaryStats* systemSummaryStats) const {
const ProcStatInfo& procStatInfo = procStatCollector->deltaStats();
- systemSummaryStats->cpuIoWaitTime = procStatInfo.cpuStats.ioWaitTime;
- systemSummaryStats->totalCpuTime = procStatInfo.totalCpuTime();
+ systemSummaryStats->cpuIoWaitTimeMillis = procStatInfo.cpuStats.ioWaitTimeMillis;
+ systemSummaryStats->cpuIdleTimeMillis = procStatInfo.cpuStats.idleTimeMillis;
+ systemSummaryStats->totalCpuTimeMillis = procStatInfo.totalCpuTimeMillis();
+ systemSummaryStats->contextSwitchesCount = procStatInfo.contextSwitchesCount;
systemSummaryStats->ioBlockedProcessCount = procStatInfo.ioBlockedProcessCount;
systemSummaryStats->totalProcessCount = procStatInfo.totalProcessCount();
}
+Result<void> IoPerfCollection::onUserSwitchCollectionDump(int fd) const {
+ if (!WriteStringToFd(StringPrintf(kUserSwitchCollectionTitle, std::string(75, '-').c_str(),
+ std::string(38, '=').c_str()),
+ fd)) {
+ return Error(FAILED_TRANSACTION) << "Failed to dump the user-switch collection report.";
+ }
+ if (!mUserSwitchCollections.empty() &&
+ !WriteStringToFd(StringPrintf(kUserSwitchCollectionSubtitle, mUserSwitchCollections.size()),
+ fd)) {
+ return Error(FAILED_TRANSACTION) << "Failed to dump the user-switch collection report.";
+ }
+ if (mUserSwitchCollections.empty() && !WriteStringToFd(kEmptyCollectionMessage, fd)) {
+ return Error(FAILED_TRANSACTION) << "Failed to dump the user-switch collection report.";
+ }
+ for (size_t i = 0; i < mUserSwitchCollections.size(); ++i) {
+ const auto& userSwitchCollection = mUserSwitchCollections[i];
+ if (!WriteStringToFd(StringPrintf(kUserSwitchEventTitle, i, userSwitchCollection.from,
+ userSwitchCollection.to, std::string(26, '=').c_str()),
+ fd) ||
+ !WriteStringToFd(userSwitchCollection.toString(), fd)) {
+ return Error(FAILED_TRANSACTION) << "Failed to dump the user-switch collection report.";
+ }
+ }
+ return {};
+}
+
} // namespace watchdog
} // namespace automotive
} // namespace android
diff --git a/cpp/watchdog/server/src/IoPerfCollection.h b/cpp/watchdog/server/src/IoPerfCollection.h
index 31354c8..498413a 100644
--- a/cpp/watchdog/server/src/IoPerfCollection.h
+++ b/cpp/watchdog/server/src/IoPerfCollection.h
@@ -67,18 +67,18 @@
}
};
struct ProcStats {
- uint64_t count = 0;
- struct ProcessCount {
+ uint64_t value = 0;
+ struct ProcessValue {
std::string comm = "";
- uint64_t count = 0;
+ uint64_t value = 0;
};
- std::vector<ProcessCount> topNProcesses = {};
+ std::vector<ProcessValue> topNProcesses = {};
};
uid_t uid = 0;
std::string genericPackageName = "";
std::variant<std::monostate, IoStats, ProcStats> stats;
std::string toString(MetricType metricsType, const int64_t totalIoStats[][UID_STATES]) const;
- std::string toString(int64_t count) const;
+ std::string toString(int64_t totalValue) const;
};
/**
@@ -86,12 +86,14 @@
* `/proc/[pid]/stat`, `/proc/[pid]/task/[tid]/stat`, and /proc/[pid]/status` files.
*/
struct UserPackageSummaryStats {
+ std::vector<UserPackageStats> topNCpuTimes = {};
std::vector<UserPackageStats> topNIoReads = {};
std::vector<UserPackageStats> topNIoWrites = {};
std::vector<UserPackageStats> topNIoBlocked = {};
std::vector<UserPackageStats> topNMajorFaults = {};
int64_t totalIoStats[METRIC_TYPES][UID_STATES] = {{0}};
std::unordered_map<uid_t, uint64_t> taskCountByUid = {};
+ int64_t totalCpuTimeMillis = 0;
uint64_t totalMajorFaults = 0;
// Percentage of increase/decrease in the major page faults since last collection.
double majorFaultsPercentChange = 0.0;
@@ -100,8 +102,10 @@
// System performance stats collected from the `/proc/stats` file.
struct SystemSummaryStats {
- uint64_t cpuIoWaitTime = 0;
- uint64_t totalCpuTime = 0;
+ int64_t cpuIoWaitTimeMillis = 0;
+ int64_t cpuIdleTimeMillis = 0;
+ int64_t totalCpuTimeMillis = 0;
+ uint64_t contextSwitchesCount = 0;
uint32_t ioBlockedProcessCount = 0;
uint32_t totalProcessCount = 0;
std::string toString() const;
@@ -122,14 +126,22 @@
std::string toString() const;
};
+// Group of performance records collected for a user switch collection event.
+struct UserSwitchCollectionInfo : CollectionInfo {
+ userid_t from = 0;
+ userid_t to = 0;
+};
+
// IoPerfCollection implements the I/O performance data collection module.
class IoPerfCollection final : public DataProcessorInterface {
public:
IoPerfCollection() :
mTopNStatsPerCategory(0),
mTopNStatsPerSubcategory(0),
+ mMaxUserSwitchEvents(0),
mBoottimeCollection({}),
mPeriodicCollection({}),
+ mUserSwitchCollections({}),
mCustomCollection({}),
mLastMajorFaults(0) {}
@@ -147,6 +159,11 @@
const android::wp<UidStatsCollectorInterface>& uidStatsCollector,
const android::wp<ProcStatCollectorInterface>& procStatCollector) override;
+ android::base::Result<void> onUserSwitchCollection(
+ time_t time, userid_t from, userid_t to,
+ const android::wp<UidStatsCollectorInterface>& uidStatsCollector,
+ const android::wp<ProcStatCollectorInterface>& procStatCollector) override;
+
android::base::Result<void> onCustomCollection(
time_t time, SystemState systemState,
const std::unordered_set<std::string>& filterPackages,
@@ -189,34 +206,37 @@
void processProcStatLocked(const android::sp<ProcStatCollectorInterface>& procStatCollector,
SystemSummaryStats* systemSummaryStats) const;
+ // Dump the user switch collection
+ android::base::Result<void> onUserSwitchCollectionDump(int fd) const;
+
// Top N per-UID stats per category.
int mTopNStatsPerCategory;
// Top N per-process stats per subcategory.
int mTopNStatsPerSubcategory;
+ // Max amount of user switch events cached in |mUserSwitchCollections|.
+ size_t mMaxUserSwitchEvents;
+
// Makes sure only one collection is running at any given time.
mutable Mutex mMutex;
// Info for the boot-time collection event. The cache is persisted until system shutdown/reboot.
CollectionInfo mBoottimeCollection GUARDED_BY(mMutex);
- /**
- * Info for the periodic collection event. The cache size is limited by
- * |ro.carwatchdog.periodic_collection_buffer_size|.
- */
+ // Info for the periodic collection event. The cache size is limited by
+ // |ro.carwatchdog.periodic_collection_buffer_size|.
CollectionInfo mPeriodicCollection GUARDED_BY(mMutex);
- /**
- * Info for the custom collection event. The info is cleared at the end of every custom
- * collection.
- */
+ // Cache for user switch collection events. Events are cached from oldest to newest.
+ std::vector<UserSwitchCollectionInfo> mUserSwitchCollections GUARDED_BY(mMutex);
+
+ // Info for the custom collection event. The info is cleared at the end of every custom
+ // collection.
CollectionInfo mCustomCollection GUARDED_BY(mMutex);
- /**
- * Major faults delta from last collection. Useful when calculating the percentage change in
- * major faults since last collection.
- */
+ // Major faults delta from last collection. Useful when calculating the percentage change in
+ // major faults since last collection.
uint64_t mLastMajorFaults GUARDED_BY(mMutex);
friend class WatchdogPerfService;
diff --git a/cpp/watchdog/server/src/ProcStatCollector.cpp b/cpp/watchdog/server/src/ProcStatCollector.cpp
index e120d2d..5c96576 100644
--- a/cpp/watchdog/server/src/ProcStatCollector.cpp
+++ b/cpp/watchdog/server/src/ProcStatCollector.cpp
@@ -31,15 +31,16 @@
namespace watchdog {
using ::android::base::Error;
+using ::android::base::ParseInt;
+using ::android::base::ParseUint;
using ::android::base::ReadFileToString;
using ::android::base::Result;
+using ::android::base::Split;
using ::android::base::StartsWith;
-using base::ParseUint;
-using base::Split;
namespace {
-bool parseCpuStats(const std::string& data, CpuStats* cpuStats) {
+bool parseCpuStats(const std::string& data, CpuStats* cpuStats, int32_t millisPerClockTick) {
std::vector<std::string> fields = Split(data, " ");
if (fields.size() == 12 && fields[1].empty()) {
/* The first cpu line will have an extra space after the first word. This will generate an
@@ -47,17 +48,40 @@
*/
fields.erase(fields.begin() + 1);
}
- if (fields.size() != 11 || fields[0] != "cpu" || !ParseUint(fields[1], &cpuStats->userTime) ||
- !ParseUint(fields[2], &cpuStats->niceTime) || !ParseUint(fields[3], &cpuStats->sysTime) ||
- !ParseUint(fields[4], &cpuStats->idleTime) ||
- !ParseUint(fields[5], &cpuStats->ioWaitTime) || !ParseUint(fields[6], &cpuStats->irqTime) ||
- !ParseUint(fields[7], &cpuStats->softIrqTime) ||
- !ParseUint(fields[8], &cpuStats->stealTime) ||
- !ParseUint(fields[9], &cpuStats->guestTime) ||
- !ParseUint(fields[10], &cpuStats->guestNiceTime)) {
+ if (fields.size() != 11 || fields[0] != "cpu" ||
+ !ParseInt(fields[1], &cpuStats->userTimeMillis) ||
+ !ParseInt(fields[2], &cpuStats->niceTimeMillis) ||
+ !ParseInt(fields[3], &cpuStats->sysTimeMillis) ||
+ !ParseInt(fields[4], &cpuStats->idleTimeMillis) ||
+ !ParseInt(fields[5], &cpuStats->ioWaitTimeMillis) ||
+ !ParseInt(fields[6], &cpuStats->irqTimeMillis) ||
+ !ParseInt(fields[7], &cpuStats->softIrqTimeMillis) ||
+ !ParseInt(fields[8], &cpuStats->stealTimeMillis) ||
+ !ParseInt(fields[9], &cpuStats->guestTimeMillis) ||
+ !ParseInt(fields[10], &cpuStats->guestNiceTimeMillis)) {
ALOGW("Invalid cpu line: \"%s\"", data.c_str());
return false;
}
+ // Convert clock ticks to millis
+ cpuStats->userTimeMillis *= millisPerClockTick;
+ cpuStats->niceTimeMillis *= millisPerClockTick;
+ cpuStats->sysTimeMillis *= millisPerClockTick;
+ cpuStats->idleTimeMillis *= millisPerClockTick;
+ cpuStats->ioWaitTimeMillis *= millisPerClockTick;
+ cpuStats->irqTimeMillis *= millisPerClockTick;
+ cpuStats->softIrqTimeMillis *= millisPerClockTick;
+ cpuStats->stealTimeMillis *= millisPerClockTick;
+ cpuStats->guestTimeMillis *= millisPerClockTick;
+ cpuStats->guestNiceTimeMillis *= millisPerClockTick;
+ return true;
+}
+
+bool parseContextSwitches(const std::string& data, uint64_t* out) {
+ std::vector<std::string> fields = Split(data, " ");
+ if (fields.size() != 2 || !StartsWith(fields[0], "ctxt") || !ParseUint(fields[1], out)) {
+ ALOGW("Invalid ctxt line: \"%s\"", data.c_str());
+ return false;
+ }
return true;
}
@@ -74,7 +98,7 @@
Result<void> ProcStatCollector::collect() {
if (!mEnabled) {
- return Error() << "Can not access " << kPath;
+ return Error() << "Cannot access " << kPath;
}
Mutex::Autolock lock(mMutex);
@@ -98,6 +122,7 @@
std::vector<std::string> lines = Split(std::move(buffer), "\n");
ProcStatInfo info;
+ bool didReadContextSwitches = false;
bool didReadProcsRunning = false;
bool didReadProcsBlocked = false;
for (size_t i = 0; i < lines.size(); i++) {
@@ -105,12 +130,20 @@
continue;
}
if (!lines[i].compare(0, 4, "cpu ")) {
- if (info.totalCpuTime() != 0) {
+ if (info.totalCpuTimeMillis() != 0) {
return Error() << "Duplicate `cpu .*` line in " << kPath;
}
- if (!parseCpuStats(std::move(lines[i]), &info.cpuStats)) {
+ if (!parseCpuStats(lines[i], &info.cpuStats, mMillisPerClockTick)) {
return Error() << "Failed to parse `cpu .*` line in " << kPath;
}
+ } else if (!lines[i].compare(0, 4, "ctxt")) {
+ if (didReadContextSwitches) {
+ return Error() << "Duplicate `ctxt .*` line in " << kPath;
+ }
+ if (!parseContextSwitches(std::move(lines[i]), &info.contextSwitchesCount)) {
+ return Error() << "Failed to parse `ctxt .*` line in " << kPath;
+ }
+ didReadContextSwitches = true;
} else if (!lines[i].compare(0, 6, "procs_")) {
if (!lines[i].compare(0, 13, "procs_running")) {
if (didReadProcsRunning) {
@@ -134,7 +167,8 @@
return Error() << "Unknown procs_ line `" << lines[i] << "` in " << kPath;
}
}
- if (info.totalCpuTime() == 0 || !didReadProcsRunning || !didReadProcsBlocked) {
+ if (info.totalCpuTimeMillis() == 0 || !didReadContextSwitches || !didReadProcsRunning ||
+ !didReadProcsBlocked) {
return Error() << kPath << " is incomplete";
}
return info;
diff --git a/cpp/watchdog/server/src/ProcStatCollector.h b/cpp/watchdog/server/src/ProcStatCollector.h
index 9516c7d..6296aef 100644
--- a/cpp/watchdog/server/src/ProcStatCollector.h
+++ b/cpp/watchdog/server/src/ProcStatCollector.h
@@ -30,45 +30,55 @@
constexpr const char* kProcStatPath = "/proc/stat";
struct CpuStats {
- uint64_t userTime = 0; // Time spent in user mode.
- uint64_t niceTime = 0; // Time spent in user mode with low priority (nice).
- uint64_t sysTime = 0; // Time spent in system mode.
- uint64_t idleTime = 0; // Time spent in the idle task.
- uint64_t ioWaitTime = 0; // Time spent on context switching/waiting due to I/O operations.
- uint64_t irqTime = 0; // Time servicing interrupts.
- uint64_t softIrqTime = 0; // Time servicing soft interrupts.
- uint64_t stealTime = 0; // Stolen time (Time spent in other OS in a virtualized env).
- uint64_t guestTime = 0; // Time spent running a virtual CPU for guest OS.
- uint64_t guestNiceTime = 0; // Time spent running a niced virtual CPU for guest OS.
+ int64_t userTimeMillis = 0; // Time spent in user mode.
+ int64_t niceTimeMillis = 0; // Time spent in user mode with low priority (nice).
+ int64_t sysTimeMillis = 0; // Time spent in system mode.
+ int64_t idleTimeMillis = 0; // Time spent in the idle task.
+ int64_t ioWaitTimeMillis = 0; // Time spent on context switching/waiting due to I/O operations.
+ int64_t irqTimeMillis = 0; // Time servicing interrupts.
+ int64_t softIrqTimeMillis = 0; // Time servicing soft interrupts.
+ int64_t stealTimeMillis = 0; // Stolen time (Time spent in other OS in a virtualized env).
+ int64_t guestTimeMillis = 0; // Time spent running a virtual CPU for guest OS.
+ int64_t guestNiceTimeMillis = 0; // Time spent running a niced virtual CPU for guest OS.
CpuStats& operator-=(const CpuStats& rhs) {
- userTime -= rhs.userTime;
- niceTime -= rhs.niceTime;
- sysTime -= rhs.sysTime;
- idleTime -= rhs.idleTime;
- ioWaitTime -= rhs.ioWaitTime;
- irqTime -= rhs.irqTime;
- softIrqTime -= rhs.softIrqTime;
- stealTime -= rhs.stealTime;
- guestTime -= rhs.guestTime;
- guestNiceTime -= rhs.guestNiceTime;
+ userTimeMillis -= rhs.userTimeMillis;
+ niceTimeMillis -= rhs.niceTimeMillis;
+ sysTimeMillis -= rhs.sysTimeMillis;
+ idleTimeMillis -= rhs.idleTimeMillis;
+ ioWaitTimeMillis -= rhs.ioWaitTimeMillis;
+ irqTimeMillis -= rhs.irqTimeMillis;
+ softIrqTimeMillis -= rhs.softIrqTimeMillis;
+ stealTimeMillis -= rhs.stealTimeMillis;
+ guestTimeMillis -= rhs.guestTimeMillis;
+ guestNiceTimeMillis -= rhs.guestNiceTimeMillis;
return *this;
}
};
class ProcStatInfo {
public:
- ProcStatInfo() : cpuStats({}), runnableProcessCount(0), ioBlockedProcessCount(0) {}
- ProcStatInfo(CpuStats stats, uint32_t runnableCnt, uint32_t ioBlockedCnt) :
- cpuStats(stats), runnableProcessCount(runnableCnt), ioBlockedProcessCount(ioBlockedCnt) {}
+ ProcStatInfo() :
+ cpuStats({}),
+ contextSwitchesCount(0),
+ runnableProcessCount(0),
+ ioBlockedProcessCount(0) {}
+ ProcStatInfo(CpuStats stats, uint64_t ctxtSwitches, uint32_t runnableCnt,
+ uint32_t ioBlockedCnt) :
+ cpuStats(stats),
+ contextSwitchesCount(ctxtSwitches),
+ runnableProcessCount(runnableCnt),
+ ioBlockedProcessCount(ioBlockedCnt) {}
CpuStats cpuStats;
+ uint64_t contextSwitchesCount;
uint32_t runnableProcessCount;
uint32_t ioBlockedProcessCount;
- uint64_t totalCpuTime() const {
- return cpuStats.userTime + cpuStats.niceTime + cpuStats.sysTime + cpuStats.idleTime +
- cpuStats.ioWaitTime + cpuStats.irqTime + cpuStats.softIrqTime + cpuStats.stealTime +
- cpuStats.guestTime + cpuStats.guestNiceTime;
+ int64_t totalCpuTimeMillis() const {
+ return cpuStats.userTimeMillis + cpuStats.niceTimeMillis + cpuStats.sysTimeMillis +
+ cpuStats.idleTimeMillis + cpuStats.ioWaitTimeMillis + cpuStats.irqTimeMillis +
+ cpuStats.softIrqTimeMillis + cpuStats.stealTimeMillis + cpuStats.guestTimeMillis +
+ cpuStats.guestNiceTimeMillis;
}
uint32_t totalProcessCount() const { return runnableProcessCount + ioBlockedProcessCount; }
bool operator==(const ProcStatInfo& info) const {
@@ -111,7 +121,7 @@
class ProcStatCollector final : public ProcStatCollectorInterface {
public:
explicit ProcStatCollector(const std::string& path = kProcStatPath) :
- kPath(path), mLatestStats({}) {}
+ kPath(path), mMillisPerClockTick(1000 / sysconf(_SC_CLK_TCK)), mLatestStats({}) {}
~ProcStatCollector() {}
@@ -149,6 +159,9 @@
// Path to proc stat file. Default path is |kProcStatPath|.
const std::string kPath;
+ // Number of milliseconds per clock cycle.
+ int32_t mMillisPerClockTick;
+
// Makes sure only one collection is running at any given time.
mutable Mutex mMutex;
diff --git a/cpp/watchdog/server/src/ThreadPriorityController.cpp b/cpp/watchdog/server/src/ThreadPriorityController.cpp
new file mode 100644
index 0000000..67d6ce0
--- /dev/null
+++ b/cpp/watchdog/server/src/ThreadPriorityController.cpp
@@ -0,0 +1,149 @@
+/**
+ * Copyright (c) 2022, 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 "ThreadPriorityController.h"
+
+#include "UidProcStatsCollector.h"
+
+namespace android {
+namespace automotive {
+namespace watchdog {
+
+namespace {
+
+using ::android::automotive::watchdog::internal::ThreadPolicyWithPriority;
+using ::android::base::Result;
+using ::android::binder::Status;
+
+Status fromExceptionCode(int32_t exceptionCode, const std::string& message) {
+ ALOGW("%s", message.c_str());
+ return Status::fromExceptionCode(exceptionCode, message.c_str());
+}
+
+Status fromServiceSpecificError(const std::string& message) {
+ ALOGW("%s", message.c_str());
+ return Status::fromServiceSpecificError(/*exceptionCode=*/0, message.c_str());
+}
+
+constexpr int PRIORITY_MIN = 1;
+constexpr int PRIORITY_MAX = 99;
+
+} // namespace
+
+Status ThreadPriorityController::checkPidTidUid(pid_t pid, pid_t tid, uid_t uid) {
+ auto tidStatus = mSystemCallsInterface->readPidStatusFileForPid(tid);
+ if (!tidStatus.ok()) {
+ return fromExceptionCode(Status::EX_ILLEGAL_STATE,
+ StringPrintf("invalid thread ID: %d", tid));
+ }
+ uid_t uidForThread = std::get<0>(*tidStatus);
+ pid_t tgid = std::get<1>(*tidStatus);
+ if (pid != tgid) {
+ return fromExceptionCode(Status::EX_ILLEGAL_STATE,
+ StringPrintf("invalid process ID: %d", pid));
+ }
+ if (uid != uidForThread) {
+ return fromExceptionCode(Status::EX_ILLEGAL_STATE,
+ StringPrintf("invalid user ID: %d", uid));
+ }
+ return Status::ok();
+}
+
+Status ThreadPriorityController::setThreadPriority(int pid, int tid, int uid, int policy,
+ int priority) {
+ pid_t tpid = static_cast<pid_t>(tid);
+ pid_t ppid = static_cast<pid_t>(pid);
+ uid_t uuid = static_cast<uid_t>(uid);
+ Status status = checkPidTidUid(ppid, tpid, uuid);
+ if (!status.isOk()) {
+ return status;
+ }
+
+ if (policy != SCHED_FIFO && policy != SCHED_RR && policy != SCHED_OTHER) {
+ return fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT,
+ StringPrintf("invalid policy: %d, only support SCHED_OTHER(%d)"
+ ", SCHED_FIFO(%d) and SCHED_RR(%d)",
+ policy, SCHED_OTHER, SCHED_FIFO, SCHED_RR));
+ }
+
+ if (policy == SCHED_OTHER) {
+ priority = 0;
+ } else if (priority < PRIORITY_MIN || priority > PRIORITY_MAX) {
+ return fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT,
+ StringPrintf("invalid priority: %d for policy: (%d), "
+ "must be within %d and %d",
+ priority, policy, PRIORITY_MIN, PRIORITY_MAX));
+ }
+
+ sched_param param{.sched_priority = priority};
+ errno = 0;
+ if (mSystemCallsInterface->setScheduler(tpid, policy, ¶m) != 0) {
+ return fromServiceSpecificError(
+ StringPrintf("sched_setscheduler failed, errno: %d", errno));
+ }
+ return Status::ok();
+}
+
+Status ThreadPriorityController::getThreadPriority(int pid, int tid, int uid,
+ ThreadPolicyWithPriority* result) {
+ pid_t tpid = static_cast<pid_t>(tid);
+ pid_t ppid = static_cast<pid_t>(pid);
+ uid_t uuid = static_cast<uid_t>(uid);
+ Status status = checkPidTidUid(ppid, tpid, uuid);
+ if (!status.isOk()) {
+ return status;
+ }
+
+ errno = 0;
+ int policy = mSystemCallsInterface->getScheduler(tpid);
+ if (policy < 0) {
+ return fromServiceSpecificError(
+ StringPrintf("sched_getscheduler failed, errno: %d", errno));
+ }
+
+ sched_param param = {};
+ errno = 0;
+ int callResult = mSystemCallsInterface->getParam(tpid, ¶m);
+ if (callResult != 0) {
+ return fromServiceSpecificError(StringPrintf("sched_getparam failed, errno: %d", errno));
+ }
+
+ result->policy = policy;
+ result->priority = param.sched_priority;
+ return Status::ok();
+}
+
+int ThreadPriorityController::SystemCalls::setScheduler(pid_t tid, int policy,
+ const sched_param* param) {
+ return sched_setscheduler(tid, policy, param);
+}
+
+int ThreadPriorityController::SystemCalls::getScheduler(pid_t tid) {
+ return sched_getscheduler(tid);
+}
+
+int ThreadPriorityController::SystemCalls::getParam(pid_t tid, sched_param* param) {
+ return sched_getparam(tid, param);
+}
+
+Result<std::tuple<uid_t, pid_t>> ThreadPriorityController::SystemCalls::readPidStatusFileForPid(
+ pid_t pid) {
+ return UidProcStatsCollector::readPidStatusFileForPid(pid);
+}
+
+} // namespace watchdog
+} // namespace automotive
+} // namespace android
diff --git a/cpp/watchdog/server/src/ThreadPriorityController.h b/cpp/watchdog/server/src/ThreadPriorityController.h
new file mode 100644
index 0000000..5ff2e02
--- /dev/null
+++ b/cpp/watchdog/server/src/ThreadPriorityController.h
@@ -0,0 +1,70 @@
+/**
+ * Copyright (c) 2022, 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 CPP_WATCHDOG_SERVER_SRC_THREADPRIORITYCONTROLLER_H_
+#define CPP_WATCHDOG_SERVER_SRC_THREADPRIORITYCONTROLLER_H_
+
+#include <android-base/result.h>
+#include <android/automotive/watchdog/internal/ThreadPolicyWithPriority.h>
+
+#include <sched.h>
+
+namespace android {
+namespace automotive {
+namespace watchdog {
+
+class ThreadPriorityController final {
+public:
+ // An interface for stubbing system calls in unit testing.
+ class SystemCallsInterface {
+ public:
+ virtual int setScheduler(pid_t tid, int policy, const sched_param* param) = 0;
+ virtual int getScheduler(pid_t tid) = 0;
+ virtual int getParam(pid_t tid, sched_param* param) = 0;
+ virtual android::base::Result<std::tuple<uid_t, pid_t>> readPidStatusFileForPid(
+ pid_t pid) = 0;
+
+ virtual ~SystemCallsInterface() = default;
+ };
+
+ ThreadPriorityController() : mSystemCallsInterface(std::make_unique<SystemCalls>()) {}
+
+ explicit ThreadPriorityController(std::unique_ptr<SystemCallsInterface> s) :
+ mSystemCallsInterface(std::move(s)) {}
+
+ android::binder::Status setThreadPriority(int pid, int tid, int uid, int policy, int priority);
+ android::binder::Status getThreadPriority(
+ int pid, int tid, int uid,
+ android::automotive::watchdog::internal::ThreadPolicyWithPriority* result);
+
+private:
+ class SystemCalls final : public SystemCallsInterface {
+ int setScheduler(pid_t tid, int policy, const sched_param* param) override;
+ int getScheduler(pid_t tid) override;
+ int getParam(pid_t tid, sched_param* param) override;
+ android::base::Result<std::tuple<uid_t, pid_t>> readPidStatusFileForPid(pid_t pid) override;
+ };
+
+ std::unique_ptr<SystemCallsInterface> mSystemCallsInterface;
+
+ android::binder::Status checkPidTidUid(pid_t pid, pid_t tid, uid_t uid);
+};
+
+} // namespace watchdog
+} // namespace automotive
+} // namespace android
+
+#endif // CPP_WATCHDOG_SERVER_SRC_THREADPRIORITYCONTROLLER_H_
diff --git a/cpp/watchdog/server/src/UidCpuStatsCollector.cpp b/cpp/watchdog/server/src/UidCpuStatsCollector.cpp
new file mode 100644
index 0000000..a3b01b0
--- /dev/null
+++ b/cpp/watchdog/server/src/UidCpuStatsCollector.cpp
@@ -0,0 +1,135 @@
+/*
+ * Copyright (c) 2022, 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.
+ */
+
+#define LOG_TAG "carwatchdogd"
+
+#include "UidCpuStatsCollector.h"
+
+#include <android-base/file.h>
+#include <android-base/parseint.h>
+#include <android-base/strings.h>
+
+#include <inttypes.h>
+
+#include <string>
+#include <unordered_map>
+#include <vector>
+
+namespace android {
+namespace automotive {
+namespace watchdog {
+
+namespace {
+
+using ::android::base::EndsWith;
+using ::android::base::Error;
+using ::android::base::ParseInt;
+using ::android::base::ReadFileToString;
+using ::android::base::Result;
+using ::android::base::Split;
+
+enum class ReadError : int {
+ ERR_INVALID_FILE,
+ ERR_FILE_OPEN_READ,
+ NUM_ERRORS,
+};
+
+/**
+ * Returns a map of CPU time in milliseconds spent by each UID since system boot up.
+ *
+ * /proc/uid_cputime/show_uid_stat file format:
+ * <uid>: <user_time_micro_seconds> <system_time_micro_seconds>
+ */
+Result<std::unordered_map<uid_t, int64_t>> readUidCpuTimeFile(const std::string& path) {
+ std::string buffer;
+ if (!ReadFileToString(path, &buffer)) {
+ return Error(static_cast<int>(ReadError::ERR_FILE_OPEN_READ))
+ << "ReadFileToString failed for " << path;
+ }
+ std::unordered_map<uid_t, int64_t> cpuTimeMillisByUid;
+ std::vector<std::string> lines = Split(buffer, "\n");
+ for (size_t i = 0; i < lines.size(); i++) {
+ if (lines[i].empty()) {
+ continue;
+ }
+ const std::string delimiter = " ";
+ std::vector<std::string> elements = Split(lines[i], delimiter);
+ if (elements.size() < 3) {
+ return Error(static_cast<int>(ReadError::ERR_INVALID_FILE))
+ << "Line \"" << lines[i] << "\" doesn't contain the delimiter \"" << delimiter
+ << "\" in file " << path;
+ }
+ if (EndsWith(elements[0], ":")) {
+ elements[0].pop_back();
+ }
+ int64_t uid = -1;
+ int64_t userCpuTimeUs = 0;
+ int64_t systemCpuTimeUs = 0;
+ if (!ParseInt(elements[0], &uid) || !ParseInt(elements[1], &userCpuTimeUs) ||
+ !ParseInt(elements[2], &systemCpuTimeUs)) {
+ return Error(static_cast<int>(ReadError::ERR_INVALID_FILE))
+ << "Failed to parse line from file: " << path << ", error: line " << lines[i]
+ << " has invalid format";
+ }
+ if (cpuTimeMillisByUid.find(uid) != cpuTimeMillisByUid.end()) {
+ return Error(static_cast<int>(ReadError::ERR_INVALID_FILE))
+ << "Duplicate " << uid << " line: \"" << lines[i] << "\" in file " << path;
+ }
+ // Store CPU time as milliseconds
+ cpuTimeMillisByUid[uid] = userCpuTimeUs / 1000 + systemCpuTimeUs / 1000;
+ }
+ if (cpuTimeMillisByUid.empty()) {
+ return Error(static_cast<int>(ReadError::ERR_INVALID_FILE)) << "Empty file: " << path;
+ }
+ return cpuTimeMillisByUid;
+}
+
+} // namespace
+
+Result<void> UidCpuStatsCollector::collect() {
+ Mutex::Autolock lock(mMutex);
+ if (!mEnabled) {
+ return Error() << "Can not access: " << mPath;
+ }
+ auto cpuTimeMillisByUid = readUidCpuTimeFile(mPath);
+ if (!cpuTimeMillisByUid.ok()) {
+ return Error(cpuTimeMillisByUid.error().code())
+ << "Failed to read top-level per UID CPU time file " << mPath << ": "
+ << cpuTimeMillisByUid.error().message();
+ }
+
+ mDeltaStats.clear();
+ for (const auto& [uid, cpuTime] : *cpuTimeMillisByUid) {
+ if (cpuTime == 0) {
+ continue;
+ }
+ int64_t deltaCpuTime = cpuTime;
+ if (const auto& it = mLatestStats.find(uid);
+ it != mLatestStats.end() && it->second <= deltaCpuTime) {
+ deltaCpuTime -= it->second;
+ if (deltaCpuTime == 0) {
+ continue;
+ }
+ }
+ mDeltaStats[uid] = deltaCpuTime;
+ }
+ mLatestStats = std::move(*cpuTimeMillisByUid);
+ return {};
+}
+
+} // namespace watchdog
+} // namespace automotive
+} // namespace android
diff --git a/cpp/watchdog/server/src/UidCpuStatsCollector.h b/cpp/watchdog/server/src/UidCpuStatsCollector.h
new file mode 100644
index 0000000..5d49196
--- /dev/null
+++ b/cpp/watchdog/server/src/UidCpuStatsCollector.h
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) 2022, 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 CPP_WATCHDOG_SERVER_SRC_UIDCPUSTATSCOLLECTOR_H_
+#define CPP_WATCHDOG_SERVER_SRC_UIDCPUSTATSCOLLECTOR_H_
+
+#include <android-base/result.h>
+#include <android-base/stringprintf.h>
+#include <utils/Mutex.h>
+#include <utils/RefBase.h>
+
+#include <stdint.h>
+
+#include <string>
+#include <unordered_map>
+
+namespace android {
+namespace automotive {
+namespace watchdog {
+
+inline constexpr char kShowUidCpuTimeFile[] = "/proc/uid_cputime/show_uid_stat";
+
+// Collector/Parser for `/proc/uid_cputime/show_uid_stat`.
+class UidCpuStatsCollectorInterface : public RefBase {
+public:
+ // Initializes the collector.
+ virtual void init() = 0;
+ // Collects the per-UID CPU stats.
+ virtual android::base::Result<void> collect() = 0;
+ // Returns the latest per-UID CPU stats.
+ virtual const std::unordered_map<uid_t, int64_t> latestStats() const = 0;
+ // Returns the delta of per-UID CPU stats since the last before collection.
+ virtual const std::unordered_map<uid_t, int64_t> deltaStats() const = 0;
+ // Returns true only when the per-UID CPU stats file is accessible.
+ virtual bool enabled() const = 0;
+ // Returns the path for the per-UID CPU stats file.
+ virtual const std::string filePath() const = 0;
+};
+
+class UidCpuStatsCollector final : public UidCpuStatsCollectorInterface {
+public:
+ explicit UidCpuStatsCollector(const std::string& path = kShowUidCpuTimeFile) : mPath(path) {}
+
+ ~UidCpuStatsCollector() {}
+
+ void init() override {
+ Mutex::Autolock lock(mMutex);
+ // Note: Verify proc file access outside the constructor. Otherwise, the unittests of
+ // dependent classes would call the constructor before mocking and get killed due to
+ // sepolicy violation.
+ mEnabled = access(mPath.c_str(), R_OK) == 0;
+ }
+
+ android::base::Result<void> collect() override;
+
+ const std::unordered_map<uid_t, int64_t> latestStats() const override {
+ Mutex::Autolock lock(mMutex);
+ return mLatestStats;
+ }
+
+ const std::unordered_map<uid_t, int64_t> deltaStats() const override {
+ Mutex::Autolock lock(mMutex);
+ return mDeltaStats;
+ }
+
+ bool enabled() const override {
+ Mutex::Autolock lock(mMutex);
+ return mEnabled;
+ }
+
+ const std::string filePath() const override { return mPath; }
+
+private:
+ // Path to show_uid_stat file. Default path is |kShowUidCpuTimeFile|.
+ const std::string mPath;
+
+ // Makes sure only one collection is running at any given time.
+ mutable Mutex mMutex;
+
+ // True if |mPath| is accessible.
+ bool mEnabled GUARDED_BY(mMutex);
+
+ // Latest dump from the file at |mPath|.
+ std::unordered_map<uid_t, int64_t> mLatestStats GUARDED_BY(mMutex);
+
+ // Delta of per-UID CPU stats since last before collection.
+ std::unordered_map<uid_t, int64_t> mDeltaStats GUARDED_BY(mMutex);
+};
+
+} // namespace watchdog
+} // namespace automotive
+} // namespace android
+
+#endif // CPP_WATCHDOG_SERVER_SRC_UIDCPUSTATSCOLLECTOR_H_
diff --git a/cpp/watchdog/server/src/UidProcStatsCollector.cpp b/cpp/watchdog/server/src/UidProcStatsCollector.cpp
index aa1ddf2..c98c687 100644
--- a/cpp/watchdog/server/src/UidProcStatsCollector.cpp
+++ b/cpp/watchdog/server/src/UidProcStatsCollector.cpp
@@ -21,6 +21,7 @@
#include <android-base/file.h>
#include <android-base/parseint.h>
+#include <android-base/result.h>
#include <android-base/stringprintf.h>
#include <android-base/strings.h>
#include <log/log.h>
@@ -47,20 +48,15 @@
namespace {
+constexpr const char* kProcPidStatFileFormat = "/proc/%" PRIu32 "/stat";
+constexpr const char* kProcPidStatusFileFormat = "/proc/%" PRIu32 "/status";
+
enum ReadError {
ERR_INVALID_FILE = 0,
ERR_FILE_OPEN_READ = 1,
NUM_ERRORS = 2,
};
-// Per-pid/tid stats.
-struct PidStat {
- std::string comm = "";
- std::string state = "";
- uint64_t startTime = 0;
- uint64_t majorFaults = 0;
-};
-
/**
* /proc/PID/stat or /proc/PID/task/TID/stat format:
* <pid> <comm> <state> <ppid> <pgrp ID> <session ID> <tty_nr> <tpgid> <flags> <minor faults>
@@ -100,17 +96,21 @@
pidStat->comm.erase(pidStat->comm.begin());
pidStat->comm.erase(pidStat->comm.end() - 1);
+ int64_t systemCpuTime = 0;
if (fields.size() < 22 + commEndOffset ||
!ParseUint(fields[11 + commEndOffset], &pidStat->majorFaults) ||
- !ParseUint(fields[21 + commEndOffset], &pidStat->startTime)) {
+ !ParseInt(fields[13 + commEndOffset], &pidStat->cpuTimeMillis) ||
+ !ParseInt(fields[14 + commEndOffset], &systemCpuTime) ||
+ !ParseInt(fields[21 + commEndOffset], &pidStat->startTimeMillis)) {
ALOGD("Invalid proc pid stat contents: \"%s\"", line.c_str());
return false;
}
+ pidStat->cpuTimeMillis += systemCpuTime;
pidStat->state = fields[2 + commEndOffset];
return true;
}
-Result<void> readPidStatFile(const std::string& path, PidStat* pidStat) {
+Result<PidStat> readPidStatFile(const std::string& path, int32_t millisPerClockTick) {
std::string buffer;
if (!ReadFileToString(path, &buffer)) {
return Error(ERR_FILE_OPEN_READ) << "ReadFileToString failed for " << path;
@@ -119,10 +119,13 @@
if (lines.size() != 1 && (lines.size() != 2 || !lines[1].empty())) {
return Error(ERR_INVALID_FILE) << path << " contains " << lines.size() << " lines != 1";
}
- if (!parsePidStatLine(std::move(lines[0]), pidStat)) {
+ PidStat pidStat;
+ if (!parsePidStatLine(std::move(lines[0]), &pidStat)) {
return Error(ERR_INVALID_FILE) << "Failed to parse the contents of " << path;
}
- return {};
+ pidStat.startTimeMillis = pidStat.startTimeMillis * millisPerClockTick;
+ pidStat.cpuTimeMillis = pidStat.cpuTimeMillis * millisPerClockTick;
+ return pidStat;
}
Result<std::unordered_map<std::string, std::string>> readKeyValueFile(
@@ -155,6 +158,8 @@
}
/**
+ * Returns UID and TGID from the given pid status file.
+ *
* /proc/PID/status file format:
* Tgid: <Thread group ID of the process>
* Uid: <Read UID> <Effective UID> <Saved set UID> <Filesystem UID>
@@ -185,18 +190,19 @@
} // namespace
std::string ProcessStats::toString() const {
- return StringPrintf("{comm: %s, startTime: %" PRIu64 ", totalMajorFaults: %" PRIu64
+ return StringPrintf("{comm: %s, startTimeMillis: %" PRIu64 ", cpuTimeMillis: %" PRIu64
+ ", totalMajorFaults: %" PRIu64
", totalTasksCount: %d, ioBlockedTasksCount: %d}",
- comm.c_str(), startTime, totalMajorFaults, totalTasksCount,
- ioBlockedTasksCount);
+ comm.c_str(), startTimeMillis, cpuTimeMillis, totalMajorFaults,
+ totalTasksCount, ioBlockedTasksCount);
}
std::string UidProcStats::toString() const {
std::string buffer;
StringAppendF(&buffer,
- "UidProcStats{totalMajorFaults: %" PRIu64 ", totalTasksCount: %d,"
- "ioBlockedTasksCount: %d, processStatsByPid: {",
- totalMajorFaults, totalTasksCount, ioBlockedTasksCount);
+ "UidProcStats{cpuTimeMillis: %" PRIu64 ", totalMajorFaults: %" PRIu64
+ ", totalTasksCount: %d, ioBlockedTasksCount: %d, processStatsByPid: {",
+ cpuTimeMillis, totalMajorFaults, totalTasksCount, ioBlockedTasksCount);
for (const auto& [pid, processStats] : processStatsByPid) {
StringAppendF(&buffer, "{pid: %" PRIi32 ", processStats: %s},", pid,
processStats.toString().c_str());
@@ -241,15 +247,21 @@
.totalTasksCount = currStats.totalTasksCount,
.ioBlockedTasksCount = currStats.ioBlockedTasksCount,
};
+ // Generate the delta stats since the previous collection. Delta stats are generated by
+ // calculating the difference between the |prevStats| and the |currStats|.
for (const auto& [pid, processStats] : currStats.processStatsByPid) {
ProcessStats deltaProcessStats = processStats;
if (const auto& it = prevStats.processStatsByPid.find(pid);
it != prevStats.processStatsByPid.end() &&
- it->second.startTime == processStats.startTime &&
- it->second.totalMajorFaults <= deltaProcessStats.totalMajorFaults) {
- deltaProcessStats.totalMajorFaults =
- deltaProcessStats.totalMajorFaults - it->second.totalMajorFaults;
+ it->second.startTimeMillis == deltaProcessStats.startTimeMillis) {
+ if (it->second.cpuTimeMillis <= deltaProcessStats.cpuTimeMillis) {
+ deltaProcessStats.cpuTimeMillis -= it->second.cpuTimeMillis;
+ }
+ if (it->second.totalMajorFaults <= deltaProcessStats.totalMajorFaults) {
+ deltaProcessStats.totalMajorFaults -= it->second.totalMajorFaults;
+ }
}
+ deltaStats.cpuTimeMillis += deltaProcessStats.cpuTimeMillis;
deltaStats.totalMajorFaults += deltaProcessStats.totalMajorFaults;
deltaStats.processStatsByPid[pid] = deltaProcessStats;
}
@@ -290,6 +302,7 @@
uidProcStatsByUid[uid] = {};
}
UidProcStats* uidProcStats = &uidProcStatsByUid[uid];
+ uidProcStats->cpuTimeMillis += processStats.cpuTimeMillis;
uidProcStats->totalMajorFaults += processStats.totalMajorFaults;
uidProcStats->totalTasksCount += processStats.totalTasksCount;
uidProcStats->ioBlockedTasksCount += processStats.ioBlockedTasksCount;
@@ -301,12 +314,12 @@
Result<std::tuple<uid_t, ProcessStats>> UidProcStatsCollector::readProcessStatsLocked(
pid_t pid) const {
// 1. Read top-level pid stats.
- PidStat pidStat = {};
std::string path = StringPrintf((mPath + kStatFileFormat).c_str(), pid);
- if (auto result = readPidStatFile(path, &pidStat); !result.ok()) {
- return Error(result.error().code())
+ auto pidStat = readPidStatFile(path, mMillisPerClockTick);
+ if (!pidStat.ok()) {
+ return Error(pidStat.error().code())
<< "Failed to read top-level per-process stat file '%s': %s"
- << result.error().message().c_str();
+ << pidStat.error().message().c_str();
}
// 2. Read aggregated process status.
@@ -321,7 +334,7 @@
for (const auto& [curUid, uidProcStats] : mLatestStats) {
if (const auto it = uidProcStats.processStatsByPid.find(pid);
it != uidProcStats.processStatsByPid.end() &&
- it->second.startTime == pidStat.startTime) {
+ it->second.startTimeMillis == pidStat->startTimeMillis) {
tgid = pid;
uid = curUid;
break;
@@ -338,14 +351,15 @@
}
ProcessStats processStats = {
- .comm = std::move(pidStat.comm),
- .startTime = pidStat.startTime,
+ .comm = std::move(pidStat->comm),
+ .startTimeMillis = pidStat->startTimeMillis,
+ .cpuTimeMillis = pidStat->cpuTimeMillis,
.totalTasksCount = 1,
/* Top-level process stats has the aggregated major page faults count and this should be
* persistent across thread creation/termination. Thus use the value from this field.
*/
- .totalMajorFaults = pidStat.majorFaults,
- .ioBlockedTasksCount = pidStat.state == "D" ? 1 : 0,
+ .totalMajorFaults = pidStat->majorFaults,
+ .ioBlockedTasksCount = pidStat->state == "D" ? 1 : 0,
};
// 3. Read per-thread stats.
@@ -359,24 +373,34 @@
continue;
}
- PidStat tidStat = {};
path = StringPrintf((taskDir + kStatFileFormat).c_str(), tid);
- if (const auto& result = readPidStatFile(path, &tidStat); !result.ok()) {
- if (result.error().code() != ERR_FILE_OPEN_READ) {
+ auto tidStat = readPidStatFile(path, mMillisPerClockTick);
+ if (!tidStat.ok()) {
+ if (tidStat.error().code() != ERR_FILE_OPEN_READ) {
return Error() << "Failed to read per-thread stat file: "
- << result.error().message().c_str();
+ << tidStat.error().message().c_str();
}
/* Maybe the thread terminated before reading the file so skip this thread and
* continue with scanning the next thread's stat.
*/
continue;
}
- processStats.ioBlockedTasksCount += tidStat.state == "D" ? 1 : 0;
+ processStats.ioBlockedTasksCount += tidStat->state == "D" ? 1 : 0;
processStats.totalTasksCount += 1;
}
return std::make_tuple(uid, processStats);
}
+Result<PidStat> UidProcStatsCollector::readStatFileForPid(pid_t pid) {
+ std::string path = StringPrintf(kProcPidStatFileFormat, pid);
+ return readPidStatFile(path, 1000 / sysconf(_SC_CLK_TCK));
+}
+
+Result<std::tuple<uid_t, pid_t>> UidProcStatsCollector::readPidStatusFileForPid(pid_t pid) {
+ std::string path = StringPrintf(kProcPidStatusFileFormat, pid);
+ return readPidStatusFile(path);
+}
+
} // namespace watchdog
} // namespace automotive
} // namespace android
diff --git a/cpp/watchdog/server/src/UidProcStatsCollector.h b/cpp/watchdog/server/src/UidProcStatsCollector.h
index ffe5c8e..54a2a0f 100644
--- a/cpp/watchdog/server/src/UidProcStatsCollector.h
+++ b/cpp/watchdog/server/src/UidProcStatsCollector.h
@@ -25,6 +25,7 @@
#include <inttypes.h>
#include <stdint.h>
+#include <unistd.h>
#include <string>
#include <unordered_map>
@@ -43,10 +44,21 @@
constexpr const char kTaskDirFormat[] = "/%" PRIu32 "/task";
constexpr const char kStatusFileFormat[] = "/%" PRIu32 "/status";
+// Per-pid/tid stats.
+// The int64_t type is used due to AIDL limitations representing long field values.
+struct PidStat {
+ std::string comm = "";
+ std::string state = "";
+ int64_t startTimeMillis = 0;
+ int64_t cpuTimeMillis = 0;
+ uint64_t majorFaults = 0;
+};
+
// Per-process stats.
struct ProcessStats {
std::string comm = "";
- uint64_t startTime = 0; // Useful when identifying PID reuse
+ int64_t startTimeMillis = 0; // Useful when identifying PID reuse
+ int64_t cpuTimeMillis = 0;
uint64_t totalMajorFaults = 0;
int totalTasksCount = 0;
int ioBlockedTasksCount = 0;
@@ -55,6 +67,7 @@
// Per-UID stats.
struct UidProcStats {
+ int64_t cpuTimeMillis = 0;
uint64_t totalMajorFaults = 0;
int totalTasksCount = 0;
int ioBlockedTasksCount = 0;
@@ -83,7 +96,10 @@
class UidProcStatsCollector final : public UidProcStatsCollectorInterface {
public:
explicit UidProcStatsCollector(const std::string& path = kProcDirPath) :
- mPath(path), mLatestStats({}) {}
+ mMillisPerClockTick(1000 / sysconf(_SC_CLK_TCK)),
+ mPath(path),
+ mLatestStats({}),
+ mDeltaStats({}) {}
~UidProcStatsCollector() {}
@@ -108,6 +124,10 @@
const std::string dirPath() const { return mPath; }
+ static android::base::Result<PidStat> readStatFileForPid(pid_t pid);
+
+ static android::base::Result<std::tuple<uid_t, pid_t>> readPidStatusFileForPid(pid_t pid);
+
private:
android::base::Result<std::unordered_map<uid_t, UidProcStats>> readUidProcStatsLocked() const;
@@ -117,6 +137,9 @@
// 3. Tid stat file at |mPath| + |kTaskDirFormat| + |kStatFileFormat|
android::base::Result<std::tuple<uid_t, ProcessStats>> readProcessStatsLocked(pid_t pid) const;
+ // Number of milliseconds per clock cycle.
+ int32_t mMillisPerClockTick;
+
// Proc directory path. Default value is |kProcDirPath|.
// Updated by tests to point to a different location when needed.
std::string mPath;
diff --git a/cpp/watchdog/server/src/UidStatsCollector.cpp b/cpp/watchdog/server/src/UidStatsCollector.cpp
index a7fef59..c796c80 100644
--- a/cpp/watchdog/server/src/UidStatsCollector.cpp
+++ b/cpp/watchdog/server/src/UidStatsCollector.cpp
@@ -57,16 +57,25 @@
return Error() << "Failed to collect per-uid process stats: " << result.error();
}
}
+ if (mUidCpuStatsCollector->enabled()) {
+ if (const auto& result = mUidCpuStatsCollector->collect(); !result.ok()) {
+ return Error() << "Failed to collect per-uid CPU stats: " << result.error();
+ }
+ }
+
mLatestStats =
- process(mUidIoStatsCollector->latestStats(), mUidProcStatsCollector->latestStats());
- mDeltaStats = process(mUidIoStatsCollector->deltaStats(), mUidProcStatsCollector->deltaStats());
+ process(mUidIoStatsCollector->latestStats(), mUidProcStatsCollector->latestStats(),
+ mUidCpuStatsCollector->latestStats());
+ mDeltaStats = process(mUidIoStatsCollector->deltaStats(), mUidProcStatsCollector->deltaStats(),
+ mUidCpuStatsCollector->deltaStats());
return {};
}
std::vector<UidStats> UidStatsCollector::process(
const std::unordered_map<uid_t, UidIoStats>& uidIoStatsByUid,
- const std::unordered_map<uid_t, UidProcStats>& uidProcStatsByUid) const {
- if (uidIoStatsByUid.empty() && uidProcStatsByUid.empty()) {
+ const std::unordered_map<uid_t, UidProcStats>& uidProcStatsByUid,
+ const std::unordered_map<uid_t, int64_t>& cpuTimeMillisByUid) const {
+ if (uidIoStatsByUid.empty() && uidProcStatsByUid.empty() && cpuTimeMillisByUid.empty()) {
return std::vector<UidStats>();
}
std::unordered_set<uid_t> uidSet;
@@ -76,6 +85,9 @@
for (const auto& [uid, _] : uidProcStatsByUid) {
uidSet.insert(uid);
}
+ for (const auto& [uid, _] : cpuTimeMillisByUid) {
+ uidSet.insert(uid);
+ }
std::vector<uid_t> uids;
for (const auto& uid : uidSet) {
uids.push_back(uid);
@@ -92,8 +104,14 @@
if (const auto it = uidIoStatsByUid.find(uid); it != uidIoStatsByUid.end()) {
curUidStats.ioStats = it->second;
}
+ if (const auto it = cpuTimeMillisByUid.find(uid); it != cpuTimeMillisByUid.end()) {
+ curUidStats.cpuTimeMillis = it->second;
+ }
if (const auto it = uidProcStatsByUid.find(uid); it != uidProcStatsByUid.end()) {
curUidStats.procStats = it->second;
+ if (curUidStats.cpuTimeMillis == 0) {
+ curUidStats.cpuTimeMillis = curUidStats.procStats.cpuTimeMillis;
+ }
}
uidStats.emplace_back(std::move(curUidStats));
}
diff --git a/cpp/watchdog/server/src/UidStatsCollector.h b/cpp/watchdog/server/src/UidStatsCollector.h
index 630d4bb..3091371 100644
--- a/cpp/watchdog/server/src/UidStatsCollector.h
+++ b/cpp/watchdog/server/src/UidStatsCollector.h
@@ -18,6 +18,7 @@
#define CPP_WATCHDOG_SERVER_SRC_UIDSTATSCOLLECTOR_H_
#include "PackageInfoResolver.h"
+#include "UidCpuStatsCollector.h"
#include "UidIoStatsCollector.h"
#include "UidProcStatsCollector.h"
@@ -43,6 +44,7 @@
struct UidStats {
android::automotive::watchdog::internal::PackageInfo packageInfo;
+ int64_t cpuTimeMillis = 0;
UidIoStats ioStats = {};
UidProcStats procStats = {};
// Returns true when package info is available.
@@ -72,11 +74,13 @@
public:
UidStatsCollector() :
mPackageInfoResolver(PackageInfoResolver::getInstance()),
+ mUidCpuStatsCollector(android::sp<UidCpuStatsCollector>::make()),
mUidIoStatsCollector(android::sp<UidIoStatsCollector>::make()),
mUidProcStatsCollector(android::sp<UidProcStatsCollector>::make()) {}
void init() override {
Mutex::Autolock lock(mMutex);
+ mUidCpuStatsCollector->init();
mUidIoStatsCollector->init();
mUidProcStatsCollector->init();
}
@@ -100,12 +104,16 @@
private:
std::vector<UidStats> process(
const std::unordered_map<uid_t, UidIoStats>& uidIoStatsByUid,
- const std::unordered_map<uid_t, UidProcStats>& uidProcStatsByUid) const;
+ const std::unordered_map<uid_t, UidProcStats>& uidProcStatsByUid,
+ const std::unordered_map<uid_t, int64_t>& cpuTimeMillisByUid) const;
+
// Local PackageInfoResolverInterface instance. Useful to mock in tests.
sp<PackageInfoResolverInterface> mPackageInfoResolver;
mutable Mutex mMutex;
+ android::sp<UidCpuStatsCollectorInterface> mUidCpuStatsCollector GUARDED_BY(mMutex);
+
android::sp<UidIoStatsCollectorInterface> mUidIoStatsCollector GUARDED_BY(mMutex);
android::sp<UidProcStatsCollectorInterface> mUidProcStatsCollector GUARDED_BY(mMutex);
diff --git a/cpp/watchdog/server/src/WatchdogInternalHandler.cpp b/cpp/watchdog/server/src/WatchdogInternalHandler.cpp
index 19784e9..9427322 100644
--- a/cpp/watchdog/server/src/WatchdogInternalHandler.cpp
+++ b/cpp/watchdog/server/src/WatchdogInternalHandler.cpp
@@ -18,6 +18,7 @@
#include "WatchdogInternalHandler.h"
+#include "UidProcStatsCollector.h"
#include "WatchdogBinderMediator.h"
#include <android/automotive/watchdog/internal/BootPhase.h>
@@ -39,6 +40,7 @@
using aawi::PowerCycle;
using aawi::ProcessIdentifier;
using aawi::ResourceOveruseConfiguration;
+using aawi::ThreadPolicyWithPriority;
using ::android::sp;
using ::android::String16;
using ::android::binder::Status;
@@ -184,10 +186,6 @@
case aawi::StateType::USER_STATE: {
userid_t userId = static_cast<userid_t>(arg1);
aawi::UserState userState = static_cast<aawi::UserState>(static_cast<uint32_t>(arg2));
- if (userState >= aawi::UserState::NUM_USER_STATES) {
- return fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT,
- StringPrintf("Invalid user state %d", userState));
- }
return handleUserStateChange(userId, userState);
}
case aawi::StateType::BOOT_PHASE: {
@@ -227,22 +225,37 @@
return Status::ok();
}
-Status WatchdogInternalHandler::handleUserStateChange(userid_t userId, aawi::UserState userState) {
+Status WatchdogInternalHandler::handleUserStateChange(userid_t userId,
+ const aawi::UserState& userState) {
std::string stateDesc;
switch (userState) {
case aawi::UserState::USER_STATE_STARTED:
stateDesc = "started";
- mWatchdogProcessService->notifyUserStateChange(userId, /*isStarted=*/true);
+ mWatchdogProcessService->onUserStateChange(userId, /*isStarted=*/true);
+ break;
+ case aawi::UserState::USER_STATE_SWITCHING:
+ stateDesc = "switching";
+ mWatchdogPerfService->onUserStateChange(userId, userState);
+ break;
+ case aawi::UserState::USER_STATE_UNLOCKING:
+ stateDesc = "unlocking";
+ mWatchdogPerfService->onUserStateChange(userId, userState);
+ break;
+ case aawi::UserState::USER_STATE_POST_UNLOCKED:
+ stateDesc = "post_unlocked";
+ mWatchdogPerfService->onUserStateChange(userId, userState);
break;
case aawi::UserState::USER_STATE_STOPPED:
stateDesc = "stopped";
- mWatchdogProcessService->notifyUserStateChange(userId, /*isStarted=*/false);
+ mWatchdogProcessService->onUserStateChange(userId, /*isStarted=*/false);
break;
case aawi::UserState::USER_STATE_REMOVED:
stateDesc = "removed";
mIoOveruseMonitor->removeStatsForUser(userId);
break;
default:
+ // UserState::USER_STATE_UNLOCKED is not sent by CarService to the daemon. If signal is
+ // received, an exception will be thrown.
ALOGW("Unsupported user state: %d", userState);
return Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT, "Unsupported user state");
}
@@ -289,6 +302,29 @@
return Status::ok();
}
+Status WatchdogInternalHandler::setThreadPriority(int pid, int tid, int uid, int policy,
+ int priority) {
+ Status status = checkSystemUser();
+ if (!status.isOk()) {
+ return status;
+ }
+ return mThreadPriorityController->setThreadPriority(pid, tid, uid, policy, priority);
+}
+
+Status WatchdogInternalHandler::getThreadPriority(int pid, int tid, int uid,
+ ThreadPolicyWithPriority* result) {
+ Status status = checkSystemUser();
+ if (!status.isOk()) {
+ return status;
+ }
+ return mThreadPriorityController->getThreadPriority(pid, tid, uid, result);
+}
+
+void WatchdogInternalHandler::setThreadPriorityController(
+ std::unique_ptr<ThreadPriorityController> threadPriorityController) {
+ mThreadPriorityController = std::move(threadPriorityController);
+}
+
} // namespace watchdog
} // namespace automotive
} // namespace android
diff --git a/cpp/watchdog/server/src/WatchdogInternalHandler.h b/cpp/watchdog/server/src/WatchdogInternalHandler.h
index 54f5c68..1232c2f 100644
--- a/cpp/watchdog/server/src/WatchdogInternalHandler.h
+++ b/cpp/watchdog/server/src/WatchdogInternalHandler.h
@@ -18,6 +18,7 @@
#define CPP_WATCHDOG_SERVER_SRC_WATCHDOGINTERNALHANDLER_H_
#include "IoOveruseMonitor.h"
+#include "ThreadPriorityController.h"
#include "WatchdogPerfService.h"
#include "WatchdogProcessService.h"
#include "WatchdogServiceHelper.h"
@@ -41,11 +42,12 @@
class WatchdogBinderMediatorInterface;
class WatchdogBinderMediator;
+class WatchdogInternalHandlerTestPeer;
class WatchdogInternalHandler final :
public android::automotive::watchdog::internal::BnCarWatchdog {
public:
- explicit WatchdogInternalHandler(
+ WatchdogInternalHandler(
const android::sp<WatchdogBinderMediatorInterface>& watchdogBinderMediator,
const android::sp<WatchdogServiceHelperInterface>& watchdogServiceHelper,
const android::sp<WatchdogProcessServiceInterface>& watchdogProcessService,
@@ -55,7 +57,8 @@
mWatchdogServiceHelper(watchdogServiceHelper),
mWatchdogProcessService(watchdogProcessService),
mWatchdogPerfService(watchdogPerfService),
- mIoOveruseMonitor(ioOveruseMonitor) {}
+ mIoOveruseMonitor(ioOveruseMonitor),
+ mThreadPriorityController(std::make_unique<ThreadPriorityController>()) {}
~WatchdogInternalHandler() { terminate(); }
status_t dump(int fd, const Vector<android::String16>& args) override;
@@ -95,6 +98,11 @@
std::vector<android::automotive::watchdog::internal::ResourceOveruseConfiguration>*
configs) override;
android::binder::Status controlProcessHealthCheck(bool enable) override;
+ android::binder::Status setThreadPriority(int pid, int tid, int uid, int policy,
+ int priority) override;
+ android::binder::Status getThreadPriority(
+ int pid, int tid, int uid,
+ android::automotive::watchdog::internal::ThreadPolicyWithPriority* result) override;
protected:
void terminate() {
@@ -112,15 +120,19 @@
android::automotive::watchdog::internal::PowerCycle powerCycle);
android::binder::Status handleUserStateChange(
- userid_t userId, android::automotive::watchdog::internal::UserState userState);
+ userid_t userId, const android::automotive::watchdog::internal::UserState& userState);
+
+ void setThreadPriorityController(std::unique_ptr<ThreadPriorityController> controller);
android::sp<WatchdogBinderMediatorInterface> mWatchdogBinderMediator;
android::sp<WatchdogServiceHelperInterface> mWatchdogServiceHelper;
android::sp<WatchdogProcessServiceInterface> mWatchdogProcessService;
android::sp<WatchdogPerfServiceInterface> mWatchdogPerfService;
android::sp<IoOveruseMonitorInterface> mIoOveruseMonitor;
+ std::unique_ptr<ThreadPriorityController> mThreadPriorityController;
friend class WatchdogBinderMediator;
+ friend class WatchdogInternalHandlerTestPeer;
FRIEND_TEST(WatchdogInternalHandlerTest, TestTerminate);
};
diff --git a/cpp/watchdog/server/src/WatchdogPerfService.cpp b/cpp/watchdog/server/src/WatchdogPerfService.cpp
index 63998a8..a45dab2 100644
--- a/cpp/watchdog/server/src/WatchdogPerfService.cpp
+++ b/cpp/watchdog/server/src/WatchdogPerfService.cpp
@@ -19,7 +19,6 @@
#include "WatchdogPerfService.h"
-#include <WatchdogProperties.sysprop.h>
#include <android-base/file.h>
#include <android-base/parseint.h>
#include <android-base/stringprintf.h>
@@ -36,10 +35,13 @@
namespace automotive {
namespace watchdog {
+namespace {
+
using ::android::sp;
using ::android::String16;
using ::android::String8;
using ::android::automotive::watchdog::internal::PowerCycle;
+using ::android::automotive::watchdog::internal::UserState;
using ::android::base::Error;
using ::android::base::Join;
using ::android::base::ParseUint;
@@ -49,11 +51,9 @@
using ::android::base::StringPrintf;
using ::android::base::WriteStringToFd;
-namespace {
-
// Minimum required collection interval between subsequent collections.
const std::chrono::nanoseconds kMinEventInterval = 1s;
-const std::chrono::seconds kDefaultBoottimeCollectionInterval = 1s;
+const std::chrono::seconds kDefaultSystemEventCollectionInterval = 1s;
const std::chrono::seconds kDefaultPeriodicCollectionInterval = 20s;
const std::chrono::seconds kDefaultPeriodicMonitorInterval = 5s;
const std::chrono::nanoseconds kCustomCollectionInterval = 10s;
@@ -102,6 +102,8 @@
return "BOOT_TIME_COLLECTION";
case EventType::PERIODIC_COLLECTION:
return "PERIODIC_COLLECTION";
+ case EventType::USER_SWITCH_COLLECTION:
+ return "USER_SWITCH_COLLECTION";
case EventType::CUSTOM_COLLECTION:
return "CUSTOM_COLLECTION";
case EventType::PERIODIC_MONITOR:
@@ -166,10 +168,10 @@
if (mCurrCollectionEvent != EventType::INIT || mCollectionThread.joinable()) {
return Error(INVALID_OPERATION) << "Cannot start " << kServiceName << " more than once";
}
- std::chrono::nanoseconds boottimeCollectionInterval =
+ std::chrono::nanoseconds systemEventCollectionInterval =
std::chrono::duration_cast<std::chrono::nanoseconds>(
- std::chrono::seconds(sysprop::boottimeCollectionInterval().value_or(
- kDefaultBoottimeCollectionInterval.count())));
+ std::chrono::seconds(sysprop::systemEventCollectionInterval().value_or(
+ kDefaultSystemEventCollectionInterval.count())));
std::chrono::nanoseconds periodicCollectionInterval =
std::chrono::duration_cast<std::chrono::nanoseconds>(
std::chrono::seconds(sysprop::periodicCollectionInterval().value_or(
@@ -180,7 +182,7 @@
kDefaultPeriodicMonitorInterval.count())));
mBoottimeCollection = {
.eventType = EventType::BOOT_TIME_COLLECTION,
- .interval = boottimeCollectionInterval,
+ .interval = systemEventCollectionInterval,
.lastUptime = 0,
};
mPeriodicCollection = {
@@ -188,6 +190,11 @@
.interval = periodicCollectionInterval,
.lastUptime = 0,
};
+ mUserSwitchCollection = {{
+ .eventType = EventType::USER_SWITCH_COLLECTION,
+ .interval = systemEventCollectionInterval,
+ .lastUptime = 0,
+ }};
mPeriodicMonitor = {
.eventType = EventType::PERIODIC_MONITOR,
.interval = periodicMonitorInterval,
@@ -249,7 +256,7 @@
ALOGE("Terminating %s as carwatchdog is terminating", kServiceName);
if (mCurrCollectionEvent != EventType::INIT) {
/*
- * Looper runs only after EventType::TNIT has completed so remove looper messages
+ * Looper runs only after EventType::INIT has completed so remove looper messages
* and wake the looper only when the current collection has changed from INIT.
*/
mHandlerLooper->removeMessages(sp<WatchdogPerfService>::fromExisting(this));
@@ -290,13 +297,95 @@
toString(expected));
return {};
}
- mBoottimeCollection.lastUptime = mHandlerLooper->now();
+ nsecs_t endBootCollectionTime = mHandlerLooper->now() + mPostSystemEventDurationNs.count();
+ mHandlerLooper->sendMessageAtTime(endBootCollectionTime,
+ sp<WatchdogPerfService>::fromExisting(this),
+ SwitchMessage::END_BOOTTIME_COLLECTION);
+ if (DEBUG) {
+ ALOGD("Boot complete signal received.");
+ }
+ return {};
+}
+
+Result<void> WatchdogPerfService::onUserStateChange(userid_t userId, const UserState& userState) {
+ Mutex::Autolock lock(mMutex);
+ if (mCurrCollectionEvent == EventType::BOOT_TIME_COLLECTION) {
+ return {};
+ }
+ switch (static_cast<int>(userState)) {
+ case static_cast<int>(UserState::USER_STATE_SWITCHING):
+ // TODO(b/243984863): Handle multi-user switching scenario.
+ mUserSwitchCollection.from = mUserSwitchCollection.to;
+ mUserSwitchCollection.to = userId;
+ if (mCurrCollectionEvent != EventType::PERIODIC_COLLECTION &&
+ mCurrCollectionEvent != EventType::USER_SWITCH_COLLECTION) {
+ ALOGE("Unable to start %s. Current performance data collection event: %s",
+ toString(EventType::USER_SWITCH_COLLECTION), toString(mCurrCollectionEvent));
+ return {};
+ }
+ startUserSwitchCollection();
+ ALOGI("Switching to %s (userIds: from = %d, to = %d)", toString(mCurrCollectionEvent),
+ mUserSwitchCollection.from, mUserSwitchCollection.to);
+ break;
+ case static_cast<int>(UserState::USER_STATE_UNLOCKING):
+ if (mCurrCollectionEvent != EventType::PERIODIC_COLLECTION) {
+ if (mCurrCollectionEvent != EventType::USER_SWITCH_COLLECTION) {
+ ALOGE("Unable to start %s. Current performance data collection event: %s",
+ toString(EventType::USER_SWITCH_COLLECTION),
+ toString(mCurrCollectionEvent));
+ }
+ return {};
+ }
+ if (mUserSwitchCollection.to != userId) {
+ return {};
+ }
+ startUserSwitchCollection();
+ ALOGI("Switching to %s (userId: %d)", toString(mCurrCollectionEvent), userId);
+ break;
+ case static_cast<int>(UserState::USER_STATE_POST_UNLOCKED): {
+ if (mCurrCollectionEvent != EventType::USER_SWITCH_COLLECTION) {
+ ALOGE("Ignoring USER_STATE_POST_UNLOCKED because no user switch collection in "
+ "progress. Current performance data collection event: %s.",
+ toString(mCurrCollectionEvent));
+ return {};
+ }
+ if (mUserSwitchCollection.to != userId) {
+ ALOGE("Ignoring USER_STATE_POST_UNLOCKED signal for user id: %d. "
+ "Current user being switched to: %d",
+ userId, mUserSwitchCollection.to);
+ return {};
+ }
+ auto thiz = sp<WatchdogPerfService>::fromExisting(this);
+ mHandlerLooper->removeMessages(thiz, SwitchMessage::END_USER_SWITCH_COLLECTION);
+ nsecs_t endUserSwitchCollectionTime =
+ mHandlerLooper->now() + mPostSystemEventDurationNs.count();
+ mHandlerLooper->sendMessageAtTime(endUserSwitchCollectionTime, thiz,
+ SwitchMessage::END_USER_SWITCH_COLLECTION);
+ break;
+ }
+ default:
+ ALOGE("Unsupported user state: %d", static_cast<int>(userState));
+ return {};
+ }
+ if (DEBUG) {
+ ALOGD("Handled user state change: userId = %d, userState = %d", userId,
+ static_cast<int>(userState));
+ }
+ return {};
+}
+
+Result<void> WatchdogPerfService::startUserSwitchCollection() {
auto thiz = sp<WatchdogPerfService>::fromExisting(this);
mHandlerLooper->removeMessages(thiz);
- mHandlerLooper->sendMessage(thiz, SwitchMessage::END_BOOTTIME_COLLECTION);
- if (DEBUG) {
- ALOGD("Boot-time event finished");
- }
+ mUserSwitchCollection.lastUptime = mHandlerLooper->now();
+ // End |EventType::USER_SWITCH_COLLECTION| after a timeout because the user switch end
+ // signal won't be received within a few seconds when the switch is blocked due to a
+ // keyguard event. Otherwise, polling beyond a few seconds will lead to unnecessary data
+ // collection.
+ nsecs_t uptime = mHandlerLooper->now() + mUserSwitchTimeoutNs.count();
+ mHandlerLooper->sendMessageAtTime(uptime, thiz, SwitchMessage::END_USER_SWITCH_COLLECTION);
+ mCurrCollectionEvent = EventType::USER_SWITCH_COLLECTION;
+ mHandlerLooper->sendMessage(thiz, EventType::USER_SWITCH_COLLECTION);
return {};
}
@@ -394,6 +483,10 @@
kDumpMajorDelimiter.c_str(), std::string(33, '=').c_str()),
fd) ||
!WriteStringToFd(mBoottimeCollection.toString(), fd) ||
+ !WriteStringToFd(StringPrintf("\nUser-switch collection information:\n%s\n",
+ std::string(35, '=').c_str()),
+ fd) ||
+ !WriteStringToFd(mUserSwitchCollection.toString(), fd) ||
!WriteStringToFd(StringPrintf("\nPeriodic collection information:\n%s\n",
std::string(32, '=').c_str()),
fd) ||
@@ -537,6 +630,7 @@
result = processCollectionEvent(&mBoottimeCollection);
break;
case static_cast<int>(SwitchMessage::END_BOOTTIME_COLLECTION):
+ mHandlerLooper->removeMessages(sp<WatchdogPerfService>::fromExisting(this));
if (result = processCollectionEvent(&mBoottimeCollection); result.ok()) {
Mutex::Autolock lock(mMutex);
switchToPeriodicLocked(/*startNow=*/false);
@@ -545,6 +639,16 @@
case static_cast<int>(EventType::PERIODIC_COLLECTION):
result = processCollectionEvent(&mPeriodicCollection);
break;
+ case static_cast<int>(EventType::USER_SWITCH_COLLECTION):
+ result = processCollectionEvent(&mUserSwitchCollection);
+ break;
+ case static_cast<int>(SwitchMessage::END_USER_SWITCH_COLLECTION):
+ mHandlerLooper->removeMessages(sp<WatchdogPerfService>::fromExisting(this));
+ if (result = processCollectionEvent(&mUserSwitchCollection); result.ok()) {
+ Mutex::Autolock lock(mMutex);
+ switchToPeriodicLocked(/*startNow=*/false);
+ }
+ break;
case static_cast<int>(EventType::CUSTOM_COLLECTION):
result = processCollectionEvent(&mCustomCollection);
break;
@@ -652,6 +756,14 @@
result = processor->onPeriodicCollection(now, mSystemState, mUidStatsCollector,
mProcStatCollector);
break;
+ case EventType::USER_SWITCH_COLLECTION: {
+ WatchdogPerfService::UserSwitchEventMetadata* userSwitchMetadata =
+ static_cast<WatchdogPerfService::UserSwitchEventMetadata*>(metadata);
+ result = processor->onUserSwitchCollection(now, userSwitchMetadata->from,
+ userSwitchMetadata->to,
+ mUidStatsCollector, mProcStatCollector);
+ break;
+ }
case EventType::CUSTOM_COLLECTION:
result = processor->onCustomCollection(now, mSystemState, metadata->filterPackages,
mUidStatsCollector, mProcStatCollector);
diff --git a/cpp/watchdog/server/src/WatchdogPerfService.h b/cpp/watchdog/server/src/WatchdogPerfService.h
index 68a1e6a..3f412f8 100644
--- a/cpp/watchdog/server/src/WatchdogPerfService.h
+++ b/cpp/watchdog/server/src/WatchdogPerfService.h
@@ -22,9 +22,11 @@
#include "ProcStatCollector.h"
#include "UidStatsCollector.h"
+#include <WatchdogProperties.sysprop.h>
#include <android-base/chrono_utils.h>
#include <android-base/result.h>
#include <android/automotive/watchdog/internal/PowerCycle.h>
+#include <android/automotive/watchdog/internal/UserState.h>
#include <cutils/multiuser.h>
#include <gtest/gtest_prod.h>
#include <utils/Errors.h>
@@ -52,6 +54,8 @@
} // namespace internal
+constexpr std::chrono::seconds kDefaultPostSystemEventDurationSec = 30s;
+constexpr std::chrono::seconds kDefaultUserSwitchTimeoutSec = 30s;
constexpr const char* kStartCustomCollectionFlag = "--start_perf";
constexpr const char* kEndCustomCollectionFlag = "--stop_perf";
constexpr const char* kIntervalFlag = "--interval";
@@ -86,6 +90,11 @@
time_t time, SystemState systemState,
const android::wp<UidStatsCollectorInterface>& uidStatsCollector,
const android::wp<ProcStatCollectorInterface>& procStatCollector) = 0;
+ // Callback to process the data collected during user switch.
+ virtual android::base::Result<void> onUserSwitchCollection(
+ time_t time, userid_t from, userid_t to,
+ const android::wp<UidStatsCollectorInterface>& uidStatsCollector,
+ const android::wp<ProcStatCollectorInterface>& procStatCollector) = 0;
/**
* Callback to process the data collected on custom collection and filter the results only to
* the specified |filterPackages|.
@@ -118,6 +127,7 @@
// Collection events.
BOOT_TIME_COLLECTION,
PERIODIC_COLLECTION,
+ USER_SWITCH_COLLECTION,
CUSTOM_COLLECTION,
// Monitor event.
@@ -134,6 +144,12 @@
END_BOOTTIME_COLLECTION = EventType::LAST_EVENT + 1,
/**
+ * On receiving this message, collect the last user switch record and start periodic collection
+ * and monitor.
+ */
+ END_USER_SWITCH_COLLECTION,
+
+ /**
* On receiving this message, ends custom collection, discard collected data and start periodic
* collection and monitor.
*/
@@ -159,8 +175,14 @@
virtual void terminate() = 0;
// Sets the system state.
virtual void setSystemState(SystemState systemState) = 0;
- // Ends the boot-time collection by switching to periodic collection and returns immediately.
+ // Ends the boot-time collection by switching to periodic collection after the post event
+ // duration.
virtual android::base::Result<void> onBootFinished() = 0;
+ // Starts and ends the user switch collection depending on the user states received.
+ virtual android::base::Result<void> onUserStateChange(
+ userid_t userId,
+ const android::automotive::watchdog::internal::UserState& userState) = 0;
+
/**
* Depending on the arguments, it either:
* 1. Starts a custom collection.
@@ -178,10 +200,17 @@
class WatchdogPerfService final : public WatchdogPerfServiceInterface {
public:
WatchdogPerfService() :
+ mPostSystemEventDurationNs(std::chrono::duration_cast<std::chrono::nanoseconds>(
+ std::chrono::seconds(sysprop::postSystemEventDuration().value_or(
+ kDefaultPostSystemEventDurationSec.count())))),
+ mUserSwitchTimeoutNs(std::chrono::duration_cast<std::chrono::nanoseconds>(
+ std::chrono::seconds(sysprop::userSwitchTimeout().value_or(
+ kDefaultUserSwitchTimeoutSec.count())))),
mHandlerLooper(android::sp<LooperWrapper>::make()),
mSystemState(NORMAL_MODE),
mBoottimeCollection({}),
mPeriodicCollection({}),
+ mUserSwitchCollection({}),
mCustomCollection({}),
mPeriodicMonitor({}),
mCurrCollectionEvent(EventType::INIT),
@@ -201,6 +230,10 @@
android::base::Result<void> onBootFinished() override;
+ android::base::Result<void> onUserStateChange(
+ userid_t userId,
+ const android::automotive::watchdog::internal::UserState& userState) override;
+
android::base::Result<void> onCustomCollection(int fd,
const Vector<android::String16>& args) override;
@@ -222,6 +255,13 @@
std::string toString() const;
};
+ struct UserSwitchEventMetadata : WatchdogPerfService::EventMetadata {
+ // User id of user being switched from.
+ userid_t from = 0;
+ // User id of user being switched to.
+ userid_t to = 0;
+ };
+
// Dumps the collectors' status when they are disabled.
android::base::Result<void> dumpCollectorsStatusLocked(int fd) const;
@@ -247,6 +287,9 @@
*/
android::base::Result<void> endCustomCollection(int fd);
+ // Start a user switch collection.
+ android::base::Result<void> startUserSwitchCollection();
+
// Handles the messages received by the lopper.
void handleMessage(const Message& message) override;
@@ -265,37 +308,43 @@
*/
EventMetadata* currCollectionMetadataLocked();
+ // Duration to extend a system event collection after the final signal is received.
+ std::chrono::nanoseconds mPostSystemEventDurationNs;
+
+ // Timeout duration for user switch collection in case final signal isn't received.
+ std::chrono::nanoseconds mUserSwitchTimeoutNs;
+
// Thread on which the actual collection happens.
std::thread mCollectionThread;
// Makes sure only one collection is running at any given time.
mutable Mutex mMutex;
- // Handler lopper to execute different collection events on the collection thread.
+ // Handler looper to execute different collection events on the collection thread.
android::sp<LooperWrapper> mHandlerLooper GUARDED_BY(mMutex);
// Current system state.
SystemState mSystemState GUARDED_BY(mMutex);
- // Info for the |CollectionEvent::BOOT_TIME| collection event.
+ // Info for the |EventType::BOOT_TIME_COLLECTION| collection event.
EventMetadata mBoottimeCollection GUARDED_BY(mMutex);
- // Info for the |CollectionEvent::PERIODIC| collection event.
+ // Info for the |EventType::PERIODIC_COLLECTION| collection event.
EventMetadata mPeriodicCollection GUARDED_BY(mMutex);
- /*
- * Info for the |CollectionEvent::CUSTOM| collection event. The info is cleared at the end of
- * every custom collection.
- */
+ // Info for the |EventType::USER_SWITCH_COLLECTION| collection event.
+ UserSwitchEventMetadata mUserSwitchCollection GUARDED_BY(mMutex);
+
+ // Info for the |EventType::CUSTOM_COLLECTION| collection event. The info is cleared at the end
+ // of every custom collection.
EventMetadata mCustomCollection GUARDED_BY(mMutex);
- // Info for the |EventType::PERIODIC| monitor event.
+ // Info for the |EventType::PERIODIC_MONITOR| monitor event.
EventMetadata mPeriodicMonitor GUARDED_BY(mMutex);
- /**
- * Tracks either the WatchdogPerfService's state or current collection event. Updated on
- * |start|, |onBootComplete|, |startCustomCollection|, |endCustomCollection|, and |terminate|.
- */
+ // Tracks either the WatchdogPerfService's state or current collection event. Updated on
+ // |start|, |onBootFinished|, |onUserStateChange|, |startCustomCollection|,
+ // |endCustomCollection|, and |terminate|.
EventType mCurrCollectionEvent GUARDED_BY(mMutex);
// Collector for UID process and I/O stats.
diff --git a/cpp/watchdog/server/src/WatchdogProcessService.cpp b/cpp/watchdog/server/src/WatchdogProcessService.cpp
index bf7e8aa..9c785b4 100644
--- a/cpp/watchdog/server/src/WatchdogProcessService.cpp
+++ b/cpp/watchdog/server/src/WatchdogProcessService.cpp
@@ -19,6 +19,7 @@
#include "WatchdogProcessService.h"
+#include "UidProcStatsCollector.h"
#include "WatchdogServiceHelper.h"
#include <aidl/android/hardware/automotive/vehicle/BnVehicle.h>
@@ -124,6 +125,14 @@
return sysPowerCtl == "reboot" || sysPowerCtl == "shutdown";
}
+int64_t getStartTimeForPid(pid_t pid) {
+ auto pidStat = UidProcStatsCollector::readStatFileForPid(pid);
+ if (!pidStat.ok()) {
+ return elapsedRealtime();
+ }
+ return pidStat->startTimeMillis;
+}
+
} // namespace
WatchdogProcessService::WatchdogProcessService(const sp<Looper>& handlerLooper) :
@@ -155,6 +164,8 @@
mOverriddenClientHealthCheckWindowNs = std::optional<std::chrono::seconds>{
std::max(clientHealthCheckIntervalSec, normalSec)};
}
+
+ mGetStartTimeForPidFunc = &getStartTimeForPid;
}
Result<void> WatchdogProcessService::registerWatchdogServiceHelper(
@@ -169,15 +180,22 @@
Status WatchdogProcessService::registerClient(const sp<ICarWatchdogClient>& client,
TimeoutLength timeout) {
+ if (client == nullptr) {
+ return Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT,
+ "Must provide non-null client");
+ }
pid_t callingPid = IPCThreadState::self()->getCallingPid();
uid_t callingUid = IPCThreadState::self()->getCallingUid();
- ClientInfo clientInfo(client, callingPid, callingUid);
- Mutex::Autolock lock(mMutex);
- return registerClientLocked(clientInfo, timeout);
+ ClientInfo clientInfo(client, callingPid, callingUid, mGetStartTimeForPidFunc(callingPid));
+ return registerClient(clientInfo, timeout);
}
Status WatchdogProcessService::unregisterClient(const sp<ICarWatchdogClient>& client) {
+ if (client == nullptr) {
+ return Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT,
+ "Must provide non-null client");
+ }
Mutex::Autolock lock(mMutex);
sp<IBinder> binder = BnCarWatchdogClient::asBinder(client);
// kTimeouts is declared as global static constant to cover all kinds of timeout (CRITICAL,
@@ -189,13 +207,19 @@
pid_t callingPid = IPCThreadState::self()->getCallingPid();
uid_t callingUid = IPCThreadState::self()->getCallingUid();
- Mutex::Autolock lock(mMutex);
- if (mWatchdogServiceHelper == nullptr) {
- return Status::fromExceptionCode(Status::EX_ILLEGAL_STATE,
- "Watchdog service helper instance is null");
+ sp<WatchdogServiceHelperInterface> helper;
+ {
+ Mutex::Autolock lock(mMutex);
+ if (mWatchdogServiceHelper == nullptr) {
+ return Status::fromExceptionCode(Status::EX_ILLEGAL_STATE,
+ "Watchdog service helper instance is null");
+ }
+ helper = mWatchdogServiceHelper;
}
- ClientInfo clientInfo(mWatchdogServiceHelper, binder, callingPid, callingUid);
- return registerClientLocked(clientInfo, TimeoutLength::TIMEOUT_CRITICAL);
+
+ ClientInfo clientInfo(helper, binder, callingPid, callingUid,
+ mGetStartTimeForPidFunc(callingPid));
+ return registerClient(clientInfo, TimeoutLength::TIMEOUT_CRITICAL);
}
void WatchdogProcessService::unregisterCarWatchdogService(const sp<IBinder>& binder) {
@@ -206,17 +230,37 @@
}
Status WatchdogProcessService::registerMonitor(const sp<aawi::ICarWatchdogMonitor>& monitor) {
- Mutex::Autolock lock(mMutex);
- sp<IBinder> binder = aawi::BnCarWatchdogMonitor::asBinder(monitor);
- if (mMonitor != nullptr && binder == aawi::BnCarWatchdogMonitor::asBinder(mMonitor)) {
- return Status::ok();
+ if (monitor == nullptr) {
+ return Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT,
+ "Must provide non-null monitor");
}
- status_t ret = binder->linkToDeath(mBinderDeathRecipient);
- if (ret != OK) {
+ sp<BinderDeathRecipient> binderDeathRecipient;
+ sp<IBinder> binder = aawi::BnCarWatchdogMonitor::asBinder(monitor);
+ {
+ Mutex::Autolock lock(mMutex);
+ if (mBinderDeathRecipient == nullptr) {
+ return Status::fromExceptionCode(Status::EX_ILLEGAL_STATE,
+ "Service is not initialized");
+ }
+ if (mMonitor != nullptr) {
+ if (binder == aawi::BnCarWatchdogMonitor::asBinder(mMonitor)) {
+ return Status::ok();
+ }
+ aawi::BnCarWatchdogMonitor::asBinder(mMonitor)->unlinkToDeath(mBinderDeathRecipient);
+ }
+ mMonitor = monitor;
+ binderDeathRecipient = mBinderDeathRecipient;
+ }
+ if (status_t ret = binder->linkToDeath(binderDeathRecipient); ret != OK) {
+ {
+ Mutex::Autolock lock(mMutex);
+ if (mMonitor != nullptr && binder == aawi::BnCarWatchdogMonitor::asBinder(mMonitor)) {
+ mMonitor.clear();
+ }
+ }
ALOGW("Failed to register the monitor as it is dead.");
return Status::fromExceptionCode(Status::EX_ILLEGAL_STATE, "The monitor is dead.");
}
- mMonitor = monitor;
if (DEBUG) {
ALOGD("Car watchdog monitor is registered");
}
@@ -224,7 +268,14 @@
}
Status WatchdogProcessService::unregisterMonitor(const sp<aawi::ICarWatchdogMonitor>& monitor) {
+ if (monitor == nullptr) {
+ return Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT,
+ "Must provide non-null monitor");
+ }
Mutex::Autolock lock(mMutex);
+ if (mBinderDeathRecipient == nullptr) {
+ return Status::fromExceptionCode(Status::EX_ILLEGAL_STATE, "Service is not initialized");
+ }
sp<IBinder> curBinder = aawi::BnCarWatchdogMonitor::asBinder(mMonitor);
sp<IBinder> newBinder = aawi::BnCarWatchdogMonitor::asBinder(monitor);
if (curBinder != newBinder) {
@@ -303,7 +354,7 @@
}
}
-void WatchdogProcessService::notifyUserStateChange(userid_t userId, bool isStarted) {
+void WatchdogProcessService::onUserStateChange(userid_t userId, bool isStarted) {
std::string buffer;
Mutex::Autolock lock(mMutex);
if (isStarted) {
@@ -403,14 +454,17 @@
}
Result<void> WatchdogProcessService::start() {
- if (mServiceStarted) {
- return Error(INVALID_OPERATION) << "Cannot start process monitoring more than once";
+ {
+ Mutex::Autolock lock(mMutex);
+ if (mServiceStarted) {
+ return Error(INVALID_OPERATION) << "Cannot start process monitoring more than once";
+ }
+ auto thiz = sp<WatchdogProcessService>::fromExisting(this);
+ mMessageHandler = sp<MessageHandlerImpl>::make(thiz);
+ mBinderDeathRecipient = sp<BinderDeathRecipient>::make(thiz);
+ mPropertyChangeListener = std::make_shared<PropertyChangeListener>(thiz);
+ mServiceStarted = true;
}
- auto thiz = sp<WatchdogProcessService>::fromExisting(this);
- mMessageHandler = sp<MessageHandlerImpl>::make(thiz);
- mBinderDeathRecipient = sp<BinderDeathRecipient>::make(thiz);
- mPropertyChangeListener = std::make_shared<PropertyChangeListener>(thiz);
- mServiceStarted = true;
reportWatchdogAliveToVhal();
return {};
}
@@ -432,6 +486,7 @@
sp<IBinder> binder = aawi::BnCarWatchdogMonitor::asBinder(mMonitor);
binder->unlinkToDeath(mBinderDeathRecipient);
}
+ mBinderDeathRecipient.clear();
mHandlerLooper->removeMessages(mMessageHandler, MSG_VHAL_HEALTH_CHECK);
mServiceStarted = false;
if (mVhalService == nullptr) {
@@ -449,30 +504,45 @@
mVhalService.reset();
}
-Status WatchdogProcessService::registerClientLocked(const ClientInfo& clientInfo,
- TimeoutLength timeout) {
- if (findClientAndProcessLocked(kTimeouts, clientInfo, nullptr)) {
- ALOGW("Failed to register (%s) as it is already registered.",
- clientInfo.toString().c_str());
- return Status::ok();
+Status WatchdogProcessService::registerClient(const ClientInfo& clientInfo, TimeoutLength timeout) {
+ sp<BinderDeathRecipient> binderDeathRecipient;
+ {
+ Mutex::Autolock lock(mMutex);
+ if (mBinderDeathRecipient == nullptr) {
+ return Status::fromExceptionCode(Status::EX_ILLEGAL_STATE,
+ "Service is not initialized");
+ }
+ if (findClientAndProcessLocked(kTimeouts, clientInfo, nullptr)) {
+ ALOGW("Failed to register (%s) as it is already registered.",
+ clientInfo.toString().c_str());
+ return Status::ok();
+ }
+ std::vector<ClientInfo>& clients = mClients[timeout];
+ clients.emplace_back(clientInfo);
+ binderDeathRecipient = mBinderDeathRecipient;
}
- status_t status = clientInfo.linkToDeath(mBinderDeathRecipient);
- if (status != OK) {
+ if (status_t status = clientInfo.linkToDeath(binderDeathRecipient); status != OK) {
+ Mutex::Autolock lock(mMutex);
+ std::vector<TimeoutLength> timeouts = {timeout};
+ findClientAndProcessLocked(timeouts, clientInfo,
+ [&](std::vector<ClientInfo>& clients,
+ std::vector<ClientInfo>::const_iterator it) {
+ clients.erase(it);
+ });
ALOGW("Failed to register (%s) as it is dead", clientInfo.toString().c_str());
std::string errorStr = StringPrintf("(%s) is dead", clientInfo.toString().c_str());
return Status::fromExceptionCode(Status::EX_ILLEGAL_STATE, errorStr.c_str());
}
- std::vector<ClientInfo>& clients = mClients[timeout];
- clients.emplace_back(clientInfo);
-
- // If the client array becomes non-empty, start health checking.
- if (clients.size() == 1) {
- startHealthCheckingLocked(timeout);
- }
if (DEBUG) {
ALOGD("Car watchdog client (%s, timeout = %d) is registered", clientInfo.toString().c_str(),
timeout);
}
+ Mutex::Autolock lock(mMutex);
+ // If the client array becomes non-empty, start health checking.
+ if (mClients[timeout].size() == 1) {
+ startHealthCheckingLocked(timeout);
+ ALOGI("Starting health checking for timeout = %d", timeout);
+ }
return Status::ok();
}
@@ -565,12 +635,14 @@
for (PingedClientMap::const_iterator it = clients.cbegin(); it != clients.cend(); it++) {
pid_t pid = -1;
userid_t userId = -1;
+ uint64_t startTimeMillis = 0;
std::vector<TimeoutLength> timeouts = {timeout};
findClientAndProcessLocked(timeouts, it->second,
[&](std::vector<ClientInfo>& cachedClients,
std::vector<ClientInfo>::const_iterator
cachedClientsIt) {
pid = cachedClientsIt->pid;
+ startTimeMillis = cachedClientsIt->startTimeMillis;
userId = cachedClientsIt->userId;
cachedClients.erase(cachedClientsIt);
});
@@ -578,9 +650,7 @@
clientsToNotify.emplace_back(&it->second);
ProcessIdentifier processIdentifier;
processIdentifier.pid = pid;
- // TODO(b/213939034): Read pid start time and populate
- // processIdentifier.startTimeMillis
- processIdentifier.startTimeMillis = elapsedRealtime();
+ processIdentifier.startTimeMillis = startTimeMillis;
processIdentifiers.push_back(processIdentifier);
}
}
@@ -859,9 +929,7 @@
if (info.interfaceName == kVhalInterfaceName) {
ProcessIdentifier processIdentifier;
processIdentifier.pid = info.pid;
- // TODO(b/213939034): Read pid start time and populate
- // processIdentifier.startTimeMillis
- processIdentifier.startTimeMillis = elapsedRealtime();
+ processIdentifier.startTimeMillis = mGetStartTimeForPidFunc(info.pid);
processIdentifiers.push_back(processIdentifier);
break;
}
diff --git a/cpp/watchdog/server/src/WatchdogProcessService.h b/cpp/watchdog/server/src/WatchdogProcessService.h
index 7f127bd..1bb8efe 100644
--- a/cpp/watchdog/server/src/WatchdogProcessService.h
+++ b/cpp/watchdog/server/src/WatchdogProcessService.h
@@ -92,7 +92,7 @@
const android::automotive::watchdog::internal::ProcessIdentifier&
processIdentifier) = 0;
virtual void setEnabled(bool isEnabled) = 0;
- virtual void notifyUserStateChange(userid_t userId, bool isStarted) = 0;
+ virtual void onUserStateChange(userid_t userId, bool isStarted) = 0;
};
class WatchdogProcessService final : public WatchdogProcessServiceInterface {
@@ -133,7 +133,7 @@
monitor,
const android::automotive::watchdog::internal::ProcessIdentifier& processIdentifier);
virtual void setEnabled(bool isEnabled);
- virtual void notifyUserStateChange(userid_t userId, bool isStarted);
+ virtual void onUserStateChange(userid_t userId, bool isStarted);
private:
enum ClientType {
@@ -141,16 +141,21 @@
Service,
};
- struct ClientInfo {
- ClientInfo(const android::sp<ICarWatchdogClient>& client, pid_t pid, userid_t userId) :
+ class ClientInfo {
+ public:
+ ClientInfo(const android::sp<ICarWatchdogClient>& client, pid_t pid, userid_t userId,
+ uint64_t startTimeMillis) :
pid(pid),
userId(userId),
+ startTimeMillis(startTimeMillis),
type(ClientType::Regular),
client(client) {}
ClientInfo(const android::sp<WatchdogServiceHelperInterface>& helper,
- const android::sp<android::IBinder>& binder, pid_t pid, userid_t userId) :
+ const android::sp<android::IBinder>& binder, pid_t pid, userid_t userId,
+ uint64_t startTimeMillis) :
pid(pid),
userId(userId),
+ startTimeMillis(startTimeMillis),
type(ClientType::Service),
watchdogServiceHelper(helper),
watchdogServiceBinder(binder) {}
@@ -170,6 +175,7 @@
pid_t pid;
userid_t userId;
+ int64_t startTimeMillis;
int sessionId;
private:
@@ -226,8 +232,7 @@
};
private:
- android::binder::Status registerClientLocked(const ClientInfo& clientInfo,
- TimeoutLength timeout);
+ android::binder::Status registerClient(const ClientInfo& clientInfo, TimeoutLength timeout);
android::binder::Status unregisterClientLocked(const std::vector<TimeoutLength>& timeouts,
android::sp<IBinder> binder,
ClientType clientType);
@@ -270,7 +275,6 @@
private:
android::sp<Looper> mHandlerLooper;
android::sp<MessageHandlerImpl> mMessageHandler;
- android::sp<BinderDeathRecipient> mBinderDeathRecipient;
std::unordered_set<aidl::android::hardware::automotive::vehicle::VehicleProperty>
mNotSupportedVhalProperties;
std::shared_ptr<PropertyChangeListener> mPropertyChangeListener;
@@ -281,6 +285,7 @@
std::optional<std::chrono::nanoseconds> mOverriddenClientHealthCheckWindowNs;
std::shared_ptr<android::frameworks::automotive::vhal::IVhalClient::OnBinderDiedCallbackFunc>
mOnBinderDiedCallback;
+ std::function<int64_t(pid_t)> mGetStartTimeForPidFunc;
android::Mutex mMutex;
std::unordered_map<TimeoutLength, std::vector<ClientInfo>> mClients GUARDED_BY(mMutex);
@@ -293,6 +298,7 @@
GUARDED_BY(mMutex);
HeartBeat mVhalHeartBeat GUARDED_BY(mMutex);
android::sp<WatchdogServiceHelperInterface> mWatchdogServiceHelper GUARDED_BY(mMutex);
+ android::sp<BinderDeathRecipient> mBinderDeathRecipient GUARDED_BY(mMutex);
// For unit tests.
friend class internal::WatchdogProcessServicePeer;
diff --git a/cpp/watchdog/server/src/WatchdogServiceHelper.cpp b/cpp/watchdog/server/src/WatchdogServiceHelper.cpp
index f541ea9..2b4b578 100644
--- a/cpp/watchdog/server/src/WatchdogServiceHelper.cpp
+++ b/cpp/watchdog/server/src/WatchdogServiceHelper.cpp
@@ -61,33 +61,47 @@
Status WatchdogServiceHelper::registerService(
const android::sp<ICarWatchdogServiceForSystem>& service) {
- std::unique_lock writeLock(mRWMutex);
- if (mWatchdogProcessService == nullptr) {
- return Status::fromExceptionCode(Status::EX_ILLEGAL_STATE,
- "Must initialize watchdog service helper before "
- "registering car watchdog service");
+ if (service == nullptr) {
+ return Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT,
+ "Must provide non-null service");
}
- sp<IBinder> curBinder = BnCarWatchdogServiceForSystem::asBinder(mService);
- sp<IBinder> newBinder = BnCarWatchdogServiceForSystem::asBinder(service);
- if (mService != nullptr && curBinder == newBinder) {
- return Status::ok();
+ sp<IBinder> binder = BnCarWatchdogServiceForSystem::asBinder(service);
+ {
+ std::unique_lock writeLock(mRWMutex);
+ if (mWatchdogProcessService == nullptr) {
+ return Status::fromExceptionCode(Status::EX_ILLEGAL_STATE,
+ "Must initialize watchdog service helper before "
+ "registering car watchdog service");
+ }
+ if (mService != nullptr && BnCarWatchdogServiceForSystem::asBinder(mService) == binder) {
+ return Status::ok();
+ }
+ unregisterServiceLocked();
+ if (Status status = mWatchdogProcessService->registerCarWatchdogService(binder);
+ !status.isOk()) {
+ return status;
+ }
+ mService = service;
}
- if (status_t ret = newBinder->linkToDeath(sp<WatchdogServiceHelper>::fromExisting(this));
+ if (status_t ret = binder->linkToDeath(sp<WatchdogServiceHelper>::fromExisting(this));
ret != OK) {
+ std::unique_lock writeLock(mRWMutex);
+ if (mService != nullptr && BnCarWatchdogServiceForSystem::asBinder(mService) == binder) {
+ mWatchdogProcessService->unregisterCarWatchdogService(binder);
+ mService.clear();
+ }
return Status::fromExceptionCode(Status::EX_ILLEGAL_STATE,
"Failed to register car watchdog service as it is dead");
}
- unregisterServiceLocked();
- if (Status status = mWatchdogProcessService->registerCarWatchdogService(newBinder);
- !status.isOk()) {
- newBinder->unlinkToDeath(sp<WatchdogServiceHelper>::fromExisting(this));
- return status;
- }
- mService = service;
+ ALOGI("CarWatchdogService is registered");
return Status::ok();
}
Status WatchdogServiceHelper::unregisterService(const sp<ICarWatchdogServiceForSystem>& service) {
+ if (service == nullptr) {
+ return Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT,
+ "Must provide non-null service");
+ }
std::unique_lock writeLock(mRWMutex);
if (sp<IBinder> binder = BnCarWatchdogServiceForSystem::asBinder(service);
binder != BnCarWatchdogServiceForSystem::asBinder(mService)) {
@@ -96,6 +110,7 @@
"registered");
}
unregisterServiceLocked();
+ ALOGI("CarWatchdogService is unregistered");
return Status::ok();
}
diff --git a/cpp/watchdog/server/sysprop/WatchdogProperties.sysprop b/cpp/watchdog/server/sysprop/WatchdogProperties.sysprop
index 4b51213..20f3b14 100644
--- a/cpp/watchdog/server/sysprop/WatchdogProperties.sysprop
+++ b/cpp/watchdog/server/sysprop/WatchdogProperties.sysprop
@@ -17,11 +17,29 @@
# Interval in seconds between consecutive boot-time performance data collections.
prop {
- api_name: "boottimeCollectionInterval"
+ api_name: "systemEventCollectionInterval"
type: Integer
scope: Internal
access: Readonly
- prop_name: "ro.carwatchdog.boottime_collection_interval"
+ prop_name: "ro.carwatchdog.system_event_collection_interval"
+}
+
+# Duration in seconds of timeout when final signal not received during user-switch.
+prop {
+ api_name: "userSwitchTimeout"
+ type: Integer
+ scope: Internal
+ access: Readonly
+ prop_name: "ro.carwatchdog.user_switch_timeout"
+}
+
+# Duration in seconds of data collection after final signal received for system event.
+prop {
+ api_name: "postSystemEventDuration"
+ type: Integer
+ scope: Internal
+ access: Readonly
+ prop_name: "ro.carwatchdog.post_system_event_duration"
}
# Maximum number of periodically collected records to be cached in memory.
@@ -78,6 +96,15 @@
prop_name: "ro.carwatchdog.top_n_stats_per_subcategory"
}
+# Max cache size of user-switch events.
+prop {
+ api_name: "maxUserSwitchEvents"
+ type: Integer
+ scope: Internal
+ access: Readonly
+ prop_name: "ro.carwatchdog.max_user_switch_events"
+}
+
# Percentage of I/O overuse threshold.
prop {
api_name: "ioOveruseWarnPercentage"
diff --git a/cpp/watchdog/server/sysprop/api/libwatchdog_properties-latest.txt b/cpp/watchdog/server/sysprop/api/libwatchdog_properties-latest.txt
index ab59538..da8cfe1 100644
--- a/cpp/watchdog/server/sysprop/api/libwatchdog_properties-latest.txt
+++ b/cpp/watchdog/server/sysprop/api/libwatchdog_properties-latest.txt
@@ -1,10 +1,22 @@
props {
module: "android.automotive.watchdog.sysprop"
prop {
- api_name: "boottimeCollectionInterval"
+ api_name: "systemEventCollectionInterval"
type: Integer
scope: Internal
- prop_name: "ro.carwatchdog.boottime_collection_interval"
+ prop_name: "ro.carwatchdog.system_event_collection_interval"
+ }
+ prop {
+ api_name: "userSwitchTimeout"
+ type: Integer
+ scope: Internal
+ prop_name: "ro.carwatchdog.user_switch_timeout"
+ }
+ prop {
+ api_name: "postSystemEventDuration"
+ type: Integer
+ scope: Internal
+ prop_name: "ro.carwatchdog.post_system_event_duration"
}
prop {
api_name: "periodicCollectionBufferSize"
@@ -30,4 +42,10 @@
scope: Internal
prop_name: "ro.carwatchdog.top_n_stats_per_subcategory"
}
+ prop {
+ api_name: "maxUserSwitchEvents"
+ type: Integer
+ scope: Internal
+ prop_name: "ro.carwatchdog.max_user_switch_events"
+ }
}
diff --git a/cpp/watchdog/server/tests/IoPerfCollectionTest.cpp b/cpp/watchdog/server/tests/IoPerfCollectionTest.cpp
index 49f1aee..2bbd11f 100644
--- a/cpp/watchdog/server/tests/IoPerfCollectionTest.cpp
+++ b/cpp/watchdog/server/tests/IoPerfCollectionTest.cpp
@@ -36,6 +36,8 @@
namespace automotive {
namespace watchdog {
+namespace {
+
using ::android::RefBase;
using ::android::sp;
using ::android::automotive::watchdog::internal::PackageInfo;
@@ -54,7 +56,9 @@
using ::testing::UnorderedElementsAreArray;
using ::testing::VariantWith;
-namespace {
+constexpr int kTestTopNStatsPerCategory = 5;
+constexpr int kTestTopNStatsPerSubcategory = 5;
+constexpr int kTestMaxUserSwitchEvents = 3;
MATCHER_P(IoStatsEq, expected, "") {
return ExplainMatchResult(AllOf(Field("bytes", &UserPackageStats::IoStats::bytes,
@@ -64,25 +68,26 @@
arg, result_listener);
}
-MATCHER_P(ProcessCountEq, expected, "") {
- return ExplainMatchResult(AllOf(Field("comm", &UserPackageStats::ProcStats::ProcessCount::comm,
+MATCHER_P(ProcessValueEq, expected, "") {
+ return ExplainMatchResult(AllOf(Field("comm", &UserPackageStats::ProcStats::ProcessValue::comm,
Eq(expected.comm)),
- Field("count",
- &UserPackageStats::ProcStats::ProcessCount::count,
- Eq(expected.count))),
+ Field("value",
+ &UserPackageStats::ProcStats::ProcessValue::value,
+ Eq(expected.value))),
arg, result_listener);
}
MATCHER_P(ProcStatsEq, expected, "") {
- std::vector<Matcher<const UserPackageStats::ProcStats::ProcessCount&>> processCountMatchers;
- for (const auto& processCount : expected.topNProcesses) {
- processCountMatchers.push_back(ProcessCountEq(processCount));
+ std::vector<Matcher<const UserPackageStats::ProcStats::ProcessValue&>> processValueMatchers;
+ processValueMatchers.reserve(expected.topNProcesses.size());
+ for (const auto& processValue : expected.topNProcesses) {
+ processValueMatchers.push_back(ProcessValueEq(processValue));
}
- return ExplainMatchResult(AllOf(Field("count", &UserPackageStats::ProcStats::count,
- Eq(expected.count)),
+ return ExplainMatchResult(AllOf(Field("value", &UserPackageStats::ProcStats::value,
+ Eq(expected.value)),
Field("topNProcesses",
&UserPackageStats::ProcStats::topNProcesses,
- ElementsAreArray(processCountMatchers))),
+ ElementsAreArray(processValueMatchers))),
arg, result_listener);
}
@@ -129,7 +134,9 @@
}
return ElementsAreArray(matchers);
};
- return ExplainMatchResult(AllOf(Field("topNIoReads", &UserPackageSummaryStats::topNIoReads,
+ return ExplainMatchResult(AllOf(Field("topNCpuTimes", &UserPackageSummaryStats::topNCpuTimes,
+ userPackageStatsMatchers(expected.topNCpuTimes)),
+ Field("topNIoReads", &UserPackageSummaryStats::topNIoReads,
userPackageStatsMatchers(expected.topNIoReads)),
Field("topNIoWrites", &UserPackageSummaryStats::topNIoWrites,
userPackageStatsMatchers(expected.topNIoWrites)),
@@ -143,6 +150,9 @@
Field("taskCountByUid",
&UserPackageSummaryStats::taskCountByUid,
IsSubsetOf(expected.taskCountByUid)),
+ Field("totalCpuTimeMillis",
+ &UserPackageSummaryStats::totalCpuTimeMillis,
+ Eq(expected.totalCpuTimeMillis)),
Field("totalMajorFaults",
&UserPackageSummaryStats::totalMajorFaults,
Eq(expected.totalMajorFaults)),
@@ -153,10 +163,18 @@
}
MATCHER_P(SystemSummaryStatsEq, expected, "") {
- return ExplainMatchResult(AllOf(Field("cpuIoWaitTime", &SystemSummaryStats::cpuIoWaitTime,
- Eq(expected.cpuIoWaitTime)),
- Field("totalCpuTime", &SystemSummaryStats::totalCpuTime,
- Eq(expected.totalCpuTime)),
+ return ExplainMatchResult(AllOf(Field("cpuIoWaitTimeMillis",
+ &SystemSummaryStats::cpuIoWaitTimeMillis,
+ Eq(expected.cpuIoWaitTimeMillis)),
+ Field("cpuIdleTimeMillis",
+ &SystemSummaryStats::cpuIdleTimeMillis,
+ Eq(expected.cpuIdleTimeMillis)),
+ Field("totalCpuTimeMillis",
+ &SystemSummaryStats::totalCpuTimeMillis,
+ Eq(expected.totalCpuTimeMillis)),
+ Field("contextSwitchesCount",
+ &SystemSummaryStats::contextSwitchesCount,
+ Eq(expected.contextSwitchesCount)),
Field("ioBlockedProcessCount",
&SystemSummaryStats::ioBlockedProcessCount,
Eq(expected.ioBlockedProcessCount)),
@@ -193,6 +211,26 @@
arg, result_listener);
}
+MATCHER_P(UserSwitchCollectionInfoEq, expected, "") {
+ return ExplainMatchResult(AllOf(Field("from", &UserSwitchCollectionInfo::from,
+ Eq(expected.from)),
+ Field("to", &UserSwitchCollectionInfo::to, Eq(expected.to)),
+ Field("maxCacheSize", &UserSwitchCollectionInfo::maxCacheSize,
+ Eq(expected.maxCacheSize)),
+ Field("records", &UserSwitchCollectionInfo::records,
+ ElementsAreArray(constructPerfStatsRecordMatchers(
+ expected.records)))),
+ arg, result_listener);
+}
+
+MATCHER_P(UserSwitchCollectionsEq, expected, "") {
+ std::vector<Matcher<const UserSwitchCollectionInfo&>> userSwitchCollectionMatchers;
+ for (const auto& curCollection : expected) {
+ userSwitchCollectionMatchers.push_back(UserSwitchCollectionInfoEq(curCollection));
+ }
+ return ExplainMatchResult(ElementsAreArray(userSwitchCollectionMatchers), arg, result_listener);
+}
+
int countOccurrences(std::string str, std::string subStr) {
size_t pos = 0;
int occurrences = 0;
@@ -216,75 +254,99 @@
};
std::vector<UidStats>
uidStats{{.packageInfo = constructPackageInfo("mount", 1009),
+ .cpuTimeMillis = int64Multiplier(50),
.ioStats = {/*fgRdBytes=*/0,
/*bgRdBytes=*/int64Multiplier(14'000),
/*fgWrBytes=*/0,
/*bgWrBytes=*/int64Multiplier(16'000),
/*fgFsync=*/0, /*bgFsync=*/int64Multiplier(100)},
- .procStats = {.totalMajorFaults = uint64Multiplier(11'000),
+ .procStats = {.cpuTimeMillis = int64Multiplier(50),
+ .totalMajorFaults = uint64Multiplier(11'000),
.totalTasksCount = 1,
.ioBlockedTasksCount = 1,
.processStatsByPid =
{{/*pid=*/100,
{/*comm=*/"disk I/O", /*startTime=*/234,
+ /*cpuTimeMillis=*/int64Multiplier(50),
/*totalMajorFaults=*/uint64Multiplier(11'000),
/*totalTasksCount=*/1,
/*ioBlockedTasksCount=*/1}}}}},
{.packageInfo =
constructPackageInfo("com.google.android.car.kitchensink", 1002001),
+ .cpuTimeMillis = int64Multiplier(60),
.ioStats = {/*fgRdBytes=*/0,
/*bgRdBytes=*/int64Multiplier(3'400),
/*fgWrBytes=*/0,
/*bgWrBytes=*/int64Multiplier(6'700),
/*fgFsync=*/0,
/*bgFsync=*/int64Multiplier(200)},
- .procStats = {.totalMajorFaults = uint64Multiplier(22'445),
+ .procStats = {.cpuTimeMillis = int64Multiplier(50),
+ .totalMajorFaults = uint64Multiplier(22'445),
.totalTasksCount = 5,
.ioBlockedTasksCount = 3,
.processStatsByPid =
{{/*pid=*/1000,
{/*comm=*/"KitchenSinkApp", /*startTime=*/467,
+ /*cpuTimeMillis=*/int64Multiplier(25),
/*totalMajorFaults=*/uint64Multiplier(12'345),
/*totalTasksCount=*/2,
/*ioBlockedTasksCount=*/1}},
{/*pid=*/1001,
{/*comm=*/"CTS", /*startTime=*/789,
+ /*cpuTimeMillis=*/int64Multiplier(25),
/*totalMajorFaults=*/uint64Multiplier(10'100),
/*totalTasksCount=*/3,
/*ioBlockedTasksCount=*/2}}}}},
{.packageInfo = constructPackageInfo("", 1012345),
+ .cpuTimeMillis = int64Multiplier(100),
.ioStats = {/*fgRdBytes=*/int64Multiplier(1'000),
/*bgRdBytes=*/int64Multiplier(4'200),
/*fgWrBytes=*/int64Multiplier(300),
/*bgWrBytes=*/int64Multiplier(5'600),
/*fgFsync=*/int64Multiplier(600),
/*bgFsync=*/int64Multiplier(300)},
- .procStats = {.totalMajorFaults = uint64Multiplier(50'900),
+ .procStats = {.cpuTimeMillis = int64Multiplier(100),
+ .totalMajorFaults = uint64Multiplier(50'900),
.totalTasksCount = 4,
.ioBlockedTasksCount = 2,
.processStatsByPid =
{{/*pid=*/2345,
{/*comm=*/"MapsApp", /*startTime=*/6789,
+ /*cpuTimeMillis=*/int64Multiplier(100),
/*totalMajorFaults=*/uint64Multiplier(50'900),
/*totalTasksCount=*/4,
/*ioBlockedTasksCount=*/2}}}}},
{.packageInfo = constructPackageInfo("com.google.radio", 1015678),
+ .cpuTimeMillis = 0,
.ioStats = {/*fgRdBytes=*/0,
/*bgRdBytes=*/0,
/*fgWrBytes=*/0,
/*bgWrBytes=*/0,
/*fgFsync=*/0, /*bgFsync=*/0},
- .procStats = {.totalMajorFaults = 0,
+ .procStats = {.cpuTimeMillis = 0,
+ .totalMajorFaults = 0,
.totalTasksCount = 4,
.ioBlockedTasksCount = 0,
.processStatsByPid = {
{/*pid=*/2345,
{/*comm=*/"RadioApp", /*startTime=*/19789,
+ /*cpuTimeMillis=*/0,
/*totalMajorFaults=*/0,
/*totalTasksCount=*/4,
/*ioBlockedTasksCount=*/0}}}}}};
UserPackageSummaryStats userPackageSummaryStats{
+ .topNCpuTimes = {{1012345, "1012345",
+ UserPackageStats::ProcStats{uint64Multiplier(100),
+ {{"MapsApp", uint64Multiplier(100)}}}},
+ {1002001, "com.google.android.car.kitchensink",
+ UserPackageStats::ProcStats{uint64Multiplier(60),
+ {{"CTS", uint64Multiplier(25)},
+ {"KitchenSinkApp",
+ uint64Multiplier(25)}}}},
+ {1009, "mount",
+ UserPackageStats::ProcStats{uint64Multiplier(50),
+ {{"disk I/O", uint64Multiplier(50)}}}}},
.topNIoReads =
{{1009, "mount",
UserPackageStats::IoStats{{0, int64Multiplier(14'000)},
@@ -325,6 +387,7 @@
{int64Multiplier(300), int64Multiplier(28'300)},
{int64Multiplier(600), int64Multiplier(600)}},
.taskCountByUid = {{1009, 1}, {1002001, 5}, {1012345, 4}},
+ .totalCpuTimeMillis = int64Multiplier(48'376),
.totalMajorFaults = uint64Multiplier(84'345),
.majorFaultsPercentChange = 0.0,
};
@@ -332,21 +395,27 @@
}
std::tuple<ProcStatInfo, SystemSummaryStats> sampleProcStat(int multiplier = 1) {
+ const auto int64Multiplier = [&](int64_t bytes) -> int64_t {
+ return static_cast<int64_t>(bytes * multiplier);
+ };
const auto uint64Multiplier = [&](uint64_t bytes) -> uint64_t {
return static_cast<uint64_t>(bytes * multiplier);
};
const auto uint32Multiplier = [&](uint32_t bytes) -> uint32_t {
return static_cast<uint32_t>(bytes * multiplier);
};
- ProcStatInfo procStatInfo{/*cpuStats=*/{uint64Multiplier(2'900), uint64Multiplier(7'900),
- uint64Multiplier(4'900), uint64Multiplier(8'900),
- /*ioWaitTime=*/uint64Multiplier(5'900),
- uint64Multiplier(6'966), uint64Multiplier(7'980), 0, 0,
- uint64Multiplier(2'930)},
- /*runnableProcessCount=*/uint32Multiplier(100),
- /*ioBlockedProcessCount=*/uint32Multiplier(57)};
- SystemSummaryStats systemSummaryStats{/*cpuIoWaitTime=*/uint64Multiplier(5'900),
- /*totalCpuTime=*/uint64Multiplier(48'376),
+ ProcStatInfo procStatInfo{/*stats=*/{int64Multiplier(2'900), int64Multiplier(7'900),
+ int64Multiplier(4'900), int64Multiplier(8'900),
+ /*ioWaitTimeMillis=*/int64Multiplier(5'900),
+ int64Multiplier(6'966), int64Multiplier(7'980), 0, 0,
+ int64Multiplier(2'930)},
+ /*ctxtSwitches=*/uint64Multiplier(500),
+ /*runnableCnt=*/uint32Multiplier(100),
+ /*ioBlockedCnt=*/uint32Multiplier(57)};
+ SystemSummaryStats systemSummaryStats{/*cpuIoWaitTimeMillis=*/int64Multiplier(5'900),
+ /*cpuIdleTimeMillis=*/int64Multiplier(8'900),
+ /*totalCpuTimeMillis=*/int64Multiplier(48'376),
+ /*contextSwitchesCount=*/uint64Multiplier(500),
/*ioBlockedProcessCount=*/uint32Multiplier(57),
/*totalProcessCount=*/uint32Multiplier(157)};
return std::make_tuple(procStatInfo, systemSummaryStats);
@@ -372,6 +441,8 @@
void setTopNStatsPerSubcategory(int value) { mCollector->mTopNStatsPerSubcategory = value; }
+ void setMaxUserSwitchEvents(int value) { mCollector->mMaxUserSwitchEvents = value; }
+
const CollectionInfo& getBoottimeCollectionInfo() {
Mutex::Autolock lock(mCollector->mMutex);
return mCollector->mBoottimeCollection;
@@ -382,6 +453,11 @@
return mCollector->mPeriodicCollection;
}
+ const std::vector<UserSwitchCollectionInfo>& getUserSwitchCollectionInfos() {
+ Mutex::Autolock lock(mCollector->mMutex);
+ return mCollector->mUserSwitchCollections;
+ }
+
const CollectionInfo& getCustomCollectionInfo() {
Mutex::Autolock lock(mCollector->mMutex);
return mCollector->mCustomCollection;
@@ -401,8 +477,9 @@
mCollector = sp<IoPerfCollection>::make();
mCollectorPeer = sp<internal::IoPerfCollectionPeer>::make(mCollector);
ASSERT_RESULT_OK(mCollectorPeer->init());
- mCollectorPeer->setTopNStatsPerCategory(5);
- mCollectorPeer->setTopNStatsPerSubcategory(5);
+ mCollectorPeer->setTopNStatsPerCategory(kTestTopNStatsPerCategory);
+ mCollectorPeer->setTopNStatsPerSubcategory(kTestTopNStatsPerSubcategory);
+ mCollectorPeer->setMaxUserSwitchEvents(kTestMaxUserSwitchEvents);
}
void TearDown() override {
@@ -471,8 +548,178 @@
<< expected.toString() << "\nActual:\n"
<< actual.toString();
- ASSERT_NO_FATAL_FAILURE(checkDumpContents(/*wantedEmptyCollectionInstances=*/1))
- << "Periodic collection shouldn't be reported";
+ ASSERT_NO_FATAL_FAILURE(checkDumpContents(/*wantedEmptyCollectionInstances=*/2))
+ << "Periodic and user-switch collections shouldn't be reported";
+}
+
+TEST_F(IoPerfCollectionTest, TestOnUserSwitchCollection) {
+ auto [uidStats, userPackageSummaryStats] = sampleUidStats();
+ auto [procStatInfo, systemSummaryStats] = sampleProcStat();
+
+ EXPECT_CALL(*mMockUidStatsCollector, deltaStats()).WillOnce(Return(uidStats));
+ EXPECT_CALL(*mMockProcStatCollector, deltaStats()).WillOnce(Return(procStatInfo));
+
+ time_t now = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
+ ASSERT_RESULT_OK(mCollector->onUserSwitchCollection(now, 100, 101, mMockUidStatsCollector,
+ mMockProcStatCollector));
+
+ const auto& actualInfos = mCollectorPeer->getUserSwitchCollectionInfos();
+ const auto& actual = actualInfos[0];
+
+ UserSwitchCollectionInfo expected{
+ {
+ .maxCacheSize = std::numeric_limits<std::size_t>::max(),
+ .records = {{
+ .systemSummaryStats = systemSummaryStats,
+ .userPackageSummaryStats = userPackageSummaryStats,
+ }},
+ },
+ .from = 100,
+ .to = 101,
+ };
+
+ EXPECT_THAT(actualInfos.size(), 1);
+
+ EXPECT_THAT(actual, UserSwitchCollectionInfoEq(expected))
+ << "User switch collection info doesn't match.\nExpected:\n"
+ << expected.toString() << "\nActual:\n"
+ << actual.toString();
+
+ // Continuation of the previous user switch collection
+ std::vector<UidStats> nextUidStats = {
+ {.packageInfo = constructPackageInfo("mount", 1009),
+ .ioStats = {/*fgRdBytes=*/0,
+ /*bgRdBytes=*/5'000,
+ /*fgWrBytes=*/0,
+ /*bgWrBytes=*/3'000,
+ /*fgFsync=*/0, /*bgFsync=*/50},
+ .procStats = {.cpuTimeMillis = 50,
+ .totalMajorFaults = 6'000,
+ .totalTasksCount = 1,
+ .ioBlockedTasksCount = 2,
+ .processStatsByPid = {{/*pid=*/100,
+ {/*comm=*/"disk I/O", /*startTime=*/234,
+ /*cpuTimeMillis=*/50,
+ /*totalMajorFaults=*/6'000,
+ /*totalTasksCount=*/1,
+ /*ioBlockedTasksCount=*/2}}}}}};
+
+ UserPackageSummaryStats nextUserPackageSummaryStats = {
+ .topNIoReads = {{1009, "mount", UserPackageStats::IoStats{{0, 5'000}, {0, 50}}}},
+ .topNIoWrites = {{1009, "mount", UserPackageStats::IoStats{{0, 3'000}, {0, 50}}}},
+ .topNIoBlocked = {{1009, "mount", UserPackageStats::ProcStats{2, {{"disk I/O", 2}}}}},
+ .topNMajorFaults = {{1009, "mount",
+ UserPackageStats::ProcStats{6'000, {{"disk I/O", 6'000}}}}},
+ .totalIoStats = {{0, 5'000}, {0, 3'000}, {0, 50}},
+ .taskCountByUid = {{1009, 1}},
+ .totalCpuTimeMillis = 48'376,
+ .totalMajorFaults = 6'000,
+ .majorFaultsPercentChange = (6'000.0 - 84'345.0) / 84'345.0 * 100.0,
+ };
+
+ ProcStatInfo nextProcStatInfo = procStatInfo;
+ SystemSummaryStats nextSystemSummaryStats = systemSummaryStats;
+
+ nextProcStatInfo.contextSwitchesCount = 300;
+ nextSystemSummaryStats.contextSwitchesCount = 300;
+
+ EXPECT_CALL(*mMockUidStatsCollector, deltaStats()).WillOnce(Return(nextUidStats));
+ EXPECT_CALL(*mMockProcStatCollector, deltaStats()).WillOnce(Return(nextProcStatInfo));
+
+ now = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
+ ASSERT_RESULT_OK(mCollector->onUserSwitchCollection(now, 100, 101, mMockUidStatsCollector,
+ mMockProcStatCollector));
+
+ auto& continuationActualInfos = mCollectorPeer->getUserSwitchCollectionInfos();
+ auto& continuationActual = continuationActualInfos[0];
+
+ expected = {
+ {
+ .maxCacheSize = std::numeric_limits<std::size_t>::max(),
+ .records = {{.systemSummaryStats = systemSummaryStats,
+ .userPackageSummaryStats = userPackageSummaryStats},
+ {.systemSummaryStats = nextSystemSummaryStats,
+ .userPackageSummaryStats = nextUserPackageSummaryStats}},
+ },
+ .from = 100,
+ .to = 101,
+ };
+
+ EXPECT_THAT(continuationActualInfos.size(), 1);
+
+ EXPECT_THAT(continuationActual, UserSwitchCollectionInfoEq(expected))
+ << "User switch collection info after continuation doesn't match.\nExpected:\n"
+ << expected.toString() << "\nActual:\n"
+ << actual.toString();
+
+ ASSERT_NO_FATAL_FAILURE(checkDumpContents(/*wantedEmptyCollectionInstances=*/2))
+ << "Boottime and Periodic collections shouldn't be reported";
+}
+
+TEST_F(IoPerfCollectionTest, TestUserSwitchCollectionsMaxCacheSize) {
+ auto [uidStats, userPackageSummaryStats] = sampleUidStats();
+ auto [procStatInfo, systemSummaryStats] = sampleProcStat();
+
+ EXPECT_CALL(*mMockUidStatsCollector, deltaStats()).WillRepeatedly(Return(uidStats));
+ EXPECT_CALL(*mMockProcStatCollector, deltaStats()).WillRepeatedly(Return(procStatInfo));
+
+ std::vector<UserSwitchCollectionInfo> expectedEvents;
+ for (userid_t userId = 100; userId < 100 + kTestMaxUserSwitchEvents; ++userId) {
+ expectedEvents.push_back({
+ {
+ .maxCacheSize = std::numeric_limits<std::size_t>::max(),
+ .records = {{
+ .systemSummaryStats = systemSummaryStats,
+ .userPackageSummaryStats = userPackageSummaryStats,
+ }},
+ },
+ .from = userId,
+ .to = userId + 1,
+ });
+ }
+
+ time_t now = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
+
+ for (userid_t userId = 100; userId < 100 + kTestMaxUserSwitchEvents; ++userId) {
+ ASSERT_RESULT_OK(mCollector->onUserSwitchCollection(now, userId, userId + 1,
+ mMockUidStatsCollector,
+ mMockProcStatCollector));
+ }
+
+ const auto& actual = mCollectorPeer->getUserSwitchCollectionInfos();
+
+ EXPECT_THAT(actual.size(), kTestMaxUserSwitchEvents);
+
+ EXPECT_THAT(actual, UserSwitchCollectionsEq(expectedEvents))
+ << "User switch collection infos don't match.";
+
+ // Add new user switch event with max cache size. The oldest user switch event should be dropped
+ // and the new one added to the cache.
+ userid_t userId = 100 + kTestMaxUserSwitchEvents;
+
+ expectedEvents.push_back({
+ {
+ .maxCacheSize = std::numeric_limits<std::size_t>::max(),
+ .records = {{
+ .systemSummaryStats = systemSummaryStats,
+ .userPackageSummaryStats = userPackageSummaryStats,
+ }},
+ },
+ .from = userId,
+ .to = userId + 1,
+ });
+ expectedEvents.erase(expectedEvents.begin());
+
+ ASSERT_RESULT_OK(mCollector->onUserSwitchCollection(now, userId, userId + 1,
+ mMockUidStatsCollector,
+ mMockProcStatCollector));
+
+ const auto& actualInfos = mCollectorPeer->getUserSwitchCollectionInfos();
+
+ EXPECT_THAT(actualInfos.size(), kTestMaxUserSwitchEvents);
+
+ EXPECT_THAT(actualInfos, UserSwitchCollectionsEq(expectedEvents))
+ << "User switch collection infos don't match.";
}
TEST_F(IoPerfCollectionTest, TestOnPeriodicCollection) {
@@ -503,8 +750,8 @@
<< expected.toString() << "\nActual:\n"
<< actual.toString();
- ASSERT_NO_FATAL_FAILURE(checkDumpContents(/*wantedEmptyCollectionInstances=*/1))
- << "Boot-time collection shouldn't be reported";
+ ASSERT_NO_FATAL_FAILURE(checkDumpContents(/*wantedEmptyCollectionInstances=*/2))
+ << "Boot-time and user-switch collections shouldn't be reported";
}
TEST_F(IoPerfCollectionTest, TestOnCustomCollectionWithoutPackageFilter) {
@@ -567,6 +814,10 @@
const auto actual = mCollectorPeer->getCustomCollectionInfo();
UserPackageSummaryStats userPackageSummaryStats{
+ .topNCpuTimes = {{1009, "mount", UserPackageStats::ProcStats{50, {{"disk I/O", 50}}}},
+ {1002001, "com.google.android.car.kitchensink",
+ UserPackageStats::ProcStats{60,
+ {{"CTS", 25}, {"KitchenSinkApp", 25}}}}},
.topNIoReads = {{1009, "mount", UserPackageStats::IoStats{{0, 14'000}, {0, 100}}},
{1002001, "com.google.android.car.kitchensink",
UserPackageStats::IoStats{{0, 3'400}, {0, 200}}}},
@@ -584,6 +835,7 @@
{{"KitchenSinkApp", 12'345}, {"CTS", 10'100}}}}},
.totalIoStats = {{1000, 21'600}, {300, 28'300}, {600, 600}},
.taskCountByUid = {{1009, 1}, {1002001, 5}},
+ .totalCpuTimeMillis = 48'376,
.totalMajorFaults = 84'345,
.majorFaultsPercentChange = 0.0,
};
@@ -633,6 +885,8 @@
const auto actual = mCollectorPeer->getPeriodicCollectionInfo();
UserPackageSummaryStats userPackageSummaryStats{
+ .topNCpuTimes = {{1012345, "1012345",
+ UserPackageStats::ProcStats{100, {{"MapsApp", 100}}}}},
.topNIoReads = {{1009, "mount", UserPackageStats::IoStats{{0, 14'000}, {0, 100}}}},
.topNIoWrites = {{1009, "mount", UserPackageStats::IoStats{{0, 16'000}, {0, 100}}}},
.topNIoBlocked = {{1002001, "com.google.android.car.kitchensink",
@@ -641,6 +895,7 @@
UserPackageStats::ProcStats{50'900, {{"MapsApp", 50'900}}}}},
.totalIoStats = {{1000, 21'600}, {300, 28'300}, {600, 600}},
.taskCountByUid = {{1009, 1}, {1002001, 5}, {1012345, 4}},
+ .totalCpuTimeMillis = 48'376,
.totalMajorFaults = 84'345,
.majorFaultsPercentChange = 0.0,
};
@@ -659,8 +914,8 @@
<< expected.toString() << "\nActual:\n"
<< actual.toString();
- ASSERT_NO_FATAL_FAILURE(checkDumpContents(/*wantedEmptyCollectionInstances=*/1))
- << "Boot-time collection shouldn't be reported";
+ ASSERT_NO_FATAL_FAILURE(checkDumpContents(/*wantedEmptyCollectionInstances=*/2))
+ << "Boot-time and user-switch collections shouldn't be reported";
}
TEST_F(IoPerfCollectionTest, TestConsecutiveOnPeriodicCollection) {
@@ -707,8 +962,8 @@
<< expected.toString() << "\nActual:\n"
<< actual.toString();
- ASSERT_NO_FATAL_FAILURE(checkDumpContents(/*wantedEmptyCollectionInstances=*/1))
- << "Boot-time collection shouldn't be reported";
+ ASSERT_NO_FATAL_FAILURE(checkDumpContents(/*wantedEmptyCollectionInstances=*/2))
+ << "Boot-time and user-switch collection shouldn't be reported";
}
} // namespace watchdog
diff --git a/cpp/watchdog/server/tests/LooperStub.cpp b/cpp/watchdog/server/tests/LooperStub.cpp
index 57fb891..cad9037 100644
--- a/cpp/watchdog/server/tests/LooperStub.cpp
+++ b/cpp/watchdog/server/tests/LooperStub.cpp
@@ -19,6 +19,8 @@
#include <android-base/chrono_utils.h>
#include <utils/Looper.h>
+#include <inttypes.h>
+
#include <future> // NOLINT(build/c++11)
namespace android {
@@ -78,6 +80,12 @@
Mutex::Autolock lock(mMutex);
mHandler = handler;
nsecs_t uptimeDelay = uptime - now();
+ if (uptimeDelay < 0) {
+ ALOGE("Posted message: %d in looper with an elapsed uptime: %" PRId64 "(now=%" PRId64
+ "). Won't process message.",
+ message.what, uptime, uptime - uptimeDelay);
+ return;
+ }
size_t pos = static_cast<size_t>(ns2s(uptimeDelay));
while (mCache.size() < pos + 1) {
mCache.emplace_back(LooperStub::CacheEntry());
diff --git a/cpp/watchdog/server/tests/LooperStub.h b/cpp/watchdog/server/tests/LooperStub.h
index 9389c66..409d1a5 100644
--- a/cpp/watchdog/server/tests/LooperStub.h
+++ b/cpp/watchdog/server/tests/LooperStub.h
@@ -42,7 +42,8 @@
nsecs_t now() override { return mTimer.count(); }
// No-op when mShouldPoll is false. Otherwise, sends messages (in a non-empty CacheEntry from
- // the front of |mCache|) to the underlying looper and polls the looper immediately.
+ // the front of |mCache|) to the underlying looper and polls the looper immediately. This
+ // method is called internally by the underlying looper.
int pollAll(int timeoutMillis) override;
// Updates the front of |mCache| with the given message so the next pollAll call to the
diff --git a/cpp/watchdog/server/tests/MockDataProcessor.h b/cpp/watchdog/server/tests/MockDataProcessor.h
index ee199e4..8abc753 100644
--- a/cpp/watchdog/server/tests/MockDataProcessor.h
+++ b/cpp/watchdog/server/tests/MockDataProcessor.h
@@ -41,6 +41,10 @@
(time_t, SystemState, const wp<UidStatsCollectorInterface>&,
const wp<ProcStatCollectorInterface>&),
(override));
+ MOCK_METHOD(android::base::Result<void>, onUserSwitchCollection,
+ (time_t, userid_t, userid_t, const wp<UidStatsCollectorInterface>&,
+ const wp<ProcStatCollectorInterface>&),
+ (override));
MOCK_METHOD(android::base::Result<void>, onCustomCollection,
(time_t, SystemState, const std::unordered_set<std::string>&,
const wp<UidStatsCollectorInterface>&, const wp<ProcStatCollectorInterface>&),
diff --git a/cpp/watchdog/server/tests/MockUidCpuStatsCollector.h b/cpp/watchdog/server/tests/MockUidCpuStatsCollector.h
new file mode 100644
index 0000000..3f42187
--- /dev/null
+++ b/cpp/watchdog/server/tests/MockUidCpuStatsCollector.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2022, 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 CPP_WATCHDOG_SERVER_TESTS_MOCKUIDCPUSTATSCOLLECTOR_H_
+#define CPP_WATCHDOG_SERVER_TESTS_MOCKUIDCPUSTATSCOLLECTOR_H_
+
+#include "UidCpuStatsCollector.h"
+
+#include <android-base/result.h>
+#include <gmock/gmock.h>
+
+#include <string>
+#include <unordered_map>
+
+namespace android {
+namespace automotive {
+namespace watchdog {
+
+class MockUidCpuStatsCollector : public UidCpuStatsCollectorInterface {
+public:
+ MockUidCpuStatsCollector() { ON_CALL(*this, enabled()).WillByDefault(::testing::Return(true)); }
+ MOCK_METHOD(void, init, (), (override));
+ MOCK_METHOD(android::base::Result<void>, collect, (), (override));
+ MOCK_METHOD((const std::unordered_map<uid_t, int64_t>), latestStats, (), (const, override));
+ MOCK_METHOD((const std::unordered_map<uid_t, int64_t>), deltaStats, (), (const, override));
+ MOCK_METHOD(bool, enabled, (), (const, override));
+ MOCK_METHOD(const std::string, filePath, (), (const, override));
+};
+
+} // namespace watchdog
+} // namespace automotive
+} // namespace android
+
+#endif // CPP_WATCHDOG_SERVER_TESTS_MOCKUIDCPUSTATSCOLLECTOR_H_
diff --git a/cpp/watchdog/server/tests/MockWatchdogPerfService.h b/cpp/watchdog/server/tests/MockWatchdogPerfService.h
index 9fb59e2..9aebb2f 100644
--- a/cpp/watchdog/server/tests/MockWatchdogPerfService.h
+++ b/cpp/watchdog/server/tests/MockWatchdogPerfService.h
@@ -20,6 +20,7 @@
#include "WatchdogPerfService.h"
#include <android-base/result.h>
+#include <android/automotive/watchdog/internal/UserState.h>
#include <gmock/gmock.h>
#include <utils/String16.h>
#include <utils/Vector.h>
@@ -38,6 +39,10 @@
MOCK_METHOD(void, terminate, (), (override));
MOCK_METHOD(void, setSystemState, (SystemState), (override));
MOCK_METHOD(android::base::Result<void>, onBootFinished, (), (override));
+ MOCK_METHOD(android::base::Result<void>, onUserStateChange,
+ (userid_t userId,
+ const android::automotive::watchdog::internal::UserState& userState),
+ (override));
MOCK_METHOD(android::base::Result<void>, onCustomCollection,
(int fd, const Vector<android::String16>& args), (override));
MOCK_METHOD(android::base::Result<void>, onDump, (int fd), (const, override));
diff --git a/cpp/watchdog/server/tests/MockWatchdogProcessService.h b/cpp/watchdog/server/tests/MockWatchdogProcessService.h
index 2969a86..93f330a 100644
--- a/cpp/watchdog/server/tests/MockWatchdogProcessService.h
+++ b/cpp/watchdog/server/tests/MockWatchdogProcessService.h
@@ -75,7 +75,7 @@
const android::automotive::watchdog::internal::ProcessIdentifier&),
(override));
MOCK_METHOD(void, setEnabled, (bool), (override));
- MOCK_METHOD(void, notifyUserStateChange, (userid_t, bool), (override));
+ MOCK_METHOD(void, onUserStateChange, (userid_t, bool), (override));
};
} // namespace watchdog
diff --git a/cpp/watchdog/server/tests/ProcStatCollectorTest.cpp b/cpp/watchdog/server/tests/ProcStatCollectorTest.cpp
index 633766f..f1d390c 100644
--- a/cpp/watchdog/server/tests/ProcStatCollectorTest.cpp
+++ b/cpp/watchdog/server/tests/ProcStatCollectorTest.cpp
@@ -28,21 +28,30 @@
namespace automotive {
namespace watchdog {
+namespace {
+
using ::android::base::StringPrintf;
using ::android::base::WriteStringToFile;
-namespace {
+const int64_t kMillisPerClockTick = 1000 / sysconf(_SC_CLK_TCK);
+
+int64_t clockTicksToMillis(int64_t ticks) {
+ return ticks * kMillisPerClockTick;
+}
std::string toString(const ProcStatInfo& info) {
const auto& cpuStats = info.cpuStats;
- return StringPrintf("Cpu Stats:\nUserTime: %" PRIu64 " NiceTime: %" PRIu64 " SysTime: %" PRIu64
- " IdleTime: %" PRIu64 " IoWaitTime: %" PRIu64 " IrqTime: %" PRIu64
- " SoftIrqTime: %" PRIu64 " StealTime: %" PRIu64 " GuestTime: %" PRIu64
- " GuestNiceTime: %" PRIu64 "\nNumber of running processes: %" PRIu32
+ return StringPrintf("Cpu Stats:\nUserTimeMillis: %" PRIu64 " NiceTimeMillis: %" PRIu64
+ " SysTimeMillis: %" PRIu64 " IdleTimeMillis: %" PRIu64
+ " IoWaitTimeMillis: %" PRIu64 " IrqTimeMillis: %" PRIu64
+ " SoftIrqTimeMillis: %" PRIu64 " StealTimeMillis: %" PRIu64
+ " GuestTimeMillis: %" PRIu64 " GuestNiceTimeMillis: %" PRIu64
+ "\nNumber of running processes: %" PRIu32
"\nNumber of blocked processes: %" PRIu32,
- cpuStats.userTime, cpuStats.niceTime, cpuStats.sysTime, cpuStats.idleTime,
- cpuStats.ioWaitTime, cpuStats.irqTime, cpuStats.softIrqTime,
- cpuStats.stealTime, cpuStats.guestTime, cpuStats.guestNiceTime,
+ cpuStats.userTimeMillis, cpuStats.niceTimeMillis, cpuStats.sysTimeMillis,
+ cpuStats.idleTimeMillis, cpuStats.ioWaitTimeMillis, cpuStats.irqTimeMillis,
+ cpuStats.softIrqTimeMillis, cpuStats.stealTimeMillis,
+ cpuStats.guestTimeMillis, cpuStats.guestNiceTimeMillis,
info.runnableProcessCount, info.ioBlockedProcessCount);
}
@@ -68,17 +77,18 @@
"softirq 33275060 934664 11958403 5111 516325 200333 0 341482 10651335 0 8667407\n";
ProcStatInfo expectedFirstDelta;
expectedFirstDelta.cpuStats = {
- .userTime = 6200,
- .niceTime = 5700,
- .sysTime = 1700,
- .idleTime = 3100,
- .ioWaitTime = 1100,
- .irqTime = 5200,
- .softIrqTime = 3900,
- .stealTime = 0,
- .guestTime = 0,
- .guestNiceTime = 0,
+ .userTimeMillis = clockTicksToMillis(6200),
+ .niceTimeMillis = clockTicksToMillis(5700),
+ .sysTimeMillis = clockTicksToMillis(1700),
+ .idleTimeMillis = clockTicksToMillis(3100),
+ .ioWaitTimeMillis = clockTicksToMillis(1100),
+ .irqTimeMillis = clockTicksToMillis(5200),
+ .softIrqTimeMillis = clockTicksToMillis(3900),
+ .stealTimeMillis = clockTicksToMillis(0),
+ .guestTimeMillis = clockTicksToMillis(0),
+ .guestNiceTimeMillis = clockTicksToMillis(0),
};
+ expectedFirstDelta.contextSwitchesCount = 579020168;
expectedFirstDelta.runnableProcessCount = 17;
expectedFirstDelta.ioBlockedProcessCount = 5;
@@ -105,7 +115,7 @@
"cpu3 3000 920 240 850 500 430 340 0 0 0\n"
"intr 694351583 0 0 0 297062868 0 5922464 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 "
"0 0\n"
- "ctxt 579020168\n"
+ "ctxt 810020192\n"
"btime 1579718450\n"
"processes 113804\n"
"procs_running 10\n"
@@ -113,17 +123,18 @@
"softirq 33275060 934664 11958403 5111 516325 200333 0 341482 10651335 0 8667407\n";
ProcStatInfo expectedSecondDelta;
expectedSecondDelta.cpuStats = {
- .userTime = 10000,
- .niceTime = 3000,
- .sysTime = 300,
- .idleTime = 1000,
- .ioWaitTime = 1100,
- .irqTime = 1000,
- .softIrqTime = 2000,
- .stealTime = 0,
- .guestTime = 0,
- .guestNiceTime = 0,
+ .userTimeMillis = clockTicksToMillis(10000),
+ .niceTimeMillis = clockTicksToMillis(3000),
+ .sysTimeMillis = clockTicksToMillis(300),
+ .idleTimeMillis = clockTicksToMillis(1000),
+ .ioWaitTimeMillis = clockTicksToMillis(1100),
+ .irqTimeMillis = clockTicksToMillis(1000),
+ .softIrqTimeMillis = clockTicksToMillis(2000),
+ .stealTimeMillis = clockTicksToMillis(0),
+ .guestTimeMillis = clockTicksToMillis(0),
+ .guestNiceTimeMillis = clockTicksToMillis(0),
};
+ expectedFirstDelta.contextSwitchesCount = 810020192;
expectedSecondDelta.runnableProcessCount = 10;
expectedSecondDelta.ioBlockedProcessCount = 2;
@@ -188,6 +199,31 @@
EXPECT_FALSE(collector.collect().ok()) << "No error returned due to missing cpu line";
}
+TEST(ProcStatCollectorTest, TestErrorOnMissingCtxtLine) {
+ constexpr char contents[] =
+ "cpu 16200 8700 2000 4100 1250 6200 5900 0 0 0\n"
+ "cpu0 2400 2900 600 690 340 4300 2100 0 0 0\n"
+ "cpu1 1900 2380 510 760 51 370 1500 0 0 0\n"
+ "cpu2 900 400 400 1000 600 400 160 0 0 0\n"
+ "cpu3 1000 20 190 650 109 130 140 0 0 0\n"
+ "intr 694351583 0 0 0 297062868 0 5922464 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 "
+ "0 0\n"
+ "btime 1579718450\n"
+ "processes 113804\n"
+ "procs_running 17\n"
+ "procs_blocked 5\n"
+ "softirq 33275060 934664 11958403 5111 516325 200333 0 341482 10651335 0 8667407\n";
+ TemporaryFile tf;
+ ASSERT_NE(tf.fd, -1);
+ ASSERT_TRUE(WriteStringToFile(contents, tf.path));
+
+ ProcStatCollector collector(tf.path);
+ collector.init();
+
+ ASSERT_TRUE(collector.enabled()) << "Temporary file is inaccessible";
+ EXPECT_FALSE(collector.collect().ok()) << "No error returned due to missing ctxt line";
+}
+
TEST(ProcStatCollectorTest, TestErrorOnMissingProcsRunningLine) {
constexpr char contents[] =
"cpu 16200 8700 2000 4100 1250 6200 5900 0 0 0\n"
@@ -276,7 +312,7 @@
/* The below checks should pass because the /proc/stats file should have the CPU time spent
* since bootup and there should be at least one running process.
*/
- EXPECT_GT(info.totalCpuTime(), static_cast<uint64_t>(0));
+ EXPECT_GT(info.totalCpuTimeMillis(), 0);
EXPECT_GT(info.totalProcessCount(), static_cast<uint32_t>(0));
}
diff --git a/cpp/watchdog/server/tests/UidCpuStatsCollectorTest.cpp b/cpp/watchdog/server/tests/UidCpuStatsCollectorTest.cpp
new file mode 100644
index 0000000..5b4a12a
--- /dev/null
+++ b/cpp/watchdog/server/tests/UidCpuStatsCollectorTest.cpp
@@ -0,0 +1,117 @@
+/*
+ * Copyright 2022 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 "UidCpuStatsCollector.h"
+
+#include <android-base/file.h>
+#include <android-base/stringprintf.h>
+#include <gmock/gmock.h>
+
+#include <inttypes.h>
+
+#include <unordered_map>
+
+namespace android {
+namespace automotive {
+namespace watchdog {
+
+using ::android::base::StringAppendF;
+using ::android::base::WriteStringToFile;
+using ::testing::UnorderedElementsAreArray;
+
+namespace {
+
+std::string toString(const std::unordered_map<uid_t, int64_t>& cpuTimeMillisByUid) {
+ std::string buffer;
+ for (const auto& [uid, cpuTime] : cpuTimeMillisByUid) {
+ StringAppendF(&buffer, "{%d: %" PRId64 "}\n", uid, cpuTime);
+ }
+ return buffer;
+}
+
+} // namespace
+
+TEST(UidCpuStatsCollectorTest, TestValidStatFile) {
+ // Format: <uid>: <user_time_micro_seconds> <system_time_micro_seconds>
+ constexpr char firstSnapshot[] = "0: 7000000 5000000\n"
+ "100: 1256700 4545636\n"
+ "1009: 500000 500000\n"
+ "1001000: 40000 30000\n";
+ std::unordered_map<uid_t, int64_t> expectedFirstUsage = {{0, 12'000},
+ {100, 5'801},
+ {1009, 1'000},
+ {1001000, 70}};
+
+ TemporaryFile tf;
+ ASSERT_NE(tf.fd, -1);
+ ASSERT_TRUE(WriteStringToFile(firstSnapshot, tf.path));
+
+ UidCpuStatsCollector collector(tf.path);
+ collector.init();
+
+ ASSERT_TRUE(collector.enabled()) << "Temporary file is inaccessible";
+ ASSERT_RESULT_OK(collector.collect());
+
+ const auto& actualFirstUsage = collector.deltaStats();
+ EXPECT_THAT(actualFirstUsage, UnorderedElementsAreArray(expectedFirstUsage))
+ << "Expected: " << toString(expectedFirstUsage)
+ << "Actual: " << toString(actualFirstUsage);
+
+ constexpr char secondSnapshot[] = "0: 7500000 5000000\n"
+ "100: 1266700 4565636\n"
+ "1009: 700000 600000\n"
+ "1001000: 40000 30000\n";
+ std::unordered_map<uid_t, int64_t> expectedSecondUsage = {{0, 500}, {100, 30}, {1009, 300}};
+
+ ASSERT_TRUE(WriteStringToFile(secondSnapshot, tf.path));
+ ASSERT_RESULT_OK(collector.collect());
+
+ const auto& actualSecondUsage = collector.deltaStats();
+ EXPECT_THAT(actualSecondUsage, UnorderedElementsAreArray(expectedSecondUsage))
+ << "Expected: " << toString(expectedSecondUsage)
+ << "Actual: " << toString(actualSecondUsage);
+}
+
+TEST(UidCpuStatsCollectorTest, TestErrorOnInvalidStatFile) {
+ constexpr char contents[] = "0: 7000000 5000000\n"
+ "100: 1256700 4545636\n"
+ "1009: 500000 500000\n"
+ "1001000: CORRUPTED DATA\n";
+ TemporaryFile tf;
+ ASSERT_NE(tf.fd, -1);
+ ASSERT_TRUE(WriteStringToFile(contents, tf.path));
+
+ UidCpuStatsCollector collector(tf.path);
+ collector.init();
+
+ ASSERT_TRUE(collector.enabled()) << "Temporary file is inaccessible";
+ EXPECT_FALSE(collector.collect().ok()) << "No error returned for invalid file";
+}
+
+TEST(UidCpuStatsCollectorTest, TestErrorOnEmptyStatFile) {
+ TemporaryFile tf;
+ ASSERT_NE(tf.fd, -1);
+
+ UidCpuStatsCollector collector(tf.path);
+ collector.init();
+
+ ASSERT_TRUE(collector.enabled()) << "Temporary file is inaccessible";
+ EXPECT_FALSE(collector.collect().ok()) << "No error returned for invalid file";
+}
+
+} // namespace watchdog
+} // namespace automotive
+} // namespace android
diff --git a/cpp/watchdog/server/tests/UidProcStatsCollectorTest.cpp b/cpp/watchdog/server/tests/UidProcStatsCollectorTest.cpp
index 03e89c8..2af010d 100644
--- a/cpp/watchdog/server/tests/UidProcStatsCollectorTest.cpp
+++ b/cpp/watchdog/server/tests/UidProcStatsCollectorTest.cpp
@@ -60,6 +60,10 @@
return buffer;
}
+int64_t ticksToMillis(int32_t clockTicks) {
+ return (clockTicks * 1000) / sysconf(_SC_CLK_TCK);
+}
+
} // namespace
TEST(UidProcStatsCollectorTest, TestValidStatFiles) {
@@ -69,8 +73,8 @@
};
std::unordered_map<pid_t, std::string> perProcessStat = {
- {1, "1 (init) S 0 0 0 0 0 0 0 0 220 0 0 0 0 0 0 0 2 0 0\n"},
- {1000, "1000 (system_server) D 1 0 0 0 0 0 0 0 600 0 0 0 0 0 0 0 2 0 13400\n"},
+ {1, "1 (init) S 0 0 0 0 0 0 0 0 220 0 6 4 0 0 0 0 2 0 19\n"},
+ {1000, "1000 (system_server) D 1 0 0 0 0 0 0 0 600 0 8000 4000 0 0 0 0 2 0 13400\n"},
};
std::unordered_map<pid_t, std::string> perProcessStatus = {
@@ -79,23 +83,29 @@
};
std::unordered_map<pid_t, std::string> perThreadStat = {
- {1, "1 (init) S 0 0 0 0 0 0 0 0 200 0 0 0 0 0 0 0 2 0 0\n"},
- {453, "453 (init) D 0 0 0 0 0 0 0 0 20 0 0 0 0 0 0 0 2 0 275\n"},
- {1000, "1000 (system_server) D 1 0 0 0 0 0 0 0 250 0 0 0 0 0 0 0 2 0 13400\n"},
- {1100, "1100 (system_server) D 1 0 0 0 0 0 0 0 350 0 0 0 0 0 0 0 2 0 13900\n"},
+ {1, "1 (init) S 0 0 0 0 0 0 0 0 200 0 3 2 0 0 0 0 2 0 19\n"},
+ {453, "453 (init) D 0 0 0 0 0 0 0 0 20 0 3 2 0 0 0 0 2 0 275\n"},
+ {1000, "1000 (system_server) D 1 0 0 0 0 0 0 0 250 0 4000 2000 0 0 0 0 2 0 13400\n"},
+ {1100, "1100 (system_server) D 1 0 0 0 0 0 0 0 350 0 4000 2000 0 0 0 0 2 0 13900\n"},
};
std::unordered_map<uid_t, UidProcStats> expected =
{{0,
- UidProcStats{.totalMajorFaults = 220,
+ UidProcStats{.cpuTimeMillis = ticksToMillis(10),
+ .totalMajorFaults = 220,
.totalTasksCount = 2,
.ioBlockedTasksCount = 1,
- .processStatsByPid = {{1, {"init", 0, 220, 2, 1}}}}},
+ .processStatsByPid = {{1,
+ {"init", ticksToMillis(19), ticksToMillis(10),
+ 220, 2, 1}}}}},
{10001234,
- UidProcStats{.totalMajorFaults = 600,
+ UidProcStats{.cpuTimeMillis = ticksToMillis(12'000),
+ .totalMajorFaults = 600,
.totalTasksCount = 2,
.ioBlockedTasksCount = 2,
- .processStatsByPid = {{1000, {"system_server", 13'400, 600, 2, 2}}}}}};
+ .processStatsByPid = {{1000,
+ {"system_server", ticksToMillis(13'400),
+ ticksToMillis(12'000), 600, 2, 2}}}}}};
TemporaryDir firstSnapshot;
ASSERT_RESULT_OK(populateProcPidDir(firstSnapshot.path, pidToTids, perProcessStat,
@@ -114,34 +124,40 @@
<< "First snapshot doesn't match.\nExpected:\n"
<< toString(expected) << "\nActual:\n"
<< toString(actual);
+
pidToTids = {
{1, {1, 453}}, {1000, {1000, 1400}}, // TID 1100 terminated and 1400 instantiated.
};
perProcessStat = {
- {1, "1 (init) S 0 0 0 0 0 0 0 0 920 0 0 0 0 0 0 0 2 0 0\n"},
- {1000, "1000 (system_server) R 1 0 0 0 0 0 0 0 1550 0 0 0 0 0 0 0 2 0 13400\n"},
+ {1, "1 (init) S 0 0 0 0 0 0 0 0 920 0 10 10 0 0 0 0 2 0 19\n"},
+ {1000, "1000 (system_server) R 1 0 0 0 0 0 0 0 1550 0 10000 8000 0 0 0 0 2 0 13400\n"},
};
perThreadStat = {
- {1, "1 (init) S 0 0 0 0 0 0 0 0 600 0 0 0 0 0 0 0 2 0 0\n"},
- {453, "453 (init) S 0 0 0 0 0 0 0 0 320 0 0 0 0 0 0 0 2 0 275\n"},
- {1000, "1000 (system_server) R 1 0 0 0 0 0 0 0 600 0 0 0 0 0 0 0 2 0 13400\n"},
+ {1, "1 (init) S 0 0 0 0 0 0 0 0 600 0 5 5 0 0 0 0 2 0 19\n"},
+ {453, "453 (init) S 0 0 0 0 0 0 0 0 320 0 5 5 0 0 0 0 2 0 275\n"},
+ {1000, "1000 (system_server) R 1 0 0 0 0 0 0 0 600 0 5000 2000 0 0 0 0 2 0 13400\n"},
// TID 1100 hits +400 major page faults before terminating. This is counted against
// PID 1000's perProcessStat.
- {1400, "1400 (system_server) S 1 0 0 0 0 0 0 0 200 0 0 0 0 0 0 0 2 0 8977476\n"},
+ {1400, "1400 (system_server) S 1 0 0 0 0 0 0 0 200 0 5000 2000 0 0 0 0 2 0 8977476\n"},
};
expected = {{0,
- {.totalMajorFaults = 700,
+ {.cpuTimeMillis = ticksToMillis(10),
+ .totalMajorFaults = 700,
.totalTasksCount = 2,
.ioBlockedTasksCount = 0,
- .processStatsByPid = {{1, {"init", 0, 700, 2, 0}}}}},
+ .processStatsByPid =
+ {{1, {"init", ticksToMillis(19), ticksToMillis(10), 700, 2, 0}}}}},
{10001234,
- {.totalMajorFaults = 950,
+ {.cpuTimeMillis = ticksToMillis(6'000),
+ .totalMajorFaults = 950,
.totalTasksCount = 2,
.ioBlockedTasksCount = 0,
- .processStatsByPid = {{1000, {"system_server", 13'400, 950, 2, 0}}}}}};
+ .processStatsByPid = {{1000,
+ {"system_server", ticksToMillis(13'400),
+ ticksToMillis(6'000), 950, 2, 0}}}}}};
TemporaryDir secondSnapshot;
ASSERT_RESULT_OK(populateProcPidDir(secondSnapshot.path, pidToTids, perProcessStat,
@@ -170,11 +186,11 @@
};
std::unordered_map<pid_t, std::string> perProcessStat = {
- {1, "1 (init) S 0 0 0 0 0 0 0 0 220 0 0 0 0 0 0 0 1 0 0\n"},
+ {1, "1 (init) S 0 0 0 0 0 0 0 0 220 0 10 10 0 0 0 0 1 0 19\n"},
// Process 100 terminated.
- {1000, "1000 (system_server) R 1 0 0 0 0 0 0 0 600 0 0 0 0 0 0 0 1 0 1000\n"},
- {2000, "2000 (logd) R 1 0 0 0 0 0 0 0 1200 0 0 0 0 0 0 0 1 0 4567\n"},
- {3000, "3000 (disk I/O) R 1 0 0 0 0 0 0 0 10300 0 0 0 0 0 0 0 2 0 67890\n"},
+ {1000, "1000 (system_server) R 1 0 0 0 0 0 0 0 600 0 20 20 0 0 0 0 1 0 1000\n"},
+ {2000, "2000 (logd) R 1 0 0 0 0 0 0 0 1200 0 30 30 0 0 0 0 1 0 4567\n"},
+ {3000, "3000 (disk I/O) R 1 0 0 0 0 0 0 0 10300 0 40 40 0 0 0 0 2 0 67890\n"},
};
std::unordered_map<pid_t, std::string> perProcessStatus = {
@@ -185,24 +201,32 @@
};
std::unordered_map<pid_t, std::string> perThreadStat = {
- {1, "1 (init) S 0 0 0 0 0 0 0 0 200 0 0 0 0 0 0 0 1 0 0\n"},
+ {1, "1 (init) S 0 0 0 0 0 0 0 0 200 0 10 10 0 0 0 0 1 0 19\n"},
// Process 2000 terminated.
- {3000, "3000 (disk I/O) R 1 0 0 0 0 0 0 0 2400 0 0 0 0 0 0 0 2 0 67890\n"},
+ {3000, "3000 (disk I/O) R 1 0 0 0 0 0 0 0 2400 0 30 30 0 0 0 0 2 0 67890\n"},
// TID 3300 terminated.
};
std::unordered_map<uid_t, UidProcStats> expected =
{{0,
- UidProcStats{.totalMajorFaults = 220,
+ UidProcStats{.cpuTimeMillis = ticksToMillis(20),
+ .totalMajorFaults = 220,
.totalTasksCount = 1,
.ioBlockedTasksCount = 0,
- .processStatsByPid = {{1, {"init", 0, 220, 1, 0}}}}},
+ .processStatsByPid = {{1,
+ {"init", ticksToMillis(19), ticksToMillis(20),
+ 220, 1, 0}}}}},
{10001234,
- UidProcStats{.totalMajorFaults = 11500,
+ UidProcStats{.cpuTimeMillis = ticksToMillis(140),
+ .totalMajorFaults = 11500,
.totalTasksCount = 2,
.ioBlockedTasksCount = 0,
- .processStatsByPid = {{2000, {"logd", 4567, 1200, 1, 0}},
- {3000, {"disk I/O", 67890, 10'300, 1, 0}}}}}};
+ .processStatsByPid = {{2000,
+ {"logd", ticksToMillis(4567), ticksToMillis(60),
+ 1200, 1, 0}},
+ {3000,
+ {"disk I/O", ticksToMillis(67890),
+ ticksToMillis(80), 10'300, 1, 0}}}}}};
TemporaryDir procDir;
ASSERT_RESULT_OK(populateProcPidDir(procDir.path, pidToTids, perProcessStat, perProcessStatus,
@@ -230,9 +254,9 @@
};
std::unordered_map<pid_t, std::string> perProcessStat = {
- {1, "1 (init) S 0 0 0 0 0 0 0 0 1200 0 0 0 0 0 0 0 4 0 0\n"},
- {1000, "1000 (system_server) R 1 0 0 0 0 0 0 0 250 0 0 0 0 0 0 0 1 0 1000\n"},
- {2345, "2345 (logd) R 1 0 0 0 0 0 0 0 54354 0 0 0 0 0 0 0 1 0 456\n"},
+ {1, "1 (init) S 0 0 0 0 0 0 0 0 1200 0 40 40 0 0 0 0 4 0 19\n"},
+ {1000, "1000 (system_server) R 1 0 0 0 0 0 0 0 250 0 10 10 0 0 0 0 1 0 1000\n"},
+ {2345, "2345 (logd) R 1 0 0 0 0 0 0 0 54354 0 10 10 0 0 0 0 1 0 456\n"},
};
std::unordered_map<pid_t, std::string> perProcessStatus = {
@@ -242,26 +266,34 @@
};
std::unordered_map<pid_t, std::string> perThreadStat = {
- {1, "1 (init) S 0 0 0 0 0 0 0 0 200 0 0 0 0 0 0 0 4 0 0\n"},
- {367, "367 (init) S 0 0 0 0 0 0 0 0 400 0 0 0 0 0 0 0 4 0 100\n"},
- {453, "453 (init) S 0 0 0 0 0 0 0 0 100 0 0 0 0 0 0 0 4 0 275\n"},
- {589, "589 (init) D 0 0 0 0 0 0 0 0 500 0 0 0 0 0 0 0 4 0 600\n"},
- {1000, "1000 (system_server) R 1 0 0 0 0 0 0 0 250 0 0 0 0 0 0 0 1 0 1000\n"},
- {2345, "2345 (logd) R 1 0 0 0 0 0 0 0 54354 0 0 0 0 0 0 0 1 0 456\n"},
+ {1, "1 (init) S 0 0 0 0 0 0 0 0 200 0 10 10 0 0 0 0 4 0 19\n"},
+ {367, "367 (init) S 0 0 0 0 0 0 0 0 400 0 10 10 0 0 0 0 4 0 100\n"},
+ {453, "453 (init) S 0 0 0 0 0 0 0 0 100 0 10 10 0 0 0 0 4 0 275\n"},
+ {589, "589 (init) D 0 0 0 0 0 0 0 0 500 0 10 10 0 0 0 0 4 0 600\n"},
+ {1000, "1000 (system_server) R 1 0 0 0 0 0 0 0 250 0 10 10 0 0 0 0 1 0 1000\n"},
+ {2345, "2345 (logd) R 1 0 0 0 0 0 0 0 54354 0 10 10 0 0 0 0 1 0 456\n"},
};
std::unordered_map<uid_t, UidProcStats> expected =
{{0,
- UidProcStats{.totalMajorFaults = 1200,
+ UidProcStats{.cpuTimeMillis = ticksToMillis(80),
+ .totalMajorFaults = 1200,
.totalTasksCount = 4,
.ioBlockedTasksCount = 1,
- .processStatsByPid = {{1, {"init", 0, 1200, 4, 1}}}}},
+ .processStatsByPid = {{1,
+ {"init", ticksToMillis(19), ticksToMillis(80),
+ 1200, 4, 1}}}}},
{10001234,
- UidProcStats{.totalMajorFaults = 54'604,
+ UidProcStats{.cpuTimeMillis = ticksToMillis(40),
+ .totalMajorFaults = 54'604,
.totalTasksCount = 2,
.ioBlockedTasksCount = 0,
- .processStatsByPid = {{1000, {"system_server", 1000, 250, 1, 0}},
- {2345, {"logd", 456, 54'354, 1, 0}}}}}};
+ .processStatsByPid = {{1000,
+ {"system_server", ticksToMillis(1000),
+ ticksToMillis(20), 250, 1, 0}},
+ {2345,
+ {"logd", ticksToMillis(456), ticksToMillis(20),
+ 54'354, 1, 0}}}}}};
TemporaryDir firstSnapshot;
ASSERT_RESULT_OK(populateProcPidDir(firstSnapshot.path, pidToTids, perProcessStat,
@@ -289,9 +321,9 @@
};
perProcessStat = {
- {1, "1 (init) S 0 0 0 0 0 0 0 0 1800 0 0 0 0 0 0 0 2 0 0\n"},
- {367, "367 (system_server) R 1 0 0 0 0 0 0 0 100 0 0 0 0 0 0 0 2 0 3450\n"},
- {1000, "1000 (logd) R 1 0 0 0 0 0 0 0 2000 0 0 0 0 0 0 0 2 0 4650\n"},
+ {1, "1 (init) S 0 0 0 0 0 0 0 0 1800 0 60 60 0 0 0 0 2 0 19\n"},
+ {367, "367 (system_server) R 1 0 0 0 0 0 0 0 100 0 30 30 0 0 0 0 2 0 3450\n"},
+ {1000, "1000 (logd) R 1 0 0 0 0 0 0 0 2000 0 20 20 0 0 0 0 2 0 4650\n"},
};
perProcessStatus = {
@@ -301,25 +333,33 @@
};
perThreadStat = {
- {1, "1 (init) S 0 0 0 0 0 0 0 0 500 0 0 0 0 0 0 0 2 0 0\n"},
- {589, "589 (init) S 0 0 0 0 0 0 0 0 300 0 0 0 0 0 0 0 2 0 2345\n"},
- {367, "367 (system_server) R 1 0 0 0 0 0 0 0 50 0 0 0 0 0 0 0 2 0 3450\n"},
- {2000, "2000 (system_server) R 1 0 0 0 0 0 0 0 50 0 0 0 0 0 0 0 2 0 3670\n"},
- {1000, "1000 (logd) R 1 0 0 0 0 0 0 0 200 0 0 0 0 0 0 0 2 0 4650\n"},
- {453, "453 (logd) D 1 0 0 0 0 0 0 0 1800 0 0 0 0 0 0 0 2 0 4770\n"},
+ {1, "1 (init) S 0 0 0 0 0 0 0 0 500 0 20 20 0 0 0 0 2 0 19\n"},
+ {589, "589 (init) S 0 0 0 0 0 0 0 0 300 0 10 10 0 0 0 0 2 0 2345\n"},
+ {367, "367 (system_server) R 1 0 0 0 0 0 0 0 50 0 15 15 0 0 0 0 2 0 3450\n"},
+ {2000, "2000 (system_server) R 1 0 0 0 0 0 0 0 50 0 15 15 0 0 0 0 2 0 3670\n"},
+ {1000, "1000 (logd) R 1 0 0 0 0 0 0 0 200 0 10 10 0 0 0 0 2 0 4650\n"},
+ {453, "453 (logd) D 1 0 0 0 0 0 0 0 1800 0 10 10 0 0 0 0 2 0 4770\n"},
};
expected = {{0,
- UidProcStats{.totalMajorFaults = 600,
+ UidProcStats{.cpuTimeMillis = ticksToMillis(40),
+ .totalMajorFaults = 600,
.totalTasksCount = 2,
.ioBlockedTasksCount = 0,
- .processStatsByPid = {{1, {"init", 0, 600, 2, 0}}}}},
+ .processStatsByPid = {{1,
+ {"init", ticksToMillis(19), ticksToMillis(40),
+ 600, 2, 0}}}}},
{10001234,
- UidProcStats{.totalMajorFaults = 2100,
+ UidProcStats{.cpuTimeMillis = ticksToMillis(100),
+ .totalMajorFaults = 2100,
.totalTasksCount = 4,
.ioBlockedTasksCount = 1,
- .processStatsByPid = {{367, {"system_server", 3450, 100, 2, 0}},
- {1000, {"logd", 4650, 2000, 2, 1}}}}}};
+ .processStatsByPid = {{367,
+ {"system_server", ticksToMillis(3450),
+ ticksToMillis(60), 100, 2, 0}},
+ {1000,
+ {"logd", ticksToMillis(4650),
+ ticksToMillis(40), 2000, 2, 1}}}}}};
TemporaryDir secondSnapshot;
ASSERT_RESULT_OK(populateProcPidDir(secondSnapshot.path, pidToTids, perProcessStat,
@@ -353,7 +393,7 @@
};
std::unordered_map<pid_t, std::string> perThreadStat = {
- {1, "1 (init) S 0 0 0 0 0 0 0 0 200 0 0 0 0 0 0 0 1 0 0\n"},
+ {1, "1 (init) S 0 0 0 0 0 0 0 0 200 0 0 0 0 0 0 0 1 0 19\n"},
};
TemporaryDir procDir;
@@ -374,7 +414,7 @@
};
std::unordered_map<pid_t, std::string> perProcessStat = {
- {1, "1 (init) S 0 0 0 0 0 0 0 0 200 0 0 0 0 0 0 0 1 0 0\n"},
+ {1, "1 (init) S 0 0 0 0 0 0 0 0 200 0 0 0 0 0 0 0 1 0 19\n"},
};
std::unordered_map<pid_t, std::string> perProcessStatus = {
@@ -382,7 +422,7 @@
};
std::unordered_map<pid_t, std::string> perThreadStat = {
- {1, "1 (init) S 0 0 0 0 0 0 0 0 200 0 0 0 0 0 0 0 1 0 0\n"},
+ {1, "1 (init) S 0 0 0 0 0 0 0 0 200 0 0 0 0 0 0 0 1 0 19\n"},
};
TemporaryDir procDir;
@@ -433,7 +473,8 @@
};
std::unordered_map<pid_t, std::string> perProcessStat = {
- {1, "1 (random process name with space) S 0 0 0 0 0 0 0 0 200 0 0 0 0 0 0 0 1 0 0\n"},
+ {1,
+ "1 (random process name with space) S 0 0 0 0 0 0 0 0 200 0 10 10 0 0 0 0 1 0 19\n"},
};
std::unordered_map<pid_t, std::string> perProcessStatus = {
@@ -441,16 +482,20 @@
};
std::unordered_map<pid_t, std::string> perThreadStat = {
- {1, "1 (random process name with space) S 0 0 0 0 0 0 0 0 200 0 0 0 0 0 0 0 1 0 0\n"},
+ {1,
+ "1 (random process name with space) S 0 0 0 0 0 0 0 0 200 0 10 10 0 0 0 0 1 0 19\n"},
};
std::unordered_map<uid_t, UidProcStats> expected = {
{0,
- UidProcStats{.totalMajorFaults = 200,
+ UidProcStats{.cpuTimeMillis = ticksToMillis(20),
+ .totalMajorFaults = 200,
.totalTasksCount = 1,
.ioBlockedTasksCount = 0,
.processStatsByPid = {
- {1, {"random process name with space", 0, 200, 1, 0}}}}}};
+ {1,
+ {"random process name with space", ticksToMillis(19),
+ ticksToMillis(20), 200, 1, 0}}}}}};
TemporaryDir procDir;
ASSERT_RESULT_OK(populateProcPidDir(procDir.path, pidToTids, perProcessStat, perProcessStatus,
diff --git a/cpp/watchdog/server/tests/UidProcStatsCollectorTestUtils.h b/cpp/watchdog/server/tests/UidProcStatsCollectorTestUtils.h
index 6e5a409..dd80928 100644
--- a/cpp/watchdog/server/tests/UidProcStatsCollectorTestUtils.h
+++ b/cpp/watchdog/server/tests/UidProcStatsCollectorTestUtils.h
@@ -28,7 +28,8 @@
MATCHER_P(ProcessStatsEq, expected, "") {
const auto& actual = arg;
return ::testing::Value(actual.comm, ::testing::Eq(expected.comm)) &&
- ::testing::Value(actual.startTime, ::testing::Eq(expected.startTime)) &&
+ ::testing::Value(actual.startTimeMillis, ::testing::Eq(expected.startTimeMillis)) &&
+ ::testing::Value(actual.cpuTimeMillis, ::testing::Eq(expected.cpuTimeMillis)) &&
::testing::Value(actual.totalMajorFaults, ::testing::Eq(expected.totalMajorFaults)) &&
::testing::Value(actual.totalTasksCount, ::testing::Eq(expected.totalTasksCount)) &&
::testing::Value(actual.ioBlockedTasksCount,
@@ -44,7 +45,8 @@
MATCHER_P(UidProcStatsEq, expected, "") {
const auto& actual = arg;
- return ::testing::Value(actual.totalMajorFaults, ::testing::Eq(expected.totalMajorFaults)) &&
+ return ::testing::Value(actual.cpuTimeMillis, ::testing::Eq(expected.cpuTimeMillis)) &&
+ ::testing::Value(actual.totalMajorFaults, ::testing::Eq(expected.totalMajorFaults)) &&
::testing::Value(actual.totalTasksCount, ::testing::Eq(expected.totalTasksCount)) &&
::testing::Value(actual.ioBlockedTasksCount,
::testing::Eq(expected.ioBlockedTasksCount)) &&
diff --git a/cpp/watchdog/server/tests/UidStatsCollectorTest.cpp b/cpp/watchdog/server/tests/UidStatsCollectorTest.cpp
index 8694c89..ad30733 100644
--- a/cpp/watchdog/server/tests/UidStatsCollectorTest.cpp
+++ b/cpp/watchdog/server/tests/UidStatsCollectorTest.cpp
@@ -15,6 +15,7 @@
*/
#include "MockPackageInfoResolver.h"
+#include "MockUidCpuStatsCollector.h"
#include "MockUidIoStatsCollector.h"
#include "MockUidProcStatsCollector.h"
#include "PackageInfoTestUtils.h"
@@ -27,6 +28,8 @@
#include <gmock/gmock.h>
#include <utils/RefBase.h>
+#include <inttypes.h>
+
#include <string>
namespace android {
@@ -52,7 +55,9 @@
namespace {
std::string toString(const UidStats& uidStats) {
- return StringPrintf("UidStats{%s, %s, %s}", uidStats.packageInfo.toString().c_str(),
+ return StringPrintf("UidStats{packageInfo: %s, cpuTimeMillis: %" PRId64
+ ", ioStats: %s, procStats: %s}",
+ uidStats.packageInfo.toString().c_str(), uidStats.cpuTimeMillis,
uidStats.ioStats.toString().c_str(), uidStats.procStats.toString().c_str());
}
@@ -69,6 +74,8 @@
MATCHER_P(UidStatsEq, expected, "") {
return ExplainMatchResult(AllOf(Field("packageInfo", &UidStats::packageInfo,
PackageInfoEq(expected.packageInfo)),
+ Field("cpuTimeMillis", &UidStats::cpuTimeMillis,
+ Eq(expected.cpuTimeMillis)),
Field("ioStats", &UidStats::ioStats, Eq(expected.ioStats)),
Field("procStats", &UidStats::procStats,
UidProcStatsEq(expected.procStats))),
@@ -102,34 +109,45 @@
std::unordered_map<uid_t, UidProcStats> sampleUidProcStatsByUid() {
return {{1001234,
- UidProcStats{.totalMajorFaults = 220,
+ UidProcStats{.cpuTimeMillis = 10,
+ .totalMajorFaults = 220,
.totalTasksCount = 2,
.ioBlockedTasksCount = 1,
- .processStatsByPid = {{1, {"init", 0, 220, 2, 1}}}}},
+ .processStatsByPid = {{1, {"init", 0, 10, 220, 2, 1}}}}},
{1005678,
- UidProcStats{.totalMajorFaults = 600,
+ UidProcStats{.cpuTimeMillis = 43,
+ .totalMajorFaults = 600,
.totalTasksCount = 2,
.ioBlockedTasksCount = 2,
- .processStatsByPid = {{1000, {"system_server", 13'400, 600, 2, 2}}}}}};
+ .processStatsByPid = {
+ {1000, {"system_server", 13'400, 43, 600, 2, 2}}}}}};
+}
+
+std::unordered_map<uid_t, int64_t> sampleUidCpuStatsByUid() {
+ return {{1001234, 15}, {1005678, 43}};
}
std::vector<UidStats> sampleUidStats() {
return {{.packageInfo = constructPackageInfo("system.daemon", 1001234, UidType::NATIVE),
+ .cpuTimeMillis = 15,
.ioStats = UidIoStats{/*fgRdBytes=*/3'000, /*bgRdBytes=*/0, /*fgWrBytes=*/500,
/*bgWrBytes=*/0, /*fgFsync=*/20, /*bgFsync=*/0},
- .procStats = UidProcStats{.totalMajorFaults = 220,
+ .procStats = UidProcStats{.cpuTimeMillis = 10,
+ .totalMajorFaults = 220,
.totalTasksCount = 2,
.ioBlockedTasksCount = 1,
- .processStatsByPid = {{1, {"init", 0, 220, 2, 1}}}}},
+ .processStatsByPid = {{1, {"init", 0, 10, 220, 2, 1}}}}},
{.packageInfo = constructPackageInfo("kitchensink.app", 1005678, UidType::APPLICATION),
+ .cpuTimeMillis = 43,
.ioStats = UidIoStats{/*fgRdBytes=*/30, /*bgRdBytes=*/100, /*fgWrBytes=*/50,
/*bgWrBytes=*/200,
/*fgFsync=*/45, /*bgFsync=*/60},
- .procStats = UidProcStats{.totalMajorFaults = 600,
+ .procStats = UidProcStats{.cpuTimeMillis = 43,
+ .totalMajorFaults = 600,
.totalTasksCount = 2,
.ioBlockedTasksCount = 2,
.processStatsByPid = {
- {1000, {"system_server", 13'400, 600, 2, 2}}}}}};
+ {1000, {"system_server", 13'400, 43, 600, 2, 2}}}}}};
}
} // namespace
@@ -140,18 +158,22 @@
public:
explicit UidStatsCollectorPeer(sp<UidStatsCollector> collector) : mCollector(collector) {}
- void setPackageInfoResolver(sp<PackageInfoResolverInterface> packageInfoResolver) {
+ void setPackageInfoResolver(const sp<PackageInfoResolverInterface>& packageInfoResolver) {
mCollector->mPackageInfoResolver = packageInfoResolver;
}
- void setUidIoStatsCollector(sp<UidIoStatsCollectorInterface> uidIoStatsCollector) {
+ void setUidIoStatsCollector(const sp<UidIoStatsCollectorInterface>& uidIoStatsCollector) {
mCollector->mUidIoStatsCollector = uidIoStatsCollector;
}
- void setUidProcStatsCollector(sp<UidProcStatsCollectorInterface> uidProcStatsCollector) {
+ void setUidProcStatsCollector(const sp<UidProcStatsCollectorInterface>& uidProcStatsCollector) {
mCollector->mUidProcStatsCollector = uidProcStatsCollector;
}
+ void setUidCpuStatsCollector(const sp<UidCpuStatsCollectorInterface>& uidCpuStatsCollector) {
+ mCollector->mUidCpuStatsCollector = uidCpuStatsCollector;
+ }
+
private:
sp<UidStatsCollector> mCollector;
};
@@ -166,9 +188,11 @@
mMockPackageInfoResolver = sp<MockPackageInfoResolver>::make();
mMockUidIoStatsCollector = sp<MockUidIoStatsCollector>::make();
mMockUidProcStatsCollector = sp<MockUidProcStatsCollector>::make();
+ mMockUidCpuStatsCollector = sp<MockUidCpuStatsCollector>::make();
mUidStatsCollectorPeer->setPackageInfoResolver(mMockPackageInfoResolver);
mUidStatsCollectorPeer->setUidIoStatsCollector(mMockUidIoStatsCollector);
mUidStatsCollectorPeer->setUidProcStatsCollector(mMockUidProcStatsCollector);
+ mUidStatsCollectorPeer->setUidCpuStatsCollector(mMockUidCpuStatsCollector);
}
virtual void TearDown() {
@@ -177,6 +201,7 @@
mMockPackageInfoResolver.clear();
mMockUidIoStatsCollector.clear();
mMockUidProcStatsCollector.clear();
+ mMockUidCpuStatsCollector.clear();
}
sp<UidStatsCollector> mUidStatsCollector;
@@ -184,6 +209,7 @@
sp<MockPackageInfoResolver> mMockPackageInfoResolver;
sp<MockUidIoStatsCollector> mMockUidIoStatsCollector;
sp<MockUidProcStatsCollector> mMockUidProcStatsCollector;
+ sp<MockUidCpuStatsCollector> mMockUidCpuStatsCollector;
};
TEST_F(UidStatsCollectorTest, TestInit) {
@@ -233,12 +259,14 @@
const std::unordered_map<uid_t, PackageInfo> packageInfoByUid = samplePackageInfoByUid();
const std::unordered_map<uid_t, UidIoStats> uidIoStatsByUid = sampleUidIoStatsByUid();
const std::unordered_map<uid_t, UidProcStats> uidProcStatsByUid = sampleUidProcStatsByUid();
+ const std::unordered_map<uid_t, int64_t> uidCpuStatsByUid = sampleUidCpuStatsByUid();
EXPECT_CALL(*mMockPackageInfoResolver,
getPackageInfosForUids(UnorderedElementsAre(1001234, 1005678)))
.WillOnce(Return(packageInfoByUid));
EXPECT_CALL(*mMockUidIoStatsCollector, latestStats()).WillOnce(Return(uidIoStatsByUid));
EXPECT_CALL(*mMockUidProcStatsCollector, latestStats()).WillOnce(Return(uidProcStatsByUid));
+ EXPECT_CALL(*mMockUidCpuStatsCollector, latestStats()).WillOnce(Return(uidCpuStatsByUid));
ASSERT_RESULT_OK(mUidStatsCollector->collect());
@@ -259,12 +287,14 @@
const std::unordered_map<uid_t, PackageInfo> packageInfoByUid = samplePackageInfoByUid();
const std::unordered_map<uid_t, UidIoStats> uidIoStatsByUid = sampleUidIoStatsByUid();
const std::unordered_map<uid_t, UidProcStats> uidProcStatsByUid = sampleUidProcStatsByUid();
+ const std::unordered_map<uid_t, int64_t> uidCpuStatsByUid = sampleUidCpuStatsByUid();
EXPECT_CALL(*mMockPackageInfoResolver,
getPackageInfosForUids(UnorderedElementsAre(1001234, 1005678)))
.WillOnce(Return(packageInfoByUid));
EXPECT_CALL(*mMockUidIoStatsCollector, deltaStats()).WillOnce(Return(uidIoStatsByUid));
EXPECT_CALL(*mMockUidProcStatsCollector, deltaStats()).WillOnce(Return(uidProcStatsByUid));
+ EXPECT_CALL(*mMockUidCpuStatsCollector, deltaStats()).WillOnce(Return(uidCpuStatsByUid));
ASSERT_RESULT_OK(mUidStatsCollector->collect());
@@ -286,12 +316,14 @@
std::unordered_map<uid_t, UidIoStats> uidIoStatsByUid = sampleUidIoStatsByUid();
uidIoStatsByUid.erase(1001234);
const std::unordered_map<uid_t, UidProcStats> uidProcStatsByUid = sampleUidProcStatsByUid();
+ const std::unordered_map<uid_t, int64_t> uidCpuStatsByUid = sampleUidCpuStatsByUid();
EXPECT_CALL(*mMockPackageInfoResolver,
getPackageInfosForUids(UnorderedElementsAre(1001234, 1005678)))
.WillOnce(Return(packageInfoByUid));
EXPECT_CALL(*mMockUidIoStatsCollector, deltaStats()).WillOnce(Return(uidIoStatsByUid));
EXPECT_CALL(*mMockUidProcStatsCollector, deltaStats()).WillOnce(Return(uidProcStatsByUid));
+ EXPECT_CALL(*mMockUidCpuStatsCollector, deltaStats()).WillOnce(Return(uidCpuStatsByUid));
ASSERT_RESULT_OK(mUidStatsCollector->collect());
@@ -314,12 +346,14 @@
const std::unordered_map<uid_t, UidIoStats> uidIoStatsByUid = sampleUidIoStatsByUid();
std::unordered_map<uid_t, UidProcStats> uidProcStatsByUid = sampleUidProcStatsByUid();
uidProcStatsByUid.erase(1001234);
+ const std::unordered_map<uid_t, int64_t> uidCpuStatsByUid = sampleUidCpuStatsByUid();
EXPECT_CALL(*mMockPackageInfoResolver,
getPackageInfosForUids(UnorderedElementsAre(1001234, 1005678)))
.WillOnce(Return(packageInfoByUid));
EXPECT_CALL(*mMockUidIoStatsCollector, deltaStats()).WillOnce(Return(uidIoStatsByUid));
EXPECT_CALL(*mMockUidProcStatsCollector, deltaStats()).WillOnce(Return(uidProcStatsByUid));
+ EXPECT_CALL(*mMockUidCpuStatsCollector, deltaStats()).WillOnce(Return(uidCpuStatsByUid));
ASSERT_RESULT_OK(mUidStatsCollector->collect());
@@ -337,9 +371,8 @@
EXPECT_THAT(actual, IsEmpty()) << "Latest UID stats isn't empty.\nActual: " << toString(actual);
}
-TEST_F(UidStatsCollectorTest, TestCollectDeltaStatsWithMissingPackageInfo) {
- std::unordered_map<uid_t, PackageInfo> packageInfoByUid = samplePackageInfoByUid();
- packageInfoByUid.erase(1001234);
+TEST_F(UidStatsCollectorTest, TestCollectDeltaStatsWithMissingUidCpuStats) {
+ const std::unordered_map<uid_t, PackageInfo> packageInfoByUid = samplePackageInfoByUid();
const std::unordered_map<uid_t, UidIoStats> uidIoStatsByUid = sampleUidIoStatsByUid();
const std::unordered_map<uid_t, UidProcStats> uidProcStatsByUid = sampleUidProcStatsByUid();
@@ -352,6 +385,38 @@
ASSERT_RESULT_OK(mUidStatsCollector->collect());
std::vector<UidStats> expected = sampleUidStats();
+ // Since no Uid CPU time was recovered from the /proc/uid_cputime/show_uid_stat file, the
+ // collector will default the UID CPU time to the UidProcStats' CPU time.
+ expected[0].cpuTimeMillis = 10;
+
+ auto actual = mUidStatsCollector->deltaStats();
+
+ EXPECT_THAT(actual, UnorderedElementsAreArray(UidStatsMatchers(expected)))
+ << "Delta UID stats doesn't match.\nExpected: " << toString(expected)
+ << "\nActual: " << toString(actual);
+
+ actual = mUidStatsCollector->latestStats();
+
+ EXPECT_THAT(actual, IsEmpty()) << "Latest UID stats isn't empty.\nActual: " << toString(actual);
+}
+
+TEST_F(UidStatsCollectorTest, TestCollectDeltaStatsWithMissingPackageInfo) {
+ std::unordered_map<uid_t, PackageInfo> packageInfoByUid = samplePackageInfoByUid();
+ packageInfoByUid.erase(1001234);
+ const std::unordered_map<uid_t, UidIoStats> uidIoStatsByUid = sampleUidIoStatsByUid();
+ const std::unordered_map<uid_t, UidProcStats> uidProcStatsByUid = sampleUidProcStatsByUid();
+ const std::unordered_map<uid_t, int64_t> uidCpuStatsByUid = sampleUidCpuStatsByUid();
+
+ EXPECT_CALL(*mMockPackageInfoResolver,
+ getPackageInfosForUids(UnorderedElementsAre(1001234, 1005678)))
+ .WillOnce(Return(packageInfoByUid));
+ EXPECT_CALL(*mMockUidIoStatsCollector, deltaStats()).WillOnce(Return(uidIoStatsByUid));
+ EXPECT_CALL(*mMockUidProcStatsCollector, deltaStats()).WillOnce(Return(uidProcStatsByUid));
+ EXPECT_CALL(*mMockUidCpuStatsCollector, deltaStats()).WillOnce(Return(uidCpuStatsByUid));
+
+ ASSERT_RESULT_OK(mUidStatsCollector->collect());
+
+ std::vector<UidStats> expected = sampleUidStats();
expected[0].packageInfo = constructPackageInfo("", 1001234);
auto actual = mUidStatsCollector->deltaStats();
diff --git a/cpp/watchdog/server/tests/WatchdogInternalHandlerTest.cpp b/cpp/watchdog/server/tests/WatchdogInternalHandlerTest.cpp
index 41da286..cf72613 100644
--- a/cpp/watchdog/server/tests/WatchdogInternalHandlerTest.cpp
+++ b/cpp/watchdog/server/tests/WatchdogInternalHandlerTest.cpp
@@ -18,6 +18,7 @@
#include "MockWatchdogPerfService.h"
#include "MockWatchdogProcessService.h"
#include "MockWatchdogServiceHelper.h"
+#include "ThreadPriorityController.h"
#include "WatchdogBinderMediator.h"
#include "WatchdogInternalHandler.h"
#include "WatchdogServiceHelper.h"
@@ -35,6 +36,8 @@
#include <utils/RefBase.h>
#include <errno.h>
+#include <sched.h>
+#include <unistd.h>
namespace android {
namespace automotive {
@@ -48,6 +51,8 @@
using aawi::PowerCycle;
using aawi::ProcessIdentifier;
using aawi::ResourceOveruseConfiguration;
+using aawi::ThreadPolicyWithPriority;
+using aawi::UserState;
using ::android::sp;
using ::android::String16;
using ::android::base::Result;
@@ -56,6 +61,19 @@
using ::testing::Pointer;
using ::testing::Return;
+class WatchdogInternalHandlerTestPeer final {
+public:
+ explicit WatchdogInternalHandlerTestPeer(WatchdogInternalHandler* handler) :
+ mHandler(handler) {}
+
+ void setThreadPriorityController(std::unique_ptr<ThreadPriorityController> controller) {
+ mHandler->setThreadPriorityController(std::move(controller));
+ }
+
+private:
+ WatchdogInternalHandler* mHandler;
+};
+
namespace {
class MockWatchdogBinderMediator :
@@ -89,6 +107,20 @@
MOCK_METHOD(Status, notifySystemStateChange, (StateType, int32_t, int32_t), (override));
};
+class MockSystemCalls : public ThreadPriorityController::SystemCallsInterface {
+public:
+ MockSystemCalls(int tid, int uid, int pid) {
+ ON_CALL(*this, readPidStatusFileForPid(tid))
+ .WillByDefault(Return(std::make_tuple(uid, pid)));
+ }
+
+ MOCK_METHOD(int, setScheduler, (pid_t tid, int policy, const sched_param* param), (override));
+ MOCK_METHOD(int, getScheduler, (pid_t tid), (override));
+ MOCK_METHOD(int, getParam, (pid_t tid, sched_param* param), (override));
+ MOCK_METHOD((Result<std::tuple<uid_t, pid_t>>), readPidStatusFileForPid, (pid_t pid),
+ (override));
+};
+
class ScopedChangeCallingUid final : public RefBase {
public:
explicit ScopedChangeCallingUid(uid_t uid) {
@@ -115,10 +147,18 @@
pid_t mCallingPid;
};
+MATCHER_P(PriorityEq, priority, "") {
+ return (arg->sched_priority) == priority;
+}
+
} // namespace
class WatchdogInternalHandlerTest : public ::testing::Test {
protected:
+ static constexpr pid_t TEST_PID = 1;
+ static constexpr pid_t TEST_TID = 2;
+ static constexpr uid_t TEST_UID = 3;
+
virtual void SetUp() {
mMockWatchdogProcessService = sp<MockWatchdogProcessService>::make();
mMockWatchdogPerfService = sp<MockWatchdogPerfService>::make();
@@ -130,6 +170,12 @@
mMockWatchdogServiceHelper,
mMockWatchdogProcessService,
mMockWatchdogPerfService, mMockIoOveruseMonitor);
+ WatchdogInternalHandlerTestPeer peer(mWatchdogInternalHandler.get());
+ std::unique_ptr<MockSystemCalls> mockSystemCalls =
+ std::make_unique<MockSystemCalls>(TEST_TID, TEST_UID, TEST_PID);
+ mMockSystemCalls = mockSystemCalls.get();
+ peer.setThreadPriorityController(
+ std::make_unique<ThreadPriorityController>(std::move(mockSystemCalls)));
}
virtual void TearDown() {
mMockWatchdogBinderMediator.clear();
@@ -153,6 +199,7 @@
sp<MockIoOveruseMonitor> mMockIoOveruseMonitor;
sp<WatchdogInternalHandler> mWatchdogInternalHandler;
sp<ScopedChangeCallingUid> mScopedChangeCallingUid;
+ MockSystemCalls* mMockSystemCalls;
};
TEST_F(WatchdogInternalHandlerTest, TestTerminate) {
@@ -385,10 +432,10 @@
ASSERT_TRUE(status.isOk()) << status;
}
-TEST_F(WatchdogInternalHandlerTest, TestNotifyUserStateChangeWithStartedUser) {
+TEST_F(WatchdogInternalHandlerTest, TestOnUserStateChangeWithStartedUser) {
setSystemCallingUid();
aawi::StateType type = aawi::StateType::USER_STATE;
- EXPECT_CALL(*mMockWatchdogProcessService, notifyUserStateChange(234567, /*isStarted=*/true));
+ EXPECT_CALL(*mMockWatchdogProcessService, onUserStateChange(234567, /*isStarted=*/true));
Status status = mWatchdogInternalHandler
->notifySystemStateChange(type, 234567,
static_cast<int32_t>(
@@ -396,10 +443,55 @@
ASSERT_TRUE(status.isOk()) << status;
}
-TEST_F(WatchdogInternalHandlerTest, TestNotifyUserStateChangeWithStoppedUser) {
+TEST_F(WatchdogInternalHandlerTest, TestOnUserStateChangeWithSwitchingUser) {
setSystemCallingUid();
aawi::StateType type = aawi::StateType::USER_STATE;
- EXPECT_CALL(*mMockWatchdogProcessService, notifyUserStateChange(234567, /*isStarted=*/false));
+
+ EXPECT_CALL(*mMockWatchdogPerfService,
+ onUserStateChange(234567, UserState::USER_STATE_SWITCHING));
+
+ auto status = mWatchdogInternalHandler
+ ->notifySystemStateChange(type, 234567,
+ static_cast<int32_t>(
+ UserState::USER_STATE_SWITCHING));
+
+ ASSERT_TRUE(status.isOk()) << status;
+}
+
+TEST_F(WatchdogInternalHandlerTest, TestOnUserStateChangeWithUnlockingUser) {
+ setSystemCallingUid();
+ aawi::StateType type = aawi::StateType::USER_STATE;
+
+ EXPECT_CALL(*mMockWatchdogPerfService,
+ onUserStateChange(234567, UserState::USER_STATE_UNLOCKING));
+
+ auto status = mWatchdogInternalHandler
+ ->notifySystemStateChange(type, 234567,
+ static_cast<int32_t>(
+ UserState::USER_STATE_UNLOCKING));
+
+ ASSERT_TRUE(status.isOk()) << status;
+}
+
+TEST_F(WatchdogInternalHandlerTest, TestOnUserStateChangeWithPostUnlockedUser) {
+ setSystemCallingUid();
+ aawi::StateType type = aawi::StateType::USER_STATE;
+
+ EXPECT_CALL(*mMockWatchdogPerfService,
+ onUserStateChange(234567, UserState::USER_STATE_POST_UNLOCKED));
+
+ auto status = mWatchdogInternalHandler
+ ->notifySystemStateChange(type, 234567,
+ static_cast<int32_t>(
+ UserState::USER_STATE_POST_UNLOCKED));
+
+ ASSERT_TRUE(status.isOk()) << status;
+}
+
+TEST_F(WatchdogInternalHandlerTest, TestOnUserStateChangeWithStoppedUser) {
+ setSystemCallingUid();
+ aawi::StateType type = aawi::StateType::USER_STATE;
+ EXPECT_CALL(*mMockWatchdogProcessService, onUserStateChange(234567, /*isStarted=*/false));
Status status = mWatchdogInternalHandler
->notifySystemStateChange(type, 234567,
static_cast<int32_t>(
@@ -407,7 +499,7 @@
ASSERT_TRUE(status.isOk()) << status;
}
-TEST_F(WatchdogInternalHandlerTest, TestNotifyUserStateChangeWithRemovedUser) {
+TEST_F(WatchdogInternalHandlerTest, TestOnUserStateChangeWithRemovedUser) {
setSystemCallingUid();
aawi::StateType type = aawi::StateType::USER_STATE;
EXPECT_CALL(*mMockIoOveruseMonitor, removeStatsForUser(/*userId=*/234567));
@@ -418,8 +510,8 @@
ASSERT_TRUE(status.isOk()) << status;
}
-TEST_F(WatchdogInternalHandlerTest, TestErrorOnNotifyUserStateChangeWithInvalidArgs) {
- EXPECT_CALL(*mMockWatchdogProcessService, notifyUserStateChange(_, _)).Times(0);
+TEST_F(WatchdogInternalHandlerTest, TestErrorOnOnUserStateChangeWithInvalidArgs) {
+ EXPECT_CALL(*mMockWatchdogProcessService, onUserStateChange(_, _)).Times(0);
aawi::StateType type = aawi::StateType::USER_STATE;
Status status = mWatchdogInternalHandler->notifySystemStateChange(type, 234567, -1);
@@ -509,6 +601,155 @@
ASSERT_FALSE(status.isOk()) << status;
}
+TEST_F(WatchdogInternalHandlerTest, TestSetThreadPriority) {
+ setSystemCallingUid();
+ int policy = SCHED_FIFO;
+ int priority = 1;
+ EXPECT_CALL(*mMockSystemCalls, setScheduler(TEST_TID, policy, PriorityEq(priority)))
+ .WillOnce(Return(0));
+
+ Status status = mWatchdogInternalHandler->setThreadPriority(TEST_PID, TEST_TID, TEST_UID,
+ policy, priority);
+
+ ASSERT_TRUE(status.isOk()) << status;
+}
+
+TEST_F(WatchdogInternalHandlerTest, TestSetThreadPriorityDefaultPolicy) {
+ setSystemCallingUid();
+ int policy = SCHED_OTHER;
+ int setPriority = 1;
+ // Default policy should ignore the provided priority.
+ int expectedPriority = 0;
+ EXPECT_CALL(*mMockSystemCalls, setScheduler(TEST_TID, policy, PriorityEq(expectedPriority)))
+ .WillOnce(Return(0));
+
+ Status status = mWatchdogInternalHandler->setThreadPriority(TEST_PID, TEST_TID, TEST_UID,
+ policy, setPriority);
+
+ ASSERT_TRUE(status.isOk()) << status;
+}
+
+TEST_F(WatchdogInternalHandlerTest, TestSetThreadPriorityInvalidPid) {
+ setSystemCallingUid();
+
+ Status status = mWatchdogInternalHandler->setThreadPriority(TEST_PID + 1, TEST_TID, TEST_UID,
+ SCHED_FIFO, 1);
+
+ EXPECT_FALSE(status.isOk());
+ EXPECT_EQ(status.exceptionCode(), EX_ILLEGAL_STATE);
+}
+
+TEST_F(WatchdogInternalHandlerTest, TestSetThreadPriorityInvalidTid) {
+ setSystemCallingUid();
+
+ Status status = mWatchdogInternalHandler->setThreadPriority(TEST_PID, TEST_TID + 1, TEST_UID,
+ SCHED_FIFO, 1);
+
+ EXPECT_FALSE(status.isOk());
+ EXPECT_EQ(status.exceptionCode(), EX_ILLEGAL_STATE);
+}
+
+TEST_F(WatchdogInternalHandlerTest, TestSetThreadPriorityInvalidUid) {
+ setSystemCallingUid();
+
+ Status status = mWatchdogInternalHandler->setThreadPriority(TEST_PID, TEST_TID, TEST_UID + 1,
+ SCHED_FIFO, 1);
+
+ EXPECT_FALSE(status.isOk());
+ EXPECT_EQ(status.exceptionCode(), EX_ILLEGAL_STATE);
+}
+
+TEST_F(WatchdogInternalHandlerTest, TestSetThreadPriorityInvalidPolicy) {
+ setSystemCallingUid();
+
+ Status status =
+ mWatchdogInternalHandler->setThreadPriority(TEST_PID, TEST_TID, TEST_UID, -1, 1);
+
+ EXPECT_FALSE(status.isOk());
+ EXPECT_EQ(status.exceptionCode(), EX_ILLEGAL_ARGUMENT);
+}
+
+TEST_F(WatchdogInternalHandlerTest, TestSetThreadPriorityInvalidPriority) {
+ setSystemCallingUid();
+
+ Status status = mWatchdogInternalHandler->setThreadPriority(TEST_PID, TEST_TID, TEST_UID,
+ SCHED_FIFO, 0);
+
+ EXPECT_FALSE(status.isOk());
+ EXPECT_EQ(status.exceptionCode(), EX_ILLEGAL_ARGUMENT);
+}
+
+TEST_F(WatchdogInternalHandlerTest, TestSetThreadPriorityFailed) {
+ setSystemCallingUid();
+ int expectedPolicy = SCHED_FIFO;
+ int expectedPriority = 1;
+ EXPECT_CALL(*mMockSystemCalls,
+ setScheduler(TEST_TID, expectedPolicy, PriorityEq(expectedPriority)))
+ .WillOnce(Return(-1));
+
+ Status status = mWatchdogInternalHandler->setThreadPriority(TEST_PID, TEST_TID, TEST_UID,
+ expectedPolicy, expectedPriority);
+
+ EXPECT_FALSE(status.isOk());
+ EXPECT_EQ(status.exceptionCode(), EX_SERVICE_SPECIFIC);
+}
+
+TEST_F(WatchdogInternalHandlerTest, TestGetThreadPriority) {
+ setSystemCallingUid();
+ int expectedPolicy = SCHED_FIFO;
+ int expectedPriority = 1;
+ EXPECT_CALL(*mMockSystemCalls, getScheduler(TEST_TID)).WillOnce(Return(expectedPolicy));
+ EXPECT_CALL(*mMockSystemCalls, getParam(TEST_TID, _))
+ .WillOnce([expectedPriority](pid_t, sched_param* param) {
+ param->sched_priority = expectedPriority;
+ return 0;
+ });
+
+ ThreadPolicyWithPriority actual;
+ Status status =
+ mWatchdogInternalHandler->getThreadPriority(TEST_PID, TEST_TID, TEST_UID, &actual);
+
+ ASSERT_TRUE(status.isOk()) << status;
+ EXPECT_EQ(actual.policy, expectedPolicy);
+ EXPECT_EQ(actual.priority, expectedPriority);
+}
+
+TEST_F(WatchdogInternalHandlerTest, TestGetThreadPriorityInvalidPid) {
+ setSystemCallingUid();
+
+ ThreadPolicyWithPriority actual;
+ Status status =
+ mWatchdogInternalHandler->getThreadPriority(TEST_PID + 1, TEST_TID, TEST_UID, &actual);
+
+ EXPECT_FALSE(status.isOk());
+ EXPECT_EQ(status.exceptionCode(), EX_ILLEGAL_STATE);
+}
+
+TEST_F(WatchdogInternalHandlerTest, TestGetThreadPriorityGetSchedulerFailed) {
+ setSystemCallingUid();
+ EXPECT_CALL(*mMockSystemCalls, getScheduler(TEST_TID)).WillOnce(Return(-1));
+
+ ThreadPolicyWithPriority actual;
+ Status status =
+ mWatchdogInternalHandler->getThreadPriority(TEST_PID, TEST_TID, TEST_UID, &actual);
+
+ EXPECT_FALSE(status.isOk());
+ EXPECT_EQ(status.exceptionCode(), EX_SERVICE_SPECIFIC);
+}
+
+TEST_F(WatchdogInternalHandlerTest, TestGetThreadPriorityGetParamFailed) {
+ setSystemCallingUid();
+ EXPECT_CALL(*mMockSystemCalls, getScheduler(TEST_TID)).WillOnce(Return(0));
+ EXPECT_CALL(*mMockSystemCalls, getParam(TEST_TID, _)).WillOnce(Return(-1));
+
+ ThreadPolicyWithPriority actual;
+ Status status =
+ mWatchdogInternalHandler->getThreadPriority(TEST_PID, TEST_TID, TEST_UID, &actual);
+
+ EXPECT_FALSE(status.isOk());
+ EXPECT_EQ(status.exceptionCode(), EX_SERVICE_SPECIFIC);
+}
+
} // namespace watchdog
} // namespace automotive
} // namespace android
diff --git a/cpp/watchdog/server/tests/WatchdogPerfServiceTest.cpp b/cpp/watchdog/server/tests/WatchdogPerfServiceTest.cpp
index 7eadd54..679e57e 100644
--- a/cpp/watchdog/server/tests/WatchdogPerfServiceTest.cpp
+++ b/cpp/watchdog/server/tests/WatchdogPerfServiceTest.cpp
@@ -25,6 +25,7 @@
#include <WatchdogProperties.sysprop.h>
#include <android-base/file.h>
+#include <android/automotive/watchdog/internal/UserState.h>
#include <gmock/gmock.h>
#include <utils/RefBase.h>
@@ -41,6 +42,7 @@
using ::android::sp;
using ::android::String16;
using ::android::wp;
+using ::android::automotive::watchdog::internal::UserState;
using ::android::automotive::watchdog::testing::LooperStub;
using ::android::base::Error;
using ::android::base::Result;
@@ -53,11 +55,13 @@
using ::testing::StrictMock;
using ::testing::UnorderedElementsAreArray;
-constexpr std::chrono::seconds kTestBoottimeCollectionInterval = 1s;
+constexpr std::chrono::seconds kTestPostSystemEventDuration = 10s;
+constexpr std::chrono::seconds kTestSystemEventCollectionInterval = 1s;
constexpr std::chrono::seconds kTestPeriodicCollectionInterval = 5s;
constexpr std::chrono::seconds kTestCustomCollectionInterval = 3s;
constexpr std::chrono::seconds kTestCustomCollectionDuration = 11s;
constexpr std::chrono::seconds kTestPeriodicMonitorInterval = 2s;
+constexpr std::chrono::seconds kTestUserSwitchTimeout = 15s;
namespace internal {
@@ -79,9 +83,17 @@
void updateIntervals() {
Mutex::Autolock lock(mService->mMutex);
- mService->mBoottimeCollection.interval = kTestBoottimeCollectionInterval;
+ mService->mPostSystemEventDurationNs = kTestPostSystemEventDuration;
+ mService->mBoottimeCollection.interval = kTestSystemEventCollectionInterval;
mService->mPeriodicCollection.interval = kTestPeriodicCollectionInterval;
+ mService->mUserSwitchCollection.interval = kTestSystemEventCollectionInterval;
mService->mPeriodicMonitor.interval = kTestPeriodicMonitorInterval;
+ mService->mUserSwitchTimeoutNs = kTestUserSwitchTimeout;
+ }
+
+ void clearPostSystemEventDuration() {
+ Mutex::Autolock lock(mService->mMutex);
+ mService->mPostSystemEventDurationNs = 0ns;
}
EventType getCurrCollectionEvent() {
@@ -150,11 +162,17 @@
}
void startPeriodicCollection() {
- EXPECT_CALL(*mMockUidStatsCollector, collect()).Times(2);
- EXPECT_CALL(*mMockProcStatCollector, collect()).Times(2);
+ int bootIterations = static_cast<int>(kTestPostSystemEventDuration.count() /
+ kTestSystemEventCollectionInterval.count());
+
+ // Add the boot collection event done during startService()
+ bootIterations += 1;
+
+ EXPECT_CALL(*mMockUidStatsCollector, collect()).Times(bootIterations);
+ EXPECT_CALL(*mMockProcStatCollector, collect()).Times(bootIterations);
EXPECT_CALL(*mMockDataProcessor,
onBoottimeCollection(_, Eq(mMockUidStatsCollector), Eq(mMockProcStatCollector)))
- .Times(2);
+ .Times(bootIterations);
// Make sure the collection event changes from EventType::INIT to
// EventType::BOOT_TIME_COLLECTION.
@@ -163,9 +181,12 @@
// Mark boot complete.
ASSERT_RESULT_OK(mService->onBootFinished());
- // Process |SwitchMessage::END_BOOTTIME_COLLECTION| and switch to periodic collection.
- ASSERT_RESULT_OK(mLooperStub->pollCache());
+ // Poll all post boot-time collections
+ for (int i = 1; i < bootIterations; i++) {
+ ASSERT_RESULT_OK(mLooperStub->pollCache());
+ }
+ // Process |SwitchMessage::END_BOOTTIME_COLLECTION| and switch to periodic collection.
ASSERT_EQ(mServicePeer->getCurrCollectionEvent(), EventType::PERIODIC_COLLECTION)
<< "Invalid collection event";
@@ -215,11 +236,11 @@
ASSERT_FALSE(mService->start().ok())
<< "No error returned when WatchdogPerfService was started more than once";
- ASSERT_TRUE(sysprop::boottimeCollectionInterval().has_value());
+ ASSERT_TRUE(sysprop::systemEventCollectionInterval().has_value());
ASSERT_EQ(std::chrono::duration_cast<std::chrono::seconds>(
mService->mBoottimeCollection.interval)
.count(),
- sysprop::boottimeCollectionInterval().value());
+ sysprop::systemEventCollectionInterval().value());
ASSERT_TRUE(sysprop::periodicCollectionInterval().has_value());
ASSERT_EQ(std::chrono::duration_cast<std::chrono::seconds>(
mService->mPeriodicCollection.interval)
@@ -260,27 +281,43 @@
ASSERT_RESULT_OK(mLooperStub->pollCache());
- ASSERT_EQ(mLooperStub->numSecondsElapsed(), kTestBoottimeCollectionInterval.count())
+ ASSERT_EQ(mLooperStub->numSecondsElapsed(), kTestSystemEventCollectionInterval.count())
<< "Subsequent boot-time collection didn't happen at "
- << kTestBoottimeCollectionInterval.count() << " seconds interval";
+ << kTestSystemEventCollectionInterval.count() << " seconds interval";
ASSERT_EQ(mServicePeer->getCurrCollectionEvent(), EventType::BOOT_TIME_COLLECTION)
<< "Invalid collection event";
ASSERT_NO_FATAL_FAILURE(verifyAndClearExpectations());
- // #3 Last boot-time collection
- EXPECT_CALL(*mMockUidStatsCollector, collect()).Times(1);
- EXPECT_CALL(*mMockProcStatCollector, collect()).Times(1);
+ // #3 Post system event collection - boot-time
+ int maxIterations = static_cast<int>(kTestPostSystemEventDuration.count() /
+ kTestSystemEventCollectionInterval.count());
+
+ EXPECT_CALL(*mMockUidStatsCollector, collect()).Times(maxIterations);
+ EXPECT_CALL(*mMockProcStatCollector, collect()).Times(maxIterations);
EXPECT_CALL(*mMockDataProcessor,
onBoottimeCollection(_, Eq(mMockUidStatsCollector), Eq(mMockProcStatCollector)))
- .Times(1);
+ .Times(maxIterations);
ASSERT_RESULT_OK(mService->onBootFinished());
+ // Poll all post system event collections - boot-time except last
+ for (int i = 0; i < maxIterations - 1; i++) {
+ ASSERT_RESULT_OK(mLooperStub->pollCache());
+
+ ASSERT_EQ(mLooperStub->numSecondsElapsed(), kTestSystemEventCollectionInterval.count())
+ << "Subsequent post boot-time collection didn't happen at "
+ << kTestSystemEventCollectionInterval.count() << " seconds interval";
+ ASSERT_EQ(mServicePeer->getCurrCollectionEvent(), EventType::BOOT_TIME_COLLECTION)
+ << "Invalid collection event";
+ }
+
+ // Poll the last post system event collection - boot-time. The last boot-time collection should
+ // switch to periodic collection.
ASSERT_RESULT_OK(mLooperStub->pollCache());
- ASSERT_EQ(mLooperStub->numSecondsElapsed(), 0)
- << "Last boot-time collection didn't happen immediately after receiving boot complete "
- << "notification";
+ ASSERT_EQ(mLooperStub->numSecondsElapsed(), kTestSystemEventCollectionInterval.count())
+ << "Last boot-time collection didn't happen immediately after sending "
+ << "END_BOOTTIME_COLLECTION message";
ASSERT_EQ(mServicePeer->getCurrCollectionEvent(), EventType::PERIODIC_COLLECTION)
<< "Invalid collection event";
ASSERT_NO_FATAL_FAILURE(verifyAndClearExpectations());
@@ -461,6 +498,61 @@
ASSERT_EQ(mServicePeer->getCurrCollectionEvent(), EventType::TERMINATED);
}
+TEST_F(WatchdogPerfServiceTest, TestBoottimeCollectionWithNoPostSystemEventDuration) {
+ ASSERT_NO_FATAL_FAILURE(startService());
+
+ mServicePeer->clearPostSystemEventDuration();
+
+ // #1 Boot-time collection
+ EXPECT_CALL(*mMockUidStatsCollector, collect()).Times(1);
+ EXPECT_CALL(*mMockProcStatCollector, collect()).Times(1);
+ EXPECT_CALL(*mMockDataProcessor,
+ onBoottimeCollection(_, Eq(mMockUidStatsCollector), Eq(mMockProcStatCollector)))
+ .Times(1);
+
+ ASSERT_RESULT_OK(mLooperStub->pollCache());
+
+ ASSERT_EQ(mLooperStub->numSecondsElapsed(), 0)
+ << "Boot-time collection didn't start immediately";
+ ASSERT_EQ(mServicePeer->getCurrCollectionEvent(), EventType::BOOT_TIME_COLLECTION)
+ << "Invalid collection event";
+ ASSERT_NO_FATAL_FAILURE(verifyAndClearExpectations());
+
+ // #2 Boot-time collection
+ EXPECT_CALL(*mMockUidStatsCollector, collect()).Times(1);
+ EXPECT_CALL(*mMockProcStatCollector, collect()).Times(1);
+ EXPECT_CALL(*mMockDataProcessor,
+ onBoottimeCollection(_, Eq(mMockUidStatsCollector), Eq(mMockProcStatCollector)))
+ .Times(1);
+
+ ASSERT_RESULT_OK(mLooperStub->pollCache());
+
+ ASSERT_EQ(mLooperStub->numSecondsElapsed(), kTestSystemEventCollectionInterval.count())
+ << "Subsequent boot-time collection didn't happen at "
+ << kTestSystemEventCollectionInterval.count() << " seconds interval";
+ ASSERT_EQ(mServicePeer->getCurrCollectionEvent(), EventType::BOOT_TIME_COLLECTION)
+ << "Invalid collection event";
+ ASSERT_NO_FATAL_FAILURE(verifyAndClearExpectations());
+
+ // #3 Last boot-time collection
+ EXPECT_CALL(*mMockUidStatsCollector, collect()).Times(1);
+ EXPECT_CALL(*mMockProcStatCollector, collect()).Times(1);
+ EXPECT_CALL(*mMockDataProcessor,
+ onBoottimeCollection(_, Eq(mMockUidStatsCollector), Eq(mMockProcStatCollector)))
+ .Times(1);
+
+ ASSERT_RESULT_OK(mService->onBootFinished());
+
+ ASSERT_RESULT_OK(mLooperStub->pollCache());
+
+ ASSERT_EQ(mLooperStub->numSecondsElapsed(), 0)
+ << "Last boot-time collection didn't happen immediately after receiving boot complete "
+ << "notification";
+ ASSERT_EQ(mServicePeer->getCurrCollectionEvent(), EventType::PERIODIC_COLLECTION)
+ << "Invalid collection event";
+ ASSERT_NO_FATAL_FAILURE(verifyAndClearExpectations());
+}
+
TEST_F(WatchdogPerfServiceTest, TestCustomCollection) {
ASSERT_NO_FATAL_FAILURE(startService());
@@ -517,6 +609,456 @@
EXPECT_CALL(*mMockDataProcessor, terminate()).Times(1);
}
+TEST_F(WatchdogPerfServiceTest, TestUserSwitchCollection) {
+ ASSERT_NO_FATAL_FAILURE(startService());
+
+ ASSERT_NO_FATAL_FAILURE(startPeriodicCollection());
+
+ userid_t fromUserId = 0;
+ userid_t toUserId = 100;
+
+ // #1 Start user switch collection
+ EXPECT_CALL(*mMockUidStatsCollector, collect()).Times(1);
+ EXPECT_CALL(*mMockProcStatCollector, collect()).Times(1);
+ EXPECT_CALL(*mMockDataProcessor,
+ onUserSwitchCollection(_, Eq(fromUserId), Eq(toUserId), Eq(mMockUidStatsCollector),
+ Eq(mMockProcStatCollector)))
+ .Times(1);
+
+ ASSERT_RESULT_OK(mService->onUserStateChange(100, UserState::USER_STATE_SWITCHING));
+
+ ASSERT_RESULT_OK(mLooperStub->pollCache());
+
+ ASSERT_EQ(mLooperStub->numSecondsElapsed(), 0)
+ << "User switch collection didn't start immediately";
+ ASSERT_EQ(mServicePeer->getCurrCollectionEvent(), EventType::USER_SWITCH_COLLECTION)
+ << "Invalid collection event";
+ ASSERT_NO_FATAL_FAILURE(verifyAndClearExpectations());
+
+ // #2 User switch collection
+ EXPECT_CALL(*mMockUidStatsCollector, collect()).Times(1);
+ EXPECT_CALL(*mMockProcStatCollector, collect()).Times(1);
+ EXPECT_CALL(*mMockDataProcessor,
+ onUserSwitchCollection(_, Eq(fromUserId), Eq(toUserId), Eq(mMockUidStatsCollector),
+ Eq(mMockProcStatCollector)))
+ .Times(1);
+
+ ASSERT_RESULT_OK(mLooperStub->pollCache());
+
+ ASSERT_EQ(mLooperStub->numSecondsElapsed(), kTestSystemEventCollectionInterval.count())
+ << "Subsequent user switch collection didn't happen at "
+ << kTestSystemEventCollectionInterval.count() << " seconds interval";
+ ASSERT_EQ(mServicePeer->getCurrCollectionEvent(), EventType::USER_SWITCH_COLLECTION)
+ << "Invalid collection event";
+ ASSERT_NO_FATAL_FAILURE(verifyAndClearExpectations());
+
+ // #3 Post system event collection - user switch
+ int maxIterations = static_cast<int>(kTestPostSystemEventDuration.count() /
+ kTestSystemEventCollectionInterval.count());
+
+ EXPECT_CALL(*mMockUidStatsCollector, collect()).Times(maxIterations);
+ EXPECT_CALL(*mMockProcStatCollector, collect()).Times(maxIterations);
+ EXPECT_CALL(*mMockDataProcessor,
+ onUserSwitchCollection(_, Eq(fromUserId), Eq(toUserId), Eq(mMockUidStatsCollector),
+ Eq(mMockProcStatCollector)))
+ .Times(maxIterations);
+
+ ASSERT_RESULT_OK(mService->onUserStateChange(100, UserState::USER_STATE_POST_UNLOCKED));
+
+ // Poll all post user switch collections except last
+ for (int i = 0; i < maxIterations - 1; ++i) {
+ ASSERT_RESULT_OK(mLooperStub->pollCache());
+
+ ASSERT_EQ(mLooperStub->numSecondsElapsed(), kTestSystemEventCollectionInterval.count())
+ << "Subsequent post system event collection - user switch didn't happen at "
+ << kTestSystemEventCollectionInterval.count() << " seconds interval";
+ ASSERT_EQ(mServicePeer->getCurrCollectionEvent(), EventType::USER_SWITCH_COLLECTION)
+ << "Invalid collection event";
+ }
+
+ // Poll the last post system event collection - user switch. The last user switch collection
+ // event should switch to periodic collection.
+ ASSERT_RESULT_OK(mLooperStub->pollCache());
+
+ ASSERT_EQ(mLooperStub->numSecondsElapsed(), kTestSystemEventCollectionInterval.count())
+ << "Last user switch collection didn't happen immediately after sending "
+ << "END_USER_SWITCH_COLLECTION message";
+ ASSERT_EQ(mServicePeer->getCurrCollectionEvent(), EventType::PERIODIC_COLLECTION)
+ << "Invalid collection event";
+ ASSERT_NO_FATAL_FAILURE(verifyAndClearExpectations());
+}
+
+TEST_F(WatchdogPerfServiceTest, TestUserSwitchCollectionWithDelayedUnlocking) {
+ ASSERT_NO_FATAL_FAILURE(startService());
+
+ ASSERT_NO_FATAL_FAILURE(startPeriodicCollection());
+
+ userid_t fromUserId = 0;
+ userid_t toUserId = 100;
+
+ // #1 Start user switch collection
+ EXPECT_CALL(*mMockUidStatsCollector, collect()).Times(1);
+ EXPECT_CALL(*mMockProcStatCollector, collect()).Times(1);
+ EXPECT_CALL(*mMockDataProcessor,
+ onUserSwitchCollection(_, Eq(fromUserId), Eq(toUserId), Eq(mMockUidStatsCollector),
+ Eq(mMockProcStatCollector)))
+ .Times(1);
+
+ ASSERT_RESULT_OK(mService->onUserStateChange(100, UserState::USER_STATE_SWITCHING));
+
+ ASSERT_RESULT_OK(mLooperStub->pollCache());
+
+ ASSERT_EQ(mLooperStub->numSecondsElapsed(), 0)
+ << "User switch collection didn't start immediately";
+ ASSERT_EQ(mServicePeer->getCurrCollectionEvent(), EventType::USER_SWITCH_COLLECTION)
+ << "Invalid collection event";
+ ASSERT_NO_FATAL_FAILURE(verifyAndClearExpectations());
+
+ // #2 User switch collections before timeout
+ int maxIterations = static_cast<int>(kTestUserSwitchTimeout.count() /
+ kTestSystemEventCollectionInterval.count());
+
+ EXPECT_CALL(*mMockUidStatsCollector, collect()).Times(maxIterations);
+ EXPECT_CALL(*mMockProcStatCollector, collect()).Times(maxIterations);
+ EXPECT_CALL(*mMockDataProcessor,
+ onUserSwitchCollection(_, Eq(fromUserId), Eq(toUserId), Eq(mMockUidStatsCollector),
+ Eq(mMockProcStatCollector)))
+ .Times(maxIterations);
+
+ // Poll all user switch collections except last
+ for (int i = 0; i < maxIterations - 1; i++) {
+ ASSERT_RESULT_OK(mLooperStub->pollCache());
+
+ ASSERT_EQ(mLooperStub->numSecondsElapsed(), kTestSystemEventCollectionInterval.count())
+ << "Subsequent user switch collection didn't happen at "
+ << kTestSystemEventCollectionInterval.count() << " seconds interval";
+ ASSERT_EQ(mServicePeer->getCurrCollectionEvent(), EventType::USER_SWITCH_COLLECTION)
+ << "Invalid collection event";
+ }
+
+ // Poll the last user switch collection. The last user switch collection event should start
+ // periodic collection.
+ ASSERT_RESULT_OK(mLooperStub->pollCache());
+
+ ASSERT_EQ(mLooperStub->numSecondsElapsed(), kTestSystemEventCollectionInterval.count())
+ << "Last user switch collection didn't happen immediately after sending "
+ << "END_USER_SWITCH_COLLECTION message";
+ ASSERT_EQ(mServicePeer->getCurrCollectionEvent(), EventType::PERIODIC_COLLECTION)
+ << "Invalid collection event";
+ ASSERT_NO_FATAL_FAILURE(verifyAndClearExpectations());
+
+ // #3 Start user switch collection with unlocking signal
+ EXPECT_CALL(*mMockUidStatsCollector, collect()).Times(1);
+ EXPECT_CALL(*mMockProcStatCollector, collect()).Times(1);
+ EXPECT_CALL(*mMockDataProcessor,
+ onUserSwitchCollection(_, Eq(fromUserId), Eq(toUserId), Eq(mMockUidStatsCollector),
+ Eq(mMockProcStatCollector)))
+ .Times(1);
+
+ ASSERT_RESULT_OK(mService->onUserStateChange(100, UserState::USER_STATE_UNLOCKING));
+
+ ASSERT_RESULT_OK(mLooperStub->pollCache());
+
+ ASSERT_EQ(mLooperStub->numSecondsElapsed(), 0)
+ << "User switch collection didn't start immediately";
+ ASSERT_EQ(mServicePeer->getCurrCollectionEvent(), EventType::USER_SWITCH_COLLECTION)
+ << "Invalid collection event";
+ ASSERT_NO_FATAL_FAILURE(verifyAndClearExpectations());
+
+ // #4 User switch collections after unlocking
+ EXPECT_CALL(*mMockUidStatsCollector, collect()).Times(1);
+ EXPECT_CALL(*mMockProcStatCollector, collect()).Times(1);
+ EXPECT_CALL(*mMockDataProcessor,
+ onUserSwitchCollection(_, Eq(fromUserId), Eq(toUserId), Eq(mMockUidStatsCollector),
+ Eq(mMockProcStatCollector)))
+ .Times(1);
+
+ ASSERT_RESULT_OK(mLooperStub->pollCache());
+
+ ASSERT_EQ(mLooperStub->numSecondsElapsed(), kTestSystemEventCollectionInterval.count())
+ << "Subsequent user switch collection didn't happen at "
+ << kTestSystemEventCollectionInterval.count() << " seconds interval";
+ ASSERT_EQ(mServicePeer->getCurrCollectionEvent(), EventType::USER_SWITCH_COLLECTION)
+ << "Invalid collection event";
+ ASSERT_NO_FATAL_FAILURE(verifyAndClearExpectations());
+
+ // #5 Post system event collection - user switch
+ maxIterations = static_cast<int>(kTestPostSystemEventDuration.count() /
+ kTestSystemEventCollectionInterval.count());
+
+ EXPECT_CALL(*mMockUidStatsCollector, collect()).Times(maxIterations);
+ EXPECT_CALL(*mMockProcStatCollector, collect()).Times(maxIterations);
+ EXPECT_CALL(*mMockDataProcessor,
+ onUserSwitchCollection(_, Eq(fromUserId), Eq(toUserId), Eq(mMockUidStatsCollector),
+ Eq(mMockProcStatCollector)))
+ .Times(maxIterations);
+
+ ASSERT_RESULT_OK(mService->onUserStateChange(100, UserState::USER_STATE_POST_UNLOCKED));
+
+ // Poll all post user switch collections except last
+ for (int i = 0; i < maxIterations - 1; ++i) {
+ ASSERT_RESULT_OK(mLooperStub->pollCache());
+
+ ASSERT_EQ(mLooperStub->numSecondsElapsed(), kTestSystemEventCollectionInterval.count())
+ << "Subsequent post user switch collection didn't happen at "
+ << kTestSystemEventCollectionInterval.count() << " seconds interval";
+ ASSERT_EQ(mServicePeer->getCurrCollectionEvent(), EventType::USER_SWITCH_COLLECTION)
+ << "Invalid collection event";
+ }
+
+ // Poll the last post user switch collection
+ ASSERT_RESULT_OK(mLooperStub->pollCache());
+
+ ASSERT_EQ(mLooperStub->numSecondsElapsed(), kTestSystemEventCollectionInterval.count())
+ << "Last user switch collection didn't happen immediately after sending "
+ << "END_USER_SWITCH_COLLECTION message";
+ ASSERT_EQ(mServicePeer->getCurrCollectionEvent(), EventType::PERIODIC_COLLECTION)
+ << "Invalid collection event";
+ ASSERT_NO_FATAL_FAILURE(verifyAndClearExpectations());
+}
+
+TEST_F(WatchdogPerfServiceTest, TestUserSwitchEventDuringUserSwitchCollection) {
+ ASSERT_NO_FATAL_FAILURE(startService());
+
+ ASSERT_NO_FATAL_FAILURE(startPeriodicCollection());
+
+ userid_t fromUserId = 0;
+ userid_t toUserId = 100;
+
+ // #1 Start user switch collection
+ EXPECT_CALL(*mMockUidStatsCollector, collect()).Times(2);
+ EXPECT_CALL(*mMockProcStatCollector, collect()).Times(2);
+ EXPECT_CALL(*mMockDataProcessor,
+ onUserSwitchCollection(_, Eq(fromUserId), Eq(toUserId), Eq(mMockUidStatsCollector),
+ Eq(mMockProcStatCollector)))
+ .Times(2);
+
+ ASSERT_RESULT_OK(mService->onUserStateChange(toUserId, UserState::USER_STATE_SWITCHING));
+
+ ASSERT_RESULT_OK(mLooperStub->pollCache());
+
+ ASSERT_EQ(mLooperStub->numSecondsElapsed(), 0)
+ << "User switch collection didn't start immediately";
+ ASSERT_EQ(mServicePeer->getCurrCollectionEvent(), EventType::USER_SWITCH_COLLECTION)
+ << "Invalid collection event";
+
+ // #2 User switch collection
+ ASSERT_RESULT_OK(mLooperStub->pollCache());
+
+ ASSERT_EQ(mLooperStub->numSecondsElapsed(), kTestSystemEventCollectionInterval.count())
+ << "Subsequent user switch collection didn't happen at "
+ << kTestSystemEventCollectionInterval.count() << " seconds interval";
+ ASSERT_EQ(mServicePeer->getCurrCollectionEvent(), EventType::USER_SWITCH_COLLECTION)
+ << "Invalid collection event";
+ ASSERT_NO_FATAL_FAILURE(verifyAndClearExpectations());
+
+ // #3 Start new user switch collection during prev user switch event
+ userid_t newFromUserId = 100;
+ userid_t newToUserId = 101;
+
+ EXPECT_CALL(*mMockUidStatsCollector, collect()).Times(1);
+ EXPECT_CALL(*mMockProcStatCollector, collect()).Times(1);
+ EXPECT_CALL(*mMockDataProcessor,
+ onUserSwitchCollection(_, Eq(newFromUserId), Eq(newToUserId),
+ Eq(mMockUidStatsCollector), Eq(mMockProcStatCollector)))
+ .Times(1);
+
+ ASSERT_RESULT_OK(mService->onUserStateChange(newToUserId, UserState::USER_STATE_SWITCHING));
+
+ ASSERT_RESULT_OK(mLooperStub->pollCache());
+
+ ASSERT_EQ(mLooperStub->numSecondsElapsed(), 0)
+ << "New user switch collection didn't start immediately";
+ ASSERT_EQ(mServicePeer->getCurrCollectionEvent(), EventType::USER_SWITCH_COLLECTION)
+ << "Invalid collection event";
+ ASSERT_NO_FATAL_FAILURE(verifyAndClearExpectations());
+
+ // #4 New user switch collection
+ EXPECT_CALL(*mMockUidStatsCollector, collect()).Times(1);
+ EXPECT_CALL(*mMockProcStatCollector, collect()).Times(1);
+ EXPECT_CALL(*mMockDataProcessor,
+ onUserSwitchCollection(_, Eq(newFromUserId), Eq(newToUserId),
+ Eq(mMockUidStatsCollector), Eq(mMockProcStatCollector)))
+ .Times(1);
+
+ ASSERT_RESULT_OK(mLooperStub->pollCache());
+
+ ASSERT_EQ(mLooperStub->numSecondsElapsed(), kTestSystemEventCollectionInterval.count())
+ << "Subsequent new user switch collection didn't happen at "
+ << kTestSystemEventCollectionInterval.count() << " seconds interval";
+ ASSERT_EQ(mServicePeer->getCurrCollectionEvent(), EventType::USER_SWITCH_COLLECTION)
+ << "Invalid collection event";
+ ASSERT_NO_FATAL_FAILURE(verifyAndClearExpectations());
+
+ // #5 Post system event collection - new user switch
+ int maxIterations = static_cast<int>(kTestPostSystemEventDuration.count() /
+ kTestSystemEventCollectionInterval.count());
+
+ EXPECT_CALL(*mMockUidStatsCollector, collect()).Times(maxIterations);
+ EXPECT_CALL(*mMockProcStatCollector, collect()).Times(maxIterations);
+ EXPECT_CALL(*mMockDataProcessor,
+ onUserSwitchCollection(_, Eq(newFromUserId), Eq(newToUserId),
+ Eq(mMockUidStatsCollector), Eq(mMockProcStatCollector)))
+ .Times(maxIterations);
+
+ ASSERT_RESULT_OK(mService->onUserStateChange(newToUserId, UserState::USER_STATE_POST_UNLOCKED));
+
+ // Poll all post user switch collections except last
+ for (int i = 0; i < maxIterations - 1; ++i) {
+ ASSERT_RESULT_OK(mLooperStub->pollCache());
+
+ ASSERT_EQ(mLooperStub->numSecondsElapsed(), kTestSystemEventCollectionInterval.count())
+ << "Subsequent post system event collection - new user switch didn't happen at "
+ << kTestSystemEventCollectionInterval.count() << " seconds interval";
+ ASSERT_EQ(mServicePeer->getCurrCollectionEvent(), EventType::USER_SWITCH_COLLECTION)
+ << "Invalid collection event";
+ }
+
+ // Poll the last post system event collection - user switch. The last user switch collection
+ // event should switch to periodic collection.
+ ASSERT_RESULT_OK(mLooperStub->pollCache());
+
+ ASSERT_EQ(mLooperStub->numSecondsElapsed(), kTestSystemEventCollectionInterval.count())
+ << "Last new user switch collection didn't happen immediately after sending "
+ << "END_USER_SWITCH_COLLECTION message";
+ ASSERT_EQ(mServicePeer->getCurrCollectionEvent(), EventType::PERIODIC_COLLECTION)
+ << "Invalid collection event";
+ ASSERT_NO_FATAL_FAILURE(verifyAndClearExpectations());
+}
+
+TEST_F(WatchdogPerfServiceTest, TestUserSwitchCollectionWithTwoTimeouts) {
+ ASSERT_NO_FATAL_FAILURE(startService());
+
+ ASSERT_NO_FATAL_FAILURE(startPeriodicCollection());
+
+ userid_t fromUserId = 0;
+ userid_t toUserId = 100;
+
+ // #1 Start user switch collection
+ EXPECT_CALL(*mMockUidStatsCollector, collect()).Times(1);
+ EXPECT_CALL(*mMockProcStatCollector, collect()).Times(1);
+ EXPECT_CALL(*mMockDataProcessor,
+ onUserSwitchCollection(_, Eq(fromUserId), Eq(toUserId), Eq(mMockUidStatsCollector),
+ Eq(mMockProcStatCollector)))
+ .Times(1);
+
+ ASSERT_RESULT_OK(mService->onUserStateChange(100, UserState::USER_STATE_SWITCHING));
+
+ ASSERT_RESULT_OK(mLooperStub->pollCache());
+
+ ASSERT_EQ(mLooperStub->numSecondsElapsed(), 0)
+ << "User switch collection didn't start immediately";
+ ASSERT_EQ(mServicePeer->getCurrCollectionEvent(), EventType::USER_SWITCH_COLLECTION)
+ << "Invalid collection event";
+ ASSERT_NO_FATAL_FAILURE(verifyAndClearExpectations());
+
+ // #2 User switch collections before timeout
+ int maxIterations = static_cast<int>(kTestUserSwitchTimeout.count() /
+ kTestSystemEventCollectionInterval.count());
+
+ EXPECT_CALL(*mMockUidStatsCollector, collect()).Times(maxIterations);
+ EXPECT_CALL(*mMockProcStatCollector, collect()).Times(maxIterations);
+ EXPECT_CALL(*mMockDataProcessor,
+ onUserSwitchCollection(_, Eq(fromUserId), Eq(toUserId), Eq(mMockUidStatsCollector),
+ Eq(mMockProcStatCollector)))
+ .Times(maxIterations);
+
+ // Poll all user switch collections except last
+ for (int i = 0; i < maxIterations - 1; ++i) {
+ ASSERT_RESULT_OK(mLooperStub->pollCache());
+
+ ASSERT_EQ(mLooperStub->numSecondsElapsed(), kTestSystemEventCollectionInterval.count())
+ << "Subsequent post user switch collection didn't happen at "
+ << kTestSystemEventCollectionInterval.count() << " seconds interval";
+ ASSERT_EQ(mServicePeer->getCurrCollectionEvent(), EventType::USER_SWITCH_COLLECTION)
+ << "Invalid collection event";
+ }
+
+ // Poll the last user switch collection
+ ASSERT_RESULT_OK(mLooperStub->pollCache());
+
+ ASSERT_EQ(mLooperStub->numSecondsElapsed(), kTestSystemEventCollectionInterval.count())
+ << "Last user switch collection didn't happen immediately after sending "
+ << "END_USER_SWITCH_COLLECTION message";
+ ASSERT_EQ(mServicePeer->getCurrCollectionEvent(), EventType::PERIODIC_COLLECTION)
+ << "Invalid collection event";
+ ASSERT_NO_FATAL_FAILURE(verifyAndClearExpectations());
+
+ // #3 Start user switch collection with unlocking signal
+ EXPECT_CALL(*mMockUidStatsCollector, collect()).Times(1);
+ EXPECT_CALL(*mMockProcStatCollector, collect()).Times(1);
+ EXPECT_CALL(*mMockDataProcessor,
+ onUserSwitchCollection(_, Eq(fromUserId), Eq(toUserId), Eq(mMockUidStatsCollector),
+ Eq(mMockProcStatCollector)))
+ .Times(1);
+
+ ASSERT_RESULT_OK(mService->onUserStateChange(100, UserState::USER_STATE_UNLOCKING));
+
+ ASSERT_RESULT_OK(mLooperStub->pollCache());
+
+ ASSERT_EQ(mLooperStub->numSecondsElapsed(), 0)
+ << "User switch collection didn't start immediately";
+ ASSERT_EQ(mServicePeer->getCurrCollectionEvent(), EventType::USER_SWITCH_COLLECTION)
+ << "Invalid collection event";
+ ASSERT_NO_FATAL_FAILURE(verifyAndClearExpectations());
+
+ // #4 User switch collections after unlocking
+ maxIterations = static_cast<int>(kTestUserSwitchTimeout.count() /
+ kTestSystemEventCollectionInterval.count());
+
+ EXPECT_CALL(*mMockUidStatsCollector, collect()).Times(maxIterations);
+ EXPECT_CALL(*mMockProcStatCollector, collect()).Times(maxIterations);
+ EXPECT_CALL(*mMockDataProcessor,
+ onUserSwitchCollection(_, Eq(fromUserId), Eq(toUserId), Eq(mMockUidStatsCollector),
+ Eq(mMockProcStatCollector)))
+ .Times(maxIterations);
+
+ // Poll all post user switch collections except last
+ for (int i = 0; i < maxIterations - 1; ++i) {
+ ASSERT_RESULT_OK(mLooperStub->pollCache());
+
+ ASSERT_EQ(mLooperStub->numSecondsElapsed(), kTestSystemEventCollectionInterval.count())
+ << "Subsequent post user switch collection didn't happen at "
+ << kTestSystemEventCollectionInterval.count() << " seconds interval";
+ ASSERT_EQ(mServicePeer->getCurrCollectionEvent(), EventType::USER_SWITCH_COLLECTION)
+ << "Invalid collection event";
+ }
+
+ // Poll the last post user switch collection
+ ASSERT_RESULT_OK(mLooperStub->pollCache());
+
+ ASSERT_EQ(mLooperStub->numSecondsElapsed(), kTestSystemEventCollectionInterval.count())
+ << "Last user switch collection didn't happen immediately after sending "
+ << "END_USER_SWITCH_COLLECTION message";
+ ASSERT_EQ(mServicePeer->getCurrCollectionEvent(), EventType::PERIODIC_COLLECTION)
+ << "Invalid collection event";
+ ASSERT_NO_FATAL_FAILURE(verifyAndClearExpectations());
+}
+
+TEST_F(WatchdogPerfServiceTest, TestUserSwitchCollectionUserUnlockingWithNoPrevTimeout) {
+ ASSERT_NO_FATAL_FAILURE(startService());
+ ASSERT_NO_FATAL_FAILURE(startPeriodicCollection());
+ ASSERT_NO_FATAL_FAILURE(skipPeriodicMonitorEvents());
+
+ EXPECT_CALL(*mMockUidStatsCollector, collect()).Times(1);
+ EXPECT_CALL(*mMockProcStatCollector, collect()).Times(1);
+ EXPECT_CALL(*mMockDataProcessor,
+ onPeriodicCollection(_, SystemState::NORMAL_MODE, Eq(mMockUidStatsCollector),
+ Eq(mMockProcStatCollector)))
+ .Times(1);
+ EXPECT_CALL(*mMockDataProcessor, onUserSwitchCollection(_, _, _, _, _)).Times(0);
+
+ ASSERT_RESULT_OK(mService->onUserStateChange(100, UserState::USER_STATE_UNLOCKING));
+
+ ASSERT_RESULT_OK(mLooperStub->pollCache());
+
+ ASSERT_EQ(mLooperStub->numSecondsElapsed(), 1)
+ << "First periodic collection didn't happen at 1 second interval";
+ ASSERT_EQ(mServicePeer->getCurrCollectionEvent(), EventType::PERIODIC_COLLECTION)
+ << "Invalid collection event";
+ ASSERT_NO_FATAL_FAILURE(verifyAndClearExpectations());
+}
+
TEST_F(WatchdogPerfServiceTest, TestPeriodicMonitorRequestsCollection) {
ASSERT_NO_FATAL_FAILURE(startService());
diff --git a/cpp/watchdog/server/tests/WatchdogProcessServiceTest.cpp b/cpp/watchdog/server/tests/WatchdogProcessServiceTest.cpp
index 9e96f1d..0e544a8 100644
--- a/cpp/watchdog/server/tests/WatchdogProcessServiceTest.cpp
+++ b/cpp/watchdog/server/tests/WatchdogProcessServiceTest.cpp
@@ -80,7 +80,9 @@
class WatchdogProcessServicePeer final {
public:
explicit WatchdogProcessServicePeer(const sp<WatchdogProcessService>& watchdogProcessService) :
- mWatchdogProcessService(watchdogProcessService) {}
+ mWatchdogProcessService(watchdogProcessService) {
+ mWatchdogProcessService->mGetStartTimeForPidFunc = [](pid_t) -> uint64_t { return 12356; };
+ }
void setVhalService(std::shared_ptr<afav::IVhalClient> service) {
mWatchdogProcessService->mVhalService = service;
diff --git a/cpp/watchdog/server/tests/WatchdogServiceHelperTest.cpp b/cpp/watchdog/server/tests/WatchdogServiceHelperTest.cpp
index 02d8d1a..02ffb22 100644
--- a/cpp/watchdog/server/tests/WatchdogServiceHelperTest.cpp
+++ b/cpp/watchdog/server/tests/WatchdogServiceHelperTest.cpp
@@ -209,25 +209,29 @@
}
TEST_F(WatchdogServiceHelperTest, TestErrorOnRegisterServiceWithBinderDied) {
+ sp<IBinder> binder = static_cast<sp<IBinder>>(mMockCarWatchdogServiceForSystemBinder);
+ EXPECT_CALL(*mMockWatchdogProcessService, registerCarWatchdogService(binder))
+ .WillOnce(Return(Status::ok()));
EXPECT_CALL(*mMockCarWatchdogServiceForSystemBinder, linkToDeath(_, nullptr, 0))
.WillOnce(Return(DEAD_OBJECT));
- EXPECT_CALL(*mMockWatchdogProcessService, registerCarWatchdogService(_)).Times(0);
+ EXPECT_CALL(*mMockWatchdogProcessService, unregisterCarWatchdogService(binder)).Times(1);
ASSERT_FALSE(mWatchdogServiceHelper->registerService(mMockCarWatchdogServiceForSystem).isOk())
<< "Failed to return error on register service with dead binder";
+ ASSERT_EQ(mWatchdogServiceHelperPeer->getCarWatchdogServiceForSystem(), nullptr);
}
TEST_F(WatchdogServiceHelperTest, TestErrorOnRegisterServiceWithWatchdogProcessServiceError) {
sp<IBinder> binder = static_cast<sp<IBinder>>(mMockCarWatchdogServiceForSystemBinder);
- EXPECT_CALL(*mMockCarWatchdogServiceForSystemBinder, linkToDeath(_, nullptr, 0))
- .WillOnce(Return(OK));
+ EXPECT_CALL(*mMockCarWatchdogServiceForSystemBinder, linkToDeath(_, nullptr, 0)).Times(0);
EXPECT_CALL(*mMockCarWatchdogServiceForSystemBinder, unlinkToDeath(_, nullptr, 0, nullptr))
- .WillOnce(Return(OK));
+ .Times(0);
EXPECT_CALL(*mMockWatchdogProcessService, registerCarWatchdogService(binder))
.WillOnce(Return(Status::fromExceptionCode(Status::EX_ILLEGAL_STATE)));
ASSERT_FALSE(mWatchdogServiceHelper->registerService(mMockCarWatchdogServiceForSystem).isOk())
<< "Failed to return error on error from watchdog process service";
+ ASSERT_EQ(mWatchdogServiceHelperPeer->getCarWatchdogServiceForSystem(), nullptr);
}
TEST_F(WatchdogServiceHelperTest, TestUnregisterService) {
diff --git a/data/etc/android.car.cluster.xml b/data/etc/android.car.cluster.xml
index de3acca..191ded5 100644
--- a/data/etc/android.car.cluster.xml
+++ b/data/etc/android.car.cluster.xml
@@ -22,5 +22,6 @@
<permission name="android.permission.WRITE_SECURE_SETTINGS"/>
<permission name="android.car.permission.CAR_ENGINE_DETAILED"/>
<permission name="android.car.permission.CAR_INSTRUMENT_CLUSTER_CONTROL"/>
+ <permission name="android.permission.MEDIA_CONTENT_CONTROL"/>
</privapp-permissions>
</permissions>
diff --git a/data/etc/com.android.car.shell.xml b/data/etc/com.android.car.shell.xml
index b2b6040..5b58628 100644
--- a/data/etc/com.android.car.shell.xml
+++ b/data/etc/com.android.car.shell.xml
@@ -32,6 +32,8 @@
<permission name="android.car.permission.CONTROL_CAR_APP_LAUNCH"/>
<permission name="android.car.permission.CONTROL_CAR_POWER_POLICY"/>
<permission name="android.car.permission.CONTROL_CAR_CLIMATE"/>
+ <permission name="android.car.permission.CONTROL_CAR_DOORS"/>
+ <permission name="android.car.permission.CONTROL_CAR_WINDOWS"/>
<permission name="android.car.permission.CAR_TIRES"/>
<permission name="android.car.permission.READ_CAR_STEERING"/>
<permission name="android.car.permission.REQUEST_CAR_EVS_ACTIVITY" />
@@ -43,5 +45,21 @@
<permission name="android.car.permission.CONTROL_CAR_WATCHDOG_CONFIG" />
<permission name="android.car.permission.USE_CAR_TELEMETRY_SERVICE" />
<permission name="android.car.permission.CONTROL_SHUTDOWN_PROCESS"/>
+ <permission name="android.car.permission.CAR_DYNAMICS_STATE"/>
+ <permission name="android.car.permission.CAR_ENGINE_DETAILED"/>
+ <permission name="android.car.permission.CAR_MILEAGE"/>
+ <permission name="android.car.permission.CAR_TIRES"/>
+ <permission name="android.car.permission.CAR_EXTERIOR_LIGHTS"/>
+ <permission name="android.car.permission.CONTROL_CAR_EXTERIOR_LIGHTS"/>
+ <permission name="android.car.permission.CAR_VENDOR_EXTENSION"/>
+ <permission name="android.car.permission.CONTROL_CAR_ENERGY"/>
+ <permission name="android.car.permission.CONTROL_CAR_ENERGY_PORTS"/>
+ <permission name="android.car.permission.CAR_IDENTIFICATION"/>
+ <permission name="android.car.permission.PRIVILEGED_CAR_INFO"/>
+ <permission name="android.car.permission.MANAGE_THREAD_PRIORITY"/>
+ <permission name="android.car.permission.CONTROL_CAR_SEATS"/>
+ <permission name="android.car.permission.CONTROL_CAR_MIRRORS"/>
+ <permission name="android.car.permission.READ_CAR_INTERIOR_LIGHTS" />
+ <permission name="android.car.permission.CONTROL_CAR_INTERIOR_LIGHTS" />
</privapp-permissions>
</permissions>
diff --git a/data/etc/com.android.carsystemui.xml b/data/etc/com.android.carsystemui.xml
index 6c9103c..a3f845a 100644
--- a/data/etc/com.android.carsystemui.xml
+++ b/data/etc/com.android.carsystemui.xml
@@ -21,6 +21,7 @@
<permission name="android.car.permission.CAR_ENROLL_TRUST"/>
<permission name="android.car.permission.CAR_INSTRUMENT_CLUSTER_CONTROL"/>
<permission name="android.car.permission.CAR_POWER"/>
+ <permission name="android.car.permission.CAR_DRIVING_STATE"/>
<permission name="android.car.permission.CONTROL_CAR_CLIMATE"/>
<permission name="android.car.permission.CONTROL_CAR_EVS_ACTIVITY"/>
<permission name="android.car.permission.MONITOR_CAR_EVS_STATUS"/>
diff --git a/packages/CarActivityResolver/AndroidManifest.xml b/packages/CarActivityResolver/AndroidManifest.xml
index 62b1fb7..e52f63e 100644
--- a/packages/CarActivityResolver/AndroidManifest.xml
+++ b/packages/CarActivityResolver/AndroidManifest.xml
@@ -34,6 +34,9 @@
<!-- To change the preferred activity. -->
<uses-permission android:name="android.permission.SET_PREFERRED_APPLICATIONS" />
+ <!-- Prevent overlay. -->
+ <uses-permission android:name="android.permission.HIDE_OVERLAY_WINDOWS" />
+
<!-- DisplayResolveInfo requires this permission to read a flag that guards delegate chooser
flow. -->
<uses-permission android:name="android.permission.READ_DEVICE_CONFIG" />
diff --git a/packages/CarDeveloperOptions/AndroidManifest.xml b/packages/CarDeveloperOptions/AndroidManifest.xml
index 34d243f..8a98780 100644
--- a/packages/CarDeveloperOptions/AndroidManifest.xml
+++ b/packages/CarDeveloperOptions/AndroidManifest.xml
@@ -860,6 +860,15 @@
</activity>
<activity
+ android:name="com.android.settings.Settings$PrivacyControlsActivity"
+ android:enabled="false"
+ android:exported="false"
+ tools:node="merge"
+ tools:replace="android:exported">
+ <intent-filter tools:node="removeAll"/>
+ </activity>
+
+ <activity
android:name="com.android.settings.security.CredentialStorage"
android:enabled="false"
android:exported="false"
@@ -2481,7 +2490,7 @@
</activity>
<activity
- android:name="com.android.settingslib.qrcode.QrCodeScanModeActivity"
+ android:name="com.android.settings.bluetooth.QrCodeScanModeActivity"
android:enabled="false"
android:exported="false"
tools:node="merge"
diff --git a/packages/CarDeveloperOptions/res/values-v31/themes.xml b/packages/CarDeveloperOptions/res/values-v31/themes.xml
new file mode 100644
index 0000000..07d68c4
--- /dev/null
+++ b/packages/CarDeveloperOptions/res/values-v31/themes.xml
@@ -0,0 +1,21 @@
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<resources>
+ <style name="CollapsingToolbarTitle.Expanded" parent="CollapsingToolbarTitle.Collapsed">
+ <item name="android:textSize">36dp</item>
+ <item name="android:textColor">@*android:color/car_body1</item>
+ </style>
+</resources>
diff --git a/packages/CarDeveloperOptions/res/values/themes.xml b/packages/CarDeveloperOptions/res/values/themes.xml
index 73bf8d8..43887b3 100644
--- a/packages/CarDeveloperOptions/res/values/themes.xml
+++ b/packages/CarDeveloperOptions/res/values/themes.xml
@@ -39,6 +39,16 @@
<item name="buttonBarButtonStyle">@*android:style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog</item>
</style>
+ <style name="Theme.SubSettings" parent="@android:style/Theme.DeviceDefault.NoActionBar">
+ <item name="alertDialogTheme">@style/Theme.AlertDialog</item>
+ <item name="switchBarTheme">@style/ThemeOverlay.SwitchBar.Settings</item>
+ </style>
+
+ <style name="CollapsingToolbarTitle.Expanded" parent="CollapsingToolbarTitle.Collapsed">
+ <item name="android:textSize">36dp</item>
+ <item name="android:textColor">@*android:color/car_body1</item>
+ </style>
+
<style name="MainSwitchText">
<item name="android:textSize">@*android:dimen/car_body4_size</item>
<item name="android:textColor">?android:attr/textColorPrimary</item>
@@ -58,5 +68,4 @@
<style name="CarDeveloperOptionsPreferenceFragment" parent="@style/PreferenceFragment.CarUi">
<item name="android:layout">@layout/preference_list_fragment</item>
</style>
-
</resources>
\ No newline at end of file
diff --git a/packages/CarDeveloperOptions/src/com/android/car/developeroptions/CarDevelopmentSettingsDashboardFragment.java b/packages/CarDeveloperOptions/src/com/android/car/developeroptions/CarDevelopmentSettingsDashboardFragment.java
index d74b8ea..f39b709 100644
--- a/packages/CarDeveloperOptions/src/com/android/car/developeroptions/CarDevelopmentSettingsDashboardFragment.java
+++ b/packages/CarDeveloperOptions/src/com/android/car/developeroptions/CarDevelopmentSettingsDashboardFragment.java
@@ -35,6 +35,7 @@
import com.android.settings.SettingsActivity;
import com.android.settings.development.DevelopmentSettingsDashboardFragment;
import com.android.settingslib.core.AbstractPreferenceController;
+import com.android.settingslib.drawer.CategoryKey;
import java.util.ArrayList;
import java.util.List;
@@ -123,6 +124,13 @@
}
}
+ @Override
+ public String getCategoryKey() {
+ // Manually return the development category here since this class is not present in the
+ // DashboardFragmentRegistry.
+ return CategoryKey.CATEGORY_SYSTEM_DEVELOPMENT;
+ }
+
protected ToolbarController getToolbar() {
return requireToolbar(requireActivity());
}
diff --git a/packages/CarManagedProvisioning/AndroidManifest.xml b/packages/CarManagedProvisioning/AndroidManifest.xml
index 3dab876..837f90c 100644
--- a/packages/CarManagedProvisioning/AndroidManifest.xml
+++ b/packages/CarManagedProvisioning/AndroidManifest.xml
@@ -45,29 +45,25 @@
<activity
android:name=".preprovisioning.terms.CarTermsActivity"
- android:immersive="true"
- android:exported="true">
+ android:immersive="true">
</activity>
<activity
android:name=".provisioning.CarLandingActivity"
- android:immersive="true"
- android:exported="true">
+ android:immersive="true">
</activity>
<activity
android:name=".provisioning.CarProvisioningActivity"
android:excludeFromRecents="true"
android:immersive="true"
- android:launchMode="singleTop"
- android:exported="true">
+ android:launchMode="singleTop">
</activity>
<activity
android:name=".provisioning.CarResetAndReturnDeviceActivity"
android:excludeFromRecents="true"
- android:immersive="true"
- android:exported="true">
+ android:immersive="true">
</activity>
</application>
</manifest>
diff --git a/packages/CarManagedProvisioning/res/values-fa/strings.xml b/packages/CarManagedProvisioning/res/values-fa/strings.xml
index f3c6111..c97c2b3 100644
--- a/packages/CarManagedProvisioning/res/values-fa/strings.xml
+++ b/packages/CarManagedProvisioning/res/values-fa/strings.xml
@@ -41,6 +41,6 @@
<string name="fully_managed_device_provisioning_return_device_subheader" msgid="5809488930429106172">"این خودرو را بازنشانی و به مدیر سازمان برگردانید یا برای ادامه راهاندازی به صفحه قبلی برگردید."</string>
<string name="fully_managed_device_cancel_setup_button" msgid="4113790677940440998">"لغو راهاندازی"</string>
<string name="fully_managed_device_reset_and_return_button" msgid="4951274590516561428">"بازنشانی و برگرداندن"</string>
- <string name="fully_managed_device_provisioning_privacy_title" msgid="4789425994893472324">"اعلان حریم خصوصی"</string>
+ <string name="fully_managed_device_provisioning_privacy_title" msgid="4789425994893472324">"اعلان حریمخصوصی"</string>
<string name="fully_managed_device_provisioning_privacy_body" msgid="5549745709511179391">"ممکن است مدیر سازمان بتواند دادهها و فعالیتتان را در این خودرو ببیند."</string>
</resources>
diff --git a/packages/CarManagedProvisioning/res/values-ky/strings.xml b/packages/CarManagedProvisioning/res/values-ky/strings.xml
index a630645..3992d55 100644
--- a/packages/CarManagedProvisioning/res/values-ky/strings.xml
+++ b/packages/CarManagedProvisioning/res/values-ky/strings.xml
@@ -39,7 +39,7 @@
<string name="fully_managed_device_provisioning_progress_label" msgid="988594700479673633">"Башкарылган унаа жөндөлүүдө"</string>
<string name="fully_managed_device_provisioning_return_device_title" msgid="1578111657911434819">"Жөндөөнү жокко чыгарып, унааны кайтаруу"</string>
<string name="fully_managed_device_provisioning_return_device_subheader" msgid="5809488930429106172">"Унааны баштапкы абалга келтирип, уюмдун башкаруучусуна кайтарыңыз же жөндөй берүү үчүн мурунку экранга кайтыңыз."</string>
- <string name="fully_managed_device_cancel_setup_button" msgid="4113790677940440998">"Токтотуу"</string>
+ <string name="fully_managed_device_cancel_setup_button" msgid="4113790677940440998">"Жөндөөнү токтотуу"</string>
<string name="fully_managed_device_reset_and_return_button" msgid="4951274590516561428">"Баштапкы абалга келтирип, кайтаруу"</string>
<string name="fully_managed_device_provisioning_privacy_title" msgid="4789425994893472324">"Купуялык эскертүүсү"</string>
<string name="fully_managed_device_provisioning_privacy_body" msgid="5549745709511179391">"Уюмдун башкаруучусу бул унаадагы дайын-даректериңизди жана аракеттериңизди көрө алат."</string>
diff --git a/packages/CarManagedProvisioning/res/values-or/strings.xml b/packages/CarManagedProvisioning/res/values-or/strings.xml
index e4b27ec..7eb325b 100644
--- a/packages/CarManagedProvisioning/res/values-or/strings.xml
+++ b/packages/CarManagedProvisioning/res/values-or/strings.xml
@@ -18,15 +18,15 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="brand_screen_header" msgid="4382251935798018352">"ଏହି ଗାଡ଼ିଟି ସଂସ୍ଥାର ଅଟେ"</string>
- <string name="contact_device_provider" msgid="338577979231875837">"ଅଧିକ ଜାଣିବାକୁ, <xliff:g id="IT_ADMIN">%1$s</xliff:g>ଙ୍କ ସହ କଣ୍ଟାକ୍ଟ କରନ୍ତୁ।"</string>
+ <string name="contact_device_provider" msgid="338577979231875837">"ଅଧିକ ଜାଣିବାକୁ, <xliff:g id="IT_ADMIN">%1$s</xliff:g>ଙ୍କ ସହ ଯୋଗାଯୋଗ କରନ୍ତୁ।"</string>
<string name="organization_admin" msgid="6551608903069550652">"ସଂସ୍ଥାର ପରିଚାଳକ"</string>
- <string name="if_questions_contact_admin" msgid="4645510019575736238">"ଯଦି ଆପଣଙ୍କର କିଛି ପ୍ରଶ୍ନ ଅଛି, ତେବେ ସଂସ୍ଥାର ପରିଚାଳକଙ୍କ ସହ କଣ୍ଟାକ୍ଟ କରନ୍ତୁ"</string>
+ <string name="if_questions_contact_admin" msgid="4645510019575736238">"ଯଦି ଆପଣଙ୍କର କିଛି ପ୍ରଶ୍ନ ଅଛି, ତେବେ ସଂସ୍ଥାର ପରିଚାଳକଙ୍କ ସହ ଯୋଗାଯୋଗ କରନ୍ତୁ"</string>
<string name="admin_has_ability_to_monitor_device" msgid="3132155961508293345">"ନେଟୱାର୍କ କାର୍ଯ୍ୟକଳାପ ଏବଂ ଗାଡ଼ିର ଲୋକେସନ ସମେତ, ସେଟିଂସ, କର୍ପୋରେଟ ଆକ୍ସେସ, ଆପ, ଅନୁମତି ଏବଂ ଏହି ଗାଡ଼ି ସହ ସମ୍ବନ୍ଧିତ ଡାଟାକୁ ମନିଟର ଓ ପରିଚାଳନା କରିବାର କ୍ଷମତା ସଂସ୍ଥାର ପରିଚାଳକଙ୍କ ପାଖରେ ଅଛି।<xliff:g id="LINE_BREAK">
-</xliff:g>ସଂସ୍ଥାର ଗୋପନୀୟତା ନୀତିଗୁଡ଼ିକ ସମେତ, ଅଧିକ ସୂଚନା ପାଇଁ ସଂସ୍ଥାର ପରିଚାଳକଙ୍କ ସହ କଣ୍ଟାକ୍ଟ କରନ୍ତୁ।"</string>
- <string name="contact_your_admin_for_more_info" msgid="1419852317652804536">"ସଂସ୍ଥାର ଗୋପନୀୟତା ନୀତିଗୁଡ଼ିକ ସମେତ, ଅଧିକ ସୂଚନା ପାଇଁ ସଂସ୍ଥାର ପରିଚାଳକଙ୍କ ସହ କଣ୍ଟାକ୍ଟ କରନ୍ତୁ।"</string>
+</xliff:g>ସଂସ୍ଥାର ଗୋପନୀୟତା ନୀତିଗୁଡ଼ିକ ସମେତ, ଅଧିକ ସୂଚନା ପାଇଁ ସଂସ୍ଥାର ପରିଚାଳକଙ୍କ ସହ ଯୋଗାଯୋଗ କରନ୍ତୁ।"</string>
+ <string name="contact_your_admin_for_more_info" msgid="1419852317652804536">"ସଂସ୍ଥାର ଗୋପନୀୟତା ନୀତିଗୁଡ଼ିକ ସମେତ, ଅଧିକ ସୂଚନା ପାଇଁ ସଂସ୍ଥାର ପରିଚାଳକଙ୍କ ସହ ଯୋଗାଯୋଗ କରନ୍ତୁ।"</string>
<string name="managed_device_info" msgid="2134697391634083944">"ଏହା ଏକ ପରିଚାଳିତ ଗାଡ଼ି ଅଟେ"</string>
- <string name="contact_your_admin_for_help" msgid="1741496631607502730">"ସହାୟତା ପାଇଁ ସଂସ୍ଥାର ପରିଚାଳକଙ୍କ ସହ କଣ୍ଟାକ୍ଟ କରନ୍ତୁ"</string>
+ <string name="contact_your_admin_for_help" msgid="1741496631607502730">"ସହାୟତା ପାଇଁ ସଂସ୍ଥାର ପରିଚାଳକଙ୍କ ସହ ଯୋଗାଯୋଗ କରନ୍ତୁ"</string>
<string name="fully_managed_device_provisioning_accept_header" msgid="8767138982035307813">"ପରିଚାଳିତ ଗାଡ଼ି ସେଟ ଅପ କରନ୍ତୁ"</string>
<string name="fully_managed_device_provisioning_step_1_header" msgid="8704166635032524345">"ଆପଣଙ୍କ ସଂସ୍ଥାର ଆପଗୁଡ଼ିକୁ ଆକ୍ସେସ କରନ୍ତୁ"</string>
<string name="fully_managed_device_provisioning_step_1_description" msgid="5960961281295355254">"ଇନଫୋଟେନମେଣ୍ଟ ସିଷ୍ଟମ ସେଟ ଅପ କରାଯାଉଛି..."</string>
@@ -37,9 +37,9 @@
<string name="fully_managed_device_with_permission_control_provisioning_summary" msgid="2503568673345133100">"ଆପଣଙ୍କ ୱାର୍କ ଆପଗୁଡ଼ିକୁ ସହଜରେ ଆକ୍ସେସ କରିବା ପାଇଁ ଏହି ଗାଡ଼ିର ଇନଫୋଟେନମେଣ୍ଟ ସିଷ୍ଟମକୁ ବ୍ୟବହାର କରନ୍ତୁ। ଏହି ଗାଡ଼ି ବ୍ୟକ୍ତିଗତ ନୁହେଁ, ତେଣୁ ସଂସ୍ଥାର ପରିଚାଳକ ଆପଣଙ୍କ କାର୍ଯ୍ୟକଳାପ ଏବଂ ଡାଟା ଦେଖିବାକୁ ସକ୍ଷମ ହୋଇପାରନ୍ତି। ସଂସ୍ଥାର ପରିଚାଳକ ମାଇକ୍ରୋଫୋନ ଏବଂ ଲୋକେସନ ଅନୁମତି ପରି ଏହି ଗାଡ଼ିରେ ଥିବା ଆପଗୁଡ଼ିକ ପାଇଁ ଅନୁମତିଗୁଡ଼ିକୁ ମଧ୍ୟ ସେଟ କରିପାରିବେ।"</string>
<string name="fully_managed_device_provisioning_summary" msgid="4323948058344613817">"ଆପଣଙ୍କ ୱାର୍କ ଆପଗୁଡ଼ିକୁ ସହଜରେ ଆକ୍ସେସ କରିବା ପାଇଁ ଏହି ଗାଡ଼ିର ଇନଫୋଟେନମେଣ୍ଟ ସିଷ୍ଟମକୁ ବ୍ୟବହାର କରନ୍ତୁ। ଏହି ଗାଡ଼ି ବ୍ୟକ୍ତିଗତ ନୁହେଁ, ତେଣୁ ସଂସ୍ଥାର ପରିଚାଳକ ଆପଣଙ୍କ ଡାଟା ଏବଂ କାର୍ଯ୍ୟକଳାପ ଦେଖିବାକୁ ସକ୍ଷମ ହୋଇପାରନ୍ତି।"</string>
<string name="fully_managed_device_provisioning_progress_label" msgid="988594700479673633">"ପରିଚାଳିତ ଗାଡ଼ି ସେଟ ଅପ କରାଯାଉଛି"</string>
- <string name="fully_managed_device_provisioning_return_device_title" msgid="1578111657911434819">"ସେଟଅପ କରିବା ବାତିଲ କରି ଗାଡ଼ି ଫେରାନ୍ତୁ"</string>
+ <string name="fully_managed_device_provisioning_return_device_title" msgid="1578111657911434819">"ସେଟଅପ କରିବା ବାତିଲ୍ କରି ଗାଡ଼ି ଫେରାନ୍ତୁ"</string>
<string name="fully_managed_device_provisioning_return_device_subheader" msgid="5809488930429106172">"ଏହି ଗାଡ଼ିକୁ ରିସେଟ କରି ସଂସ୍ଥାର ପରିଚାଳକଙ୍କୁ ଫେରାନ୍ତୁ କିମ୍ବା ସେଟଅପ କରିବା ଜାରି ରଖିବା ପାଇଁ ପୂର୍ବବର୍ତ୍ତୀ ସ୍କ୍ରିନକୁ ଫେରନ୍ତୁ।"</string>
- <string name="fully_managed_device_cancel_setup_button" msgid="4113790677940440998">"ସେଟଅପ୍ ବାତିଲ କରନ୍ତୁ"</string>
+ <string name="fully_managed_device_cancel_setup_button" msgid="4113790677940440998">"ସେଟଅପ୍ ବାତିଲ୍ କରନ୍ତୁ"</string>
<string name="fully_managed_device_reset_and_return_button" msgid="4951274590516561428">"ରିସେଟ କରି ଫେରାନ୍ତୁ"</string>
<string name="fully_managed_device_provisioning_privacy_title" msgid="4789425994893472324">"ଗୋପନୀୟତା ନୋଟିସ"</string>
<string name="fully_managed_device_provisioning_privacy_body" msgid="5549745709511179391">"ସଂସ୍ଥାର ପରିଚାଳକ ଏହି ଗାଡ଼ିରେ ଥିବା ଆପଣଙ୍କ ଡାଟା ଏବଂ କାର୍ଯ୍ୟକଳାପ ଦେଖିବାକୁ ସକ୍ଷମ ହୋଇପାରନ୍ତି।"</string>
diff --git a/packages/CarShell/AndroidManifest.xml b/packages/CarShell/AndroidManifest.xml
index 9e8ff44..abacb85 100644
--- a/packages/CarShell/AndroidManifest.xml
+++ b/packages/CarShell/AndroidManifest.xml
@@ -67,4 +67,24 @@
<uses-permission android:name="android.car.permission.USE_CAR_TELEMETRY_SERVICE" />
<!-- Permission required for CTS test - LocationManagerFineTest -->
<uses-permission android:name="android.permission.LOCATION_BYPASS" />
+ <!-- Permissions required for CTS test - CarPropertyManagerTest -->
+ <uses-permission android:name="android.car.permission.CAR_DYNAMICS_STATE" />
+ <uses-permission android:name="android.car.permission.CAR_ENGINE_DETAILED" />
+ <uses-permission android:name="android.car.permission.CAR_MILEAGE" />
+ <uses-permission android:name="android.car.permission.CAR_TIRES" />
+ <uses-permission android:name="android.car.permission.CAR_EXTERIOR_LIGHTS" />
+ <uses-permission android:name="android.car.permission.CONTROL_CAR_EXTERIOR_LIGHTS" />
+ <uses-permission android:name="android.car.permission.CAR_VENDOR_EXTENSION" />
+ <uses-permission android:name="android.car.permission.CONTROL_CAR_DOORS" />
+ <uses-permission android:name="android.car.permission.CONTROL_CAR_ENERGY" />
+ <uses-permission android:name="android.car.permission.CONTROL_CAR_ENERGY_PORTS" />
+ <uses-permission android:name="android.car.permission.CONTROL_CAR_SEATS" />
+ <uses-permission android:name="android.car.permission.CONTROL_CAR_WINDOWS" />
+ <uses-permission android:name="android.car.permission.CAR_IDENTIFICATION" />
+ <uses-permission android:name="android.car.permission.PRIVILEGED_CAR_INFO" />
+ <uses-permission android:name="android.car.permission.CONTROL_CAR_MIRRORS" />
+ <uses-permission android:name="android.car.permission.READ_CAR_INTERIOR_LIGHTS" />
+ <uses-permission android:name="android.car.permission.CONTROL_CAR_INTERIOR_LIGHTS" />
+ <!-- Permissions required for CTS test - CarPerformanceManagerTest -->
+ <uses-permission android:name="android.car.permission.MANAGE_THREAD_PRIORITY" />
</manifest>
diff --git a/packages/ScriptExecutor/src/JniUtils.cpp b/packages/ScriptExecutor/src/JniUtils.cpp
index 0d3f472..62467f5 100644
--- a/packages/ScriptExecutor/src/JniUtils.cpp
+++ b/packages/ScriptExecutor/src/JniUtils.cpp
@@ -54,6 +54,7 @@
ScopedLocalRef<jclass> stringClass(env, env->FindClass("java/lang/String"));
ScopedLocalRef<jclass> intArrayClass(env, env->FindClass("[I"));
ScopedLocalRef<jclass> longArrayClass(env, env->FindClass("[J"));
+ ScopedLocalRef<jclass> doubleArrayClass(env, env->FindClass("[D"));
ScopedLocalRef<jclass> stringArrayClass(env, env->FindClass("[Ljava/lang/String;"));
// TODO(b/188816922): Handle more types such as float and integer arrays,
// and perhaps nested Bundles.
@@ -105,7 +106,7 @@
lua_createtable(lua, kLength, 0);
jint* rawIntArray = env->GetIntArrayElements(intArray, nullptr);
// Fills in the table at stack idx -2 with key value pairs, where key is a
- // Lua index and value is an integer from the byte array at that index
+ // Lua index and value is an integer from the int array at that index
for (int i = 0; i < kLength; i++) {
// Stack at index -1 is rawIntArray[i] after this push.
lua_pushinteger(lua, rawIntArray[i]);
@@ -123,7 +124,7 @@
lua_createtable(lua, kLength, 0);
jlong* rawLongArray = env->GetLongArrayElements(longArray, nullptr);
// Fills in the table at stack idx -2 with key value pairs, where key is a
- // Lua index and value is an integer from the byte array at that index
+ // Lua index and value is an integer from the long array at that index
for (int i = 0; i < kLength; i++) {
lua_pushinteger(lua, rawLongArray[i]);
lua_rawseti(lua, /* idx= */ -2,
@@ -131,6 +132,22 @@
}
// JNI_ABORT is used because we do not need to copy back elements.
env->ReleaseLongArrayElements(longArray, rawLongArray, JNI_ABORT);
+ } else if (env->IsInstanceOf(value.get(), doubleArrayClass.get())) {
+ jdoubleArray doubleArray = static_cast<jdoubleArray>(value.get());
+ const auto kLength = env->GetArrayLength(doubleArray);
+ // Arrays are represented as a table of sequential elements in Lua.
+ // We are creating a nested table to represent this array. We specify number of elements
+ // in the Java array to preallocate memory accordingly.
+ lua_createtable(lua, kLength, 0);
+ jdouble* rawDoubleArray = env->GetDoubleArrayElements(doubleArray, nullptr);
+ // Fills in the table at stack idx -2 with key value pairs, where key is a
+ // Lua index and value is an double from the double array at that index
+ for (int i = 0; i < kLength; i++) {
+ lua_pushnumber(lua, rawDoubleArray[i]);
+ lua_rawseti(lua, /* idx= */ -2,
+ i + 1); // lua index starts from 1
+ }
+ env->ReleaseDoubleArrayElements(doubleArray, rawDoubleArray, JNI_ABORT);
} else if (env->IsInstanceOf(value.get(), stringArrayClass.get())) {
jobjectArray stringArray = static_cast<jobjectArray>(value.get());
const auto kLength = env->GetArrayLength(stringArray);
diff --git a/packages/ScriptExecutor/tests/unit/src/com/android/car/scriptexecutortest/unit/JniUtilsTest.java b/packages/ScriptExecutor/tests/unit/src/com/android/car/scriptexecutortest/unit/JniUtilsTest.java
index 7cf8728..7a7404f 100644
--- a/packages/ScriptExecutor/tests/unit/src/com/android/car/scriptexecutortest/unit/JniUtilsTest.java
+++ b/packages/ScriptExecutor/tests/unit/src/com/android/car/scriptexecutortest/unit/JniUtilsTest.java
@@ -37,6 +37,7 @@
private static final String NUMBER_KEY = "number_key";
private static final String INT_ARRAY_KEY = "int_array_key";
private static final String LONG_ARRAY_KEY = "long_array_key";
+ private static final String DOUBLE_ARRAY_KEY = "double_array_key";
private static final boolean BOOLEAN_VALUE = true;
private static final double NUMBER_VALUE = 0.1;
@@ -44,6 +45,7 @@
private static final String STRING_VALUE = "test";
private static final int[] INT_ARRAY_VALUE = new int[]{1, 2, 3};
private static final long[] LONG_ARRAY_VALUE = new long[]{1, 2, 3, 4};
+ private static final double[] DOUBLE_ARRAY_VALUE = new double[]{1.1d, 2.2d, 3.3d, 4.4d};
// Pointer to Lua Engine instantiated in native space.
private long mLuaEnginePtr = 0;
@@ -91,6 +93,8 @@
private native boolean nativeHasLongArrayValue(long luaEnginePtr, String key, long[] value);
+ private native boolean nativeHasDoubleArrayValue(long luaEnginePtr, String key, double[] value);
+
@Test
public void pushBundleToLuaTable_nullBundleMakesEmptyLuaTable() {
nativePushBundleToLuaTableCaller(mLuaEnginePtr, null);
@@ -136,6 +140,7 @@
PersistableBundle bundle = new PersistableBundle();
bundle.putIntArray(INT_ARRAY_KEY, INT_ARRAY_VALUE);
bundle.putLongArray(LONG_ARRAY_KEY, LONG_ARRAY_VALUE);
+ bundle.putDoubleArray(DOUBLE_ARRAY_KEY, DOUBLE_ARRAY_VALUE);
// Invokes the corresponding helper method to convert the bundle
// to Lua table on Lua stack.
@@ -147,5 +152,8 @@
assertThat(nativeHasIntArrayValue(mLuaEnginePtr, INT_ARRAY_KEY, INT_ARRAY_VALUE)).isTrue();
assertThat(
nativeHasLongArrayValue(mLuaEnginePtr, LONG_ARRAY_KEY, LONG_ARRAY_VALUE)).isTrue();
+ assertThat(
+ nativeHasDoubleArrayValue(mLuaEnginePtr, DOUBLE_ARRAY_KEY, DOUBLE_ARRAY_VALUE))
+ .isTrue();
}
}
diff --git a/packages/ScriptExecutor/tests/unit/src/com/android/car/scriptexecutortest/unit/JniUtilsTestHelper.cpp b/packages/ScriptExecutor/tests/unit/src/com/android/car/scriptexecutortest/unit/JniUtilsTestHelper.cpp
index 57fea30..11ae637 100644
--- a/packages/ScriptExecutor/tests/unit/src/com/android/car/scriptexecutortest/unit/JniUtilsTestHelper.cpp
+++ b/packages/ScriptExecutor/tests/unit/src/com/android/car/scriptexecutortest/unit/JniUtilsTestHelper.cpp
@@ -29,8 +29,8 @@
namespace {
template <typename T>
-bool hasIntegerArray(JNIEnv* env, jobject object, jlong luaEnginePtr, jstring key, T rawInputArray,
- const int arrayLength) {
+bool hasValidNumberArray(JNIEnv* env, jobject object, jlong luaEnginePtr, jstring key,
+ T rawInputArray, const int arrayLength, bool checkIsInteger) {
const char* rawKey = env->GetStringUTFChars(key, nullptr);
scriptexecutor::LuaEngine* engine =
reinterpret_cast<scriptexecutor::LuaEngine*>(static_cast<intptr_t>(luaEnginePtr));
@@ -53,9 +53,12 @@
bool is_equal = true;
for (int i = 0; i < arrayLength; ++i) {
lua_rawgeti(luaState, -1, i + 1);
- if (!lua_isinteger(luaState, /* index = */ -1) ||
- (lua_tointeger(luaState, /* index = */ -1) != rawInputArray[i])) {
- is_equal = false;
+ if (checkIsInteger) {
+ is_equal = lua_isinteger(luaState, /* idx = */ -1) &&
+ lua_tointeger(luaState, /* idx = */ -1) == rawInputArray[i];
+ } else {
+ is_equal = lua_isnumber(luaState, /* idx = */ -1) &&
+ lua_tonumber(luaState, /* idx = */ -1) == rawInputArray[i];
}
lua_pop(luaState, 1);
if (!is_equal) break;
@@ -189,7 +192,8 @@
JNIEnv* env, jobject object, jlong luaEnginePtr, jstring key, jintArray value) {
jint* rawInputArray = env->GetIntArrayElements(value, nullptr);
const auto kInputLength = env->GetArrayLength(value);
- bool result = hasIntegerArray(env, object, luaEnginePtr, key, rawInputArray, kInputLength);
+ bool result = hasValidNumberArray(env, object, luaEnginePtr, key, rawInputArray, kInputLength,
+ /* checkIsInteger= */ true);
env->ReleaseIntArrayElements(value, rawInputArray, JNI_ABORT);
return result;
}
@@ -199,11 +203,23 @@
JNIEnv* env, jobject object, jlong luaEnginePtr, jstring key, jlongArray value) {
jlong* rawInputArray = env->GetLongArrayElements(value, nullptr);
const auto kInputLength = env->GetArrayLength(value);
- bool result = hasIntegerArray(env, object, luaEnginePtr, key, rawInputArray, kInputLength);
+ bool result = hasValidNumberArray(env, object, luaEnginePtr, key, rawInputArray, kInputLength,
+ /* checkIsInteger= */ true);
env->ReleaseLongArrayElements(value, rawInputArray, JNI_ABORT);
return result;
}
+JNIEXPORT bool JNICALL
+Java_com_android_car_scriptexecutortest_unit_JniUtilsTest_nativeHasDoubleArrayValue(
+ JNIEnv* env, jobject object, jlong luaEnginePtr, jstring key, jdoubleArray value) {
+ jdouble* rawInputArray = env->GetDoubleArrayElements(value, nullptr);
+ const auto kInputLength = env->GetArrayLength(value);
+ bool result = hasValidNumberArray(env, object, luaEnginePtr, key, rawInputArray, kInputLength,
+ /* checkIsInteger= */ false);
+ env->ReleaseDoubleArrayElements(value, rawInputArray, JNI_ABORT);
+ return result;
+}
+
} // extern "C"
} // namespace
diff --git a/service-builtin/AndroidManifest.xml b/service-builtin/AndroidManifest.xml
index d581770..d599ca4 100644
--- a/service-builtin/AndroidManifest.xml
+++ b/service-builtin/AndroidManifest.xml
@@ -23,7 +23,41 @@
<original-package android:name="com.android.car"/>
<!-- Do not add any new permission here.
- Update ../service/AndroidManifest instead -->
+ Update ../service/AndroidManifest instead (Except signature only permission).
+ Signature only permission should be associated with platform signature, not module
+ signature. -->
+
+ <!-- Must be required by projection service to ensure only system can bind to it.
+ <p>Protection level: signature
+ -->
+ <permission android:name="android.car.permission.BIND_PROJECTION_SERVICE"
+ android:protectionLevel="signature"
+ android:label="@string/car_permission_label_bind_projection_service"
+ android:description="@string/car_permission_desc_bind_projection_service"/>
+
+ <!-- Must be required by VMS client service to ensure only system can bind to it.
+ <p>Protection level: signature
+ -->
+ <permission android:name="android.car.permission.BIND_VMS_CLIENT"
+ android:protectionLevel="signature"
+ android:label="@string/car_permission_label_bind_vms_client"
+ android:description="@string/car_permission_desc_bind_vms_client"/>
+
+ <!-- Must be required by instrument cluster service to ensure only system can bind to it.
+ <p>Protection level: signature
+ -->
+ <permission android:name="android.car.permission.BIND_INSTRUMENT_CLUSTER_RENDERER_SERVICE"
+ android:protectionLevel="signature"
+ android:label="@string/car_permission_label_bind_instrument_cluster_rendering"
+ android:description="@string/car_permission_desc_bind_instrument_cluster_rendering"/>
+
+ <!-- Allows an application to handle the vehicle input events.
+ <p>Protection level: signature
+ -->
+ <permission android:name="android.car.permission.BIND_CAR_INPUT_SERVICE"
+ android:protectionLevel="signature"
+ android:label="@string/car_permission_label_bind_input_service"
+ android:description="@string/car_permission_desc_bind_input_service"/>
<uses-permission android:name="android.permission.CALL_PHONE"/>
<uses-permission android:name="android.permission.DEVICE_POWER"/>
diff --git a/service-builtin/res/values-af/strings.xml b/service-builtin/res/values-af/strings.xml
index c997a06..2caf8d0 100644
--- a/service-builtin/res/values-af/strings.xml
+++ b/service-builtin/res/values-af/strings.xml
@@ -16,6 +16,14 @@
<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_bind_projection_service" msgid="5362076216606651526">"bind aan \'n projeksiediens"</string>
+<string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"Dit laat die houer toe om aan die topvlak-koppelvlak van \'n projeksiediens te bind. Dit behoort nooit vir normale programme nodig te wees nie."</string>
+<string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"VMS-kliëntediens"</string>
+<string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"Bind aan VMS-kliënte"</string>
+<string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"Instrumentgroeplewering"</string>
+<string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"Ontvang instrumentgroepdata"</string>
+<string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Motorinvoerdiens"</string>
+<string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Hanteer invoergebeurtenisse"</string>
<string name="activity_blocked_text" msgid="5991043857905412794">"Jy kan nie hierdie kenmerk gebruik terwyl jy bestuur nie"</string>
<string name="exit_button_message" msgid="5375678491245394542">"Kies <xliff:g id="EXIT_BUTTON">%s</xliff:g> om oor te begin met veilige programkenmerke."</string>
<string name="exit_button" msgid="3491899413031549265">"Terug"</string>
diff --git a/service-builtin/res/values-am/strings.xml b/service-builtin/res/values-am/strings.xml
index 2884d49..7c7daa6 100644
--- a/service-builtin/res/values-am/strings.xml
+++ b/service-builtin/res/values-am/strings.xml
@@ -16,6 +16,14 @@
<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_bind_projection_service" msgid="5362076216606651526">"ለየመላክና ማሳየት አገልግሎት የተወሰነ"</string>
+<string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"ያዡ ግቤት ስልቱን ወደ ከፍተኛ-ደረጃ የመላክና ማሳየት አገልግሎት መጠረዝ ይፈቅዳሉ። ለመደበኛ መተግበሪያዎች በፍፁም አያስፈልግም።"</string>
+<string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"VMS ደንበኛ አገልግሎት"</string>
+<string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"ለ VMS ደንበኞች የተወሰነ"</string>
+<string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"የመሣሪያ ስብስብ አቅርቦት"</string>
+<string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"የመሣሪያ ስብስብ ውሂብን ተቀበል"</string>
+<string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"የመኪና ግቤት አገልግሎት"</string>
+<string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"የግቤት ክስተቶችን ያስተናግዱ"</string>
<string name="activity_blocked_text" msgid="5991043857905412794">"እየነዱ ሳለ ይህን ባህሪ መጠቀም አይችሉም"</string>
<string name="exit_button_message" msgid="5375678491245394542">"ከደህንነት አስተማማኝ የሆኑ የመተግበሪያ ባህሪያት ጋር መልሶ ለመጀመር፣ <xliff:g id="EXIT_BUTTON">%s</xliff:g>ን ይምረጡ።"</string>
<string name="exit_button" msgid="3491899413031549265">"ተመለስ"</string>
diff --git a/service-builtin/res/values-ar/strings.xml b/service-builtin/res/values-ar/strings.xml
index ff4526e..f692315 100644
--- a/service-builtin/res/values-ar/strings.xml
+++ b/service-builtin/res/values-ar/strings.xml
@@ -16,6 +16,14 @@
<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_bind_projection_service" msgid="5362076216606651526">"الالتزام بخدمة عرض"</string>
+<string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"يتيح للمالك الالتزام بواجهة المستوى العلوي لخدمة عرض. لن تكون هناك حاجة إليه مطلقًا مع التطبيقات العادية."</string>
+<string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"خدمة عميل الأجهزة الافتراضية"</string>
+<string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"الالتزام بعملاء الأجهزة الافتراضية"</string>
+<string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"جارٍ عرض مجموعة العدادات"</string>
+<string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"تلقّي بيانات مجموعة الأدوات"</string>
+<string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"خدمة إدخال السيارة"</string>
+<string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"التعامل مع أحداث الإدخال"</string>
<string name="activity_blocked_text" msgid="5991043857905412794">"لا يمكنك استخدام هذه الميزة أثناء القيادة."</string>
<string name="exit_button_message" msgid="5375678491245394542">"للبدء من جديد باستخدام ميزات تطبيق آمنة، اختَر <xliff:g id="EXIT_BUTTON">%s</xliff:g>."</string>
<string name="exit_button" msgid="3491899413031549265">"رجوع"</string>
diff --git a/service-builtin/res/values-as/strings.xml b/service-builtin/res/values-as/strings.xml
index 82279d2..4a92843 100644
--- a/service-builtin/res/values-as/strings.xml
+++ b/service-builtin/res/values-as/strings.xml
@@ -16,6 +16,14 @@
<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_bind_projection_service" msgid="5362076216606651526">"প্ৰজেক্শ্বন সেৱাৰ সৈতে সংযুক্ত হ’ব"</string>
+<string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"এটা প্ৰজেক্শ্বন সেৱাৰ শীৰ্ষ স্তৰৰ ইণ্টাৰফে’চৰ সৈতে সংযুক্ত হ’বলৈ ধাৰকক অনুমতি দিয়ে। সাধাৰণ এপ্সমূহৰ বাবে কেতিয়াও প্ৰয়োজন হ’ব নালাগে।"</string>
+<string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"VMS ক্লায়েণ্ট সেৱা"</string>
+<string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"VMS ক্লায়েণ্টৰ সৈতে সংযুক্ত হ’ব পাৰে"</string>
+<string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"ইনষ্ট্ৰুমেণ্ট ক্লাষ্টাৰ ৰেণ্ডাৰ কৰি থকা হৈছে"</string>
+<string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"ইনষ্ট্ৰুমেণ্ট ক্লাষ্টাৰৰ ডেটা পায়"</string>
+<string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"গাড়ীৰ ইনপুট সেৱা"</string>
+<string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"ইনপুট ইভেণ্ট নিয়ন্ত্ৰণ কৰিব"</string>
<string name="activity_blocked_text" msgid="5991043857905412794">"আপুনি গাড়ী চলাই থকাৰ সময়ত এই সুবিধাটো ব্যৱহাৰ কৰিব নোৱাৰে"</string>
<string name="exit_button_message" msgid="5375678491245394542">"সুৰক্ষিত এপ্ সুবিধাসহ আকৌ আৰম্ভ কৰিবলৈ <xliff:g id="EXIT_BUTTON">%s</xliff:g> বাছনি কৰক।"</string>
<string name="exit_button" msgid="3491899413031549265">"উভতি যাওক"</string>
diff --git a/service-builtin/res/values-az/strings.xml b/service-builtin/res/values-az/strings.xml
index c2e4581..01b9fa5 100644
--- a/service-builtin/res/values-az/strings.xml
+++ b/service-builtin/res/values-az/strings.xml
@@ -16,6 +16,14 @@
<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_bind_projection_service" msgid="5362076216606651526">"proyeksiya xidmətinə bağlanmaq"</string>
+<string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"Sahibin proyeksiya xidmətinin yuxarı səviyyəli interfeysinə bağlanmasına icazə verir. Normal tətbiqlər üçün heç vaxt tələb olunmur."</string>
+<string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"VMS Müştəri Xidməti"</string>
+<string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"VMS müştərilərinə bağlanmaq"</string>
+<string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"Alət Klasterinin Təchizatı"</string>
+<string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"Alət klasteri məlumatlarını almaq"</string>
+<string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Avtomobil Daxiletmə Xidməti"</string>
+<string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Daxiletmələri idarə etmək"</string>
<string name="activity_blocked_text" msgid="5991043857905412794">"Avtomobil sürərkən bu funksiyanı istifadə edə bilməzsiniz"</string>
<string name="exit_button_message" msgid="5375678491245394542">"Təhlükəsiz tətbiq xüsusiyyətləri ilə başlamaq üçün <xliff:g id="EXIT_BUTTON">%s</xliff:g> seçin."</string>
<string name="exit_button" msgid="3491899413031549265">"Geri"</string>
diff --git a/service-builtin/res/values-b+sr+Latn/strings.xml b/service-builtin/res/values-b+sr+Latn/strings.xml
index f2bf5fd..16e37d6 100644
--- a/service-builtin/res/values-b+sr+Latn/strings.xml
+++ b/service-builtin/res/values-b+sr+Latn/strings.xml
@@ -16,6 +16,14 @@
<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_bind_projection_service" msgid="5362076216606651526">"povezivanje sa uslugom projekcije"</string>
+<string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"Dozvoljava vlasniku da se poveže sa interfejsom usluge projekcije najvišeg nivoa. Uobičajene aplikacije nikada ne bi trebalo da je koriste."</string>
+<string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"VMS usluga za klijente"</string>
+<string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"Povezuje sa VMS klijentima"</string>
+<string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"Prikazivanje na instrument tabli"</string>
+<string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"Prima podatke sa instrument table"</string>
+<string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Usluga automobilskog unosa"</string>
+<string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Upravlja događajima unosa"</string>
<string name="activity_blocked_text" msgid="5991043857905412794">"Ne možete da koristite ovu funkciju dok vozite"</string>
<string name="exit_button_message" msgid="5375678491245394542">"Da biste ponovo počeli sa bezbednim funkcijama aplikacije, izaberite <xliff:g id="EXIT_BUTTON">%s</xliff:g>."</string>
<string name="exit_button" msgid="3491899413031549265">"Nazad"</string>
diff --git a/service-builtin/res/values-be/strings.xml b/service-builtin/res/values-be/strings.xml
index f925381..04d43d1 100644
--- a/service-builtin/res/values-be/strings.xml
+++ b/service-builtin/res/values-be/strings.xml
@@ -16,6 +16,14 @@
<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_bind_projection_service" msgid="5362076216606651526">"звязваць з сэрвісам трансляцыі"</string>
+<string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"Дазваляе ўладальніку звязвацца з інтэрфейсам службы трансляцыі вышэйшага ўзроўню. Не патрэбна для звычайных праграм."</string>
+<string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"Служба кліента VMS"</string>
+<string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"Звязвацца з кліентамі VMS"</string>
+<string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"Візуалізацыя на прыборнай панэлі"</string>
+<string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"Магчымасць атрымліваць даныя з прыборнай панэлі"</string>
+<string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Сэрвіс уводу аўтамабіля"</string>
+<string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Магчымасць апрацоўваць падзеі ўводу"</string>
<string name="activity_blocked_text" msgid="5991043857905412794">"Вам нельга выкарыстоўваць гэту функцыю, калі вы ведзяце аўтамабіль"</string>
<string name="exit_button_message" msgid="5375678491245394542">"Каб перазапусціць праграму ў бяспечным рэжыме, націсніце кнопку \"<xliff:g id="EXIT_BUTTON">%s</xliff:g>\"."</string>
<string name="exit_button" msgid="3491899413031549265">"Назад"</string>
diff --git a/service-builtin/res/values-bg/strings.xml b/service-builtin/res/values-bg/strings.xml
index 0290a2e..bff75a1 100644
--- a/service-builtin/res/values-bg/strings.xml
+++ b/service-builtin/res/values-bg/strings.xml
@@ -16,6 +16,14 @@
<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_bind_projection_service" msgid="5362076216606651526">"обвързване с услуга за прожектиране"</string>
+<string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"Разрешава на притежателя да се обвърже с интерфейса от най-високото ниво на услуга за прожектиране. Нормалните приложения би трябвало никога да не се нуждаят от това."</string>
+<string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"Клиентска услуга за VMS"</string>
+<string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"Обвързване с клиентски програми за VMS"</string>
+<string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"Изобразяване в арматурното табло"</string>
+<string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"Получаване на данни за арматурното табло"</string>
+<string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Автомобилна услуга за входящи данни"</string>
+<string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Обработване на входящи събития"</string>
<string name="activity_blocked_text" msgid="5991043857905412794">"Не можете да използвате тази функция по време на шофиране"</string>
<string name="exit_button_message" msgid="5375678491245394542">"За да рестартирате приложението и безопасните му функции, изберете „<xliff:g id="EXIT_BUTTON">%s</xliff:g>“."</string>
<string name="exit_button" msgid="3491899413031549265">"Назад"</string>
diff --git a/service-builtin/res/values-bn/strings.xml b/service-builtin/res/values-bn/strings.xml
index 947cdfc..32c2ed5 100644
--- a/service-builtin/res/values-bn/strings.xml
+++ b/service-builtin/res/values-bn/strings.xml
@@ -16,6 +16,14 @@
<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_bind_projection_service" msgid="5362076216606651526">"প্রোজেকশন পরিষেবার সাথে যুক্ত হওয়া"</string>
+<string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"হোল্ডারকে একটি প্রোজেকশন পরিষেবার উচ্চ মানের ইন্টারফেসে যুক্ত হতে অনুমতি দেয়। সধারণ অ্যাপের ক্ষেত্রে কখনই প্রয়োজন হয় না।"</string>
+<string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"VMS ক্লায়েন্ট পরিষেবা"</string>
+<string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"VMS ক্লায়েন্টের সাথে যুক্ত হন"</string>
+<string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"ইনস্ট্রুমেন্ট ক্লাস্টার রেন্ডার করা"</string>
+<string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"ইনস্ট্রুমেন্ট ক্লাস্টার ডেটা পান"</string>
+<string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"গাড়ির ইনপুট সার্ভিস"</string>
+<string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"ইনপুট ইভেন্ট হ্যান্ডেল করা"</string>
<string name="activity_blocked_text" msgid="5991043857905412794">"ড্রাইভ করার সময় আপনি এই ফিচারটি ব্যবহার করতে পারবেন না"</string>
<string name="exit_button_message" msgid="5375678491245394542">"অ্যাপের সুরক্ষিত ফিচারগুলি নিয়ে আবার শুরু করতে, <xliff:g id="EXIT_BUTTON">%s</xliff:g> বেছে নিন।"</string>
<string name="exit_button" msgid="3491899413031549265">"আবার চালু করুন"</string>
diff --git a/service-builtin/res/values-bs/strings.xml b/service-builtin/res/values-bs/strings.xml
index 07876c2..1236026 100644
--- a/service-builtin/res/values-bs/strings.xml
+++ b/service-builtin/res/values-bs/strings.xml
@@ -16,6 +16,14 @@
<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_bind_projection_service" msgid="5362076216606651526">"vezati za uslugu projiciranja"</string>
+<string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"Dozvoljava vlasniku povezivanje s interfejsom najvišeg nivoa usluge za projiciranje. Nije potrebno za obične aplikacije."</string>
+<string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"VMS usluga klijenta"</string>
+<string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"Vezati za VMS klijenta"</string>
+<string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"Iscrtavanje na kontrolnoj tabli"</string>
+<string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"Primite podatke s kontrolne ploče"</string>
+<string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Usluga unosa za automobil"</string>
+<string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Rukovati događajima unosa"</string>
<string name="activity_blocked_text" msgid="5991043857905412794">"Ne možete koristiti ovu funkciju tokom vožnje"</string>
<string name="exit_button_message" msgid="5375678491245394542">"Da počnete ponovo s funkcijama sigurne aplikacije, odaberite <xliff:g id="EXIT_BUTTON">%s</xliff:g>."</string>
<string name="exit_button" msgid="3491899413031549265">"Nazad"</string>
diff --git a/service-builtin/res/values-ca/strings.xml b/service-builtin/res/values-ca/strings.xml
index a627305..4984a1c 100644
--- a/service-builtin/res/values-ca/strings.xml
+++ b/service-builtin/res/values-ca/strings.xml
@@ -16,6 +16,14 @@
<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_bind_projection_service" msgid="5362076216606651526">"vincula a un servei de projecció"</string>
+<string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"Permet que el titular vinculi a la interfície de nivell superior d\'un servei de projecció. No s\'hauria de necessitar mai per a les aplicacions normals"</string>
+<string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"Servei de client de VMS"</string>
+<string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"Vincular a clients de VMS"</string>
+<string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"Renderització del quadre de comandament"</string>
+<string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"Rebre dades del quadre de comandament"</string>
+<string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Servei d\'entrada del cotxe"</string>
+<string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Gestionar els esdeveniments d\'entrada"</string>
<string name="activity_blocked_text" msgid="5991043857905412794">"No pots fer servir aquesta funció mentre condueixes"</string>
<string name="exit_button_message" msgid="5375678491245394542">"Per tornar a començar amb unes funcions d\'aplicació segures, selecciona <xliff:g id="EXIT_BUTTON">%s</xliff:g>."</string>
<string name="exit_button" msgid="3491899413031549265">"Enrere"</string>
diff --git a/service-builtin/res/values-cs/strings.xml b/service-builtin/res/values-cs/strings.xml
index b12e7af..826c6aa 100644
--- a/service-builtin/res/values-cs/strings.xml
+++ b/service-builtin/res/values-cs/strings.xml
@@ -16,6 +16,14 @@
<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_bind_projection_service" msgid="5362076216606651526">"vazba na promítací službu"</string>
+<string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"Umožňuje držiteli navázat se na nejvyšší úroveň promítací služby. Běžné aplikace by toto oprávnění neměly nikdy požadovat."</string>
+<string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"Klientská služba VMS"</string>
+<string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"Vazba na klienty VMS"</string>
+<string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"Vykreslování na přístrojové desce"</string>
+<string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"Přijímat údaje z přístrojové desky"</string>
+<string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Služba vstupu auta"</string>
+<string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Zpracování vstupních událostí"</string>
<string name="activity_blocked_text" msgid="5991043857905412794">"Tuto funkci nelze používat při řízení"</string>
<string name="exit_button_message" msgid="5375678491245394542">"Chcete-li začít znovu s bezpečnými funkcemi aplikace, vyberte <xliff:g id="EXIT_BUTTON">%s</xliff:g>."</string>
<string name="exit_button" msgid="3491899413031549265">"Zpět"</string>
diff --git a/service-builtin/res/values-da/strings.xml b/service-builtin/res/values-da/strings.xml
index 51e7f35..554fe07 100644
--- a/service-builtin/res/values-da/strings.xml
+++ b/service-builtin/res/values-da/strings.xml
@@ -16,6 +16,14 @@
<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_bind_projection_service" msgid="5362076216606651526">"oprette tilknytning til en projiceringstjeneste"</string>
+<string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"Tillader, at indehaveren opretter en tilknytning til det øverste niveau af grænsefladen i en projiceringstjeneste. Dette bør aldrig være nødvendigt for almindelige apps."</string>
+<string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"VMS-klientservice"</string>
+<string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"Oprette tilknytning til VMS-klienter"</string>
+<string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"Gengivelse af instrumentbrættet"</string>
+<string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"Modtag instrumentbrætdata"</string>
+<string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Bilens inputservice"</string>
+<string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Håndter input"</string>
<string name="activity_blocked_text" msgid="5991043857905412794">"Du kan ikke bruge denne funktion, mens du kører"</string>
<string name="exit_button_message" msgid="5375678491245394542">"Vælg <xliff:g id="EXIT_BUTTON">%s</xliff:g> for at starte forfra med sikre appfunktioner."</string>
<string name="exit_button" msgid="3491899413031549265">"Tilbage"</string>
diff --git a/service-builtin/res/values-de/strings.xml b/service-builtin/res/values-de/strings.xml
index 24a6f10..07e1c88 100644
--- a/service-builtin/res/values-de/strings.xml
+++ b/service-builtin/res/values-de/strings.xml
@@ -16,6 +16,14 @@
<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_bind_projection_service" msgid="5362076216606651526">"sich an einen Projektionsdienst zu binden"</string>
+<string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"Ermöglicht dem Inhaber, sich an die Oberfläche eines Projektionsdienstes auf oberster Ebene zu binden. Sollte für normale Apps nie benötigt werden."</string>
+<string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"VMS-Clientdienst"</string>
+<string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"An VMS-Clients binden"</string>
+<string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"Kombi-Instrument-Rendering"</string>
+<string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"Daten von Kombi-Instrument erhalten"</string>
+<string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Eingabedienst für das Auto"</string>
+<string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Eingabe-Ereignisse verwalten"</string>
<string name="activity_blocked_text" msgid="5991043857905412794">"Du kannst diese Funktion nicht während der Fahrt nutzen"</string>
<string name="exit_button_message" msgid="5375678491245394542">"Wähle <xliff:g id="EXIT_BUTTON">%s</xliff:g>, um die App mit sicheren Funktionen neu zu starten."</string>
<string name="exit_button" msgid="3491899413031549265">"Zurück"</string>
diff --git a/service-builtin/res/values-el/strings.xml b/service-builtin/res/values-el/strings.xml
index 4a03fa5..2ffc0e9 100644
--- a/service-builtin/res/values-el/strings.xml
+++ b/service-builtin/res/values-el/strings.xml
@@ -16,6 +16,14 @@
<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_bind_projection_service" msgid="5362076216606651526">"σύνδεση σε υπηρεσία προβολής"</string>
+<string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"Επιτρέπει στον κάτοχο τη δέσμευση στη διεπαφή ανωτάτου επιπέδου μιας υπηρεσίας προβολής. Δεν απαιτείται ποτέ για κανονικές εφαρμογές."</string>
+<string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"Υπηρεσία εφαρμογής πελάτη VMS"</string>
+<string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"Δέσμευση σε εφαρμογές πελάτη VMS"</string>
+<string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"Απόδοση καντράν"</string>
+<string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"Λήψη δεδομένων καντράν"</string>
+<string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Υπηρεσία εισόδου αυτοκινήτου"</string>
+<string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Χειρισμός συμβάντων εισόδου"</string>
<string name="activity_blocked_text" msgid="5991043857905412794">"Δεν μπορείτε να χρησιμοποιείτε αυτήν τη λειτουργία κατά την οδήγηση."</string>
<string name="exit_button_message" msgid="5375678491245394542">"Για να ξεκινήσετε από την αρχή με ασφαλείς λειτουργίες εφαρμογής, επιλέξτε <xliff:g id="EXIT_BUTTON">%s</xliff:g>."</string>
<string name="exit_button" msgid="3491899413031549265">"Πίσω"</string>
diff --git a/service-builtin/res/values-en-rAU/strings.xml b/service-builtin/res/values-en-rAU/strings.xml
index a1c74879..cfbe1e1 100644
--- a/service-builtin/res/values-en-rAU/strings.xml
+++ b/service-builtin/res/values-en-rAU/strings.xml
@@ -16,6 +16,14 @@
<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_bind_projection_service" msgid="5362076216606651526">"bind to a projection service"</string>
+<string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"Allows the holder to bind to the top-level interface of a projection service. Should never be needed for normal apps."</string>
+<string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"VMS Client Service"</string>
+<string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"Bind to VMS clients"</string>
+<string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"Instrument cluster rendering"</string>
+<string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"Receive instrument cluster data"</string>
+<string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Car input service"</string>
+<string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Handle input events"</string>
<string name="activity_blocked_text" msgid="5991043857905412794">"You can’t use this feature while driving"</string>
<string name="exit_button_message" msgid="5375678491245394542">"To start again with safe app features, select <xliff:g id="EXIT_BUTTON">%s</xliff:g>."</string>
<string name="exit_button" msgid="3491899413031549265">"Back"</string>
diff --git a/service-builtin/res/values-en-rCA/strings.xml b/service-builtin/res/values-en-rCA/strings.xml
index a1c74879..cfbe1e1 100644
--- a/service-builtin/res/values-en-rCA/strings.xml
+++ b/service-builtin/res/values-en-rCA/strings.xml
@@ -16,6 +16,14 @@
<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_bind_projection_service" msgid="5362076216606651526">"bind to a projection service"</string>
+<string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"Allows the holder to bind to the top-level interface of a projection service. Should never be needed for normal apps."</string>
+<string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"VMS Client Service"</string>
+<string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"Bind to VMS clients"</string>
+<string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"Instrument cluster rendering"</string>
+<string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"Receive instrument cluster data"</string>
+<string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Car input service"</string>
+<string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Handle input events"</string>
<string name="activity_blocked_text" msgid="5991043857905412794">"You can’t use this feature while driving"</string>
<string name="exit_button_message" msgid="5375678491245394542">"To start again with safe app features, select <xliff:g id="EXIT_BUTTON">%s</xliff:g>."</string>
<string name="exit_button" msgid="3491899413031549265">"Back"</string>
diff --git a/service-builtin/res/values-en-rGB/strings.xml b/service-builtin/res/values-en-rGB/strings.xml
index a1c74879..cfbe1e1 100644
--- a/service-builtin/res/values-en-rGB/strings.xml
+++ b/service-builtin/res/values-en-rGB/strings.xml
@@ -16,6 +16,14 @@
<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_bind_projection_service" msgid="5362076216606651526">"bind to a projection service"</string>
+<string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"Allows the holder to bind to the top-level interface of a projection service. Should never be needed for normal apps."</string>
+<string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"VMS Client Service"</string>
+<string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"Bind to VMS clients"</string>
+<string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"Instrument cluster rendering"</string>
+<string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"Receive instrument cluster data"</string>
+<string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Car input service"</string>
+<string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Handle input events"</string>
<string name="activity_blocked_text" msgid="5991043857905412794">"You can’t use this feature while driving"</string>
<string name="exit_button_message" msgid="5375678491245394542">"To start again with safe app features, select <xliff:g id="EXIT_BUTTON">%s</xliff:g>."</string>
<string name="exit_button" msgid="3491899413031549265">"Back"</string>
diff --git a/service-builtin/res/values-en-rIN/strings.xml b/service-builtin/res/values-en-rIN/strings.xml
index a1c74879..cfbe1e1 100644
--- a/service-builtin/res/values-en-rIN/strings.xml
+++ b/service-builtin/res/values-en-rIN/strings.xml
@@ -16,6 +16,14 @@
<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_bind_projection_service" msgid="5362076216606651526">"bind to a projection service"</string>
+<string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"Allows the holder to bind to the top-level interface of a projection service. Should never be needed for normal apps."</string>
+<string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"VMS Client Service"</string>
+<string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"Bind to VMS clients"</string>
+<string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"Instrument cluster rendering"</string>
+<string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"Receive instrument cluster data"</string>
+<string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Car input service"</string>
+<string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Handle input events"</string>
<string name="activity_blocked_text" msgid="5991043857905412794">"You can’t use this feature while driving"</string>
<string name="exit_button_message" msgid="5375678491245394542">"To start again with safe app features, select <xliff:g id="EXIT_BUTTON">%s</xliff:g>."</string>
<string name="exit_button" msgid="3491899413031549265">"Back"</string>
diff --git a/service-builtin/res/values-en-rXC/strings.xml b/service-builtin/res/values-en-rXC/strings.xml
index 3d50987..48e85f2 100644
--- a/service-builtin/res/values-en-rXC/strings.xml
+++ b/service-builtin/res/values-en-rXC/strings.xml
@@ -16,6 +16,14 @@
<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_bind_projection_service" msgid="5362076216606651526">"bind to a projection service"</string>
+<string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"Allows the holder to bind to the top-level interface of a projection service. Should never be needed for normal apps."</string>
+<string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"VMS Client Service"</string>
+<string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"Bind to VMS clients"</string>
+<string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"Instrument Cluster Rendering"</string>
+<string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"Receive instrument cluster data"</string>
+<string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Car Input Service"</string>
+<string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Handle input events"</string>
<string name="activity_blocked_text" msgid="5991043857905412794">"You can’t use this feature while driving"</string>
<string name="exit_button_message" msgid="5375678491245394542">"To start over with safe app features, select <xliff:g id="EXIT_BUTTON">%s</xliff:g>."</string>
<string name="exit_button" msgid="3491899413031549265">"Back"</string>
diff --git a/service-builtin/res/values-es-rUS/strings.xml b/service-builtin/res/values-es-rUS/strings.xml
index 53898e0..dfee2fb 100644
--- a/service-builtin/res/values-es-rUS/strings.xml
+++ b/service-builtin/res/values-es-rUS/strings.xml
@@ -16,6 +16,14 @@
<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_bind_projection_service" msgid="5362076216606651526">"vincular un servicio de proyección"</string>
+<string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"Permite al propietario vincularse a la interfaz de nivel superior de un servicio de proyección. Las apps normales no deberían necesitar este permiso."</string>
+<string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"Servicio del cliente de VMS"</string>
+<string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"Vincular a clientes VMS"</string>
+<string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"Procesamiento de clúster de instrumentos"</string>
+<string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"Recibir datos del clúster de instrumentos"</string>
+<string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Servicio de entrada del auto"</string>
+<string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Controlar eventos de entrada"</string>
<string name="activity_blocked_text" msgid="5991043857905412794">"No puedes usar esta función mientras conduces"</string>
<string name="exit_button_message" msgid="5375678491245394542">"Para volver a comenzar con funciones de app seguras, selecciona <xliff:g id="EXIT_BUTTON">%s</xliff:g>."</string>
<string name="exit_button" msgid="3491899413031549265">"Atrás"</string>
diff --git a/service-builtin/res/values-es/strings.xml b/service-builtin/res/values-es/strings.xml
index 7d84669..d289b85 100644
--- a/service-builtin/res/values-es/strings.xml
+++ b/service-builtin/res/values-es/strings.xml
@@ -16,6 +16,14 @@
<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_bind_projection_service" msgid="5362076216606651526">"vincular un servicio de proyección"</string>
+<string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"Permite al titular vincular con la interfaz de nivel superior de un servicio de proyección. Las aplicaciones normales no deberían necesitar este permiso."</string>
+<string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"Servicio de cliente de VMS"</string>
+<string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"Vincular con clientes VMS"</string>
+<string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"Representación de datos en el panel de instrumentos"</string>
+<string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"Recibir datos del panel de instrumentos"</string>
+<string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Servicio de entrada del coche"</string>
+<string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Gestionar eventos de entrada"</string>
<string name="activity_blocked_text" msgid="5991043857905412794">"No puedes usar esta función mientras conduces"</string>
<string name="exit_button_message" msgid="5375678491245394542">"Para volver a empezar con funciones de aplicaciones seguras, selecciona <xliff:g id="EXIT_BUTTON">%s</xliff:g>."</string>
<string name="exit_button" msgid="3491899413031549265">"Atrás"</string>
diff --git a/service-builtin/res/values-et/strings.xml b/service-builtin/res/values-et/strings.xml
index 915cbb3..dc8d6fe 100644
--- a/service-builtin/res/values-et/strings.xml
+++ b/service-builtin/res/values-et/strings.xml
@@ -16,6 +16,14 @@
<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_bind_projection_service" msgid="5362076216606651526">"sidumine projitseerimisteenusega"</string>
+<string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"Lubab omanikul siduda projitseerimisteenuse ülataseme liidesega. Tavarakenduste puhul ei peaks seda kunagi vaja minema."</string>
+<string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"VMS-kliendi teenus"</string>
+<string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"Sidumine VMS-klientidega"</string>
+<string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"Näidikulaua renderdamine"</string>
+<string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"Näidikulaua teabe saamine"</string>
+<string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Auto sisendteenus"</string>
+<string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Sisestussündmuste töötlemine"</string>
<string name="activity_blocked_text" msgid="5991043857905412794">"Te ei saa seda funktsiooni sõidu ajal kasutada"</string>
<string name="exit_button_message" msgid="5375678491245394542">"Uuesti alustamiseks turvaliste rakenduste funktsioonidega valige <xliff:g id="EXIT_BUTTON">%s</xliff:g>."</string>
<string name="exit_button" msgid="3491899413031549265">"Tagasi"</string>
diff --git a/service-builtin/res/values-eu/strings.xml b/service-builtin/res/values-eu/strings.xml
index 8a95d5e..fdde757 100644
--- a/service-builtin/res/values-eu/strings.xml
+++ b/service-builtin/res/values-eu/strings.xml
@@ -16,6 +16,14 @@
<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_bind_projection_service" msgid="5362076216606651526">"lotu proiekzio-zerbitzu batekin"</string>
+<string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"Proiekzio-zerbitzu baten goi-mailako interfazeari lotzeko baimena ematen die titularrei. Aplikazio normalek ez lukete beharko."</string>
+<string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"VMS bezeroen zerbitzua"</string>
+<string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"Lotu VMS bezeroekin"</string>
+<string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"Instrumentu lukuaren errendatzea"</string>
+<string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"Jaso instrumentu lukuaren datuak"</string>
+<string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Autoaren sarrerako zerbitzua"</string>
+<string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Kudeatu sarrerako gertaerak"</string>
<string name="activity_blocked_text" msgid="5991043857905412794">"Ezin duzu erabili eginbidea gidatu bitartean"</string>
<string name="exit_button_message" msgid="5375678491245394542">"Berriro hasi nahi baduzu aplikazioaren eginbide seguruekin, hautatu <xliff:g id="EXIT_BUTTON">%s</xliff:g>."</string>
<string name="exit_button" msgid="3491899413031549265">"Atzera"</string>
diff --git a/service-builtin/res/values-fa/strings.xml b/service-builtin/res/values-fa/strings.xml
index e65772f..44be5dd 100644
--- a/service-builtin/res/values-fa/strings.xml
+++ b/service-builtin/res/values-fa/strings.xml
@@ -16,6 +16,14 @@
<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_bind_projection_service" msgid="5362076216606651526">"اتصال به سرویس انتقال محتوا"</string>
+<string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"به برنامه اجازه میدهد که به واسط سطح بالای سرویس انتقال محتوا متصل شود. هرگز نباید برای برنامههای معمولی مورد نیاز باشد."</string>
+<string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"سرویس کارخواه VMS"</string>
+<string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"اتصال به کارخواهان VMS"</string>
+<string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"پرداز داشبورد"</string>
+<string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"دریافت دادههای داشبورد"</string>
+<string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"سرویس ورودی خودرو"</string>
+<string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"مدیریت رویدادهای ورودی"</string>
<string name="activity_blocked_text" msgid="5991043857905412794">"هنگام رانندگی نمیتوانید از این ویژگی استفاده کنید"</string>
<string name="exit_button_message" msgid="5375678491245394542">"برای شروع مجدد با ویژگیهای برنامه امن، <xliff:g id="EXIT_BUTTON">%s</xliff:g> را انتخاب کنید."</string>
<string name="exit_button" msgid="3491899413031549265">"برگشت"</string>
diff --git a/service-builtin/res/values-fi/strings.xml b/service-builtin/res/values-fi/strings.xml
index 50a9afd..4533d6a 100644
--- a/service-builtin/res/values-fi/strings.xml
+++ b/service-builtin/res/values-fi/strings.xml
@@ -16,6 +16,14 @@
<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_bind_projection_service" msgid="5362076216606651526">"sitoutua projektiopalveluun"</string>
+<string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"Antaa sovelluksen sitoutua projektiopalvelun ylemmän tason käyttöliittymään. Ei tavallisten sovelluksien käyttöön."</string>
+<string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"VMS-asiakassovelluspalvelu"</string>
+<string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"sitoutua VMS-asiakassovelluksiin"</string>
+<string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"Instrumenttijoukon renderöinti"</string>
+<string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"vastaanottaa instrumenttijoukkojen dataa"</string>
+<string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Auton syötepalvelu"</string>
+<string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"käsitellä syötteitä"</string>
<string name="activity_blocked_text" msgid="5991043857905412794">"Et voi käyttää ominaisuutta ajon aikana"</string>
<string name="exit_button_message" msgid="5375678491245394542">"Jos haluat aloittaa alusta turvallisilla sovellusominaisuuksilla, valitse <xliff:g id="EXIT_BUTTON">%s</xliff:g>."</string>
<string name="exit_button" msgid="3491899413031549265">"Takaisin"</string>
diff --git a/service-builtin/res/values-fr-rCA/strings.xml b/service-builtin/res/values-fr-rCA/strings.xml
index 6d5e173..6e774cd 100644
--- a/service-builtin/res/values-fr-rCA/strings.xml
+++ b/service-builtin/res/values-fr-rCA/strings.xml
@@ -16,6 +16,14 @@
<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_bind_projection_service" msgid="5362076216606651526">"s\'associer à un service de production"</string>
+<string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"Permet à l\'application autorisée de s\'associer à l\'interface de plus haut niveau d\'un service de projection. Les applications standard ne devraient pas avoir recours à cette fonctionnalité."</string>
+<string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"Service client des messages de signalisation dynamique"</string>
+<string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"S\'associer aux clients des messages de signalisation dynamique"</string>
+<string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"Rendu du groupe d\'instruments"</string>
+<string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"Recevoir les données du groupe d\'instruments"</string>
+<string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Service d\'entrée de la voiture"</string>
+<string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Gérer les événements d\'entrée"</string>
<string name="activity_blocked_text" msgid="5991043857905412794">"Vous ne pouvez pas utiliser cette fonctionnalité en conduisant"</string>
<string name="exit_button_message" msgid="5375678491245394542">"Pour recommencer avec des fonctionnalités d\'application sécurisées, sélectionnez <xliff:g id="EXIT_BUTTON">%s</xliff:g>."</string>
<string name="exit_button" msgid="3491899413031549265">"Retour"</string>
diff --git a/service-builtin/res/values-fr/strings.xml b/service-builtin/res/values-fr/strings.xml
index 24ca750..1acac89 100644
--- a/service-builtin/res/values-fr/strings.xml
+++ b/service-builtin/res/values-fr/strings.xml
@@ -16,6 +16,14 @@
<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_bind_projection_service" msgid="5362076216606651526">"Associer à un service de projection"</string>
+<string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"Permet à l\'application autorisée de s\'associer à l\'interface de plus haut niveau d\'un service de projection. Cette autorisation ne devrait jamais être nécessaire pour les applications standards."</string>
+<string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"Service client VMS"</string>
+<string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"S\'associer à des clients VMS"</string>
+<string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"Rendu du groupe d\'instruments"</string>
+<string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"Recevoir les données du groupe d\'instruments"</string>
+<string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Service d\'entrée de la voiture"</string>
+<string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Gérer les événements d\'entrée"</string>
<string name="activity_blocked_text" msgid="5991043857905412794">"Vous ne pouvez pas utiliser cette fonctionnalité en conduisant"</string>
<string name="exit_button_message" msgid="5375678491245394542">"Pour recommencer avec des fonctionnalités d\'application sécurisées, sélectionnez <xliff:g id="EXIT_BUTTON">%s</xliff:g>."</string>
<string name="exit_button" msgid="3491899413031549265">"Retour"</string>
diff --git a/service-builtin/res/values-gl/strings.xml b/service-builtin/res/values-gl/strings.xml
index 7245441..a9440ad 100644
--- a/service-builtin/res/values-gl/strings.xml
+++ b/service-builtin/res/values-gl/strings.xml
@@ -16,6 +16,14 @@
<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_bind_projection_service" msgid="5362076216606651526">"vincular cun servizo de proxección"</string>
+<string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"Permite ao propietario vincularse á interface de nivel superior dun servizo de proxección. Non debería ser nunca necesario para as aplicacións normais."</string>
+<string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"Servizo de cliente de VMS"</string>
+<string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"Vincular a clientes de VMS"</string>
+<string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"Representación do panel de instrumentos"</string>
+<string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"Recibir datos do panel de instrumentos"</string>
+<string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Servizo de entrada do coche"</string>
+<string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Controlar os eventos de entrada"</string>
<string name="activity_blocked_text" msgid="5991043857905412794">"Non podes utilizar esta función mentres conduces"</string>
<string name="exit_button_message" msgid="5375678491245394542">"Para comezar de novo coas funcións de aplicacións seguras, selecciona o botón <xliff:g id="EXIT_BUTTON">%s</xliff:g>."</string>
<string name="exit_button" msgid="3491899413031549265">"Atrás"</string>
diff --git a/service-builtin/res/values-gu/strings.xml b/service-builtin/res/values-gu/strings.xml
index 1a1a86b..c1eab9f 100644
--- a/service-builtin/res/values-gu/strings.xml
+++ b/service-builtin/res/values-gu/strings.xml
@@ -16,6 +16,14 @@
<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_bind_projection_service" msgid="5362076216606651526">"પ્રોજેક્શન સેવા સાથે જોડાઓ"</string>
+<string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"ધારકને કોઈ પ્રોજેક્શન સેવાના ઉચ્ચ લેવલના ઇન્ટરફેસથી પ્રતિબદ્ધ થવાની મંજૂરી આપે છે. સામાન્ય ઍપ માટે ક્યારેય જરૂરી હોવું જોઈએ નહીં."</string>
+<string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"VMS ક્લાયન્ટ સેવા"</string>
+<string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"VMS ક્લાયન્ટથી પ્રતિબદ્ધ થાઓ"</string>
+<string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"ઇન્સ્ટ્રુમેન્ટ ક્લસ્ટર રેન્ડર કરી રહ્યું છે"</string>
+<string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"ઇન્સ્ટ્રુમેન્ટ ક્લસ્ટરનો ડેટા પ્રાપ્ત કરો"</string>
+<string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"કારની ઇનપુટ સેવા"</string>
+<string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"ઇનપુટ ઇવેન્ટ્સને હૅન્ડલ કરો"</string>
<string name="activity_blocked_text" msgid="5991043857905412794">"ડ્રાઇવ કરતી વખતે તમે આ સુવિધાનો ઉપયોગ કરી શકતા નથી"</string>
<string name="exit_button_message" msgid="5375678491245394542">"સુરક્ષિત ઍપ્લિકેશન સુવિધાઓ સાથે ફરી શરૂ કરવા, <xliff:g id="EXIT_BUTTON">%s</xliff:g> પસંદ કરો."</string>
<string name="exit_button" msgid="3491899413031549265">"પાછળ"</string>
diff --git a/service-builtin/res/values-hi/strings.xml b/service-builtin/res/values-hi/strings.xml
index 42489bc..a78e207 100644
--- a/service-builtin/res/values-hi/strings.xml
+++ b/service-builtin/res/values-hi/strings.xml
@@ -16,6 +16,14 @@
<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_bind_projection_service" msgid="5362076216606651526">"प्रोजेक्ट करने की सुविधा इस्तेमाल कर सकता है"</string>
+<string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"उपोयगकर्ता को किसी प्रोजेक्ट करने की सुविधा के टॉप-लेवल इंटरफ़ेस से जोड़ता है. सामान्य ऐप्लिकेशन के लिए इसकी कभी ज़रूरत नहीं होती."</string>
+<string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"वीएमएस क्लाइंट सुविधा"</string>
+<string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"वीएमएस क्लाइंट से जोड़ सकता है"</string>
+<string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"इंस्ट्रूमेंट क्लस्टर रेंडर करने की सुविधा"</string>
+<string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"इंस्ट्रूमेंट क्लस्टर का डेटा पाएं"</string>
+<string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"कार की इनपुट सेवा"</string>
+<string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"इनपुट से जुड़े इवेंट प्रबंधित कर सकता है"</string>
<string name="activity_blocked_text" msgid="5991043857905412794">"आप गाड़ी चलाते समय इस सुविधा का इस्तेमाल नहीं कर सकते"</string>
<string name="exit_button_message" msgid="5375678491245394542">"सुरक्षित ऐप्लिकेशन सुविधाएं फिर से शुरू करने के लिए, <xliff:g id="EXIT_BUTTON">%s</xliff:g> चुनें."</string>
<string name="exit_button" msgid="3491899413031549265">"वापस शुरू करें"</string>
diff --git a/service-builtin/res/values-hr/strings.xml b/service-builtin/res/values-hr/strings.xml
index 28e0988..31f3ae0 100644
--- a/service-builtin/res/values-hr/strings.xml
+++ b/service-builtin/res/values-hr/strings.xml
@@ -16,6 +16,14 @@
<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_bind_projection_service" msgid="5362076216606651526">"vezati se na uslugu projekcije"</string>
+<string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"Nositelju omogućuje vezanje uz sučelje najviše razine usluge za projiciranje. Ne bi smjelo biti potrebno za normalne aplikacije."</string>
+<string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"VMS usluga za klijente"</string>
+<string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"vezati se na VMS klijente"</string>
+<string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"generiranje na instrumentnoj ploči"</string>
+<string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"primati podatke instrumentne ploče"</string>
+<string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"usluga automobilskog unosa"</string>
+<string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"rukovati događajima unosa"</string>
<string name="activity_blocked_text" msgid="5991043857905412794">"Tu značajku ne možete upotrebljavati tijekom vožnje"</string>
<string name="exit_button_message" msgid="5375678491245394542">"Da biste započeli ponovo sa sigurnim značajkama aplikacije, odaberite <xliff:g id="EXIT_BUTTON">%s</xliff:g>."</string>
<string name="exit_button" msgid="3491899413031549265">"Natrag"</string>
diff --git a/service-builtin/res/values-hu/strings.xml b/service-builtin/res/values-hu/strings.xml
index 3b619ff..14eaa3a 100644
--- a/service-builtin/res/values-hu/strings.xml
+++ b/service-builtin/res/values-hu/strings.xml
@@ -16,6 +16,14 @@
<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_bind_projection_service" msgid="5362076216606651526">"összeköthető kivetítési szolgáltatásokkal"</string>
+<string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"Lehetővé teszi a használó számára, hogy csatlakozzon a kivetítési szolgáltatás legfelső szintű kezelőfelületéhez. A normál alkalmazásoknak erre soha nincs szüksége."</string>
+<string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"Változtatható jelzésképű táblák ügyfélszolgáltatója"</string>
+<string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"Változtatható jelzésképű táblák ügyfeleivel való összekapcsolás"</string>
+<string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"Műszerfalon való megjelenítés"</string>
+<string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"Műszerfaladatok fogadása"</string>
+<string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Az autó beviteli szolgáltatása"</string>
+<string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Kezelheti a beviteli eseményeket"</string>
<string name="activity_blocked_text" msgid="5991043857905412794">"Vezetés közben nem használhatja ezt a funkciót"</string>
<string name="exit_button_message" msgid="5375678491245394542">"Ha biztonságos alkalmazásfunkciókkal szeretné újrakezdeni, válassza a következő gombot: <xliff:g id="EXIT_BUTTON">%s</xliff:g>."</string>
<string name="exit_button" msgid="3491899413031549265">"Vissza"</string>
diff --git a/service-builtin/res/values-hy/strings.xml b/service-builtin/res/values-hy/strings.xml
index 34f2c2d..5b42f99 100644
--- a/service-builtin/res/values-hy/strings.xml
+++ b/service-builtin/res/values-hy/strings.xml
@@ -16,6 +16,14 @@
<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_bind_projection_service" msgid="5362076216606651526">"միանալ արտապատկերման ծառայությանը"</string>
+<string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"Թույլ է տալիս սեփականատիրոջը միանալ արտապատկերման ծառայության բազային միջերեսին: Սովորական հավելվածների համար երբևէ չպետք է անհրաժեշտ լինի:"</string>
+<string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"VMS սպասառուների ծառայություն"</string>
+<string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"Միանալ VMS սպասառուներին"</string>
+<string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"Սարքերի վահանակի արտապատկերում"</string>
+<string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"Ստանալ տվյալներ սարքերի վահանակից"</string>
+<string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Ներածման ծառայություն"</string>
+<string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Մշակել ներածման իրադարձությունները"</string>
<string name="activity_blocked_text" msgid="5991043857905412794">"Դուք չեք կարող օգտագործել այս գործառույթը մեքենա վարելիս"</string>
<string name="exit_button_message" msgid="5375678491245394542">"Հավելվածն անվտանգ ռեժիմում վերագործարկելու համար սեղմեք<xliff:g id="EXIT_BUTTON">%s</xliff:g> կոճակը:"</string>
<string name="exit_button" msgid="3491899413031549265">"Հետ"</string>
diff --git a/service-builtin/res/values-in/strings.xml b/service-builtin/res/values-in/strings.xml
index 300aa20..8f8c0a7 100644
--- a/service-builtin/res/values-in/strings.xml
+++ b/service-builtin/res/values-in/strings.xml
@@ -16,6 +16,14 @@
<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_bind_projection_service" msgid="5362076216606651526">"mengikat ke layanan proyeksi"</string>
+<string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"Mengizinkan pemegang untuk mengikat antarmuka tingkat tinggi dari suatu layanan proyeksi. Tidak pernah diperlukan oleh aplikasi normal."</string>
+<string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"Layanan Klien VMS"</string>
+<string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"Mengikat ke klien VMS"</string>
+<string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"Rendering Kluster Instrumen"</string>
+<string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"Menerima data kluster instrumen"</string>
+<string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Layanan Masukan Mobil"</string>
+<string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Menangani aktivitas masukan"</string>
<string name="activity_blocked_text" msgid="5991043857905412794">"Anda tidak dapat menggunakan fitur ini saat mengemudi"</string>
<string name="exit_button_message" msgid="5375678491245394542">"Untuk mulai dari awal dengan fitur apl yang aman, pilih <xliff:g id="EXIT_BUTTON">%s</xliff:g>."</string>
<string name="exit_button" msgid="3491899413031549265">"Kembali"</string>
diff --git a/service-builtin/res/values-is/strings.xml b/service-builtin/res/values-is/strings.xml
index 4c1a930..5d884b1 100644
--- a/service-builtin/res/values-is/strings.xml
+++ b/service-builtin/res/values-is/strings.xml
@@ -16,6 +16,14 @@
<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_bind_projection_service" msgid="5362076216606651526">"binda við vörpunarþjónustu"</string>
+<string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"Heimilar handhafa að bindast efsta viðmótslagi vörpunarþjónustu. Ætti aldrei að vera nauðsynlegt fyrir venjuleg forrit."</string>
+<string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"VMS-biðlaraþjónusta"</string>
+<string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"Bindst VMS-biðlara"</string>
+<string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"Teiknun mælaborðs"</string>
+<string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"Fá mælaborðsgögn"</string>
+<string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Inntaksþjónusta bíls"</string>
+<string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Stjórna inntakstilvikum"</string>
<string name="activity_blocked_text" msgid="5991043857905412794">"Þú getur ekki notað þennan eiginleika við akstur"</string>
<string name="exit_button_message" msgid="5375678491245394542">"Til að byrja aftur að setja upp örugga forritseiginleika skaltu velja <xliff:g id="EXIT_BUTTON">%s</xliff:g>."</string>
<string name="exit_button" msgid="3491899413031549265">"Til baka"</string>
diff --git a/service-builtin/res/values-it/strings.xml b/service-builtin/res/values-it/strings.xml
index e8e0668..13c9a1a 100644
--- a/service-builtin/res/values-it/strings.xml
+++ b/service-builtin/res/values-it/strings.xml
@@ -16,6 +16,14 @@
<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_bind_projection_service" msgid="5362076216606651526">"Associazione a un servizio di proiezione"</string>
+<string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"Consente al titolare di collegarsi all\'interfaccia di primo livello di un servizio di proiezione. Non dovrebbe mai essere necessaria per le app normali."</string>
+<string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"Servizio client VMS"</string>
+<string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"Consente l\'associazione a client VMS"</string>
+<string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"Visualizzazione sul quadro strumenti"</string>
+<string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"Consente di ricevere dati del quadro strumenti."</string>
+<string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Servizio di input dell\'auto"</string>
+<string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Consente di gestire gli eventi di input."</string>
<string name="activity_blocked_text" msgid="5991043857905412794">"Non è possibile usare questa funzionalità durante la guida"</string>
<string name="exit_button_message" msgid="5375678491245394542">"Seleziona <xliff:g id="EXIT_BUTTON">%s</xliff:g> per ricominciare con le funzionalità sicure dell\'app."</string>
<string name="exit_button" msgid="3491899413031549265">"Indietro"</string>
diff --git a/service-builtin/res/values-iw/strings.xml b/service-builtin/res/values-iw/strings.xml
index 6d56301..696f89a 100644
--- a/service-builtin/res/values-iw/strings.xml
+++ b/service-builtin/res/values-iw/strings.xml
@@ -16,6 +16,14 @@
<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_bind_projection_service" msgid="5362076216606651526">"הכפפה לשירות ההקרנה למסך"</string>
+<string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"מאפשרת למשתמש לבצע הכפפה לממשק ברמה עליונה של שירות הקרנה למסך. הרשאה זו לעולם אינה נחוצה לאפליקציות רגילות."</string>
+<string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"שירות לקוח VMS"</string>
+<string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"הכפפה ללקוחות VMS"</string>
+<string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"עיבוד של אשכול הכלים"</string>
+<string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"קבלת נתונים של אשכול כלים"</string>
+<string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"שירות הקלט של הרכב"</string>
+<string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"ניהול אירועי קלט"</string>
<string name="activity_blocked_text" msgid="5991043857905412794">"אי אפשר להשתמש בתכונה הזו במהלך הנהיגה"</string>
<string name="exit_button_message" msgid="5375678491245394542">"כדי להפעיל מחדש את האפליקציה במצב בטוח, יש ללחוץ על <xliff:g id="EXIT_BUTTON">%s</xliff:g>."</string>
<string name="exit_button" msgid="3491899413031549265">"הקודם"</string>
diff --git a/service-builtin/res/values-ja/strings.xml b/service-builtin/res/values-ja/strings.xml
index 69025ed..509a510 100644
--- a/service-builtin/res/values-ja/strings.xml
+++ b/service-builtin/res/values-ja/strings.xml
@@ -16,6 +16,14 @@
<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_bind_projection_service" msgid="5362076216606651526">"投影サービスへのバインド"</string>
+<string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"投影サービスのトップレベル インターフェースにバインドすることをホルダーに許可。通常のアプリでは不要です。"</string>
+<string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"VMS クライアント サービス"</string>
+<string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"VMS クライアントにバインド"</string>
+<string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"インストルメント クラスタのレンダリング"</string>
+<string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"インストルメント クラスタ データを受信します"</string>
+<string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"車の入力サービス"</string>
+<string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"入力イベントを処理します"</string>
<string name="activity_blocked_text" msgid="5991043857905412794">"運転中はこの機能を利用できません"</string>
<string name="exit_button_message" msgid="5375678491245394542">"アプリをセーフモードで再起動するには、<xliff:g id="EXIT_BUTTON">%s</xliff:g> を選択します。"</string>
<string name="exit_button" msgid="3491899413031549265">"戻る"</string>
diff --git a/service-builtin/res/values-ka/strings.xml b/service-builtin/res/values-ka/strings.xml
index f0b5300..ad65a2a 100644
--- a/service-builtin/res/values-ka/strings.xml
+++ b/service-builtin/res/values-ka/strings.xml
@@ -16,6 +16,14 @@
<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_bind_projection_service" msgid="5362076216606651526">"პროეცირების სერვისთან მიბმა"</string>
+<string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"მფლობელს აძლევს პროეცირების სერვისის ზედა დონის ინტერფეისთან მიბმის საშუალებას. ნორმალურ აპებს არასოდეს უნდა დაჭირდეთ."</string>
+<string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"VMS კლიენტის სერვისი"</string>
+<string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"VMS კლიენტებთან მიბმა"</string>
+<string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"რენდერი ხელსაწყოთა პანელზე"</string>
+<string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"ხელსაწყოთა პანელის მონაცემების მიღება"</string>
+<string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"მანქანის შეყვანის სერვისი"</string>
+<string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"შეტანის მოვლენების დამუშავება"</string>
<string name="activity_blocked_text" msgid="5991043857905412794">"მანქანის მართვისას ამ ფუნქციას ვერ გამოიყენებთ"</string>
<string name="exit_button_message" msgid="5375678491245394542">"აპის უსაფრთხო რეჟიმში გასაშვებად აირჩიეთ „<xliff:g id="EXIT_BUTTON">%s</xliff:g>“."</string>
<string name="exit_button" msgid="3491899413031549265">"უკან"</string>
diff --git a/service-builtin/res/values-kk/strings.xml b/service-builtin/res/values-kk/strings.xml
index e4c56ce..d001961 100644
--- a/service-builtin/res/values-kk/strings.xml
+++ b/service-builtin/res/values-kk/strings.xml
@@ -16,6 +16,14 @@
<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_bind_projection_service" msgid="5362076216606651526">"проекция қызметімен байланыстыру"</string>
+<string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"Пайдаланушыға проекция қызметінің жоғары деңгейлі интерфейсімен байланыстыруға мүмкіндік береді. Қалыпты қолданбаларға қажет емес."</string>
+<string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"VMS клиенттік қызметі"</string>
+<string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"VMS клиенттерімен байланыстыруға болады."</string>
+<string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"Құралдар кластерін көрсету"</string>
+<string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"Құралдар кластері туралы дерек алу"</string>
+<string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Көліктің дерек енгізу қызметі"</string>
+<string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Деректерді енгізу оқиғаларын басқаруға болады"</string>
<string name="activity_blocked_text" msgid="5991043857905412794">"Бұл функцияны көлік жүргізген кезде пайдалана алмайсыз."</string>
<string name="exit_button_message" msgid="5375678491245394542">"Қолданбаны қауіпсіз күйде қайта іске қосу үшін <xliff:g id="EXIT_BUTTON">%s</xliff:g> түймесін басыңыз."</string>
<string name="exit_button" msgid="3491899413031549265">"Артқа"</string>
diff --git a/service-builtin/res/values-km/strings.xml b/service-builtin/res/values-km/strings.xml
index b475562..ded364f 100644
--- a/service-builtin/res/values-km/strings.xml
+++ b/service-builtin/res/values-km/strings.xml
@@ -16,6 +16,14 @@
<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_bind_projection_service" msgid="5362076216606651526">"ភ្ជាប់ទៅសេវាកម្មបញ្ចាំង"</string>
+<string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"អនុញ្ញាតឱ្យទម្រភ្ជាប់ជាមួយផ្ទៃកម្រិតកំពូលរបស់សេវាកម្មបញ្ចាំង។ មិនគួរចាំបាច់សម្រាប់កម្មវិធីធម្មតាទេ។"</string>
+<string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"សេវាកម្មអតិថិជន VMS"</string>
+<string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"ភ្ជាប់ទៅអតិថិជន VMS"</string>
+<string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"ការបំប្លែងបណ្ដុំឧបករណ៍"</string>
+<string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"ទទួលបានទិន្នន័យបណ្ដុំឧបករណ៍"</string>
+<string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"សេវាកម្មបញ្ចូលរបស់រថយន្ត"</string>
+<string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"គ្រប់គ្រងព្រឹត្តិការណ៍បញ្ចូល"</string>
<string name="activity_blocked_text" msgid="5991043857905412794">"អ្នកមិនអាចប្រើមុខងារនេះបានទេ ខណៈពេលកំពុងបើកបរ"</string>
<string name="exit_button_message" msgid="5375678491245394542">"ដើម្បីចាប់ផ្តើមឡើងវិញដោយប្រើមុខងារកម្មវិធីដែលមានសុវត្ថិភាព សូមជ្រើសរើស <xliff:g id="EXIT_BUTTON">%s</xliff:g> ។"</string>
<string name="exit_button" msgid="3491899413031549265">"ថយក្រោយ"</string>
diff --git a/service-builtin/res/values-kn/strings.xml b/service-builtin/res/values-kn/strings.xml
index bf923b5..8670f56 100644
--- a/service-builtin/res/values-kn/strings.xml
+++ b/service-builtin/res/values-kn/strings.xml
@@ -16,6 +16,14 @@
<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_bind_projection_service" msgid="5362076216606651526">"ಪ್ರೊಜೆಕ್ಷನ್ ಸೇವೆಗೆ ಪ್ರತಿಬಂಧಿಸಿ"</string>
+<string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"ಪ್ರೊಜೆಕ್ಷನ್ ಸೇವೆಯ ಉನ್ನತ ಮಟ್ಟದ ಇಂಟರ್ ಫೇಸ್ಗೆ ಪ್ರತಿಬಂಧಿಸಲು ಮಾಲೀಕರಿಗೆ ಅವಕಾಶ ನೀಡುತ್ತದೆ. ಸಾಮಾನ್ಯ ಆ್ಯಪ್ಗಳಿಗೆ ಎಂದಿಗೂ ಅಗತ್ಯವಿರುವುದಿಲ್ಲ."</string>
+<string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"VMS ಕ್ಲೈಂಟ್ ಸೇವೆ"</string>
+<string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"VMS ಕ್ಲೈಂಟ್ಗಳಿಗೆ ಪ್ರತಿಬಂಧಿಸಿ"</string>
+<string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"ಸಲಕರಣೆ ಸಂಚಯ ತೋರಿಸು"</string>
+<string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"ಸಲಕರಣೆ ಸಂಚಯ ಮಾಹಿತಿಯನ್ನು ಸ್ವೀಕರಿಸಿ"</string>
+<string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"ಕಾರಿನ ಇನ್ಪುಟ್ ಸೇವೆ"</string>
+<string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"ಊಡಿಕೆ ಘಟನೆಗಳನ್ನು ನಿಯಂತ್ರಿಸಿ"</string>
<string name="activity_blocked_text" msgid="5991043857905412794">"ಡ್ರೈವ್ ಮಾಡುವಾಗ ನೀವು ಈ ಫೀಚರ್ ಅನ್ನು ಬಳಸಲಾಗುವುದಿಲ್ಲ"</string>
<string name="exit_button_message" msgid="5375678491245394542">"ಆಪ್ನ ಸುರಕ್ಷೆ ಗುಣಲಕ್ಷಣಗಳನ್ನು ಒಳಗೊಂಡು ಮತ್ತೆ ಪ್ರಾರಂಭಿಸಲು, <xliff:g id="EXIT_BUTTON">%s</xliff:g> ಆಯ್ಕೆ ಮಾಡಿ."</string>
<string name="exit_button" msgid="3491899413031549265">"ಹಿಂದಕ್ಕೆ"</string>
diff --git a/service-builtin/res/values-ko/strings.xml b/service-builtin/res/values-ko/strings.xml
index c202a09..4a077c3 100644
--- a/service-builtin/res/values-ko/strings.xml
+++ b/service-builtin/res/values-ko/strings.xml
@@ -16,6 +16,14 @@
<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_bind_projection_service" msgid="5362076216606651526">"프로젝션 서비스에 연결"</string>
+<string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"권한을 가진 프로그램이 프로젝션 서비스의 최상위 인터페이스에 연결되도록 허용합니다. 일반 앱에는 필요하지 않습니다."</string>
+<string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"VMS 클라이언트 서비스"</string>
+<string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"VMS 클라이언트에 연결"</string>
+<string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"계기판 렌더링"</string>
+<string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"계기판 데이터 수신"</string>
+<string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"차량 입력 서비스"</string>
+<string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"입력 이벤트 처리"</string>
<string name="activity_blocked_text" msgid="5991043857905412794">"운전 중에는 이 기능을 사용하실 수 없습니다."</string>
<string name="exit_button_message" msgid="5375678491245394542">"안전한 앱 기능으로 다시 시작하려면 <xliff:g id="EXIT_BUTTON">%s</xliff:g>을(를) 선택하세요."</string>
<string name="exit_button" msgid="3491899413031549265">"뒤로"</string>
diff --git a/service-builtin/res/values-ky/strings.xml b/service-builtin/res/values-ky/strings.xml
index 90010f0..615e296 100644
--- a/service-builtin/res/values-ky/strings.xml
+++ b/service-builtin/res/values-ky/strings.xml
@@ -16,6 +16,14 @@
<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_bind_projection_service" msgid="5362076216606651526">"долбоорлоо кызматына туташуу"</string>
+<string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"Ээсине долбоорлоо кызматынын жогорку деңгээл интерфейсине туташуу мүмкүнчүлүгүн берет. Жалпыга багышталган колдонмолордо эч качан колдонулбашы керек."</string>
+<string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"VMS кардарларды тейлөө кызматы"</string>
+<string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"VMS кардарларына туташуу"</string>
+<string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"Куралдар кластери түзүлүүдө"</string>
+<string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"Куралдар кластеринин дайындарын алуу"</string>
+<string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Унаанын киргизүү кызматы"</string>
+<string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Киргизүү аракеттерин башкаруу"</string>
<string name="activity_blocked_text" msgid="5991043857905412794">"Бул функцияны унаа айдап баратканда колдоно албайсыз"</string>
<string name="exit_button_message" msgid="5375678491245394542">"Колдонмонун коопсуз функцияларын иштетүү үчүн <xliff:g id="EXIT_BUTTON">%s</xliff:g> баскычын басыңыз."</string>
<string name="exit_button" msgid="3491899413031549265">"Артка"</string>
@@ -30,9 +38,9 @@
<string name="factory_reset_warning" msgid="8463356329619149262">"Түзмөгүңүз тазаланат"</string>
<string name="factory_reset_message" msgid="1972536809866779972">"Түзмөктү башкаруучу колдонмо жараксыз. Түзмөгүңүз азыр тазаланат.\n\nСуроолоруңуз болсо, ишканаңыздын администраторуна кайрылыңыз."</string>
<string name="resource_overuse_notification_title" msgid="1622015333965744463">"<xliff:g id="ID_1">^1</xliff:g> системанын ишине кедергисин тийгизип жатат"</string>
- <string name="resource_overuse_notification_text_disable_app" msgid="6230392052741662158">"Системанын ишин жакшыртуу үчүн колдонмону өчүрүп коюңуз. Аны кайра жөндөөлөрдөн иштетип койсоңуз болот."</string>
+ <string name="resource_overuse_notification_text_disable_app" msgid="6230392052741662158">"Тутумдун ишин жакшыртуу үчүн колдонмону өчүрүп коюңуз. Аны кайра жөндөөлөрдөн иштетип койсоңуз болот."</string>
<string name="resource_overuse_notification_text_prioritize_app" msgid="5712958688473220136">"Колдонмону пайдалана берүү үчүн ага артыкчылык бериңиз."</string>
- <string name="resource_overuse_notification_text_uninstall_app" msgid="7571808726595158942">"Системанын ишин жакшыртуу үчүн колдонмону чыгарып салыңыз."</string>
+ <string name="resource_overuse_notification_text_uninstall_app" msgid="7571808726595158942">"Тутумдун ишин жакшыртуу үчүн колдонмону чыгарып салыңыз."</string>
<string name="resource_overuse_notification_button_disable_app" msgid="7366883746281232189">"Колдонмону өчүрүп коюу"</string>
<string name="resource_overuse_notification_button_prioritize_app" msgid="1093325910457794796">"Колдонмого артыкчылык берүү"</string>
<string name="resource_overuse_notification_button_uninstall_app" msgid="5259756814713178196">"Колдонмону чыгарып салуу"</string>
diff --git a/service-builtin/res/values-lo/strings.xml b/service-builtin/res/values-lo/strings.xml
index a6aadee..d88d254 100644
--- a/service-builtin/res/values-lo/strings.xml
+++ b/service-builtin/res/values-lo/strings.xml
@@ -16,6 +16,14 @@
<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_bind_projection_service" msgid="5362076216606651526">"ຜູກມັດກັບການບໍລິການສາຍພາບ"</string>
+<string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"ອະນຸຍາດໃຫ້ຜູ້ຖືຜູກມັດກັບສ່ວນຕິດຕໍ່ຜູ້ໃຊ້ລະດັບສູງຂອງການບໍລິການສາຍພາບ. ບໍ່ຄວນຕ້ອງການສຳລັບແອັບປົກກະຕິ."</string>
+<string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"ການບໍລິການລູກຂ່າຍ VMS"</string>
+<string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"ຜູກມັດກັບລູກຂ່າຍ VMS"</string>
+<string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"ການສະແດງຜົນແຜງໜ້າປັດ"</string>
+<string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"ຮັບຂໍ້ມູນຈາກແຜງໜ້າປັດ"</string>
+<string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"ການບໍລິການປ້ອນຂໍ້ມູນຂອງລົດ"</string>
+<string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"ຈັດການເຫດການປ້ອນຂໍ້ມູນ"</string>
<string name="activity_blocked_text" msgid="5991043857905412794">"ທ່ານບໍ່ສາມາດໃຊ້ຄຸນສົມບັດນີ້ໃນຂະນະທີ່ຂັບລົດໄດ້"</string>
<string name="exit_button_message" msgid="5375678491245394542">"ເພື່ອເລີ່ມຕົ້ນຄືນໃໝ່ດ້ວຍຄຸນສົມບັດແອັບທີ່ປອດໄພ, ກະລຸນາເລືອກ <xliff:g id="EXIT_BUTTON">%s</xliff:g>."</string>
<string name="exit_button" msgid="3491899413031549265">"ກັບຄືນ"</string>
diff --git a/service-builtin/res/values-lt/strings.xml b/service-builtin/res/values-lt/strings.xml
index a5edabe..dbc6b0f 100644
--- a/service-builtin/res/values-lt/strings.xml
+++ b/service-builtin/res/values-lt/strings.xml
@@ -16,6 +16,14 @@
<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_bind_projection_service" msgid="5362076216606651526">"susieti su projektavimo paslauga"</string>
+<string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"Savininkui leidžiama susisaistyti su aukščiausio lygio projektavimo paslaugos sąsaja. Įprastoms programoms to neturėtų prireikti."</string>
+<string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"VMS kliento paslauga"</string>
+<string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"Susaistyti su VMS klientais"</string>
+<string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"Instrumentų blokinio pateikimas"</string>
+<string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"Gauti instrumentų blokinio duomenis"</string>
+<string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Automobilio įvesties paslauga"</string>
+<string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Apdoroti įvesties įvykius."</string>
<string name="activity_blocked_text" msgid="5991043857905412794">"Negalite naudoti šios funkcijos vairuodami"</string>
<string name="exit_button_message" msgid="5375678491245394542">"Jei norite pradėti iš naujo naudodami saugias programos funkcijas, pasirinkite <xliff:g id="EXIT_BUTTON">%s</xliff:g>."</string>
<string name="exit_button" msgid="3491899413031549265">"Atgal"</string>
diff --git a/service-builtin/res/values-lv/strings.xml b/service-builtin/res/values-lv/strings.xml
index d36d5f7..36777ed 100644
--- a/service-builtin/res/values-lv/strings.xml
+++ b/service-builtin/res/values-lv/strings.xml
@@ -16,6 +16,14 @@
<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_bind_projection_service" msgid="5362076216606651526">"saistīt ar projicēšanas pakalpojumu"</string>
+<string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"Ļauj īpašniekam izveidot saiti ar projicēšanas pakalpojuma augšējā līmeņa saskarni. Parastajām lietotnēm tas nekad nav nepieciešams."</string>
+<string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"VMS klienta pakalpojums"</string>
+<string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"Saistīt ar VMS klientiem"</string>
+<string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"Atveide mēraparātu blokā"</string>
+<string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"Saņemt datus no mēraparātu bloka."</string>
+<string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Automašīnas ievades pakalpojums"</string>
+<string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Apstrādāt ievades notikumus."</string>
<string name="activity_blocked_text" msgid="5991043857905412794">"Jūs nevarat izmantot šo funkciju braukšanas laikā."</string>
<string name="exit_button_message" msgid="5375678491245394542">"Lai atsāktu darbu ar drošām lietotnes funkcijām, atlasiet pogu <xliff:g id="EXIT_BUTTON">%s</xliff:g>."</string>
<string name="exit_button" msgid="3491899413031549265">"Atpakaļ"</string>
diff --git a/service-builtin/res/values-mk/strings.xml b/service-builtin/res/values-mk/strings.xml
index a6081b0..c227ead 100644
--- a/service-builtin/res/values-mk/strings.xml
+++ b/service-builtin/res/values-mk/strings.xml
@@ -16,6 +16,14 @@
<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_bind_projection_service" msgid="5362076216606651526">"поврзување со услуга за прикажување"</string>
+<string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"Дозволува приклучната станица да се поврзе со интерфејс од највисоко ниво на услугата за прикажување. Не треба да се користи за обични апликации."</string>
+<string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"Услуга на клиентот за VMS"</string>
+<string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"Сврзувајте се со клиенти за VMS"</string>
+<string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"Прикажување на инструменталната табла"</string>
+<string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"Примајте податоци од инструменталната табла"</string>
+<string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Влезна услуга на автомобилот"</string>
+<string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Ракува со влезните настани"</string>
<string name="activity_blocked_text" msgid="5991043857905412794">"Не може да ја користите функцијава додека возите"</string>
<string name="exit_button_message" msgid="5375678491245394542">"За да започнете одново со безбедносните фунции на апликацијата, изберете <xliff:g id="EXIT_BUTTON">%s</xliff:g>."</string>
<string name="exit_button" msgid="3491899413031549265">"Назад"</string>
diff --git a/service-builtin/res/values-ml/strings.xml b/service-builtin/res/values-ml/strings.xml
index fd3e09b..488a0b1 100644
--- a/service-builtin/res/values-ml/strings.xml
+++ b/service-builtin/res/values-ml/strings.xml
@@ -16,6 +16,14 @@
<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_bind_projection_service" msgid="5362076216606651526">"പ്രൊജക്ഷൻ സേവനവുമായി ബന്ധിപ്പിക്കുക"</string>
+<string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"പ്രൊജക്ഷൻ സേവനത്തിൻ്റെ ഏറ്റവും മികച്ച ഇൻ്റർഫേസുമായി ബന്ധിപ്പിക്കാൻ ദാതാവിനെ അനുവദിക്കുന്നു. സാധാരണ ആപ്പുകൾക്ക് ഒരിക്കലും ആവശ്യമില്ല."</string>
+<string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"VMS ക്ലയൻ്റ് സേവനം"</string>
+<string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"VMS ക്ലയൻ്റുകളുമായി ബന്ധിപ്പിക്കുക"</string>
+<string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"ഇൻസ്ട്രുമെന്റ് ക്ലസ്റ്റർ റെൻഡർ ചെയ്യൽ"</string>
+<string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"ഇൻസ്ട്രുമെന്റ് ക്ലസ്റ്റർ ഡാറ്റ സ്വീകരിക്കുക"</string>
+<string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"കാറിന്റെ ഇൻപുട്ട് സേവനം"</string>
+<string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"ഇൻപുട്ട് ഇവന്റുകൾ കൈകാര്യം ചെയ്യുക"</string>
<string name="activity_blocked_text" msgid="5991043857905412794">"ഡ്രെെവ് ചെയ്യുമ്പോൾ നിങ്ങൾ ഈ ഫീച്ചർ ഉപയോഗിക്കരുത്"</string>
<string name="exit_button_message" msgid="5375678491245394542">"സുരക്ഷിതമായ ആപ്പ് ഫീച്ചറുകൾ ഉപയോഗിച്ച് പുനരാരംഭിക്കാൻ, <xliff:g id="EXIT_BUTTON">%s</xliff:g> തിരഞ്ഞെടുക്കുക."</string>
<string name="exit_button" msgid="3491899413031549265">"മടങ്ങുക"</string>
diff --git a/service-builtin/res/values-mn/strings.xml b/service-builtin/res/values-mn/strings.xml
index 966ed11..db8667e 100644
--- a/service-builtin/res/values-mn/strings.xml
+++ b/service-builtin/res/values-mn/strings.xml
@@ -16,6 +16,14 @@
<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_bind_projection_service" msgid="5362076216606651526">"проекцын үйлчилгээнд холбох"</string>
+<string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"Эзэмшигчид проекцын үйлчилгээний дээд түвшний харагдах байдлыг холбохыг зөвшөөрдөг. Энгийн аппуудад хэзээ ч хэрэг болох ёсгүй."</string>
+<string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"VMS Клиентийн үйлчилгээ"</string>
+<string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"VMS клиентэд холбох"</string>
+<string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"Хяналтын самбарын буулгалт"</string>
+<string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"Хяналтын самбарын өгөгдлийг хүлээн авах"</string>
+<string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Машины оролтын үйлчилгээ"</string>
+<string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Оролтын арга хэмжээг боловсруулах"</string>
<string name="activity_blocked_text" msgid="5991043857905412794">"Та жолоо барьж байхдаа энэ онцлогийг ашиглах боломжгүй"</string>
<string name="exit_button_message" msgid="5375678491245394542">"Аппын аюулгүй онцлогуудтайгаар дахин эхлүүлэхийн тулд <xliff:g id="EXIT_BUTTON">%s</xliff:g>-г сонгоно уу."</string>
<string name="exit_button" msgid="3491899413031549265">"Буцах"</string>
diff --git a/service-builtin/res/values-mr/strings.xml b/service-builtin/res/values-mr/strings.xml
index 7032891..49f3a66 100644
--- a/service-builtin/res/values-mr/strings.xml
+++ b/service-builtin/res/values-mr/strings.xml
@@ -16,6 +16,14 @@
<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_bind_projection_service" msgid="5362076216606651526">"प्रोजेक्शन सेवेशी प्रतिबद्ध व्हा"</string>
+<string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"धारकाला प्रोजेक्शन सेवेच्या उच्च पातळीच्या इंटरफेसशी प्रतिबद्ध होण्याची अनुमती देते. साधारण अॅप्ससाठी कधीही आवश्यक नाही."</string>
+<string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"VMS क्लायंट सेवा"</string>
+<string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"VMS क्लायंटशी प्रतिबद्ध व्हा"</string>
+<string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"इंस्ट्रुमेंट क्लस्टर रेंडरिंग"</string>
+<string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"इंस्ट्रुमेंट क्लस्टर डेटा मिळवा"</string>
+<string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"कार इनपुट सेवा"</string>
+<string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"इनपुट इव्हेंट हाताळा"</string>
<string name="activity_blocked_text" msgid="5991043857905412794">"तुम्ही गाडी चालवत असताना हे वैशिष्ट्य वापरू शकत नाही"</string>
<string name="exit_button_message" msgid="5375678491245394542">"सुरक्षित अॅप वैशिष्ट्यांसोबत पुन्हा सुरुवात करण्यासाठी, <xliff:g id="EXIT_BUTTON">%s</xliff:g> निवडा."</string>
<string name="exit_button" msgid="3491899413031549265">"मागे जा"</string>
diff --git a/service-builtin/res/values-ms/strings.xml b/service-builtin/res/values-ms/strings.xml
index 44f6822..c471c13 100644
--- a/service-builtin/res/values-ms/strings.xml
+++ b/service-builtin/res/values-ms/strings.xml
@@ -16,6 +16,14 @@
<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_bind_projection_service" msgid="5362076216606651526">"ikat pada perkhidmatan unjuran"</string>
+<string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"Membenarkan pemegang terikat dengan antara muka peringkat tertinggi bagi perkhidmatan unjuran. Tidak sekali-kali diperlukan untuk apl biasa."</string>
+<string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"Perkhidmatan Pelanggan VMS"</string>
+<string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"Terikat pada pelanggan VMS"</string>
+<string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"Pemaparan Kluster Alatan"</string>
+<string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"Terima data kluster alatan"</string>
+<string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Perkhidmatan Input Kereta"</string>
+<string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Kendalikan peristiwa input"</string>
<string name="activity_blocked_text" msgid="5991043857905412794">"Anda tidak boleh menggunakan ciri ini semasa memandu"</string>
<string name="exit_button_message" msgid="5375678491245394542">"Untuk bermula semula dengan ciri apl selamat, pilih <xliff:g id="EXIT_BUTTON">%s</xliff:g>."</string>
<string name="exit_button" msgid="3491899413031549265">"Kembali"</string>
diff --git a/service-builtin/res/values-my/strings.xml b/service-builtin/res/values-my/strings.xml
index a7380b0..fca4d27 100644
--- a/service-builtin/res/values-my/strings.xml
+++ b/service-builtin/res/values-my/strings.xml
@@ -16,6 +16,14 @@
<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_bind_projection_service" msgid="5362076216606651526">"ခန့်မှန်းခြင်းဆိုင်ရာ ဝန်ဆောင်မှုနှင့် ပူးပေါင်းပါမည်"</string>
+<string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"ဖုန်းကိုင်ထားသူနှင့် ပုံရိပ်ပြသသော ဝန်ဆောင်မှု၏ ထိပ်ပိုင်းအင်တာဖေ့စ် ကို ပူးပေါင်းခွင့်ပေးသည်။ ပုံမှန် အက်ပ်များအတွက် မည်သည့်အခါမျှ မလိုအပ်ပါ။"</string>
+<string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"VMS ကလိုင်းယင့် ဝန်ဆောင်မှု"</string>
+<string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"VMS ကလိုင်းယင့်များနှင့် ပူးပေါင်းခြင်း"</string>
+<string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"ကိရိယာအစုအဝေးကို ပြင်ဆင်ခြင်း"</string>
+<string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"ကိရိယာအစုအဝေး ဒေတာကို လက်ခံရန်"</string>
+<string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"ကား၏ အချက်အလက်ထည့်သွင်းခြင်း ဝန်ဆောင်မှု"</string>
+<string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"အချက်အလက်ထည့်သွင်းခြင်း အစီအစဉ်များကို စီမံပါမည်"</string>
<string name="activity_blocked_text" msgid="5991043857905412794">"ကားမောင်းနေစဉ် ဤဝန်ဆောင်မှုကို သုံး၍မရပါ"</string>
<string name="exit_button_message" msgid="5375678491245394542">"စိတ်ချရသော အက်ပ်လုပ်ဆောင်ချက်များနှင့်အတူ အစမှပြန်စရန် <xliff:g id="EXIT_BUTTON">%s</xliff:g> ကို ရွေးချယ်ပါ။"</string>
<string name="exit_button" msgid="3491899413031549265">"နောက်သို့"</string>
diff --git a/service-builtin/res/values-nb/strings.xml b/service-builtin/res/values-nb/strings.xml
index b62e2b2..bad1df7 100644
--- a/service-builtin/res/values-nb/strings.xml
+++ b/service-builtin/res/values-nb/strings.xml
@@ -16,6 +16,14 @@
<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_bind_projection_service" msgid="5362076216606651526">"binde til en projeksjonstjeneste"</string>
+<string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"Lar dokken binde seg til det øverste nivået av grensesnittet for en projiseringstjeneste. Skal aldri være nødvendig for vanlige apper."</string>
+<string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"VMS-klienttjeneste"</string>
+<string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"Bind til VMS-klienter"</string>
+<string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"Gjengivelse på instrumentpanelet"</string>
+<string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"Mottak av data fra instrumentpanelet"</string>
+<string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Bilens inndatatjeneste"</string>
+<string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Behandling av inndatahendelser"</string>
<string name="activity_blocked_text" msgid="5991043857905412794">"Du kan ikke bruke denne funksjonen når du kjører"</string>
<string name="exit_button_message" msgid="5375678491245394542">"For å starte på nytt med sikre appfunksjoner, velg <xliff:g id="EXIT_BUTTON">%s</xliff:g>."</string>
<string name="exit_button" msgid="3491899413031549265">"Tilbake"</string>
diff --git a/service-builtin/res/values-ne/strings.xml b/service-builtin/res/values-ne/strings.xml
index 201b843..5bd17ad 100644
--- a/service-builtin/res/values-ne/strings.xml
+++ b/service-builtin/res/values-ne/strings.xml
@@ -16,6 +16,14 @@
<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_bind_projection_service" msgid="5362076216606651526">"प्रोजेक्सन सेवामा सम्बद्ध हुने"</string>
+<string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"धारकलाई प्रोजेक्सन सेवाको उच्च स्तरको इन्टरफेसमा सम्बद्ध हुने अनुमति दिन्छ। साधारण अनुप्रयोगहरूको लागि कहिल्यै पनि आवश्यक पर्दैन।"</string>
+<string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"VMS क्लाइन्ट सेवा"</string>
+<string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"VMS क्लाइन्टहरूमा सम्बद्ध हुनुहोस्"</string>
+<string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"उपकरणको क्लस्टर रेन्डर गर्ने प्रक्रिया"</string>
+<string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"उपकरणको क्लस्टरको डेटा प्राप्त गर्नुहोस्"</string>
+<string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"कारको इनपुट सेवा"</string>
+<string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"इनपुट गरिएका कार्यक्रमहरू व्यवस्थापन गर्ने"</string>
<string name="activity_blocked_text" msgid="5991043857905412794">"तपाईं सवारी साधन चलाइरहेका बेला यो सुविधा प्रयोग गर्न सक्नुहुन्न"</string>
<string name="exit_button_message" msgid="5375678491245394542">"एपका सुरक्षित सुविधाहरूको प्रयोग गरी फेरि सुरु गर्न <xliff:g id="EXIT_BUTTON">%s</xliff:g> चयन गर्नुहोस्।"</string>
<string name="exit_button" msgid="3491899413031549265">"पछाडि"</string>
diff --git a/service-builtin/res/values-nl/strings.xml b/service-builtin/res/values-nl/strings.xml
index 8508aef..6ace471 100644
--- a/service-builtin/res/values-nl/strings.xml
+++ b/service-builtin/res/values-nl/strings.xml
@@ -16,6 +16,14 @@
<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_bind_projection_service" msgid="5362076216606651526">"verbinding maken met een projectieservice"</string>
+<string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"Hiermee kan de houder verbinding maken met de hoofdinterface van een projectieservice. Nooit vereist voor normale apps."</string>
+<string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"VMS-clientservice"</string>
+<string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"Verbinding maken met VMS-clients"</string>
+<string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"Weergave instrumentcluster"</string>
+<string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"Gegevens van instrumentcluster ontvangen"</string>
+<string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Invoerservice van auto"</string>
+<string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Invoergebeurtenissen verwerken"</string>
<string name="activity_blocked_text" msgid="5991043857905412794">"Je kunt deze functie niet gebruiken tijdens het rijden"</string>
<string name="exit_button_message" msgid="5375678491245394542">"Selecteer <xliff:g id="EXIT_BUTTON">%s</xliff:g> om opnieuw te beginnen met de veilige app-functies."</string>
<string name="exit_button" msgid="3491899413031549265">"Vorige"</string>
diff --git a/service-builtin/res/values-or/strings.xml b/service-builtin/res/values-or/strings.xml
index 400de3e..16fe8fa 100644
--- a/service-builtin/res/values-or/strings.xml
+++ b/service-builtin/res/values-or/strings.xml
@@ -16,6 +16,14 @@
<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_bind_projection_service" msgid="5362076216606651526">"ଏକ ପ୍ରୋଜେକ୍ସନ୍ ସେବା ସହ ଯୋଡ଼ି ହୁଅନ୍ତୁ"</string>
+<string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"ଏକ ପ୍ରୋଜେକ୍ସନ୍ ସେବାର ଶୀର୍ଷ-ସ୍ତର ଇଣ୍ଟର୍ଫେସ୍କୁ ବାନ୍ଧିରଖିବା ପାଇଁ ଧାରକକୁ ଅନୁମତି ଦିଏ। ସାମାନ୍ୟ ଆପ୍ଗୁଡ଼ିକ ପାଇଁ ଏହା ଆବଶ୍ୟକ ନୁହେଁ।"</string>
+<string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"VMS ଗ୍ରାହକ ସେବା"</string>
+<string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"VMS ଗ୍ରାହକମାନଙ୍କ ସହ ଯୋଡ଼ି ହୁଅନ୍ତୁ"</string>
+<string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"ଇନ୍ଷ୍ଟ୍ରୁମେଣ୍ଟ କ୍ଲଷ୍ଟର୍ ରେଣ୍ଡରିଂ"</string>
+<string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"ଇନ୍ଷ୍ଟ୍ରୁମେଣ୍ଟ କ୍ଲଷ୍ଟର୍ର ଡାଟା ପ୍ରାପ୍ତ କରନ୍ତୁ"</string>
+<string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"କାର୍ର ଇନ୍ପୁଟ୍ ସେବା"</string>
+<string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"ଇନ୍ପୁଟ୍ ଇଭେଣ୍ଟଗୁଡ଼ିକ ପରିଚାଳନା କରିପାରେ"</string>
<string name="activity_blocked_text" msgid="5991043857905412794">"ଆପଣ ଡ୍ରାଇଭ୍ କରିବା ସମୟରେ ଏହି ଫିଚର୍ ବ୍ୟବହାର କରିପାରିବେ ନାହିଁ"</string>
<string name="exit_button_message" msgid="5375678491245394542">"ସୁରକ୍ଷିତ ଆପ୍ ବୈଶିଷ୍ଟ୍ୟଗୁଡ଼ିକୁ ନେଇ ପୁଣି ଆରମ୍ଭ କରିବା ପାଇଁ, <xliff:g id="EXIT_BUTTON">%s</xliff:g> ଚୟନ କରନ୍ତୁ।"</string>
<string name="exit_button" msgid="3491899413031549265">"ପଛକୁ ଫେରନ୍ତୁ"</string>
@@ -28,7 +36,7 @@
<string name="factory_reset_notification_text" msgid="6051393302193696102">"ଇନଫୋଟେନମେଣ୍ଟ ସିଷ୍ଟମରେ ଥିବା ସମସ୍ତ ଡାଟା ଖାଲି ହୋଇଯିବ। ରିସେଟ୍ ହେବା ପରେ, ଆପଣ ଏକ ନୂଆ ପ୍ରୋଫାଇଲ୍ ସେଟ୍ ଅପ୍ କରିପାରିବେ।"</string>
<string name="factory_reset_notification_button" msgid="6926734587145351076">"ଅଧିକ"</string>
<string name="factory_reset_warning" msgid="8463356329619149262">"ଆପଣଙ୍କ ଡିଭାଇସ୍ ବର୍ତ୍ତମାନ ଲିଭାଯିବ"</string>
- <string name="factory_reset_message" msgid="1972536809866779972">"ଆଡମିନ ଆପ ବ୍ୟବହାର କରାଯାଇପାରିବ ନାହିଁ। ଆପଣଙ୍କ ଡିଭାଇସର ସମସ୍ତ ଡାଟାକୁ ବର୍ତ୍ତମାନ ଖାଲି କରାଯିବ।\n\nଯଦି ଆପଣଙ୍କର କିଛି ପ୍ରଶ୍ନ ଅଛି, ତେବେ ଆପଣଙ୍କ ସଂସ୍ଥାର ଆଡମିନଙ୍କ ସହ କଣ୍ଟାକ୍ଟ କରନ୍ତୁ।"</string>
+ <string name="factory_reset_message" msgid="1972536809866779972">"ଆଡମିନ ଆପ ବ୍ୟବହାର କରାଯାଇପାରିବ ନାହିଁ। ଆପଣଙ୍କ ଡିଭାଇସର ସମସ୍ତ ଡାଟାକୁ ବର୍ତ୍ତମାନ ଖାଲି କରାଯିବ।\n\nଯଦି ଆପଣଙ୍କର କିଛି ପ୍ରଶ୍ନ ଅଛି, ତେବେ ଆପଣଙ୍କ ସଂସ୍ଥାର ଆଡମିନଙ୍କ ସହ ଯୋଗାଯୋଗ କରନ୍ତୁ।"</string>
<string name="resource_overuse_notification_title" msgid="1622015333965744463">"<xliff:g id="ID_1">^1</xliff:g> ଆପଣଙ୍କ ସିଷ୍ଟମର ପରଫରମାନ୍ସକୁ ପ୍ରଭାବିତ କରୁଛି"</string>
<string name="resource_overuse_notification_text_disable_app" msgid="6230392052741662158">"ସିଷ୍ଟମର ପରଫରମାନ୍ସକୁ ଉନ୍ନତ କରିବା ପାଇଁ ଆପକୁ ଅକ୍ଷମ କରନ୍ତୁ। ଆପଣ ସେଟିଂସରେ ପୁଣି ଥରେ ଆପକୁ ସକ୍ଷମ କରିପାରିବେ।"</string>
<string name="resource_overuse_notification_text_prioritize_app" msgid="5712958688473220136">"ଆପ ବ୍ୟବହାର କରିବା ଜାରି ରଖିବା ପାଇଁ ଆପକୁ ପ୍ରାଥମିକତା ଦିଅନ୍ତୁ।"</string>
diff --git a/service-builtin/res/values-pa/strings.xml b/service-builtin/res/values-pa/strings.xml
index 20135cd..1b96c38 100644
--- a/service-builtin/res/values-pa/strings.xml
+++ b/service-builtin/res/values-pa/strings.xml
@@ -16,6 +16,14 @@
<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_bind_projection_service" msgid="5362076216606651526">"ਯੋਜਨਾਬੰਦੀ ਸੇਵਾ ਨਾਲ ਜੋੜੋ"</string>
+<string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"ਹੋਲਡਰ ਨੂੰ ਯੋਜਨਾਬੰਦੀ ਸੇਵਾ ਦੇ ਉੱਚ-ਪੱਧਰ ਦੇ ਇੰਟਰਫੇਸ ਨਾਲ ਜੋੜਨ ਦਿੰਦਾ ਹੈ। ਇਹ ਆਮ ਐਪਾਂ ਲਈ ਕਦੇ ਵੀ ਲੋੜੀਂਦਾ ਨਹੀਂ ਹੋਣਾ ਚਾਹੀਦਾ।"</string>
+<string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"VMS ਕਲਾਇੰਟ ਸੇਵਾ"</string>
+<string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"VMS ਕਲਾਇੰਟਾਂ ਨਾਲ ਜੋੜੋ"</string>
+<string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"ਇੰਸਟਰੂਮੈਂਟ ਕਲੱਸਟਰ ਰੈਂਡਰਿੰਗ"</string>
+<string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"ਇੰਸਟਰੂਮੈਂਟ ਕਲੱਸਟਰ ਡਾਟਾ ਪ੍ਰਾਪਤ ਕਰੋ"</string>
+<string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"ਕਾਰ ਇਨਪੁੱਟ ਸਰਵਿਸ"</string>
+<string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"ਇਨਪੁੱਟ ਇਵੈਂਟਾਂ ਦੀ ਸੰਭਾਲ"</string>
<string name="activity_blocked_text" msgid="5991043857905412794">"ਤੁਸੀਂ ਇਹ ਵਿਸ਼ੇਸ਼ਤਾ ਗੱਡੀ ਚਲਾਉਂਦੇ ਸਮੇਂ ਨਹੀਂ ਵਰਤ ਸਕਦੇ"</string>
<string name="exit_button_message" msgid="5375678491245394542">"ਸੁਰੱਖਿਅਤ ਐਪ ਵਿਸ਼ੇਸ਼ਤਾਵਾਂ ਨਾਲ ਮੁੜ ਤੋਂ ਸ਼ੁਰੂ ਕਰਨ ਲਈ, <xliff:g id="EXIT_BUTTON">%s</xliff:g> ਚੁਣੋ।"</string>
<string name="exit_button" msgid="3491899413031549265">"ਪਿੱਛੇ"</string>
diff --git a/service-builtin/res/values-pl/strings.xml b/service-builtin/res/values-pl/strings.xml
index 0994657..775a8be 100644
--- a/service-builtin/res/values-pl/strings.xml
+++ b/service-builtin/res/values-pl/strings.xml
@@ -16,6 +16,14 @@
<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_bind_projection_service" msgid="5362076216606651526">"powiązanie z usługą wyświetlania treści"</string>
+<string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"Zezwala na tworzenie powiązania z interfejsem najwyższego poziomu usługi projekcji. Nie powinno być nigdy potrzebne w przypadku zwykłych aplikacji."</string>
+<string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"Usługa klienta VMS"</string>
+<string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"Powiązanie z klientami VMS"</string>
+<string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"Renderowanie w klastrze przyrządów"</string>
+<string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"Otrzymywanie danych o klastrze przyrządów"</string>
+<string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Usługa wprowadzania danych w samochodzie"</string>
+<string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Obsługa zdarzeń wprowadzania danych"</string>
<string name="activity_blocked_text" msgid="5991043857905412794">"Podczas jazdy nie można korzystać z tej funkcji"</string>
<string name="exit_button_message" msgid="5375678491245394542">"Aby jeszcze raz przejść do funkcji bezpieczeństwa w aplikacji, wybierz <xliff:g id="EXIT_BUTTON">%s</xliff:g>."</string>
<string name="exit_button" msgid="3491899413031549265">"Wstecz"</string>
diff --git a/service-builtin/res/values-pt-rPT/strings.xml b/service-builtin/res/values-pt-rPT/strings.xml
index 339d88a..750efba 100644
--- a/service-builtin/res/values-pt-rPT/strings.xml
+++ b/service-builtin/res/values-pt-rPT/strings.xml
@@ -16,6 +16,14 @@
<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_bind_projection_service" msgid="5362076216606651526">"vincular a um serviço de projeção"</string>
+<string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"Permite que o titular se vincule à interface de nível superior de um serviço de projeção. Nunca deverá ser necessário para aplicações normais."</string>
+<string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"Serviço de cliente VMS"</string>
+<string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"Vincular a clientes VMS"</string>
+<string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"Renderização do cluster do instrumento"</string>
+<string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"Receba os dados do cluster do instrumento."</string>
+<string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Serviço de entrada do automóvel"</string>
+<string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Processe eventos de entrada."</string>
<string name="activity_blocked_text" msgid="5991043857905412794">"Não pode usar esta funcionalidade enquanto conduz"</string>
<string name="exit_button_message" msgid="5375678491245394542">"Para começar de novo com funcionalidades de aplicações seguras, selecione <xliff:g id="EXIT_BUTTON">%s</xliff:g>."</string>
<string name="exit_button" msgid="3491899413031549265">"Anterior"</string>
diff --git a/service-builtin/res/values-pt/strings.xml b/service-builtin/res/values-pt/strings.xml
index 35afede..93f47e4 100644
--- a/service-builtin/res/values-pt/strings.xml
+++ b/service-builtin/res/values-pt/strings.xml
@@ -16,6 +16,14 @@
<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_bind_projection_service" msgid="5362076216606651526">"vincular um serviço de projeção"</string>
+<string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"Permite que o proprietário vincule a interface de nível superior de um serviço de projeção. Nunca deve ser necessário para apps normais."</string>
+<string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"Serviço de cliente VMS"</string>
+<string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"Vincular clientes VMS"</string>
+<string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"Renderização de cluster de instrumento"</string>
+<string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"Receber dados do cluster de instrumento"</string>
+<string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Serviço de entrada do carro"</string>
+<string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Gerenciar eventos de entrada"</string>
<string name="activity_blocked_text" msgid="5991043857905412794">"Não é possível usar esse recurso enquanto você dirige"</string>
<string name="exit_button_message" msgid="5375678491245394542">"Para reiniciar o app com recursos de segurança, selecione <xliff:g id="EXIT_BUTTON">%s</xliff:g>."</string>
<string name="exit_button" msgid="3491899413031549265">"Voltar"</string>
diff --git a/service-builtin/res/values-ro/strings.xml b/service-builtin/res/values-ro/strings.xml
index 816594b..9b13111 100644
--- a/service-builtin/res/values-ro/strings.xml
+++ b/service-builtin/res/values-ro/strings.xml
@@ -16,6 +16,14 @@
<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_bind_projection_service" msgid="5362076216606651526">"Se conectează la un serviciu de proiecție"</string>
+<string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"Permite proprietarului să se conecteze la interfața de nivel superior a unui serviciu de proiecție. Nu ar trebui să fie niciodată necesară pentru aplicațiile obișnuite"</string>
+<string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"Serviciu client VMS"</string>
+<string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"Se conectează la clienții VMS"</string>
+<string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"Redarea grupurilor de instrumente"</string>
+<string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"Primiți date despre grupul de instrumente"</string>
+<string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Gestionează serviciul de intrare pentru mașină"</string>
+<string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Gestionează evenimentele de intrare"</string>
<string name="activity_blocked_text" msgid="5991043857905412794">"Nu puteți folosi această funcție în timp ce conduceți"</string>
<string name="exit_button_message" msgid="5375678491245394542">"Pentru a începe din nou cu funcțiile pentru aplicații sigure, selectați <xliff:g id="EXIT_BUTTON">%s</xliff:g>."</string>
<string name="exit_button" msgid="3491899413031549265">"Înapoi"</string>
diff --git a/service-builtin/res/values-ru/strings.xml b/service-builtin/res/values-ru/strings.xml
index a3888e2..58af8e3 100644
--- a/service-builtin/res/values-ru/strings.xml
+++ b/service-builtin/res/values-ru/strings.xml
@@ -16,6 +16,14 @@
<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_bind_projection_service" msgid="5362076216606651526">"подключение к сервису проекции"</string>
+<string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"Приложение сможет подключаться к базовому интерфейсу сервиса проекции. Это разрешение не используется обычными приложениями."</string>
+<string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"VMS-клиент"</string>
+<string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"Подключение к VMS-клиентам"</string>
+<string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"Визуализация данных на приборной панели"</string>
+<string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"Возможность получать данные с приборной панели"</string>
+<string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Автомобильная служба ввода"</string>
+<string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Возможность обрабатывать события ввода"</string>
<string name="activity_blocked_text" msgid="5991043857905412794">"Эту функцию нельзя использовать во время вождения."</string>
<string name="exit_button_message" msgid="5375678491245394542">"Чтобы перезапустить приложение в безопасном режиме, нажмите кнопку \"<xliff:g id="EXIT_BUTTON">%s</xliff:g>\"."</string>
<string name="exit_button" msgid="3491899413031549265">"Назад"</string>
diff --git a/service-builtin/res/values-si/strings.xml b/service-builtin/res/values-si/strings.xml
index eb2c686..73268f1 100644
--- a/service-builtin/res/values-si/strings.xml
+++ b/service-builtin/res/values-si/strings.xml
@@ -16,6 +16,14 @@
<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_bind_projection_service" msgid="5362076216606651526">"ප්රක්ෂේපණ සේවාවකට බඳින්න"</string>
+<string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"ප්රක්ෂේපණ සේවාවක ඉහළ-මට්ටමේ අතුරු මුහුණතට බැඳීමට ධාරකයට ඉඩ දෙයි. සාමාන්ය යෙදුම්වලට කිසි විටෙක අවශ්ය නොවෙයි."</string>
+<string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"VMS සේවාලාභී සේවාව"</string>
+<string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"VMS සේවාලාභීන්ට බඳින්න"</string>
+<string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"උපකරණ කලප් විදහීම"</string>
+<string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"උපකරණ කලප් දත්ත ලබා ගන්න"</string>
+<string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"මෝටර් රථ ආදාන සේවය"</string>
+<string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"ආදාන සිදුවීම් පරිහරණ කරන්න"</string>
<string name="activity_blocked_text" msgid="5991043857905412794">"රිය පදවන අතරතුර ඔබට මෙම විශේෂාංගය භාවිත කළ නොහැකිය"</string>
<string name="exit_button_message" msgid="5375678491245394542">"ආරක්ෂිත යෙදුම් විශේෂාංග සමඟ පටන් ගැනීමට, <xliff:g id="EXIT_BUTTON">%s</xliff:g> තෝරන්න."</string>
<string name="exit_button" msgid="3491899413031549265">"ආපසු"</string>
diff --git a/service-builtin/res/values-sk/strings.xml b/service-builtin/res/values-sk/strings.xml
index 743fb6e..21eee31 100644
--- a/service-builtin/res/values-sk/strings.xml
+++ b/service-builtin/res/values-sk/strings.xml
@@ -16,6 +16,14 @@
<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_bind_projection_service" msgid="5362076216606651526">"naviazať sa na premietaciu službu"</string>
+<string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"Umožňuje držiteľovi naviazať sa na najvyššiu úroveň rozhrania premietacej služby. Bežné aplikácie by toto nastavenie nemali nikdy potrebovať."</string>
+<string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"Klientska služba VMS"</string>
+<string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"Naviazať sa na klienty VMS"</string>
+<string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"Vykresľovanie klastra prístrojov"</string>
+<string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"Získavať údaje o klastri prístrojov"</string>
+<string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Služba vstupov auta"</string>
+<string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Spravovať udalosti vstupu"</string>
<string name="activity_blocked_text" msgid="5991043857905412794">"Túto funkciu nie je možné používať za jazdy"</string>
<string name="exit_button_message" msgid="5375678491245394542">"Ak chcete začať odznova s bezpečnými funkciami aplikácie, vyberte tlačidlo <xliff:g id="EXIT_BUTTON">%s</xliff:g>."</string>
<string name="exit_button" msgid="3491899413031549265">"Späť"</string>
diff --git a/service-builtin/res/values-sl/strings.xml b/service-builtin/res/values-sl/strings.xml
index 0b16789..b0386ac 100644
--- a/service-builtin/res/values-sl/strings.xml
+++ b/service-builtin/res/values-sl/strings.xml
@@ -16,6 +16,14 @@
<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_bind_projection_service" msgid="5362076216606651526">"povezava s storitvijo projiciranja"</string>
+<string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"Imetniku omogoča povezovanje z vmesnikom storitve projiciranja najvišje ravni. Tega ni treba nikoli uporabiti za navadne aplikacije."</string>
+<string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"Storitev odjemalca VMS"</string>
+<string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"Povezovanje z odjemalci VMS"</string>
+<string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"Upodobitev instrumentne plošče"</string>
+<string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"Prejemanje podatkov instrumentne plošče"</string>
+<string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Storitev za vhode avtomobila"</string>
+<string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Obravnava dogodkov vnosa"</string>
<string name="activity_blocked_text" msgid="5991043857905412794">"Te funkcije med vožnjo ne morete uporabljati"</string>
<string name="exit_button_message" msgid="5375678491245394542">"Če želite začeti znova z varnimi funkcijami aplikacij, izberite <xliff:g id="EXIT_BUTTON">%s</xliff:g>."</string>
<string name="exit_button" msgid="3491899413031549265">"Nazaj"</string>
diff --git a/service-builtin/res/values-sq/strings.xml b/service-builtin/res/values-sq/strings.xml
index 334718f..a1ff722 100644
--- a/service-builtin/res/values-sq/strings.xml
+++ b/service-builtin/res/values-sq/strings.xml
@@ -16,6 +16,14 @@
<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_bind_projection_service" msgid="5362076216606651526">"lidhu me një shërbim projektimi"</string>
+<string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"Lejon që mbajtësi të lidhet me ndërfaqen e nivelit të lartë të një shërbimi projektimi. Nuk duhet të nevojitet ndonjëherë për aplikacionet normale."</string>
+<string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"Shërbimi i klientit i VMS-së"</string>
+<string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"Lidh me klientët VMS"</string>
+<string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"Interpretimi i grupimit të instrumenteve"</string>
+<string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"Merr të dhënat e grupimit të instrumenteve"</string>
+<string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Shërbimi i hyrjes së makinës"</string>
+<string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Menaxho ngjarjet e hyrjes"</string>
<string name="activity_blocked_text" msgid="5991043857905412794">"Nuk mund ta përdorësh këtë veçori gjatë drejtimit të makinës"</string>
<string name="exit_button_message" msgid="5375678491245394542">"Për të filluar nga e para me funksionet e sigurta të aplikacionit, zgjidh <xliff:g id="EXIT_BUTTON">%s</xliff:g>."</string>
<string name="exit_button" msgid="3491899413031549265">"Prapa"</string>
diff --git a/service-builtin/res/values-sr/strings.xml b/service-builtin/res/values-sr/strings.xml
index deb1954..1588dde 100644
--- a/service-builtin/res/values-sr/strings.xml
+++ b/service-builtin/res/values-sr/strings.xml
@@ -16,6 +16,14 @@
<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_bind_projection_service" msgid="5362076216606651526">"повезивање са услугом пројекције"</string>
+<string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"Дозвољава власнику да се повеже са интерфејсом услуге пројекције највишег нивоа. Уобичајене апликације никада не би требало да је користе."</string>
+<string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"VMS услуга за клијенте"</string>
+<string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"Повезује са VMS клијентима"</string>
+<string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"Приказивање на инструмент табли"</string>
+<string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"Прима податке са инструмент табле"</string>
+<string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Услуга аутомобилског уноса"</string>
+<string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Управља догађајима уноса"</string>
<string name="activity_blocked_text" msgid="5991043857905412794">"Не можете да користите ову функцију док возите"</string>
<string name="exit_button_message" msgid="5375678491245394542">"Да бисте поново почели са безбедним функцијама апликације, изаберите <xliff:g id="EXIT_BUTTON">%s</xliff:g>."</string>
<string name="exit_button" msgid="3491899413031549265">"Назад"</string>
diff --git a/service-builtin/res/values-sv/strings.xml b/service-builtin/res/values-sv/strings.xml
index 79d1f9f..1b26ed8 100644
--- a/service-builtin/res/values-sv/strings.xml
+++ b/service-builtin/res/values-sv/strings.xml
@@ -16,6 +16,14 @@
<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_bind_projection_service" msgid="5362076216606651526">"bind till projektionstjänst"</string>
+<string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"Innehavaren tillåts att binda till den översta nivåns gränssnitt för en projektionstjänst. Ska inte behövas för vanliga appar."</string>
+<string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"VMS-klienttjänst"</string>
+<string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"Bind till VMS-klienter"</string>
+<string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"Rendering på digital instrumentbräda"</string>
+<string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"Ta emot data från bilens digitala instrumentbräda"</string>
+<string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Indatatjänst för bilen"</string>
+<string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Hantera indatahändelser"</string>
<string name="activity_blocked_text" msgid="5991043857905412794">"Du kan inte använda funktionen medan du kör"</string>
<string name="exit_button_message" msgid="5375678491245394542">"Välj <xliff:g id="EXIT_BUTTON">%s</xliff:g> om du vill starta om appen med säkra funktioner."</string>
<string name="exit_button" msgid="3491899413031549265">"Tillbaka"</string>
diff --git a/service-builtin/res/values-sw/strings.xml b/service-builtin/res/values-sw/strings.xml
index 841d4f3..1003cda 100644
--- a/service-builtin/res/values-sw/strings.xml
+++ b/service-builtin/res/values-sw/strings.xml
@@ -16,6 +16,14 @@
<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_bind_projection_service" msgid="5362076216606651526">"kupachika kwenye huduma ya kuonyesha skrini"</string>
+<string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"Inaruhusu kishikiliaji kipachikwe katika kiolesura cha kiwango cha juu cha huduma ya kuonyesha. Haipaswi kuhitajika katika programu za kawaida."</string>
+<string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"Huduma ya Viteja vya VMS"</string>
+<string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"Ipachike kwenye viteja vya VMS"</string>
+<string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"Uwasilishaji wa Kikundi cha Zana"</string>
+<string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"Kupokea data ya kikundi cha zana"</string>
+<string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Huduma ya Kuweka Data ya Gari"</string>
+<string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Kudhibiti matukio ya kuweka data"</string>
<string name="activity_blocked_text" msgid="5991043857905412794">"Huwezi kutumia kipengele hiki wakati unaendesha gari"</string>
<string name="exit_button_message" msgid="5375678491245394542">"Ili uanzishe tena ukitumia vipengele salama vya programu, chagua <xliff:g id="EXIT_BUTTON">%s</xliff:g>."</string>
<string name="exit_button" msgid="3491899413031549265">"Rudi Nyuma"</string>
diff --git a/service-builtin/res/values-ta/strings.xml b/service-builtin/res/values-ta/strings.xml
index 27abf0d..aa8f5a6 100644
--- a/service-builtin/res/values-ta/strings.xml
+++ b/service-builtin/res/values-ta/strings.xml
@@ -16,6 +16,14 @@
<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_bind_projection_service" msgid="5362076216606651526">"காட்சிப்படுத்தல் சேவையுடன் இணைக்க வேண்டும்"</string>
+<string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"காட்சிப்படுத்தல் சேவையின் உயர் நிலை இடைமுகத்துடன் இணைப்பதற்கு ஹோல்டரை அனுமதிக்கிறது. வழக்கமான ஆப்ஸிற்கு எப்போதுமே தேவைப்படாது."</string>
+<string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"VMS கிளையண்ட் சேவை"</string>
+<string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"VMS கிளையண்ட்டுகளுடன் இணைத்தல்"</string>
+<string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"இன்ஸ்ட்ருமெண்ட் கிளஸ்டரை ஒழுங்கமைத்தல்"</string>
+<string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"இன்ஸ்ட்ருமெண்ட் கிளஸ்டர் தரவைப் பெறுதல்"</string>
+<string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"காருக்கு உற்பத்தியாளர் வழங்கும் சேவை"</string>
+<string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"உற்பத்தியாளர் வழங்கும் சேவைகளைக் கையாளுதல்"</string>
<string name="activity_blocked_text" msgid="5991043857905412794">"வாகனம் ஓட்டும்போது இந்த அம்சத்தைப் பயன்படுத்த முடியாது"</string>
<string name="exit_button_message" msgid="5375678491245394542">"ஆப்ஸைப் பாதுகாப்பான அம்சங்களுடன் மீண்டும் தொடங்க <xliff:g id="EXIT_BUTTON">%s</xliff:g>ஐத் தேர்ந்தெடுக்கவும்."</string>
<string name="exit_button" msgid="3491899413031549265">"பின்செல்"</string>
diff --git a/service-builtin/res/values-te/strings.xml b/service-builtin/res/values-te/strings.xml
index 3660982..0926348 100644
--- a/service-builtin/res/values-te/strings.xml
+++ b/service-builtin/res/values-te/strings.xml
@@ -16,6 +16,14 @@
<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_bind_projection_service" msgid="5362076216606651526">"ప్రొజెక్షన్ సేవకు అనుబంధించగలవు"</string>
+<string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"ప్రొజెక్షన్ సేవ యొక్క అగ్ర-స్థాయి ఇంటర్ఫేస్కు అనుబంధించడానికి హోల్డర్ను అనుమతిస్తుంది. సాధారణ యాప్లకు ఎప్పటికీ దీని అవసరం లేదు."</string>
+<string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"VMS క్లయింట్ సేవ"</string>
+<string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"VMS క్లయింట్లను ఆచరించండి"</string>
+<string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"పరికర గుంపు రెండరింగ్"</string>
+<string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"పరికర గుంపు డేటాను పొందండి"</string>
+<string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"కారు ఇన్పుట్ సేవ"</string>
+<string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"ఇన్పుట్ ఈవెంట్లను హ్యాండిల్ చేయండి"</string>
<string name="activity_blocked_text" msgid="5991043857905412794">"డ్రైవింగ్లో ఉండగా మీరు ఈ ఫీచర్ను ఉపయోగించలేరు"</string>
<string name="exit_button_message" msgid="5375678491245394542">"సురక్షిత యాప్ లక్షణాలతో ప్రారంభించడానికి, <xliff:g id="EXIT_BUTTON">%s</xliff:g>ని ఎంచుకోండి."</string>
<string name="exit_button" msgid="3491899413031549265">"వెనుకకు"</string>
diff --git a/service-builtin/res/values-th/strings.xml b/service-builtin/res/values-th/strings.xml
index 996e461..95f175c 100644
--- a/service-builtin/res/values-th/strings.xml
+++ b/service-builtin/res/values-th/strings.xml
@@ -16,6 +16,14 @@
<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_bind_projection_service" msgid="5362076216606651526">"เชื่อมโยงกับบริการการฉายภาพ"</string>
+<string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"อนุญาตให้เจ้าของเชื่อมโยงกับอินเทอร์เฟซระดับบนสุดของบริการการฉายภาพ ไม่ควรต้องใช้สำหรับแอปทั่วไป"</string>
+<string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"บริการไคลเอ็นต์ VMS"</string>
+<string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"เชื่อมโยงกับไคลเอ็นต์ VMS"</string>
+<string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"การแสดงผลแผงหน้าปัด"</string>
+<string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"รับข้อมูลจากแผงหน้าปัด"</string>
+<string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"บริการป้อนข้อมูลของรถ"</string>
+<string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"จัดการเหตุการณ์การป้อนข้อมูล"</string>
<string name="activity_blocked_text" msgid="5991043857905412794">"คุณใช้ฟีเจอร์นี้ขณะขับรถไม่ได้"</string>
<string name="exit_button_message" msgid="5375678491245394542">"เลือก <xliff:g id="EXIT_BUTTON">%s</xliff:g> เพื่อเริ่มต้นใหม่โดยใช้ฟีเจอร์แอปที่ปลอดภัย"</string>
<string name="exit_button" msgid="3491899413031549265">"กลับ"</string>
diff --git a/service-builtin/res/values-tl/strings.xml b/service-builtin/res/values-tl/strings.xml
index cbd4367..00047e7 100644
--- a/service-builtin/res/values-tl/strings.xml
+++ b/service-builtin/res/values-tl/strings.xml
@@ -16,6 +16,14 @@
<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_bind_projection_service" msgid="5362076216606651526">"sumailalim sa isang serbisyo sa projection"</string>
+<string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"Binibigyang-daan ang may-ari na sumailalim sa nangungunang interface ng isang serbisyo sa projection. Hindi kailanman dapat na kailanganin para sa mga karaniwang app."</string>
+<string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"Serbisyo ng VMS Client"</string>
+<string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"Sumailalim sa mga VMS client"</string>
+<string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"Pag-render ng Cluster ng Instrumento"</string>
+<string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"Makatanggap ng data ng cluster ng instrumento"</string>
+<string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Serbisyo sa Input ng Sasakyan"</string>
+<string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Pangasiwaan ang mga event ng input"</string>
<string name="activity_blocked_text" msgid="5991043857905412794">"Hindi mo puwedeng gamitin ang feature na ito habang nagmamaneho"</string>
<string name="exit_button_message" msgid="5375678491245394542">"Para magsimula sa mga ligtas na feature ng app, piliin ang <xliff:g id="EXIT_BUTTON">%s</xliff:g>."</string>
<string name="exit_button" msgid="3491899413031549265">"Bumalik"</string>
diff --git a/service-builtin/res/values-tr/strings.xml b/service-builtin/res/values-tr/strings.xml
index fc1068f..4fb708a 100644
--- a/service-builtin/res/values-tr/strings.xml
+++ b/service-builtin/res/values-tr/strings.xml
@@ -16,6 +16,14 @@
<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_bind_projection_service" msgid="5362076216606651526">"projeksiyon hizmetine bağlanma"</string>
+<string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"Cihazın sahibine bir projeksiyon hizmetinin en üst düzey arayüzüne bağlanma izni verir. Normal uygulamalarda hiçbir zaman gerek duyulmaz."</string>
+<string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"VMS İstemci Hizmeti"</string>
+<string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"VMS istemcilerine bağla"</string>
+<string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"Gösterge Grubunda Oluşturma"</string>
+<string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"Gösterge grubu verilerini alma"</string>
+<string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Araç Giriş Hizmeti"</string>
+<string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Giriş olaylarını işleme"</string>
<string name="activity_blocked_text" msgid="5991043857905412794">"Sürüş sırasında bu özelliği kullanamazsınız"</string>
<string name="exit_button_message" msgid="5375678491245394542">"Güvenli uygulama özellikleriyle baştan başlamak için <xliff:g id="EXIT_BUTTON">%s</xliff:g> düğmesini seçin."</string>
<string name="exit_button" msgid="3491899413031549265">"Geri"</string>
diff --git a/service-builtin/res/values-uk/strings.xml b/service-builtin/res/values-uk/strings.xml
index 031476a..91f75e7 100644
--- a/service-builtin/res/values-uk/strings.xml
+++ b/service-builtin/res/values-uk/strings.xml
@@ -16,6 +16,14 @@
<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_bind_projection_service" msgid="5362076216606651526">"зв’язок із сервісом проекції"</string>
+<string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"Дозволяє власникові прив’язуватися до інтерфейсу верхнього рівня сервісу проекції. Ніколи не застосовується для звичайних додатків."</string>
+<string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"Виконувати функції клієнтського сервісу дорожніх повідомлень"</string>
+<string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"Зв’язуватися з клієнтами дорожніх повідомлень"</string>
+<string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"Відображення панелі приладів"</string>
+<string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"Отримувати дані з панелі приладів"</string>
+<string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Сервіс даних про вхідні події автомобіля"</string>
+<string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Обробка вхідних подій"</string>
<string name="activity_blocked_text" msgid="5991043857905412794">"Ця функція недоступна під час руху"</string>
<string name="exit_button_message" msgid="5375678491245394542">"Щоб почати знову з безпечними функціями додатка, натисніть кнопку \"<xliff:g id="EXIT_BUTTON">%s</xliff:g>\"."</string>
<string name="exit_button" msgid="3491899413031549265">"Назад"</string>
diff --git a/service-builtin/res/values-ur/strings.xml b/service-builtin/res/values-ur/strings.xml
index ea51901..3ba9396 100644
--- a/service-builtin/res/values-ur/strings.xml
+++ b/service-builtin/res/values-ur/strings.xml
@@ -16,6 +16,14 @@
<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_bind_projection_service" msgid="5362076216606651526">"کسی پروجیکشن سروس کا پابند بنیں"</string>
+<string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"حامل کو پروجیکشن سروس کے اعلی سطحی انٹرفیس کا پابند ہونے کی اجازت دیتا ہے۔ عام ایپس کے لیے کبھی بھی اس کی ضرورت نہيں ہونی چاہئے۔"</string>
+<string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"VMS کلائنٹ سروس"</string>
+<string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"VMS کلائنٹس کا پابند بنیں"</string>
+<string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"آلہ کے گروہ کی رینڈرنگ"</string>
+<string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"آلہ کے گروہ کا ڈیٹا موصول کریں"</string>
+<string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"کار کی ان پٹ سروس"</string>
+<string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"ایونٹس کے ان پٹ کو ہینڈل کریں"</string>
<string name="activity_blocked_text" msgid="5991043857905412794">"ڈرائیونگ کے دوران آپ یہ خصوصیت استعمال نہیں کر سکتے"</string>
<string name="exit_button_message" msgid="5375678491245394542">"محفوظ اپپ کی خصوصیات کے ساتھ شروع کرنے کے لیے <xliff:g id="EXIT_BUTTON">%s</xliff:g> پر کلک کریں۔"</string>
<string name="exit_button" msgid="3491899413031549265">"پیچھے"</string>
diff --git a/service-builtin/res/values-uz/strings.xml b/service-builtin/res/values-uz/strings.xml
index 5a7d0e3..63086d4 100644
--- a/service-builtin/res/values-uz/strings.xml
+++ b/service-builtin/res/values-uz/strings.xml
@@ -16,6 +16,14 @@
<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_bind_projection_service" msgid="5362076216606651526">"proyeksiya xizmatiga ulanish"</string>
+<string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"Proyeksiya xizmatining yuqori darajali interfeysiga ulana oladi. Oddiy ilovalar tomonidan ishlatilmaydi."</string>
+<string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"VMS mijoz xizmati"</string>
+<string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"VMS mijozlarga ulanish"</string>
+<string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"Axborotlarni asboblar paneliga chiqarish"</string>
+<string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"Asboblar panelidan axborotlarni olish"</string>
+<string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Avtomobilda matn kiritish xizmati"</string>
+<string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Matn kiritish hodisalari bilan ishlash imkoniyati"</string>
<string name="activity_blocked_text" msgid="5991043857905412794">"Avtomobilda harakatlanayotganda bu funksiyadan foydalanish imkonsiz"</string>
<string name="exit_button_message" msgid="5375678491245394542">"Ilovani xavfsiz rejimda ishga tushirish uchun <xliff:g id="EXIT_BUTTON">%s</xliff:g> tugmasini bosing."</string>
<string name="exit_button" msgid="3491899413031549265">"Orqaga"</string>
diff --git a/service-builtin/res/values-vi/strings.xml b/service-builtin/res/values-vi/strings.xml
index d3ebbdf..bbbdb67 100644
--- a/service-builtin/res/values-vi/strings.xml
+++ b/service-builtin/res/values-vi/strings.xml
@@ -16,6 +16,14 @@
<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_bind_projection_service" msgid="5362076216606651526">"liên kết với dịch vụ chiếu"</string>
+<string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"Cho phép khung liên kết với giao diện cấp cao nhất của dịch vụ chiếu. Điều này không cần thiết đối với các ứng dụng thông thường."</string>
+<string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"Dịch vụ ứng dụng VMS"</string>
+<string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"Liên kết với ứng dụng VMS"</string>
+<string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"Hiển thị nhóm dụng cụ"</string>
+<string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"Nhận dữ liệu nhóm dụng cụ"</string>
+<string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Dịch vụ nhập dành cho ô tô"</string>
+<string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Xử lý sự kiện nhập"</string>
<string name="activity_blocked_text" msgid="5991043857905412794">"Bạn không thể dùng tính năng này khi đang lái xe"</string>
<string name="exit_button_message" msgid="5375678491245394542">"Để bắt đầu lại với các tính năng an toàn của ứng dụng, hãy chọn <xliff:g id="EXIT_BUTTON">%s</xliff:g>."</string>
<string name="exit_button" msgid="3491899413031549265">"Quay lại"</string>
diff --git a/service-builtin/res/values-zh-rCN/strings.xml b/service-builtin/res/values-zh-rCN/strings.xml
index 7ec3841..692987b 100644
--- a/service-builtin/res/values-zh-rCN/strings.xml
+++ b/service-builtin/res/values-zh-rCN/strings.xml
@@ -16,6 +16,14 @@
<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_bind_projection_service" msgid="5362076216606651526">"绑定到投影服务"</string>
+<string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"允许应用绑定到投影服务的顶级接口。普通应用绝不需要此权限。"</string>
+<string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"VMS 客户端服务"</string>
+<string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"绑定到 VMS 客户端"</string>
+<string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"仪表板呈现"</string>
+<string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"接收仪表板数据"</string>
+<string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"汽车输入服务"</string>
+<string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"处理输入事件"</string>
<string name="activity_blocked_text" msgid="5991043857905412794">"您不能在驾车时使用此功能"</string>
<string name="exit_button_message" msgid="5375678491245394542">"要重新开始使用安全的应用功能,请选择<xliff:g id="EXIT_BUTTON">%s</xliff:g>。"</string>
<string name="exit_button" msgid="3491899413031549265">"返回"</string>
diff --git a/service-builtin/res/values-zh-rHK/strings.xml b/service-builtin/res/values-zh-rHK/strings.xml
index 16091eb..a22eff4 100644
--- a/service-builtin/res/values-zh-rHK/strings.xml
+++ b/service-builtin/res/values-zh-rHK/strings.xml
@@ -16,6 +16,14 @@
<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_bind_projection_service" msgid="5362076216606651526">"繫結至投射服務"</string>
+<string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"允許應用程式繫結至投射服務的頂層介面 (不建議一般應用程式使用)。"</string>
+<string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"交通訊息顯示屏用戶端服務"</string>
+<string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"繫結至交通訊息顯示屏用戶端"</string>
+<string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"正在輸出儀表板"</string>
+<string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"接收儀表板資料"</string>
+<string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"汽車輸入服務"</string>
+<string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"處理輸入活動"</string>
<string name="activity_blocked_text" msgid="5991043857905412794">"您無法在駕駛時使用此功能"</string>
<string name="exit_button_message" msgid="5375678491245394542">"如要以安全應用程式功能重新啟動,請選擇 <xliff:g id="EXIT_BUTTON">%s</xliff:g>。"</string>
<string name="exit_button" msgid="3491899413031549265">"返回"</string>
diff --git a/service-builtin/res/values-zh-rTW/strings.xml b/service-builtin/res/values-zh-rTW/strings.xml
index ec4fc88..3ab9c2b 100644
--- a/service-builtin/res/values-zh-rTW/strings.xml
+++ b/service-builtin/res/values-zh-rTW/strings.xml
@@ -16,6 +16,14 @@
<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_bind_projection_service" msgid="5362076216606651526">"繫結至投影服務"</string>
+<string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"允許應用程式繫結至投放服務的頂層介面 (一般應用程式並不需要)。"</string>
+<string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"VMS 用戶端服務"</string>
+<string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"繫結至 VMS 用戶端"</string>
+<string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"儀錶板轉譯"</string>
+<string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"接收儀錶板資料"</string>
+<string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"車輛輸入服務"</string>
+<string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"處理輸入事件"</string>
<string name="activity_blocked_text" msgid="5991043857905412794">"開車時無法使用這項功能"</string>
<string name="exit_button_message" msgid="5375678491245394542">"如要使用安全應用程式功能重新啟動,請選取「離開」按鈕 <xliff:g id="EXIT_BUTTON">%s</xliff:g>。"</string>
<string name="exit_button" msgid="3491899413031549265">"返回"</string>
diff --git a/service-builtin/res/values-zu/strings.xml b/service-builtin/res/values-zu/strings.xml
index be740b0..3f9c536 100644
--- a/service-builtin/res/values-zu/strings.xml
+++ b/service-builtin/res/values-zu/strings.xml
@@ -16,6 +16,14 @@
<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_bind_projection_service" msgid="5362076216606651526">"bophezela kusevisi yokuphrojekthwa"</string>
+<string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"Ivumela umbambi ukuthi aboshezelwe kusixhumi esibonakalayo seleveli ephezulu yesevisi yokuphrojektha. Akumele kudingelwe izinhlelo zokusebenza ezijwayelekile."</string>
+<string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"Isevisi yeklayenti le-VMS"</string>
+<string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"Bophezela kumaklayenti e-VMS"</string>
+<string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"Ukusebenzisa into yokusebenza"</string>
+<string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"Thola idatha yento yokusebenza"</string>
+<string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Isevisi yokufaka yemoto"</string>
+<string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Phatha imicimbi yokungena"</string>
<string name="activity_blocked_text" msgid="5991043857905412794">"Awukwazi ukusebenzisa lesi sakhi ngenkathi ushayela"</string>
<string name="exit_button_message" msgid="5375678491245394542">"Ukuze uqalise futhi ngezici zohlelo lokusebenza, khetha <xliff:g id="EXIT_BUTTON">%s</xliff:g>."</string>
<string name="exit_button" msgid="3491899413031549265">"Emuva"</string>
diff --git a/service-builtin/res/values/strings.xml b/service-builtin/res/values/strings.xml
index d6d2d0d..e15b970 100644
--- a/service-builtin/res/values/strings.xml
+++ b/service-builtin/res/values/strings.xml
@@ -16,6 +16,24 @@
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_title" translatable="false">Car service</string>
+ <!-- Permission text: allows framework to bind to the services in projection apps[CHAR LIMIT=NONE] -->
+ <string name="car_permission_label_bind_projection_service">bind to a projection service</string>
+ <!-- Permission text: allows framework to bind to the services in projection apps[CHAR LIMIT=NONE] -->
+ <string name="car_permission_desc_bind_projection_service">Allows the holder to bind to the top-level interface of a projection service. Should never be needed for normal apps."</string>
+
+ <!-- Permission text: apps can act as VMS router core [CHAR LIMIT=NONE] -->
+ <string name="car_permission_label_bind_vms_client">VMS Client Service</string>
+ <!-- Permission text: apps can act as VMS router core [CHAR LIMIT=NONE] -->
+ <string name="car_permission_desc_bind_vms_client">Bind to VMS clients</string>
+
+ <string name="car_permission_label_bind_instrument_cluster_rendering">Instrument Cluster Rendering</string>
+ <string name="car_permission_desc_bind_instrument_cluster_rendering">Receive instrument cluster data</string>
+
+ <!-- Permission text: apps can handle input events [CHAR LIMIT=NONE] -->
+ <string name="car_permission_label_bind_input_service">Car Input Service</string>
+ <!-- Permission text: apps can handle input events [CHAR LIMIT=NONE] -->
+ <string name="car_permission_desc_bind_input_service">Handle input events</string>
+
<!-- Blocking activity: Message to show to user when a feature of current application is not allowed. [CHAR LIMIT=120] -->
<string name="activity_blocked_text">You can\u2019t use this feature while driving</string>
<!-- Blocking activity: Message to accompany the exit_button that restarts the blocked app. [CHAR LIMIT=120] -->
diff --git a/service-builtin/src/com/android/car/evs/EvsHalWrapperImpl.java b/service-builtin/src/com/android/car/evs/EvsHalWrapperImpl.java
index b427090..5ce35ea 100644
--- a/service-builtin/src/com/android/car/evs/EvsHalWrapperImpl.java
+++ b/service-builtin/src/com/android/car/evs/EvsHalWrapperImpl.java
@@ -83,6 +83,10 @@
@Override
public boolean connectToHalServiceIfNecessary() {
+ if (!isConnected() && !init()) {
+ return false;
+ }
+
return nativeConnectToHalServiceIfNecessary(getNativeHandle());
}
diff --git a/service/Android.bp b/service/Android.bp
index 69807c0..c84c874 100644
--- a/service/Android.bp
+++ b/service/Android.bp
@@ -72,8 +72,8 @@
],
static_libs: [
- "android.automotive.telemetry.internal-V1-java", // ICarTelemetryInternal
- "android.automotive.watchdog.internal-V1-java",
+ "android.automotive.telemetry.internal-V2-java", // ICarTelemetryInternal
+ "android.automotive.watchdog.internal-V2-java",
"android.frameworks.automotive.powerpolicy.internal-V1-java",
"android.hidl.base-V1.0-java",
"android.hardware.automotive.audiocontrol-V1.0-java",
diff --git a/service/AndroidManifest.xml b/service/AndroidManifest.xml
index 9bc49f9..1752eab 100644
--- a/service/AndroidManifest.xml
+++ b/service/AndroidManifest.xml
@@ -217,14 +217,6 @@
android:label="@string/car_permission_label_access_projection_status"
android:description="@string/car_permission_desc_access_projection_status"/>
- <!-- Must be required by projection service to ensure only system can bind to it.
- <p>Protection level: signature
- -->
- <permission android:name="android.car.permission.BIND_PROJECTION_SERVICE"
- android:protectionLevel="signature"
- android:label="@string/car_permission_label_bind_projection_service"
- android:description="@string/car_permission_desc_bind_projection_service"/>
-
<!-- Allows an application to emulate the vehicle HAL for testing purposes.
<p>Protection level: signature|privileged
-->
@@ -361,14 +353,6 @@
android:label="@string/car_permission_label_diag_clear"
android:description="@string/car_permission_desc_diag_clear"/>
- <!-- Must be required by VMS client service to ensure only system can bind to it.
- <p>Protection level: signature
- -->
- <permission android:name="android.car.permission.BIND_VMS_CLIENT"
- android:protectionLevel="signature"
- android:label="@string/car_permission_label_bind_vms_client"
- android:description="@string/car_permission_desc_bind_vms_client"/>
-
<!-- Allows an application to publich VMS messages.
<p>Protection level: signature|privileged
-->
@@ -459,27 +443,11 @@
android:label="@string/car_permission_label_audio_settings"
android:description="@string/car_permission_desc_audio_settings"/>
- <!-- Must be required by instrument cluster service to ensure only system can bind to it.
- <p>Protection level: signature
- -->
<permission android:name="android.car.permission.RECEIVE_CAR_AUDIO_DUCKING_EVENTS"
android:protectionLevel="signature|privileged"
android:label="@string/car_permission_label_receive_ducking"
android:description="@string/car_permission_desc_receive_ducking"/>
- <permission android:name="android.car.permission.BIND_INSTRUMENT_CLUSTER_RENDERER_SERVICE"
- android:protectionLevel="signature"
- android:label="@string/car_permission_label_bind_instrument_cluster_rendering"
- android:description="@string/car_permission_desc_bind_instrument_cluster_rendering"/>
-
- <!-- Allows an application to handle the vehicle input events.
- <p>Protection level: signature
- -->
- <permission android:name="android.car.permission.BIND_CAR_INPUT_SERVICE"
- android:protectionLevel="signature"
- android:label="@string/car_permission_label_bind_input_service"
- android:description="@string/car_permission_desc_bind_input_service"/>
-
<!-- Allows an application to declare activities to be displayed in the instrument cluster.
<p>Protection level: signature|privileged
-->
@@ -939,6 +907,14 @@
android:label="@string/car_permission_label_control_car_app_launch"
android:description="@string/car_permission_desc_control_car_app_launch"/>
+ <!-- Allows an application to set its own thread's scheduling policy and priority.
+ <p>Protection level: signature|privileged
+ -->
+ <permission android:name="android.car.permission.MANAGE_THREAD_PRIORITY"
+ android:protectionLevel="signature|privileged"
+ android:label="@string/car_permission_label_manage_thread_priority"
+ android:description="@string/car_permission_desc_manage_thread_priority"/>
+
<!-- NOTE: when you're adding a new permission, you should edit
cts/tests/tests/permission2/res/raw/automotive_android_manifest.xml accordingly and run
the test with 'atest android.permission2.cts.PermissionPolicyTest' to verify it.
diff --git a/service/OWNERS b/service/OWNERS
index 45b56d8..200f00c 100644
--- a/service/OWNERS
+++ b/service/OWNERS
@@ -3,5 +3,51 @@
kevinme@google.com
salsavage@google.com
twasilczyk@google.com
-ycheo@google.com
-ericjeong@google.com
+
+# ActivityManager
+per-file src/com/android/car/SystemActivityMonitoringService.java = ycheo@google.com
+per-file src/com/android/car/am/* = ycheo@google.com
+per-file src/com/android/car/systeminterface/ActivityManagerInterface.java = ycheo@google.com
+
+# Audio
+per-file src/com/android/car/audio/* = oscarazu@google.com, ericjeong@google.com
+
+# Cluster
+per-file src/com/android/car/cluster/* = ycheo@google.com
+per-file src/com/android/car/hal/ClusterHalService.java = ycheo@google.com
+
+# Input
+per-file src/com/android/car/CarInputService.java = ycheo@google.com
+per-file src/com/android/car/hal/InputHalService.java = ycheo@google.com
+
+# PackageManager
+per-file src/com/android/car/pm/AppBlockingPolicyProxy.java = ycheo@google.com
+per-file src/com/android/car/pm/Car*.java = ycheo@google.com
+per-file src/com/android/car/pm/TEST_MAPPING = ycheo@google.com
+per-file src/com/android/car/pm/WindowDumpParser.java = ycheo@google.com
+
+# Power
+per-file src/com/android/car/garagemode/* = ericjeong@google.com
+per-file src/com/android/car/hal/PowerHalService.java = ericjeong@google.com
+per-file src/com/android/car/power/* = ericjeong@google.com
+per-file src/com/android/car/systeminterface/SystemPowerControlHelper.java = ericjeong@google.com
+per-file src/com/android/car/systeminterface/SystemStateInterface.java = ericjeong@google.com
+per-file src/com/android/car/systeminterface/WakeLockInterface.java = ericjeong@google.com
+
+# StorageMonitor
+per-file src/com/android/car/CarStorageMonitoringService.java = lakshmana@google.com
+per-file src/com/android/car/systeminterface/StorageMonitoringInterface.java = lakshmana@google.com
+
+# System
+per-file src/com/android/car/*VehicleStub.java = ericjeong@google.com
+per-file src/com/android/car/hal/AidlHal*.java = ericjeong@google.com
+per-file src/com/android/car/hal/HidlHal*.java = ericjeong@google.com
+per-file src/com/android/car/hal/HalAreaConfig.java = ericjeong@google.com
+per-file src/com/android/car/hal/HalClient*.java = ericjeong@google.com
+per-file src/com/android/car/hal/HalProp*.java = ericjeong@google.com
+per-file src/com/android/car/hal/VehicleHal.java = ericjeong@google.com
+
+# Watchdog
+per-file proto/android/car/watchdog/* = lakshmana@google.com
+per-file src/com/android/car/os/* = lakshmana@google.com
+per-file src/com/android/car/watchdog/* = lakshmana@google.com
diff --git a/service/proto/android/car/telemetry/metrics_report.proto b/service/proto/android/car/telemetry/metrics_report.proto
new file mode 100644
index 0000000..c885c02
--- /dev/null
+++ b/service/proto/android/car/telemetry/metrics_report.proto
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+syntax = "proto2";
+
+package android.car.telemetry;
+
+option java_package = "com.android.car.telemetry";
+option java_outer_classname = "MetricsReportProto";
+
+// A list of MetricsReportContainers.
+// Used by ResultStore to store multiple reports as a single file.
+message MetricsReportList {
+ repeated MetricsReportContainer report = 1;
+}
+
+// A wrapper around a metrics report. It contains the bytes of a serialized PersistableBundle and
+// information on which Lua callback was used to produce the report.
+message MetricsReportContainer {
+ // Bytes from a serialized PersistableBundle (the metrics report).
+ optional bytes report_bytes = 1;
+
+ // Whether this report is the last report for this MetricsConfig. True if the report is
+ // produced from on_script_finished() Lua callback.
+ optional bool is_last_report = 2;
+}
diff --git a/service/res/values-af/strings.xml b/service/res/values-af/strings.xml
index 249b8a0..f2fe643 100644
--- a/service/res/values-af/strings.xml
+++ b/service/res/values-af/strings.xml
@@ -42,8 +42,6 @@
<string name="car_permission_desc_projection" msgid="2352178999656292944">"Laat \'n program toe om \'n koppelvlak van \'n foon af op die motor se skerm te projekteer."</string>
<string name="car_permission_label_access_projection_status" msgid="4231618890836627402">"toegang tot projeksiestatus"</string>
<string name="car_permission_desc_access_projection_status" msgid="8497351979100616278">"Laat \'n program toe om die status te kry van ander programme wat na die motor se skerm projekteer."</string>
- <string name="car_permission_label_bind_projection_service" msgid="5362076216606651526">"bind aan \'n projeksiediens"</string>
- <string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"Dit laat die houer toe om aan die topvlak-koppelvlak van \'n projeksiediens te bind. Dit behoort nooit vir normale programme nodig te wees nie."</string>
<string name="car_permission_label_audio_volume" msgid="310587969373137690">"beheer motor se oudiovolume"</string>
<string name="car_permission_label_audio_settings" msgid="6524703796944023977">"beheer motor se oudio-instellings"</string>
<string name="car_permission_label_mock_vehicle_hal" msgid="7198852512207405935">"boots voertuig-HAL na"</string>
@@ -62,8 +60,6 @@
<string name="car_permission_desc_car_cluster_control" msgid="9222776665281176031">"Begin programme in die instrumentgroep"</string>
<string name="car_permission_car_monitor_cluster_navigation_state" msgid="7025307242306902441">"Instrumentgroep se navigasiestaat"</string>
<string name="car_permission_desc_car_monitor_cluster_navigation_state" msgid="8745047153878713339">"Luister vir veranderinge aan instrumentgroep se navigasiestaat"</string>
- <string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"Instrumentgroeplewering"</string>
- <string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"Ontvang instrumentgroepdata"</string>
<string name="car_permission_label_car_ux_restrictions_configuration" msgid="6801393970411049725">"UX-beperkingsopstelling"</string>
<string name="car_permission_desc_car_ux_restrictions_configuration" msgid="5711926927484813777">"Stel UX-beperkings op"</string>
<string name="car_permission_label_access_private_display_id" msgid="6712116114341634316">"Leestoegang tot privaat skerm-ID"</string>
@@ -74,8 +70,6 @@
<string name="car_permission_desc_read_car_occupant_awareness_state" msgid="188865882598414986">"Laat toe dat status- en bespeuringsdata vir die insittendebewustheidstelsel gelees word"</string>
<string name="car_permission_label_control_car_occupant_awareness_system" msgid="7163330266691094542">"Beheer insittendebewustheidstelsel se grafiek"</string>
<string name="car_permission_desc_control_car_occupant_awareness_system" msgid="7123482622084531911">"Laat toe dat die begin en einde van die insittendebewustheidstelsel se bespeuringsgrafiek beheer word"</string>
- <string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Motorinvoerdiens"</string>
- <string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Hanteer invoergebeurtenisse"</string>
<string name="car_permission_label_diag_read" msgid="7248894224877702604">"lees diagnostiese data"</string>
<string name="car_permission_desc_diag_read" msgid="1121426363040966178">"Lees diagnostiese data van die motor af."</string>
<string name="car_permission_label_diag_clear" msgid="4783070510879698157">"vee diagnostiese data uit"</string>
@@ -84,8 +78,6 @@
<string name="car_permission_desc_vms_publisher" msgid="5589489298597386828">"Publiseer VMS-boodskappe"</string>
<string name="car_permission_label_vms_subscriber" msgid="5648841182059222299">"VMS-intekenaar"</string>
<string name="car_permission_desc_vms_subscriber" msgid="7551009457847673620">"Teken in op VMS-boodskappe"</string>
- <string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"VMS-kliëntediens"</string>
- <string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"Bind aan VMS-kliënte"</string>
<string name="car_permission_label_storage_monitoring" msgid="2327639346522530549">"Flitsbergingkontrolering"</string>
<string name="car_permission_desc_storage_monitoring" msgid="2075712271139671318">"Monitor flitsberginggebruik"</string>
<string name="car_permission_label_driving_state" msgid="7754624599537393650">"luister na bestuurstaat"</string>
diff --git a/service/res/values-am/strings.xml b/service/res/values-am/strings.xml
index 2b1b74e..e7c95ca 100644
--- a/service/res/values-am/strings.xml
+++ b/service/res/values-am/strings.xml
@@ -42,8 +42,6 @@
<string name="car_permission_desc_projection" msgid="2352178999656292944">"አንድ መተግበሪያ በይነገጽን ከአንድ ስልክ በመኪናው ማሳያ ላይ እንዲልክና እንዲያሳይ ይፈቅድለታል።"</string>
<string name="car_permission_label_access_projection_status" msgid="4231618890836627402">"የመላክና ማሳየት አገልግሎት ሁኔታን ድረስበት"</string>
<string name="car_permission_desc_access_projection_status" msgid="8497351979100616278">"አንድ መተግበሪያ ወደ መኪናው ማሳያ በመላክና ማሳየት ላይ ያሉ የሌሎች መተግበሪያዎችን ሁኔታ እንዲያገኝ ይፈቅድለታል።"</string>
- <string name="car_permission_label_bind_projection_service" msgid="5362076216606651526">"ለየመላክና ማሳየት አገልግሎት የተወሰነ"</string>
- <string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"ያዡ ግቤት ስልቱን ወደ ከፍተኛ-ደረጃ የመላክና ማሳየት አገልግሎት መጠረዝ ይፈቅዳሉ። ለመደበኛ መተግበሪያዎች በፍፁም አያስፈልግም።"</string>
<string name="car_permission_label_audio_volume" msgid="310587969373137690">"የመኪናውን የኦዲዮ ድምፅ መጠን ይቆጣጠሩ"</string>
<string name="car_permission_label_audio_settings" msgid="6524703796944023977">"የመኪናውን የኦዶዮ ቅንብሮች ተቆጣጠር"</string>
<string name="car_permission_label_mock_vehicle_hal" msgid="7198852512207405935">"የመኪና HAL አቅርብ"</string>
@@ -62,8 +60,6 @@
<string name="car_permission_desc_car_cluster_control" msgid="9222776665281176031">"መተግበሪያዎችን በመሣሪያ ስብስብ ውስጥ አስጀምር"</string>
<string name="car_permission_car_monitor_cluster_navigation_state" msgid="7025307242306902441">"የመሣሪያ ስብስብ ዳሰሳ ሁኔታ"</string>
<string name="car_permission_desc_car_monitor_cluster_navigation_state" msgid="8745047153878713339">"የመሣሪያ ስብስብ ዳሰሳ ሁኔታ ለውጦችን ያዳምጡ"</string>
- <string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"የመሣሪያ ስብስብ አቅርቦት"</string>
- <string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"የመሣሪያ ስብስብ ውሂብን ተቀበል"</string>
<string name="car_permission_label_car_ux_restrictions_configuration" msgid="6801393970411049725">"UX ገደቦች ውቅረት"</string>
<string name="car_permission_desc_car_ux_restrictions_configuration" msgid="5711926927484813777">"የUX ገደቦችን ያዋቅሩ"</string>
<string name="car_permission_label_access_private_display_id" msgid="6712116114341634316">"የግል ማሳያ መታወቂያ የንባብ መዳረሻ"</string>
@@ -74,8 +70,6 @@
<string name="car_permission_desc_read_car_occupant_awareness_state" msgid="188865882598414986">"የተሳፋሪ ማስገንዘቢያ ሥርዓት ሁኔታን እና ፈልጎ ማግኛን ውሂብ ማንበብን ያስችላል"</string>
<string name="car_permission_label_control_car_occupant_awareness_system" msgid="7163330266691094542">"የተሳፋሪ ማስገንዘቢያ ሥርዓት ፈልጎ ማወቂያ ግራፍን ይቆጣጠሩ"</string>
<string name="car_permission_desc_control_car_occupant_awareness_system" msgid="7123482622084531911">"የተሳፋሪ ማስገንዘቢያ ሥርዓት ፈልጎ ማወቂያ ግራፍ ማስጀመርን እና ማስቆምን መቆጣጠርን ያስችላል"</string>
- <string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"የመኪና ግቤት አገልግሎት"</string>
- <string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"የግቤት ክስተቶችን ያስተናግዱ"</string>
<string name="car_permission_label_diag_read" msgid="7248894224877702604">"የምርመራ ውሂብን አንብብ"</string>
<string name="car_permission_desc_diag_read" msgid="1121426363040966178">"ከመኪናው ላይ የምርመራ ውሂብን ያንብቡ።"</string>
<string name="car_permission_label_diag_clear" msgid="4783070510879698157">"የምርመራ ውሂብን አጽዳ"</string>
@@ -84,8 +78,6 @@
<string name="car_permission_desc_vms_publisher" msgid="5589489298597386828">"የVMS መልእክቶችን ያትሙ"</string>
<string name="car_permission_label_vms_subscriber" msgid="5648841182059222299">"VMS ደንበኝነት ተመዝጋቢ"</string>
<string name="car_permission_desc_vms_subscriber" msgid="7551009457847673620">"ወደ VMS መልዕክቶች በደንበኝነት ይመዝገቡ"</string>
- <string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"VMS ደንበኛ አገልግሎት"</string>
- <string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"ለ VMS ደንበኞች የተወሰነ"</string>
<string name="car_permission_label_storage_monitoring" msgid="2327639346522530549">"የማከማቻ ቁጥጥር አደራረግ ብልጭታ"</string>
<string name="car_permission_desc_storage_monitoring" msgid="2075712271139671318">"የብልጭታ ማከማቻ አጠቃቀምን ይቆጣጠሩ"</string>
<string name="car_permission_label_driving_state" msgid="7754624599537393650">"የመንዳት ሁነታን በማዳመጥ ላይ"</string>
diff --git a/service/res/values-ar/strings.xml b/service/res/values-ar/strings.xml
index 46a94b9..a1a5c22 100644
--- a/service/res/values-ar/strings.xml
+++ b/service/res/values-ar/strings.xml
@@ -42,8 +42,6 @@
<string name="car_permission_desc_projection" msgid="2352178999656292944">"يتيح لتطبيق عرض واجهة من هاتف على شاشة السيارة."</string>
<string name="car_permission_label_access_projection_status" msgid="4231618890836627402">"الحصول على معلومات عن حالة العرض"</string>
<string name="car_permission_desc_access_projection_status" msgid="8497351979100616278">"يتيح لتطبيق معرفة حالة التطبيقات الأخرى التي تعرض محتوى على شاشة السيارة."</string>
- <string name="car_permission_label_bind_projection_service" msgid="5362076216606651526">"الالتزام بخدمة عرض"</string>
- <string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"يتيح للمالك الالتزام بواجهة المستوى العلوي لخدمة عرض. لن تكون هناك حاجة إليه مطلقًا مع التطبيقات العادية."</string>
<string name="car_permission_label_audio_volume" msgid="310587969373137690">"التحكم في مستوى الصوت داخل السيارة"</string>
<string name="car_permission_label_audio_settings" msgid="6524703796944023977">"إدارة إعدادات الصوت في السيارة"</string>
<string name="car_permission_label_mock_vehicle_hal" msgid="7198852512207405935">"محاكاة vehicle HAL"</string>
@@ -62,8 +60,6 @@
<string name="car_permission_desc_car_cluster_control" msgid="9222776665281176031">"تشغيل التطبيقات في مجموعة العدادات"</string>
<string name="car_permission_car_monitor_cluster_navigation_state" msgid="7025307242306902441">"حالة التنقل على شاشة مجموعة عدادات"</string>
<string name="car_permission_desc_car_monitor_cluster_navigation_state" msgid="8745047153878713339">"الانتباه إلى تغييرات حالة التنقل على شاشة مجموعة العدادات"</string>
- <string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"جارٍ عرض مجموعة العدادات"</string>
- <string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"تلقّي بيانات مجموعة الأدوات"</string>
<string name="car_permission_label_car_ux_restrictions_configuration" msgid="6801393970411049725">"ضبط قيود تجربة المستخدم"</string>
<string name="car_permission_desc_car_ux_restrictions_configuration" msgid="5711926927484813777">"ضبط قيود تجربة المُستخدِم"</string>
<string name="car_permission_label_access_private_display_id" msgid="6712116114341634316">"إذن الوصول لقراءة معرّف الشاشة الخاص"</string>
@@ -74,8 +70,6 @@
<string name="car_permission_desc_read_car_occupant_awareness_state" msgid="188865882598414986">"السماح بقراءة حالة Occupant Awareness System وبيانات التعرف عليه"</string>
<string name="car_permission_label_control_car_occupant_awareness_system" msgid="7163330266691094542">"التحكّم في الرسم البياني لنظام Occupant Awareness System"</string>
<string name="car_permission_desc_control_car_occupant_awareness_system" msgid="7123482622084531911">"السماح بالتحكّم في بدء وإيقاف الرسم البياني للتعرف على Occupant Awareness System"</string>
- <string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"خدمة إدخال السيارة"</string>
- <string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"التعامل مع أحداث الإدخال"</string>
<string name="car_permission_label_diag_read" msgid="7248894224877702604">"قراءة البيانات التشخيصية"</string>
<string name="car_permission_desc_diag_read" msgid="1121426363040966178">"يمكنك قراءة البيانات التشخيصية من السيارة."</string>
<string name="car_permission_label_diag_clear" msgid="4783070510879698157">"محو البيانات التشخيصية"</string>
@@ -84,8 +78,6 @@
<string name="car_permission_desc_vms_publisher" msgid="5589489298597386828">"نشر رسائل الأجهزة الافتراضية"</string>
<string name="car_permission_label_vms_subscriber" msgid="5648841182059222299">"المشترك في الجهاز الافتراضي"</string>
<string name="car_permission_desc_vms_subscriber" msgid="7551009457847673620">"الاشتراك في رسائل الأجهزة الافتراضية"</string>
- <string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"خدمة عميل الأجهزة الافتراضية"</string>
- <string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"الالتزام بعملاء الأجهزة الافتراضية"</string>
<string name="car_permission_label_storage_monitoring" msgid="2327639346522530549">"مراقبة سعة تخزين الفلاش"</string>
<string name="car_permission_desc_storage_monitoring" msgid="2075712271139671318">"مراقبة استخدام سعة تخزين الفلاش"</string>
<string name="car_permission_label_driving_state" msgid="7754624599537393650">"الاستماع إلى معلومات عن حالة القيادة"</string>
diff --git a/service/res/values-as/strings.xml b/service/res/values-as/strings.xml
index 942edb4..f567a47 100644
--- a/service/res/values-as/strings.xml
+++ b/service/res/values-as/strings.xml
@@ -42,8 +42,6 @@
<string name="car_permission_desc_projection" msgid="2352178999656292944">"কোনো এপক ফ’নৰ পৰা এটা ইণ্টাৰফে’চ গাড়ীৰ ডিছপ্লে’ত প্ৰজেক্ট কৰিবলৈ অনুমতি দিয়ে।"</string>
<string name="car_permission_label_access_projection_status" msgid="4231618890836627402">"প্ৰজেক্শ্বনৰ স্থিতি এক্সেছ কৰিব"</string>
<string name="car_permission_desc_access_projection_status" msgid="8497351979100616278">"কোনো এপক গাড়ী ডিছপ্লে’ত প্ৰজেক্ট কৰি থকা অন্য এপৰ স্থিতি লাভ কৰিবলৈ অনুমতি দিয়ে।"</string>
- <string name="car_permission_label_bind_projection_service" msgid="5362076216606651526">"প্ৰজেক্শ্বন সেৱাৰ সৈতে সংযুক্ত হ’ব"</string>
- <string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"এটা প্ৰজেক্শ্বন সেৱাৰ শীৰ্ষ স্তৰৰ ইণ্টাৰফে’চৰ সৈতে সংযুক্ত হ’বলৈ ধাৰকক অনুমতি দিয়ে। সাধাৰণ এপ্সমূহৰ বাবে কেতিয়াও প্ৰয়োজন হ’ব নালাগে।"</string>
<string name="car_permission_label_audio_volume" msgid="310587969373137690">"গাড়ীৰ অডিঅ’ ভলিউম নিয়ন্ত্ৰণ কৰিব"</string>
<string name="car_permission_label_audio_settings" msgid="6524703796944023977">"গাড়ীৰ অডিঅ’ ছেটিংসমূহ পৰিচালনা কৰিব"</string>
<string name="car_permission_label_mock_vehicle_hal" msgid="7198852512207405935">"বাহনৰ HAL ইমুলে’ট কৰিব"</string>
@@ -62,8 +60,6 @@
<string name="car_permission_desc_car_cluster_control" msgid="9222776665281176031">"ইনষ্ট্ৰুমেণ্ট ক্লাষ্টাৰত এপ্ লঞ্চ কৰিব"</string>
<string name="car_permission_car_monitor_cluster_navigation_state" msgid="7025307242306902441">"ইনষ্ট্ৰুমেণ্ট ক্লাষ্টাৰ নেভিগে’শ্বনৰ অৱস্থা"</string>
<string name="car_permission_desc_car_monitor_cluster_navigation_state" msgid="8745047153878713339">"ইনষ্ট্ৰুমেণ্ট ক্লাষ্টাৰ নেভিগে’শ্বনৰ অৱস্থাৰ সালসলনিবোৰ জানিবলৈ শুনক"</string>
- <string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"ইনষ্ট্ৰুমেণ্ট ক্লাষ্টাৰ ৰেণ্ডাৰ কৰি থকা হৈছে"</string>
- <string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"ইনষ্ট্ৰুমেণ্ট ক্লাষ্টাৰৰ ডেটা পায়"</string>
<string name="car_permission_label_car_ux_restrictions_configuration" msgid="6801393970411049725">"UX সীমাবদ্ধতা কনফিগাৰেশ্বন"</string>
<string name="car_permission_desc_car_ux_restrictions_configuration" msgid="5711926927484813777">"UXৰ সীমাবদ্ধতা কনফিগাৰ কৰক"</string>
<string name="car_permission_label_access_private_display_id" msgid="6712116114341634316">"ব্যক্তিগত ডিছপ্লে’ আইডিলৈ পঢ়াৰ এক্সেছ"</string>
@@ -74,8 +70,6 @@
<string name="car_permission_desc_read_car_occupant_awareness_state" msgid="188865882598414986">"Occupant Awareness Systemৰ স্থিতি পঢ়া আৰু ডেটা চিনাক্ত কৰাৰ অনুমতি দিয়ে"</string>
<string name="car_permission_label_control_car_occupant_awareness_system" msgid="7163330266691094542">"Occupant Awareness Systemৰ লেখ নিয়ন্ত্ৰণ কৰক"</string>
<string name="car_permission_desc_control_car_occupant_awareness_system" msgid="7123482622084531911">"Occupant Awareness System চিনাক্তকৰণৰ লেখৰ আৰম্ভ কৰা আৰু বন্ধ কৰা কার্য নিয়ন্ত্ৰণ কৰাটোৰ অনুমতি দিয়ে"</string>
- <string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"গাড়ীৰ ইনপুট সেৱা"</string>
- <string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"ইনপুট ইভেণ্ট নিয়ন্ত্ৰণ কৰিব"</string>
<string name="car_permission_label_diag_read" msgid="7248894224877702604">"ডায়গন’ষ্টিক ডেটা পঢ়িব"</string>
<string name="car_permission_desc_diag_read" msgid="1121426363040966178">"গাড়ীৰ ডায়গ’ষ্টিক তথ্য পঢ়িব।"</string>
<string name="car_permission_label_diag_clear" msgid="4783070510879698157">"ডায়গন’ষ্টিক ডেটা মচিব"</string>
@@ -84,8 +78,6 @@
<string name="car_permission_desc_vms_publisher" msgid="5589489298597386828">"VMS বাৰ্তা প্ৰকাশ কৰিব পাৰে"</string>
<string name="car_permission_label_vms_subscriber" msgid="5648841182059222299">"VMS গ্ৰাহক"</string>
<string name="car_permission_desc_vms_subscriber" msgid="7551009457847673620">"VMS বাৰ্তাৰ গ্ৰাহকভুক্তি কৰিব পাৰে"</string>
- <string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"VMS ক্লায়েণ্ট সেৱা"</string>
- <string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"VMS ক্লায়েণ্টৰ সৈতে সংযুক্ত হ’ব পাৰে"</string>
<string name="car_permission_label_storage_monitoring" msgid="2327639346522530549">"ফ্লেশ্ব ষ্ট’ৰেজ নিৰীক্ষণ কৰা"</string>
<string name="car_permission_desc_storage_monitoring" msgid="2075712271139671318">"ফ্লেশ্ব ষ্ট’ৰেজৰ ব্যৱহাৰ নিৰীক্ষণ কৰক"</string>
<string name="car_permission_label_driving_state" msgid="7754624599537393650">"গাড়ী চালনাৰ স্থিতি সলনি হ’লে সেইয়া জানিব"</string>
diff --git a/service/res/values-az/strings.xml b/service/res/values-az/strings.xml
index 3605c5f..f872fb3 100644
--- a/service/res/values-az/strings.xml
+++ b/service/res/values-az/strings.xml
@@ -42,8 +42,6 @@
<string name="car_permission_desc_projection" msgid="2352178999656292944">"Tətbiqin telefondakı interfeysi avtomobilin displeyinə ötürməsinə imkan verir."</string>
<string name="car_permission_label_access_projection_status" msgid="4231618890836627402">"proyeksiya statusuna giriş"</string>
<string name="car_permission_desc_access_projection_status" msgid="8497351979100616278">"Tətbiqə avtomobil displeyinə proyeksiya edən digər tətbiqlərin statusunu əldə etmək icazəsi verir."</string>
- <string name="car_permission_label_bind_projection_service" msgid="5362076216606651526">"proyeksiya xidmətinə bağlanmaq"</string>
- <string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"Sahibin proyeksiya xidmətinin yuxarı səviyyəli interfeysinə bağlanmasına icazə verir. Normal tətbiqlər üçün heç vaxt tələb olunmur."</string>
<string name="car_permission_label_audio_volume" msgid="310587969373137690">"avtomobilin audio səsini idarə etmək"</string>
<string name="car_permission_label_audio_settings" msgid="6524703796944023977">"avtomobilin audio ayarlarını idarə etmək"</string>
<string name="car_permission_label_mock_vehicle_hal" msgid="7198852512207405935">"avtomobilin HAL məlumatlarının emulyasiyası"</string>
@@ -62,8 +60,6 @@
<string name="car_permission_desc_car_cluster_control" msgid="9222776665281176031">"Alət klasterində tətbiqləri işə salmaq"</string>
<string name="car_permission_car_monitor_cluster_navigation_state" msgid="7025307242306902441">"Alət klasteri naviqasiya vəziyyəti"</string>
<string name="car_permission_desc_car_monitor_cluster_navigation_state" msgid="8745047153878713339">"Alət klasteri naviqasiya vəziyyəti dəyişikliklərini dinləmək."</string>
- <string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"Alət Klasterinin Təchizatı"</string>
- <string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"Alət klasteri məlumatlarını almaq"</string>
<string name="car_permission_label_car_ux_restrictions_configuration" msgid="6801393970411049725">"UX Məhdudiyyətləri Konfiqurasiyası"</string>
<string name="car_permission_desc_car_ux_restrictions_configuration" msgid="5711926927484813777">"UX Məhdudiyyətlərinin Konfiqurasiyası"</string>
<string name="car_permission_label_access_private_display_id" msgid="6712116114341634316">"Şəxsi displey ID\'sinə oxumaq üçün giriş"</string>
@@ -74,8 +70,6 @@
<string name="car_permission_desc_read_car_occupant_awareness_state" msgid="188865882598414986">"Sərnişin Məlumatlılıq Sisteminin vəziyyət və aşkarlama datasını oxumağa icazə verir"</string>
<string name="car_permission_label_control_car_occupant_awareness_system" msgid="7163330266691094542">"Sərnişin Məlumatlılıq Sistemi Qrafikinə nəzarət"</string>
<string name="car_permission_desc_control_car_occupant_awareness_system" msgid="7123482622084531911">"Sərnişin Məlumatlılıq Sisteminin aşkarlama qrafikinin başladılması və dayandırılmasına nəzarətə icazə verir"</string>
- <string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Avtomobil Daxiletmə Xidməti"</string>
- <string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Daxiletmələri idarə etmək"</string>
<string name="car_permission_label_diag_read" msgid="7248894224877702604">"diaqnoztika məlumatlarını oxumaq"</string>
<string name="car_permission_desc_diag_read" msgid="1121426363040966178">"Avtomobilin diaqnoztika məlumatlarını oxumaq."</string>
<string name="car_permission_label_diag_clear" msgid="4783070510879698157">"diaqnoztika məlumatlarını silmək"</string>
@@ -84,8 +78,6 @@
<string name="car_permission_desc_vms_publisher" msgid="5589489298597386828">"VMS mesajlarını nəşr etmək"</string>
<string name="car_permission_label_vms_subscriber" msgid="5648841182059222299">"VMS Abunəçisi"</string>
<string name="car_permission_desc_vms_subscriber" msgid="7551009457847673620">"VMS mesajlara abunə olmaq"</string>
- <string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"VMS Müştəri Xidməti"</string>
- <string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"VMS müştərilərinə bağlanmaq"</string>
<string name="car_permission_label_storage_monitoring" msgid="2327639346522530549">"Fleş yaddaşa nəzarət"</string>
<string name="car_permission_desc_storage_monitoring" msgid="2075712271139671318">"Fleş yaddaş istifadəsinə nəzarət"</string>
<string name="car_permission_label_driving_state" msgid="7754624599537393650">"sürücülük vəziyyətini dinləmək"</string>
diff --git a/service/res/values-b+sr+Latn/strings.xml b/service/res/values-b+sr+Latn/strings.xml
index df82cf2..b2969e9 100644
--- a/service/res/values-b+sr+Latn/strings.xml
+++ b/service/res/values-b+sr+Latn/strings.xml
@@ -42,8 +42,6 @@
<string name="car_permission_desc_projection" msgid="2352178999656292944">"Omogućava aplikaciji da projektuje interfejs sa telefona na ekran automobila."</string>
<string name="car_permission_label_access_projection_status" msgid="4231618890836627402">"pristup statusu projekcije"</string>
<string name="car_permission_desc_access_projection_status" msgid="8497351979100616278">"Dozvoljava aplikaciji da pronađe status drugih aplikacija koje projektuju na ekran automobila."</string>
- <string name="car_permission_label_bind_projection_service" msgid="5362076216606651526">"povezivanje sa uslugom projekcije"</string>
- <string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"Dozvoljava vlasniku da se poveže sa interfejsom usluge projekcije najvišeg nivoa. Uobičajene aplikacije nikada ne bi trebalo da je koriste."</string>
<string name="car_permission_label_audio_volume" msgid="310587969373137690">"kontrolisanje jačine zvuka u automobilu"</string>
<string name="car_permission_label_audio_settings" msgid="6524703796944023977">"upravljanje podešavanjima zvuka u automobilu"</string>
<string name="car_permission_label_mock_vehicle_hal" msgid="7198852512207405935">"emulacija HAL-a vozila"</string>
@@ -62,8 +60,6 @@
<string name="car_permission_desc_car_cluster_control" msgid="9222776665281176031">"Pokreće aplikacije na instrument tabli"</string>
<string name="car_permission_car_monitor_cluster_navigation_state" msgid="7025307242306902441">"Status kretanja na instrument tabli"</string>
<string name="car_permission_desc_car_monitor_cluster_navigation_state" msgid="8745047153878713339">"Otkrivanje promena statusa kretanja na instrument tabli"</string>
- <string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"Prikazivanje na instrument tabli"</string>
- <string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"Prima podatke sa instrument table"</string>
<string name="car_permission_label_car_ux_restrictions_configuration" msgid="6801393970411049725">"Konfiguracija ograničenja KD-a"</string>
<string name="car_permission_desc_car_ux_restrictions_configuration" msgid="5711926927484813777">"Konfiguriše ograničenja KD-a"</string>
<string name="car_permission_label_access_private_display_id" msgid="6712116114341634316">"Pristup za čitanje ID-u za privatni prikaz"</string>
@@ -74,8 +70,6 @@
<string name="car_permission_desc_read_car_occupant_awareness_state" msgid="188865882598414986">"Omogućava čitanje podataka o statusu i otkrivanju za Occupant Awareness System"</string>
<string name="car_permission_label_control_car_occupant_awareness_system" msgid="7163330266691094542">"Upravljanje grafikonom za Occupant Awareness System"</string>
<string name="car_permission_desc_control_car_occupant_awareness_system" msgid="7123482622084531911">"Omogućava pokretanje i zaustavljanje grafikona otkrivanja za Occupant Awareness System"</string>
- <string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Usluga automobilskog unosa"</string>
- <string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Upravlja događajima unosa"</string>
<string name="car_permission_label_diag_read" msgid="7248894224877702604">"čitanje dijagnostičkih podataka"</string>
<string name="car_permission_desc_diag_read" msgid="1121426363040966178">"Čitanje dijagnostičkih podataka iz automobila."</string>
<string name="car_permission_label_diag_clear" msgid="4783070510879698157">"brisanje dijagnostičkih podataka"</string>
@@ -84,8 +78,6 @@
<string name="car_permission_desc_vms_publisher" msgid="5589489298597386828">"Objavljuje VMS poruke"</string>
<string name="car_permission_label_vms_subscriber" msgid="5648841182059222299">"Pretplatnik na VMS poruke"</string>
<string name="car_permission_desc_vms_subscriber" msgid="7551009457847673620">"Pretplaćuje na VMS poruke"</string>
- <string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"VMS usluga za klijente"</string>
- <string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"Povezuje sa VMS klijentima"</string>
<string name="car_permission_label_storage_monitoring" msgid="2327639346522530549">"Praćenje fleš memorije"</string>
<string name="car_permission_desc_storage_monitoring" msgid="2075712271139671318">"Nadgleda korišćenje fleš memorije"</string>
<string name="car_permission_label_driving_state" msgid="7754624599537393650">"slušanje stanja vožnje"</string>
diff --git a/service/res/values-be/strings.xml b/service/res/values-be/strings.xml
index 26231fd..2e6f2ad 100644
--- a/service/res/values-be/strings.xml
+++ b/service/res/values-be/strings.xml
@@ -42,8 +42,6 @@
<string name="car_permission_desc_projection" msgid="2352178999656292944">"Дазваляе праграме трансліраваць інтэрфейс тэлефона на экран аўтамабіля."</string>
<string name="car_permission_label_access_projection_status" msgid="4231618890836627402">"дазволіць доступ да стану трансляцыі"</string>
<string name="car_permission_desc_access_projection_status" msgid="8497351979100616278">"Дазваляе праграме атрымліваць звесткі пра стан іншых праграм з трансляцыяй на экран аўтамабіля."</string>
- <string name="car_permission_label_bind_projection_service" msgid="5362076216606651526">"звязваць з сэрвісам трансляцыі"</string>
- <string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"Дазваляе ўладальніку звязвацца з інтэрфейсам службы трансляцыі вышэйшага ўзроўню. Не патрэбна для звычайных праграм."</string>
<string name="car_permission_label_audio_volume" msgid="310587969373137690">"рэгуляваць гучнасць аўдыясістэмы ў аўтамабілі"</string>
<string name="car_permission_label_audio_settings" msgid="6524703796944023977">"кіраваць наладамі аўдыя ў аўтамабілі"</string>
<string name="car_permission_label_mock_vehicle_hal" msgid="7198852512207405935">"эмуляваць інтэрфейс HAL аўтамабіля"</string>
@@ -62,8 +60,6 @@
<string name="car_permission_desc_car_cluster_control" msgid="9222776665281176031">"Запуск праграмы з прыборнай панэлі"</string>
<string name="car_permission_car_monitor_cluster_navigation_state" msgid="7025307242306902441">"Стан навігацыі на прыборнай панэлі"</string>
<string name="car_permission_desc_car_monitor_cluster_navigation_state" msgid="8745047153878713339">"Адсочванне змен у стане навігацыі на прыборнай панэлі"</string>
- <string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"Візуалізацыя на прыборнай панэлі"</string>
- <string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"Магчымасць атрымліваць даныя з прыборнай панэлі"</string>
<string name="car_permission_label_car_ux_restrictions_configuration" msgid="6801393970411049725">"Канфігурацыя абмежаванняў UX"</string>
<string name="car_permission_desc_car_ux_restrictions_configuration" msgid="5711926927484813777">"Наладжванне абмежаванняў UX"</string>
<string name="car_permission_label_access_private_display_id" msgid="6712116114341634316">"Доступ да счытвання ідэнтыфікатара прыватнага дысплэя"</string>
@@ -74,8 +70,6 @@
<string name="car_permission_desc_read_car_occupant_awareness_state" msgid="188865882598414986">"Дазваляе счытваць стан і даныя выяўлення для сістэмы інфармавання пра пасажыра"</string>
<string name="car_permission_label_control_car_occupant_awareness_system" msgid="7163330266691094542">"Правяраць графік сістэмы інфармавання пра пасажыра"</string>
<string name="car_permission_desc_control_car_occupant_awareness_system" msgid="7123482622084531911">"Дазваляе кантраляваць запуск і прыпыненне графіка выяўлення для сістэмы інфармавання пра пасажыра"</string>
- <string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Сэрвіс уводу аўтамабіля"</string>
- <string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Магчымасць апрацоўваць падзеі ўводу"</string>
<string name="car_permission_label_diag_read" msgid="7248894224877702604">"атрымліваць даныя дыягностыкі"</string>
<string name="car_permission_desc_diag_read" msgid="1121426363040966178">"Счытванне дыягнастычных даных аўтамабіля"</string>
<string name="car_permission_label_diag_clear" msgid="4783070510879698157">"ачысціць даныя дыягностыкі"</string>
@@ -84,8 +78,6 @@
<string name="car_permission_desc_vms_publisher" msgid="5589489298597386828">"Публікаваць VMS-паведамленні"</string>
<string name="car_permission_label_vms_subscriber" msgid="5648841182059222299">"Падпіска на VMS-паведамленні"</string>
<string name="car_permission_desc_vms_subscriber" msgid="7551009457847673620">"Падпісацца на VMS-паведамленні"</string>
- <string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"Служба кліента VMS"</string>
- <string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"Звязвацца з кліентамі VMS"</string>
<string name="car_permission_label_storage_monitoring" msgid="2327639346522530549">"Маніторынг флэш-сховішча"</string>
<string name="car_permission_desc_storage_monitoring" msgid="2075712271139671318">"Магчымасць адсочваць выкарыстанне флэш-сховішча"</string>
<string name="car_permission_label_driving_state" msgid="7754624599537393650">"адсочваць стан язды"</string>
diff --git a/service/res/values-bg/strings.xml b/service/res/values-bg/strings.xml
index ca0f266..15031e5 100644
--- a/service/res/values-bg/strings.xml
+++ b/service/res/values-bg/strings.xml
@@ -42,8 +42,6 @@
<string name="car_permission_desc_projection" msgid="2352178999656292944">"Разрешава на приложението да прожектира интерфейса от телефон на дисплея на автомобила."</string>
<string name="car_permission_label_access_projection_status" msgid="4231618890836627402">"достъп до състоянието на прожектиране"</string>
<string name="car_permission_desc_access_projection_status" msgid="8497351979100616278">"Разрешава на приложението да извлича състоянието на други приложения, които се прожектират на дисплея на автомобила."</string>
- <string name="car_permission_label_bind_projection_service" msgid="5362076216606651526">"обвързване с услуга за прожектиране"</string>
- <string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"Разрешава на притежателя да се обвърже с интерфейса от най-високото ниво на услуга за прожектиране. Нормалните приложения би трябвало никога да не се нуждаят от това."</string>
<string name="car_permission_label_audio_volume" msgid="310587969373137690">"контролиране на силата на звука на автомобилната аудиосистема"</string>
<string name="car_permission_label_audio_settings" msgid="6524703796944023977">"управление на звуковите настройки на автомобила"</string>
<string name="car_permission_label_mock_vehicle_hal" msgid="7198852512207405935">"емулиране на HAL интерфейса на превозното средство"</string>
@@ -62,8 +60,6 @@
<string name="car_permission_desc_car_cluster_control" msgid="9222776665281176031">"Стартиране на приложения в арматурното табло"</string>
<string name="car_permission_car_monitor_cluster_navigation_state" msgid="7025307242306902441">"Състояние на навигационната система на арматурното табло"</string>
<string name="car_permission_desc_car_monitor_cluster_navigation_state" msgid="8745047153878713339">"Регистриране на промените в състоянието на навигационната система на арматурното табло"</string>
- <string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"Изобразяване в арматурното табло"</string>
- <string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"Получаване на данни за арматурното табло"</string>
<string name="car_permission_label_car_ux_restrictions_configuration" msgid="6801393970411049725">"Конфигуриране на ограничения за ПРП"</string>
<string name="car_permission_desc_car_ux_restrictions_configuration" msgid="5711926927484813777">"Конфигуриране на ограничения за ПРП"</string>
<string name="car_permission_label_access_private_display_id" msgid="6712116114341634316">"Достъп за четене до идентификационния номер на частния дисплей"</string>
@@ -74,8 +70,6 @@
<string name="car_permission_desc_read_car_occupant_awareness_state" msgid="188865882598414986">"Разрешава четенето на състоянието и данните за установяване на системата за информираност на пътниците"</string>
<string name="car_permission_label_control_car_occupant_awareness_system" msgid="7163330266691094542">"Управление на графиката за системата за информираност на пътниците"</string>
<string name="car_permission_desc_control_car_occupant_awareness_system" msgid="7123482622084531911">"Разрешава управлението на стартирането и спирането на графиката за установяване на системата за информираност на пътниците"</string>
- <string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Автомобилна услуга за входящи данни"</string>
- <string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Обработване на входящи събития"</string>
<string name="car_permission_label_diag_read" msgid="7248894224877702604">"четене на диагностични данни"</string>
<string name="car_permission_desc_diag_read" msgid="1121426363040966178">"Четене на диагностични данни от автомобила."</string>
<string name="car_permission_label_diag_clear" msgid="4783070510879698157">"изчистване на диагностичните данни"</string>
@@ -84,8 +78,6 @@
<string name="car_permission_desc_vms_publisher" msgid="5589489298597386828">"Публикуване на VMS съобщения"</string>
<string name="car_permission_label_vms_subscriber" msgid="5648841182059222299">"Абониране за VMS"</string>
<string name="car_permission_desc_vms_subscriber" msgid="7551009457847673620">"Абониране за VMS съобщения"</string>
- <string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"Клиентска услуга за VMS"</string>
- <string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"Обвързване с клиентски програми за VMS"</string>
<string name="car_permission_label_storage_monitoring" msgid="2327639346522530549">"Наблюдение на флаш хранилището"</string>
<string name="car_permission_desc_storage_monitoring" msgid="2075712271139671318">"Наблюдение на използването на флаш хранилището"</string>
<string name="car_permission_label_driving_state" msgid="7754624599537393650">"слушане за състоянието на шофиране"</string>
diff --git a/service/res/values-bn/strings.xml b/service/res/values-bn/strings.xml
index 461e0d7..6b3413c 100644
--- a/service/res/values-bn/strings.xml
+++ b/service/res/values-bn/strings.xml
@@ -42,8 +42,6 @@
<string name="car_permission_desc_projection" msgid="2352178999656292944">"ফোন ও গাড়ির ডিসপ্লের মধ্যে ইন্টারফেস তৈরি করতে অ্যাপকে অনুমতি দিন।"</string>
<string name="car_permission_label_access_projection_status" msgid="4231618890836627402">"প্রোজেকশনের স্ট্যাটাস অ্যাক্সেস করা"</string>
<string name="car_permission_desc_access_projection_status" msgid="8497351979100616278">"গাড়ির ডিসপ্লেতে অন্যান্য অ্যাপের প্রোজেক্টিং স্ট্যাটাস দেখতে অ্যাপকে অনুমতি দিন।"</string>
- <string name="car_permission_label_bind_projection_service" msgid="5362076216606651526">"প্রোজেকশন পরিষেবার সাথে যুক্ত হওয়া"</string>
- <string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"হোল্ডারকে একটি প্রোজেকশন পরিষেবার উচ্চ মানের ইন্টারফেসে যুক্ত হতে অনুমতি দেয়। সধারণ অ্যাপের ক্ষেত্রে কখনই প্রয়োজন হয় না।"</string>
<string name="car_permission_label_audio_volume" msgid="310587969373137690">"গাড়ির অডিও ভলিউম নিয়ন্ত্রণ করা"</string>
<string name="car_permission_label_audio_settings" msgid="6524703796944023977">"গাড়ির অডিও সেটিংস ম্যানেজ করা"</string>
<string name="car_permission_label_mock_vehicle_hal" msgid="7198852512207405935">"গাড়ির HAL অনুকরণ করা"</string>
@@ -62,8 +60,6 @@
<string name="car_permission_desc_car_cluster_control" msgid="9222776665281176031">"ইনস্ট্রুমেন্ট ক্লাস্টারে অ্যাপ চালু করা"</string>
<string name="car_permission_car_monitor_cluster_navigation_state" msgid="7025307242306902441">"ইনস্ট্রুমেন্ট ক্লাস্টার নেভিগেশনের স্ট্যাটাস"</string>
<string name="car_permission_desc_car_monitor_cluster_navigation_state" msgid="8745047153878713339">"ইনস্ট্রুমেন্ট ক্লাস্টার নেভিগেশনের স্ট্যাটাস সংক্রান্ত পরিবর্তন শুনুন"</string>
- <string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"ইনস্ট্রুমেন্ট ক্লাস্টার রেন্ডার করা"</string>
- <string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"ইনস্ট্রুমেন্ট ক্লাস্টার ডেটা পান"</string>
<string name="car_permission_label_car_ux_restrictions_configuration" msgid="6801393970411049725">"UX বিধিনিষেধ কনফিগারেশন"</string>
<string name="car_permission_desc_car_ux_restrictions_configuration" msgid="5711926927484813777">"UX বিধিনিষেধ কনফিগার করা"</string>
<string name="car_permission_label_access_private_display_id" msgid="6712116114341634316">"ব্যক্তিগত ডিসপ্লে আইডিতে পড়ার অ্যাক্সেস"</string>
@@ -74,8 +70,6 @@
<string name="car_permission_desc_read_car_occupant_awareness_state" msgid="188865882598414986">"অকুপেন্ট সচেতনতা সিস্টেমের জন্য পড়ার স্ট্যাটাস এবং ডিটেকশন ডেটার অনুমতি দেওয়া"</string>
<string name="car_permission_label_control_car_occupant_awareness_system" msgid="7163330266691094542">"অকুপেন্ট সচেতনতা সিস্টেম গ্রাফ কন্ট্রোল করা"</string>
<string name="car_permission_desc_control_car_occupant_awareness_system" msgid="7123482622084531911">"অকুপেন্ট সচেতনতা সিস্টেম ডিটেকশন গ্রাফের চালু এবং বন্ধ করার ফিচার নিয়ন্ত্রণে অনুমতি দেওয়া"</string>
- <string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"গাড়ির ইনপুট সার্ভিস"</string>
- <string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"ইনপুট ইভেন্ট হ্যান্ডেল করা"</string>
<string name="car_permission_label_diag_read" msgid="7248894224877702604">"ডায়াগনস্টিক ডেটা দেখা"</string>
<string name="car_permission_desc_diag_read" msgid="1121426363040966178">"গাড়ির ডায়াগনস্টিক সংক্রান্ত ডেটা দেখা।"</string>
<string name="car_permission_label_diag_clear" msgid="4783070510879698157">"ডায়াগনস্টিকস ডেটা সরানো"</string>
@@ -84,8 +78,6 @@
<string name="car_permission_desc_vms_publisher" msgid="5589489298597386828">"vms মেসেজ প্রকাশ করুন"</string>
<string name="car_permission_label_vms_subscriber" msgid="5648841182059222299">"VMS সাবস্ক্রাইবার"</string>
<string name="car_permission_desc_vms_subscriber" msgid="7551009457847673620">"VMS মেসেজে সাবস্ক্রাইব করুন"</string>
- <string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"VMS ক্লায়েন্ট পরিষেবা"</string>
- <string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"VMS ক্লায়েন্টের সাথে যুক্ত হন"</string>
<string name="car_permission_label_storage_monitoring" msgid="2327639346522530549">"ফ্ল্যাশ স্টোরেজ মনিটর করা"</string>
<string name="car_permission_desc_storage_monitoring" msgid="2075712271139671318">"ফ্ল্যাশ স্টোরেজের ব্যবহার মনিটর করা"</string>
<string name="car_permission_label_driving_state" msgid="7754624599537393650">"ড্রাইভিংয়ের স্ট্যাটাস পরিবর্তন করার বিষয়ে শোনা"</string>
diff --git a/service/res/values-bs/strings.xml b/service/res/values-bs/strings.xml
index fb7c0c7..ef200fb 100644
--- a/service/res/values-bs/strings.xml
+++ b/service/res/values-bs/strings.xml
@@ -42,8 +42,6 @@
<string name="car_permission_desc_projection" msgid="2352178999656292944">"Omogućava aplikaciji da projicira interfejs s telefona na ekran automobila."</string>
<string name="car_permission_label_access_projection_status" msgid="4231618890836627402">"pristupiti statusu projiciranja"</string>
<string name="car_permission_desc_access_projection_status" msgid="8497351979100616278">"Omogućava aplikaciji da primi status drugih aplikacija koje projiciraju sadržaj na ekran automobila."</string>
- <string name="car_permission_label_bind_projection_service" msgid="5362076216606651526">"vezati za uslugu projiciranja"</string>
- <string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"Dozvoljava vlasniku povezivanje s interfejsom najvišeg nivoa usluge za projiciranje. Nije potrebno za obične aplikacije."</string>
<string name="car_permission_label_audio_volume" msgid="310587969373137690">"kontrolirati jačinu zvuka automobila"</string>
<string name="car_permission_label_audio_settings" msgid="6524703796944023977">"upravljati zvučnim postavkama automobila"</string>
<string name="car_permission_label_mock_vehicle_hal" msgid="7198852512207405935">"emulirati HAL vozila"</string>
@@ -62,8 +60,6 @@
<string name="car_permission_desc_car_cluster_control" msgid="9222776665281176031">"Pokrenuti aplikacije na kontrolnoj tabli"</string>
<string name="car_permission_car_monitor_cluster_navigation_state" msgid="7025307242306902441">"Stanje navigacije kontrolne table"</string>
<string name="car_permission_desc_car_monitor_cluster_navigation_state" msgid="8745047153878713339">"Praćenje promjena stanja navigacije kontrolne table"</string>
- <string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"Iscrtavanje na kontrolnoj tabli"</string>
- <string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"Primite podatke s kontrolne ploče"</string>
<string name="car_permission_label_car_ux_restrictions_configuration" msgid="6801393970411049725">"Konfiguracija ograničenja IK-a"</string>
<string name="car_permission_desc_car_ux_restrictions_configuration" msgid="5711926927484813777">"Konfigurirajte ograničenja IK-a"</string>
<string name="car_permission_label_access_private_display_id" msgid="6712116114341634316">"Pristup očitavanju ID-a privatnog ekrana"</string>
@@ -74,8 +70,6 @@
<string name="car_permission_desc_read_car_occupant_awareness_state" msgid="188865882598414986">"Omogućava očitavanje statusa i otkrivanje podataka za Sistem informiranosti o broju prisutnih"</string>
<string name="car_permission_label_control_car_occupant_awareness_system" msgid="7163330266691094542">"Kontroliranje grafikona Sistema informiranosti o broju prisutnih"</string>
<string name="car_permission_desc_control_car_occupant_awareness_system" msgid="7123482622084531911">"Omogućava kontroliranje početka i zaustavljanja grafikona otkrivanja Sistema informiranosti o broju prisutnih"</string>
- <string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Usluga unosa za automobil"</string>
- <string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Rukovati događajima unosa"</string>
<string name="car_permission_label_diag_read" msgid="7248894224877702604">"očitati dijagnostičke podatke"</string>
<string name="car_permission_desc_diag_read" msgid="1121426363040966178">"Očitati dijagnostičke podatke automobila."</string>
<string name="car_permission_label_diag_clear" msgid="4783070510879698157">"brisati dijagnostičke podatke"</string>
@@ -84,8 +78,6 @@
<string name="car_permission_desc_vms_publisher" msgid="5589489298597386828">"Objaviti VMS poruke"</string>
<string name="car_permission_label_vms_subscriber" msgid="5648841182059222299">"VMS pretplatnik"</string>
<string name="car_permission_desc_vms_subscriber" msgid="7551009457847673620">"Pretplatiti se na VMS poruke"</string>
- <string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"VMS usluga klijenta"</string>
- <string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"Vezati za VMS klijenta"</string>
<string name="car_permission_label_storage_monitoring" msgid="2327639346522530549">"Nadzor flash pohrane"</string>
<string name="car_permission_desc_storage_monitoring" msgid="2075712271139671318">"Pratiti korištenje flash pohrane"</string>
<string name="car_permission_label_driving_state" msgid="7754624599537393650">"slušati izmjene stanja vožnje"</string>
diff --git a/service/res/values-ca/strings.xml b/service/res/values-ca/strings.xml
index 5f208e0..535dc5d 100644
--- a/service/res/values-ca/strings.xml
+++ b/service/res/values-ca/strings.xml
@@ -42,8 +42,6 @@
<string name="car_permission_desc_projection" msgid="2352178999656292944">"Permet que una aplicació projecti la interfície d\'un telèfon a la pantalla del cotxe"</string>
<string name="car_permission_label_access_projection_status" msgid="4231618890836627402">"accedeix a l\'estat de la projecció"</string>
<string name="car_permission_desc_access_projection_status" msgid="8497351979100616278">"Permet que una aplicació obtingui l\'estat d\'altres aplicacions que s\'estiguin projectant a la pantalla del cotxe"</string>
- <string name="car_permission_label_bind_projection_service" msgid="5362076216606651526">"vincula a un servei de projecció"</string>
- <string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"Permet que el titular vinculi a la interfície de nivell superior d\'un servei de projecció. No s\'hauria de necessitar mai per a les aplicacions normals"</string>
<string name="car_permission_label_audio_volume" msgid="310587969373137690">"controla el volum de l\'àudio del cotxe"</string>
<string name="car_permission_label_audio_settings" msgid="6524703796944023977">"gestiona la configuració de l\'àudio del cotxe"</string>
<string name="car_permission_label_mock_vehicle_hal" msgid="7198852512207405935">"emula l\'API vehicle HAL"</string>
@@ -62,8 +60,6 @@
<string name="car_permission_desc_car_cluster_control" msgid="9222776665281176031">"Executar aplicacions al quadre de comandament"</string>
<string name="car_permission_car_monitor_cluster_navigation_state" msgid="7025307242306902441">"Estat de navegació del quadre de comandament"</string>
<string name="car_permission_desc_car_monitor_cluster_navigation_state" msgid="8745047153878713339">"Escolta els canvis en l\'estat de navegació del quadre de comandament"</string>
- <string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"Renderització del quadre de comandament"</string>
- <string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"Rebre dades del quadre de comandament"</string>
<string name="car_permission_label_car_ux_restrictions_configuration" msgid="6801393970411049725">"Configuració de les restriccions de l\'experiència d\'usuari"</string>
<string name="car_permission_desc_car_ux_restrictions_configuration" msgid="5711926927484813777">"Configurar les restriccions de l\'experiència d\'usuari"</string>
<string name="car_permission_label_access_private_display_id" msgid="6712116114341634316">"Accés de lectura a l\'identificador de pantalla privat"</string>
@@ -74,8 +70,6 @@
<string name="car_permission_desc_read_car_occupant_awareness_state" msgid="188865882598414986">"Permet llegir les dades de detecció i d\'estat del Sistema de detecció d\'ocupants"</string>
<string name="car_permission_label_control_car_occupant_awareness_system" msgid="7163330266691094542">"Controlar el gràfic del Sistema de detecció d\'ocupants"</string>
<string name="car_permission_desc_control_car_occupant_awareness_system" msgid="7123482622084531911">"Permet controlar l\'inici i la pausa del gràfic de detecció del Sistema de detecció d\'ocupants"</string>
- <string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Servei d\'entrada del cotxe"</string>
- <string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Gestionar els esdeveniments d\'entrada"</string>
<string name="car_permission_label_diag_read" msgid="7248894224877702604">"llegeix les dades de diagnòstic"</string>
<string name="car_permission_desc_diag_read" msgid="1121426363040966178">"Llegeix les dades de diagnòstic del cotxe."</string>
<string name="car_permission_label_diag_clear" msgid="4783070510879698157">"esborra les dades de diagnòstic"</string>
@@ -84,8 +78,6 @@
<string name="car_permission_desc_vms_publisher" msgid="5589489298597386828">"Publicar missatges VMS"</string>
<string name="car_permission_label_vms_subscriber" msgid="5648841182059222299">"Subscriptor de VMS"</string>
<string name="car_permission_desc_vms_subscriber" msgid="7551009457847673620">"Subscriure\'s als missatges VMS"</string>
- <string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"Servei de client de VMS"</string>
- <string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"Vincular a clients de VMS"</string>
<string name="car_permission_label_storage_monitoring" msgid="2327639346522530549">"Supervisió de l\'emmagatzematge flaix"</string>
<string name="car_permission_desc_storage_monitoring" msgid="2075712271139671318">"Supervisar l\'ús d\'emmagatzematge flaix"</string>
<string name="car_permission_label_driving_state" msgid="7754624599537393650">"escolta l\'estat de conducció"</string>
diff --git a/service/res/values-cs/strings.xml b/service/res/values-cs/strings.xml
index 3e168f2..5bb1d08 100644
--- a/service/res/values-cs/strings.xml
+++ b/service/res/values-cs/strings.xml
@@ -42,8 +42,6 @@
<string name="car_permission_desc_projection" msgid="2352178999656292944">"Umožňuje aplikaci promítat rozhraní z telefonu na displej auta."</string>
<string name="car_permission_label_access_projection_status" msgid="4231618890836627402">"přístup ke stavu promítání"</string>
<string name="car_permission_desc_access_projection_status" msgid="8497351979100616278">"Umožňuje aplikaci zjistit stav ostatních aplikací, které promítají obsah na displej auta."</string>
- <string name="car_permission_label_bind_projection_service" msgid="5362076216606651526">"vazba na promítací službu"</string>
- <string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"Umožňuje držiteli navázat se na nejvyšší úroveň promítací služby. Běžné aplikace by toto oprávnění neměly nikdy požadovat."</string>
<string name="car_permission_label_audio_volume" msgid="310587969373137690">"ovládání hlasitosti zvuku v autě"</string>
<string name="car_permission_label_audio_settings" msgid="6524703796944023977">"správa nastavení zvuku auta"</string>
<string name="car_permission_label_mock_vehicle_hal" msgid="7198852512207405935">"emulace vrstvy HAL vozidla"</string>
@@ -62,8 +60,6 @@
<string name="car_permission_desc_car_cluster_control" msgid="9222776665281176031">"Spouštění aplikací na přístrojové desce"</string>
<string name="car_permission_car_monitor_cluster_navigation_state" msgid="7025307242306902441">"Stav navigace na přístrojové desce"</string>
<string name="car_permission_desc_car_monitor_cluster_navigation_state" msgid="8745047153878713339">"Naslouchat změnám stavu navigace na přístrojové desce"</string>
- <string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"Vykreslování na přístrojové desce"</string>
- <string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"Přijímat údaje z přístrojové desky"</string>
<string name="car_permission_label_car_ux_restrictions_configuration" msgid="6801393970411049725">"Konfigurace omezení uživatelského prostředí"</string>
<string name="car_permission_desc_car_ux_restrictions_configuration" msgid="5711926927484813777">"Konfigurace omezení uživatelského prostředí"</string>
<string name="car_permission_label_access_private_display_id" msgid="6712116114341634316">"Přístup pro čtení k soukromému ID displeje"</string>
@@ -74,8 +70,6 @@
<string name="car_permission_desc_read_car_occupant_awareness_state" msgid="188865882598414986">"Umožňuje čtení stavu a dat ze systému detekce uživatele"</string>
<string name="car_permission_label_control_car_occupant_awareness_system" msgid="7163330266691094542">"Systému detekce uživatele – ovládání grafu"</string>
<string name="car_permission_desc_control_car_occupant_awareness_system" msgid="7123482622084531911">"Umožňuje ovládat zahájení a ukončení grafu systému detekce uživatele"</string>
- <string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Služba vstupu auta"</string>
- <string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Zpracování vstupních událostí"</string>
<string name="car_permission_label_diag_read" msgid="7248894224877702604">"čtení diagnostických dat"</string>
<string name="car_permission_desc_diag_read" msgid="1121426363040966178">"Čtení diagnostických dat z auta."</string>
<string name="car_permission_label_diag_clear" msgid="4783070510879698157">"vymazat diagnostická data"</string>
@@ -84,8 +78,6 @@
<string name="car_permission_desc_vms_publisher" msgid="5589489298597386828">"Publikování zpráv VMS"</string>
<string name="car_permission_label_vms_subscriber" msgid="5648841182059222299">"Odběratel VMS"</string>
<string name="car_permission_desc_vms_subscriber" msgid="7551009457847673620">"Přihlášení k odběru zpráv VMS"</string>
- <string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"Klientská služba VMS"</string>
- <string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"Vazba na klienty VMS"</string>
<string name="car_permission_label_storage_monitoring" msgid="2327639346522530549">"Sledování úložiště flash"</string>
<string name="car_permission_desc_storage_monitoring" msgid="2075712271139671318">"Sledování využití úložiště flash"</string>
<string name="car_permission_label_driving_state" msgid="7754624599537393650">"poslech změn jízdy autem"</string>
diff --git a/service/res/values-da/strings.xml b/service/res/values-da/strings.xml
index db84ab8..3752122 100644
--- a/service/res/values-da/strings.xml
+++ b/service/res/values-da/strings.xml
@@ -42,8 +42,6 @@
<string name="car_permission_desc_projection" msgid="2352178999656292944">"Tillader, at en app kan projicere en brugerflade fra en telefon til bilens display."</string>
<string name="car_permission_label_access_projection_status" msgid="4231618890836627402">"få adgang til projiceringsstatus"</string>
<string name="car_permission_desc_access_projection_status" msgid="8497351979100616278">"Tillader, at en app henter statussen for andre apps, der projicerer til bilens display."</string>
- <string name="car_permission_label_bind_projection_service" msgid="5362076216606651526">"oprette tilknytning til en projiceringstjeneste"</string>
- <string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"Tillader, at indehaveren opretter en tilknytning til det øverste niveau af grænsefladen i en projiceringstjeneste. Dette bør aldrig være nødvendigt for almindelige apps."</string>
<string name="car_permission_label_audio_volume" msgid="310587969373137690">"styre bilens lydstyrke"</string>
<string name="car_permission_label_audio_settings" msgid="6524703796944023977">"administrere bilens lydindstillinger"</string>
<string name="car_permission_label_mock_vehicle_hal" msgid="7198852512207405935">"efterligne Vehicle HAL (Hardware Abstraction Layer)"</string>
@@ -62,8 +60,6 @@
<string name="car_permission_desc_car_cluster_control" msgid="9222776665281176031">"Start apps på instrumentbrættet"</string>
<string name="car_permission_car_monitor_cluster_navigation_state" msgid="7025307242306902441">"Tilstand for navigation på instrumentbrættet"</string>
<string name="car_permission_desc_car_monitor_cluster_navigation_state" msgid="8745047153878713339">"Lytte efter ændringer af tilstanden for navigation på instrumentbrættet"</string>
- <string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"Gengivelse af instrumentbrættet"</string>
- <string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"Modtag instrumentbrætdata"</string>
<string name="car_permission_label_car_ux_restrictions_configuration" msgid="6801393970411049725">"Konfiguration af UX-begrænsninger"</string>
<string name="car_permission_desc_car_ux_restrictions_configuration" msgid="5711926927484813777">"Konfigurer UX-begrænsninger"</string>
<string name="car_permission_label_access_private_display_id" msgid="6712116114341634316">"Læseadgang til privatskærm-id"</string>
@@ -74,8 +70,6 @@
<string name="car_permission_desc_read_car_occupant_awareness_state" msgid="188865882598414986">"Giver mulighed for at aflæse status og registreringsdata for Occupant Awareness System"</string>
<string name="car_permission_label_control_car_occupant_awareness_system" msgid="7163330266691094542">"Styr grafen for Occupant Awareness System"</string>
<string name="car_permission_desc_control_car_occupant_awareness_system" msgid="7123482622084531911">"Giver mulighed for at starte og stoppe registreringsgrafen for Occupant Awareness System"</string>
- <string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Bilens inputservice"</string>
- <string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Håndter input"</string>
<string name="car_permission_label_diag_read" msgid="7248894224877702604">"tjekke diagnosticeringsdata"</string>
<string name="car_permission_desc_diag_read" msgid="1121426363040966178">"Tjek diagnosticeringsdata fra bilen."</string>
<string name="car_permission_label_diag_clear" msgid="4783070510879698157">"rydde diagnosticeringsdata"</string>
@@ -84,8 +78,6 @@
<string name="car_permission_desc_vms_publisher" msgid="5589489298597386828">"Udgive VMS-meddelelser"</string>
<string name="car_permission_label_vms_subscriber" msgid="5648841182059222299">"VMS-abonnent"</string>
<string name="car_permission_desc_vms_subscriber" msgid="7551009457847673620">"Abonnere på VMS-meddelelser"</string>
- <string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"VMS-klientservice"</string>
- <string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"Oprette tilknytning til VMS-klienter"</string>
<string name="car_permission_label_storage_monitoring" msgid="2327639346522530549">"Overvågning af Flash-lager"</string>
<string name="car_permission_desc_storage_monitoring" msgid="2075712271139671318">"Overvåg Flash-lagerforbrug"</string>
<string name="car_permission_label_driving_state" msgid="7754624599537393650">"lytte til tilstanden Kører"</string>
diff --git a/service/res/values-de/strings.xml b/service/res/values-de/strings.xml
index 926e9fc..0f0d4d7 100644
--- a/service/res/values-de/strings.xml
+++ b/service/res/values-de/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="2215078736675564541">"Fahrzeuginformationen"</string>
+ <string name="car_permission_label" msgid="2215078736675564541">"Fahrzeuginformationen"</string>
<string name="car_permission_desc" msgid="3584369074931334964">"Zugriff auf Informationen deines Autos"</string>
<string name="car_permission_label_camera" msgid="3725702064841827180">"auf die Autokamera zuzugreifen"</string>
<string name="car_permission_desc_camera" msgid="917024932164501426">"Auf Autokamera(s) zugreifen."</string>
@@ -42,8 +42,6 @@
<string name="car_permission_desc_projection" msgid="2352178999656292944">"Ermöglicht einer App, den Bildschirm eines Smartphones auf das Display des Autos zu übertragen."</string>
<string name="car_permission_label_access_projection_status" msgid="4231618890836627402">"auf den Projektionsstatus zuzugreifen"</string>
<string name="car_permission_desc_access_projection_status" msgid="8497351979100616278">"Ermöglicht einer App, den Status anderer Apps,abzurufen, die auf das Display des Autos übertragen werden."</string>
- <string name="car_permission_label_bind_projection_service" msgid="5362076216606651526">"sich an einen Projektionsdienst zu binden"</string>
- <string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"Ermöglicht dem Inhaber, sich an die Oberfläche eines Projektionsdienstes auf oberster Ebene zu binden. Sollte für normale Apps nie benötigt werden."</string>
<string name="car_permission_label_audio_volume" msgid="310587969373137690">"die Lautstärke der Audioanlage des Autos zu steuern"</string>
<string name="car_permission_label_audio_settings" msgid="6524703796944023977">"die Einstellungen der Audioanlage des Autos zu verwalten"</string>
<string name="car_permission_label_mock_vehicle_hal" msgid="7198852512207405935">"Fahrzeug-HAL emulieren"</string>
@@ -62,8 +60,6 @@
<string name="car_permission_desc_car_cluster_control" msgid="9222776665281176031">"Apps im Kombi-Instrument starten"</string>
<string name="car_permission_car_monitor_cluster_navigation_state" msgid="7025307242306902441">"Kombi-Instrumenten-Navigationsstatus"</string>
<string name="car_permission_desc_car_monitor_cluster_navigation_state" msgid="8745047153878713339">"Auf Änderungen des Kombi-Instrumenten-Navigationsstatus achten"</string>
- <string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"Kombi-Instrument-Rendering"</string>
- <string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"Daten von Kombi-Instrument erhalten"</string>
<string name="car_permission_label_car_ux_restrictions_configuration" msgid="6801393970411049725">"UX-Einschränkungen konfigurieren"</string>
<string name="car_permission_desc_car_ux_restrictions_configuration" msgid="5711926927484813777">"UX-Einschränkungen konfigurieren"</string>
<string name="car_permission_label_access_private_display_id" msgid="6712116114341634316">"Lesezugriff auf private Display-ID"</string>
@@ -74,8 +70,6 @@
<string name="car_permission_desc_read_car_occupant_awareness_state" msgid="188865882598414986">"Berechtigung, die Status- und Erkennungsdaten des Occupant Awareness System zu lesen"</string>
<string name="car_permission_label_control_car_occupant_awareness_system" msgid="7163330266691094542">"Occupant Awareness System Graph steuern"</string>
<string name="car_permission_desc_control_car_occupant_awareness_system" msgid="7123482622084531911">"Berechtigung, den Start- und Stoppvorgang des Occupant Awareness System-Erkennungsgraphen zu steuern"</string>
- <string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Eingabedienst für das Auto"</string>
- <string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Eingabe-Ereignisse verwalten"</string>
<string name="car_permission_label_diag_read" msgid="7248894224877702604">"Fehlerberichte zu lesen"</string>
<string name="car_permission_desc_diag_read" msgid="1121426363040966178">"Fehlerberichte des Autos lesen."</string>
<string name="car_permission_label_diag_clear" msgid="4783070510879698157">"Fehlerberichte zu löschen"</string>
@@ -84,8 +78,6 @@
<string name="car_permission_desc_vms_publisher" msgid="5589489298597386828">"VMS-Meldungen senden"</string>
<string name="car_permission_label_vms_subscriber" msgid="5648841182059222299">"VMS-Abonnent"</string>
<string name="car_permission_desc_vms_subscriber" msgid="7551009457847673620">"VMS-Meldungen abonnieren"</string>
- <string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"VMS-Clientdienst"</string>
- <string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"An VMS-Clients binden"</string>
<string name="car_permission_label_storage_monitoring" msgid="2327639346522530549">"Flash-Speicher-Nutzung verfolgen"</string>
<string name="car_permission_desc_storage_monitoring" msgid="2075712271139671318">"Flash-Speicher-Nutzung verfolgen"</string>
<string name="car_permission_label_driving_state" msgid="7754624599537393650">"Informationen zum Fahrzustand entgegenzunehmen"</string>
diff --git a/service/res/values-el/strings.xml b/service/res/values-el/strings.xml
index 4804b72..84f8a50 100644
--- a/service/res/values-el/strings.xml
+++ b/service/res/values-el/strings.xml
@@ -42,8 +42,6 @@
<string name="car_permission_desc_projection" msgid="2352178999656292944">"Επιτρέπει σε μια εφαρμογή να προβάλλει μια διεπαφή από ένα τηλέφωνο στην οθόνη του αυτοκινήτου."</string>
<string name="car_permission_label_access_projection_status" msgid="4231618890836627402">"πρόσβαση στην κατάσταση προβολής"</string>
<string name="car_permission_desc_access_projection_status" msgid="8497351979100616278">"Επιτρέπει σε μια εφαρμογή να λάβει την κατάσταση άλλων εφαρμογών που προβάλλουν στην οθόνη ενός αυτοκινήτου."</string>
- <string name="car_permission_label_bind_projection_service" msgid="5362076216606651526">"σύνδεση σε υπηρεσία προβολής"</string>
- <string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"Επιτρέπει στον κάτοχο τη δέσμευση στη διεπαφή ανωτάτου επιπέδου μιας υπηρεσίας προβολής. Δεν απαιτείται ποτέ για κανονικές εφαρμογές."</string>
<string name="car_permission_label_audio_volume" msgid="310587969373137690">"έλεγχος έντασης ήχου αυτοκινήτου"</string>
<string name="car_permission_label_audio_settings" msgid="6524703796944023977">"διαχείριση των ρυθμίσεων ήχου του αυτοκινήτου"</string>
<string name="car_permission_label_mock_vehicle_hal" msgid="7198852512207405935">"προσομοίωση HAL οχήματος"</string>
@@ -62,8 +60,6 @@
<string name="car_permission_desc_car_cluster_control" msgid="9222776665281176031">"Εκκίνηση εφαρμογών στο καντράν"</string>
<string name="car_permission_car_monitor_cluster_navigation_state" msgid="7025307242306902441">"Κατάσταση πλοήγησης στο καντράν"</string>
<string name="car_permission_desc_car_monitor_cluster_navigation_state" msgid="8745047153878713339">"Ακρόαση για αλλαγές κατάστασης πλοήγησης στο καντράν"</string>
- <string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"Απόδοση καντράν"</string>
- <string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"Λήψη δεδομένων καντράν"</string>
<string name="car_permission_label_car_ux_restrictions_configuration" msgid="6801393970411049725">"Διαμόρφωση περιορισμών εμπειρίας χρήστη"</string>
<string name="car_permission_desc_car_ux_restrictions_configuration" msgid="5711926927484813777">"Διαμόρφωση περιορισμών εμπειρίας χρήστη"</string>
<string name="car_permission_label_access_private_display_id" msgid="6712116114341634316">"Πρόσβαση ανάγνωσης στο ιδιωτικό αναγνωριστικό οθόνης"</string>
@@ -74,8 +70,6 @@
<string name="car_permission_desc_read_car_occupant_awareness_state" msgid="188865882598414986">"Επιτρέπει την ανάγνωση των δεδομένων κατάστασης και ανίχνευσης του συστήματος ελέγχου συμπεριφοράς οδηγού."</string>
<string name="car_permission_label_control_car_occupant_awareness_system" msgid="7163330266691094542">"Έλεγχος γραφήματος συστήματος ελέγχου συμπεριφοράς οδηγού"</string>
<string name="car_permission_desc_control_car_occupant_awareness_system" msgid="7123482622084531911">"Επιτρέπει τον έλεγχο της έναρξης και της διακοπής του γραφήματος ανίχνευσης του συστήματος ελέγχου συμπεριφοράς οδηγού."</string>
- <string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Υπηρεσία εισόδου αυτοκινήτου"</string>
- <string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Χειρισμός συμβάντων εισόδου"</string>
<string name="car_permission_label_diag_read" msgid="7248894224877702604">"παρακολούθηση δεδομένων διαγνωστικών στοιχείων"</string>
<string name="car_permission_desc_diag_read" msgid="1121426363040966178">"Παρακολούθηση δεδομένων διαγνωστικών στοιχείων από το αυτοκίνητο."</string>
<string name="car_permission_label_diag_clear" msgid="4783070510879698157">"διαγραφή δεδομένων διαγνωστικών στοιχείων"</string>
@@ -84,8 +78,6 @@
<string name="car_permission_desc_vms_publisher" msgid="5589489298597386828">"Δημοσίευση μηνυμάτων VMS"</string>
<string name="car_permission_label_vms_subscriber" msgid="5648841182059222299">"Εγγεγραμμένη εφαρμογή VMS"</string>
<string name="car_permission_desc_vms_subscriber" msgid="7551009457847673620">"Εγγραφή σε μηνύματα VMS"</string>
- <string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"Υπηρεσία εφαρμογής πελάτη VMS"</string>
- <string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"Δέσμευση σε εφαρμογές πελάτη VMS"</string>
<string name="car_permission_label_storage_monitoring" msgid="2327639346522530549">"Παρακολούθηση αποθηκευτικού χώρου flash"</string>
<string name="car_permission_desc_storage_monitoring" msgid="2075712271139671318">"Παρακολούθηση χρήσης αποθηκευτικού χώρου flash"</string>
<string name="car_permission_label_driving_state" msgid="7754624599537393650">"ακρόαση κατάστασης οδήγησης"</string>
diff --git a/service/res/values-en-rAU/strings.xml b/service/res/values-en-rAU/strings.xml
index 8c4cf61..ef982fb 100644
--- a/service/res/values-en-rAU/strings.xml
+++ b/service/res/values-en-rAU/strings.xml
@@ -42,8 +42,6 @@
<string name="car_permission_desc_projection" msgid="2352178999656292944">"Allows an app to project an interface from a phone on the car’s display."</string>
<string name="car_permission_label_access_projection_status" msgid="4231618890836627402">"access projection status"</string>
<string name="car_permission_desc_access_projection_status" msgid="8497351979100616278">"Allows an app to get the status of other apps projecting to the car’s display."</string>
- <string name="car_permission_label_bind_projection_service" msgid="5362076216606651526">"bind to a projection service"</string>
- <string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"Allows the holder to bind to the top-level interface of a projection service. Should never be needed for normal apps."</string>
<string name="car_permission_label_audio_volume" msgid="310587969373137690">"control car’s audio volume"</string>
<string name="car_permission_label_audio_settings" msgid="6524703796944023977">"manage car’s audio settings"</string>
<string name="car_permission_label_mock_vehicle_hal" msgid="7198852512207405935">"emulate vehicle HAL"</string>
@@ -62,8 +60,6 @@
<string name="car_permission_desc_car_cluster_control" msgid="9222776665281176031">"Launch apps in the instrument cluster"</string>
<string name="car_permission_car_monitor_cluster_navigation_state" msgid="7025307242306902441">"Instrument cluster navigation state"</string>
<string name="car_permission_desc_car_monitor_cluster_navigation_state" msgid="8745047153878713339">"Listen for instrument cluster navigation state changes"</string>
- <string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"Instrument cluster rendering"</string>
- <string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"Receive instrument cluster data"</string>
<string name="car_permission_label_car_ux_restrictions_configuration" msgid="6801393970411049725">"UX restrictions configuration"</string>
<string name="car_permission_desc_car_ux_restrictions_configuration" msgid="5711926927484813777">"Configure UX restrictions"</string>
<string name="car_permission_label_access_private_display_id" msgid="6712116114341634316">"Read access to private display ID"</string>
@@ -74,8 +70,6 @@
<string name="car_permission_desc_read_car_occupant_awareness_state" msgid="188865882598414986">"Allows reading status and detection data for occupant awareness system"</string>
<string name="car_permission_label_control_car_occupant_awareness_system" msgid="7163330266691094542">"Control occupant awareness system graph"</string>
<string name="car_permission_desc_control_car_occupant_awareness_system" msgid="7123482622084531911">"Allows controlling the start and stop of the occupant awareness system detection graph"</string>
- <string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Car input service"</string>
- <string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Handle input events"</string>
<string name="car_permission_label_diag_read" msgid="7248894224877702604">"read diagnostic data"</string>
<string name="car_permission_desc_diag_read" msgid="1121426363040966178">"Read diagnostic data from the car."</string>
<string name="car_permission_label_diag_clear" msgid="4783070510879698157">"clear diagnostic data"</string>
@@ -84,8 +78,6 @@
<string name="car_permission_desc_vms_publisher" msgid="5589489298597386828">"Publish VMS messages"</string>
<string name="car_permission_label_vms_subscriber" msgid="5648841182059222299">"VMS Subscriber"</string>
<string name="car_permission_desc_vms_subscriber" msgid="7551009457847673620">"Subscribe to VMS messages"</string>
- <string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"VMS Client Service"</string>
- <string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"Bind to VMS clients"</string>
<string name="car_permission_label_storage_monitoring" msgid="2327639346522530549">"Flash storage monitoring"</string>
<string name="car_permission_desc_storage_monitoring" msgid="2075712271139671318">"Monitor flash storage usage"</string>
<string name="car_permission_label_driving_state" msgid="7754624599537393650">"listen to driving state"</string>
diff --git a/service/res/values-en-rCA/strings.xml b/service/res/values-en-rCA/strings.xml
index 8c4cf61..ef982fb 100644
--- a/service/res/values-en-rCA/strings.xml
+++ b/service/res/values-en-rCA/strings.xml
@@ -42,8 +42,6 @@
<string name="car_permission_desc_projection" msgid="2352178999656292944">"Allows an app to project an interface from a phone on the car’s display."</string>
<string name="car_permission_label_access_projection_status" msgid="4231618890836627402">"access projection status"</string>
<string name="car_permission_desc_access_projection_status" msgid="8497351979100616278">"Allows an app to get the status of other apps projecting to the car’s display."</string>
- <string name="car_permission_label_bind_projection_service" msgid="5362076216606651526">"bind to a projection service"</string>
- <string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"Allows the holder to bind to the top-level interface of a projection service. Should never be needed for normal apps."</string>
<string name="car_permission_label_audio_volume" msgid="310587969373137690">"control car’s audio volume"</string>
<string name="car_permission_label_audio_settings" msgid="6524703796944023977">"manage car’s audio settings"</string>
<string name="car_permission_label_mock_vehicle_hal" msgid="7198852512207405935">"emulate vehicle HAL"</string>
@@ -62,8 +60,6 @@
<string name="car_permission_desc_car_cluster_control" msgid="9222776665281176031">"Launch apps in the instrument cluster"</string>
<string name="car_permission_car_monitor_cluster_navigation_state" msgid="7025307242306902441">"Instrument cluster navigation state"</string>
<string name="car_permission_desc_car_monitor_cluster_navigation_state" msgid="8745047153878713339">"Listen for instrument cluster navigation state changes"</string>
- <string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"Instrument cluster rendering"</string>
- <string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"Receive instrument cluster data"</string>
<string name="car_permission_label_car_ux_restrictions_configuration" msgid="6801393970411049725">"UX restrictions configuration"</string>
<string name="car_permission_desc_car_ux_restrictions_configuration" msgid="5711926927484813777">"Configure UX restrictions"</string>
<string name="car_permission_label_access_private_display_id" msgid="6712116114341634316">"Read access to private display ID"</string>
@@ -74,8 +70,6 @@
<string name="car_permission_desc_read_car_occupant_awareness_state" msgid="188865882598414986">"Allows reading status and detection data for occupant awareness system"</string>
<string name="car_permission_label_control_car_occupant_awareness_system" msgid="7163330266691094542">"Control occupant awareness system graph"</string>
<string name="car_permission_desc_control_car_occupant_awareness_system" msgid="7123482622084531911">"Allows controlling the start and stop of the occupant awareness system detection graph"</string>
- <string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Car input service"</string>
- <string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Handle input events"</string>
<string name="car_permission_label_diag_read" msgid="7248894224877702604">"read diagnostic data"</string>
<string name="car_permission_desc_diag_read" msgid="1121426363040966178">"Read diagnostic data from the car."</string>
<string name="car_permission_label_diag_clear" msgid="4783070510879698157">"clear diagnostic data"</string>
@@ -84,8 +78,6 @@
<string name="car_permission_desc_vms_publisher" msgid="5589489298597386828">"Publish VMS messages"</string>
<string name="car_permission_label_vms_subscriber" msgid="5648841182059222299">"VMS Subscriber"</string>
<string name="car_permission_desc_vms_subscriber" msgid="7551009457847673620">"Subscribe to VMS messages"</string>
- <string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"VMS Client Service"</string>
- <string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"Bind to VMS clients"</string>
<string name="car_permission_label_storage_monitoring" msgid="2327639346522530549">"Flash storage monitoring"</string>
<string name="car_permission_desc_storage_monitoring" msgid="2075712271139671318">"Monitor flash storage usage"</string>
<string name="car_permission_label_driving_state" msgid="7754624599537393650">"listen to driving state"</string>
diff --git a/service/res/values-en-rGB/strings.xml b/service/res/values-en-rGB/strings.xml
index 8c4cf61..ef982fb 100644
--- a/service/res/values-en-rGB/strings.xml
+++ b/service/res/values-en-rGB/strings.xml
@@ -42,8 +42,6 @@
<string name="car_permission_desc_projection" msgid="2352178999656292944">"Allows an app to project an interface from a phone on the car’s display."</string>
<string name="car_permission_label_access_projection_status" msgid="4231618890836627402">"access projection status"</string>
<string name="car_permission_desc_access_projection_status" msgid="8497351979100616278">"Allows an app to get the status of other apps projecting to the car’s display."</string>
- <string name="car_permission_label_bind_projection_service" msgid="5362076216606651526">"bind to a projection service"</string>
- <string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"Allows the holder to bind to the top-level interface of a projection service. Should never be needed for normal apps."</string>
<string name="car_permission_label_audio_volume" msgid="310587969373137690">"control car’s audio volume"</string>
<string name="car_permission_label_audio_settings" msgid="6524703796944023977">"manage car’s audio settings"</string>
<string name="car_permission_label_mock_vehicle_hal" msgid="7198852512207405935">"emulate vehicle HAL"</string>
@@ -62,8 +60,6 @@
<string name="car_permission_desc_car_cluster_control" msgid="9222776665281176031">"Launch apps in the instrument cluster"</string>
<string name="car_permission_car_monitor_cluster_navigation_state" msgid="7025307242306902441">"Instrument cluster navigation state"</string>
<string name="car_permission_desc_car_monitor_cluster_navigation_state" msgid="8745047153878713339">"Listen for instrument cluster navigation state changes"</string>
- <string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"Instrument cluster rendering"</string>
- <string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"Receive instrument cluster data"</string>
<string name="car_permission_label_car_ux_restrictions_configuration" msgid="6801393970411049725">"UX restrictions configuration"</string>
<string name="car_permission_desc_car_ux_restrictions_configuration" msgid="5711926927484813777">"Configure UX restrictions"</string>
<string name="car_permission_label_access_private_display_id" msgid="6712116114341634316">"Read access to private display ID"</string>
@@ -74,8 +70,6 @@
<string name="car_permission_desc_read_car_occupant_awareness_state" msgid="188865882598414986">"Allows reading status and detection data for occupant awareness system"</string>
<string name="car_permission_label_control_car_occupant_awareness_system" msgid="7163330266691094542">"Control occupant awareness system graph"</string>
<string name="car_permission_desc_control_car_occupant_awareness_system" msgid="7123482622084531911">"Allows controlling the start and stop of the occupant awareness system detection graph"</string>
- <string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Car input service"</string>
- <string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Handle input events"</string>
<string name="car_permission_label_diag_read" msgid="7248894224877702604">"read diagnostic data"</string>
<string name="car_permission_desc_diag_read" msgid="1121426363040966178">"Read diagnostic data from the car."</string>
<string name="car_permission_label_diag_clear" msgid="4783070510879698157">"clear diagnostic data"</string>
@@ -84,8 +78,6 @@
<string name="car_permission_desc_vms_publisher" msgid="5589489298597386828">"Publish VMS messages"</string>
<string name="car_permission_label_vms_subscriber" msgid="5648841182059222299">"VMS Subscriber"</string>
<string name="car_permission_desc_vms_subscriber" msgid="7551009457847673620">"Subscribe to VMS messages"</string>
- <string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"VMS Client Service"</string>
- <string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"Bind to VMS clients"</string>
<string name="car_permission_label_storage_monitoring" msgid="2327639346522530549">"Flash storage monitoring"</string>
<string name="car_permission_desc_storage_monitoring" msgid="2075712271139671318">"Monitor flash storage usage"</string>
<string name="car_permission_label_driving_state" msgid="7754624599537393650">"listen to driving state"</string>
diff --git a/service/res/values-en-rIN/strings.xml b/service/res/values-en-rIN/strings.xml
index 8c4cf61..ef982fb 100644
--- a/service/res/values-en-rIN/strings.xml
+++ b/service/res/values-en-rIN/strings.xml
@@ -42,8 +42,6 @@
<string name="car_permission_desc_projection" msgid="2352178999656292944">"Allows an app to project an interface from a phone on the car’s display."</string>
<string name="car_permission_label_access_projection_status" msgid="4231618890836627402">"access projection status"</string>
<string name="car_permission_desc_access_projection_status" msgid="8497351979100616278">"Allows an app to get the status of other apps projecting to the car’s display."</string>
- <string name="car_permission_label_bind_projection_service" msgid="5362076216606651526">"bind to a projection service"</string>
- <string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"Allows the holder to bind to the top-level interface of a projection service. Should never be needed for normal apps."</string>
<string name="car_permission_label_audio_volume" msgid="310587969373137690">"control car’s audio volume"</string>
<string name="car_permission_label_audio_settings" msgid="6524703796944023977">"manage car’s audio settings"</string>
<string name="car_permission_label_mock_vehicle_hal" msgid="7198852512207405935">"emulate vehicle HAL"</string>
@@ -62,8 +60,6 @@
<string name="car_permission_desc_car_cluster_control" msgid="9222776665281176031">"Launch apps in the instrument cluster"</string>
<string name="car_permission_car_monitor_cluster_navigation_state" msgid="7025307242306902441">"Instrument cluster navigation state"</string>
<string name="car_permission_desc_car_monitor_cluster_navigation_state" msgid="8745047153878713339">"Listen for instrument cluster navigation state changes"</string>
- <string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"Instrument cluster rendering"</string>
- <string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"Receive instrument cluster data"</string>
<string name="car_permission_label_car_ux_restrictions_configuration" msgid="6801393970411049725">"UX restrictions configuration"</string>
<string name="car_permission_desc_car_ux_restrictions_configuration" msgid="5711926927484813777">"Configure UX restrictions"</string>
<string name="car_permission_label_access_private_display_id" msgid="6712116114341634316">"Read access to private display ID"</string>
@@ -74,8 +70,6 @@
<string name="car_permission_desc_read_car_occupant_awareness_state" msgid="188865882598414986">"Allows reading status and detection data for occupant awareness system"</string>
<string name="car_permission_label_control_car_occupant_awareness_system" msgid="7163330266691094542">"Control occupant awareness system graph"</string>
<string name="car_permission_desc_control_car_occupant_awareness_system" msgid="7123482622084531911">"Allows controlling the start and stop of the occupant awareness system detection graph"</string>
- <string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Car input service"</string>
- <string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Handle input events"</string>
<string name="car_permission_label_diag_read" msgid="7248894224877702604">"read diagnostic data"</string>
<string name="car_permission_desc_diag_read" msgid="1121426363040966178">"Read diagnostic data from the car."</string>
<string name="car_permission_label_diag_clear" msgid="4783070510879698157">"clear diagnostic data"</string>
@@ -84,8 +78,6 @@
<string name="car_permission_desc_vms_publisher" msgid="5589489298597386828">"Publish VMS messages"</string>
<string name="car_permission_label_vms_subscriber" msgid="5648841182059222299">"VMS Subscriber"</string>
<string name="car_permission_desc_vms_subscriber" msgid="7551009457847673620">"Subscribe to VMS messages"</string>
- <string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"VMS Client Service"</string>
- <string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"Bind to VMS clients"</string>
<string name="car_permission_label_storage_monitoring" msgid="2327639346522530549">"Flash storage monitoring"</string>
<string name="car_permission_desc_storage_monitoring" msgid="2075712271139671318">"Monitor flash storage usage"</string>
<string name="car_permission_label_driving_state" msgid="7754624599537393650">"listen to driving state"</string>
diff --git a/service/res/values-en-rXC/strings.xml b/service/res/values-en-rXC/strings.xml
index 31cc3ea..7be1b4c 100644
--- a/service/res/values-en-rXC/strings.xml
+++ b/service/res/values-en-rXC/strings.xml
@@ -42,8 +42,6 @@
<string name="car_permission_desc_projection" msgid="2352178999656292944">"Allows an app to project an interface from a phone on the car’s display."</string>
<string name="car_permission_label_access_projection_status" msgid="4231618890836627402">"access projection status"</string>
<string name="car_permission_desc_access_projection_status" msgid="8497351979100616278">"Allows an app to get the status of other apps projecting to the car’s display."</string>
- <string name="car_permission_label_bind_projection_service" msgid="5362076216606651526">"bind to a projection service"</string>
- <string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"Allows the holder to bind to the top-level interface of a projection service. Should never be needed for normal apps."</string>
<string name="car_permission_label_audio_volume" msgid="310587969373137690">"control car’s audio volume"</string>
<string name="car_permission_label_audio_settings" msgid="6524703796944023977">"manage car’s audio settings"</string>
<string name="car_permission_label_mock_vehicle_hal" msgid="7198852512207405935">"emulate vehicle HAL"</string>
@@ -62,8 +60,6 @@
<string name="car_permission_desc_car_cluster_control" msgid="9222776665281176031">"Launch apps in the instrument cluster"</string>
<string name="car_permission_car_monitor_cluster_navigation_state" msgid="7025307242306902441">"Instrument cluster navigation state"</string>
<string name="car_permission_desc_car_monitor_cluster_navigation_state" msgid="8745047153878713339">"Listen for instrument cluster navigation state changes"</string>
- <string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"Instrument Cluster Rendering"</string>
- <string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"Receive instrument cluster data"</string>
<string name="car_permission_label_car_ux_restrictions_configuration" msgid="6801393970411049725">"UX Restrictions Configuration"</string>
<string name="car_permission_desc_car_ux_restrictions_configuration" msgid="5711926927484813777">"Configure UX Restrictions"</string>
<string name="car_permission_label_access_private_display_id" msgid="6712116114341634316">"Read access to private display id"</string>
@@ -74,8 +70,6 @@
<string name="car_permission_desc_read_car_occupant_awareness_state" msgid="188865882598414986">"Allows reading status and detection data for Occupant Awareness System"</string>
<string name="car_permission_label_control_car_occupant_awareness_system" msgid="7163330266691094542">"Control Occupant Awareness System Graph"</string>
<string name="car_permission_desc_control_car_occupant_awareness_system" msgid="7123482622084531911">"Allows controlling the start and stopping of the Occupant Awareness System detection graph"</string>
- <string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Car Input Service"</string>
- <string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Handle input events"</string>
<string name="car_permission_label_diag_read" msgid="7248894224877702604">"read diagnostic data"</string>
<string name="car_permission_desc_diag_read" msgid="1121426363040966178">"Read diagnostic data from the car."</string>
<string name="car_permission_label_diag_clear" msgid="4783070510879698157">"clear diagnostic data"</string>
@@ -84,8 +78,6 @@
<string name="car_permission_desc_vms_publisher" msgid="5589489298597386828">"Publish VMS messages"</string>
<string name="car_permission_label_vms_subscriber" msgid="5648841182059222299">"VMS Subscriber"</string>
<string name="car_permission_desc_vms_subscriber" msgid="7551009457847673620">"Subscribe to VMS messages"</string>
- <string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"VMS Client Service"</string>
- <string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"Bind to VMS clients"</string>
<string name="car_permission_label_storage_monitoring" msgid="2327639346522530549">"Flash storage monitoring"</string>
<string name="car_permission_desc_storage_monitoring" msgid="2075712271139671318">"Monitor flash storage usage"</string>
<string name="car_permission_label_driving_state" msgid="7754624599537393650">"listen to driving state"</string>
diff --git a/service/res/values-es-rUS/strings.xml b/service/res/values-es-rUS/strings.xml
index fa86329..234fc95 100644
--- a/service/res/values-es-rUS/strings.xml
+++ b/service/res/values-es-rUS/strings.xml
@@ -42,8 +42,6 @@
<string name="car_permission_desc_projection" msgid="2352178999656292944">"Permite que una app proyecte la interfaz de un teléfono en la pantalla del vehículo."</string>
<string name="car_permission_label_access_projection_status" msgid="4231618890836627402">"acceder al estado de proyección"</string>
<string name="car_permission_desc_access_projection_status" msgid="8497351979100616278">"Permite que una app obtenga el estado de otras que se proyectan en la pantalla del vehículo."</string>
- <string name="car_permission_label_bind_projection_service" msgid="5362076216606651526">"vincular un servicio de proyección"</string>
- <string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"Permite al propietario vincularse a la interfaz de nivel superior de un servicio de proyección. Las apps normales no deberían necesitar este permiso."</string>
<string name="car_permission_label_audio_volume" msgid="310587969373137690">"controlar el volumen de audio del vehículo"</string>
<string name="car_permission_label_audio_settings" msgid="6524703796944023977">"administrar la configuración de audio del vehículo"</string>
<string name="car_permission_label_mock_vehicle_hal" msgid="7198852512207405935">"emular HAL del vehículo"</string>
@@ -62,8 +60,6 @@
<string name="car_permission_desc_car_cluster_control" msgid="9222776665281176031">"Iniciar apps en el clúster de instrumentos"</string>
<string name="car_permission_car_monitor_cluster_navigation_state" msgid="7025307242306902441">"Estado del clúster de instrumentos del navegación"</string>
<string name="car_permission_desc_car_monitor_cluster_navigation_state" msgid="8745047153878713339">"Escucha los cambios de estado del clúster de instrumentos del navegación"</string>
- <string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"Procesamiento de clúster de instrumentos"</string>
- <string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"Recibir datos del clúster de instrumentos"</string>
<string name="car_permission_label_car_ux_restrictions_configuration" msgid="6801393970411049725">"Configuración de restricciones de UX"</string>
<string name="car_permission_desc_car_ux_restrictions_configuration" msgid="5711926927484813777">"Configurar restricciones de UX"</string>
<string name="car_permission_label_access_private_display_id" msgid="6712116114341634316">"Acceso de lectura para un ID de pantalla privado"</string>
@@ -74,8 +70,6 @@
<string name="car_permission_desc_read_car_occupant_awareness_state" msgid="188865882598414986">"Permite leer el estado y los datos de detección del Sistema de detección de ocupantes"</string>
<string name="car_permission_label_control_car_occupant_awareness_system" msgid="7163330266691094542">"Control del gráfico del Sistema de detección de ocupantes"</string>
<string name="car_permission_desc_control_car_occupant_awareness_system" msgid="7123482622084531911">"Permite controlar el inicio y la detención del gráfico de detección del Sistema de detección de ocupantes"</string>
- <string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Servicio de entrada del auto"</string>
- <string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Controlar eventos de entrada"</string>
<string name="car_permission_label_diag_read" msgid="7248894224877702604">"leer datos de diagnóstico"</string>
<string name="car_permission_desc_diag_read" msgid="1121426363040966178">"Leer datos de diagnóstico del vehículo."</string>
<string name="car_permission_label_diag_clear" msgid="4783070510879698157">"borrar datos de diagnóstico"</string>
@@ -84,8 +78,6 @@
<string name="car_permission_desc_vms_publisher" msgid="5589489298597386828">"Publicar mensajes VMS"</string>
<string name="car_permission_label_vms_subscriber" msgid="5648841182059222299">"Suscriptor de VMS"</string>
<string name="car_permission_desc_vms_subscriber" msgid="7551009457847673620">"Suscribirse a mensajes VMS"</string>
- <string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"Servicio del cliente de VMS"</string>
- <string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"Vincular a clientes VMS"</string>
<string name="car_permission_label_storage_monitoring" msgid="2327639346522530549">"Supervisión del almacenamiento flash"</string>
<string name="car_permission_desc_storage_monitoring" msgid="2075712271139671318">"Controlar el uso del almacenamiento flash"</string>
<string name="car_permission_label_driving_state" msgid="7754624599537393650">"escuchar el estado de conducción"</string>
diff --git a/service/res/values-es/strings.xml b/service/res/values-es/strings.xml
index eb1bed3..4f84835 100644
--- a/service/res/values-es/strings.xml
+++ b/service/res/values-es/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="2215078736675564541">"Información sobre el coche"</string>
+ <string name="car_permission_label" msgid="2215078736675564541">"información sobre el coche"</string>
<string name="car_permission_desc" msgid="3584369074931334964">"acceder a los datos de tu coche"</string>
<string name="car_permission_label_camera" msgid="3725702064841827180">"acceder a la cámara del coche"</string>
<string name="car_permission_desc_camera" msgid="917024932164501426">"Acceder a las cámaras del coche."</string>
@@ -42,8 +42,6 @@
<string name="car_permission_desc_projection" msgid="2352178999656292944">"Permite que una aplicación proyecte la interfaz de un teléfono en la pantalla del coche."</string>
<string name="car_permission_label_access_projection_status" msgid="4231618890836627402">"acceder al estado de proyección"</string>
<string name="car_permission_desc_access_projection_status" msgid="8497351979100616278">"Permite que una aplicación consulte el estado de otras aplicaciones proyectadas en la pantalla del coche."</string>
- <string name="car_permission_label_bind_projection_service" msgid="5362076216606651526">"vincular un servicio de proyección"</string>
- <string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"Permite al titular vincular con la interfaz de nivel superior de un servicio de proyección. Las aplicaciones normales no deberían necesitar este permiso."</string>
<string name="car_permission_label_audio_volume" msgid="310587969373137690">"controlar el volumen del audio del coche"</string>
<string name="car_permission_label_audio_settings" msgid="6524703796944023977">"gestionar los ajustes de audio del coche"</string>
<string name="car_permission_label_mock_vehicle_hal" msgid="7198852512207405935">"emular HAL del vehículo"</string>
@@ -62,8 +60,6 @@
<string name="car_permission_desc_car_cluster_control" msgid="9222776665281176031">"Iniciar aplicaciones en el panel de instrumentos"</string>
<string name="car_permission_car_monitor_cluster_navigation_state" msgid="7025307242306902441">"Estado de navegación del clúster de instrumentos"</string>
<string name="car_permission_desc_car_monitor_cluster_navigation_state" msgid="8745047153878713339">"Escucha los cambios en el estado de navegación del clúster de instrumentos"</string>
- <string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"Representación de datos en el panel de instrumentos"</string>
- <string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"Recibir datos del panel de instrumentos"</string>
<string name="car_permission_label_car_ux_restrictions_configuration" msgid="6801393970411049725">"Configuración de restricciones de la experiencia de usuario"</string>
<string name="car_permission_desc_car_ux_restrictions_configuration" msgid="5711926927484813777">"Configurar restricciones de la experiencia de usuario"</string>
<string name="car_permission_label_access_private_display_id" msgid="6712116114341634316">"Acceso de lectura al ID privado de pantalla"</string>
@@ -74,8 +70,6 @@
<string name="car_permission_desc_read_car_occupant_awareness_state" msgid="188865882598414986">"Permite leer el estado y los datos de detección del sistema de detección de ocupantes"</string>
<string name="car_permission_label_control_car_occupant_awareness_system" msgid="7163330266691094542">"Controlar el gráfico del sistema de detección de ocupantes"</string>
<string name="car_permission_desc_control_car_occupant_awareness_system" msgid="7123482622084531911">"Permite configurar el inicio y las pausas del gráfico de detección del sistema de detección de ocupantes"</string>
- <string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Servicio de entrada del coche"</string>
- <string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Gestionar eventos de entrada"</string>
<string name="car_permission_label_diag_read" msgid="7248894224877702604">"consultar datos de diagnóstico"</string>
<string name="car_permission_desc_diag_read" msgid="1121426363040966178">"Consultar los datos de diagnóstico del coche."</string>
<string name="car_permission_label_diag_clear" msgid="4783070510879698157">"borrar los datos de diagnóstico"</string>
@@ -84,8 +78,6 @@
<string name="car_permission_desc_vms_publisher" msgid="5589489298597386828">"Publicar mensajes VMS"</string>
<string name="car_permission_label_vms_subscriber" msgid="5648841182059222299">"Suscriptor de VMS"</string>
<string name="car_permission_desc_vms_subscriber" msgid="7551009457847673620">"Suscribirse a mensajes VMS"</string>
- <string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"Servicio de cliente de VMS"</string>
- <string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"Vincular con clientes VMS"</string>
<string name="car_permission_label_storage_monitoring" msgid="2327639346522530549">"Supervisión de almacenamiento flash"</string>
<string name="car_permission_desc_storage_monitoring" msgid="2075712271139671318">"Supervisar uso del almacenamiento flash"</string>
<string name="car_permission_label_driving_state" msgid="7754624599537393650">"detectar el estado de conducción"</string>
diff --git a/service/res/values-et/strings.xml b/service/res/values-et/strings.xml
index 4d51be3..13e4a8c 100644
--- a/service/res/values-et/strings.xml
+++ b/service/res/values-et/strings.xml
@@ -42,8 +42,6 @@
<string name="car_permission_desc_projection" msgid="2352178999656292944">"Lubab rakendusel liidese kuva projitseerida telefonist auto ekraanile."</string>
<string name="car_permission_label_access_projection_status" msgid="4231618890836627402">"juurdepääs projitseerimise olekule"</string>
<string name="car_permission_desc_access_projection_status" msgid="8497351979100616278">"Lubab rakendusel vaadata nende rakenduste olekut, mis kuva auto ekraanile projitseerivad."</string>
- <string name="car_permission_label_bind_projection_service" msgid="5362076216606651526">"sidumine projitseerimisteenusega"</string>
- <string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"Lubab omanikul siduda projitseerimisteenuse ülataseme liidesega. Tavarakenduste puhul ei peaks seda kunagi vaja minema."</string>
<string name="car_permission_label_audio_volume" msgid="310587969373137690">"auto helitugevuse juhtimine"</string>
<string name="car_permission_label_audio_settings" msgid="6524703796944023977">"auto heliseadete haldamine"</string>
<string name="car_permission_label_mock_vehicle_hal" msgid="7198852512207405935">"sõiduki HAL-i jäljendamine"</string>
@@ -62,8 +60,6 @@
<string name="car_permission_desc_car_cluster_control" msgid="9222776665281176031">"Kuva rakendusi näidikulaual"</string>
<string name="car_permission_car_monitor_cluster_navigation_state" msgid="7025307242306902441">"Näidikulaual navigeerimise olek"</string>
<string name="car_permission_desc_car_monitor_cluster_navigation_state" msgid="8745047153878713339">"Näidikuplokis navigeerimise oleku muudatuste kuulamine"</string>
- <string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"Näidikulaua renderdamine"</string>
- <string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"Näidikulaua teabe saamine"</string>
<string name="car_permission_label_car_ux_restrictions_configuration" msgid="6801393970411049725">"Kasutuskogemuse piirangute seadistus"</string>
<string name="car_permission_desc_car_ux_restrictions_configuration" msgid="5711926927484813777">"Kasutuskogemuse piirangute seadistamine"</string>
<string name="car_permission_label_access_private_display_id" msgid="6712116114341634316">"Lugemisega juurdepääs privaatse ekraani ID-le"</string>
@@ -74,8 +70,6 @@
<string name="car_permission_desc_read_car_occupant_awareness_state" msgid="188865882598414986">"Võimaldab lugeda süsteemi Occupant Awareness System oleku- ja tuvastamisandmeid"</string>
<string name="car_permission_label_control_car_occupant_awareness_system" msgid="7163330266691094542">"Süsteemi Occupant Awareness System graafiku juhtimine"</string>
<string name="car_permission_desc_control_car_occupant_awareness_system" msgid="7123482622084531911">"Võimaldab juhtida süsteemi Occupant Awareness System tuvastamisgraafiku käivitamist ja peatamist"</string>
- <string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Auto sisendteenus"</string>
- <string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Sisestussündmuste töötlemine"</string>
<string name="car_permission_label_diag_read" msgid="7248894224877702604">"diagnostikaandmete lugemine"</string>
<string name="car_permission_desc_diag_read" msgid="1121426363040966178">"Auto diagnostikaandmete lugemine."</string>
<string name="car_permission_label_diag_clear" msgid="4783070510879698157">"diagnostikaandmete kustutamine"</string>
@@ -84,8 +78,6 @@
<string name="car_permission_desc_vms_publisher" msgid="5589489298597386828">"VMS-sõnumite avaldamine"</string>
<string name="car_permission_label_vms_subscriber" msgid="5648841182059222299">"VMS-tellija"</string>
<string name="car_permission_desc_vms_subscriber" msgid="7551009457847673620">"VMS-sõnumite tellimine"</string>
- <string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"VMS-kliendi teenus"</string>
- <string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"Sidumine VMS-klientidega"</string>
<string name="car_permission_label_storage_monitoring" msgid="2327639346522530549">"Välkmälu jälgimine"</string>
<string name="car_permission_desc_storage_monitoring" msgid="2075712271139671318">"Välkmälu kasutuse jälgimine"</string>
<string name="car_permission_label_driving_state" msgid="7754624599537393650">"sõitmise oleku kuulamine"</string>
diff --git a/service/res/values-eu/strings.xml b/service/res/values-eu/strings.xml
index aa3fcb4..e1c2346 100644
--- a/service/res/values-eu/strings.xml
+++ b/service/res/values-eu/strings.xml
@@ -38,12 +38,10 @@
<string name="car_permission_desc_vendor_extension" msgid="2970718502334714035">"Atzitu auto-saltzailearen kanala autoari buruzko informazio zehatza trukatzeko."</string>
<string name="car_permission_label_radio" msgid="6009465291685935112">"kudeatu autoaren irratia"</string>
<string name="car_permission_desc_radio" msgid="3385999027478186964">"Atzitu autoaren irratia."</string>
- <string name="car_permission_label_projection" msgid="9107156380287576787">"proiektatu telefonoaren interfazea autoaren pantailan"</string>
- <string name="car_permission_desc_projection" msgid="2352178999656292944">"Telefonoaren interfazea autoaren pantailan proiektatzeko baimena ematen dio aplikazioari."</string>
+ <string name="car_permission_label_projection" msgid="9107156380287576787">"proiektatu telefonoaren interfazea autoko pantailan"</string>
+ <string name="car_permission_desc_projection" msgid="2352178999656292944">"Telefonoaren interfazea autoko pantailan proiektatzeko baimena ematen dio aplikazioari."</string>
<string name="car_permission_label_access_projection_status" msgid="4231618890836627402">"atzitu proiekzio-egoera"</string>
- <string name="car_permission_desc_access_projection_status" msgid="8497351979100616278">"Autoaren pantailan proiektatutako aplikazioen egoera atzitzeko baimena ematen dio aplikazioari."</string>
- <string name="car_permission_label_bind_projection_service" msgid="5362076216606651526">"lotu proiekzio-zerbitzu batekin"</string>
- <string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"Proiekzio-zerbitzu baten goi-mailako interfazeari lotzeko baimena ematen die titularrei. Aplikazio normalek ez lukete beharko."</string>
+ <string name="car_permission_desc_access_projection_status" msgid="8497351979100616278">"Autoko pantailan proiektatutako aplikazioen egoera atzitzeko baimena ematen dio aplikazioari."</string>
<string name="car_permission_label_audio_volume" msgid="310587969373137690">"kontrolatu autoaren audioaren bolumena"</string>
<string name="car_permission_label_audio_settings" msgid="6524703796944023977">"kudeatu autoaren audio-ezarpenak"</string>
<string name="car_permission_label_mock_vehicle_hal" msgid="7198852512207405935">"emulatu autoaren hardware-abstrakzioaren geruza (HAL)"</string>
@@ -62,8 +60,6 @@
<string name="car_permission_desc_car_cluster_control" msgid="9222776665281176031">"Abiarazi aplikazioak instrumentu lukuan"</string>
<string name="car_permission_car_monitor_cluster_navigation_state" msgid="7025307242306902441">"Instrumentuen lukuko nabigazioaren egoera"</string>
<string name="car_permission_desc_car_monitor_cluster_navigation_state" msgid="8745047153878713339">"Entzun instrumentuen lukuko nabigazioaren egoeran ematen diren aldaketak"</string>
- <string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"Instrumentu lukuaren errendatzea"</string>
- <string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"Jaso instrumentu lukuaren datuak"</string>
<string name="car_permission_label_car_ux_restrictions_configuration" msgid="6801393970411049725">"Erabiltzeko moduaren murriztapenen konfigurazioa"</string>
<string name="car_permission_desc_car_ux_restrictions_configuration" msgid="5711926927484813777">"Konfiguratu erabiltzeko moduaren murriztapenak"</string>
<string name="car_permission_label_access_private_display_id" msgid="6712116114341634316">"Irakurtzeko baimena pantailaren ID pribatuari"</string>
@@ -74,8 +70,6 @@
<string name="car_permission_desc_read_car_occupant_awareness_state" msgid="188865882598414986">"Bidaiariak hautemateko sistemaren egoerei eta detekzioei buruzko datuak irakurtzeko aukera ematen du"</string>
<string name="car_permission_label_control_car_occupant_awareness_system" msgid="7163330266691094542">"Kontrolatu Bidaiariak hautemateko sistemaren grafikoa"</string>
<string name="car_permission_desc_control_car_occupant_awareness_system" msgid="7123482622084531911">"Bidaiariak hautemateko sistemaren detekzioen grafikoa noiz hasi eta noiz bukatu kontrolatzeko aukera ematen du"</string>
- <string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Autoaren sarrerako zerbitzua"</string>
- <string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Kudeatu sarrerako gertaerak"</string>
<string name="car_permission_label_diag_read" msgid="7248894224877702604">"irakurri diagnostiko-datuak"</string>
<string name="car_permission_desc_diag_read" msgid="1121426363040966178">"Irakurri autoaren diagnostiko-datuak."</string>
<string name="car_permission_label_diag_clear" msgid="4783070510879698157">"garbitu diagnostiko-datuak"</string>
@@ -84,8 +78,6 @@
<string name="car_permission_desc_vms_publisher" msgid="5589489298597386828">"Argitaratu VMS mezuak"</string>
<string name="car_permission_label_vms_subscriber" msgid="5648841182059222299">"VMS harpideduna"</string>
<string name="car_permission_desc_vms_subscriber" msgid="7551009457847673620">"Harpidetu VMS mezuetara"</string>
- <string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"VMS bezeroen zerbitzua"</string>
- <string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"Lotu VMS bezeroekin"</string>
<string name="car_permission_label_storage_monitoring" msgid="2327639346522530549">"Flash-memoria gainbegiratzea"</string>
<string name="car_permission_desc_storage_monitoring" msgid="2075712271139671318">"Gainbegiratu flash-memoriaren erabilera"</string>
<string name="car_permission_label_driving_state" msgid="7754624599537393650">"entzun gidatze-egoera"</string>
diff --git a/service/res/values-fa/strings.xml b/service/res/values-fa/strings.xml
index 7415bae..3ab9659 100644
--- a/service/res/values-fa/strings.xml
+++ b/service/res/values-fa/strings.xml
@@ -42,8 +42,6 @@
<string name="car_permission_desc_projection" msgid="2352178999656292944">"به برنامهای اجازه میدهد واسطی را از تلفن به نمایشگر خودرو انتقال دهد"</string>
<string name="car_permission_label_access_projection_status" msgid="4231618890836627402">"دسترسی به وضعیت انتقال محتوا"</string>
<string name="car_permission_desc_access_projection_status" msgid="8497351979100616278">"به برنامهای اجازه میدهد وضعیت سایر برنامههایی را که به نمایشگر خودرو انتقال داده میشوند دریافت کند."</string>
- <string name="car_permission_label_bind_projection_service" msgid="5362076216606651526">"اتصال به سرویس انتقال محتوا"</string>
- <string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"به برنامه اجازه میدهد که به واسط سطح بالای سرویس انتقال محتوا متصل شود. هرگز نباید برای برنامههای معمولی مورد نیاز باشد."</string>
<string name="car_permission_label_audio_volume" msgid="310587969373137690">"کنترل میزان صدای خودرو"</string>
<string name="car_permission_label_audio_settings" msgid="6524703796944023977">"مدیریت تنظیمات صدای خودرو"</string>
<string name="car_permission_label_mock_vehicle_hal" msgid="7198852512207405935">"شبیهسازی HAL خودرو"</string>
@@ -62,8 +60,6 @@
<string name="car_permission_desc_car_cluster_control" msgid="9222776665281176031">"راهاندازی برنامهها در داشبورد"</string>
<string name="car_permission_car_monitor_cluster_navigation_state" msgid="7025307242306902441">"وضعیت ناوبری داشبورد"</string>
<string name="car_permission_desc_car_monitor_cluster_navigation_state" msgid="8745047153878713339">"گوش دادن به تغییرات وضعیت ناوبری داشبورد"</string>
- <string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"پرداز داشبورد"</string>
- <string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"دریافت دادههای داشبورد"</string>
<string name="car_permission_label_car_ux_restrictions_configuration" msgid="6801393970411049725">"پیکربندی محدودیتهای UX"</string>
<string name="car_permission_desc_car_ux_restrictions_configuration" msgid="5711926927484813777">"پیکربندی محدودیتهای UX"</string>
<string name="car_permission_label_access_private_display_id" msgid="6712116114341634316">"دسترسی خواندن به شناسه نمایشگر خصوصی"</string>
@@ -74,8 +70,6 @@
<string name="car_permission_desc_read_car_occupant_awareness_state" msgid="188865882598414986">"اجازه میدهد وضعیت و دادههای تشخیص «سیستم هوشیاری سرنشین» خوانده شود"</string>
<string name="car_permission_label_control_car_occupant_awareness_system" msgid="7163330266691094542">"کنترل نمودار «سیستم هوشیاری سرنشین»"</string>
<string name="car_permission_desc_control_car_occupant_awareness_system" msgid="7123482622084531911">"اجازه میدهد شروع و توقف نمودار تشخیص «سیستم هوشیاری سرنشین» کنترل شود"</string>
- <string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"سرویس ورودی خودرو"</string>
- <string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"مدیریت رویدادهای ورودی"</string>
<string name="car_permission_label_diag_read" msgid="7248894224877702604">"خواندن دادههای عیبیابی"</string>
<string name="car_permission_desc_diag_read" msgid="1121426363040966178">"دادههای عیبیابی خودرو را بخوانید."</string>
<string name="car_permission_label_diag_clear" msgid="4783070510879698157">"پاک کردن دادههای عیبیابی"</string>
@@ -84,8 +78,6 @@
<string name="car_permission_desc_vms_publisher" msgid="5589489298597386828">"انتشار پیامهای VMS"</string>
<string name="car_permission_label_vms_subscriber" msgid="5648841182059222299">"مشترک VMS"</string>
<string name="car_permission_desc_vms_subscriber" msgid="7551009457847673620">"مشترک شدن در پیامهای VMS"</string>
- <string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"سرویس کارخواه VMS"</string>
- <string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"اتصال به کارخواهان VMS"</string>
<string name="car_permission_label_storage_monitoring" msgid="2327639346522530549">"پایش فضای ذخیرهسازی فلاش"</string>
<string name="car_permission_desc_storage_monitoring" msgid="2075712271139671318">"پایش مصرف فضای ذخیرهسازی فلاش"</string>
<string name="car_permission_label_driving_state" msgid="7754624599537393650">"گوش دادن به وضعیت رانندگی"</string>
diff --git a/service/res/values-fi/strings.xml b/service/res/values-fi/strings.xml
index e1ee592..6a12e4a 100644
--- a/service/res/values-fi/strings.xml
+++ b/service/res/values-fi/strings.xml
@@ -42,8 +42,6 @@
<string name="car_permission_desc_projection" msgid="2352178999656292944">"Sallii sovelluksen projisoida puhelimen käyttöliittymän auton näyttöön."</string>
<string name="car_permission_label_access_projection_status" msgid="4231618890836627402">"nähdä projektiotilan"</string>
<string name="car_permission_desc_access_projection_status" msgid="8497351979100616278">"Sallii sovelluksen nähdä muiden auton näyttöön projisoivien sovellusten tilan."</string>
- <string name="car_permission_label_bind_projection_service" msgid="5362076216606651526">"sitoutua projektiopalveluun"</string>
- <string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"Antaa sovelluksen sitoutua projektiopalvelun ylemmän tason käyttöliittymään. Ei tavallisten sovelluksien käyttöön."</string>
<string name="car_permission_label_audio_volume" msgid="310587969373137690">"ohjata äänenvoimakkuutta autossa"</string>
<string name="car_permission_label_audio_settings" msgid="6524703796944023977">"muokata auton ääniasetuksia"</string>
<string name="car_permission_label_mock_vehicle_hal" msgid="7198852512207405935">"jäljitellä auton ajoneuvo-HAL:ää"</string>
@@ -62,8 +60,6 @@
<string name="car_permission_desc_car_cluster_control" msgid="9222776665281176031">"käynnistää sovelluksia instrumenttijoukossa"</string>
<string name="car_permission_car_monitor_cluster_navigation_state" msgid="7025307242306902441">"Instrumenttijoukon navigointitila"</string>
<string name="car_permission_desc_car_monitor_cluster_navigation_state" msgid="8745047153878713339">"Kuuntele muutokset instrumenttijoukon navigointitilassa"</string>
- <string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"Instrumenttijoukon renderöinti"</string>
- <string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"vastaanottaa instrumenttijoukkojen dataa"</string>
<string name="car_permission_label_car_ux_restrictions_configuration" msgid="6801393970411049725">"UX-rajoitusten määritys"</string>
<string name="car_permission_desc_car_ux_restrictions_configuration" msgid="5711926927484813777">"Määritä UX-rajoitukset"</string>
<string name="car_permission_label_access_private_display_id" msgid="6712116114341634316">"Yksityisen näyttötunnuksen lukuoikeus"</string>
@@ -74,8 +70,6 @@
<string name="car_permission_desc_read_car_occupant_awareness_state" msgid="188865882598414986">"Sallii Occupant Awareness Systemin tilan ja tunnistusdatan lukemisen"</string>
<string name="car_permission_label_control_car_occupant_awareness_system" msgid="7163330266691094542">"Ohjata Occupant Awareness System Graphia"</string>
<string name="car_permission_desc_control_car_occupant_awareness_system" msgid="7123482622084531911">"Sallii Occupant Awareness Systemin käynnistyksen ja pysäytyksen ohjaamisen"</string>
- <string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Auton syötepalvelu"</string>
- <string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"käsitellä syötteitä"</string>
<string name="car_permission_label_diag_read" msgid="7248894224877702604">"nähdä diagnostiikkadataa"</string>
<string name="car_permission_desc_diag_read" msgid="1121426363040966178">"lukea auton diagnostiikkadataa"</string>
<string name="car_permission_label_diag_clear" msgid="4783070510879698157">"poistaa diagnostiikkatiedot"</string>
@@ -84,8 +78,6 @@
<string name="car_permission_desc_vms_publisher" msgid="5589489298597386828">"julkaista VMS-viestejä"</string>
<string name="car_permission_label_vms_subscriber" msgid="5648841182059222299">"VMS-tilaaja"</string>
<string name="car_permission_desc_vms_subscriber" msgid="7551009457847673620">"tilata VMS-viestejä"</string>
- <string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"VMS-asiakassovelluspalvelu"</string>
- <string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"sitoutua VMS-asiakassovelluksiin"</string>
<string name="car_permission_label_storage_monitoring" msgid="2327639346522530549">"seurata flash-tallennustilaa"</string>
<string name="car_permission_desc_storage_monitoring" msgid="2075712271139671318">"valvoa flash-tallennustilan käyttöä"</string>
<string name="car_permission_label_driving_state" msgid="7754624599537393650">"kuunnella ajotilaa"</string>
diff --git a/service/res/values-fr-rCA/strings.xml b/service/res/values-fr-rCA/strings.xml
index 8beded2..3e65de2 100644
--- a/service/res/values-fr-rCA/strings.xml
+++ b/service/res/values-fr-rCA/strings.xml
@@ -42,8 +42,6 @@
<string name="car_permission_desc_projection" msgid="2352178999656292944">"Permet à une application de diffuser l\'interface d\'un téléphone sur l\'écran de la voiture."</string>
<string name="car_permission_label_access_projection_status" msgid="4231618890836627402">"accéder à l\'état de projection"</string>
<string name="car_permission_desc_access_projection_status" msgid="8497351979100616278">"Permet à l\'application de recevoir l\'état des autres applications diffusées sur l\'écran de la voiture."</string>
- <string name="car_permission_label_bind_projection_service" msgid="5362076216606651526">"s\'associer à un service de production"</string>
- <string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"Permet à l\'application autorisée de s\'associer à l\'interface de plus haut niveau d\'un service de projection. Les applications standard ne devraient pas avoir recours à cette fonctionnalité."</string>
<string name="car_permission_label_audio_volume" msgid="310587969373137690">"contrôler le volume audio de la voiture"</string>
<string name="car_permission_label_audio_settings" msgid="6524703796944023977">"gérer les paramètres audio de la voiture"</string>
<string name="car_permission_label_mock_vehicle_hal" msgid="7198852512207405935">"émuler le système HAL du véhicule"</string>
@@ -62,8 +60,6 @@
<string name="car_permission_desc_car_cluster_control" msgid="9222776665281176031">"Lancer les applications dans le groupe d\'instruments"</string>
<string name="car_permission_car_monitor_cluster_navigation_state" msgid="7025307242306902441">"État de la navigation dans le groupe d\'instruments"</string>
<string name="car_permission_desc_car_monitor_cluster_navigation_state" msgid="8745047153878713339">"Écouter les changements de l\'état de la navigation dans le groupe d\'instruments"</string>
- <string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"Rendu du groupe d\'instruments"</string>
- <string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"Recevoir les données du groupe d\'instruments"</string>
<string name="car_permission_label_car_ux_restrictions_configuration" msgid="6801393970411049725">"Configuration des restrictions relatives à l\'expérience utilisateur"</string>
<string name="car_permission_desc_car_ux_restrictions_configuration" msgid="5711926927484813777">"Configurer les restrictions relatives à l\'expérience utilisateur"</string>
<string name="car_permission_label_access_private_display_id" msgid="6712116114341634316">"Accès en lecture à l\'identifiant privé d\'écran"</string>
@@ -74,8 +70,6 @@
<string name="car_permission_desc_read_car_occupant_awareness_state" msgid="188865882598414986">"Permet de lire les données liées à l\'état et à la détection du système de détection des occupants"</string>
<string name="car_permission_label_control_car_occupant_awareness_system" msgid="7163330266691094542">"Contrôler le graphique du système de détection des occupants"</string>
<string name="car_permission_desc_control_car_occupant_awareness_system" msgid="7123482622084531911">"Permet de contrôler le démarrage et l\'arrêt du graphique de détection du système de détection des occupants"</string>
- <string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Service d\'entrée de la voiture"</string>
- <string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Gérer les événements d\'entrée"</string>
<string name="car_permission_label_diag_read" msgid="7248894224877702604">"lire des données de diagnostic"</string>
<string name="car_permission_desc_diag_read" msgid="1121426363040966178">"Lire des données de diagnostic à partir de la voiture."</string>
<string name="car_permission_label_diag_clear" msgid="4783070510879698157">"effacer les données de diagnostic"</string>
@@ -84,8 +78,6 @@
<string name="car_permission_desc_vms_publisher" msgid="5589489298597386828">"Publier les messages de signalisation dynamique"</string>
<string name="car_permission_label_vms_subscriber" msgid="5648841182059222299">"Abonné aux messages de signalisation dynamique"</string>
<string name="car_permission_desc_vms_subscriber" msgid="7551009457847673620">"S\'abonner aux messages de signalisation dynamique"</string>
- <string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"Service client des messages de signalisation dynamique"</string>
- <string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"S\'associer aux clients des messages de signalisation dynamique"</string>
<string name="car_permission_label_storage_monitoring" msgid="2327639346522530549">"Surveillance de la mémoire flash"</string>
<string name="car_permission_desc_storage_monitoring" msgid="2075712271139671318">"Surveiller l\'utilisation de la mémoire flash"</string>
<string name="car_permission_label_driving_state" msgid="7754624599537393650">"écouter l\'état de la conduite"</string>
diff --git a/service/res/values-fr/strings.xml b/service/res/values-fr/strings.xml
index 713e0da..e2979c9 100644
--- a/service/res/values-fr/strings.xml
+++ b/service/res/values-fr/strings.xml
@@ -42,8 +42,6 @@
<string name="car_permission_desc_projection" msgid="2352178999656292944">"Autorise une application à projeter une interface depuis un téléphone sur l\'écran de la voiture."</string>
<string name="car_permission_label_access_projection_status" msgid="4231618890836627402">"Accéder à l\'état de projection"</string>
<string name="car_permission_desc_access_projection_status" msgid="8497351979100616278">"Autorise une application à obtenir l\'état des autres applications qui effectuent une projection sur l\'écran de la voiture."</string>
- <string name="car_permission_label_bind_projection_service" msgid="5362076216606651526">"Associer à un service de projection"</string>
- <string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"Permet à l\'application autorisée de s\'associer à l\'interface de plus haut niveau d\'un service de projection. Cette autorisation ne devrait jamais être nécessaire pour les applications standards."</string>
<string name="car_permission_label_audio_volume" msgid="310587969373137690">"Contrôler le volume du son de la voiture"</string>
<string name="car_permission_label_audio_settings" msgid="6524703796944023977">"Gérer les paramètres audio de la voiture"</string>
<string name="car_permission_label_mock_vehicle_hal" msgid="7198852512207405935">"Émuler la couche d\'abstraction du matériel de la voiture"</string>
@@ -62,8 +60,6 @@
<string name="car_permission_desc_car_cluster_control" msgid="9222776665281176031">"Lancer des applications au niveau du groupe d\'instruments"</string>
<string name="car_permission_car_monitor_cluster_navigation_state" msgid="7025307242306902441">"État de navigation du groupe d\'instruments"</string>
<string name="car_permission_desc_car_monitor_cluster_navigation_state" msgid="8745047153878713339">"Écouter les changements d\'état de navigation du groupe d\'instruments"</string>
- <string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"Rendu du groupe d\'instruments"</string>
- <string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"Recevoir les données du groupe d\'instruments"</string>
<string name="car_permission_label_car_ux_restrictions_configuration" msgid="6801393970411049725">"Configuration des restrictions relatives à l\'expérience utilisateur"</string>
<string name="car_permission_desc_car_ux_restrictions_configuration" msgid="5711926927484813777">"Configurer les restrictions relatives à l\'expérience utilisateur"</string>
<string name="car_permission_label_access_private_display_id" msgid="6712116114341634316">"Accès en lecture à l\'ID de l\'écran privé"</string>
@@ -74,8 +70,6 @@
<string name="car_permission_desc_read_car_occupant_awareness_state" msgid="188865882598414986">"Permet la lecture des données liées à l\'état et à la détection du système de perception de l\'occupant"</string>
<string name="car_permission_label_control_car_occupant_awareness_system" msgid="7163330266691094542">"Contrôler le graphique du système de perception de l\'occupant"</string>
<string name="car_permission_desc_control_car_occupant_awareness_system" msgid="7123482622084531911">"Permet de contrôler le lancement et l\'arrêt du graphique de détection du système de perception de l\'occupant"</string>
- <string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Service d\'entrée de la voiture"</string>
- <string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Gérer les événements d\'entrée"</string>
<string name="car_permission_label_diag_read" msgid="7248894224877702604">"Lire les données de diagnostic"</string>
<string name="car_permission_desc_diag_read" msgid="1121426363040966178">"Lire les données de diagnostic de la voiture."</string>
<string name="car_permission_label_diag_clear" msgid="4783070510879698157">"Effacer les données de diagnostic"</string>
@@ -84,8 +78,6 @@
<string name="car_permission_desc_vms_publisher" msgid="5589489298597386828">"Publier des messages VMS"</string>
<string name="car_permission_label_vms_subscriber" msgid="5648841182059222299">"Abonné VMS"</string>
<string name="car_permission_desc_vms_subscriber" msgid="7551009457847673620">"S\'abonner aux messages VMS"</string>
- <string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"Service client VMS"</string>
- <string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"S\'associer à des clients VMS"</string>
<string name="car_permission_label_storage_monitoring" msgid="2327639346522530549">"Contrôle du stockage Adobe Flash Player"</string>
<string name="car_permission_desc_storage_monitoring" msgid="2075712271139671318">"Contrôler l\'utilisation du stockage Adobe Flash Player"</string>
<string name="car_permission_label_driving_state" msgid="7754624599537393650">"Détecter la conduite"</string>
diff --git a/service/res/values-gl/strings.xml b/service/res/values-gl/strings.xml
index aa625c2..25b2a3f 100644
--- a/service/res/values-gl/strings.xml
+++ b/service/res/values-gl/strings.xml
@@ -42,8 +42,6 @@
<string name="car_permission_desc_projection" msgid="2352178999656292944">"Permite que unha aplicación proxecte unha interface desde un teléfono á pantalla dun coche."</string>
<string name="car_permission_label_access_projection_status" msgid="4231618890836627402">"acceder ao estado de proxección"</string>
<string name="car_permission_desc_access_projection_status" msgid="8497351979100616278">"Permite que unha aplicación consulte o estado doutras aplicacións que se proxectan na pantalla do coche."</string>
- <string name="car_permission_label_bind_projection_service" msgid="5362076216606651526">"vincular cun servizo de proxección"</string>
- <string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"Permite ao propietario vincularse á interface de nivel superior dun servizo de proxección. Non debería ser nunca necesario para as aplicacións normais."</string>
<string name="car_permission_label_audio_volume" msgid="310587969373137690">"controlar o volume do audio do coche"</string>
<string name="car_permission_label_audio_settings" msgid="6524703796944023977">"xestionar a configuración do audio do coche"</string>
<string name="car_permission_label_mock_vehicle_hal" msgid="7198852512207405935">"emular HAL do vehículo"</string>
@@ -62,8 +60,6 @@
<string name="car_permission_desc_car_cluster_control" msgid="9222776665281176031">"Iniciar aplicacións do panel de instrumentos"</string>
<string name="car_permission_car_monitor_cluster_navigation_state" msgid="7025307242306902441">"Estado de navegación do panel de instrumentos"</string>
<string name="car_permission_desc_car_monitor_cluster_navigation_state" msgid="8745047153878713339">"Escoita os cambios que se producen no estado de navegación do panel de instrumentos"</string>
- <string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"Representación do panel de instrumentos"</string>
- <string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"Recibir datos do panel de instrumentos"</string>
<string name="car_permission_label_car_ux_restrictions_configuration" msgid="6801393970411049725">"Configuración de restricións da experiencia de usuario"</string>
<string name="car_permission_desc_car_ux_restrictions_configuration" msgid="5711926927484813777">"Configurar restricións da experiencia de usuario"</string>
<string name="car_permission_label_access_private_display_id" msgid="6712116114341634316">"Acceso de escritura ao código de identificación privado da pantalla"</string>
@@ -74,8 +70,6 @@
<string name="car_permission_desc_read_car_occupant_awareness_state" msgid="188865882598414986">"Permite ler os datos da detección e do estado do sistema de detección de ocupantes"</string>
<string name="car_permission_label_control_car_occupant_awareness_system" msgid="7163330266691094542">"Controlar o gráfico do sistema de detección de ocupantes"</string>
<string name="car_permission_desc_control_car_occupant_awareness_system" msgid="7123482622084531911">"Permite controlar o inicio e a parada do gráfico de detección do sistema de detección de ocupantes"</string>
- <string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Servizo de entrada do coche"</string>
- <string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Controlar os eventos de entrada"</string>
<string name="car_permission_label_diag_read" msgid="7248894224877702604">"ler datos de diagnóstico"</string>
<string name="car_permission_desc_diag_read" msgid="1121426363040966178">"Ler datos de diagnóstico do coche."</string>
<string name="car_permission_label_diag_clear" msgid="4783070510879698157">"borrar datos de diagnóstico"</string>
@@ -84,8 +78,6 @@
<string name="car_permission_desc_vms_publisher" msgid="5589489298597386828">"Publicar mensaxes VMS"</string>
<string name="car_permission_label_vms_subscriber" msgid="5648841182059222299">"Subscritor de VMS"</string>
<string name="car_permission_desc_vms_subscriber" msgid="7551009457847673620">"Subscribirse ás mensaxes VMS"</string>
- <string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"Servizo de cliente de VMS"</string>
- <string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"Vincular a clientes de VMS"</string>
<string name="car_permission_label_storage_monitoring" msgid="2327639346522530549">"Supervisión de almacenamento da unidade flash"</string>
<string name="car_permission_desc_storage_monitoring" msgid="2075712271139671318">"Controlar o uso de almacenamento da unidade flash"</string>
<string name="car_permission_label_driving_state" msgid="7754624599537393650">"escoitar o estado de condución"</string>
@@ -126,8 +118,8 @@
<string name="car_permission_desc_vendor_permission_info" msgid="8152113853528488398">"Acceder á información sobre os permisos do vendedor do coche."</string>
<string name="car_permission_label_car_exterior_lights" msgid="541304469604902110">"ler o estado das luces exteriores do dispositivo"</string>
<string name="car_permission_desc_car_exterior_lights" msgid="4038037584100849318">"Acceder ao estado das luces exteriores do coche."</string>
- <string name="car_permission_label_car_epoch_time" msgid="6303397910662625112">"acceder ao inicio do rexistro de tempo do coche"</string>
- <string name="car_permission_desc_car_epoch_time" msgid="398907082895238558">"Acceder ao inicio do rexistro de tempo do coche."</string>
+ <string name="car_permission_label_car_epoch_time" msgid="6303397910662625112">"acceder ao tempo epoch do coche"</string>
+ <string name="car_permission_desc_car_epoch_time" msgid="398907082895238558">"Acceder ao tempo epoch do coche."</string>
<string name="car_permission_label_encryption_binding_seed" msgid="4652180636501144684">"acceder á semente de vinculación de encriptación do coche"</string>
<string name="car_permission_desc_encryption_binding_seed" msgid="6290944678417286024">"Acceder á semente de vinculación de encriptación do coche."</string>
<string name="car_permission_label_control_car_exterior_lights" msgid="101357531386232141">"ler as luces exteriores do coche"</string>
diff --git a/service/res/values-gu/strings.xml b/service/res/values-gu/strings.xml
index 903baa6..a41b9fc 100644
--- a/service/res/values-gu/strings.xml
+++ b/service/res/values-gu/strings.xml
@@ -42,8 +42,6 @@
<string name="car_permission_desc_projection" msgid="2352178999656292944">"કોઈ ઍપને કોઈ ફોનના ઇન્ટરફેસ પરથી કારના ડિસ્પ્લે પર પ્રોજેક્ટ કરવાની મંજૂરી આપે છે"</string>
<string name="car_permission_label_access_projection_status" msgid="4231618890836627402">"પ્રોજેક્શનના સ્ટેટસને ઍક્સેસ કરો"</string>
<string name="car_permission_desc_access_projection_status" msgid="8497351979100616278">"કોઈ ઍપને કારના ડિસ્પ્લે પર પ્રોજેક્ટ કરતી અન્ય ઍપનો સ્ટેટસ મેળવવાની મંજૂરી આપે છે."</string>
- <string name="car_permission_label_bind_projection_service" msgid="5362076216606651526">"પ્રોજેક્શન સેવા સાથે જોડાઓ"</string>
- <string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"ધારકને કોઈ પ્રોજેક્શન સેવાના ઉચ્ચ લેવલના ઇન્ટરફેસથી પ્રતિબદ્ધ થવાની મંજૂરી આપે છે. સામાન્ય ઍપ માટે ક્યારેય જરૂરી હોવું જોઈએ નહીં."</string>
<string name="car_permission_label_audio_volume" msgid="310587969373137690">"કારના ઑડિયોનું વૉલ્યૂમ નિયંત્રિત કરો"</string>
<string name="car_permission_label_audio_settings" msgid="6524703796944023977">"કારના ઑડિયો સેટિંગ મેનેજ કરો"</string>
<string name="car_permission_label_mock_vehicle_hal" msgid="7198852512207405935">"કારના HALનું અનુસરણ કરો"</string>
@@ -62,8 +60,6 @@
<string name="car_permission_desc_car_cluster_control" msgid="9222776665281176031">"ઇન્સ્ટ્રુમેન્ટ ક્લસ્ટરમાં ઍપ્લિકેશન લૉન્ચ કરો"</string>
<string name="car_permission_car_monitor_cluster_navigation_state" msgid="7025307242306902441">"ઇન્સ્ટ્રુમેન્ટ ક્લસ્ટરનું નૅવિગેશન સ્ટેટસ"</string>
<string name="car_permission_desc_car_monitor_cluster_navigation_state" msgid="8745047153878713339">"ઇન્સ્ટ્રુમેન્ટ ક્લસ્ટરના નૅવિગેશન સ્ટેટસમાં થતા ફેરફારો માટે સાંભળો"</string>
- <string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"ઇન્સ્ટ્રુમેન્ટ ક્લસ્ટર રેન્ડર કરી રહ્યું છે"</string>
- <string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"ઇન્સ્ટ્રુમેન્ટ ક્લસ્ટરનો ડેટા પ્રાપ્ત કરો"</string>
<string name="car_permission_label_car_ux_restrictions_configuration" msgid="6801393970411049725">"UX પ્રતિબંધોની ગોઠવણી"</string>
<string name="car_permission_desc_car_ux_restrictions_configuration" msgid="5711926927484813777">"UX પ્રતિબંધોને ગોઠવણી કરો"</string>
<string name="car_permission_label_access_private_display_id" msgid="6712116114341634316">"ખાનગી ડિસ્પ્લે id માટે વાંચવાનો ઍક્સેસ"</string>
@@ -74,8 +70,6 @@
<string name="car_permission_desc_read_car_occupant_awareness_state" msgid="188865882598414986">"\'કારમાં સવાર લોકોની જાગરૂકતા સંબંધિત સિસ્ટમ\'ના સ્ટેટસ અને તેની જાણકારીના ડેટાને વાંચવાની મંજૂરી આપે છે"</string>
<string name="car_permission_label_control_car_occupant_awareness_system" msgid="7163330266691094542">"\'કારમાં સવાર લોકોની જાગરૂકતા સંબંધિત સિસ્ટમ\'ના ગ્રાફને નિયંત્રિત કરો"</string>
<string name="car_permission_desc_control_car_occupant_awareness_system" msgid="7123482622084531911">"\'કારમાં સવાર લોકોની જાગરૂકતા સંબંધિત સિસ્ટમ\'ની જાણકારીના ગ્રાફનું નિયંત્રણ શરૂ કરવાની અને રોકવાની મંજૂરી આપે છે"</string>
- <string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"કારની ઇનપુટ સેવા"</string>
- <string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"ઇનપુટ ઇવેન્ટ્સને હૅન્ડલ કરો"</string>
<string name="car_permission_label_diag_read" msgid="7248894224877702604">"નિદાનનો ડેટા વાંચો"</string>
<string name="car_permission_desc_diag_read" msgid="1121426363040966178">"કારમાંથી નિદાનનો ડેટા વાંચો."</string>
<string name="car_permission_label_diag_clear" msgid="4783070510879698157">"નિદાનનો ડેટા સાફ કરો"</string>
@@ -84,8 +78,6 @@
<string name="car_permission_desc_vms_publisher" msgid="5589489298597386828">"VMS સંદેશા પ્રકાશિત કરો"</string>
<string name="car_permission_label_vms_subscriber" msgid="5648841182059222299">"VMS સબ્સ્ક્રાઇબર"</string>
<string name="car_permission_desc_vms_subscriber" msgid="7551009457847673620">"VMS સંદેશાને સબ્સ્ક્રાઇબ કરો"</string>
- <string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"VMS ક્લાયન્ટ સેવા"</string>
- <string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"VMS ક્લાયન્ટથી પ્રતિબદ્ધ થાઓ"</string>
<string name="car_permission_label_storage_monitoring" msgid="2327639346522530549">"પેન ડ્રાઇવના સ્ટોરેજનું નિરીક્ષણ કરવાની મંજૂરી આપો"</string>
<string name="car_permission_desc_storage_monitoring" msgid="2075712271139671318">"ફ્લૅશ સ્ટોરેજના વપરાશનું નિરીક્ષણ કરો"</string>
<string name="car_permission_label_driving_state" msgid="7754624599537393650">"ડ્રાઇવ કરવાની સ્થિતિ વિશે સાંભળો"</string>
diff --git a/service/res/values-hi/strings.xml b/service/res/values-hi/strings.xml
index 2ebcf98..e457d73 100644
--- a/service/res/values-hi/strings.xml
+++ b/service/res/values-hi/strings.xml
@@ -42,8 +42,6 @@
<string name="car_permission_desc_projection" msgid="2352178999656292944">"ऐप्लिकेशन कार की डिसप्ले पर, फ़ोन से किसी इंटरफ़ेस को प्रोजेक्ट कर सकता है."</string>
<string name="car_permission_label_access_projection_status" msgid="4231618890836627402">"प्रोजेक्ट करने की स्थिति को ऐक्सेस कर सकता है"</string>
<string name="car_permission_desc_access_projection_status" msgid="8497351979100616278">"ऐप्लिकेशन, कार की डिसप्ले पर प्रोजेक्ट किए जा रहे दूसरे ऐप्लिकेशन की स्थिति देख सकता है."</string>
- <string name="car_permission_label_bind_projection_service" msgid="5362076216606651526">"प्रोजेक्ट करने की सुविधा इस्तेमाल कर सकता है"</string>
- <string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"उपोयगकर्ता को किसी प्रोजेक्ट करने की सुविधा के टॉप-लेवल इंटरफ़ेस से जोड़ता है. सामान्य ऐप्लिकेशन के लिए इसकी कभी ज़रूरत नहीं होती."</string>
<string name="car_permission_label_audio_volume" msgid="310587969373137690">"कार में ऑडियो की आवाज़ नियंत्रित कर सकता है"</string>
<string name="car_permission_label_audio_settings" msgid="6524703796944023977">"कार में ऑडियो की सेटिंग मैनेज कर सकता है"</string>
<string name="car_permission_label_mock_vehicle_hal" msgid="7198852512207405935">"वाहन एलएएल की तरह काम करना"</string>
@@ -62,8 +60,6 @@
<string name="car_permission_desc_car_cluster_control" msgid="9222776665281176031">"इंस्ट्रूमेंट क्लस्टर में ऐप्लिकेशन लॉन्च करें"</string>
<string name="car_permission_car_monitor_cluster_navigation_state" msgid="7025307242306902441">"गाड़ी के इंस्ट्रुमेंट क्लस्टर के नेविगेशन की स्थिति"</string>
<string name="car_permission_desc_car_monitor_cluster_navigation_state" msgid="8745047153878713339">"इंस्ट्रुमेंट क्लस्टर के नेविगेशन की स्थिति के बदलावों के लिए सुनें"</string>
- <string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"इंस्ट्रूमेंट क्लस्टर रेंडर करने की सुविधा"</string>
- <string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"इंस्ट्रूमेंट क्लस्टर का डेटा पाएं"</string>
<string name="car_permission_label_car_ux_restrictions_configuration" msgid="6801393970411049725">"UX पाबंदियों का कॉन्फ़िगरेशन"</string>
<string name="car_permission_desc_car_ux_restrictions_configuration" msgid="5711926927484813777">"UX की पाबंदियां कॉन्फ़िगर करें"</string>
<string name="car_permission_label_access_private_display_id" msgid="6712116114341634316">"निजी डिसप्ले आईडी के लिए पढ़ने का ऐक्सेस"</string>
@@ -74,8 +70,6 @@
<string name="car_permission_desc_read_car_occupant_awareness_state" msgid="188865882598414986">"इससे Occupant Awareness System की स्थिति और डिटेक्शन सिस्टम के नतीजों को पढ़ने की अनुमति मिलती है. डिटेक्शन सिस्टम यह बताता है कि ड्राइवर कहां देख रहा है."</string>
<string name="car_permission_label_control_car_occupant_awareness_system" msgid="7163330266691094542">"इससे ऐप्लिकेशन को Occupant Awareness System Graph कंट्रोल करने की अनुमति मिलती है"</string>
<string name="car_permission_desc_control_car_occupant_awareness_system" msgid="7123482622084531911">"इससे Occupant Awareness System के डिटेक्शन ग्राफ़ को शुरू करने या रोकने की अनुमति मिलती है"</string>
- <string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"कार की इनपुट सेवा"</string>
- <string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"इनपुट से जुड़े इवेंट प्रबंधित कर सकता है"</string>
<string name="car_permission_label_diag_read" msgid="7248894224877702604">"गड़बड़ी की पहचान का डेटा देख सकता है"</string>
<string name="car_permission_desc_diag_read" msgid="1121426363040966178">"कार की \'गड़बड़ी की पहचान का डेटा\' देख सकता है."</string>
<string name="car_permission_label_diag_clear" msgid="4783070510879698157">"गड़बड़ी की पहचान का डेटा मिटा सकता है"</string>
@@ -84,8 +78,6 @@
<string name="car_permission_desc_vms_publisher" msgid="5589489298597386828">"वीएमएस मैसेज भेज सकता है"</string>
<string name="car_permission_label_vms_subscriber" msgid="5648841182059222299">"वीएमएस का डेटा पा सकता है"</string>
<string name="car_permission_desc_vms_subscriber" msgid="7551009457847673620">"वीएमएस मैसेज की सदस्यता ले सकता है"</string>
- <string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"वीएमएस क्लाइंट सुविधा"</string>
- <string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"वीएमएस क्लाइंट से जोड़ सकता है"</string>
<string name="car_permission_label_storage_monitoring" msgid="2327639346522530549">"फ़्लैश डिवाइस की मेमोरी पर नज़र रख सकता है"</string>
<string name="car_permission_desc_storage_monitoring" msgid="2075712271139671318">"फ़्लैश डिवाइस की मेमोरी के इस्तेमाल की निगरानी कर सकता है"</string>
<string name="car_permission_label_driving_state" msgid="7754624599537393650">"गाड़ी चलाते समय होने वाले बदलावों की स्थिति को सुन सकता है"</string>
diff --git a/service/res/values-hr/strings.xml b/service/res/values-hr/strings.xml
index 3cf5c5d..77b4a88 100644
--- a/service/res/values-hr/strings.xml
+++ b/service/res/values-hr/strings.xml
@@ -42,8 +42,6 @@
<string name="car_permission_desc_projection" msgid="2352178999656292944">"Aplikaciji omogućuje da projicira sučelje s telefona na automobilskom zaslonu."</string>
<string name="car_permission_label_access_projection_status" msgid="4231618890836627402">"pristupiti statusu projiciranja"</string>
<string name="car_permission_desc_access_projection_status" msgid="8497351979100616278">"Aplikaciji omogućuje da dohvati status drugih aplikacija koje projiciraju na automobilski zaslon."</string>
- <string name="car_permission_label_bind_projection_service" msgid="5362076216606651526">"vezati se na uslugu projekcije"</string>
- <string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"Nositelju omogućuje vezanje uz sučelje najviše razine usluge za projiciranje. Ne bi smjelo biti potrebno za normalne aplikacije."</string>
<string name="car_permission_label_audio_volume" msgid="310587969373137690">"upravljati glasnoćom zvuka za automobil"</string>
<string name="car_permission_label_audio_settings" msgid="6524703796944023977">"upravljati postavkama zvuka za automobil"</string>
<string name="car_permission_label_mock_vehicle_hal" msgid="7198852512207405935">"emulirati HAL vozila"</string>
@@ -62,8 +60,6 @@
<string name="car_permission_desc_car_cluster_control" msgid="9222776665281176031">"pokretati aplikacije na instrumentnoj ploči"</string>
<string name="car_permission_car_monitor_cluster_navigation_state" msgid="7025307242306902441">"Stanje navigacije skupine instrumenata"</string>
<string name="car_permission_desc_car_monitor_cluster_navigation_state" msgid="8745047153878713339">"Pratite promjene u stanju navigacije skupine instrumenata"</string>
- <string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"generiranje na instrumentnoj ploči"</string>
- <string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"primati podatke instrumentne ploče"</string>
<string name="car_permission_label_car_ux_restrictions_configuration" msgid="6801393970411049725">"konfiguracija ograničenja UX-a"</string>
<string name="car_permission_desc_car_ux_restrictions_configuration" msgid="5711926927484813777">"konfigurirati ograničenja UX-a"</string>
<string name="car_permission_label_access_private_display_id" msgid="6712116114341634316">"Pristup za čitanje ID-ju za privatni prikaz"</string>
@@ -74,8 +70,6 @@
<string name="car_permission_desc_read_car_occupant_awareness_state" msgid="188865882598414986">"Omogućuje očitavanje statusa i podataka o detektiranju za Sustav detektiranja prisutnosti"</string>
<string name="car_permission_label_control_car_occupant_awareness_system" msgid="7163330266691094542">"Kontrola grafikona Sustava detektiranja prisutnosti"</string>
<string name="car_permission_desc_control_car_occupant_awareness_system" msgid="7123482622084531911">"Omogućuje kontroliranje početka i završetka grafikona detektiranja za Sustav detektiranja prisutnosti"</string>
- <string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"usluga automobilskog unosa"</string>
- <string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"rukovati događajima unosa"</string>
<string name="car_permission_label_diag_read" msgid="7248894224877702604">"čitati dijagnostičke podatke"</string>
<string name="car_permission_desc_diag_read" msgid="1121426363040966178">"čitati dijagnostičke podatke automobila"</string>
<string name="car_permission_label_diag_clear" msgid="4783070510879698157">"izbrisati dijagnostičke podatke"</string>
@@ -84,8 +78,6 @@
<string name="car_permission_desc_vms_publisher" msgid="5589489298597386828">"objavljivati VMS poruke"</string>
<string name="car_permission_label_vms_subscriber" msgid="5648841182059222299">"VMS pretplatnik"</string>
<string name="car_permission_desc_vms_subscriber" msgid="7551009457847673620">"pretplatiti se na VMS poruke"</string>
- <string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"VMS usluga za klijente"</string>
- <string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"vezati se na VMS klijente"</string>
<string name="car_permission_label_storage_monitoring" msgid="2327639346522530549">"nadzor flash pohrane"</string>
<string name="car_permission_desc_storage_monitoring" msgid="2075712271139671318">"nadzirati upotrebu flash pohrane"</string>
<string name="car_permission_label_driving_state" msgid="7754624599537393650">"slušati stanje vožnje"</string>
diff --git a/service/res/values-hu/strings.xml b/service/res/values-hu/strings.xml
index 3382d91..3285cfc 100644
--- a/service/res/values-hu/strings.xml
+++ b/service/res/values-hu/strings.xml
@@ -42,8 +42,6 @@
<string name="car_permission_desc_projection" msgid="2352178999656292944">"Lehetővé teszi az alkalmazás számára, hogy kivetítse a telefon kezelőfelületét az autó képernyőjén."</string>
<string name="car_permission_label_access_projection_status" msgid="4231618890836627402">"hozzáférhet a kivetítési állapothoz"</string>
<string name="car_permission_desc_access_projection_status" msgid="8497351979100616278">"Lehetővé teszi az alkalmazás számára más alkalmazások állapotának kivetítését az autó képernyőjére."</string>
- <string name="car_permission_label_bind_projection_service" msgid="5362076216606651526">"összeköthető kivetítési szolgáltatásokkal"</string>
- <string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"Lehetővé teszi a használó számára, hogy csatlakozzon a kivetítési szolgáltatás legfelső szintű kezelőfelületéhez. A normál alkalmazásoknak erre soha nincs szüksége."</string>
<string name="car_permission_label_audio_volume" msgid="310587969373137690">"vezérelheti az autó hangerejét"</string>
<string name="car_permission_label_audio_settings" msgid="6524703796944023977">"kezelheti az autó multimédia-rendszerének beállításait"</string>
<string name="car_permission_label_mock_vehicle_hal" msgid="7198852512207405935">"emulálhatja a jármű hardverabsztrakciós rétegét (HAL)"</string>
@@ -62,8 +60,6 @@
<string name="car_permission_desc_car_cluster_control" msgid="9222776665281176031">"Az alkalmazások műszerfalon való indítása"</string>
<string name="car_permission_car_monitor_cluster_navigation_state" msgid="7025307242306902441">"Műszerfal navigációs állapota"</string>
<string name="car_permission_desc_car_monitor_cluster_navigation_state" msgid="8745047153878713339">"A műszerfal navigációs állapota változásainak figyelése"</string>
- <string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"Műszerfalon való megjelenítés"</string>
- <string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"Műszerfaladatok fogadása"</string>
<string name="car_permission_label_car_ux_restrictions_configuration" msgid="6801393970411049725">"Felhasználói élményre vonatkozó korlátozások beállítása"</string>
<string name="car_permission_desc_car_ux_restrictions_configuration" msgid="5711926927484813777">"Felhasználói élményre vonatkozó korlátozások beállítása"</string>
<string name="car_permission_label_access_private_display_id" msgid="6712116114341634316">"Olvasási hozzáférés a privát megjelenítési azonosítóhoz"</string>
@@ -74,8 +70,6 @@
<string name="car_permission_desc_read_car_occupant_awareness_state" msgid="188865882598414986">"Engedélyezi a státusz- és észlelési adatok olvasását az Occupant Awareness System számára"</string>
<string name="car_permission_label_control_car_occupant_awareness_system" msgid="7163330266691094542">"Az Occupant Awareness System grafikonjának irányítása"</string>
<string name="car_permission_desc_control_car_occupant_awareness_system" msgid="7123482622084531911">"Engedélyezi az Occupant Awareness System észlelési grafikonjának indítását és leállítását"</string>
- <string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Az autó beviteli szolgáltatása"</string>
- <string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Kezelheti a beviteli eseményeket"</string>
<string name="car_permission_label_diag_read" msgid="7248894224877702604">"olvashatja a diagnosztikai adatokat"</string>
<string name="car_permission_desc_diag_read" msgid="1121426363040966178">"Olvashatja az autó diagnosztikai adatait."</string>
<string name="car_permission_label_diag_clear" msgid="4783070510879698157">"törölheti a diagnosztikai adatokat"</string>
@@ -84,8 +78,6 @@
<string name="car_permission_desc_vms_publisher" msgid="5589489298597386828">"Változtatható jelzésképű táblák üzeneteinek megjelenítése"</string>
<string name="car_permission_label_vms_subscriber" msgid="5648841182059222299">"Feliratkozhat a változtatható jelzésképű táblák üzeneteire"</string>
<string name="car_permission_desc_vms_subscriber" msgid="7551009457847673620">"Feliratkozhat a változtatható jelzésképű táblák üzeneteire"</string>
- <string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"Változtatható jelzésképű táblák ügyfélszolgáltatója"</string>
- <string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"Változtatható jelzésképű táblák ügyfeleivel való összekapcsolás"</string>
<string name="car_permission_label_storage_monitoring" msgid="2327639346522530549">"Flash-tárhely figyelése"</string>
<string name="car_permission_desc_storage_monitoring" msgid="2075712271139671318">"Figyelheti a Flash-tárhely használatát"</string>
<string name="car_permission_label_driving_state" msgid="7754624599537393650">"meghallgathatja a vezetési állapotról szóló adatokat"</string>
diff --git a/service/res/values-hy/strings.xml b/service/res/values-hy/strings.xml
index 00534ab..71839fd 100644
--- a/service/res/values-hy/strings.xml
+++ b/service/res/values-hy/strings.xml
@@ -42,8 +42,6 @@
<string name="car_permission_desc_projection" msgid="2352178999656292944">"Հավելվածին թույլէ տալիս արտապատկերել հեռախոսի միջերեսը մեքենայի էկրանին:"</string>
<string name="car_permission_label_access_projection_status" msgid="4231618890836627402">"օգտագործել արտապատկերման կարգավիճակի մասին տվյալները"</string>
<string name="car_permission_desc_access_projection_status" msgid="8497351979100616278">"Հավելվածին թույլ է տալիս ստանալ ավտոմեքենայի էկրանին արտապատկերող այլ հավելվածների կարգավիճակը:"</string>
- <string name="car_permission_label_bind_projection_service" msgid="5362076216606651526">"միանալ արտապատկերման ծառայությանը"</string>
- <string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"Թույլ է տալիս սեփականատիրոջը միանալ արտապատկերման ծառայության բազային միջերեսին: Սովորական հավելվածների համար երբևէ չպետք է անհրաժեշտ լինի:"</string>
<string name="car_permission_label_audio_volume" msgid="310587969373137690">"կառավարել մեքենայի աուդիո համակարգի ձայնը"</string>
<string name="car_permission_label_audio_settings" msgid="6524703796944023977">"կառավարել մեքենայի աուդիո համակարգի կարգավորումները"</string>
<string name="car_permission_label_mock_vehicle_hal" msgid="7198852512207405935">"նմանակել HAL միջերեսի տվյալները"</string>
@@ -62,8 +60,6 @@
<string name="car_permission_desc_car_cluster_control" msgid="9222776665281176031">"Գործարկել հավելվածներ սարքերի վահանակի վրա"</string>
<string name="car_permission_car_monitor_cluster_navigation_state" msgid="7025307242306902441">"Նավիգացիայի կարգավիճակը սարքերի վահանակում"</string>
<string name="car_permission_desc_car_monitor_cluster_navigation_state" msgid="8745047153878713339">"Լսել սարքերի վահանակում նավիգացիայի կարգավիճակի փոփոխությունները"</string>
- <string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"Սարքերի վահանակի արտապատկերում"</string>
- <string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"Ստանալ տվյալներ սարքերի վահանակից"</string>
<string name="car_permission_label_car_ux_restrictions_configuration" msgid="6801393970411049725">"Գործառույթների օգտագործման սահմանափակում"</string>
<string name="car_permission_desc_car_ux_restrictions_configuration" msgid="5711926927484813777">"Սահմանափակել գործառույթների օգտագործումը"</string>
<string name="car_permission_label_access_private_display_id" msgid="6712116114341634316">"Անձնական էկրանների նույնացուցիչները կարդալու թույլտվություն"</string>
@@ -74,8 +70,6 @@
<string name="car_permission_desc_read_car_occupant_awareness_state" msgid="188865882598414986">"Թույլ է տալիս կարդալ ուղևորի ներկայության որոշման համակարգի կարգավիճակը և տվյալները"</string>
<string name="car_permission_label_control_car_occupant_awareness_system" msgid="7163330266691094542">"Կառավարել ուղևորի ներկայության որոշման համակարգի տրամագիրը"</string>
<string name="car_permission_desc_control_car_occupant_awareness_system" msgid="7123482622084531911">"Թույլ է տալիս կառավարել ուղևորի ներկայության որոշման համակարգի աշխատանքի տրամագրի գործարկումը և դադարեցումը"</string>
- <string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Ներածման ծառայություն"</string>
- <string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Մշակել ներածման իրադարձությունները"</string>
<string name="car_permission_label_diag_read" msgid="7248894224877702604">"կարդալ դիագնոստիկ տվյալները"</string>
<string name="car_permission_desc_diag_read" msgid="1121426363040966178">"Կարդալ մեքենայի դիագնոստիկ տվյալները։"</string>
<string name="car_permission_label_diag_clear" msgid="4783070510879698157">"մաքրել դիագնոստիկ տվյալները"</string>
@@ -84,8 +78,6 @@
<string name="car_permission_desc_vms_publisher" msgid="5589489298597386828">"Հրապարակել VMS հաղորդագրություններ"</string>
<string name="car_permission_label_vms_subscriber" msgid="5648841182059222299">"Բաժանորդագրում VMS հաղորդագրություններին"</string>
<string name="car_permission_desc_vms_subscriber" msgid="7551009457847673620">"Բաժանորդագրվել VMS հաղորդագրություններին"</string>
- <string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"VMS սպասառուների ծառայություն"</string>
- <string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"Միանալ VMS սպասառուներին"</string>
<string name="car_permission_label_storage_monitoring" msgid="2327639346522530549">"Ֆլեշ պահեստի մոնիթորինգ"</string>
<string name="car_permission_desc_storage_monitoring" msgid="2075712271139671318">"Հետագծել ֆլեշ պահեստի օգտագործումը"</string>
<string name="car_permission_label_driving_state" msgid="7754624599537393650">"հետագծել վարելու ռեժիմը"</string>
diff --git a/service/res/values-in/strings.xml b/service/res/values-in/strings.xml
index cd94517..f527b85 100644
--- a/service/res/values-in/strings.xml
+++ b/service/res/values-in/strings.xml
@@ -42,8 +42,6 @@
<string name="car_permission_desc_projection" msgid="2352178999656292944">"Mengizinkan aplikasi untuk memproyeksikan antarmuka dari ponsel di unit tampilan mobil."</string>
<string name="car_permission_label_access_projection_status" msgid="4231618890836627402">"mengakses status proyeksi"</string>
<string name="car_permission_desc_access_projection_status" msgid="8497351979100616278">"Mengizinkan aplikasi untuk mendapatkan status proyeksi aplikasi lain di unit tampilan mobil."</string>
- <string name="car_permission_label_bind_projection_service" msgid="5362076216606651526">"mengikat ke layanan proyeksi"</string>
- <string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"Mengizinkan pemegang untuk mengikat antarmuka tingkat tinggi dari suatu layanan proyeksi. Tidak pernah diperlukan oleh aplikasi normal."</string>
<string name="car_permission_label_audio_volume" msgid="310587969373137690">"mengontrol volume audio mobil"</string>
<string name="car_permission_label_audio_settings" msgid="6524703796944023977">"mengelola setelan audio mobil"</string>
<string name="car_permission_label_mock_vehicle_hal" msgid="7198852512207405935">"mengemulasi HAL kendaraan"</string>
@@ -62,8 +60,6 @@
<string name="car_permission_desc_car_cluster_control" msgid="9222776665281176031">"Luncurkan aplikasi di kluster instrumen"</string>
<string name="car_permission_car_monitor_cluster_navigation_state" msgid="7025307242306902441">"Status navigasi cluster instrumen"</string>
<string name="car_permission_desc_car_monitor_cluster_navigation_state" msgid="8745047153878713339">"Proses perubahan status navigasi cluster instrumen"</string>
- <string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"Rendering Kluster Instrumen"</string>
- <string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"Menerima data kluster instrumen"</string>
<string name="car_permission_label_car_ux_restrictions_configuration" msgid="6801393970411049725">"Konfigurasi Batasan UX"</string>
<string name="car_permission_desc_car_ux_restrictions_configuration" msgid="5711926927484813777">"Mengonfigurasi Batasan UX"</string>
<string name="car_permission_label_access_private_display_id" msgid="6712116114341634316">"Akses baca ke ID layar pribadi"</string>
@@ -74,8 +70,6 @@
<string name="car_permission_desc_read_car_occupant_awareness_state" msgid="188865882598414986">"Mengizinkan pembacaan status dan data deteksi untuk Sistem Awareness Penumpang"</string>
<string name="car_permission_label_control_car_occupant_awareness_system" msgid="7163330266691094542">"Kontrol Grafik Sistem Awareness Penumpang"</string>
<string name="car_permission_desc_control_car_occupant_awareness_system" msgid="7123482622084531911">"Mengizinkan pengontrolan mulai dan berhentinya grafik deteksi Sistem Awareness Penumpang"</string>
- <string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Layanan Masukan Mobil"</string>
- <string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Menangani aktivitas masukan"</string>
<string name="car_permission_label_diag_read" msgid="7248894224877702604">"membaca data diagnostik"</string>
<string name="car_permission_desc_diag_read" msgid="1121426363040966178">"Membaca data diagnostik dari mobil."</string>
<string name="car_permission_label_diag_clear" msgid="4783070510879698157">"menghapus data diagnostik"</string>
@@ -84,8 +78,6 @@
<string name="car_permission_desc_vms_publisher" msgid="5589489298597386828">"Publikasikan pesan VMS"</string>
<string name="car_permission_label_vms_subscriber" msgid="5648841182059222299">"Pelanggan VMS"</string>
<string name="car_permission_desc_vms_subscriber" msgid="7551009457847673620">"Berlangganan pesan VMS"</string>
- <string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"Layanan Klien VMS"</string>
- <string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"Mengikat ke klien VMS"</string>
<string name="car_permission_label_storage_monitoring" msgid="2327639346522530549">"Pemantauan penyimpanan flash"</string>
<string name="car_permission_desc_storage_monitoring" msgid="2075712271139671318">"Memantau penggunaan penyimpanan flash"</string>
<string name="car_permission_label_driving_state" msgid="7754624599537393650">"memproses status mengemudi"</string>
diff --git a/service/res/values-is/strings.xml b/service/res/values-is/strings.xml
index 934e905..4995bb8 100644
--- a/service/res/values-is/strings.xml
+++ b/service/res/values-is/strings.xml
@@ -42,8 +42,6 @@
<string name="car_permission_desc_projection" msgid="2352178999656292944">"Gerir forriti kleift að varpa viðmóti úr síma yfir á skjá bílsins."</string>
<string name="car_permission_label_access_projection_status" msgid="4231618890836627402">"fá aðgang að vörpunarstöðu"</string>
<string name="car_permission_desc_access_projection_status" msgid="8497351979100616278">"Heimila forriti að fá stöðu annarra forrita sem varpa yfir á skjá bílsins."</string>
- <string name="car_permission_label_bind_projection_service" msgid="5362076216606651526">"binda við vörpunarþjónustu"</string>
- <string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"Heimilar handhafa að bindast efsta viðmótslagi vörpunarþjónustu. Ætti aldrei að vera nauðsynlegt fyrir venjuleg forrit."</string>
<string name="car_permission_label_audio_volume" msgid="310587969373137690">"stjórna hljóðstyrk í bílnum"</string>
<string name="car_permission_label_audio_settings" msgid="6524703796944023977">"stjórna stillingum fyrir hljóðkerfi bílsins"</string>
<string name="car_permission_label_mock_vehicle_hal" msgid="7198852512207405935">"líkja eftir HAL ökutækis"</string>
@@ -62,8 +60,6 @@
<string name="car_permission_desc_car_cluster_control" msgid="9222776665281176031">"Opna forrit á mælaborði"</string>
<string name="car_permission_car_monitor_cluster_navigation_state" msgid="7025307242306902441">"Staða leiðsagnar í mælaborði"</string>
<string name="car_permission_desc_car_monitor_cluster_navigation_state" msgid="8745047153878713339">"Hlusta eftir breytingum á stöðu leiðsagnar í mælaborði"</string>
- <string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"Teiknun mælaborðs"</string>
- <string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"Fá mælaborðsgögn"</string>
<string name="car_permission_label_car_ux_restrictions_configuration" msgid="6801393970411049725">"Grunnstilling takmarkana á upplifun notanda"</string>
<string name="car_permission_desc_car_ux_restrictions_configuration" msgid="5711926927484813777">"Stilla takmarkanir á upplifun notanda"</string>
<string name="car_permission_label_access_private_display_id" msgid="6712116114341634316">"Lesaðgangur fyrir einkaskjái með auðkenni"</string>
@@ -74,8 +70,6 @@
<string name="car_permission_desc_read_car_occupant_awareness_state" msgid="188865882598414986">"Leyfir lestur á stöðu og kennslagögnum fyrir Occupant Awareness System"</string>
<string name="car_permission_label_control_car_occupant_awareness_system" msgid="7163330266691094542">"Stjórna riti fyrir Occupant Awareness System"</string>
<string name="car_permission_desc_control_car_occupant_awareness_system" msgid="7123482622084531911">"Leyfir stjórnun á kennslariti fyrir Occupant Awareness System"</string>
- <string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Inntaksþjónusta bíls"</string>
- <string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Stjórna inntakstilvikum"</string>
<string name="car_permission_label_diag_read" msgid="7248894224877702604">"lesa greiningargögn"</string>
<string name="car_permission_desc_diag_read" msgid="1121426363040966178">"Lesa greiningargögn úr bílnum."</string>
<string name="car_permission_label_diag_clear" msgid="4783070510879698157">"hreinsa greiningargögn"</string>
@@ -84,8 +78,6 @@
<string name="car_permission_desc_vms_publisher" msgid="5589489298597386828">"Birta VMS-skilaboð"</string>
<string name="car_permission_label_vms_subscriber" msgid="5648841182059222299">"VMS-áskrifandi"</string>
<string name="car_permission_desc_vms_subscriber" msgid="7551009457847673620">"Gerast áskrifandi að VMS-skilaboðum"</string>
- <string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"VMS-biðlaraþjónusta"</string>
- <string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"Bindst VMS-biðlara"</string>
<string name="car_permission_label_storage_monitoring" msgid="2327639346522530549">"Eftirlit með Flash-geymslu"</string>
<string name="car_permission_desc_storage_monitoring" msgid="2075712271139671318">"Fylgjast með notkun á Flash-geymslu"</string>
<string name="car_permission_label_driving_state" msgid="7754624599537393650">"hlusta á akstursstöðu"</string>
diff --git a/service/res/values-it/strings.xml b/service/res/values-it/strings.xml
index c8a6df6..958d15b 100644
--- a/service/res/values-it/strings.xml
+++ b/service/res/values-it/strings.xml
@@ -42,8 +42,6 @@
<string name="car_permission_desc_projection" msgid="2352178999656292944">"Consente a un\'app di proiettare l\'interfaccia di un telefono sul display di un\'auto."</string>
<string name="car_permission_label_access_projection_status" msgid="4231618890836627402">"Accesso allo stato di proiezione"</string>
<string name="car_permission_desc_access_projection_status" msgid="8497351979100616278">"Consente a un\'app di rilevare lo stato di altre app che proiettano contenuti sul display dell\'auto."</string>
- <string name="car_permission_label_bind_projection_service" msgid="5362076216606651526">"Associazione a un servizio di proiezione"</string>
- <string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"Consente al titolare di collegarsi all\'interfaccia di primo livello di un servizio di proiezione. Non dovrebbe mai essere necessaria per le app normali."</string>
<string name="car_permission_label_audio_volume" msgid="310587969373137690">"Regolazione del volume dell\'audio dell\'automobile"</string>
<string name="car_permission_label_audio_settings" msgid="6524703796944023977">"Gestione delle impostazioni audio dell\'automobile"</string>
<string name="car_permission_label_mock_vehicle_hal" msgid="7198852512207405935">"Emulazione vehicle HAL"</string>
@@ -62,8 +60,6 @@
<string name="car_permission_desc_car_cluster_control" msgid="9222776665281176031">"Consente di avviare app nel quadro strumenti."</string>
<string name="car_permission_car_monitor_cluster_navigation_state" msgid="7025307242306902441">"Stato di navigazione sul quadro strumenti"</string>
<string name="car_permission_desc_car_monitor_cluster_navigation_state" msgid="8745047153878713339">"Consente di ascoltare le variazioni dello stato di navigazione sul quadro strumenti."</string>
- <string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"Visualizzazione sul quadro strumenti"</string>
- <string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"Consente di ricevere dati del quadro strumenti."</string>
<string name="car_permission_label_car_ux_restrictions_configuration" msgid="6801393970411049725">"Configurazione delle limitazioni dell\'esperienza utente"</string>
<string name="car_permission_desc_car_ux_restrictions_configuration" msgid="5711926927484813777">"Consente di configurare le limitazioni dell\'esperienza utente."</string>
<string name="car_permission_label_access_private_display_id" msgid="6712116114341634316">"Accesso in lettura all\'ID display privato"</string>
@@ -74,8 +70,6 @@
<string name="car_permission_desc_read_car_occupant_awareness_state" msgid="188865882598414986">"Consente di leggere lo stato e i dati di rilevamento dell\'Occupant Awareness System."</string>
<string name="car_permission_label_control_car_occupant_awareness_system" msgid="7163330266691094542">"Controllo del grafico dell\'Occupant Awareness System"</string>
<string name="car_permission_desc_control_car_occupant_awareness_system" msgid="7123482622084531911">"Consente di controllare l\'avvio e l\'interruzione del grafico di rilevamento dell\'Occupant Awareness System."</string>
- <string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Servizio di input dell\'auto"</string>
- <string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Consente di gestire gli eventi di input."</string>
<string name="car_permission_label_diag_read" msgid="7248894224877702604">"Lettura dei dati diagnostici"</string>
<string name="car_permission_desc_diag_read" msgid="1121426363040966178">"Consente di leggere i dati diagnostici dell\'automobile."</string>
<string name="car_permission_label_diag_clear" msgid="4783070510879698157">"Cancellazione dei dati diagnostici"</string>
@@ -84,8 +78,6 @@
<string name="car_permission_desc_vms_publisher" msgid="5589489298597386828">"Consente di pubblicare messaggi VMS"</string>
<string name="car_permission_label_vms_subscriber" msgid="5648841182059222299">"Abbonamento ai dati VMS"</string>
<string name="car_permission_desc_vms_subscriber" msgid="7551009457847673620">"Abbonamento ai messaggi VMS."</string>
- <string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"Servizio client VMS"</string>
- <string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"Consente l\'associazione a client VMS"</string>
<string name="car_permission_label_storage_monitoring" msgid="2327639346522530549">"Monitoraggio della memoria flash"</string>
<string name="car_permission_desc_storage_monitoring" msgid="2075712271139671318">"Consente di monitorare l\'uso della memoria flash."</string>
<string name="car_permission_label_driving_state" msgid="7754624599537393650">"Ascolto dello stato Alla guida"</string>
diff --git a/service/res/values-iw/strings.xml b/service/res/values-iw/strings.xml
index ac3bd14..84ba79a 100644
--- a/service/res/values-iw/strings.xml
+++ b/service/res/values-iw/strings.xml
@@ -42,8 +42,6 @@
<string name="car_permission_desc_projection" msgid="2352178999656292944">"מאפשרת לאפליקציה להקרין ממשק מהטלפון אל מסך התצוגה ברכב."</string>
<string name="car_permission_label_access_projection_status" msgid="4231618890836627402">"גישה לסטטוס ההקרנה למסך"</string>
<string name="car_permission_desc_access_projection_status" msgid="8497351979100616278">"מאפשרת לאפליקציה לקבל את הסטטוס של אפליקציות אחרות שמקרינות מידע למסך התצוגה ברכב."</string>
- <string name="car_permission_label_bind_projection_service" msgid="5362076216606651526">"הכפפה לשירות ההקרנה למסך"</string>
- <string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"מאפשרת למשתמש לבצע הכפפה לממשק ברמה עליונה של שירות הקרנה למסך. הרשאה זו לעולם אינה נחוצה לאפליקציות רגילות."</string>
<string name="car_permission_label_audio_volume" msgid="310587969373137690">"שליטה בעוצמת הקול של האודיו ברכב"</string>
<string name="car_permission_label_audio_settings" msgid="6524703796944023977">"ניהול ההגדרות של עוצמת הקול ברכב"</string>
<string name="car_permission_label_mock_vehicle_hal" msgid="7198852512207405935">"אמולציה של ממשק vehicle HAL"</string>
@@ -62,8 +60,6 @@
<string name="car_permission_desc_car_cluster_control" msgid="9222776665281176031">"הפעלת אפליקציות באשכול הכלים"</string>
<string name="car_permission_car_monitor_cluster_navigation_state" msgid="7025307242306902441">"מצב הניווט בלוח המחוונים"</string>
<string name="car_permission_desc_car_monitor_cluster_navigation_state" msgid="8745047153878713339">"זיהוי שינויים במצב הניווט בלוח המחוונים"</string>
- <string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"עיבוד של אשכול הכלים"</string>
- <string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"קבלת נתונים של אשכול כלים"</string>
<string name="car_permission_label_car_ux_restrictions_configuration" msgid="6801393970411049725">"הגדרת הגבלות של חוויית משתמש (UX)"</string>
<string name="car_permission_desc_car_ux_restrictions_configuration" msgid="5711926927484813777">"הגדרת הגבלות של חוויית משתמש (UX)"</string>
<string name="car_permission_label_access_private_display_id" msgid="6712116114341634316">"גישת קריאה למזהה תצוגה פרטית"</string>
@@ -74,8 +70,6 @@
<string name="car_permission_desc_read_car_occupant_awareness_state" msgid="188865882598414986">"הרשאה לסטטוס קריאה ונתוני זיהוי למערכת המודעות לתפוסה (Occupant Awareness)"</string>
<string name="car_permission_label_control_car_occupant_awareness_system" msgid="7163330266691094542">"שליטה בתרשים של מערכת המודעות לתפוסה (Occupant Awareness)"</string>
<string name="car_permission_desc_control_car_occupant_awareness_system" msgid="7123482622084531911">"הרשאה לשליטה בהתחלה ובסיום של תרשים הזיהוי של מערכת המודעות לתפוסה (Occupant Awareness)"</string>
- <string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"שירות הקלט של הרכב"</string>
- <string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"ניהול אירועי קלט"</string>
<string name="car_permission_label_diag_read" msgid="7248894224877702604">"קריאת נתוני אבחון"</string>
<string name="car_permission_desc_diag_read" msgid="1121426363040966178">"קריאת נתוני אבחון מהרכב."</string>
<string name="car_permission_label_diag_clear" msgid="4783070510879698157">"מחיקת נתוני האבחון"</string>
@@ -84,8 +78,6 @@
<string name="car_permission_desc_vms_publisher" msgid="5589489298597386828">"פרסום הודעות VMS"</string>
<string name="car_permission_label_vms_subscriber" msgid="5648841182059222299">"מנוי לנתוני VMS"</string>
<string name="car_permission_desc_vms_subscriber" msgid="7551009457847673620">"הרשמה להודעות VMS"</string>
- <string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"שירות לקוח VMS"</string>
- <string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"הכפפה ללקוחות VMS"</string>
<string name="car_permission_label_storage_monitoring" msgid="2327639346522530549">"מעקב אחר אחסון הבזק"</string>
<string name="car_permission_desc_storage_monitoring" msgid="2075712271139671318">"מעקב אחר השטח האחסון הפנוי בכונן ההבזק"</string>
<string name="car_permission_label_driving_state" msgid="7754624599537393650">"האזנה למצב הנהיגה"</string>
diff --git a/service/res/values-ja/strings.xml b/service/res/values-ja/strings.xml
index 7cf0368..49cc734 100644
--- a/service/res/values-ja/strings.xml
+++ b/service/res/values-ja/strings.xml
@@ -42,8 +42,6 @@
<string name="car_permission_desc_projection" msgid="2352178999656292944">"車のディスプレイへのスマートフォンのインターフェースの投影をアプリに許可。"</string>
<string name="car_permission_label_access_projection_status" msgid="4231618890836627402">"投影ステータスへのアクセス"</string>
<string name="car_permission_desc_access_projection_status" msgid="8497351979100616278">"車のディスプレイへの他のアプリの投影ステータスの取得をアプリに許可。"</string>
- <string name="car_permission_label_bind_projection_service" msgid="5362076216606651526">"投影サービスへのバインド"</string>
- <string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"投影サービスのトップレベル インターフェースにバインドすることをホルダーに許可。通常のアプリでは不要です。"</string>
<string name="car_permission_label_audio_volume" msgid="310587969373137690">"カーオーディオの音量の調節"</string>
<string name="car_permission_label_audio_settings" msgid="6524703796944023977">"カーオーディオの設定の管理"</string>
<string name="car_permission_label_mock_vehicle_hal" msgid="7198852512207405935">"車両ハードウェア抽象化レイヤのエミュレート"</string>
@@ -62,8 +60,6 @@
<string name="car_permission_desc_car_cluster_control" msgid="9222776665281176031">"インストルメント クラスタでアプリを起動します"</string>
<string name="car_permission_car_monitor_cluster_navigation_state" msgid="7025307242306902441">"インストルメント クラスタのナビゲーション状態"</string>
<string name="car_permission_desc_car_monitor_cluster_navigation_state" msgid="8745047153878713339">"インストルメント クラスタのナビゲーション状態の変更をリッスンする"</string>
- <string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"インストルメント クラスタのレンダリング"</string>
- <string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"インストルメント クラスタ データを受信します"</string>
<string name="car_permission_label_car_ux_restrictions_configuration" msgid="6801393970411049725">"UX 制限の設定"</string>
<string name="car_permission_desc_car_ux_restrictions_configuration" msgid="5711926927484813777">"UX 制限を設定します"</string>
<string name="car_permission_label_access_private_display_id" msgid="6712116114341634316">"非公開ディスプレイ ID への読み取りアクセス"</string>
@@ -74,8 +70,6 @@
<string name="car_permission_desc_read_car_occupant_awareness_state" msgid="188865882598414986">"乗員検知システムのステータスと検知データの読み取りを許可します"</string>
<string name="car_permission_label_control_car_occupant_awareness_system" msgid="7163330266691094542">"乗員検知システムグラフの操作"</string>
<string name="car_permission_desc_control_car_occupant_awareness_system" msgid="7123482622084531911">"乗員検知システムの検知グラフの開始および終了操作を許可します"</string>
- <string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"車の入力サービス"</string>
- <string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"入力イベントを処理します"</string>
<string name="car_permission_label_diag_read" msgid="7248894224877702604">"診断データの読み取り"</string>
<string name="car_permission_desc_diag_read" msgid="1121426363040966178">"車から診断データを読み取ります。"</string>
<string name="car_permission_label_diag_clear" msgid="4783070510879698157">"診断データの消去"</string>
@@ -84,8 +78,6 @@
<string name="car_permission_desc_vms_publisher" msgid="5589489298597386828">"VMS メッセージをパブリッシュ"</string>
<string name="car_permission_label_vms_subscriber" msgid="5648841182059222299">"VMS サブスクライバー"</string>
<string name="car_permission_desc_vms_subscriber" msgid="7551009457847673620">"VMS メッセージに登録"</string>
- <string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"VMS クライアント サービス"</string>
- <string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"VMS クライアントにバインド"</string>
<string name="car_permission_label_storage_monitoring" msgid="2327639346522530549">"フラッシュ ストレージのモニタリング"</string>
<string name="car_permission_desc_storage_monitoring" msgid="2075712271139671318">"フラッシュ ストレージの使用状況をモニタリングします"</string>
<string name="car_permission_label_driving_state" msgid="7754624599537393650">"運転状態へのアクセス"</string>
diff --git a/service/res/values-ka/strings.xml b/service/res/values-ka/strings.xml
index 56c7449..548f5dc 100644
--- a/service/res/values-ka/strings.xml
+++ b/service/res/values-ka/strings.xml
@@ -42,8 +42,6 @@
<string name="car_permission_desc_projection" msgid="2352178999656292944">"აპს აძლევს ინტერფეისის ტელეფონიდან მანქანის ეკრანზე პროეცირების საშუალებას."</string>
<string name="car_permission_label_access_projection_status" msgid="4231618890836627402">"პროეცირების სტატუსზე წვდომა"</string>
<string name="car_permission_desc_access_projection_status" msgid="8497351979100616278">"აპს აძლევს მანქანის ეკრანზე პროეცირებული სხვა აპების სტატუსის მიღების საშუალებას."</string>
- <string name="car_permission_label_bind_projection_service" msgid="5362076216606651526">"პროეცირების სერვისთან მიბმა"</string>
- <string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"მფლობელს აძლევს პროეცირების სერვისის ზედა დონის ინტერფეისთან მიბმის საშუალებას. ნორმალურ აპებს არასოდეს უნდა დაჭირდეთ."</string>
<string name="car_permission_label_audio_volume" msgid="310587969373137690">"მანქანის აუდიოს ხმის სიძლიერის გაკონტროლება"</string>
<string name="car_permission_label_audio_settings" msgid="6524703796944023977">"მანქანის აუდიო პარამეტრების მართვა"</string>
<string name="car_permission_label_mock_vehicle_hal" msgid="7198852512207405935">"ავტომობილის HAL-ინტერფეისის ემულაცია"</string>
@@ -62,8 +60,6 @@
<string name="car_permission_desc_car_cluster_control" msgid="9222776665281176031">"აპების გაშვება ხელსაწყოთა პანელზე"</string>
<string name="car_permission_car_monitor_cluster_navigation_state" msgid="7025307242306902441">"ინსტრუმენტთა ნაკრების ნავიგაციის მდგომარეობა"</string>
<string name="car_permission_desc_car_monitor_cluster_navigation_state" msgid="8745047153878713339">"მოუსმინეთ ინსტრუმენტების ნაკრების ნავიგაციის მდგომარეობის ცვლილებებს"</string>
- <string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"რენდერი ხელსაწყოთა პანელზე"</string>
- <string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"ხელსაწყოთა პანელის მონაცემების მიღება"</string>
<string name="car_permission_label_car_ux_restrictions_configuration" msgid="6801393970411049725">"UX შეზღუდვების კონფიგურაცია"</string>
<string name="car_permission_desc_car_ux_restrictions_configuration" msgid="5711926927484813777">"UX შეზღუდვების კონფიგურაცია"</string>
<string name="car_permission_label_access_private_display_id" msgid="6712116114341634316">"წვდომა წასაკითხად პირადი ჩვენების ID-ზე"</string>
@@ -74,8 +70,6 @@
<string name="car_permission_desc_read_car_occupant_awareness_state" msgid="188865882598414986">"იძლევა მძღოლის ინფორმირების სისტემის სტატუსისა და ამოცნობის მონაცემების წაკითხვის საშუალებას"</string>
<string name="car_permission_label_control_car_occupant_awareness_system" msgid="7163330266691094542">"მძღოლის ინფორმირების სისტემის დიაგრამის მართვა"</string>
<string name="car_permission_desc_control_car_occupant_awareness_system" msgid="7123482622084531911">"იძლევა მძღოლის ინფორმირების სისტემის გაშვების მართვისა და ამოცნობის დიაგრამის შეწყვეტის საშუალებას"</string>
- <string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"მანქანის შეყვანის სერვისი"</string>
- <string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"შეტანის მოვლენების დამუშავება"</string>
<string name="car_permission_label_diag_read" msgid="7248894224877702604">"დიაგნოსტიკური მონაცემების წაკითხვა"</string>
<string name="car_permission_desc_diag_read" msgid="1121426363040966178">"დიაგნოსტიკური მონაცემების წაკითხვა მანქანიდან."</string>
<string name="car_permission_label_diag_clear" msgid="4783070510879698157">"დიაგნოსტიკური მონაცემების გასუფთავება"</string>
@@ -84,8 +78,6 @@
<string name="car_permission_desc_vms_publisher" msgid="5589489298597386828">"VMS-შეტყობინებების გამოქვეყნება"</string>
<string name="car_permission_label_vms_subscriber" msgid="5648841182059222299">"VMS-შეტყობინებების გამომწერი"</string>
<string name="car_permission_desc_vms_subscriber" msgid="7551009457847673620">"VMS-შეტყობინებების გამოწერა"</string>
- <string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"VMS კლიენტის სერვისი"</string>
- <string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"VMS კლიენტებთან მიბმა"</string>
<string name="car_permission_label_storage_monitoring" msgid="2327639346522530549">"ფლეშ-მეხსიერების მონიტორინგი"</string>
<string name="car_permission_desc_storage_monitoring" msgid="2075712271139671318">"ფლეშ-მეხსიერების გამოყენების მონიტორინგი"</string>
<string name="car_permission_label_driving_state" msgid="7754624599537393650">"მანქანის მართვის მდგომარეობისთვის თვალის მიდევნება"</string>
diff --git a/service/res/values-kk/strings.xml b/service/res/values-kk/strings.xml
index 33a8247..620c0c9 100644
--- a/service/res/values-kk/strings.xml
+++ b/service/res/values-kk/strings.xml
@@ -42,8 +42,6 @@
<string name="car_permission_desc_projection" msgid="2352178999656292944">"Қолданбаға телефонның интерфейсін көліктің дисплейінде көрсетуге мүмкіндік береді."</string>
<string name="car_permission_label_access_projection_status" msgid="4231618890836627402">"проекция күйін көру"</string>
<string name="car_permission_desc_access_projection_status" msgid="8497351979100616278">"Қолданбаға көліктің дисплейінде көрсетілетін басқа қолданбалардың күйін қарауға мүмкіндік береді."</string>
- <string name="car_permission_label_bind_projection_service" msgid="5362076216606651526">"проекция қызметімен байланыстыру"</string>
- <string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"Пайдаланушыға проекция қызметінің жоғары деңгейлі интерфейсімен байланыстыруға мүмкіндік береді. Қалыпты қолданбаларға қажет емес."</string>
<string name="car_permission_label_audio_volume" msgid="310587969373137690">"көліктегі аудионың дыбыс деңгейін басқару"</string>
<string name="car_permission_label_audio_settings" msgid="6524703796944023977">"көліктің аудио параметрлерін басқару"</string>
<string name="car_permission_label_mock_vehicle_hal" msgid="7198852512207405935">"көліктің HAL интерфейсін эмуляциялау"</string>
@@ -62,8 +60,6 @@
<string name="car_permission_desc_car_cluster_control" msgid="9222776665281176031">"Құралдар кластеріндегі қолданбаларды іске қосу"</string>
<string name="car_permission_car_monitor_cluster_navigation_state" msgid="7025307242306902441">"Құралдар кластерінің навигация күйі"</string>
<string name="car_permission_desc_car_monitor_cluster_navigation_state" msgid="8745047153878713339">"Құралдар кластерінің навигация күйіндегі өзгерістерді тыңдау"</string>
- <string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"Құралдар кластерін көрсету"</string>
- <string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"Құралдар кластері туралы дерек алу"</string>
<string name="car_permission_label_car_ux_restrictions_configuration" msgid="6801393970411049725">"UX шектеулеріне қатысты конфигурация"</string>
<string name="car_permission_desc_car_ux_restrictions_configuration" msgid="5711926927484813777">"UX шектеулерін конфигурациялау"</string>
<string name="car_permission_label_access_private_display_id" msgid="6712116114341634316">"Жеке көрсетілетін идентификаторды оқуға рұқсат"</string>
@@ -74,8 +70,6 @@
<string name="car_permission_desc_read_car_occupant_awareness_state" msgid="188865882598414986">"Жолаушыларды бақылау жүйесінің күйін оқуға және деректерді анықтауға мүмкіндік береді."</string>
<string name="car_permission_label_control_car_occupant_awareness_system" msgid="7163330266691094542">"Жолаушыларды бақылау жүйесі графигі"</string>
<string name="car_permission_desc_control_car_occupant_awareness_system" msgid="7123482622084531911">"Жолаушыларды бақылау жүйесі графигінің басталуы мен аяқталуын басқаруға мүмкіндік береді."</string>
- <string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Көліктің дерек енгізу қызметі"</string>
- <string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Деректерді енгізу оқиғаларын басқаруға болады"</string>
<string name="car_permission_label_diag_read" msgid="7248894224877702604">"диагностикалық деректерді көру"</string>
<string name="car_permission_desc_diag_read" msgid="1121426363040966178">"Көліктің диагностикалық деректерін көру."</string>
<string name="car_permission_label_diag_clear" msgid="4783070510879698157">"диагностикалық деректерді өшіру"</string>
@@ -84,8 +78,6 @@
<string name="car_permission_desc_vms_publisher" msgid="5589489298597386828">"VMS хабарларын жариялауға болады."</string>
<string name="car_permission_label_vms_subscriber" msgid="5648841182059222299">"VMS жазылушысы"</string>
<string name="car_permission_desc_vms_subscriber" msgid="7551009457847673620">"VMS хабарларына жазылуға болады."</string>
- <string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"VMS клиенттік қызметі"</string>
- <string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"VMS клиенттерімен байланыстыруға болады."</string>
<string name="car_permission_label_storage_monitoring" msgid="2327639346522530549">"Флэш жадын бақылау"</string>
<string name="car_permission_desc_storage_monitoring" msgid="2075712271139671318">"Флэш жадының қолданысын бақылау"</string>
<string name="car_permission_label_driving_state" msgid="7754624599537393650">"көлік жүргізу күйін білу"</string>
diff --git a/service/res/values-km/strings.xml b/service/res/values-km/strings.xml
index 15ced99..621b072 100644
--- a/service/res/values-km/strings.xml
+++ b/service/res/values-km/strings.xml
@@ -42,8 +42,6 @@
<string name="car_permission_desc_projection" msgid="2352178999656292944">"អនុញ្ញាតឱ្យកម្មវិធីបញ្ចាំងផ្ទៃពីទូរសព្ទនៅលើផ្ទាំងអេក្រង់របស់រថយន្ត។"</string>
<string name="car_permission_label_access_projection_status" msgid="4231618890836627402">"ចូលប្រើស្ថានភាពបញ្ចាំង"</string>
<string name="car_permission_desc_access_projection_status" msgid="8497351979100616278">"អនុញ្ញាតឱ្យកម្មវិធីទទួលបានស្ថានភាពរបស់កម្មវិធីផ្សេងទៀត ដែលបញ្ចាំងនៅលើផ្ទាំងអេក្រង់របស់រថយន្ត។"</string>
- <string name="car_permission_label_bind_projection_service" msgid="5362076216606651526">"ភ្ជាប់ទៅសេវាកម្មបញ្ចាំង"</string>
- <string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"អនុញ្ញាតឱ្យទម្រភ្ជាប់ជាមួយផ្ទៃកម្រិតកំពូលរបស់សេវាកម្មបញ្ចាំង។ មិនគួរចាំបាច់សម្រាប់កម្មវិធីធម្មតាទេ។"</string>
<string name="car_permission_label_audio_volume" msgid="310587969373137690">"គ្រប់គ្រងកម្រិតសំឡេងរបស់រថយន្ត"</string>
<string name="car_permission_label_audio_settings" msgid="6524703796944023977">"គ្រប់គ្រងការកំណត់សំឡេងរបស់រថយន្ត"</string>
<string name="car_permission_label_mock_vehicle_hal" msgid="7198852512207405935">"ត្រាប់តាម HAL របស់យានជំនិះ"</string>
@@ -62,8 +60,6 @@
<string name="car_permission_desc_car_cluster_control" msgid="9222776665281176031">"ចាប់ផ្ដើមកម្មវិធីនៅក្នុងបណ្ដុំឧបករណ៍"</string>
<string name="car_permission_car_monitor_cluster_navigation_state" msgid="7025307242306902441">"ស្ថានភាពរុករកបណ្ដុំឧបករណ៍"</string>
<string name="car_permission_desc_car_monitor_cluster_navigation_state" msgid="8745047153878713339">"ស្ដាប់ការផ្លាស់ប្ដូរស្ថានភាពរុករកបណ្ដុំឧបករណ៍"</string>
- <string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"ការបំប្លែងបណ្ដុំឧបករណ៍"</string>
- <string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"ទទួលបានទិន្នន័យបណ្ដុំឧបករណ៍"</string>
<string name="car_permission_label_car_ux_restrictions_configuration" msgid="6801393970411049725">"ការកំណត់រចនាសម្ព័ន្ធការរឹតបន្តឹង UX"</string>
<string name="car_permission_desc_car_ux_restrictions_configuration" msgid="5711926927484813777">"កំណត់រចនាសម្ព័ន្ធការរឹតបន្តឹង UX"</string>
<string name="car_permission_label_access_private_display_id" msgid="6712116114341634316">"ការចូលអានលេខសម្គាល់ផ្ទាំងអេក្រង់ឯកជន"</string>
@@ -74,8 +70,6 @@
<string name="car_permission_desc_read_car_occupant_awareness_state" msgid="188865882598414986">"អនុញ្ញាតការអានស្ថានភាព និងទិន្នន័យអំពីការចាប់ប្រព័ន្ធនៃការយល់ដឹងអំពីអ្នកជិះក្នុងរថយន្ត"</string>
<string name="car_permission_label_control_car_occupant_awareness_system" msgid="7163330266691094542">"គ្រប់គ្រងក្រាហ្វអំពីប្រព័ន្ធនៃការយល់ដឹងអំពីអ្នកជិះក្នុងរថយន្ត"</string>
<string name="car_permission_desc_control_car_occupant_awareness_system" msgid="7123482622084531911">"អនុញ្ញាតការគ្រប់គ្រងការចាប់ផ្ដើម និងការបញ្ឈប់ក្រាហ្វអំពីការចាប់ប្រព័ន្ធនៃការយល់ដឹងអំពីអ្នកជិះក្នុងរថយន្ត"</string>
- <string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"សេវាកម្មបញ្ចូលរបស់រថយន្ត"</string>
- <string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"គ្រប់គ្រងព្រឹត្តិការណ៍បញ្ចូល"</string>
<string name="car_permission_label_diag_read" msgid="7248894224877702604">"អានទិន្នន័យវិភាគ"</string>
<string name="car_permission_desc_diag_read" msgid="1121426363040966178">"អានអំពីទិន្នន័យវិភាគពីរថយន្ត។"</string>
<string name="car_permission_label_diag_clear" msgid="4783070510879698157">"សម្អាតទិន្នន័យវិភាគ"</string>
@@ -84,8 +78,6 @@
<string name="car_permission_desc_vms_publisher" msgid="5589489298597386828">"បោះផ្សាយសារ VMS"</string>
<string name="car_permission_label_vms_subscriber" msgid="5648841182059222299">"អ្នកជាវ VMS"</string>
<string name="car_permission_desc_vms_subscriber" msgid="7551009457847673620">"ជាវសារ VMS"</string>
- <string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"សេវាកម្មអតិថិជន VMS"</string>
- <string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"ភ្ជាប់ទៅអតិថិជន VMS"</string>
<string name="car_permission_label_storage_monitoring" msgid="2327639346522530549">"ការតាមដានឧបករណ៍ផ្ទុកទិន្នន័យ"</string>
<string name="car_permission_desc_storage_monitoring" msgid="2075712271139671318">"តាមដានការប្រើប្រាស់ឧបករណ៍ផ្ទុកទិន្នន័យ"</string>
<string name="car_permission_label_driving_state" msgid="7754624599537393650">"ស្ដាប់អំពីស្ថានភាពបើកបរ"</string>
diff --git a/service/res/values-kn/strings.xml b/service/res/values-kn/strings.xml
index b80cfe4..3fec736 100644
--- a/service/res/values-kn/strings.xml
+++ b/service/res/values-kn/strings.xml
@@ -40,10 +40,8 @@
<string name="car_permission_desc_radio" msgid="3385999027478186964">"ಕಾರಿನ ರೇಡಿಯೋವನ್ನು ನಿಯಂತ್ರಿಸಿ."</string>
<string name="car_permission_label_projection" msgid="9107156380287576787">"ಕಾರಿನ ಡಿಸ್ಪ್ಲೇನಲ್ಲಿರುವ ಫೋನ್ನಿಂದ ಇಂಟರ್ ಫೇಸ್ ಅನ್ನು ಪ್ರಾಜೆಕ್ಟ್ ಮಾಡಿ"</string>
<string name="car_permission_desc_projection" msgid="2352178999656292944">"ಕಾರಿನ ಡಿಸ್ಪ್ಲೇನಲ್ಲಿರುವ ಫೋನ್ನಿಂದ ಇಂಟರ್ ಫೇಸ್ ಅನ್ನು ಪ್ರಾಜೆಕ್ಟ್ ಮಾಡಲು ಆ್ಯಪ್ಗೆ ಅನುಮತಿಸುತ್ತದೆ."</string>
- <string name="car_permission_label_access_projection_status" msgid="4231618890836627402">"ಪ್ರೊಜೆಕ್ಷನ್ ಸ್ಥಿತಿಯನ್ನು ಪ್ರವೇಶಿಸಿ"</string>
+ <string name="car_permission_label_access_projection_status" msgid="4231618890836627402">"ಪ್ರಕ್ಷೇಪಣೆ ಸ್ಥಿತಿಯನ್ನು ಪ್ರವೇಶಿಸಿ"</string>
<string name="car_permission_desc_access_projection_status" msgid="8497351979100616278">"ಕಾರಿನ ಡಿಸ್ಪ್ಲೇಗೆ ಪ್ರಾಜೆಕ್ಟ್ ಮಾಡುವ ಇತರ ಆ್ಯಪ್ಗಳ ಸ್ಥಿತಿಯನ್ನು ಪಡೆಯಲು ಆ್ಯಪ್ಗೆ ಅನುಮತಿಸುತ್ತದೆ."</string>
- <string name="car_permission_label_bind_projection_service" msgid="5362076216606651526">"ಪ್ರೊಜೆಕ್ಷನ್ ಸೇವೆಗೆ ಪ್ರತಿಬಂಧಿಸಿ"</string>
- <string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"ಪ್ರೊಜೆಕ್ಷನ್ ಸೇವೆಯ ಉನ್ನತ ಮಟ್ಟದ ಇಂಟರ್ ಫೇಸ್ಗೆ ಪ್ರತಿಬಂಧಿಸಲು ಮಾಲೀಕರಿಗೆ ಅವಕಾಶ ನೀಡುತ್ತದೆ. ಸಾಮಾನ್ಯ ಆ್ಯಪ್ಗಳಿಗೆ ಎಂದಿಗೂ ಅಗತ್ಯವಿರುವುದಿಲ್ಲ."</string>
<string name="car_permission_label_audio_volume" msgid="310587969373137690">"ಕಾರಿನ ಆಡಿಯೋ ವಾಲ್ಯೂಮ್ ಅನ್ನು ನಿಯಂತ್ರಿಸಿ"</string>
<string name="car_permission_label_audio_settings" msgid="6524703796944023977">"ಕಾರಿನ ಆಡಿಯೋ ಸೆಟ್ಟಿಂಗ್ಗಳನ್ನು ನಿರ್ವಹಿಸಿ"</string>
<string name="car_permission_label_mock_vehicle_hal" msgid="7198852512207405935">"ವಾಹನದ HAL ಸಂಪರ್ಕಸಾಧನವನ್ನು ಅನುಕರಿಸಿ"</string>
@@ -62,8 +60,6 @@
<string name="car_permission_desc_car_cluster_control" msgid="9222776665281176031">"ಸಲಕರಣೆ ಸಂಚಯದಲ್ಲಿ ಆ್ಯಪ್ಗಳನ್ನು ಪ್ರಾರಂಭಿಸಿ"</string>
<string name="car_permission_car_monitor_cluster_navigation_state" msgid="7025307242306902441">"ಸಲಕರಣೆ ಕ್ಲಸ್ಟರ್ ನ್ಯಾವಿಗೇಷನ್ ಸ್ಥಿತಿ"</string>
<string name="car_permission_desc_car_monitor_cluster_navigation_state" msgid="8745047153878713339">"ಸಲಕರಣೆ ಕ್ಲಸ್ಟರ್ ನ್ಯಾವಿಗೇಶನ್ ಸ್ಥಿತಿಯ ಬದಲಾವಣೆಗಳನ್ನು ಆಲಿಸಿ"</string>
- <string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"ಸಲಕರಣೆ ಸಂಚಯ ತೋರಿಸು"</string>
- <string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"ಸಲಕರಣೆ ಸಂಚಯ ಮಾಹಿತಿಯನ್ನು ಸ್ವೀಕರಿಸಿ"</string>
<string name="car_permission_label_car_ux_restrictions_configuration" msgid="6801393970411049725">"UX ನಿರ್ಬಂಧಗಳ ಸಂರಚನೆ"</string>
<string name="car_permission_desc_car_ux_restrictions_configuration" msgid="5711926927484813777">"ಯುಎಕ್ಸ್ ನಿರ್ಬಂಧಗಳನ್ನು ಸಂರಚಿಸು"</string>
<string name="car_permission_label_access_private_display_id" msgid="6712116114341634316">"ಖಾಸಗಿ ಡಿಸ್ಪ್ಲೇ ಐಡಿಗೆ ಓದುವ ಪ್ರವೇಶ"</string>
@@ -74,8 +70,6 @@
<string name="car_permission_desc_read_car_occupant_awareness_state" msgid="188865882598414986">"Occupant Awareness System ಗಾಗಿ ಓದುವ ಸ್ಥಿತಿ ಮತ್ತು ಪತ್ತೆಹಚ್ಚುವಿಕೆ ಡೇಟಾವನ್ನು ಅನುಮತಿಸುತ್ತದೆ"</string>
<string name="car_permission_label_control_car_occupant_awareness_system" msgid="7163330266691094542">"Occupant Awareness System Graph ಅನ್ನು ನಿಯಂತ್ರಿಸಿ"</string>
<string name="car_permission_desc_control_car_occupant_awareness_system" msgid="7123482622084531911">"Occupant Awareness System ಪತ್ತೆಹಚ್ಚುವಿಕೆ ಗ್ರಾಫ್ನ ಪ್ರಾರಂಭಿಸಲು ಮತ್ತು ನಿಲ್ಲಿಸುವುದನ್ನು ನಿಯಂತ್ರಿಸಲು ನಿಮಗೆ ಅನುಮತಿಸುತ್ತದೆ"</string>
- <string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"ಕಾರಿನ ಇನ್ಪುಟ್ ಸೇವೆ"</string>
- <string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"ಊಡಿಕೆ ಘಟನೆಗಳನ್ನು ನಿಯಂತ್ರಿಸಿ"</string>
<string name="car_permission_label_diag_read" msgid="7248894224877702604">"ಡಯಾಗ್ನೋಸ್ಟಿಕ್ ಡೇಟಾವನ್ನು ಓದಿ"</string>
<string name="car_permission_desc_diag_read" msgid="1121426363040966178">"ಕಾರಿನಲ್ಲಿರುವ ಅದರ ಡಯಾಗ್ನೋಸ್ಟಿಕ್ ಡೇಟಾವನ್ನು ಓದಿ."</string>
<string name="car_permission_label_diag_clear" msgid="4783070510879698157">"ಡಯಾಗ್ನೋಸ್ಟಿಕ್ ಡೇಟಾವನ್ನು ತೆರವುಗೊಳಿಸಿ"</string>
@@ -84,8 +78,6 @@
<string name="car_permission_desc_vms_publisher" msgid="5589489298597386828">"VMS ಸಂದೇಶಗಳನ್ನು ಪ್ರಕಟಿಸಿ"</string>
<string name="car_permission_label_vms_subscriber" msgid="5648841182059222299">"VMS ಸಬ್ಸ್ಕ್ರೈಬರ್"</string>
<string name="car_permission_desc_vms_subscriber" msgid="7551009457847673620">"VMS ಸಂದೇಶಗಳಿಗೆ ಸಬ್ಸ್ಕ್ರೈಬ್ ಮಾಡಿ"</string>
- <string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"VMS ಕ್ಲೈಂಟ್ ಸೇವೆ"</string>
- <string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"VMS ಕ್ಲೈಂಟ್ಗಳಿಗೆ ಪ್ರತಿಬಂಧಿಸಿ"</string>
<string name="car_permission_label_storage_monitoring" msgid="2327639346522530549">"ಫ್ಲಾಶ್ ಸಂಗ್ರಹದ ಉಸ್ತುವಾರಿ"</string>
<string name="car_permission_desc_storage_monitoring" msgid="2075712271139671318">"ಫ್ಲಾಶ್ ಸಂಗ್ರಹ ಬಳಕೆಯ ಉಸ್ತುವಾರಿ"</string>
<string name="car_permission_label_driving_state" msgid="7754624599537393650">"ಚಾಲನೆಯ ಸ್ಥಿತಿಯ ಬದಲಾವಣೆಯನ್ನು ಆಲಿಸಿ"</string>
diff --git a/service/res/values-ko/strings.xml b/service/res/values-ko/strings.xml
index 8c50995..fd40bf9 100644
--- a/service/res/values-ko/strings.xml
+++ b/service/res/values-ko/strings.xml
@@ -42,8 +42,6 @@
<string name="car_permission_desc_projection" msgid="2352178999656292944">"휴대전화의 인터페이스를 자동차 디스플레이에 전송하도록 앱을 허용하세요."</string>
<string name="car_permission_label_access_projection_status" msgid="4231618890836627402">"프로젝션 상태에 액세스"</string>
<string name="car_permission_desc_access_projection_status" msgid="8497351979100616278">"자동차 디스플레이에 전송되는 다른 앱의 상태를 가져오도록 앱을 허용하세요."</string>
- <string name="car_permission_label_bind_projection_service" msgid="5362076216606651526">"프로젝션 서비스에 연결"</string>
- <string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"권한을 가진 프로그램이 프로젝션 서비스의 최상위 인터페이스에 연결되도록 허용합니다. 일반 앱에는 필요하지 않습니다."</string>
<string name="car_permission_label_audio_volume" msgid="310587969373137690">"차량 오디오 볼륨 제어"</string>
<string name="car_permission_label_audio_settings" msgid="6524703796944023977">"차량 오디오 설정 관리"</string>
<string name="car_permission_label_mock_vehicle_hal" msgid="7198852512207405935">"차량 HAL 에뮬레이션"</string>
@@ -62,8 +60,6 @@
<string name="car_permission_desc_car_cluster_control" msgid="9222776665281176031">"계기판에서 앱 실행"</string>
<string name="car_permission_car_monitor_cluster_navigation_state" msgid="7025307242306902441">"계기판 내비게이션 상태"</string>
<string name="car_permission_desc_car_monitor_cluster_navigation_state" msgid="8745047153878713339">"계기판 내비게이션 상태 변화를 수신합니다."</string>
- <string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"계기판 렌더링"</string>
- <string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"계기판 데이터 수신"</string>
<string name="car_permission_label_car_ux_restrictions_configuration" msgid="6801393970411049725">"UX 제한사항 설정"</string>
<string name="car_permission_desc_car_ux_restrictions_configuration" msgid="5711926927484813777">"UX 제한사항 설정"</string>
<string name="car_permission_label_access_private_display_id" msgid="6712116114341634316">"비공개 디스플레이 ID를 읽을 권한"</string>
@@ -74,8 +70,6 @@
<string name="car_permission_desc_read_car_occupant_awareness_state" msgid="188865882598414986">"Occupant Awareness System의 상태 및 감지 데이터를 읽는 것을 허용합니다."</string>
<string name="car_permission_label_control_car_occupant_awareness_system" msgid="7163330266691094542">"Occupant Awareness System 그래프 제어"</string>
<string name="car_permission_desc_control_car_occupant_awareness_system" msgid="7123482622084531911">"Occupant Awareness System 감지 그래프의 시작 및 중지를 제어하는 것을 허용합니다."</string>
- <string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"차량 입력 서비스"</string>
- <string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"입력 이벤트 처리"</string>
<string name="car_permission_label_diag_read" msgid="7248894224877702604">"진단 데이터 읽기"</string>
<string name="car_permission_desc_diag_read" msgid="1121426363040966178">"차량의 진단 데이터를 읽습니다."</string>
<string name="car_permission_label_diag_clear" msgid="4783070510879698157">"진단 데이터 삭제"</string>
@@ -84,8 +78,6 @@
<string name="car_permission_desc_vms_publisher" msgid="5589489298597386828">"VMS 메시지 게시"</string>
<string name="car_permission_label_vms_subscriber" msgid="5648841182059222299">"VMS 구독자"</string>
<string name="car_permission_desc_vms_subscriber" msgid="7551009457847673620">"VMS 메시지 구독"</string>
- <string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"VMS 클라이언트 서비스"</string>
- <string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"VMS 클라이언트에 연결"</string>
<string name="car_permission_label_storage_monitoring" msgid="2327639346522530549">"플래시 저장소 모니터링"</string>
<string name="car_permission_desc_storage_monitoring" msgid="2075712271139671318">"플래시 저장소 사용 모니터링"</string>
<string name="car_permission_label_driving_state" msgid="7754624599537393650">"운전 상태 감지"</string>
diff --git a/service/res/values-ky/strings.xml b/service/res/values-ky/strings.xml
index c8c47b1..8d808d9 100644
--- a/service/res/values-ky/strings.xml
+++ b/service/res/values-ky/strings.xml
@@ -20,8 +20,8 @@
<string name="car_permission_desc" msgid="3584369074931334964">"унааңыз тууралуу маалымат алынат"</string>
<string name="car_permission_label_camera" msgid="3725702064841827180">"унаадагы камерага мүмкүнчүлүк алуу"</string>
<string name="car_permission_desc_camera" msgid="917024932164501426">"Унааңыздын камераларын колдонуу."</string>
- <string name="car_permission_label_energy" msgid="7409144323527821558">"унаанын кубаты тууралуу маалымат алуу"</string>
- <string name="car_permission_desc_energy" msgid="3392963810053235407">"Унааңыздын кубаты тууралуу маалымат алуу."</string>
+ <string name="car_permission_label_energy" msgid="7409144323527821558">"унаанын кубаты тууралуу маалыматты көрүү"</string>
+ <string name="car_permission_desc_energy" msgid="3392963810053235407">"Унааңыздын кубаты тууралуу маалыматты көрүү."</string>
<string name="car_permission_label_control_car_energy" msgid="2788215385574313796">"Электромобилди кубаттоо жөндөөлөрүн көзөмөлдөө"</string>
<string name="car_permission_desc_control_car_energy" msgid="8765015897869031807">"Электромобилди кубаттоо жөндөөлөрүн көзөмөлдөңүз."</string>
<string name="car_permission_label_adjust_range_remaining" msgid="839033553999920138">"унаа дагы канча аралыкты басып өтөрүн тууралоо"</string>
@@ -42,8 +42,6 @@
<string name="car_permission_desc_projection" msgid="2352178999656292944">"Колдонмого телефондун интерфейсин унаанын дисплейине чыгарууга мүмкүнчүлүк берет"</string>
<string name="car_permission_label_access_projection_status" msgid="4231618890836627402">"долбоорлоо статусун көрүү мүмкүнчүлүгү"</string>
<string name="car_permission_desc_access_projection_status" msgid="8497351979100616278">"Колдонмого телефондун интерфейсин унаанын дисплейине чыгарып жаткан башка колдонмолордун статусун көрүүгө мүмкүнчүлүк берет."</string>
- <string name="car_permission_label_bind_projection_service" msgid="5362076216606651526">"долбоорлоо кызматына туташуу"</string>
- <string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"Ээсине долбоорлоо кызматынын жогорку деңгээл интерфейсине туташуу мүмкүнчүлүгүн берет. Жалпыга багышталган колдонмолордо эч качан колдонулбашы керек."</string>
<string name="car_permission_label_audio_volume" msgid="310587969373137690">"унаадагы аудионун үнүнүн катуулугун көзөмөлдөө"</string>
<string name="car_permission_label_audio_settings" msgid="6524703796944023977">"унаанын аудио жөндөөлөрүн башкаруу"</string>
<string name="car_permission_label_mock_vehicle_hal" msgid="7198852512207405935">"унаадагы HAL\'ды иштетип көрүү"</string>
@@ -62,8 +60,6 @@
<string name="car_permission_desc_car_cluster_control" msgid="9222776665281176031">"Куралдар кластериндеги колдонмолорду иштетүү"</string>
<string name="car_permission_car_monitor_cluster_navigation_state" msgid="7025307242306902441">"Аспаптар кластеринин навигация абалы"</string>
<string name="car_permission_desc_car_monitor_cluster_navigation_state" msgid="8745047153878713339">"Аспаптар кластеринин навигация абалындагы өзгөрүүлөрдү угуу"</string>
- <string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"Куралдар кластери түзүлүүдө"</string>
- <string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"Куралдар кластеринин дайындарын алуу"</string>
<string name="car_permission_label_car_ux_restrictions_configuration" msgid="6801393970411049725">"UX чектөөлөрүнүн конфигурациясы"</string>
<string name="car_permission_desc_car_ux_restrictions_configuration" msgid="5711926927484813777">"КТ чектөөлөрүн конфигурациялоо"</string>
<string name="car_permission_label_access_private_display_id" msgid="6712116114341634316">"Жеке дисплей идентификаторун окуу мүмкүнчүлүгү"</string>
@@ -74,8 +70,6 @@
<string name="car_permission_desc_read_car_occupant_awareness_state" msgid="188865882598414986">"Тургундарды көзөмөлдөө тутумундагы статусту окуп, маалыматты аныктоого мүмкүнчүлүк берет"</string>
<string name="car_permission_label_control_car_occupant_awareness_system" msgid="7163330266691094542">"Тургундарды көзөмөлдөө тутумунун диаграммасы"</string>
<string name="car_permission_desc_control_car_occupant_awareness_system" msgid="7123482622084531911">"Тургундарды көзөмөлдөө тутумун аныктоо диаграммасын иштетүүнү жана токтотууну көзөмөлдөөгө мүмкүнчүлүк берет"</string>
- <string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Унаанын киргизүү кызматы"</string>
- <string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Киргизүү аракеттерин башкаруу"</string>
<string name="car_permission_label_diag_read" msgid="7248894224877702604">"мүчүлүштүктөрдү аныктоо дайындарын окуу"</string>
<string name="car_permission_desc_diag_read" msgid="1121426363040966178">"Унаадагы мүчүлүштүктөрдү аныктоо дайындарын окуу."</string>
<string name="car_permission_label_diag_clear" msgid="4783070510879698157">"мүчүлүштүктөрдү аныктоо дайындарын тазалоо"</string>
@@ -84,8 +78,6 @@
<string name="car_permission_desc_vms_publisher" msgid="5589489298597386828">"VMS билдирүүлөрүн жарыялоо"</string>
<string name="car_permission_label_vms_subscriber" msgid="5648841182059222299">"VMS жазылуучусу"</string>
<string name="car_permission_desc_vms_subscriber" msgid="7551009457847673620">"VMS билдирүүлөрүн алып туруу үчүн жазылуу"</string>
- <string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"VMS кардарларды тейлөө кызматы"</string>
- <string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"VMS кардарларына туташуу"</string>
<string name="car_permission_label_storage_monitoring" msgid="2327639346522530549">"Флэш-сактагычты көзөмөлдөө"</string>
<string name="car_permission_desc_storage_monitoring" msgid="2075712271139671318">"Флэш-сактагычтын колдонулушун көзөмөлдөө"</string>
<string name="car_permission_label_driving_state" msgid="7754624599537393650">"унаа айдоо абалын угуу"</string>
@@ -139,7 +131,7 @@
<string name="car_permission_label_car_exterior_environment" msgid="3385924985991299436">"унаанын сыртындагы температураны окуу"</string>
<string name="car_permission_desc_car_exterior_environment" msgid="1716656004731603379">"Унаанын сыртындагы температураны көрүү."</string>
<string name="car_permission_label_car_tires" msgid="4379255261197836840">"унаа дөңгөлөктөрү тууралуу маалыматты окуу"</string>
- <string name="car_permission_desc_car_tires" msgid="8134496466769810134">"Унаанын дөңгөлөктөрү тууралуу маалымат алуу."</string>
+ <string name="car_permission_desc_car_tires" msgid="8134496466769810134">"Унаанын дөңгөлөктөрү тууралуу маалыматты көрүү."</string>
<string name="car_permission_label_car_steering" msgid="7779530447441232479">"унаанын рулун буруу бурчуна тиешелүү маалыматты көрүү"</string>
<string name="car_permission_desc_car_steering" msgid="1357331844530708138">"Унаанын рулун буруу бурчуна тиешелүү маалыматты көрүү."</string>
<string name="car_permission_label_read_car_display_units" msgid="7617008314862097183">"унаанын дисплей бөлүмдөрүн окуу"</string>
diff --git a/service/res/values-lo/strings.xml b/service/res/values-lo/strings.xml
index effb0aa..d07bf73 100644
--- a/service/res/values-lo/strings.xml
+++ b/service/res/values-lo/strings.xml
@@ -42,8 +42,6 @@
<string name="car_permission_desc_projection" msgid="2352178999656292944">"ອະນຸຍາດໃຫ້ແອັບສາຍພາບສ່ວນຕິດຕໍ່ຜູ້ໃຊ້ຈາກໂທລະສັບຢູ່ໄປໃສ່ຈໍສະແດງຜົນຂອງລົດ."</string>
<string name="car_permission_label_access_projection_status" msgid="4231618890836627402">"ເຂົ້າເຖິງສະຖານະການສາຍພາບ"</string>
<string name="car_permission_desc_access_projection_status" msgid="8497351979100616278">"ອະນຸຍາດໃຫ້ແອັບຮັບສະຖານະຂອງການສາຍພາບຈາກແອັບອື່ນໄປໃສ່ຈໍສະແດງຜົນຂອງລົດ."</string>
- <string name="car_permission_label_bind_projection_service" msgid="5362076216606651526">"ຜູກມັດກັບການບໍລິການສາຍພາບ"</string>
- <string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"ອະນຸຍາດໃຫ້ຜູ້ຖືຜູກມັດກັບສ່ວນຕິດຕໍ່ຜູ້ໃຊ້ລະດັບສູງຂອງການບໍລິການສາຍພາບ. ບໍ່ຄວນຕ້ອງການສຳລັບແອັບປົກກະຕິ."</string>
<string name="car_permission_label_audio_volume" msgid="310587969373137690">"ຄວບຄຸມລະດັບເຄື່ອງສຽງໃນລົດ"</string>
<string name="car_permission_label_audio_settings" msgid="6524703796944023977">"ຈັດການການຕັ້ງຄ່າສຽງຂອງລົດ"</string>
<string name="car_permission_label_mock_vehicle_hal" msgid="7198852512207405935">"ຈຳລອງ HAL ພາຫະນະ"</string>
@@ -62,8 +60,6 @@
<string name="car_permission_desc_car_cluster_control" msgid="9222776665281176031">"ເປີດໃຊ້ແອັບໃນແຜງໜ້າປັດ"</string>
<string name="car_permission_car_monitor_cluster_navigation_state" msgid="7025307242306902441">"ສະຖານະການນຳທາງຂອງແຜງໜ້າປັດ"</string>
<string name="car_permission_desc_car_monitor_cluster_navigation_state" msgid="8745047153878713339">"ພັງການປ່ຽນສະຖານະການນຳທາງຂອງແຜງໜ້າປັດ"</string>
- <string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"ການສະແດງຜົນແຜງໜ້າປັດ"</string>
- <string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"ຮັບຂໍ້ມູນຈາກແຜງໜ້າປັດ"</string>
<string name="car_permission_label_car_ux_restrictions_configuration" msgid="6801393970411049725">"ການກຳນົດຄ່າຂໍ້ຈຳກັດ UX"</string>
<string name="car_permission_desc_car_ux_restrictions_configuration" msgid="5711926927484813777">"ກຳນົດຄ່າຂໍ້ຈຳກັດ UX"</string>
<string name="car_permission_label_access_private_display_id" msgid="6712116114341634316">"ສິດເຂົ້າເຖິງແບບອ່ານສຳລັບ ID ການສະແດງຜົນສ່ວນຕົວ"</string>
@@ -74,8 +70,6 @@
<string name="car_permission_desc_read_car_occupant_awareness_state" msgid="188865882598414986">"ອະນຸຍາດການອ່ານຂໍ້ມູນສະຖານະ ແລະ ການກວດຫາສຳລັບລະບົບການຮັບຮູ້ວ່າມີຄົນຢູ່"</string>
<string name="car_permission_label_control_car_occupant_awareness_system" msgid="7163330266691094542">"ຄວບຄຸມກຣາຟຂອງລະບົບການຮັບຮູ້ວ່າມີຄົນຢູ່"</string>
<string name="car_permission_desc_control_car_occupant_awareness_system" msgid="7123482622084531911">"ອະນຸຍາດການຄວບຄຸມການເລີ່ມ ແລະ ການຢຸດສຳລັບກຣາຟການກວດຫາຂອງລະບົບການຮັບຮູ້ວ່າມີຄົນຢູ່"</string>
- <string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"ການບໍລິການປ້ອນຂໍ້ມູນຂອງລົດ"</string>
- <string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"ຈັດການເຫດການປ້ອນຂໍ້ມູນ"</string>
<string name="car_permission_label_diag_read" msgid="7248894224877702604">"ອ່ານຂໍ້ມູນການວິເຄາະ"</string>
<string name="car_permission_desc_diag_read" msgid="1121426363040966178">"ອ່ານຂໍ້ມູນການວິເຄາະຈາກລົດ."</string>
<string name="car_permission_label_diag_clear" msgid="4783070510879698157">"ລຶບລ້າງຂໍ້ມູນການວິເຄາະ"</string>
@@ -84,8 +78,6 @@
<string name="car_permission_desc_vms_publisher" msgid="5589489298597386828">"ເຜີຍແຜ່ຂໍ້ຄວາມ VMS"</string>
<string name="car_permission_label_vms_subscriber" msgid="5648841182059222299">"ຜູ້ສະໝັກໃຊ້ VMS"</string>
<string name="car_permission_desc_vms_subscriber" msgid="7551009457847673620">"ສະໝັກໃຊ້ຂໍ້ຄວາມ VMS"</string>
- <string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"ການບໍລິການລູກຂ່າຍ VMS"</string>
- <string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"ຜູກມັດກັບລູກຂ່າຍ VMS"</string>
<string name="car_permission_label_storage_monitoring" msgid="2327639346522530549">"ການຕິດຕາມພື້ນທີ່ຈັດເກັບຂໍ້ມູນຂອງແຟລດ"</string>
<string name="car_permission_desc_storage_monitoring" msgid="2075712271139671318">"ຕິດຕາມການໃຊ້ພື້ນທີ່ເກັບຂໍ້ມູນແຟລດ"</string>
<string name="car_permission_label_driving_state" msgid="7754624599537393650">"ຟັງສະຖານະການຂັບຂີ່"</string>
diff --git a/service/res/values-lt/strings.xml b/service/res/values-lt/strings.xml
index 6462b55..38ebbc1 100644
--- a/service/res/values-lt/strings.xml
+++ b/service/res/values-lt/strings.xml
@@ -42,8 +42,6 @@
<string name="car_permission_desc_projection" msgid="2352178999656292944">"Programai leidžiama iš telefono projektuoti sąsają automobilio ekrane."</string>
<string name="car_permission_label_access_projection_status" msgid="4231618890836627402">"pasiekti projektavimo būseną"</string>
<string name="car_permission_desc_access_projection_status" msgid="8497351979100616278">"Programai leidžiama gauti kitų programų, projektuojančių automobilio ekrane, būseną."</string>
- <string name="car_permission_label_bind_projection_service" msgid="5362076216606651526">"susieti su projektavimo paslauga"</string>
- <string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"Savininkui leidžiama susisaistyti su aukščiausio lygio projektavimo paslaugos sąsaja. Įprastoms programoms to neturėtų prireikti."</string>
<string name="car_permission_label_audio_volume" msgid="310587969373137690">"valdyti automobilio garsų garsumą"</string>
<string name="car_permission_label_audio_settings" msgid="6524703796944023977">"valdyti automobilio garso nustatymus"</string>
<string name="car_permission_label_mock_vehicle_hal" msgid="7198852512207405935">"imituoti transporto priemonės HAL"</string>
@@ -62,8 +60,6 @@
<string name="car_permission_desc_car_cluster_control" msgid="9222776665281176031">"Pristatyti programas instrumentų blokinyje"</string>
<string name="car_permission_car_monitor_cluster_navigation_state" msgid="7025307242306902441">"Instrumentų blokinio navigacijos būsena"</string>
<string name="car_permission_desc_car_monitor_cluster_navigation_state" msgid="8745047153878713339">"Klausyti instrumentų blokinio navigacijos būsenos pakeitimų"</string>
- <string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"Instrumentų blokinio pateikimas"</string>
- <string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"Gauti instrumentų blokinio duomenis"</string>
<string name="car_permission_label_car_ux_restrictions_configuration" msgid="6801393970411049725">"NP apribojimų konfigūravimas"</string>
<string name="car_permission_desc_car_ux_restrictions_configuration" msgid="5711926927484813777">"Konfigūruoti NP apribojimus"</string>
<string name="car_permission_label_access_private_display_id" msgid="6712116114341634316">"Skaitymo prieiga prie privataus ekrano ID"</string>
@@ -74,8 +70,6 @@
<string name="car_permission_desc_read_car_occupant_awareness_state" msgid="188865882598414986">"Leidžiama skaityti duomenis apie keleivių stebėjimo sistemos skaitymo būseną ir aptikimą"</string>
<string name="car_permission_label_control_car_occupant_awareness_system" msgid="7163330266691094542">"Valdyti keleivių stebėjimo sistemos diagramą"</string>
<string name="car_permission_desc_control_car_occupant_awareness_system" msgid="7123482622084531911">"Leidžiama įjungti ir sustabdyti keleivių stebėjimo sistemos aptikimo diagramą"</string>
- <string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Automobilio įvesties paslauga"</string>
- <string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Apdoroti įvesties įvykius."</string>
<string name="car_permission_label_diag_read" msgid="7248894224877702604">"nuskaityti diagnostikos duomenis"</string>
<string name="car_permission_desc_diag_read" msgid="1121426363040966178">"Nuskaityti automobilio diagnostikos duomenis."</string>
<string name="car_permission_label_diag_clear" msgid="4783070510879698157">"išvalyti diagnostikos duomenis"</string>
@@ -84,8 +78,6 @@
<string name="car_permission_desc_vms_publisher" msgid="5589489298597386828">"Skelbti VMS pranešimus"</string>
<string name="car_permission_label_vms_subscriber" msgid="5648841182059222299">"VMS prenumeratorius"</string>
<string name="car_permission_desc_vms_subscriber" msgid="7551009457847673620">"Prenumeruoti VMS pranešimus"</string>
- <string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"VMS kliento paslauga"</string>
- <string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"Susaistyti su VMS klientais"</string>
<string name="car_permission_label_storage_monitoring" msgid="2327639346522530549">"Atmintuko stebėjimas"</string>
<string name="car_permission_desc_storage_monitoring" msgid="2075712271139671318">"Stebėti atmintuko naudojimą."</string>
<string name="car_permission_label_driving_state" msgid="7754624599537393650">"klausyti vairavimo būsenos"</string>
diff --git a/service/res/values-lv/strings.xml b/service/res/values-lv/strings.xml
index 9946fc2..c3a2a13 100644
--- a/service/res/values-lv/strings.xml
+++ b/service/res/values-lv/strings.xml
@@ -42,8 +42,6 @@
<string name="car_permission_desc_projection" msgid="2352178999656292944">"Ļauj lietotnei projicēt tālruņa saskarni automašīnas displejā."</string>
<string name="car_permission_label_access_projection_status" msgid="4231618890836627402">"piekļūt projicēšanas stāvoklim"</string>
<string name="car_permission_desc_access_projection_status" msgid="8497351979100616278">"Ļauj lietotnei iegūt citu tādu lietotņu statusu, kas tiek projicētas automašīnas displejā."</string>
- <string name="car_permission_label_bind_projection_service" msgid="5362076216606651526">"saistīt ar projicēšanas pakalpojumu"</string>
- <string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"Ļauj īpašniekam izveidot saiti ar projicēšanas pakalpojuma augšējā līmeņa saskarni. Parastajām lietotnēm tas nekad nav nepieciešams."</string>
<string name="car_permission_label_audio_volume" msgid="310587969373137690">"kontrolēt automašīnas audio skaļumu"</string>
<string name="car_permission_label_audio_settings" msgid="6524703796944023977">"pārvaldīt automašīnas audio iestatījumus"</string>
<string name="car_permission_label_mock_vehicle_hal" msgid="7198852512207405935">"emulēt transportlīdzekļa HAL"</string>
@@ -62,8 +60,6 @@
<string name="car_permission_desc_car_cluster_control" msgid="9222776665281176031">"Palaist lietotnes mēraparātu blokā."</string>
<string name="car_permission_car_monitor_cluster_navigation_state" msgid="7025307242306902441">"Navigācijas statuss mēraparātu panelī"</string>
<string name="car_permission_desc_car_monitor_cluster_navigation_state" msgid="8745047153878713339">"Uztvert navigācijas statusa izmaiņas mēraparātu panelī"</string>
- <string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"Atveide mēraparātu blokā"</string>
- <string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"Saņemt datus no mēraparātu bloka."</string>
<string name="car_permission_label_car_ux_restrictions_configuration" msgid="6801393970411049725">"Lietotāja pieredzes ierobežojumu konfigurēšana"</string>
<string name="car_permission_desc_car_ux_restrictions_configuration" msgid="5711926927484813777">"Konfigurēt lietotāja pieredzes ierobežojumus."</string>
<string name="car_permission_label_access_private_display_id" msgid="6712116114341634316">"Lasīšanas piekļuve privātā displeja identifikatoram"</string>
@@ -74,8 +70,6 @@
<string name="car_permission_desc_read_car_occupant_awareness_state" msgid="188865882598414986">"Ļauj lasīt pasažieru uzraudzības sistēmas statusu un noteikšanas datus."</string>
<string name="car_permission_label_control_car_occupant_awareness_system" msgid="7163330266691094542">"Kontrolēt pasažieru uzraudzības sistēmas diagrammu"</string>
<string name="car_permission_desc_control_car_occupant_awareness_system" msgid="7123482622084531911">"Ļauj kontrolēt pasažieru uzraudzības sistēmas noteikšanas diagrammas palaišanu un apturēšanu."</string>
- <string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Automašīnas ievades pakalpojums"</string>
- <string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Apstrādāt ievades notikumus."</string>
<string name="car_permission_label_diag_read" msgid="7248894224877702604">"nolasīt diagnostikas datus"</string>
<string name="car_permission_desc_diag_read" msgid="1121426363040966178">"Nolasīt diagnostikas datus no automašīnas."</string>
<string name="car_permission_label_diag_clear" msgid="4783070510879698157">"notīrīt diagnostikas datus"</string>
@@ -84,8 +78,6 @@
<string name="car_permission_desc_vms_publisher" msgid="5589489298597386828">"Publicēt VMS ziņojumus"</string>
<string name="car_permission_label_vms_subscriber" msgid="5648841182059222299">"VMS abonents"</string>
<string name="car_permission_desc_vms_subscriber" msgid="7551009457847673620">"Abonēt VMS ziņojumus"</string>
- <string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"VMS klienta pakalpojums"</string>
- <string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"Saistīt ar VMS klientiem"</string>
<string name="car_permission_label_storage_monitoring" msgid="2327639346522530549">"Zibatmiņas uzraudzība"</string>
<string name="car_permission_desc_storage_monitoring" msgid="2075712271139671318">"Uzraudzīt zibatmiņas lietojumu."</string>
<string name="car_permission_label_driving_state" msgid="7754624599537393650">"uztvert kustības stāvokli"</string>
diff --git a/service/res/values-mk/strings.xml b/service/res/values-mk/strings.xml
index de37782..42b0c73 100644
--- a/service/res/values-mk/strings.xml
+++ b/service/res/values-mk/strings.xml
@@ -17,7 +17,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="2215078736675564541">"податоци за автомобилот"</string>
- <string name="car_permission_desc" msgid="3584369074931334964">"може да пристапуваат до податоците за автомобилот"</string>
+ <string name="car_permission_desc" msgid="3584369074931334964">"пристапува до податоците за автомобилот"</string>
<string name="car_permission_label_camera" msgid="3725702064841827180">"пристапува до камерата на автомобилот"</string>
<string name="car_permission_desc_camera" msgid="917024932164501426">"Пристапува до камерите на автомобилот."</string>
<string name="car_permission_label_energy" msgid="7409144323527821558">"пристапува до информациите за енергијата на автомобилот"</string>
@@ -42,8 +42,6 @@
<string name="car_permission_desc_projection" msgid="2352178999656292944">"Дозволува апликација да го прикажува интерфејсот од телефонот на екранот на автомобилот."</string>
<string name="car_permission_label_access_projection_status" msgid="4231618890836627402">"пристапува до статусот на прикажување"</string>
<string name="car_permission_desc_access_projection_status" msgid="8497351979100616278">"Дозволува апликација да го добива статусот на другите апликации што прикажуваат на екранот на автомобилот."</string>
- <string name="car_permission_label_bind_projection_service" msgid="5362076216606651526">"поврзување со услуга за прикажување"</string>
- <string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"Дозволува приклучната станица да се поврзе со интерфејс од највисоко ниво на услугата за прикажување. Не треба да се користи за обични апликации."</string>
<string name="car_permission_label_audio_volume" msgid="310587969373137690">"ја контролира јачината на звукот на автомобилот"</string>
<string name="car_permission_label_audio_settings" msgid="6524703796944023977">"управува со поставките за звук на автомобилот"</string>
<string name="car_permission_label_mock_vehicle_hal" msgid="7198852512207405935">"го поддржува HAL за возило"</string>
@@ -62,8 +60,6 @@
<string name="car_permission_desc_car_cluster_control" msgid="9222776665281176031">"Стартува апликации на инструменталната табла"</string>
<string name="car_permission_car_monitor_cluster_navigation_state" msgid="7025307242306902441">"Состојба на навигација на инструменталната табла"</string>
<string name="car_permission_desc_car_monitor_cluster_navigation_state" msgid="8745047153878713339">"Слушајте дали има промени на состојбата на навигација на инструменталната табла"</string>
- <string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"Прикажување на инструменталната табла"</string>
- <string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"Примајте податоци од инструменталната табла"</string>
<string name="car_permission_label_car_ux_restrictions_configuration" msgid="6801393970411049725">"Конфигурација на ограничувањата на корисничкото искуство"</string>
<string name="car_permission_desc_car_ux_restrictions_configuration" msgid="5711926927484813777">"Конфигурирајте ги ограничувањата на корисничкото искуство"</string>
<string name="car_permission_label_access_private_display_id" msgid="6712116114341634316">"Пристап за читање на ID на приватен екран"</string>
@@ -74,8 +70,6 @@
<string name="car_permission_desc_read_car_occupant_awareness_state" msgid="188865882598414986">"Овозможува читање на статусот и податоците на откривање за „Системот за откривање патници“"</string>
<string name="car_permission_label_control_car_occupant_awareness_system" msgid="7163330266691094542">"Го контролира графиконот на „Системот за откривање патници“"</string>
<string name="car_permission_desc_control_car_occupant_awareness_system" msgid="7123482622084531911">"Овозможува контролирање на стартувањето и сопирањето на графиконот за откривање на „Системот за откривање патници“"</string>
- <string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Влезна услуга на автомобилот"</string>
- <string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Ракува со влезните настани"</string>
<string name="car_permission_label_diag_read" msgid="7248894224877702604">"ги чита дијагностичките податоци"</string>
<string name="car_permission_desc_diag_read" msgid="1121426363040966178">"Чита дијагностички податоци од автомобилот."</string>
<string name="car_permission_label_diag_clear" msgid="4783070510879698157">"чисти дијагностички податоци"</string>
@@ -84,8 +78,6 @@
<string name="car_permission_desc_vms_publisher" msgid="5589489298597386828">"Објавувајте VMS-пораки"</string>
<string name="car_permission_label_vms_subscriber" msgid="5648841182059222299">"Претплатник на VMS"</string>
<string name="car_permission_desc_vms_subscriber" msgid="7551009457847673620">"Претплатете се на VMS-пораки"</string>
- <string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"Услуга на клиентот за VMS"</string>
- <string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"Сврзувајте се со клиенти за VMS"</string>
<string name="car_permission_label_storage_monitoring" msgid="2327639346522530549">"Следење на флеш меморијата"</string>
<string name="car_permission_desc_storage_monitoring" msgid="2075712271139671318">"Го следи користењето на флеш меморијата"</string>
<string name="car_permission_label_driving_state" msgid="7754624599537393650">"ја слуша состојбата на возење"</string>
diff --git a/service/res/values-ml/strings.xml b/service/res/values-ml/strings.xml
index 08bbbdb..8487ac5 100644
--- a/service/res/values-ml/strings.xml
+++ b/service/res/values-ml/strings.xml
@@ -42,8 +42,6 @@
<string name="car_permission_desc_projection" msgid="2352178999656292944">"ഫോണിൽ നിന്നുള്ള ഇൻ്റർഫേസ് കാറിൻ്റെ ഡിസ്പ്ലേയിൽ പ്രൊജക്റ്റ് ചെയ്യാൻ ആപ്പിനെ അനുവദിക്കുന്നു."</string>
<string name="car_permission_label_access_projection_status" msgid="4231618890836627402">"പ്രൊജക്ഷൻ നില ആക്സസ് ചെയ്യുക"</string>
<string name="car_permission_desc_access_projection_status" msgid="8497351979100616278">"കാറിൻ്റെ ഡിസ്പ്ലേയിൽ പ്രൊജക്റ്റ് ചെയ്യുന്ന മറ്റ് ആപ്പുകളുടെ സ്റ്റാറ്റസ് ലഭിക്കാൻ ആപ്പിനെ അനുവദിക്കുന്നു."</string>
- <string name="car_permission_label_bind_projection_service" msgid="5362076216606651526">"പ്രൊജക്ഷൻ സേവനവുമായി ബന്ധിപ്പിക്കുക"</string>
- <string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"പ്രൊജക്ഷൻ സേവനത്തിൻ്റെ ഏറ്റവും മികച്ച ഇൻ്റർഫേസുമായി ബന്ധിപ്പിക്കാൻ ദാതാവിനെ അനുവദിക്കുന്നു. സാധാരണ ആപ്പുകൾക്ക് ഒരിക്കലും ആവശ്യമില്ല."</string>
<string name="car_permission_label_audio_volume" msgid="310587969373137690">"കാറിൻ്റെ ഓഡിയോ വോളിയം നിയന്ത്രിക്കുക"</string>
<string name="car_permission_label_audio_settings" msgid="6524703796944023977">"കാറിൻ്റെ ഓഡിയോ ക്രമീകരണം മാനേജ് ചെയ്യുക"</string>
<string name="car_permission_label_mock_vehicle_hal" msgid="7198852512207405935">"വാഹന HAL എമുലേറ്റ് ചെയ്യുക"</string>
@@ -62,8 +60,6 @@
<string name="car_permission_desc_car_cluster_control" msgid="9222776665281176031">"ഇൻസ്ട്രുമെന്റ് ക്ലസ്റ്ററിൽ ആപ്പുകൾ ലോഞ്ച് ചെയ്യുക"</string>
<string name="car_permission_car_monitor_cluster_navigation_state" msgid="7025307242306902441">"ഇൻസ്ട്രുമെന്റ് ക്ലസ്റ്ററിലെ നാവിഗേഷൻ നില"</string>
<string name="car_permission_desc_car_monitor_cluster_navigation_state" msgid="8745047153878713339">"ഇൻസ്ട്രുമെന്റ് ക്ലസ്റ്ററിലെ നാവിഗേഷൻ നിലയിലെ മാറ്റങ്ങൾ ശ്രദ്ധിക്കുക"</string>
- <string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"ഇൻസ്ട്രുമെന്റ് ക്ലസ്റ്റർ റെൻഡർ ചെയ്യൽ"</string>
- <string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"ഇൻസ്ട്രുമെന്റ് ക്ലസ്റ്റർ ഡാറ്റ സ്വീകരിക്കുക"</string>
<string name="car_permission_label_car_ux_restrictions_configuration" msgid="6801393970411049725">"UX നിയന്ത്രണങ്ങളുടെ കോൺഫിഗറേഷൻ"</string>
<string name="car_permission_desc_car_ux_restrictions_configuration" msgid="5711926927484813777">"UX നിയന്ത്രണങ്ങൾ കോൺഫിഗർ ചെയ്യുക"</string>
<string name="car_permission_label_access_private_display_id" msgid="6712116114341634316">"സ്വകാര്യ ഡിസ്പ്ലേ ഐഡിക്കുള്ള വായനാ ആക്സസ്"</string>
@@ -74,8 +70,6 @@
<string name="car_permission_desc_read_car_occupant_awareness_state" msgid="188865882598414986">"ഒക്യുപന്റ് അവയർനെസ് സിസ്റ്റത്തിനുള്ള വായനാ നിലയും കണ്ടെത്തൽ ഡാറ്റയും അനുവദിക്കുന്നു"</string>
<string name="car_permission_label_control_car_occupant_awareness_system" msgid="7163330266691094542">"ഒക്യുപന്റ് അവയർനെസ് സിസ്റ്റം ഗ്രാഫ് നിയന്ത്രിക്കുക"</string>
<string name="car_permission_desc_control_car_occupant_awareness_system" msgid="7123482622084531911">"ഒക്യുപന്റ് അവയർനെസ് സിസ്റ്റം കണ്ടെത്തൽ ഗ്രാഫിന്റെ ആരംഭവും നിർത്തലും നിയന്ത്രിക്കാൻ അനുവദിക്കുന്നു"</string>
- <string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"കാറിന്റെ ഇൻപുട്ട് സേവനം"</string>
- <string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"ഇൻപുട്ട് ഇവന്റുകൾ കൈകാര്യം ചെയ്യുക"</string>
<string name="car_permission_label_diag_read" msgid="7248894224877702604">"പ്രശ്നനിർണ്ണയ ഡാറ്റ വായിക്കുക"</string>
<string name="car_permission_desc_diag_read" msgid="1121426363040966178">"കാറിൽ നിന്നുള്ള പ്രശ്നനിർണ്ണയ ഡാറ്റ വായിക്കുക."</string>
<string name="car_permission_label_diag_clear" msgid="4783070510879698157">"പ്രശ്നനിർണ്ണയ ഡാറ്റ മായ്ക്കുക"</string>
@@ -84,8 +78,6 @@
<string name="car_permission_desc_vms_publisher" msgid="5589489298597386828">"VMS മെസേജുകൾ പ്രസിദ്ധീകരിക്കുക"</string>
<string name="car_permission_label_vms_subscriber" msgid="5648841182059222299">"VMS വരിക്കാരൻ"</string>
<string name="car_permission_desc_vms_subscriber" msgid="7551009457847673620">"VMS മെസേജിൻ്റെ വരിക്കാരാവുക"</string>
- <string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"VMS ക്ലയൻ്റ് സേവനം"</string>
- <string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"VMS ക്ലയൻ്റുകളുമായി ബന്ധിപ്പിക്കുക"</string>
<string name="car_permission_label_storage_monitoring" msgid="2327639346522530549">"ഫ്ലാഷ് സ്റ്റോറേജ് നിരീക്ഷിക്കുന്നു"</string>
<string name="car_permission_desc_storage_monitoring" msgid="2075712271139671318">"ഫ്ലാഷ് സ്റ്റോറേജ് ഉപയോഗം നിരീക്ഷിക്കുക"</string>
<string name="car_permission_label_driving_state" msgid="7754624599537393650">"ഡ്രൈവിംഗ് നില ശ്രദ്ധിക്കുക"</string>
diff --git a/service/res/values-mn/strings.xml b/service/res/values-mn/strings.xml
index baeeb4f..57faca2 100644
--- a/service/res/values-mn/strings.xml
+++ b/service/res/values-mn/strings.xml
@@ -42,8 +42,6 @@
<string name="car_permission_desc_projection" msgid="2352178999656292944">"Аппад утасны харагдах байдлыг машины дэлгэцэд харуулахыг зөвшөөрдөг."</string>
<string name="car_permission_label_access_projection_status" msgid="4231618890836627402">"проекцын төлөвт хандах"</string>
<string name="car_permission_desc_access_projection_status" msgid="8497351979100616278">"Аппад машины дэлгэцэд харуулж буй бусад аппын төлөвийг сонсохыг зөвшөөрдөг."</string>
- <string name="car_permission_label_bind_projection_service" msgid="5362076216606651526">"проекцын үйлчилгээнд холбох"</string>
- <string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"Эзэмшигчид проекцын үйлчилгээний дээд түвшний харагдах байдлыг холбохыг зөвшөөрдөг. Энгийн аппуудад хэзээ ч хэрэг болох ёсгүй."</string>
<string name="car_permission_label_audio_volume" msgid="310587969373137690">"машины аудионы түвшнийг хянах"</string>
<string name="car_permission_label_audio_settings" msgid="6524703796944023977">"машины аудионы тохиргоог удирдах"</string>
<string name="car_permission_label_mock_vehicle_hal" msgid="7198852512207405935">"тээврийн хэрэгслийн HAL-г эмуляц хийх"</string>
@@ -62,8 +60,6 @@
<string name="car_permission_desc_car_cluster_control" msgid="9222776665281176031">"Аппуудыг хяналтын самбарт эхлүүлэх"</string>
<string name="car_permission_car_monitor_cluster_navigation_state" msgid="7025307242306902441">"Хяналтын самбарын навигацын төлөв"</string>
<string name="car_permission_desc_car_monitor_cluster_navigation_state" msgid="8745047153878713339">"Хяналтын самбарын навигацын төлөвийн өөрчлөлтийг сонсоно уу"</string>
- <string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"Хяналтын самбарын буулгалт"</string>
- <string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"Хяналтын самбарын өгөгдлийг хүлээн авах"</string>
<string name="car_permission_label_car_ux_restrictions_configuration" msgid="6801393970411049725">"UX Хязгаарлалтын тохируулга"</string>
<string name="car_permission_desc_car_ux_restrictions_configuration" msgid="5711926927484813777">"UX хязгаарлалтыг тохируулах"</string>
<string name="car_permission_label_access_private_display_id" msgid="6712116114341634316">"Хувийн дэлгэцийн id-н хандалтыг унших"</string>
@@ -74,8 +70,6 @@
<string name="car_permission_desc_read_car_occupant_awareness_state" msgid="188865882598414986">"Оршин суугчийн дохионы мэдээллийн системийн статус болон илрүүлэлтийн өгөгдлийг унших боломж олгодог"</string>
<string name="car_permission_label_control_car_occupant_awareness_system" msgid="7163330266691094542">"Оршин суугчийн дохионы мэдээллийн системийн графикийг хянах"</string>
<string name="car_permission_desc_control_car_occupant_awareness_system" msgid="7123482622084531911">"Оршин суугчийн дохионы мэдээллийн системийн илрүүлэлтийн графикийг эхлүүлэх, зогсоохыг хянах боломж олгодог"</string>
- <string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Машины оролтын үйлчилгээ"</string>
- <string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Оролтын арга хэмжээг боловсруулах"</string>
<string name="car_permission_label_diag_read" msgid="7248894224877702604">"оношилгооны өгөгдлийг унших"</string>
<string name="car_permission_desc_diag_read" msgid="1121426363040966178">"Машины оношилгооны өгөгдлийг унших."</string>
<string name="car_permission_label_diag_clear" msgid="4783070510879698157">"оношилгооны өгөгдлийг устгах"</string>
@@ -84,8 +78,6 @@
<string name="car_permission_desc_vms_publisher" msgid="5589489298597386828">"VMS мессежийг нийтлэх"</string>
<string name="car_permission_label_vms_subscriber" msgid="5648841182059222299">"VMS Захиалагч"</string>
<string name="car_permission_desc_vms_subscriber" msgid="7551009457847673620">"VMS мессежийг захиалах"</string>
- <string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"VMS Клиентийн үйлчилгээ"</string>
- <string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"VMS клиентэд холбох"</string>
<string name="car_permission_label_storage_monitoring" msgid="2327639346522530549">"Гэрэл хадгалалтын хяналт"</string>
<string name="car_permission_desc_storage_monitoring" msgid="2075712271139671318">"Гэрэл хадгалалтын ашиглалтыг хянах"</string>
<string name="car_permission_label_driving_state" msgid="7754624599537393650">"жолоодлогын төлөвийг сонсох"</string>
diff --git a/service/res/values-mr/strings.xml b/service/res/values-mr/strings.xml
index 87a9b01..8432a4f 100644
--- a/service/res/values-mr/strings.xml
+++ b/service/res/values-mr/strings.xml
@@ -42,8 +42,6 @@
<string name="car_permission_desc_projection" msgid="2352178999656292944">"अॅपला फोनवरून कारच्या डिस्प्लेवर इंटरफेस प्रोजेक्ट करण्याची अनुमती देते."</string>
<string name="car_permission_label_access_projection_status" msgid="4231618890836627402">"प्रोजेक्शनची स्थिती अॅक्सेस करा"</string>
<string name="car_permission_desc_access_projection_status" msgid="8497351979100616278">"अॅपला कारच्या डिस्प्लेवर प्रोजेक्ट करणार्या इतर अॅप्सची स्थिती जाणून घेण्याची अनुमती देते."</string>
- <string name="car_permission_label_bind_projection_service" msgid="5362076216606651526">"प्रोजेक्शन सेवेशी प्रतिबद्ध व्हा"</string>
- <string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"धारकाला प्रोजेक्शन सेवेच्या उच्च पातळीच्या इंटरफेसशी प्रतिबद्ध होण्याची अनुमती देते. साधारण अॅप्ससाठी कधीही आवश्यक नाही."</string>
<string name="car_permission_label_audio_volume" msgid="310587969373137690">"कारचा ऑडिओ व्हॉल्यूम नियंत्रित करा"</string>
<string name="car_permission_label_audio_settings" msgid="6524703796944023977">"कारच्या ऑडिओ सेटिंग्ज व्यवस्थापित करा"</string>
<string name="car_permission_label_mock_vehicle_hal" msgid="7198852512207405935">"वाहन HAL चे अनुकरण करा"</string>
@@ -62,8 +60,6 @@
<string name="car_permission_desc_car_cluster_control" msgid="9222776665281176031">"इंस्ट्रुमेंट क्लस्टरमध्ये अॅप्स लाँच करा"</string>
<string name="car_permission_car_monitor_cluster_navigation_state" msgid="7025307242306902441">"इंस्ट्रुमेंट क्लस्टर नेव्हिगेशन स्थिती"</string>
<string name="car_permission_desc_car_monitor_cluster_navigation_state" msgid="8745047153878713339">"इंस्ट्रुमेंट क्लस्टर नेव्हिगेशन स्थितीसंबंधित बदलांकडे लक्ष द्या"</string>
- <string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"इंस्ट्रुमेंट क्लस्टर रेंडरिंग"</string>
- <string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"इंस्ट्रुमेंट क्लस्टर डेटा मिळवा"</string>
<string name="car_permission_label_car_ux_restrictions_configuration" msgid="6801393970411049725">"UX निर्बंध कॉंफिगरेशन"</string>
<string name="car_permission_desc_car_ux_restrictions_configuration" msgid="5711926927484813777">"UX निर्बंध कॉंफिगर करा"</string>
<string name="car_permission_label_access_private_display_id" msgid="6712116114341634316">"खाजगी डिस्प्ले आयडीला वाचनाचा अॅक्सेस"</string>
@@ -74,8 +70,6 @@
<string name="car_permission_desc_read_car_occupant_awareness_state" msgid="188865882598414986">"ऑक्युपंट अवेअरनेस सिस्टम यासाठी वाचन स्थिती आणि डिटेक्शन डेटाला अनुमती देते"</string>
<string name="car_permission_label_control_car_occupant_awareness_system" msgid="7163330266691094542">"ऑक्युपंट अवेअरनेस सिस्टम आलेख नियंत्रित करा"</string>
<string name="car_permission_desc_control_car_occupant_awareness_system" msgid="7123482622084531911">"ऑक्युपंट अवेअरनेस सिस्टम डिटेक्शन आलेख सुरू करणे आणि थांबवणे नियंत्रित करण्यासाठी अनुमती देते"</string>
- <string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"कार इनपुट सेवा"</string>
- <string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"इनपुट इव्हेंट हाताळा"</string>
<string name="car_permission_label_diag_read" msgid="7248894224877702604">"निदान डेटा वाचा"</string>
<string name="car_permission_desc_diag_read" msgid="1121426363040966178">"कारचा निदान डेटा वाचा."</string>
<string name="car_permission_label_diag_clear" msgid="4783070510879698157">"निदान डेटा साफ करा"</string>
@@ -84,8 +78,6 @@
<string name="car_permission_desc_vms_publisher" msgid="5589489298597386828">"VMS मेसेज प्रकाशित करा"</string>
<string name="car_permission_label_vms_subscriber" msgid="5648841182059222299">"VMS सदस्य"</string>
<string name="car_permission_desc_vms_subscriber" msgid="7551009457847673620">"VMS मेसेजचे सदस्य व्हा"</string>
- <string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"VMS क्लायंट सेवा"</string>
- <string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"VMS क्लायंटशी प्रतिबद्ध व्हा"</string>
<string name="car_permission_label_storage_monitoring" msgid="2327639346522530549">"फ्लॅश स्टोरेज परीक्षण"</string>
<string name="car_permission_desc_storage_monitoring" msgid="2075712271139671318">"फ्लॅश स्टोरेज वापराचे परीक्षण करा"</string>
<string name="car_permission_label_driving_state" msgid="7754624599537393650">"ड्रायव्हिंगची स्थिती ऐका"</string>
diff --git a/service/res/values-ms/strings.xml b/service/res/values-ms/strings.xml
index 7c13ed5..79fd058 100644
--- a/service/res/values-ms/strings.xml
+++ b/service/res/values-ms/strings.xml
@@ -42,8 +42,6 @@
<string name="car_permission_desc_projection" msgid="2352178999656292944">"Membenarkan apl mengunjurkan antara muka pada paparan kereta daripada telefon."</string>
<string name="car_permission_label_access_projection_status" msgid="4231618890836627402">"akses status unjuran"</string>
<string name="car_permission_desc_access_projection_status" msgid="8497351979100616278">"Membenarkan apl mendapatkan status apl lain yang mengunjurkan sesuatu pada paparan kereta."</string>
- <string name="car_permission_label_bind_projection_service" msgid="5362076216606651526">"ikat pada perkhidmatan unjuran"</string>
- <string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"Membenarkan pemegang terikat dengan antara muka peringkat tertinggi bagi perkhidmatan unjuran. Tidak sekali-kali diperlukan untuk apl biasa."</string>
<string name="car_permission_label_audio_volume" msgid="310587969373137690">"kawal kelantangan audio kereta"</string>
<string name="car_permission_label_audio_settings" msgid="6524703796944023977">"urus tetapan audio kereta"</string>
<string name="car_permission_label_mock_vehicle_hal" msgid="7198852512207405935">"tiru HAL kenderaan"</string>
@@ -62,8 +60,6 @@
<string name="car_permission_desc_car_cluster_control" msgid="9222776665281176031">"Lancarkan apl dalam kluster alatan"</string>
<string name="car_permission_car_monitor_cluster_navigation_state" msgid="7025307242306902441">"Keadaan navigasi kluster instrumen"</string>
<string name="car_permission_desc_car_monitor_cluster_navigation_state" msgid="8745047153878713339">"Perhatikan perubahan keadaan navigasi kluster instrumen"</string>
- <string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"Pemaparan Kluster Alatan"</string>
- <string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"Terima data kluster alatan"</string>
<string name="car_permission_label_car_ux_restrictions_configuration" msgid="6801393970411049725">"Konfigurasi Sekatan UX"</string>
<string name="car_permission_desc_car_ux_restrictions_configuration" msgid="5711926927484813777">"Konfigurasikan Sekatan UX"</string>
<string name="car_permission_label_access_private_display_id" msgid="6712116114341634316">"Akses baca ke id paparan peribadi"</string>
@@ -74,8 +70,6 @@
<string name="car_permission_desc_read_car_occupant_awareness_state" msgid="188865882598414986">"Membenarkan pembacaan status dan data pengesanan untuk Sistem Kesedaran Penumpang"</string>
<string name="car_permission_label_control_car_occupant_awareness_system" msgid="7163330266691094542">"Kawal Graf Sistem Kesedaran Penumpang"</string>
<string name="car_permission_desc_control_car_occupant_awareness_system" msgid="7123482622084531911">"Membenarkan pengawalan permulaan dan penamatan graf pengesanan Sistem Kesedaran Penumpang"</string>
- <string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Perkhidmatan Input Kereta"</string>
- <string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Kendalikan peristiwa input"</string>
<string name="car_permission_label_diag_read" msgid="7248894224877702604">"baca data diagnostik"</string>
<string name="car_permission_desc_diag_read" msgid="1121426363040966178">"Baca data diagnostik daripada kereta."</string>
<string name="car_permission_label_diag_clear" msgid="4783070510879698157">"kosongkan data diagnostik"</string>
@@ -84,8 +78,6 @@
<string name="car_permission_desc_vms_publisher" msgid="5589489298597386828">"Terbitkan mesej VMS"</string>
<string name="car_permission_label_vms_subscriber" msgid="5648841182059222299">"Pelanggan VMS"</string>
<string name="car_permission_desc_vms_subscriber" msgid="7551009457847673620">"Langgan mesej VMS"</string>
- <string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"Perkhidmatan Pelanggan VMS"</string>
- <string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"Terikat pada pelanggan VMS"</string>
<string name="car_permission_label_storage_monitoring" msgid="2327639346522530549">"Pemantauan storan pemacu kilat"</string>
<string name="car_permission_desc_storage_monitoring" msgid="2075712271139671318">"Pantau penggunaan storan pemacu kilat"</string>
<string name="car_permission_label_driving_state" msgid="7754624599537393650">"dengar keadaan pemanduan"</string>
diff --git a/service/res/values-my/strings.xml b/service/res/values-my/strings.xml
index d285213..478227a 100644
--- a/service/res/values-my/strings.xml
+++ b/service/res/values-my/strings.xml
@@ -17,7 +17,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="2215078736675564541">"ကားအချက်အလက်"</string>
- <string name="car_permission_desc" msgid="3584369074931334964">"သင့်ကား၏ အချက်အလက်များကို အသုံးပြုနိုင်သည်"</string>
+ <string name="car_permission_desc" msgid="3584369074931334964">"သင့်ကား၏ အချက်အလက်များကို အသုံးပြုပါမည်"</string>
<string name="car_permission_label_camera" msgid="3725702064841827180">"ကား၏ ကင်မရာကို အသုံးပြုပါမည်"</string>
<string name="car_permission_desc_camera" msgid="917024932164501426">"သင့်ကား၏ ကင်မရာ(များ)ကို ဝင်ရောက်အသုံးပြုပါမည်။"</string>
<string name="car_permission_label_energy" msgid="7409144323527821558">"ကား၏ စွမ်းအင်အချက်အလက်များကို ရယူပါမည်"</string>
@@ -42,8 +42,6 @@
<string name="car_permission_desc_projection" msgid="2352178999656292944">"အက်ပ်တစ်ခုက ဖုန်း၏အင်တာဖေ့စ်အား ကား၏ မျက်နှာပြင်ပြသမှုပေါ်တွင် ပုံရိပ်ပြသရန် ခွင့်ပြုသည်။"</string>
<string name="car_permission_label_access_projection_status" msgid="4231618890836627402">"ခန့်မှန်းမှုအခြေအနေကို ရယူပါမည်"</string>
<string name="car_permission_desc_access_projection_status" msgid="8497351979100616278">"အက်ပ်တစ်ခုက ကား၏ မျက်နှာပြင်ပြသမှုပေါ်တွင် အခြားအက်ပ်များ၏ အခြေအနေကို ပုံရိပ်ပြသရန် ခွင့်ပြုသည်။"</string>
- <string name="car_permission_label_bind_projection_service" msgid="5362076216606651526">"ခန့်မှန်းခြင်းဆိုင်ရာ ဝန်ဆောင်မှုနှင့် ပူးပေါင်းပါမည်"</string>
- <string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"ဖုန်းကိုင်ထားသူနှင့် ပုံရိပ်ပြသသော ဝန်ဆောင်မှု၏ ထိပ်ပိုင်းအင်တာဖေ့စ် ကို ပူးပေါင်းခွင့်ပေးသည်။ ပုံမှန် အက်ပ်များအတွက် မည်သည့်အခါမျှ မလိုအပ်ပါ။"</string>
<string name="car_permission_label_audio_volume" msgid="310587969373137690">"ကား၏ အသံအတိုးအကျယ်ကို ထိန်းချုပ်ပါမည်"</string>
<string name="car_permission_label_audio_settings" msgid="6524703796944023977">"ကား၏ အသံဆက်တင်များကို စီမံပါမည်"</string>
<string name="car_permission_label_mock_vehicle_hal" msgid="7198852512207405935">"ယာဉ်၏ \"HAL အလွှာ\" ကို အသွင်ယူလုပ်ဆောင်ရန်"</string>
@@ -62,8 +60,6 @@
<string name="car_permission_desc_car_cluster_control" msgid="9222776665281176031">"ကိရိယာအစုအဝေးအတွင်းရှိ အက်ပ်များကို စတင်ရန်"</string>
<string name="car_permission_car_monitor_cluster_navigation_state" msgid="7025307242306902441">"ကိရိယာအစုအဝေး လမ်းညွှန်အခြေအနေ"</string>
<string name="car_permission_desc_car_monitor_cluster_navigation_state" msgid="8745047153878713339">"ကိရိယာအစုအဝေး လမ်းညွှန်အခြေအနေ ပြောင်းလဲမှုများကို နားစွင့်ပါ"</string>
- <string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"ကိရိယာအစုအဝေးကို ပြင်ဆင်ခြင်း"</string>
- <string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"ကိရိယာအစုအဝေး ဒေတာကို လက်ခံရန်"</string>
<string name="car_permission_label_car_ux_restrictions_configuration" msgid="6801393970411049725">"UX ကန့်သတ်ချက်များ စီစဉ်သတ်မှတ်မှု"</string>
<string name="car_permission_desc_car_ux_restrictions_configuration" msgid="5711926927484813777">"UX ကန့်သတ်ချက်များကို စီစဉ်သတ်မှတ်ရန်"</string>
<string name="car_permission_label_access_private_display_id" msgid="6712116114341634316">"သီးသန့်ဖန်သားပြင်ပြသမှု id ကို ဖတ်ခွင့်"</string>
@@ -74,8 +70,6 @@
<string name="car_permission_desc_read_car_occupant_awareness_state" msgid="188865882598414986">"\'စီးနင်းသူ သတိရှိမှု စနစ်\' အတွက် အခြေအနေဖတ်ခြင်းနှင့် ဒေတာရှာဖွေခြင်းတို့ကို ခွင့်ပြုသည်"</string>
<string name="car_permission_label_control_car_occupant_awareness_system" msgid="7163330266691094542">"\'စီးနင်းသူ သတိရှိမှု စနစ် ဂရပ်ဖ်\' ကို ထိန်းချုပ်ရန်"</string>
<string name="car_permission_desc_control_car_occupant_awareness_system" msgid="7123482622084531911">"\'စီးနင်းသူ သတိရှိမှု စနစ်\' သိရှိသည့်ဂရပ်ဖ် စတင်ခြင်းနှင့် ရပ်တန့်ခြင်းကို ထိန်းချုပ်ရန် ခွင့်ပြုသည်"</string>
- <string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"ကား၏ အချက်အလက်ထည့်သွင်းခြင်း ဝန်ဆောင်မှု"</string>
- <string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"အချက်အလက်ထည့်သွင်းခြင်း အစီအစဉ်များကို စီမံပါမည်"</string>
<string name="car_permission_label_diag_read" msgid="7248894224877702604">"အမှားရှာပြင်ခြင်းဒေတာများကို ကြည့်ပါမည်"</string>
<string name="car_permission_desc_diag_read" msgid="1121426363040966178">"ကားအတွင်း အမှားရှာပြင်ခြင်းဒေတာကို ကြည့်ပါမည်။"</string>
<string name="car_permission_label_diag_clear" msgid="4783070510879698157">"အမှားရှာပြင်ခြင်းဒေတာများကို ရှင်းလင်းပါမည်"</string>
@@ -84,8 +78,6 @@
<string name="car_permission_desc_vms_publisher" msgid="5589489298597386828">"VMS မက်ဆေ့ဂျ်များကို ထုတ်ဝေခြင်း"</string>
<string name="car_permission_label_vms_subscriber" msgid="5648841182059222299">"VMS စာရင်းသွင်းသူ"</string>
<string name="car_permission_desc_vms_subscriber" msgid="7551009457847673620">"VMS မက်ဆေ့ဂျ်များ ရယူရန်အတွက် စာရင်းသွင်းရန်"</string>
- <string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"VMS ကလိုင်းယင့် ဝန်ဆောင်မှု"</string>
- <string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"VMS ကလိုင်းယင့်များနှင့် ပူးပေါင်းခြင်း"</string>
<string name="car_permission_label_storage_monitoring" msgid="2327639346522530549">"မြန်နှုန်းမြင့် သိုလှောင်မှုအား စောင့်ကြည့်ခြင်း"</string>
<string name="car_permission_desc_storage_monitoring" msgid="2075712271139671318">"မြန်နှုန်းမြင့်သိုလှောင်မှုအား အသုံးပြုခြင်းကို စောင့်ကြည့်ပါမည်"</string>
<string name="car_permission_label_driving_state" msgid="7754624599537393650">"ယာဉ်မောင်းနှင်မှုအခြေအနေကို စောင့်ကြည့်ပါမည်"</string>
@@ -150,8 +142,8 @@
<string name="car_permission_desc_car_powertrain" msgid="1116007372551797796">"အင်ဂျင်အားဖြင့် ကားဝင်ရိုးလည်ပတ်မှုအချက်အလက်များကို ရယူပါမည်"</string>
<string name="car_permission_label_car_power" msgid="8111448088314368268">"ကား၏ ပါဝါအခြေအနေကို ကြည့်ပါမည်"</string>
<string name="car_permission_desc_car_power" msgid="9202079903668652864">"ကား၏ ပါဝါအခြေအနေကို ရယူပါမည်။"</string>
- <string name="car_permission_label_enroll_trust" msgid="3512907900486690218">"စိတ်ချရသည့်စက်ပစ္စည်းကို စာရင်းသွင်းရန်"</string>
- <string name="car_permission_desc_enroll_trust" msgid="4148649994602185130">"စိတ်ချရသည့်စက်ပစ္စည်း စာရင်းသွင်းခြင်းကို ခွင့်ပြုရန်"</string>
+ <string name="car_permission_label_enroll_trust" msgid="3512907900486690218">"ယုံကြည်ရသည့် ကိရိယာကို စာရင်းသွင်းရန်"</string>
+ <string name="car_permission_desc_enroll_trust" msgid="4148649994602185130">"ယုံကြည်ရသည့် ကိရိယာအား စာရင်းသွင်းခြင်းကို ခွင့်ပြုရန်"</string>
<string name="car_permission_label_car_test_service" msgid="9159328930558208708">"ကား၏ စမ်းသပ်မုဒ်ကို ထိန်းချုပ်ရန်"</string>
<string name="car_permission_desc_car_test_service" msgid="7426844534110145843">"ကား၏ စမ်းသပ်မုဒ်ကို ထိန်းချုပ်ရန်"</string>
<string name="car_permission_label_control_car_features" msgid="3905791560378888286">"ကား၏ ဝန်ဆောင်မှုများကို ပိတ်ရန် သို့မဟုတ် ပိတ်ရန်"</string>
diff --git a/service/res/values-nb/strings.xml b/service/res/values-nb/strings.xml
index d8f00b7..c7057c3 100644
--- a/service/res/values-nb/strings.xml
+++ b/service/res/values-nb/strings.xml
@@ -42,8 +42,6 @@
<string name="car_permission_desc_projection" msgid="2352178999656292944">"Tillater at en app projiserer et grensesnitt fra en telefon til bilskjermen."</string>
<string name="car_permission_label_access_projection_status" msgid="4231618890836627402">"se projiseringsstatusen"</string>
<string name="car_permission_desc_access_projection_status" msgid="8497351979100616278">"Tillater at en app får statusen til andre apper som projiserer på bilskjermen."</string>
- <string name="car_permission_label_bind_projection_service" msgid="5362076216606651526">"binde til en projeksjonstjeneste"</string>
- <string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"Lar dokken binde seg til det øverste nivået av grensesnittet for en projiseringstjeneste. Skal aldri være nødvendig for vanlige apper."</string>
<string name="car_permission_label_audio_volume" msgid="310587969373137690">"kontrollére lydvolumet i bilen"</string>
<string name="car_permission_label_audio_settings" msgid="6524703796944023977">"administrere bilens lydinnstillinger"</string>
<string name="car_permission_label_mock_vehicle_hal" msgid="7198852512207405935">"emulere kjøretøys-HAL"</string>
@@ -62,8 +60,6 @@
<string name="car_permission_desc_car_cluster_control" msgid="9222776665281176031">"Åpning av apper på instrumentpanelet"</string>
<string name="car_permission_car_monitor_cluster_navigation_state" msgid="7025307242306902441">"Navigasjonstilstand for instrumentgruppen"</string>
<string name="car_permission_desc_car_monitor_cluster_navigation_state" msgid="8745047153878713339">"lytte etter endringer i navigasjonstilstanden for instrumentgruppen"</string>
- <string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"Gjengivelse på instrumentpanelet"</string>
- <string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"Mottak av data fra instrumentpanelet"</string>
<string name="car_permission_label_car_ux_restrictions_configuration" msgid="6801393970411049725">"Konfigurering av begrensninger tilknyttet brukeropplevelsen"</string>
<string name="car_permission_desc_car_ux_restrictions_configuration" msgid="5711926927484813777">"Konfigurering av begrensninger tilknyttet brukeropplevelsen"</string>
<string name="car_permission_label_access_private_display_id" msgid="6712116114341634316">"Lesetilgang til privat skjerm-ID"</string>
@@ -74,8 +70,6 @@
<string name="car_permission_desc_read_car_occupant_awareness_state" msgid="188865882598414986">"Lar deg lese av status og registreringsdata for Occupant Awareness System"</string>
<string name="car_permission_label_control_car_occupant_awareness_system" msgid="7163330266691094542">"Kontrollér diagrammet for Occupant Awareness System"</string>
<string name="car_permission_desc_control_car_occupant_awareness_system" msgid="7123482622084531911">"Lar deg kontrollere start og stopp av registreringsdiagrammet for Occupant Awareness System"</string>
- <string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Bilens inndatatjeneste"</string>
- <string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Behandling av inndatahendelser"</string>
<string name="car_permission_label_diag_read" msgid="7248894224877702604">"lese diagnostikkdata"</string>
<string name="car_permission_desc_diag_read" msgid="1121426363040966178">"Les diagnostikkdata fra bilen."</string>
<string name="car_permission_label_diag_clear" msgid="4783070510879698157">"slette diagnostikkdata"</string>
@@ -84,8 +78,6 @@
<string name="car_permission_desc_vms_publisher" msgid="5589489298597386828">"Publiser VMS-meldinger"</string>
<string name="car_permission_label_vms_subscriber" msgid="5648841182059222299">"VMS-abonnent"</string>
<string name="car_permission_desc_vms_subscriber" msgid="7551009457847673620">"Abonner på VMS-meldinger"</string>
- <string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"VMS-klienttjeneste"</string>
- <string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"Bind til VMS-klienter"</string>
<string name="car_permission_label_storage_monitoring" msgid="2327639346522530549">"Overvåking av flash-lagring"</string>
<string name="car_permission_desc_storage_monitoring" msgid="2075712271139671318">"Overvåking av bruk av flash-lagring"</string>
<string name="car_permission_label_driving_state" msgid="7754624599537393650">"lytte etter kjøretilstand"</string>
diff --git a/service/res/values-ne/strings.xml b/service/res/values-ne/strings.xml
index 4ecc60c..9746593 100644
--- a/service/res/values-ne/strings.xml
+++ b/service/res/values-ne/strings.xml
@@ -42,8 +42,6 @@
<string name="car_permission_desc_projection" msgid="2352178999656292944">"एपलाई कुनै फोनको इन्टरफेस कारको डिस्प्लेमा प्रोजेक्ट गर्न दिन्छ।"</string>
<string name="car_permission_label_access_projection_status" msgid="4231618890836627402">"प्रोजेक्सनको स्थितिमाथि पहुँच राख्ने"</string>
<string name="car_permission_desc_access_projection_status" msgid="8497351979100616278">"एपलाई कारको डिस्प्लेमा प्रोजेक्ट गरिरहेका अन्य अनुप्रयोगहरूको स्थिति प्राप्त गर्ने अनुमति दिन्छ।"</string>
- <string name="car_permission_label_bind_projection_service" msgid="5362076216606651526">"प्रोजेक्सन सेवामा सम्बद्ध हुने"</string>
- <string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"धारकलाई प्रोजेक्सन सेवाको उच्च स्तरको इन्टरफेसमा सम्बद्ध हुने अनुमति दिन्छ। साधारण अनुप्रयोगहरूको लागि कहिल्यै पनि आवश्यक पर्दैन।"</string>
<string name="car_permission_label_audio_volume" msgid="310587969373137690">"कारको अडियोको भोल्युम नियन्त्रण गर्ने"</string>
<string name="car_permission_label_audio_settings" msgid="6524703796944023977">"कारका अडियो सेटिङ व्यवस्थित गर्ने"</string>
<string name="car_permission_label_mock_vehicle_hal" msgid="7198852512207405935">"सवारी साधनको HAL को अनुकरण गर्ने"</string>
@@ -62,8 +60,6 @@
<string name="car_permission_desc_car_cluster_control" msgid="9222776665281176031">"उपकरणको क्लस्टरमा एपहरू सुरु गर्नुहोस्"</string>
<string name="car_permission_car_monitor_cluster_navigation_state" msgid="7025307242306902441">"इन्स्ट्रुमेन्ट क्लस्टरको नेभिगेसनको स्थिति"</string>
<string name="car_permission_desc_car_monitor_cluster_navigation_state" msgid="8745047153878713339">"इन्स्ट्रुमेन्ट क्लस्टरको नेभिगेसनको स्थितिमा आउने परिवर्तनको निगरानी गरियोस्"</string>
- <string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"उपकरणको क्लस्टर रेन्डर गर्ने प्रक्रिया"</string>
- <string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"उपकरणको क्लस्टरको डेटा प्राप्त गर्नुहोस्"</string>
<string name="car_permission_label_car_ux_restrictions_configuration" msgid="6801393970411049725">"UX सम्बन्धी प्रतिबन्धहरूको कन्फिगुरेसन"</string>
<string name="car_permission_desc_car_ux_restrictions_configuration" msgid="5711926927484813777">"UX सम्बन्धी प्रतिबन्धहरू कन्फिगर गर्नुहोस्"</string>
<string name="car_permission_label_access_private_display_id" msgid="6712116114341634316">"निजी डिस्प्ले ID रिड गर्ने अनुमति"</string>
@@ -74,8 +70,6 @@
<string name="car_permission_desc_read_car_occupant_awareness_state" msgid="188865882598414986">"Occupant Awareness System को स्थिति र पत्ता लगाउनेसम्बन्धी डेटा रिड गर्न दिन्छ"</string>
<string name="car_permission_label_control_car_occupant_awareness_system" msgid="7163330266691094542">"Occupant Awareness System सम्बन्धी ग्राफको नियन्त्रण गर्नुहोस्"</string>
<string name="car_permission_desc_control_car_occupant_awareness_system" msgid="7123482622084531911">"Occupant Awareness System पत्ता लगाउनेसम्बन्धी ग्राफको सुरु र समाप्त हुने कार्य नियन्त्रण गर्ने अनुमति दिनुहोस्"</string>
- <string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"कारको इनपुट सेवा"</string>
- <string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"इनपुट गरिएका कार्यक्रमहरू व्यवस्थापन गर्ने"</string>
<string name="car_permission_label_diag_read" msgid="7248894224877702604">"निदानसम्बन्धी डेटा पढ्ने"</string>
<string name="car_permission_desc_diag_read" msgid="1121426363040966178">"कारको निदानसम्बन्धी डेटा पढ्ने।"</string>
<string name="car_permission_label_diag_clear" msgid="4783070510879698157">"निदानसम्बन्धी डेटा हटाउने"</string>
@@ -84,8 +78,6 @@
<string name="car_permission_desc_vms_publisher" msgid="5589489298597386828">"VMS सन्देशहरू प्रकाशित गर्ने"</string>
<string name="car_permission_label_vms_subscriber" msgid="5648841182059222299">"VMS को सदस्य"</string>
<string name="car_permission_desc_vms_subscriber" msgid="7551009457847673620">"VMS का सन्देशहरूको सदस्यता लिनुहोस्"</string>
- <string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"VMS क्लाइन्ट सेवा"</string>
- <string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"VMS क्लाइन्टहरूमा सम्बद्ध हुनुहोस्"</string>
<string name="car_permission_label_storage_monitoring" msgid="2327639346522530549">"फ्ल्यास भण्डारणको अनुगमन"</string>
<string name="car_permission_desc_storage_monitoring" msgid="2075712271139671318">"फ्ल्यास भण्डारणको प्रयोगको अनुगमन गर्ने"</string>
<string name="car_permission_label_driving_state" msgid="7754624599537393650">"ड्राइभिङको स्थिति सुन्ने"</string>
diff --git a/service/res/values-nl/strings.xml b/service/res/values-nl/strings.xml
index b050b43..995ba18 100644
--- a/service/res/values-nl/strings.xml
+++ b/service/res/values-nl/strings.xml
@@ -42,8 +42,6 @@
<string name="car_permission_desc_projection" msgid="2352178999656292944">"Hiermee kan een app een interface van een telefoon projecteren op het display van de auto."</string>
<string name="car_permission_label_access_projection_status" msgid="4231618890836627402">"toegang tot projectiestatus"</string>
<string name="car_permission_desc_access_projection_status" msgid="8497351979100616278">"Hiermee kan een app de status ophalen van andere apps die worden geprojecteerd op het display van de auto."</string>
- <string name="car_permission_label_bind_projection_service" msgid="5362076216606651526">"verbinding maken met een projectieservice"</string>
- <string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"Hiermee kan de houder verbinding maken met de hoofdinterface van een projectieservice. Nooit vereist voor normale apps."</string>
<string name="car_permission_label_audio_volume" msgid="310587969373137690">"audiovolume van auto bedienen"</string>
<string name="car_permission_label_audio_settings" msgid="6524703796944023977">"audio-instellingen van auto beheren"</string>
<string name="car_permission_label_mock_vehicle_hal" msgid="7198852512207405935">"voertuig-HAL emuleren"</string>
@@ -62,8 +60,6 @@
<string name="car_permission_desc_car_cluster_control" msgid="9222776665281176031">"Apps openen in de instrumentcluster"</string>
<string name="car_permission_car_monitor_cluster_navigation_state" msgid="7025307242306902441">"Navigatiestatus instrumentcluster"</string>
<string name="car_permission_desc_car_monitor_cluster_navigation_state" msgid="8745047153878713339">"Luisteren naar wijzigingen in de navigatiestatus van het instrumentcluster"</string>
- <string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"Weergave instrumentcluster"</string>
- <string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"Gegevens van instrumentcluster ontvangen"</string>
<string name="car_permission_label_car_ux_restrictions_configuration" msgid="6801393970411049725">"Configuratie van beperkingen voor gebruikerservaring"</string>
<string name="car_permission_desc_car_ux_restrictions_configuration" msgid="5711926927484813777">"Beperkingen voor gebruikerservaring configureren"</string>
<string name="car_permission_label_access_private_display_id" msgid="6712116114341634316">"Leestoegang tot privé-display-ID"</string>
@@ -74,8 +70,6 @@
<string name="car_permission_desc_read_car_occupant_awareness_state" msgid="188865882598414986">"Hiermee kunnen status- en detectiegegevens van het Occupant Awareness System worden gelezen"</string>
<string name="car_permission_label_control_car_occupant_awareness_system" msgid="7163330266691094542">"Occupant Awareness System-diagram bedienen"</string>
<string name="car_permission_desc_control_car_occupant_awareness_system" msgid="7123482622084531911">"Hiermee kan het starten en stoppen van het Occupant Awareness System-detectiediagram worden bediend"</string>
- <string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Invoerservice van auto"</string>
- <string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Invoergebeurtenissen verwerken"</string>
<string name="car_permission_label_diag_read" msgid="7248894224877702604">"diagnostische gegevens lezen"</string>
<string name="car_permission_desc_diag_read" msgid="1121426363040966178">"Diagnostische gegevens van auto lezen."</string>
<string name="car_permission_label_diag_clear" msgid="4783070510879698157">"diagnostische gegevens wissen"</string>
@@ -84,8 +78,6 @@
<string name="car_permission_desc_vms_publisher" msgid="5589489298597386828">"VMS-berichten publiceren"</string>
<string name="car_permission_label_vms_subscriber" msgid="5648841182059222299">"VMS-abonnee"</string>
<string name="car_permission_desc_vms_subscriber" msgid="7551009457847673620">"Abonneren op VMS-berichten"</string>
- <string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"VMS-clientservice"</string>
- <string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"Verbinding maken met VMS-clients"</string>
<string name="car_permission_label_storage_monitoring" msgid="2327639346522530549">"Flash-geheugen controleren"</string>
<string name="car_permission_desc_storage_monitoring" msgid="2075712271139671318">"Gebruik van Flash-geheugen controleren"</string>
<string name="car_permission_label_driving_state" msgid="7754624599537393650">"luisteren naar rijstand"</string>
diff --git a/service/res/values-or/strings.xml b/service/res/values-or/strings.xml
index 170b8eb..69d50e2 100644
--- a/service/res/values-or/strings.xml
+++ b/service/res/values-or/strings.xml
@@ -17,7 +17,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="2215078736675564541">"କାର୍ର ସୂଚନା"</string>
- <string name="car_permission_desc" msgid="3584369074931334964">"ଆପଣଙ୍କ କାରର ସୂଚନା ଆକ୍ସେସ କରନ୍ତୁ"</string>
+ <string name="car_permission_desc" msgid="3584369074931334964">"ଆପଣଙ୍କ କାରର ସୂଚନା ଆକ୍ସେସ୍ କରନ୍ତୁ"</string>
<string name="car_permission_label_camera" msgid="3725702064841827180">"କାର୍\'ର କ୍ୟାମେରାକୁ ଆକ୍ସେସ୍ କରନ୍ତୁ"</string>
<string name="car_permission_desc_camera" msgid="917024932164501426">"ଆପଣଙ୍କ କାର୍ର କ୍ୟାମେରା(ଗୁଡ଼ିକ) ଆକ୍ସେସ୍ କରିପାରେ।"</string>
<string name="car_permission_label_energy" msgid="7409144323527821558">"କାର୍\'ର ଏନାର୍ଜି ସୂଚନାକୁ ଆକ୍ସେସ୍ କରନ୍ତୁ"</string>
@@ -42,8 +42,6 @@
<string name="car_permission_desc_projection" msgid="2352178999656292944">"ଏକ ଫୋନ୍ରୁ କୌଣସି ଆପ୍କୁ କାର୍ ଡିସ୍ପ୍ଲେରେ ଏକ ଇର୍ଣ୍ଟଫେସ୍କୁ ପ୍ରୋଜେକ୍ଟ କରିବାକୁ ଅନୁମତି ଦିଏ।"</string>
<string name="car_permission_label_access_projection_status" msgid="4231618890836627402">"ପ୍ରୋଜେକ୍ସନ୍ ସ୍ଥିତି ଆକ୍ସେସ୍ କରନ୍ତୁ"</string>
<string name="car_permission_desc_access_projection_status" msgid="8497351979100616278">"କାର୍ର ଡିସ୍ପ୍ଲେରେ କୌଣସି ଆପ୍କୁ ଆନ୍ୟ ଆପ୍ ଦେଉଥିବା ସ୍ଥିତିକୁ ପ୍ରାପ୍ତ କରିବାକୁ ଅନୁମତି ଦିଏ।"</string>
- <string name="car_permission_label_bind_projection_service" msgid="5362076216606651526">"ଏକ ପ୍ରୋଜେକ୍ସନ୍ ସେବା ସହ ଯୋଡ଼ି ହୁଅନ୍ତୁ"</string>
- <string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"ଏକ ପ୍ରୋଜେକ୍ସନ୍ ସେବାର ଶୀର୍ଷ-ସ୍ତର ଇଣ୍ଟର୍ଫେସ୍କୁ ବାନ୍ଧିରଖିବା ପାଇଁ ଧାରକକୁ ଅନୁମତି ଦିଏ। ସାମାନ୍ୟ ଆପ୍ଗୁଡ଼ିକ ପାଇଁ ଏହା ଆବଶ୍ୟକ ନୁହେଁ।"</string>
<string name="car_permission_label_audio_volume" msgid="310587969373137690">"କାର୍\'ର ଅଡିଓ ଭଲ୍ୟୁମ୍କୁ ନିୟନ୍ତ୍ରଣ କରନ୍ତୁ"</string>
<string name="car_permission_label_audio_settings" msgid="6524703796944023977">"କାର୍\'ର ଅଡିଓ ସେଟିଂସ୍କୁ ପରିଚାଳନା କରନ୍ତୁ"</string>
<string name="car_permission_label_mock_vehicle_hal" msgid="7198852512207405935">"ଗାଡ଼ି HALକୁ ଅନୁକରଣ କରନ୍ତୁ"</string>
@@ -62,8 +60,6 @@
<string name="car_permission_desc_car_cluster_control" msgid="9222776665281176031">"ଇନ୍ଷ୍ଟ୍ରୁମେଣ୍ଟ କ୍ଲଷ୍ଟର୍ରେ ଆପ୍ସ ଲଞ୍ଚ କରନ୍ତୁ"</string>
<string name="car_permission_car_monitor_cluster_navigation_state" msgid="7025307242306902441">"ଇନଷ୍ଟ୍ରୁମେଣ୍ଟ କ୍ଲଷ୍ଟର ନାଭିଗେସନ ସ୍ଥିତି"</string>
<string name="car_permission_desc_car_monitor_cluster_navigation_state" msgid="8745047153878713339">"ଇନଷ୍ଟ୍ରୁମେଣ୍ଟ କ୍ଲଷ୍ଟର ନାଭିଗେସନ ସ୍ଥିତି ସମ୍ବନ୍ଧିତ ପରିବର୍ତ୍ତନଗୁଡ଼ିକ ବିଷୟରେ ଜାଣିବା ପାଇଁ ଶୁଣନ୍ତୁ"</string>
- <string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"ଇନ୍ଷ୍ଟ୍ରୁମେଣ୍ଟ କ୍ଲଷ୍ଟର୍ ରେଣ୍ଡରିଂ"</string>
- <string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"ଇନ୍ଷ୍ଟ୍ରୁମେଣ୍ଟ କ୍ଲଷ୍ଟର୍ର ଡାଟା ପ୍ରାପ୍ତ କରନ୍ତୁ"</string>
<string name="car_permission_label_car_ux_restrictions_configuration" msgid="6801393970411049725">"UX ପ୍ରତିବନ୍ଧତା କନଫିଗ୍ରେଶନ୍"</string>
<string name="car_permission_desc_car_ux_restrictions_configuration" msgid="5711926927484813777">"UX ପ୍ରତିବନ୍ଧତା କନ୍ଫିଗର୍ କରନ୍ତୁ"</string>
<string name="car_permission_label_access_private_display_id" msgid="6712116114341634316">"ବ୍ୟକ୍ତିଗତ ଡିସପ୍ଲେ idକୁ ପଢ଼ିବାର ଆକ୍ସେସ୍"</string>
@@ -74,8 +70,6 @@
<string name="car_permission_desc_read_car_occupant_awareness_state" msgid="188865882598414986">"ଏହା ଅକ୍ୟୁପେଣ୍ଟ ଆୱାରନେସ୍ ସିଷ୍ଟମ୍ ପାଇଁ ସ୍ଥିତି ଏବଂ ଚିହ୍ନଟକରଣ ଡାଟା ପଢ଼ିବାକୁ ଅନୁମତି ଦେଇଥାଏ"</string>
<string name="car_permission_label_control_car_occupant_awareness_system" msgid="7163330266691094542">"ଅକ୍ୟୁପେଣ୍ଟ ଆୱାରନେସ୍ ସିଷ୍ଟମ୍ ଗ୍ରାଫ୍ ନିୟନ୍ତ୍ରଣ କରନ୍ତୁ"</string>
<string name="car_permission_desc_control_car_occupant_awareness_system" msgid="7123482622084531911">"ଏହା ଅକ୍ୟୁପେଣ୍ଟ ଆୱାରନେସ୍ ସିଷ୍ଟମ୍ ଡିଟେକ୍ସନ୍ ଗ୍ରାଫକୁ ଚାଲୁ ଏବଂ ବନ୍ଦ କରିବା ନିୟନ୍ତ୍ରଣ ପାଇଁ ଅନୁମତି ଦେଇଥାଏ"</string>
- <string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"କାର୍ର ଇନ୍ପୁଟ୍ ସେବା"</string>
- <string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"ଇନ୍ପୁଟ୍ ଇଭେଣ୍ଟଗୁଡ଼ିକ ପରିଚାଳନା କରିପାରେ"</string>
<string name="car_permission_label_diag_read" msgid="7248894224877702604">"ଡାଏଗ୍ନୋଷ୍ଟିକ୍ ଡାଟାକୁ ପଢ଼ିବ"</string>
<string name="car_permission_desc_diag_read" msgid="1121426363040966178">"କାର୍ ମଧ୍ୟରୁ ଡାଏଗ୍ନୋଷ୍ଟିକ୍ ଡାଟାକୁ ପଢ଼ିବ।"</string>
<string name="car_permission_label_diag_clear" msgid="4783070510879698157">"ଡାଏଗ୍ନୋଷ୍ଟିକ୍ ଡାଟା ଖାଲି କରନ୍ତୁ"</string>
@@ -84,8 +78,6 @@
<string name="car_permission_desc_vms_publisher" msgid="5589489298597386828">"VMS ମେସେଜ୍ଗୁଡ଼ିକୁ ପଠାଇପାରେ"</string>
<string name="car_permission_label_vms_subscriber" msgid="5648841182059222299">"VMS ସଦସ୍ୟ"</string>
<string name="car_permission_desc_vms_subscriber" msgid="7551009457847673620">"VMS ମେସେଜ୍ର ସଦସ୍ୟତା ନିଅନ୍ତୁ"</string>
- <string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"VMS ଗ୍ରାହକ ସେବା"</string>
- <string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"VMS ଗ୍ରାହକମାନଙ୍କ ସହ ଯୋଡ଼ି ହୁଅନ୍ତୁ"</string>
<string name="car_permission_label_storage_monitoring" msgid="2327639346522530549">"ଫ୍ଲାସ୍ ଷ୍ଟୋରେଜ୍କୁ ନିରୀକ୍ଷଣ କରିପାରେ"</string>
<string name="car_permission_desc_storage_monitoring" msgid="2075712271139671318">"ଫ୍ଲାସ୍ ଷ୍ଟୋରେଜ୍ର ବ୍ୟବହାରକୁ ନିରୀକ୍ଷଣ କରିପାରେ"</string>
<string name="car_permission_label_driving_state" msgid="7754624599537393650">"ଡ୍ରାଇଭିଂ ଷ୍ଟେଟ୍କୁ ଶୁଣନ୍ତୁ"</string>
diff --git a/service/res/values-pa/strings.xml b/service/res/values-pa/strings.xml
index f2e1c4b..6c45f8d 100644
--- a/service/res/values-pa/strings.xml
+++ b/service/res/values-pa/strings.xml
@@ -42,8 +42,6 @@
<string name="car_permission_desc_projection" msgid="2352178999656292944">"ਕਿਸੇ ਐਪ ਨੂੰ ਕਾਰ ਦੀ ਡਿਸਪਲੇ \'ਤੇ ਫ਼ੋਨ ਦਾ ਇੰਟਰਫੇਸ ਦਿਖਾਉਣ ਦਿੰਦੀ ਹੈ।"</string>
<string name="car_permission_label_access_projection_status" msgid="4231618890836627402">"ਯੋਜਨਾਬੰਦੀ ਸਥਿਤੀ ਤੱਕ ਪਹੁੰਚ"</string>
<string name="car_permission_desc_access_projection_status" msgid="8497351979100616278">"ਕਿਸੇ ਐਪ ਨੂੰ ਕਾਰ ਦੀ ਡਿਸਪਲੇ \'ਤੇ ਹੋਰ ਐਪਾਂ ਦੀ ਸਥਿਤੀ ਦੇਖਣ ਦਿਓ।"</string>
- <string name="car_permission_label_bind_projection_service" msgid="5362076216606651526">"ਯੋਜਨਾਬੰਦੀ ਸੇਵਾ ਨਾਲ ਜੋੜੋ"</string>
- <string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"ਹੋਲਡਰ ਨੂੰ ਯੋਜਨਾਬੰਦੀ ਸੇਵਾ ਦੇ ਉੱਚ-ਪੱਧਰ ਦੇ ਇੰਟਰਫੇਸ ਨਾਲ ਜੋੜਨ ਦਿੰਦਾ ਹੈ। ਇਹ ਆਮ ਐਪਾਂ ਲਈ ਕਦੇ ਵੀ ਲੋੜੀਂਦਾ ਨਹੀਂ ਹੋਣਾ ਚਾਹੀਦਾ।"</string>
<string name="car_permission_label_audio_volume" msgid="310587969373137690">"ਕਾਰ ਦੀ ਆਡੀਓ ਅਵਾਜ਼ \'ਤੇ ਕੰਟਰੋਲ"</string>
<string name="car_permission_label_audio_settings" msgid="6524703796944023977">"ਕਾਰ ਦੀਆਂ ਆਡੀਓ ਸੈਟਿੰਗਾਂ ਦਾ ਪ੍ਰਬੰਧਨ"</string>
<string name="car_permission_label_mock_vehicle_hal" msgid="7198852512207405935">"ਵਾਹਨ HAL ਦੀ ਨਕਲ ਕਰੋ"</string>
@@ -62,8 +60,6 @@
<string name="car_permission_desc_car_cluster_control" msgid="9222776665281176031">"ਇੰਸਟਰੂਮੈਂਟ ਕਲੱਸਟਰ ਵਿੱਚ ਐਪਾਂ ਲਾਂਚ ਕਰੋ"</string>
<string name="car_permission_car_monitor_cluster_navigation_state" msgid="7025307242306902441">"ਸਾਧਨ ਕਲੱਸਟਰ ਦੇ ਨੈਵੀਗੇਸ਼ਨ ਦੀ ਸਥਿਤੀ"</string>
<string name="car_permission_desc_car_monitor_cluster_navigation_state" msgid="8745047153878713339">"ਸਾਧਨ ਕਲੱਸਟਰ ਦੇ ਨੈਵੀਗੇਸ਼ਨ ਦੀ ਸਥਿਤੀ ਵਿਚਲੀਆਂ ਤਬਦੀਲੀਆਂ ਸੁਣੋ"</string>
- <string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"ਇੰਸਟਰੂਮੈਂਟ ਕਲੱਸਟਰ ਰੈਂਡਰਿੰਗ"</string>
- <string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"ਇੰਸਟਰੂਮੈਂਟ ਕਲੱਸਟਰ ਡਾਟਾ ਪ੍ਰਾਪਤ ਕਰੋ"</string>
<string name="car_permission_label_car_ux_restrictions_configuration" msgid="6801393970411049725">"UX ਪਾਬੰਦੀਆਂ ਦਾ ਸੰਰੂਪਣ"</string>
<string name="car_permission_desc_car_ux_restrictions_configuration" msgid="5711926927484813777">"UX ਪਾਬੰਦੀਆਂ ਦਾ ਸੰਰੂਪਣ ਕਰੋ"</string>
<string name="car_permission_label_access_private_display_id" msgid="6712116114341634316">"ਨਿੱਜੀ ਡਿਸਪਲੇ ਆਈਡੀ ਨੂੰ ਪੜ੍ਹਨ ਦੀ ਪਹੁੰਚ"</string>
@@ -74,18 +70,14 @@
<string name="car_permission_desc_read_car_occupant_awareness_state" msgid="188865882598414986">"ਕਾਰ ਚਲਾਉਣ ਵਾਲੇ ਲਈ ਜਾਗਰੂਕਤਾ ਸਿਸਟਮ ਦੀ ਸਥਿਤੀ ਨੂੰ ਪੜ੍ਹਨ ਅਤੇ ਇਸਦੇ ਡਾਟੇ ਦਾ ਪਤਾ ਲਗਾਉਣ ਦੀ ਆਗਿਆ ਦਿੰਦਾ ਹੈ"</string>
<string name="car_permission_label_control_car_occupant_awareness_system" msgid="7163330266691094542">"ਕਾਰ ਚਲਾਉਣ ਵਾਲੇ ਲਈ ਜਾਗਰੂਕਤਾ ਸਿਸਟਮ ਦੇ ਗ੍ਰਾਫ਼ ਨੂੰ ਕੰਟਰੋਲ ਕਰੋ"</string>
<string name="car_permission_desc_control_car_occupant_awareness_system" msgid="7123482622084531911">"ਕਾਰ ਚਲਾਉਣ ਵਾਲੇ ਲਈ ਜਾਗਰੂਕਤਾ ਸਿਸਟਮ ਦੇ ਪਤਾ ਲਗਾਉਣ ਵਾਲੇ ਗ੍ਰਾਫ਼ ਨੂੰ ਸ਼ੁਰੂ ਕਰਨ ਅਤੇ ਰੋਕਣ ਦੀ ਆਗਿਆ ਦਿੰਦਾ ਹੈ"</string>
- <string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"ਕਾਰ ਇਨਪੁੱਟ ਸਰਵਿਸ"</string>
- <string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"ਇਨਪੁੱਟ ਇਵੈਂਟਾਂ ਦੀ ਸੰਭਾਲ"</string>
<string name="car_permission_label_diag_read" msgid="7248894224877702604">"ਤਸ਼ਖੀਸੀ ਡਾਟੇ ਨੂੰ ਪੜ੍ਹਨਾ"</string>
<string name="car_permission_desc_diag_read" msgid="1121426363040966178">"ਕਾਰ ਦਾ ਤਸ਼ਖੀਸੀ ਡਾਟਾ ਪੜ੍ਹਨਾ।"</string>
<string name="car_permission_label_diag_clear" msgid="4783070510879698157">"ਤਸ਼ਖੀਸੀ ਡਾਟਾ ਕਲੀਅਰ ਕਰਨਾ"</string>
<string name="car_permission_desc_diag_clear" msgid="7453222114866042786">"ਕਾਰ ਦਾ ਤਸ਼ਖੀਸੀ ਡਾਟਾ ਕਲੀਅਰ ਕਰਨਾ।"</string>
<string name="car_permission_label_vms_publisher" msgid="3049934078926106641">"VMS ਪ੍ਰਕਾਸ਼ਕ"</string>
<string name="car_permission_desc_vms_publisher" msgid="5589489298597386828">"VMS ਸੁਨੇਹੇ ਪ੍ਰਕਾਸ਼ਿਤ ਕਰੋ"</string>
- <string name="car_permission_label_vms_subscriber" msgid="5648841182059222299">"VMS ਸਬਸਕ੍ਰਾਈਬਰ"</string>
- <string name="car_permission_desc_vms_subscriber" msgid="7551009457847673620">"VMS ਸੁਨੇਹਿਆਂ ਨੂੰ ਸਬਸਕ੍ਰਾਈਬ ਕਰੋ"</string>
- <string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"VMS ਕਲਾਇੰਟ ਸੇਵਾ"</string>
- <string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"VMS ਕਲਾਇੰਟਾਂ ਨਾਲ ਜੋੜੋ"</string>
+ <string name="car_permission_label_vms_subscriber" msgid="5648841182059222299">"VMS ਗਾਹਕ"</string>
+ <string name="car_permission_desc_vms_subscriber" msgid="7551009457847673620">"VMS ਸੁਨੇਹਿਆਂ ਦੇ ਗਾਹਕ ਬਣੋ"</string>
<string name="car_permission_label_storage_monitoring" msgid="2327639346522530549">"ਫਲੈਸ਼ ਸਟੋਰੇਜ ਦਾ ਨਿਰੀਖਣ"</string>
<string name="car_permission_desc_storage_monitoring" msgid="2075712271139671318">"ਫਲੈਸ਼ ਸਟੋਰੇਜ ਵਰਤੋਂ ਦਾ ਨਿਰੀਖਣ"</string>
<string name="car_permission_label_driving_state" msgid="7754624599537393650">"ਗੱਡੀ ਚਲਾਉਣ ਦੀ ਸਥਿਤੀ ਨੂੰ ਜਾਣਨਾ"</string>
@@ -93,13 +85,13 @@
<string name="car_permission_label_use_telemetry_service" msgid="948005838683758846">"ਕਾਰ ਟੈਲੀਮੀਟਰੀ ਸੇਵਾ ਵਰਤੋ"</string>
<string name="car_permission_desc_use_telemetry_service" msgid="3633214312435700766">"ਕਾਰ ਸਿਸਟਮ ਸਿਹਤ ਡਾਟਾ ਇਕੱਤਰ ਕਰੋ।"</string>
<string name="car_permission_label_use_evs_service" msgid="1729276125209310607">"ਕਾਰ ਦੀ EVS ਸੇਵਾ ਵਰਤੋ"</string>
- <string name="car_permission_desc_use_evs_service" msgid="2374737642186632816">"EVS ਵੀਡੀਓ ਸਟ੍ਰੀਮਾਂ ਨੂੰ ਸਬਸਕ੍ਰਾਈਬ ਕਰੋ"</string>
+ <string name="car_permission_desc_use_evs_service" msgid="2374737642186632816">"EVS ਵੀਡੀਓ ਸਟ੍ਰੀਮਾਂ ਦੇ ਗਾਹਕ ਬਣੋ"</string>
<string name="car_permission_label_request_evs_activity" msgid="3906551972883482883">"EVS ਪੂਰਵ-ਝਲਕ ਸਰਗਰਮੀ ਲਈ ਬੇਨਤੀ ਕਰੋ"</string>
<string name="car_permission_desc_request_evs_activity" msgid="4582768053649138488">"EVS ਪੂਰਵ-ਝਲਕ ਸਰਗਰਮੀ ਨੂੰ ਲਾਂਚ ਕਰਨ ਲਈ ਸਿਸਟਮ ਨੂੰ ਬੇਨਤੀ ਕਰੋ"</string>
<string name="car_permission_label_control_evs_activity" msgid="2030069860204405679">"EVS ਪੂਰਵ-ਝਲਕ ਸਰਗਰਮੀ ਨੂੰ ਕੰਟਰੋਲ ਕਰੋ"</string>
<string name="car_permission_desc_control_evs_activity" msgid="691646545916976346">"ਸਿਸਟਮ ਦੀ EVS ਪੂਰਵ-ਝਲਕ ਸਰਗਰਮੀ ਨੂੰ ਕੰਟਰੋਲ ਕਰੋ"</string>
<string name="car_permission_label_use_evs_camera" msgid="3607720208623955067">"EVS ਕੈਮਰਾ ਵਰਤੋ"</string>
- <string name="car_permission_desc_use_evs_camera" msgid="1625845902221003985">"EVS ਕੈਮਰਾ ਸਟ੍ਰੀਮਾਂ ਨੂੰ ਸਬਸਕ੍ਰਾਈਬ ਕਰੋ"</string>
+ <string name="car_permission_desc_use_evs_camera" msgid="1625845902221003985">"EVS ਕੈਮਰਾ ਸਟ੍ਰੀਮਾਂ ਦੇ ਗਾਹਕ ਬਣੋ"</string>
<string name="car_permission_label_monitor_evs_status" msgid="2091521314159379622">"EVS ਸੇਵਾ ਦੀ ਸਥਿਤੀ ਦੀ ਨਿਗਰਾਨੀ ਕਰੋ"</string>
<string name="car_permission_desc_monitor_evs_status" msgid="2764278897143573535">"EVS ਸੇਵਾ ਦੀ ਸਥਿਤੀ ਸੰਬੰਧੀ ਤਬਦੀਲੀਆਂ ਨੂੰ ਸੁਣੋ"</string>
<string name="car_permission_label_car_engine_detailed" msgid="8911992719173587337">"ਕਾਰ ਦੇ ਇੰਜਣ ਦੀ ਪੂਰੀ ਜਾਣਕਾਰੀ ਤੱਕ ਪਹੁੰਚ"</string>
diff --git a/service/res/values-pl/strings.xml b/service/res/values-pl/strings.xml
index 6068675..30b0180 100644
--- a/service/res/values-pl/strings.xml
+++ b/service/res/values-pl/strings.xml
@@ -42,8 +42,6 @@
<string name="car_permission_desc_projection" msgid="2352178999656292944">"Zezwala aplikacji na projekcję interfejsu z telefonu na wyświetlacz w samochodzie."</string>
<string name="car_permission_label_access_projection_status" msgid="4231618890836627402">"dostęp do stanu wyświetlania treści"</string>
<string name="car_permission_desc_access_projection_status" msgid="8497351979100616278">"Zezwala aplikacji na pobieranie stanu innych aplikacji dokonujących projekcji na wyświetlacz w samochodzie."</string>
- <string name="car_permission_label_bind_projection_service" msgid="5362076216606651526">"powiązanie z usługą wyświetlania treści"</string>
- <string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"Zezwala na tworzenie powiązania z interfejsem najwyższego poziomu usługi projekcji. Nie powinno być nigdy potrzebne w przypadku zwykłych aplikacji."</string>
<string name="car_permission_label_audio_volume" msgid="310587969373137690">"sterowanie głośnością dźwięku w samochodzie"</string>
<string name="car_permission_label_audio_settings" msgid="6524703796944023977">"zarządzanie ustawieniami dźwięku w samochodzie"</string>
<string name="car_permission_label_mock_vehicle_hal" msgid="7198852512207405935">"emulowanie interfejsu HAL pojazdu"</string>
@@ -62,8 +60,6 @@
<string name="car_permission_desc_car_cluster_control" msgid="9222776665281176031">"Uruchamianie aplikacji w klastrze przyrządów"</string>
<string name="car_permission_car_monitor_cluster_navigation_state" msgid="7025307242306902441">"Stan nawigacji grupy przyrządów"</string>
<string name="car_permission_desc_car_monitor_cluster_navigation_state" msgid="8745047153878713339">"Wykrywaj, czy zmienia się stan nawigacji grupy przyrządów"</string>
- <string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"Renderowanie w klastrze przyrządów"</string>
- <string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"Otrzymywanie danych o klastrze przyrządów"</string>
<string name="car_permission_label_car_ux_restrictions_configuration" msgid="6801393970411049725">"Konfiguracja ograniczeń UX"</string>
<string name="car_permission_desc_car_ux_restrictions_configuration" msgid="5711926927484813777">"Konfigurowanie ograniczeń UX"</string>
<string name="car_permission_label_access_private_display_id" msgid="6712116114341634316">"Odczyt prywatnego identyfikatora wyświetlacza"</string>
@@ -74,8 +70,6 @@
<string name="car_permission_desc_read_car_occupant_awareness_state" msgid="188865882598414986">"Umożliwia odczytywanie danych o stanie i działaniu systemu wykrywania osób"</string>
<string name="car_permission_label_control_car_occupant_awareness_system" msgid="7163330266691094542">"Sterowanie wykresem z systemu wykrywania osób"</string>
<string name="car_permission_desc_control_car_occupant_awareness_system" msgid="7123482622084531911">"Umożliwia włączanie i wyłączanie wykresu z systemu wykrywania osób"</string>
- <string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Usługa wprowadzania danych w samochodzie"</string>
- <string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Obsługa zdarzeń wprowadzania danych"</string>
<string name="car_permission_label_diag_read" msgid="7248894224877702604">"odczytywanie danych diagnostycznych"</string>
<string name="car_permission_desc_diag_read" msgid="1121426363040966178">"Odczytywanie danych diagnostycznych samochodu."</string>
<string name="car_permission_label_diag_clear" msgid="4783070510879698157">"czyszczenie danych diagnostycznych"</string>
@@ -84,8 +78,6 @@
<string name="car_permission_desc_vms_publisher" msgid="5589489298597386828">"Publikowanie komunikatów VMS"</string>
<string name="car_permission_label_vms_subscriber" msgid="5648841182059222299">"Subskrypcja komunikatów VMS"</string>
<string name="car_permission_desc_vms_subscriber" msgid="7551009457847673620">"Subskrybowanie komunikatów VMS"</string>
- <string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"Usługa klienta VMS"</string>
- <string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"Powiązanie z klientami VMS"</string>
<string name="car_permission_label_storage_monitoring" msgid="2327639346522530549">"Monitorowanie pamięci flash"</string>
<string name="car_permission_desc_storage_monitoring" msgid="2075712271139671318">"Monitorowanie użycia pamięci flash"</string>
<string name="car_permission_label_driving_state" msgid="7754624599537393650">"nasłuchiwanie podczas jazdy samochodem"</string>
diff --git a/service/res/values-pt-rPT/strings.xml b/service/res/values-pt-rPT/strings.xml
index 01cf93e..76b5daf 100644
--- a/service/res/values-pt-rPT/strings.xml
+++ b/service/res/values-pt-rPT/strings.xml
@@ -42,8 +42,6 @@
<string name="car_permission_desc_projection" msgid="2352178999656292944">"Permite que uma aplicação projete a interface de um telemóvel no ecrã do automóvel."</string>
<string name="car_permission_label_access_projection_status" msgid="4231618890836627402">"aceder ao estado da projeção"</string>
<string name="car_permission_desc_access_projection_status" msgid="8497351979100616278">"Permite que uma aplicação projete o estado de outras aplicações no ecrã do automóvel."</string>
- <string name="car_permission_label_bind_projection_service" msgid="5362076216606651526">"vincular a um serviço de projeção"</string>
- <string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"Permite que o titular se vincule à interface de nível superior de um serviço de projeção. Nunca deverá ser necessário para aplicações normais."</string>
<string name="car_permission_label_audio_volume" msgid="310587969373137690">"controlar o volume de áudio do automóvel"</string>
<string name="car_permission_label_audio_settings" msgid="6524703796944023977">"gerir as definições de áudio do automóvel"</string>
<string name="car_permission_label_mock_vehicle_hal" msgid="7198852512207405935">"emular a HAL do veículo"</string>
@@ -62,8 +60,6 @@
<string name="car_permission_desc_car_cluster_control" msgid="9222776665281176031">"Inicie aplicações no cluster do instrumento."</string>
<string name="car_permission_car_monitor_cluster_navigation_state" msgid="7025307242306902441">"Estado de navegação para o cluster do instrumento"</string>
<string name="car_permission_desc_car_monitor_cluster_navigation_state" msgid="8745047153878713339">"Verifique se existem alterações ao estado de navegação para o cluster do instrumento"</string>
- <string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"Renderização do cluster do instrumento"</string>
- <string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"Receba os dados do cluster do instrumento."</string>
<string name="car_permission_label_car_ux_restrictions_configuration" msgid="6801393970411049725">"Configuração das restrições da experiência do utilizador"</string>
<string name="car_permission_desc_car_ux_restrictions_configuration" msgid="5711926927484813777">"Configure restrições da experiência do utilizador."</string>
<string name="car_permission_label_access_private_display_id" msgid="6712116114341634316">"Acesso de leitura ao ID do ecrã privado"</string>
@@ -74,8 +70,6 @@
<string name="car_permission_desc_read_car_occupant_awareness_state" msgid="188865882598414986">"Permite a leitura do estado e dos dados de deteção do Sistema de deteção de ocupantes."</string>
<string name="car_permission_label_control_car_occupant_awareness_system" msgid="7163330266691094542">"Controlar o gráfico do Sistema de deteção de ocupantes"</string>
<string name="car_permission_desc_control_car_occupant_awareness_system" msgid="7123482622084531911">"Permite controlar o início e a interrupção do gráfico de deteção do Sistema de deteção de ocupantes."</string>
- <string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Serviço de entrada do automóvel"</string>
- <string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Processe eventos de entrada."</string>
<string name="car_permission_label_diag_read" msgid="7248894224877702604">"ler os dados de diagnóstico"</string>
<string name="car_permission_desc_diag_read" msgid="1121426363040966178">"Ler os dados de diagnóstico do automóvel."</string>
<string name="car_permission_label_diag_clear" msgid="4783070510879698157">"limpar os dados de diagnóstico"</string>
@@ -84,8 +78,6 @@
<string name="car_permission_desc_vms_publisher" msgid="5589489298597386828">"Publicar mensagens VMS"</string>
<string name="car_permission_label_vms_subscriber" msgid="5648841182059222299">"Subscritor de VMS"</string>
<string name="car_permission_desc_vms_subscriber" msgid="7551009457847673620">"Subscrever as mensagens VMS"</string>
- <string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"Serviço de cliente VMS"</string>
- <string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"Vincular a clientes VMS"</string>
<string name="car_permission_label_storage_monitoring" msgid="2327639346522530549">"Monitorização do armazenamento flash"</string>
<string name="car_permission_desc_storage_monitoring" msgid="2075712271139671318">"Monitorize a utilização do armazenamento flash."</string>
<string name="car_permission_label_driving_state" msgid="7754624599537393650">"ouvir o estado de condução"</string>
diff --git a/service/res/values-pt/strings.xml b/service/res/values-pt/strings.xml
index 0103442..d3d6871 100644
--- a/service/res/values-pt/strings.xml
+++ b/service/res/values-pt/strings.xml
@@ -42,8 +42,6 @@
<string name="car_permission_desc_projection" msgid="2352178999656292944">"Permite que um app projete uma interface de um smartphone na tela do carro."</string>
<string name="car_permission_label_access_projection_status" msgid="4231618890836627402">"acessar o status de projeção"</string>
<string name="car_permission_desc_access_projection_status" msgid="8497351979100616278">"Permite que um app acesse o status de outros apps que fazem projeções na tela do carro."</string>
- <string name="car_permission_label_bind_projection_service" msgid="5362076216606651526">"vincular um serviço de projeção"</string>
- <string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"Permite que o proprietário vincule a interface de nível superior de um serviço de projeção. Nunca deve ser necessário para apps normais."</string>
<string name="car_permission_label_audio_volume" msgid="310587969373137690">"controlar volume de áudio do carro"</string>
<string name="car_permission_label_audio_settings" msgid="6524703796944023977">"controlar as configurações de áudio do carro"</string>
<string name="car_permission_label_mock_vehicle_hal" msgid="7198852512207405935">"emular HAL do veículo"</string>
@@ -62,8 +60,6 @@
<string name="car_permission_desc_car_cluster_control" msgid="9222776665281176031">"Iniciar apps no cluster de instrumento"</string>
<string name="car_permission_car_monitor_cluster_navigation_state" msgid="7025307242306902441">"Estado de navegação do cluster de instrumentos"</string>
<string name="car_permission_desc_car_monitor_cluster_navigation_state" msgid="8745047153878713339">"Confira se há alterações no estado de navegação do cluster de instrumentos"</string>
- <string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"Renderização de cluster de instrumento"</string>
- <string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"Receber dados do cluster de instrumento"</string>
<string name="car_permission_label_car_ux_restrictions_configuration" msgid="6801393970411049725">"Configuração das restrições de UX"</string>
<string name="car_permission_desc_car_ux_restrictions_configuration" msgid="5711926927484813777">"Configurar restrições de UX"</string>
<string name="car_permission_label_access_private_display_id" msgid="6712116114341634316">"Acesso de leitura ao ID de exibição particular"</string>
@@ -74,8 +70,6 @@
<string name="car_permission_desc_read_car_occupant_awareness_state" msgid="188865882598414986">"Permite ler o status e os dados de detecção do sistema de detecção de ocupantes"</string>
<string name="car_permission_label_control_car_occupant_awareness_system" msgid="7163330266691094542">"Controlar o gráfico do sistema de detecção de ocupantes"</string>
<string name="car_permission_desc_control_car_occupant_awareness_system" msgid="7123482622084531911">"Permite controlar o início e fim do gráfico do sistema de detecção de ocupantes"</string>
- <string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Serviço de entrada do carro"</string>
- <string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Gerenciar eventos de entrada"</string>
<string name="car_permission_label_diag_read" msgid="7248894224877702604">"ler dados de diagnóstico"</string>
<string name="car_permission_desc_diag_read" msgid="1121426363040966178">"Ler dados de diagnóstico do carro."</string>
<string name="car_permission_label_diag_clear" msgid="4783070510879698157">"limpar dados de diagnóstico"</string>
@@ -84,8 +78,6 @@
<string name="car_permission_desc_vms_publisher" msgid="5589489298597386828">"Publicar mensagens de VMS"</string>
<string name="car_permission_label_vms_subscriber" msgid="5648841182059222299">"Inscrição em VMS"</string>
<string name="car_permission_desc_vms_subscriber" msgid="7551009457847673620">"Inscrever-se em mensagens de VMS"</string>
- <string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"Serviço de cliente VMS"</string>
- <string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"Vincular clientes VMS"</string>
<string name="car_permission_label_storage_monitoring" msgid="2327639346522530549">"Monitoramento do armazenamento flash"</string>
<string name="car_permission_desc_storage_monitoring" msgid="2075712271139671318">"Monitorar uso do armazenamento flash"</string>
<string name="car_permission_label_driving_state" msgid="7754624599537393650">"ouvir o estado de condução"</string>
diff --git a/service/res/values-ro/strings.xml b/service/res/values-ro/strings.xml
index 7e222bc..89a34e6 100644
--- a/service/res/values-ro/strings.xml
+++ b/service/res/values-ro/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="2215078736675564541">"informațiile despre mașină"</string>
+ <string name="car_permission_label" msgid="2215078736675564541">"Accesează informațiile despre mașină"</string>
<string name="car_permission_desc" msgid="3584369074931334964">"să acceseze informațiile despre mașină"</string>
<string name="car_permission_label_camera" msgid="3725702064841827180">"Accesează camera mașinii"</string>
<string name="car_permission_desc_camera" msgid="917024932164501426">"Accesează camerele mașinii."</string>
@@ -42,8 +42,6 @@
<string name="car_permission_desc_projection" msgid="2352178999656292944">"Permite unei aplicații să proiecteze o interfață de pe un telefon pe afișajul mașinii."</string>
<string name="car_permission_label_access_projection_status" msgid="4231618890836627402">"Accesează starea proiecției"</string>
<string name="car_permission_desc_access_projection_status" msgid="8497351979100616278">"Permite unei aplicații să obțină starea altor aplicații care se proiectează pe afișajul mașinii."</string>
- <string name="car_permission_label_bind_projection_service" msgid="5362076216606651526">"Se conectează la un serviciu de proiecție"</string>
- <string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"Permite proprietarului să se conecteze la interfața de nivel superior a unui serviciu de proiecție. Nu ar trebui să fie niciodată necesară pentru aplicațiile obișnuite"</string>
<string name="car_permission_label_audio_volume" msgid="310587969373137690">"Controlează volumul audio din mașină"</string>
<string name="car_permission_label_audio_settings" msgid="6524703796944023977">"Gestionează setările audio ale mașinii"</string>
<string name="car_permission_label_mock_vehicle_hal" msgid="7198852512207405935">"Imită nivelul HAL al vehiculului"</string>
@@ -62,8 +60,6 @@
<string name="car_permission_desc_car_cluster_control" msgid="9222776665281176031">"Lansați aplicațiile din grupul de instrumente"</string>
<string name="car_permission_car_monitor_cluster_navigation_state" msgid="7025307242306902441">"Starea de navigare în grupul de instrumente"</string>
<string name="car_permission_desc_car_monitor_cluster_navigation_state" msgid="8745047153878713339">"Ascultați modificările stării de navigare în grupul de instrumente"</string>
- <string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"Redarea grupurilor de instrumente"</string>
- <string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"Primiți date despre grupul de instrumente"</string>
<string name="car_permission_label_car_ux_restrictions_configuration" msgid="6801393970411049725">"Configurarea restricțiilor UX"</string>
<string name="car_permission_desc_car_ux_restrictions_configuration" msgid="5711926927484813777">"Configurați restricțiile UX"</string>
<string name="car_permission_label_access_private_display_id" msgid="6712116114341634316">"Acces pentru citire la ID-ul de afișare privată"</string>
@@ -74,8 +70,6 @@
<string name="car_permission_desc_read_car_occupant_awareness_state" msgid="188865882598414986">"Permite citirea stării și a datelor de detectare pentru Sistemul de avertizare privind ocupanții"</string>
<string name="car_permission_label_control_car_occupant_awareness_system" msgid="7163330266691094542">"Controlează graficul Sistemului de avertizare privind ocupanții"</string>
<string name="car_permission_desc_control_car_occupant_awareness_system" msgid="7123482622084531911">"Permite controlarea începerii și opririi graficului de detectare a Sistemului de avertizare privind ocupanții"</string>
- <string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Gestionează serviciul de intrare pentru mașină"</string>
- <string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Gestionează evenimentele de intrare"</string>
<string name="car_permission_label_diag_read" msgid="7248894224877702604">"Citește datele de diagnosticare"</string>
<string name="car_permission_desc_diag_read" msgid="1121426363040966178">"Citește datele de diagnosticare de la mașină."</string>
<string name="car_permission_label_diag_clear" msgid="4783070510879698157">"Șterge datele de diagnosticare"</string>
@@ -84,8 +78,6 @@
<string name="car_permission_desc_vms_publisher" msgid="5589489298597386828">"Publică mesaje VMS"</string>
<string name="car_permission_label_vms_subscriber" msgid="5648841182059222299">"Se abonează la datele VMS"</string>
<string name="car_permission_desc_vms_subscriber" msgid="7551009457847673620">"Se abonează la mesajele VMS"</string>
- <string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"Serviciu client VMS"</string>
- <string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"Se conectează la clienții VMS"</string>
<string name="car_permission_label_storage_monitoring" msgid="2327639346522530549">"Monitorizează stocarea Flash"</string>
<string name="car_permission_desc_storage_monitoring" msgid="2075712271139671318">"Monitorizează utilizarea stocării flash"</string>
<string name="car_permission_label_driving_state" msgid="7754624599537393650">"Ascultă starea La volan"</string>
diff --git a/service/res/values-ru/strings.xml b/service/res/values-ru/strings.xml
index f124b1e..25a767b 100644
--- a/service/res/values-ru/strings.xml
+++ b/service/res/values-ru/strings.xml
@@ -17,7 +17,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="2215078736675564541">"Данные автомобиля"</string>
- <string name="car_permission_desc" msgid="3584369074931334964">"получать доступ к данным автомобиля."</string>
+ <string name="car_permission_desc" msgid="3584369074931334964">"Доступ к данным автомобиля"</string>
<string name="car_permission_label_camera" msgid="3725702064841827180">"доступ к камере автомобиля"</string>
<string name="car_permission_desc_camera" msgid="917024932164501426">"Доступ к камерам автомобиля"</string>
<string name="car_permission_label_energy" msgid="7409144323527821558">"доступ к данным об энергоресурсах автомобиля"</string>
@@ -42,8 +42,6 @@
<string name="car_permission_desc_projection" msgid="2352178999656292944">"Интерфейс приложения будет отображаться на дисплее автомобиля."</string>
<string name="car_permission_label_access_projection_status" msgid="4231618890836627402">"доступ к статусу проекции"</string>
<string name="car_permission_desc_access_projection_status" msgid="8497351979100616278">"Приложение сможет узнавать статус других приложений, показывающих интерфейс на дисплее автомобиля."</string>
- <string name="car_permission_label_bind_projection_service" msgid="5362076216606651526">"подключение к сервису проекции"</string>
- <string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"Приложение сможет подключаться к базовому интерфейсу сервиса проекции. Это разрешение не используется обычными приложениями."</string>
<string name="car_permission_label_audio_volume" msgid="310587969373137690">"управление громкостью аудиосистемы"</string>
<string name="car_permission_label_audio_settings" msgid="6524703796944023977">"управление настройками аудиосистемы"</string>
<string name="car_permission_label_mock_vehicle_hal" msgid="7198852512207405935">"эмуляция интерфейса HAL"</string>
@@ -62,8 +60,6 @@
<string name="car_permission_desc_car_cluster_control" msgid="9222776665281176031">"Возможность запускать приложения с приборной панели"</string>
<string name="car_permission_car_monitor_cluster_navigation_state" msgid="7025307242306902441">"Состояние навигации на приборной панели"</string>
<string name="car_permission_desc_car_monitor_cluster_navigation_state" msgid="8745047153878713339">"Отслеживать изменения состояния навигации на приборной панели"</string>
- <string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"Визуализация данных на приборной панели"</string>
- <string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"Возможность получать данные с приборной панели"</string>
<string name="car_permission_label_car_ux_restrictions_configuration" msgid="6801393970411049725">"Установка ограничений на использование функций"</string>
<string name="car_permission_desc_car_ux_restrictions_configuration" msgid="5711926927484813777">"Возможность ограничивать использование функций"</string>
<string name="car_permission_label_access_private_display_id" msgid="6712116114341634316">"Доступ для считывания идентификатора приватного экрана"</string>
@@ -74,8 +70,6 @@
<string name="car_permission_desc_read_car_occupant_awareness_state" msgid="188865882598414986">"Считывание статуса и данных функции Occupant Awareness System"</string>
<string name="car_permission_label_control_car_occupant_awareness_system" msgid="7163330266691094542">"Управление графиком функции Occupant Awareness System"</string>
<string name="car_permission_desc_control_car_occupant_awareness_system" msgid="7123482622084531911">"Управление началом и окончанием работы графика функции Occupant Awareness System"</string>
- <string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Автомобильная служба ввода"</string>
- <string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Возможность обрабатывать события ввода"</string>
<string name="car_permission_label_diag_read" msgid="7248894224877702604">"чтение диагностических данных"</string>
<string name="car_permission_desc_diag_read" msgid="1121426363040966178">"Чтение диагностических данных автомобиля."</string>
<string name="car_permission_label_diag_clear" msgid="4783070510879698157">"удаление диагностических данных"</string>
@@ -84,8 +78,6 @@
<string name="car_permission_desc_vms_publisher" msgid="5589489298597386828">"Возможность публиковать VMS-сообщения"</string>
<string name="car_permission_label_vms_subscriber" msgid="5648841182059222299">"Подписка на VMS-сообщения"</string>
<string name="car_permission_desc_vms_subscriber" msgid="7551009457847673620">"Возможность получать VMS-сообщения"</string>
- <string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"VMS-клиент"</string>
- <string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"Подключение к VMS-клиентам"</string>
<string name="car_permission_label_storage_monitoring" msgid="2327639346522530549">"Мониторинг флеш-хранилища"</string>
<string name="car_permission_desc_storage_monitoring" msgid="2075712271139671318">"Возможность отслеживать использование флеш-хранилища"</string>
<string name="car_permission_label_driving_state" msgid="7754624599537393650">"отслеживание изменений режима \"За рулем\""</string>
diff --git a/service/res/values-si/strings.xml b/service/res/values-si/strings.xml
index 22eb238..8c01b49 100644
--- a/service/res/values-si/strings.xml
+++ b/service/res/values-si/strings.xml
@@ -42,8 +42,6 @@
<string name="car_permission_desc_projection" msgid="2352178999656292944">"යෙදුමකට දුරකථනයකින් මෝටර් රථයේ සංදර්ශකයෙහි අතුරු මුහුණතක් ප්රක්ෂේපණයට ඉඩ දෙයි."</string>
<string name="car_permission_label_access_projection_status" msgid="4231618890836627402">"ප්රක්ෂේපණ තත්ත්වයට ප්රවේශ වන්න"</string>
<string name="car_permission_desc_access_projection_status" msgid="8497351979100616278">"යෙදුමකට මෝටර් රථයේ සංදර්ශකයට ප්රක්ෂේපණය වන වෙනත් යෙදුම්වල තත්ත්වය ලබා ගැනීමට ඉඩ දෙයි."</string>
- <string name="car_permission_label_bind_projection_service" msgid="5362076216606651526">"ප්රක්ෂේපණ සේවාවකට බඳින්න"</string>
- <string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"ප්රක්ෂේපණ සේවාවක ඉහළ-මට්ටමේ අතුරු මුහුණතට බැඳීමට ධාරකයට ඉඩ දෙයි. සාමාන්ය යෙදුම්වලට කිසි විටෙක අවශ්ය නොවෙයි."</string>
<string name="car_permission_label_audio_volume" msgid="310587969373137690">"මෝටර් රථයේ ශ්රව්ය හඬ පාලනය කරන්න"</string>
<string name="car_permission_label_audio_settings" msgid="6524703796944023977">"මෝටර් රථයේ ශ්රව්ය සැකසුම් කළමනාකරණය කරන්න"</string>
<string name="car_permission_label_mock_vehicle_hal" msgid="7198852512207405935">"වාහන HAL අනුකරණය කරන්න"</string>
@@ -62,8 +60,6 @@
<string name="car_permission_desc_car_cluster_control" msgid="9222776665281176031">"උපකරණ කලඹ තුළ යෙදුම් දියත් කරන්න"</string>
<string name="car_permission_car_monitor_cluster_navigation_state" msgid="7025307242306902441">"උපකරණ පොකුරු සංචාලන තත්ත්වය"</string>
<string name="car_permission_desc_car_monitor_cluster_navigation_state" msgid="8745047153878713339">"උපකරණ පොකුරු සංචාලන තත්ත්වය වෙනස් කිරීම සඳහා සවන් දෙන්න"</string>
- <string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"උපකරණ කලප් විදහීම"</string>
- <string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"උපකරණ කලප් දත්ත ලබා ගන්න"</string>
<string name="car_permission_label_car_ux_restrictions_configuration" msgid="6801393970411049725">"UX සීමා කිරීම් වින්යාසය"</string>
<string name="car_permission_desc_car_ux_restrictions_configuration" msgid="5711926927484813777">"UX සීමා කිරීම් වින්යාස කරන්න"</string>
<string name="car_permission_label_access_private_display_id" msgid="6712116114341634316">"පෞද්ගලික සංදර්ශක ID සඳහා කියවීම් ප්රවේශය"</string>
@@ -74,8 +70,6 @@
<string name="car_permission_desc_read_car_occupant_awareness_state" msgid="188865882598414986">"පදිංචිකරුවන් දැනුවත් කිරීමේ පද්ධතිය සඳහා තත්ත්වය සහ අනාවරණ දත්ත කියවීමට ඉඩ දෙයි"</string>
<string name="car_permission_label_control_car_occupant_awareness_system" msgid="7163330266691094542">"පදිංචිකරුවන් දැනුවත් කිරීමේ පද්ධති ප්රස්ථාරය"</string>
<string name="car_permission_desc_control_car_occupant_awareness_system" msgid="7123482622084531911">"පදිංචිකරුවන් දැනුවත් කිරීමේ පද්ධති අනාවරණ ප්රස්ථාරයෙහි ආරම්භය සහ නැවැත්වීම පාලනයට ඉඩ දෙයි"</string>
- <string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"මෝටර් රථ ආදාන සේවය"</string>
- <string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"ආදාන සිදුවීම් පරිහරණ කරන්න"</string>
<string name="car_permission_label_diag_read" msgid="7248894224877702604">"දෝෂනිර්ණ දත්ත කියවන්න"</string>
<string name="car_permission_desc_diag_read" msgid="1121426363040966178">"මෝටර් රථයෙන් දෝෂනිර්ණ දත්ත කියවන්න."</string>
<string name="car_permission_label_diag_clear" msgid="4783070510879698157">"දෝෂනිර්ණ දත්ත හිස් කරන්න"</string>
@@ -84,8 +78,6 @@
<string name="car_permission_desc_vms_publisher" msgid="5589489298597386828">"VMS පණිවිඩ ප්රකාශනය"</string>
<string name="car_permission_label_vms_subscriber" msgid="5648841182059222299">"VMS ග්රාහකයා"</string>
<string name="car_permission_desc_vms_subscriber" msgid="7551009457847673620">"VMS පණිවිඩවලට දායක වන්න"</string>
- <string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"VMS සේවාලාභී සේවාව"</string>
- <string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"VMS සේවාලාභීන්ට බඳින්න"</string>
<string name="car_permission_label_storage_monitoring" msgid="2327639346522530549">"ෆ්ලෑෂ් ආචයන නිරීක්ෂණය"</string>
<string name="car_permission_desc_storage_monitoring" msgid="2075712271139671318">"ෆ්ලෑෂ් ආචයන භාවිතය නිරීක්ෂණ කරන්න"</string>
<string name="car_permission_label_driving_state" msgid="7754624599537393650">"රිය පැදවීමේ තත්ත්වයට සවන් දෙන්න"</string>
diff --git a/service/res/values-sk/strings.xml b/service/res/values-sk/strings.xml
index dc57742..886ba76 100644
--- a/service/res/values-sk/strings.xml
+++ b/service/res/values-sk/strings.xml
@@ -42,8 +42,6 @@
<string name="car_permission_desc_projection" msgid="2352178999656292944">"Umožňuje aplikácii premietať rozhranie z telefónu na obrazovke auta."</string>
<string name="car_permission_label_access_projection_status" msgid="4231618890836627402">"získať prístup k stavu premietania"</string>
<string name="car_permission_desc_access_projection_status" msgid="8497351979100616278">"Umožňuje aplikácii získať stav ďalších aplikácií premietajúcich na obrazovku auta."</string>
- <string name="car_permission_label_bind_projection_service" msgid="5362076216606651526">"naviazať sa na premietaciu službu"</string>
- <string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"Umožňuje držiteľovi naviazať sa na najvyššiu úroveň rozhrania premietacej služby. Bežné aplikácie by toto nastavenie nemali nikdy potrebovať."</string>
<string name="car_permission_label_audio_volume" msgid="310587969373137690">"ovládať hlasitosť audiosystému auta"</string>
<string name="car_permission_label_audio_settings" msgid="6524703796944023977">"spravovať nastavenia audiosystému auta"</string>
<string name="car_permission_label_mock_vehicle_hal" msgid="7198852512207405935">"emulovať vrstvu HAL vozidla"</string>
@@ -62,8 +60,6 @@
<string name="car_permission_desc_car_cluster_control" msgid="9222776665281176031">"Spustiť aplikácie v klastri nástrojov"</string>
<string name="car_permission_car_monitor_cluster_navigation_state" msgid="7025307242306902441">"Stav navigácie klastra prístroja"</string>
<string name="car_permission_desc_car_monitor_cluster_navigation_state" msgid="8745047153878713339">"Sledovať zmeny stavu navigácie klastru prístroja"</string>
- <string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"Vykresľovanie klastra prístrojov"</string>
- <string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"Získavať údaje o klastri prístrojov"</string>
<string name="car_permission_label_car_ux_restrictions_configuration" msgid="6801393970411049725">"Konfigurácia obmedzení dojmu používateľa"</string>
<string name="car_permission_desc_car_ux_restrictions_configuration" msgid="5711926927484813777">"Konfigurovať obmedzenia dojmu používateľa"</string>
<string name="car_permission_label_access_private_display_id" msgid="6712116114341634316">"Prístup na čítanie k súkromnému identifikátoru obrazovky"</string>
@@ -74,8 +70,6 @@
<string name="car_permission_desc_read_car_occupant_awareness_state" msgid="188865882598414986">"Umožňuje čítať stav a údaje o detekcii zo systému detekcie posádky"</string>
<string name="car_permission_label_control_car_occupant_awareness_system" msgid="7163330266691094542">"Ovládanie grafu systému detekcie posádky"</string>
<string name="car_permission_desc_control_car_occupant_awareness_system" msgid="7123482622084531911">"Umožňuje ovládať spustenie a zastavenie grafu detekcie systému detekcie posádky"</string>
- <string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Služba vstupov auta"</string>
- <string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Spravovať udalosti vstupu"</string>
<string name="car_permission_label_diag_read" msgid="7248894224877702604">"čítať diagnostické údaje"</string>
<string name="car_permission_desc_diag_read" msgid="1121426363040966178">"Čítanie diagnostických údajov z auta."</string>
<string name="car_permission_label_diag_clear" msgid="4783070510879698157">"vymazať diagnostické údaje"</string>
@@ -84,8 +78,6 @@
<string name="car_permission_desc_vms_publisher" msgid="5589489298597386828">"Zverejniť správy VMS"</string>
<string name="car_permission_label_vms_subscriber" msgid="5648841182059222299">"Odberateľ VMS"</string>
<string name="car_permission_desc_vms_subscriber" msgid="7551009457847673620">"Odoberať správy VMS"</string>
- <string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"Klientska služba VMS"</string>
- <string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"Naviazať sa na klienty VMS"</string>
<string name="car_permission_label_storage_monitoring" msgid="2327639346522530549">"Monitorovanie úložiska vo formáte Flash"</string>
<string name="car_permission_desc_storage_monitoring" msgid="2075712271139671318">"Monitorovať používanie úložiska vo formáte Flash"</string>
<string name="car_permission_label_driving_state" msgid="7754624599537393650">"počúvať stav jazdy"</string>
diff --git a/service/res/values-sl/strings.xml b/service/res/values-sl/strings.xml
index 98e4cd8..0271b10b 100644
--- a/service/res/values-sl/strings.xml
+++ b/service/res/values-sl/strings.xml
@@ -42,8 +42,6 @@
<string name="car_permission_desc_projection" msgid="2352178999656292944">"Aplikaciji omogoča projiciranje vmesnika iz telefona na zaslon avtomobila."</string>
<string name="car_permission_label_access_projection_status" msgid="4231618890836627402">"dostop do stanja projiciranja"</string>
<string name="car_permission_desc_access_projection_status" msgid="8497351979100616278">"Aplikaciji omogoča pridobivanje stanja drugih aplikacij, ki projicirajo na zaslon avtomobila."</string>
- <string name="car_permission_label_bind_projection_service" msgid="5362076216606651526">"povezava s storitvijo projiciranja"</string>
- <string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"Imetniku omogoča povezovanje z vmesnikom storitve projiciranja najvišje ravni. Tega ni treba nikoli uporabiti za navadne aplikacije."</string>
<string name="car_permission_label_audio_volume" msgid="310587969373137690">"nadziranje glasnosti zvoka v avtomobilu"</string>
<string name="car_permission_label_audio_settings" msgid="6524703796944023977">"upravljanje nastavitev zvoka v avtomobilu"</string>
<string name="car_permission_label_mock_vehicle_hal" msgid="7198852512207405935">"posnemanje HAL-a vozila"</string>
@@ -62,8 +60,6 @@
<string name="car_permission_desc_car_cluster_control" msgid="9222776665281176031">"Zagon aplikacij iz instrumentne plošče"</string>
<string name="car_permission_car_monitor_cluster_navigation_state" msgid="7025307242306902441">"Stanje navigacije na instrumentni plošči"</string>
<string name="car_permission_desc_car_monitor_cluster_navigation_state" msgid="8745047153878713339">"Poslušanje sprememb stanja navigacije na instrumentni plošči."</string>
- <string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"Upodobitev instrumentne plošče"</string>
- <string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"Prejemanje podatkov instrumentne plošče"</string>
<string name="car_permission_label_car_ux_restrictions_configuration" msgid="6801393970411049725">"Konfiguracija omejitev uporabniške izkušnje"</string>
<string name="car_permission_desc_car_ux_restrictions_configuration" msgid="5711926927484813777">"Konfiguriranje omejitev uporabniške izkušnje"</string>
<string name="car_permission_label_access_private_display_id" msgid="6712116114341634316">"Dostop za branje za ID zasebnega zaslona"</string>
@@ -74,8 +70,6 @@
<string name="car_permission_desc_read_car_occupant_awareness_state" msgid="188865882598414986">"Omogoča branje stanja in podatkov o zaznavanju sistema za zavedanje potnikov"</string>
<string name="car_permission_label_control_car_occupant_awareness_system" msgid="7163330266691094542">"Upravljanje grafikona sistema za zavedanje potnikov"</string>
<string name="car_permission_desc_control_car_occupant_awareness_system" msgid="7123482622084531911">"Omogoča upravljanje grafikona začetka in ustavitve zaznavanja sistema za zavedanje potnikov"</string>
- <string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Storitev za vhode avtomobila"</string>
- <string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Obravnava dogodkov vnosa"</string>
<string name="car_permission_label_diag_read" msgid="7248894224877702604">"branje diagnostičnih podatkov"</string>
<string name="car_permission_desc_diag_read" msgid="1121426363040966178">"Branje diagnostičnih podatkov avtomobila."</string>
<string name="car_permission_label_diag_clear" msgid="4783070510879698157">"brisanje diagnostičnih podatkov"</string>
@@ -84,8 +78,6 @@
<string name="car_permission_desc_vms_publisher" msgid="5589489298597386828">"Objavljanje sporočil VMS"</string>
<string name="car_permission_label_vms_subscriber" msgid="5648841182059222299">"Naročnik na VMS"</string>
<string name="car_permission_desc_vms_subscriber" msgid="7551009457847673620">"Naročanje na sporočila VMS"</string>
- <string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"Storitev odjemalca VMS"</string>
- <string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"Povezovanje z odjemalci VMS"</string>
<string name="car_permission_label_storage_monitoring" msgid="2327639346522530549">"Nadziranje bliskovne shrambe"</string>
<string name="car_permission_desc_storage_monitoring" msgid="2075712271139671318">"Nadziranje uporabe bliskovne shrambe"</string>
<string name="car_permission_label_driving_state" msgid="7754624599537393650">"poslušanje voznih stanj"</string>
diff --git a/service/res/values-sq/strings.xml b/service/res/values-sq/strings.xml
index 9c5daf0..814a2ca 100644
--- a/service/res/values-sq/strings.xml
+++ b/service/res/values-sq/strings.xml
@@ -42,8 +42,6 @@
<string name="car_permission_desc_projection" msgid="2352178999656292944">"Lejon që një aplikacion të projektojë një ndërfaqe nga një telefon në ekranin e makinës."</string>
<string name="car_permission_label_access_projection_status" msgid="4231618890836627402">"qasu te statusi i projektimit"</string>
<string name="car_permission_desc_access_projection_status" msgid="8497351979100616278">"Lejon që një aplikacion të marrë statusin e aplikacioneve të tjera që projektojnë në ekranin e makinës."</string>
- <string name="car_permission_label_bind_projection_service" msgid="5362076216606651526">"lidhu me një shërbim projektimi"</string>
- <string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"Lejon që mbajtësi të lidhet me ndërfaqen e nivelit të lartë të një shërbimi projektimi. Nuk duhet të nevojitet ndonjëherë për aplikacionet normale."</string>
<string name="car_permission_label_audio_volume" msgid="310587969373137690">"kontrollo volumin e audios së makinës"</string>
<string name="car_permission_label_audio_settings" msgid="6524703796944023977">"menaxho cilësimet e audios së makinës"</string>
<string name="car_permission_label_mock_vehicle_hal" msgid="7198852512207405935">"emulo ndërfaqen HAL të automjetit"</string>
@@ -62,8 +60,6 @@
<string name="car_permission_desc_car_cluster_control" msgid="9222776665281176031">"Hap aplikacionet në grupimin e instrumenteve"</string>
<string name="car_permission_car_monitor_cluster_navigation_state" msgid="7025307242306902441">"Gjendja e navigimit të grupimit të instrumenteve"</string>
<string name="car_permission_desc_car_monitor_cluster_navigation_state" msgid="8745047153878713339">"Dëgjo për ndryshimet e gjendjes së navigimit të grupimit të instrumenteve"</string>
- <string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"Interpretimi i grupimit të instrumenteve"</string>
- <string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"Merr të dhënat e grupimit të instrumenteve"</string>
<string name="car_permission_label_car_ux_restrictions_configuration" msgid="6801393970411049725">"Konfigurimi i kufizimeve për eksperiencën e përdoruesit"</string>
<string name="car_permission_desc_car_ux_restrictions_configuration" msgid="5711926927484813777">"Konfiguro kufizimet për eksperiencën e përdoruesit"</string>
<string name="car_permission_label_access_private_display_id" msgid="6712116114341634316">"Qasja për lexim për ID-në e ekranit privat"</string>
@@ -74,8 +70,6 @@
<string name="car_permission_desc_read_car_occupant_awareness_state" msgid="188865882598414986">"Lejon leximin e të dhënave për statusin dhe zbulimin për Occupant Awareness System"</string>
<string name="car_permission_label_control_car_occupant_awareness_system" msgid="7163330266691094542">"Kontrollo Occupant Awareness System Graph"</string>
<string name="car_permission_desc_control_car_occupant_awareness_system" msgid="7123482622084531911">"Lejon kontrollin e nisjes dhe ndalimit të grafikut të zbulimit të Occupant Awareness System"</string>
- <string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Shërbimi i hyrjes së makinës"</string>
- <string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Menaxho ngjarjet e hyrjes"</string>
<string name="car_permission_label_diag_read" msgid="7248894224877702604">"lexo të dhënat diagnostikuese"</string>
<string name="car_permission_desc_diag_read" msgid="1121426363040966178">"Lexo të dhënat diagnostikuese nga makina."</string>
<string name="car_permission_label_diag_clear" msgid="4783070510879698157">"pastro të dhënat diagnostikuese"</string>
@@ -84,8 +78,6 @@
<string name="car_permission_desc_vms_publisher" msgid="5589489298597386828">"Publiko mesazhet VMS"</string>
<string name="car_permission_label_vms_subscriber" msgid="5648841182059222299">"Abonenti i VMS-së"</string>
<string name="car_permission_desc_vms_subscriber" msgid="7551009457847673620">"Abonohu te mesazhet VMS"</string>
- <string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"Shërbimi i klientit i VMS-së"</string>
- <string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"Lidh me klientët VMS"</string>
<string name="car_permission_label_storage_monitoring" msgid="2327639346522530549">"Monitorimi i hapësirës ruajtëse të formatit flash"</string>
<string name="car_permission_desc_storage_monitoring" msgid="2075712271139671318">"Monitoro përdorimin e hapësirës ruajtëse të formatit flash"</string>
<string name="car_permission_label_driving_state" msgid="7754624599537393650">"dëgjo gjendjen e lëvizjes me makinë"</string>
diff --git a/service/res/values-sr/strings.xml b/service/res/values-sr/strings.xml
index 53726c6..c4bdc06 100644
--- a/service/res/values-sr/strings.xml
+++ b/service/res/values-sr/strings.xml
@@ -42,8 +42,6 @@
<string name="car_permission_desc_projection" msgid="2352178999656292944">"Омогућава апликацији да пројектује интерфејс са телефона на екран аутомобила."</string>
<string name="car_permission_label_access_projection_status" msgid="4231618890836627402">"приступ статусу пројекције"</string>
<string name="car_permission_desc_access_projection_status" msgid="8497351979100616278">"Дозвољава апликацији да пронађе статус других апликација које пројектују на екран аутомобила."</string>
- <string name="car_permission_label_bind_projection_service" msgid="5362076216606651526">"повезивање са услугом пројекције"</string>
- <string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"Дозвољава власнику да се повеже са интерфејсом услуге пројекције највишег нивоа. Уобичајене апликације никада не би требало да је користе."</string>
<string name="car_permission_label_audio_volume" msgid="310587969373137690">"контролисање јачине звука у аутомобилу"</string>
<string name="car_permission_label_audio_settings" msgid="6524703796944023977">"управљање подешавањима звука у аутомобилу"</string>
<string name="car_permission_label_mock_vehicle_hal" msgid="7198852512207405935">"емулација HAL-а возила"</string>
@@ -62,8 +60,6 @@
<string name="car_permission_desc_car_cluster_control" msgid="9222776665281176031">"Покреће апликације на инструмент табли"</string>
<string name="car_permission_car_monitor_cluster_navigation_state" msgid="7025307242306902441">"Статус кретања на инструмент табли"</string>
<string name="car_permission_desc_car_monitor_cluster_navigation_state" msgid="8745047153878713339">"Откривање промена статуса кретања на инструмент табли"</string>
- <string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"Приказивање на инструмент табли"</string>
- <string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"Прима податке са инструмент табле"</string>
<string name="car_permission_label_car_ux_restrictions_configuration" msgid="6801393970411049725">"Конфигурација ограничења КД-а"</string>
<string name="car_permission_desc_car_ux_restrictions_configuration" msgid="5711926927484813777">"Конфигурише ограничења КД-а"</string>
<string name="car_permission_label_access_private_display_id" msgid="6712116114341634316">"Приступ за читање ИД-у за приватни приказ"</string>
@@ -74,8 +70,6 @@
<string name="car_permission_desc_read_car_occupant_awareness_state" msgid="188865882598414986">"Омогућава читање података о статусу и откривању за Occupant Awareness System"</string>
<string name="car_permission_label_control_car_occupant_awareness_system" msgid="7163330266691094542">"Управљање графиконом за Occupant Awareness System"</string>
<string name="car_permission_desc_control_car_occupant_awareness_system" msgid="7123482622084531911">"Омогућава покретање и заустављање графикона откривања за Occupant Awareness System"</string>
- <string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Услуга аутомобилског уноса"</string>
- <string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Управља догађајима уноса"</string>
<string name="car_permission_label_diag_read" msgid="7248894224877702604">"читање дијагностичких података"</string>
<string name="car_permission_desc_diag_read" msgid="1121426363040966178">"Читање дијагностичких података из аутомобила."</string>
<string name="car_permission_label_diag_clear" msgid="4783070510879698157">"брисање дијагностичких података"</string>
@@ -84,8 +78,6 @@
<string name="car_permission_desc_vms_publisher" msgid="5589489298597386828">"Објављује VMS поруке"</string>
<string name="car_permission_label_vms_subscriber" msgid="5648841182059222299">"Претплатник на VMS поруке"</string>
<string name="car_permission_desc_vms_subscriber" msgid="7551009457847673620">"Претплаћује на VMS поруке"</string>
- <string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"VMS услуга за клијенте"</string>
- <string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"Повезује са VMS клијентима"</string>
<string name="car_permission_label_storage_monitoring" msgid="2327639346522530549">"Праћење флеш меморије"</string>
<string name="car_permission_desc_storage_monitoring" msgid="2075712271139671318">"Надгледа коришћење флеш меморије"</string>
<string name="car_permission_label_driving_state" msgid="7754624599537393650">"слушање стања вожње"</string>
diff --git a/service/res/values-sv/strings.xml b/service/res/values-sv/strings.xml
index 015ba89..623e197 100644
--- a/service/res/values-sv/strings.xml
+++ b/service/res/values-sv/strings.xml
@@ -42,8 +42,6 @@
<string name="car_permission_desc_projection" msgid="2352178999656292944">"Tillåter att en app visar ett gränssnitt från mobilen på bilens skärm."</string>
<string name="car_permission_label_access_projection_status" msgid="4231618890836627402">"åtkomst till projektionsstatus"</string>
<string name="car_permission_desc_access_projection_status" msgid="8497351979100616278">"Tillåter att en app får status från andra appar som visar något på bilens skärm."</string>
- <string name="car_permission_label_bind_projection_service" msgid="5362076216606651526">"bind till projektionstjänst"</string>
- <string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"Innehavaren tillåts att binda till den översta nivåns gränssnitt för en projektionstjänst. Ska inte behövas för vanliga appar."</string>
<string name="car_permission_label_audio_volume" msgid="310587969373137690">"styr bilens ljudvolym"</string>
<string name="car_permission_label_audio_settings" msgid="6524703796944023977">"hantera bilens ljudinställningar"</string>
<string name="car_permission_label_mock_vehicle_hal" msgid="7198852512207405935">"emulera Vehicle HAL"</string>
@@ -62,8 +60,6 @@
<string name="car_permission_desc_car_cluster_control" msgid="9222776665281176031">"Starta appar på bilens digitala instrumentbräda"</string>
<string name="car_permission_car_monitor_cluster_navigation_state" msgid="7025307242306902441">"Status för navigering på bilens digitala instrumentbräda"</string>
<string name="car_permission_desc_car_monitor_cluster_navigation_state" msgid="8745047153878713339">"Lyssna efter ändringar på bilens digitala instrumentbräda"</string>
- <string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"Rendering på digital instrumentbräda"</string>
- <string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"Ta emot data från bilens digitala instrumentbräda"</string>
<string name="car_permission_label_car_ux_restrictions_configuration" msgid="6801393970411049725">"Konfiguration för användningsbegränsningar"</string>
<string name="car_permission_desc_car_ux_restrictions_configuration" msgid="5711926927484813777">"Konfigurera användningsbegränsningar"</string>
<string name="car_permission_label_access_private_display_id" msgid="6712116114341634316">"Läsbehörighet till privat skärm-id"</string>
@@ -74,8 +70,6 @@
<string name="car_permission_desc_read_car_occupant_awareness_state" msgid="188865882598414986">"Tillåter läsning av status och detektionsdata för Occupant Awareness System"</string>
<string name="car_permission_label_control_car_occupant_awareness_system" msgid="7163330266691094542">"Styra diagrammet för Occupant Awareness System"</string>
<string name="car_permission_desc_control_car_occupant_awareness_system" msgid="7123482622084531911">"Tillåter styrning av start och stopp av detektionsdiagrammet för Occupant Awareness System"</string>
- <string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Indatatjänst för bilen"</string>
- <string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Hantera indatahändelser"</string>
<string name="car_permission_label_diag_read" msgid="7248894224877702604">"läsa diagnostikdata"</string>
<string name="car_permission_desc_diag_read" msgid="1121426363040966178">"Läsa diagnostisk data om bilen."</string>
<string name="car_permission_label_diag_clear" msgid="4783070510879698157">"rensa diagnostikdata"</string>
@@ -84,8 +78,6 @@
<string name="car_permission_desc_vms_publisher" msgid="5589489298597386828">"Publicera VMS-meddelanden"</string>
<string name="car_permission_label_vms_subscriber" msgid="5648841182059222299">"VMS-prenumeration"</string>
<string name="car_permission_desc_vms_subscriber" msgid="7551009457847673620">"Prenumerera på VMS-meddelanden"</string>
- <string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"VMS-klienttjänst"</string>
- <string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"Bind till VMS-klienter"</string>
<string name="car_permission_label_storage_monitoring" msgid="2327639346522530549">"Övervaka Flash-lagringsenheter"</string>
<string name="car_permission_desc_storage_monitoring" msgid="2075712271139671318">"Övervaka användning av Flash-lagringsutrymme"</string>
<string name="car_permission_label_driving_state" msgid="7754624599537393650">"reagera på ändringar av bilkörningsläget"</string>
diff --git a/service/res/values-sw/strings.xml b/service/res/values-sw/strings.xml
index 424b28d..08cac41 100644
--- a/service/res/values-sw/strings.xml
+++ b/service/res/values-sw/strings.xml
@@ -42,8 +42,6 @@
<string name="car_permission_desc_projection" msgid="2352178999656292944">"Inaruhusu programu ionyeshe kiolesura cha simu kwenye dashibodi ya gari."</string>
<string name="car_permission_label_access_projection_status" msgid="4231618890836627402">"kufikia hali ya kuonekana kwa skrini"</string>
<string name="car_permission_desc_access_projection_status" msgid="8497351979100616278">"Inaruhusu programu ipate hali za programu zingine zinazoonyesha kwenye dashibodi ya gari."</string>
- <string name="car_permission_label_bind_projection_service" msgid="5362076216606651526">"kupachika kwenye huduma ya kuonyesha skrini"</string>
- <string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"Inaruhusu kishikiliaji kipachikwe katika kiolesura cha kiwango cha juu cha huduma ya kuonyesha. Haipaswi kuhitajika katika programu za kawaida."</string>
<string name="car_permission_label_audio_volume" msgid="310587969373137690">"kudhibiti kiwango cha sauti ya gari"</string>
<string name="car_permission_label_audio_settings" msgid="6524703796944023977">"kudhibiti mipangilio ya sauti ya gari"</string>
<string name="car_permission_label_mock_vehicle_hal" msgid="7198852512207405935">"kuiga HAL ya gari"</string>
@@ -62,8 +60,6 @@
<string name="car_permission_desc_car_cluster_control" msgid="9222776665281176031">"Kuanzisha programu katika kikundi cha data"</string>
<string name="car_permission_car_monitor_cluster_navigation_state" msgid="7025307242306902441">"Hali ya uelekezaji kwenye kikundi cha zana"</string>
<string name="car_permission_desc_car_monitor_cluster_navigation_state" msgid="8745047153878713339">"Sikiliza mabadiliko ya hali ya uelekezaji kwenye kikundi cha zana"</string>
- <string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"Uwasilishaji wa Kikundi cha Zana"</string>
- <string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"Kupokea data ya kikundi cha zana"</string>
<string name="car_permission_label_car_ux_restrictions_configuration" msgid="6801393970411049725">"Mipangilio ya Masharti ya UX"</string>
<string name="car_permission_desc_car_ux_restrictions_configuration" msgid="5711926927484813777">"Weka Mipangilio ya Masharti ya UX"</string>
<string name="car_permission_label_access_private_display_id" msgid="6712116114341634316">"Idhini ya usomaji wa kitambulisho cha onyesho la faragha"</string>
@@ -74,8 +70,6 @@
<string name="car_permission_desc_read_car_occupant_awareness_state" msgid="188865882598414986">"Huruhusu kusoma data ya hali na ya utambuzi ya Mfumo wa Kutambua Waliomo"</string>
<string name="car_permission_label_control_car_occupant_awareness_system" msgid="7163330266691094542">"Kudhibiti Grafu ya Mfumo wa Kutambua Waliomo"</string>
<string name="car_permission_desc_control_car_occupant_awareness_system" msgid="7123482622084531911">"Huruhusu udhibiti wa kuanzisha na kusimamisha grafu ya utambuzi ya Mfumo wa Kutambua Waliomo"</string>
- <string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Huduma ya Kuweka Data ya Gari"</string>
- <string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Kudhibiti matukio ya kuweka data"</string>
<string name="car_permission_label_diag_read" msgid="7248894224877702604">"kusoma data ya uchunguzi"</string>
<string name="car_permission_desc_diag_read" msgid="1121426363040966178">"Kusoma data ya uchunguzi kwenye gari."</string>
<string name="car_permission_label_diag_clear" msgid="4783070510879698157">"kufuta data ya uchunguzi wa gari"</string>
@@ -84,8 +78,6 @@
<string name="car_permission_desc_vms_publisher" msgid="5589489298597386828">"Ichapishe ujumbe wa VMS"</string>
<string name="car_permission_label_vms_subscriber" msgid="5648841182059222299">"Programu zinaweza kujisajili illi zitumie data ya VMS"</string>
<string name="car_permission_desc_vms_subscriber" msgid="7551009457847673620">"Jisajili ili upokee ujumbe wa VMS"</string>
- <string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"Huduma ya Viteja vya VMS"</string>
- <string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"Ipachike kwenye viteja vya VMS"</string>
<string name="car_permission_label_storage_monitoring" msgid="2327639346522530549">"Kuchunguza nafasi ya kifaa cha kuhifadhi data"</string>
<string name="car_permission_desc_storage_monitoring" msgid="2075712271139671318">"Kudhibiti matumizi ya kifaa cha kuhifadhi"</string>
<string name="car_permission_label_driving_state" msgid="7754624599537393650">"kusikiliza hali ya kuendesha gari"</string>
diff --git a/service/res/values-ta/strings.xml b/service/res/values-ta/strings.xml
index 5b54dba..4b9987f 100644
--- a/service/res/values-ta/strings.xml
+++ b/service/res/values-ta/strings.xml
@@ -42,8 +42,6 @@
<string name="car_permission_desc_projection" msgid="2352178999656292944">"மொபைலில் உள்ளவற்றைக் காரின் திரையில் காட்ட ஆப்ஸை அனுமதிக்கிறது."</string>
<string name="car_permission_label_access_projection_status" msgid="4231618890836627402">"காட்சிப்படுத்தல் நிலையை அணுக வேண்டும்"</string>
<string name="car_permission_desc_access_projection_status" msgid="8497351979100616278">"காரின் திரையில் காட்டப்படும் மற்ற ஆப்ஸின் நிலையை அறிய ஆப்ஸை அனுமதிக்கிறது."</string>
- <string name="car_permission_label_bind_projection_service" msgid="5362076216606651526">"காட்சிப்படுத்தல் சேவையுடன் இணைக்க வேண்டும்"</string>
- <string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"காட்சிப்படுத்தல் சேவையின் உயர் நிலை இடைமுகத்துடன் இணைப்பதற்கு ஹோல்டரை அனுமதிக்கிறது. வழக்கமான ஆப்ஸிற்கு எப்போதுமே தேவைப்படாது."</string>
<string name="car_permission_label_audio_volume" msgid="310587969373137690">"காரின் ஆடியோ அளவை நிர்வகிக்க வேண்டும்"</string>
<string name="car_permission_label_audio_settings" msgid="6524703796944023977">"காரின் ஆடியோ அமைப்புகளை நிர்வகிக்க வேண்டும்"</string>
<string name="car_permission_label_mock_vehicle_hal" msgid="7198852512207405935">"வாகனத்தின் HAL போன்றே இன்னொன்றை உருவாக்க வேண்டும்"</string>
@@ -62,8 +60,6 @@
<string name="car_permission_desc_car_cluster_control" msgid="9222776665281176031">"இன்ஸ்ட்ருமெண்ட் கிளஸ்டரில் ஆப்ஸை அறிமுகம் செய்தல்"</string>
<string name="car_permission_car_monitor_cluster_navigation_state" msgid="7025307242306902441">"இன்ஸ்ட்ருமெண்ட் கிளஸ்டர் வழிசெலுத்தல் நிலை"</string>
<string name="car_permission_desc_car_monitor_cluster_navigation_state" msgid="8745047153878713339">"இன்ஸ்ட்ருமெண்ட் கிளஸ்டர் வழிசெலுத்தல் நிலையில் ஏற்படும் மாற்றங்களைக் கேளுங்கள்"</string>
- <string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"இன்ஸ்ட்ருமெண்ட் கிளஸ்டரை ஒழுங்கமைத்தல்"</string>
- <string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"இன்ஸ்ட்ருமெண்ட் கிளஸ்டர் தரவைப் பெறுதல்"</string>
<string name="car_permission_label_car_ux_restrictions_configuration" msgid="6801393970411049725">"UX கட்டுப்பாடுகள் உள்ளமைவு"</string>
<string name="car_permission_desc_car_ux_restrictions_configuration" msgid="5711926927484813777">"UX கட்டுப்பாடுகளை உள்ளமைத்தல்"</string>
<string name="car_permission_label_access_private_display_id" msgid="6712116114341634316">"தனிப்பட்ட காட்சி ஐடிக்குப் படிப்பதற்கான அணுகல்"</string>
@@ -74,8 +70,6 @@
<string name="car_permission_desc_read_car_occupant_awareness_state" msgid="188865882598414986">"உள்ளிருப்போருக்கான விழிப்புணர்வு சிஸ்டத்திற்கு வாசிக்கும் நிலையையும் கண்டறிதல் தரவையும் அனுமதிக்கிறது"</string>
<string name="car_permission_label_control_car_occupant_awareness_system" msgid="7163330266691094542">"உள்ளிருப்போருக்கான விழிப்புணர்வு சிஸ்டத்தின் வரைபடத்தைக் கட்டுப்படுத்த வேண்டும்"</string>
<string name="car_permission_desc_control_car_occupant_awareness_system" msgid="7123482622084531911">"உள்ளிருப்போருக்கான விழிப்புணர்வு சிஸ்டத்தின் கண்டறிதல் வரைபடத்தை தொடங்குவதற்கும் நிறுத்துவதற்கும் கட்டுப்படுத்த அனுமதிக்கிறது"</string>
- <string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"காருக்கு உற்பத்தியாளர் வழங்கும் சேவை"</string>
- <string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"உற்பத்தியாளர் வழங்கும் சேவைகளைக் கையாளுதல்"</string>
<string name="car_permission_label_diag_read" msgid="7248894224877702604">"ஆய்வுத் தரவை அறிய வேண்டும்"</string>
<string name="car_permission_desc_diag_read" msgid="1121426363040966178">"கார் தொடர்பான ஆய்வுத் தரவை அறிய வேண்டும்."</string>
<string name="car_permission_label_diag_clear" msgid="4783070510879698157">"ஆய்வுத் தரவை அழிக்க வேண்டும்"</string>
@@ -84,8 +78,6 @@
<string name="car_permission_desc_vms_publisher" msgid="5589489298597386828">"VMS மெசேஜ்களை அனுப்புதல்"</string>
<string name="car_permission_label_vms_subscriber" msgid="5648841182059222299">"VMS சந்தாதாரர்"</string>
<string name="car_permission_desc_vms_subscriber" msgid="7551009457847673620">"VMS மெசேஜ்களை பெறுதல்"</string>
- <string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"VMS கிளையண்ட் சேவை"</string>
- <string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"VMS கிளையண்ட்டுகளுடன் இணைத்தல்"</string>
<string name="car_permission_label_storage_monitoring" msgid="2327639346522530549">"ஃபிளாஷ் சேமிப்பகத்தைக் கண்காணித்தல்"</string>
<string name="car_permission_desc_storage_monitoring" msgid="2075712271139671318">"ஃபிளாஷ் சேமிப்பகத்தின் உபயோகத்தைக் கண்காணித்தல்"</string>
<string name="car_permission_label_driving_state" msgid="7754624599537393650">"கார் ஓட்டப்படும் நிலையைக் கவனிக்க வேண்டும்"</string>
diff --git a/service/res/values-te/strings.xml b/service/res/values-te/strings.xml
index d58b733..3dc67d3 100644
--- a/service/res/values-te/strings.xml
+++ b/service/res/values-te/strings.xml
@@ -42,8 +42,6 @@
<string name="car_permission_desc_projection" msgid="2352178999656292944">"కార్ డిస్ప్లేలో ఫోన్ నుండి ఇంటర్ఫేస్ను రూపొందించడానికి యాప్ను అనుమతిస్తుంది."</string>
<string name="car_permission_label_access_projection_status" msgid="4231618890836627402">"ప్రొజెక్షన్ స్టేటస్ని యాక్సెస్ చేయగలవు"</string>
<string name="car_permission_desc_access_projection_status" msgid="8497351979100616278">"కార్ డిస్ప్లేకి ప్రొజెక్ట్ చేసే ఇతర యాప్ల స్టేటస్ పొందడానికి యాప్ను అనుమతిస్తుంది."</string>
- <string name="car_permission_label_bind_projection_service" msgid="5362076216606651526">"ప్రొజెక్షన్ సేవకు అనుబంధించగలవు"</string>
- <string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"ప్రొజెక్షన్ సేవ యొక్క అగ్ర-స్థాయి ఇంటర్ఫేస్కు అనుబంధించడానికి హోల్డర్ను అనుమతిస్తుంది. సాధారణ యాప్లకు ఎప్పటికీ దీని అవసరం లేదు."</string>
<string name="car_permission_label_audio_volume" msgid="310587969373137690">"కారు ఆడియోను నియత్రించగలవు"</string>
<string name="car_permission_label_audio_settings" msgid="6524703796944023977">"కారు ఆడియో సెట్టింగ్లను నియంత్రించగలవు"</string>
<string name="car_permission_label_mock_vehicle_hal" msgid="7198852512207405935">"వాహన HALను అనుకరించగలవు"</string>
@@ -55,15 +53,13 @@
<string name="car_permission_label_control_app_blocking" msgid="9112678596919993386">"యాప్ బ్లాక్ చేయడం"</string>
<string name="car_permission_desc_control_app_blocking" msgid="7539378161760696190">"డ్రైవింగ్లో ఉన్నప్పుడు అప్లికేషన్లను బ్లాక్ చేయండి"</string>
<string name="car_permission_car_navigation_manager" msgid="5895461364007854077">"నావిగేషన్ మేనేజర్"</string>
- <string name="car_permission_desc_car_navigation_manager" msgid="6188751054665471537">"పరికర గుంపుకు నావిగేషన్ డేటాను రిపోర్ట్ చేయండి"</string>
+ <string name="car_permission_desc_car_navigation_manager" msgid="6188751054665471537">"పరికర గుంపుకు నావిగేషన్ డేటాని రిపోర్ట్ చేయండి"</string>
<string name="car_permission_car_display_in_cluster" msgid="4005987646292458684">"పరికర గుంపుకు ప్రత్యక్ష రెండరింగ్"</string>
<string name="car_permission_desc_car_display_in_cluster" msgid="2668300546822672927">"పరికర గుంపులో ప్రదర్శించాల్సిన కార్యకలాపలని తెలియచెప్పడానికి అప్లికేషన్ను అనుమతించండి."</string>
<string name="car_permission_car_cluster_control" msgid="1382247204230165674">"పరికర గుంపు నియంత్రణ"</string>
<string name="car_permission_desc_car_cluster_control" msgid="9222776665281176031">"పరికర గుంపు యాప్లను ప్రారంభించండి"</string>
<string name="car_permission_car_monitor_cluster_navigation_state" msgid="7025307242306902441">"పరికర క్లస్టర్ నావిగేషన్ స్టేట్"</string>
<string name="car_permission_desc_car_monitor_cluster_navigation_state" msgid="8745047153878713339">"పరికర క్లస్టర్ నావిగేషన్ స్టేట్ మార్పులను వినండి"</string>
- <string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"పరికర గుంపు రెండరింగ్"</string>
- <string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"పరికర గుంపు డేటాను పొందండి"</string>
<string name="car_permission_label_car_ux_restrictions_configuration" msgid="6801393970411049725">"UX పరిమితుల కాన్ఫిగరేషన్"</string>
<string name="car_permission_desc_car_ux_restrictions_configuration" msgid="5711926927484813777">"UX పరిమితులను కాన్ఫిగర్ చేయండి"</string>
<string name="car_permission_label_access_private_display_id" msgid="6712116114341634316">"ప్రైవేట్ డిస్ప్లే idకి చదివే యాక్సెస్"</string>
@@ -74,18 +70,14 @@
<string name="car_permission_desc_read_car_occupant_awareness_state" msgid="188865882598414986">"Occupant Awareness Systemకు చదివే స్టేటస్ని, డేటాను గుర్తించడాన్ని అనుమతిస్తుంది"</string>
<string name="car_permission_label_control_car_occupant_awareness_system" msgid="7163330266691094542">"Occupant Awareness System గ్రాఫ్ను నియంత్రించు"</string>
<string name="car_permission_desc_control_car_occupant_awareness_system" msgid="7123482622084531911">"Occupant Awareness Systemను గుర్తించే గ్రాఫ్ను ప్రారంభించడాన్ని, ఆపివేయడాన్ని నియంత్రించడానికి అనుమతిస్తుంది"</string>
- <string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"కారు ఇన్పుట్ సేవ"</string>
- <string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"ఇన్పుట్ ఈవెంట్లను హ్యాండిల్ చేయండి"</string>
<string name="car_permission_label_diag_read" msgid="7248894224877702604">"సమస్య విశ్లేషణ డేటాను తెలుసుకోగలవు"</string>
<string name="car_permission_desc_diag_read" msgid="1121426363040966178">"కారు నుండి విశ్లేషణ డేటాను తెలుసుకోగలవు."</string>
<string name="car_permission_label_diag_clear" msgid="4783070510879698157">"సమస్య విశ్లేషణ డేటాను క్లియర్ చేయగలవు"</string>
<string name="car_permission_desc_diag_clear" msgid="7453222114866042786">"కారు నుండి సమస్య విశ్లేషణ డేటాను క్లియర్ చేయగలవు."</string>
- <string name="car_permission_label_vms_publisher" msgid="3049934078926106641">"VMS పబ్లిషర్"</string>
+ <string name="car_permission_label_vms_publisher" msgid="3049934078926106641">"VMS ప్రచురణకర్త"</string>
<string name="car_permission_desc_vms_publisher" msgid="5589489298597386828">"VMS మెసేజ్లను పబ్లిష్ చేయండి"</string>
- <string name="car_permission_label_vms_subscriber" msgid="5648841182059222299">"VMS సబ్స్క్రయిబర్"</string>
+ <string name="car_permission_label_vms_subscriber" msgid="5648841182059222299">"VMS సభ్యులు"</string>
<string name="car_permission_desc_vms_subscriber" msgid="7551009457847673620">"VMS మెసేజ్లను పొందడానికి సబ్స్క్రయిబ్ చేయండి"</string>
- <string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"VMS క్లయింట్ సేవ"</string>
- <string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"VMS క్లయింట్లను ఆచరించండి"</string>
<string name="car_permission_label_storage_monitoring" msgid="2327639346522530549">"ఫ్లాష్ నిల్వ పర్యవేక్షణ"</string>
<string name="car_permission_desc_storage_monitoring" msgid="2075712271139671318">"ఫ్లాష్ నిల్వ వినియోగాన్ని పర్యవేక్షించండి"</string>
<string name="car_permission_label_driving_state" msgid="7754624599537393650">"డ్రైవింగ్ స్థితి మార్పులను వినగలవు"</string>
diff --git a/service/res/values-th/strings.xml b/service/res/values-th/strings.xml
index 7c1908d..b04eabe 100644
--- a/service/res/values-th/strings.xml
+++ b/service/res/values-th/strings.xml
@@ -42,8 +42,6 @@
<string name="car_permission_desc_projection" msgid="2352178999656292944">"อนุญาตให้แอปฉายภาพอินเทอร์เฟซจากโทรศัพท์ไปยังจอแสดงผลของรถยนต์"</string>
<string name="car_permission_label_access_projection_status" msgid="4231618890836627402">"เข้าถึงสถานะการฉายภาพ"</string>
<string name="car_permission_desc_access_projection_status" msgid="8497351979100616278">"อนุญาตให้แอปดูสถานะของแอปอื่นๆ ที่กำลังฉายภาพไปยังจอแสดงผลของรถยนต์"</string>
- <string name="car_permission_label_bind_projection_service" msgid="5362076216606651526">"เชื่อมโยงกับบริการการฉายภาพ"</string>
- <string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"อนุญาตให้เจ้าของเชื่อมโยงกับอินเทอร์เฟซระดับบนสุดของบริการการฉายภาพ ไม่ควรต้องใช้สำหรับแอปทั่วไป"</string>
<string name="car_permission_label_audio_volume" msgid="310587969373137690">"ควบคุมระดับเสียงของระบบเสียงในรถ"</string>
<string name="car_permission_label_audio_settings" msgid="6524703796944023977">"จัดการการตั้งค่าระบบเสียงของรถ"</string>
<string name="car_permission_label_mock_vehicle_hal" msgid="7198852512207405935">"เลียนแบบ HAL ยานพาหนะ"</string>
@@ -62,8 +60,6 @@
<string name="car_permission_desc_car_cluster_control" msgid="9222776665281176031">"เปิดแอปต่างๆ ในแผงหน้าปัด"</string>
<string name="car_permission_car_monitor_cluster_navigation_state" msgid="7025307242306902441">"สถานะการนำทางในแผงหน้าปัด"</string>
<string name="car_permission_desc_car_monitor_cluster_navigation_state" msgid="8745047153878713339">"ฟังการเปลี่ยนแปลงของสถานะการนำทางในแผงหน้าปัด"</string>
- <string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"การแสดงผลแผงหน้าปัด"</string>
- <string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"รับข้อมูลจากแผงหน้าปัด"</string>
<string name="car_permission_label_car_ux_restrictions_configuration" msgid="6801393970411049725">"การกำหนดค่าข้อจำกัด UX"</string>
<string name="car_permission_desc_car_ux_restrictions_configuration" msgid="5711926927484813777">"กำหนดค่าข้อจำกัด UX"</string>
<string name="car_permission_label_access_private_display_id" msgid="6712116114341634316">"สิทธิ์เข้าถึงแบบอ่านสำหรับรหัสการแสดงผลส่วนตัว"</string>
@@ -74,8 +70,6 @@
<string name="car_permission_desc_read_car_occupant_awareness_state" msgid="188865882598414986">"อนุญาตการอ่านข้อมูลสถานะและการตรวจจับของระบบการรับรู้ว่ามีคนอยู่"</string>
<string name="car_permission_label_control_car_occupant_awareness_system" msgid="7163330266691094542">"ควบคุมกราฟระบบการรับรู้ว่ามีคนอยู่"</string>
<string name="car_permission_desc_control_car_occupant_awareness_system" msgid="7123482622084531911">"อนุญาตการเริ่มต้นและหยุดกราฟการตรวจจับของระบบการรับรู้ว่ามีคนอยู่"</string>
- <string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"บริการป้อนข้อมูลของรถ"</string>
- <string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"จัดการเหตุการณ์การป้อนข้อมูล"</string>
<string name="car_permission_label_diag_read" msgid="7248894224877702604">"อ่านข้อมูลการวินิจฉัย"</string>
<string name="car_permission_desc_diag_read" msgid="1121426363040966178">"อ่านข้อมูลการวินิจฉัยจากรถ"</string>
<string name="car_permission_label_diag_clear" msgid="4783070510879698157">"ล้างข้อมูลการวินิจฉัย"</string>
@@ -84,8 +78,6 @@
<string name="car_permission_desc_vms_publisher" msgid="5589489298597386828">"เผยแพร่ข้อความ VMS"</string>
<string name="car_permission_label_vms_subscriber" msgid="5648841182059222299">"ผู้สมัครรับข้อมูล VMS"</string>
<string name="car_permission_desc_vms_subscriber" msgid="7551009457847673620">"สมัครรับข้อมูล VMS"</string>
- <string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"บริการไคลเอ็นต์ VMS"</string>
- <string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"เชื่อมโยงกับไคลเอ็นต์ VMS"</string>
<string name="car_permission_label_storage_monitoring" msgid="2327639346522530549">"การตรวจสอบพื้นที่เก็บข้อมูลแฟลช"</string>
<string name="car_permission_desc_storage_monitoring" msgid="2075712271139671318">"ตรวจสอบการใช้งานพื้นที่เก็บข้อมูลแฟลช"</string>
<string name="car_permission_label_driving_state" msgid="7754624599537393650">"ฟังสถานะการขับรถ"</string>
diff --git a/service/res/values-tl/strings.xml b/service/res/values-tl/strings.xml
index c30966b..e51e12e 100644
--- a/service/res/values-tl/strings.xml
+++ b/service/res/values-tl/strings.xml
@@ -42,8 +42,6 @@
<string name="car_permission_desc_projection" msgid="2352178999656292944">"Binibigyang-daan ang isang app na mag-project ng interface mula sa isang telepono sa display ng sasakyan."</string>
<string name="car_permission_label_access_projection_status" msgid="4231618890836627402">"i-access ang status ng projection"</string>
<string name="car_permission_desc_access_projection_status" msgid="8497351979100616278">"Binibigyang-daan ang isang app na kunin ang status ng iba pang app na nagpo-project sa display ng sasakyan."</string>
- <string name="car_permission_label_bind_projection_service" msgid="5362076216606651526">"sumailalim sa isang serbisyo sa projection"</string>
- <string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"Binibigyang-daan ang may-ari na sumailalim sa nangungunang interface ng isang serbisyo sa projection. Hindi kailanman dapat na kailanganin para sa mga karaniwang app."</string>
<string name="car_permission_label_audio_volume" msgid="310587969373137690">"kontrolin ang volume ng audio ng sasakyan"</string>
<string name="car_permission_label_audio_settings" msgid="6524703796944023977">"pamahalaan ang mga setting ng audio ng sasakyan"</string>
<string name="car_permission_label_mock_vehicle_hal" msgid="7198852512207405935">"gayahin ang HAL ng sasakyan"</string>
@@ -62,8 +60,6 @@
<string name="car_permission_desc_car_cluster_control" msgid="9222776665281176031">"Ilunsad ang mga app sa cluster ng instrumento"</string>
<string name="car_permission_car_monitor_cluster_navigation_state" msgid="7025307242306902441">"Status ng pag-navigate sa cluster ng instrumento"</string>
<string name="car_permission_desc_car_monitor_cluster_navigation_state" msgid="8745047153878713339">"Makinig para sa mga pagbabago sa status ng pag-navigate sa cluster ng instrumento"</string>
- <string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"Pag-render ng Cluster ng Instrumento"</string>
- <string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"Makatanggap ng data ng cluster ng instrumento"</string>
<string name="car_permission_label_car_ux_restrictions_configuration" msgid="6801393970411049725">"Configuration ng Mga Paghihigpit sa UX"</string>
<string name="car_permission_desc_car_ux_restrictions_configuration" msgid="5711926927484813777">"I-configure ang Mga Paghihigpit sa UX"</string>
<string name="car_permission_label_access_private_display_id" msgid="6712116114341634316">"Access sa pagbasa sa pribadong display id"</string>
@@ -74,8 +70,6 @@
<string name="car_permission_desc_read_car_occupant_awareness_state" msgid="188865882598414986">"Pinapayagan ang pagbasa sa status at data ng pag-detect para sa Occupant Awareness System"</string>
<string name="car_permission_label_control_car_occupant_awareness_system" msgid="7163330266691094542">"Kontrolin ang Graph ng Occupant Awareness System"</string>
<string name="car_permission_desc_control_car_occupant_awareness_system" msgid="7123482622084531911">"Pinapayagan ang pagkontrol sa pagsimula at paghinto sa detection graph ng Occupant Awareness System"</string>
- <string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Serbisyo sa Input ng Sasakyan"</string>
- <string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Pangasiwaan ang mga event ng input"</string>
<string name="car_permission_label_diag_read" msgid="7248894224877702604">"basahin ang data ng mga diagnostic"</string>
<string name="car_permission_desc_diag_read" msgid="1121426363040966178">"Basahin ang data ng mga diagnostic mula sa sasakyan."</string>
<string name="car_permission_label_diag_clear" msgid="4783070510879698157">"i-clear ang data ng mga diagnostic"</string>
@@ -84,8 +78,6 @@
<string name="car_permission_desc_vms_publisher" msgid="5589489298597386828">"Mag-publish ng mga mensahe ng VMS"</string>
<string name="car_permission_label_vms_subscriber" msgid="5648841182059222299">"Subscriber ng VMS"</string>
<string name="car_permission_desc_vms_subscriber" msgid="7551009457847673620">"Mag-subscribe sa mga mensahe ng VMS"</string>
- <string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"Serbisyo ng VMS Client"</string>
- <string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"Sumailalim sa mga VMS client"</string>
<string name="car_permission_label_storage_monitoring" msgid="2327639346522530549">"Pagsubaybay sa storage ng flash"</string>
<string name="car_permission_desc_storage_monitoring" msgid="2075712271139671318">"Subaybayan ang paggamit ng storage ng flash"</string>
<string name="car_permission_label_driving_state" msgid="7754624599537393650">"makinig sa status ng pagmamaneho"</string>
diff --git a/service/res/values-tr/strings.xml b/service/res/values-tr/strings.xml
index 0a56594..176b227 100644
--- a/service/res/values-tr/strings.xml
+++ b/service/res/values-tr/strings.xml
@@ -42,8 +42,6 @@
<string name="car_permission_desc_projection" msgid="2352178999656292944">"Uygulamaların, telefon arayüzünü araç ekranına yansıtmasına izin verir."</string>
<string name="car_permission_label_access_projection_status" msgid="4231618890836627402">"projeksiyon durumuna erişim"</string>
<string name="car_permission_desc_access_projection_status" msgid="8497351979100616278">"Bir uygulamanın, araç ekranına bir şeyler yansıtan diğer uygulamaların durumunu almasına izin verir."</string>
- <string name="car_permission_label_bind_projection_service" msgid="5362076216606651526">"projeksiyon hizmetine bağlanma"</string>
- <string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"Cihazın sahibine bir projeksiyon hizmetinin en üst düzey arayüzüne bağlanma izni verir. Normal uygulamalarda hiçbir zaman gerek duyulmaz."</string>
<string name="car_permission_label_audio_volume" msgid="310587969373137690">"aracın ses düzeyini kontrol etme"</string>
<string name="car_permission_label_audio_settings" msgid="6524703796944023977">"aracın ses ayarlarını yönetme"</string>
<string name="car_permission_label_mock_vehicle_hal" msgid="7198852512207405935">"araç HAL\'sini taklit etme"</string>
@@ -62,8 +60,6 @@
<string name="car_permission_desc_car_cluster_control" msgid="9222776665281176031">"Gösterge grubunda uygulamaları başlatma"</string>
<string name="car_permission_car_monitor_cluster_navigation_state" msgid="7025307242306902441">"Gösterge grubu navigasyon durumu"</string>
<string name="car_permission_desc_car_monitor_cluster_navigation_state" msgid="8745047153878713339">"Gösterge grubu navigasyon durumundaki değişiklikleri dinleme"</string>
- <string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"Gösterge Grubunda Oluşturma"</string>
- <string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"Gösterge grubu verilerini alma"</string>
<string name="car_permission_label_car_ux_restrictions_configuration" msgid="6801393970411049725">"Kullanıcı Deneyimi Kısıtlamaları Yapılandırması"</string>
<string name="car_permission_desc_car_ux_restrictions_configuration" msgid="5711926927484813777">"Kullanıcı Deneyimi Kısıtlamalarını Yapılandırma"</string>
<string name="car_permission_label_access_private_display_id" msgid="6712116114341634316">"Gizli görüntüleme kimliğine okuma erişimi"</string>
@@ -74,8 +70,6 @@
<string name="car_permission_desc_read_car_occupant_awareness_state" msgid="188865882598414986">"Yolcu Algılama Sistemi için durumun ve tespit verilerinin okunmasına izin verir"</string>
<string name="car_permission_label_control_car_occupant_awareness_system" msgid="7163330266691094542">"Yolcu Algılama Sistemi Grafiğini kontrol et"</string>
<string name="car_permission_desc_control_car_occupant_awareness_system" msgid="7123482622084531911">"Yolcu Algılama Sistemi tespit grafiğinin başlatılmasının ve durdurulmasının kontrol edilmesine izin verir"</string>
- <string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Araç Giriş Hizmeti"</string>
- <string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Giriş olaylarını işleme"</string>
<string name="car_permission_label_diag_read" msgid="7248894224877702604">"teşhis verilerini okuma"</string>
<string name="car_permission_desc_diag_read" msgid="1121426363040966178">"Araçtan teşhis verilerini okuma."</string>
<string name="car_permission_label_diag_clear" msgid="4783070510879698157">"teşhis verilerini temizleme"</string>
@@ -84,8 +78,6 @@
<string name="car_permission_desc_vms_publisher" msgid="5589489298597386828">"VMS mesajlarını yayınla"</string>
<string name="car_permission_label_vms_subscriber" msgid="5648841182059222299">"VMS Abonesi"</string>
<string name="car_permission_desc_vms_subscriber" msgid="7551009457847673620">"VMS mesajlarına abone ol"</string>
- <string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"VMS İstemci Hizmeti"</string>
- <string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"VMS istemcilerine bağla"</string>
<string name="car_permission_label_storage_monitoring" msgid="2327639346522530549">"Flash depolama alanını izleme"</string>
<string name="car_permission_desc_storage_monitoring" msgid="2075712271139671318">"Flash depolama alanı kullanımını izleme"</string>
<string name="car_permission_label_driving_state" msgid="7754624599537393650">"araç kullanma durumunu dinleme"</string>
diff --git a/service/res/values-uk/strings.xml b/service/res/values-uk/strings.xml
index 8374e6d..070e447 100644
--- a/service/res/values-uk/strings.xml
+++ b/service/res/values-uk/strings.xml
@@ -42,8 +42,6 @@
<string name="car_permission_desc_projection" msgid="2352178999656292944">"Дозволяє додатку відображати інтерфейс телефона на дисплеї автомобіля."</string>
<string name="car_permission_label_access_projection_status" msgid="4231618890836627402">"доступ до статусу проекції"</string>
<string name="car_permission_desc_access_projection_status" msgid="8497351979100616278">"Дозволяє додатку отримувати статус інших додатків, які відображаються на дисплеї автомобіля."</string>
- <string name="car_permission_label_bind_projection_service" msgid="5362076216606651526">"зв’язок із сервісом проекції"</string>
- <string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"Дозволяє власникові прив’язуватися до інтерфейсу верхнього рівня сервісу проекції. Ніколи не застосовується для звичайних додатків."</string>
<string name="car_permission_label_audio_volume" msgid="310587969373137690">"керування гучністю аудіосистеми автомобіля"</string>
<string name="car_permission_label_audio_settings" msgid="6524703796944023977">"керування налаштуваннями аудіосистеми автомобіля"</string>
<string name="car_permission_label_mock_vehicle_hal" msgid="7198852512207405935">"імітація рівня HAL автомобіля"</string>
@@ -62,8 +60,6 @@
<string name="car_permission_desc_car_cluster_control" msgid="9222776665281176031">"Запуск додатків на панелі приладів"</string>
<string name="car_permission_car_monitor_cluster_navigation_state" msgid="7025307242306902441">"Стан навігації групи інструментів"</string>
<string name="car_permission_desc_car_monitor_cluster_navigation_state" msgid="8745047153878713339">"Відстежуйте зміни стану навігації групи інструментів."</string>
- <string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"Відображення панелі приладів"</string>
- <string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"Отримувати дані з панелі приладів"</string>
<string name="car_permission_label_car_ux_restrictions_configuration" msgid="6801393970411049725">"Конфігурація обмежень використання функцій"</string>
<string name="car_permission_desc_car_ux_restrictions_configuration" msgid="5711926927484813777">"Налаштувати обмеження щодо використання функцій"</string>
<string name="car_permission_label_access_private_display_id" msgid="6712116114341634316">"Доступ для читання ідентифікаторів приватних екранів"</string>
@@ -74,8 +70,6 @@
<string name="car_permission_desc_read_car_occupant_awareness_state" msgid="188865882598414986">"Дозволяє переглядати статус і дані системи визначення присутності пасажира"</string>
<string name="car_permission_label_control_car_occupant_awareness_system" msgid="7163330266691094542">"Керування графіком визначення присутності пасажира"</string>
<string name="car_permission_desc_control_car_occupant_awareness_system" msgid="7123482622084531911">"Дозволяє керувати графіком визначення присутності пасажира"</string>
- <string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Сервіс даних про вхідні події автомобіля"</string>
- <string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Обробка вхідних подій"</string>
<string name="car_permission_label_diag_read" msgid="7248894224877702604">"перегляд даних діагностики"</string>
<string name="car_permission_desc_diag_read" msgid="1121426363040966178">"Перегляд даних діагностики автомобіля."</string>
<string name="car_permission_label_diag_clear" msgid="4783070510879698157">"очищення даних діагностики"</string>
@@ -84,8 +78,6 @@
<string name="car_permission_desc_vms_publisher" msgid="5589489298597386828">"Надсилати дорожні повідомлення"</string>
<string name="car_permission_label_vms_subscriber" msgid="5648841182059222299">"Підписуватися на дорожні повідомлення"</string>
<string name="car_permission_desc_vms_subscriber" msgid="7551009457847673620">"Отримувати дорожні повідомлення"</string>
- <string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"Виконувати функції клієнтського сервісу дорожніх повідомлень"</string>
- <string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"Зв’язуватися з клієнтами дорожніх повідомлень"</string>
<string name="car_permission_label_storage_monitoring" msgid="2327639346522530549">"Відстеження флеш-пам’яті"</string>
<string name="car_permission_desc_storage_monitoring" msgid="2075712271139671318">"Відстеження використання флеш-пам’яті"</string>
<string name="car_permission_label_driving_state" msgid="7754624599537393650">"відстеження стану кермування"</string>
diff --git a/service/res/values-ur/strings.xml b/service/res/values-ur/strings.xml
index 2e304ef..2047e43 100644
--- a/service/res/values-ur/strings.xml
+++ b/service/res/values-ur/strings.xml
@@ -42,8 +42,6 @@
<string name="car_permission_desc_projection" msgid="2352178999656292944">"کار کے ڈسپلے پر، ایپ، فون سے انٹرفیس پروجیکٹ کر سکتی ہے۔"</string>
<string name="car_permission_label_access_projection_status" msgid="4231618890836627402">"پروجیکشن کی صورتحال تک رسائی حاصل کریں"</string>
<string name="car_permission_desc_access_projection_status" msgid="8497351979100616278">"ایپ، کار کے ڈسپلے پر پروجیکٹ کی جا رہیں دیگر ایپس کی صورتحال حاصل کر سکتی ہے۔"</string>
- <string name="car_permission_label_bind_projection_service" msgid="5362076216606651526">"کسی پروجیکشن سروس کا پابند بنیں"</string>
- <string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"حامل کو پروجیکشن سروس کے اعلی سطحی انٹرفیس کا پابند ہونے کی اجازت دیتا ہے۔ عام ایپس کے لیے کبھی بھی اس کی ضرورت نہيں ہونی چاہئے۔"</string>
<string name="car_permission_label_audio_volume" msgid="310587969373137690">"کار کی آڈیو والیوم کو کنٹرول کریں"</string>
<string name="car_permission_label_audio_settings" msgid="6524703796944023977">"کار کی آڈیو کی ترتیبات کا نظم کریں"</string>
<string name="car_permission_label_mock_vehicle_hal" msgid="7198852512207405935">"HAL گاڑی کی تقلید کریں"</string>
@@ -62,8 +60,6 @@
<string name="car_permission_desc_car_cluster_control" msgid="9222776665281176031">"آلہ کے گروہ میں اپپس کو شروع کریں"</string>
<string name="car_permission_car_monitor_cluster_navigation_state" msgid="7025307242306902441">"انسٹرومنٹ کلسٹر نیویگیشن اسٹیٹس"</string>
<string name="car_permission_desc_car_monitor_cluster_navigation_state" msgid="8745047153878713339">"انسٹرومنٹ کلسٹر نیویگیشن اسٹیٹس میں تبدیلیوں کے لیے سنیں"</string>
- <string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"آلہ کے گروہ کی رینڈرنگ"</string>
- <string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"آلہ کے گروہ کا ڈیٹا موصول کریں"</string>
<string name="car_permission_label_car_ux_restrictions_configuration" msgid="6801393970411049725">"UX کی پابندیوں کی ترتیب"</string>
<string name="car_permission_desc_car_ux_restrictions_configuration" msgid="5711926927484813777">"UX کی پابندیاں ترتیب دیں"</string>
<string name="car_permission_label_access_private_display_id" msgid="6712116114341634316">"نجی ڈسپلے ID تک پڑھنے کی رسائی"</string>
@@ -74,8 +70,6 @@
<string name="car_permission_desc_read_car_occupant_awareness_state" msgid="188865882598414986">"کار میں بیٹھنے والے فرد کے لیے بنے آگاہی کے سسٹم کیلئے پڑھنے کی حیثیت اور ڈیٹا کا پتہ لگانے کی اجازت دیتا ہے"</string>
<string name="car_permission_label_control_car_occupant_awareness_system" msgid="7163330266691094542">"کار میں بیٹھنے والے فرد کے لیے بنے آگاہی کے سسٹم کے گراف کو کنٹرول کریں"</string>
<string name="car_permission_desc_control_car_occupant_awareness_system" msgid="7123482622084531911">"کار میں بیٹھنے والے فرد کے لیے بنا آگاہی کا سسٹم پتہ لگانے کے گراف کو شروع کرنے اور روکنے کی اجازت دیتا ہے"</string>
- <string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"کار کی ان پٹ سروس"</string>
- <string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"ایونٹس کے ان پٹ کو ہینڈل کریں"</string>
<string name="car_permission_label_diag_read" msgid="7248894224877702604">"تشخیصی ڈیٹا پڑھیں"</string>
<string name="car_permission_desc_diag_read" msgid="1121426363040966178">"کار کے تشخیصی ڈیٹا کے بارے میں پڑھیں۔"</string>
<string name="car_permission_label_diag_clear" msgid="4783070510879698157">"تشخیصی ڈیٹا صاف کریں"</string>
@@ -84,8 +78,6 @@
<string name="car_permission_desc_vms_publisher" msgid="5589489298597386828">"VMS پیغامات شائع کریں"</string>
<string name="car_permission_label_vms_subscriber" msgid="5648841182059222299">"VMS سبسکرائبر"</string>
<string name="car_permission_desc_vms_subscriber" msgid="7551009457847673620">"VMS پیغامات کو سبسکرائب کریں"</string>
- <string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"VMS کلائنٹ سروس"</string>
- <string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"VMS کلائنٹس کا پابند بنیں"</string>
<string name="car_permission_label_storage_monitoring" msgid="2327639346522530549">"اسٹوریج کی نگرانی کو فلیش کریں"</string>
<string name="car_permission_desc_storage_monitoring" msgid="2075712271139671318">"فلیش کے اسٹوریج کے استعمال کی نگرانی کریں"</string>
<string name="car_permission_label_driving_state" msgid="7754624599537393650">"کار چلانے کی صورتحال کے بارے میں سنیں"</string>
diff --git a/service/res/values-uz/strings.xml b/service/res/values-uz/strings.xml
index ba80197..5c9e233 100644
--- a/service/res/values-uz/strings.xml
+++ b/service/res/values-uz/strings.xml
@@ -42,8 +42,6 @@
<string name="car_permission_desc_projection" msgid="2352178999656292944">"Telefondagi ilova interfeysi avtomobil ekranida chiqadi."</string>
<string name="car_permission_label_access_projection_status" msgid="4231618890836627402">"proyeksiya holatini aniqlash"</string>
<string name="car_permission_desc_access_projection_status" msgid="8497351979100616278">"Ilova avtomobil ekranida chiqadigan boshqa ilovalar holatini aniqlay oladi."</string>
- <string name="car_permission_label_bind_projection_service" msgid="5362076216606651526">"proyeksiya xizmatiga ulanish"</string>
- <string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"Proyeksiya xizmatining yuqori darajali interfeysiga ulana oladi. Oddiy ilovalar tomonidan ishlatilmaydi."</string>
<string name="car_permission_label_audio_volume" msgid="310587969373137690">"audio tizim tovushi balandligini boshqarish"</string>
<string name="car_permission_label_audio_settings" msgid="6524703796944023977">"avtomobilning audio sozlamalarini boshqarish"</string>
<string name="car_permission_label_mock_vehicle_hal" msgid="7198852512207405935">"HAL interfeysini emulyatsiya qilish"</string>
@@ -62,8 +60,6 @@
<string name="car_permission_desc_car_cluster_control" msgid="9222776665281176031">"Asboblar panelida ilovalarni ishga tushirish"</string>
<string name="car_permission_car_monitor_cluster_navigation_state" msgid="7025307242306902441">"Boshqaruv panelidagi navigatsiya holati"</string>
<string name="car_permission_desc_car_monitor_cluster_navigation_state" msgid="8745047153878713339">"Boshqaruv panelidagi navigatsiya holati oʻzgarishlarini kuzatib boring"</string>
- <string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"Axborotlarni asboblar paneliga chiqarish"</string>
- <string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"Asboblar panelidan axborotlarni olish"</string>
<string name="car_permission_label_car_ux_restrictions_configuration" msgid="6801393970411049725">"Funksiyadan foydalanish cheklovini oʻrnatish"</string>
<string name="car_permission_desc_car_ux_restrictions_configuration" msgid="5711926927484813777">"Funksiyalardan foydalanishni cheklash"</string>
<string name="car_permission_label_access_private_display_id" msgid="6712116114341634316">"Shaxsiy ekran identifikatorini oʻqish uchun ruxsat"</string>
@@ -74,8 +70,6 @@
<string name="car_permission_desc_read_car_occupant_awareness_state" msgid="188865882598414986">"Yoʻlovchilarni aniqlash tizimi uchun holat va aniqlash maʼlumotlarini oʻqishga ruxsat beradi"</string>
<string name="car_permission_label_control_car_occupant_awareness_system" msgid="7163330266691094542">"Yoʻlovchilarni aniqlash tizimi chizmasini boshqarish"</string>
<string name="car_permission_desc_control_car_occupant_awareness_system" msgid="7123482622084531911">"Yoʻlovchilarni aniqlash tizimining aniqlash chizmasini boshlash va toʻxtatishni boshqarishga ruxsat beradi"</string>
- <string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Avtomobilda matn kiritish xizmati"</string>
- <string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Matn kiritish hodisalari bilan ishlash imkoniyati"</string>
<string name="car_permission_label_diag_read" msgid="7248894224877702604">"diagnostika axborotini ochish"</string>
<string name="car_permission_desc_diag_read" msgid="1121426363040966178">"Avtomobildan diagnostika axborotini olish."</string>
<string name="car_permission_label_diag_clear" msgid="4783070510879698157">"diagnostika axborotini tozalash"</string>
@@ -84,8 +78,6 @@
<string name="car_permission_desc_vms_publisher" msgid="5589489298597386828">"VMS xabarlarni ekranga chiqarish"</string>
<string name="car_permission_label_vms_subscriber" msgid="5648841182059222299">"VMS xabarlarga obuna"</string>
<string name="car_permission_desc_vms_subscriber" msgid="7551009457847673620">"VMS xabarlarga obuna"</string>
- <string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"VMS mijoz xizmati"</string>
- <string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"VMS mijozlarga ulanish"</string>
<string name="car_permission_label_storage_monitoring" msgid="2327639346522530549">"Flesh xotirani nazorat qilish"</string>
<string name="car_permission_desc_storage_monitoring" msgid="2075712271139671318">"Flesh xotiradan foydalanishni nazorat qilish"</string>
<string name="car_permission_label_driving_state" msgid="7754624599537393650">"Avtomobilda rejimini kuzatish"</string>
diff --git a/service/res/values-vi/strings.xml b/service/res/values-vi/strings.xml
index 83b7623..c92ddc3 100644
--- a/service/res/values-vi/strings.xml
+++ b/service/res/values-vi/strings.xml
@@ -42,8 +42,6 @@
<string name="car_permission_desc_projection" msgid="2352178999656292944">"Cho phép ứng dụng chiếu giao diện của một điện thoại lên màn hình trên ô tô."</string>
<string name="car_permission_label_access_projection_status" msgid="4231618890836627402">"truy cập vào trạng thái chiếu"</string>
<string name="car_permission_desc_access_projection_status" msgid="8497351979100616278">"Cho phép ứng dụng nhận biết trạng thái của các ứng dụng khác đang chiếu lên màn hình trên ô tô."</string>
- <string name="car_permission_label_bind_projection_service" msgid="5362076216606651526">"liên kết với dịch vụ chiếu"</string>
- <string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"Cho phép khung liên kết với giao diện cấp cao nhất của dịch vụ chiếu. Điều này không cần thiết đối với các ứng dụng thông thường."</string>
<string name="car_permission_label_audio_volume" msgid="310587969373137690">"kiểm soát âm lượng trên ô tô"</string>
<string name="car_permission_label_audio_settings" msgid="6524703796944023977">"quản lý tùy chọn cài đặt âm thanh của ô tô"</string>
<string name="car_permission_label_mock_vehicle_hal" msgid="7198852512207405935">"mô phỏng HAL của phương tiện"</string>
@@ -62,8 +60,6 @@
<string name="car_permission_desc_car_cluster_control" msgid="9222776665281176031">"Khởi chạy ứng dụng trong nhóm dụng cụ"</string>
<string name="car_permission_car_monitor_cluster_navigation_state" msgid="7025307242306902441">"Trạng thái điều hướng nhóm công cụ"</string>
<string name="car_permission_desc_car_monitor_cluster_navigation_state" msgid="8745047153878713339">"Nghe thông tin về việc thay đổi trạng thái điều hướng nhóm công cụ"</string>
- <string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"Hiển thị nhóm dụng cụ"</string>
- <string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"Nhận dữ liệu nhóm dụng cụ"</string>
<string name="car_permission_label_car_ux_restrictions_configuration" msgid="6801393970411049725">"Cấu hình hạn chế trải nghiệm người dùng"</string>
<string name="car_permission_desc_car_ux_restrictions_configuration" msgid="5711926927484813777">"Định cấu hình các hạn chế trải nghiệm người dùng"</string>
<string name="car_permission_label_access_private_display_id" msgid="6712116114341634316">"Quyền đọc mã màn hình riêng tư"</string>
@@ -74,8 +70,6 @@
<string name="car_permission_desc_read_car_occupant_awareness_state" msgid="188865882598414986">"Cho phép đọc trạng thái và dữ liệu phát hiện của Occupant Awareness System"</string>
<string name="car_permission_label_control_car_occupant_awareness_system" msgid="7163330266691094542">"Biểu đồ kiểm soát Occupant Awareness System"</string>
<string name="car_permission_desc_control_car_occupant_awareness_system" msgid="7123482622084531911">"Cho phép kiểm soát việc bắt đầu và dừng biểu đồ phát hiện Occupant Awareness System"</string>
- <string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Dịch vụ nhập dành cho ô tô"</string>
- <string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Xử lý sự kiện nhập"</string>
<string name="car_permission_label_diag_read" msgid="7248894224877702604">"đọc dữ liệu chẩn đoán"</string>
<string name="car_permission_desc_diag_read" msgid="1121426363040966178">"Đọc dữ liệu chẩn đoán từ ô tô."</string>
<string name="car_permission_label_diag_clear" msgid="4783070510879698157">"xóa dữ liệu chẩn đoán"</string>
@@ -84,8 +78,6 @@
<string name="car_permission_desc_vms_publisher" msgid="5589489298597386828">"Gửi tin nhắn VMS"</string>
<string name="car_permission_label_vms_subscriber" msgid="5648841182059222299">"Công cụ đăng ký nhận dữ liệu VMS"</string>
<string name="car_permission_desc_vms_subscriber" msgid="7551009457847673620">"Đăng ký nhận tin nhắn VMS"</string>
- <string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"Dịch vụ ứng dụng VMS"</string>
- <string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"Liên kết với ứng dụng VMS"</string>
<string name="car_permission_label_storage_monitoring" msgid="2327639346522530549">"Giám sát bộ nhớ flash"</string>
<string name="car_permission_desc_storage_monitoring" msgid="2075712271139671318">"Giám sát mức sử dụng bộ nhớ flash"</string>
<string name="car_permission_label_driving_state" msgid="7754624599537393650">"nghe trạng thái lái xe"</string>
diff --git a/service/res/values-zh-rCN/strings.xml b/service/res/values-zh-rCN/strings.xml
index 8098315..e401aca 100644
--- a/service/res/values-zh-rCN/strings.xml
+++ b/service/res/values-zh-rCN/strings.xml
@@ -42,8 +42,6 @@
<string name="car_permission_desc_projection" msgid="2352178999656292944">"允许应用将手机界面投影到车载显示屏。"</string>
<string name="car_permission_label_access_projection_status" msgid="4231618890836627402">"访问投影状态信息"</string>
<string name="car_permission_desc_access_projection_status" msgid="8497351979100616278">"允许应用获取投影到车载显示屏的其他应用的状态。"</string>
- <string name="car_permission_label_bind_projection_service" msgid="5362076216606651526">"绑定到投影服务"</string>
- <string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"允许应用绑定到投影服务的顶级接口。普通应用绝不需要此权限。"</string>
<string name="car_permission_label_audio_volume" msgid="310587969373137690">"控制汽车的音频音量"</string>
<string name="car_permission_label_audio_settings" msgid="6524703796944023977">"管理汽车的音频设置"</string>
<string name="car_permission_label_mock_vehicle_hal" msgid="7198852512207405935">"模拟车辆 HAL"</string>
@@ -62,8 +60,6 @@
<string name="car_permission_desc_car_cluster_control" msgid="9222776665281176031">"在仪表板上启动应用"</string>
<string name="car_permission_car_monitor_cluster_navigation_state" msgid="7025307242306902441">"仪表板导航状态"</string>
<string name="car_permission_desc_car_monitor_cluster_navigation_state" msgid="8745047153878713339">"监听仪表板导航状态更改"</string>
- <string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"仪表板呈现"</string>
- <string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"接收仪表板数据"</string>
<string name="car_permission_label_car_ux_restrictions_configuration" msgid="6801393970411049725">"用户体验限制条件配置"</string>
<string name="car_permission_desc_car_ux_restrictions_configuration" msgid="5711926927484813777">"配置用户体验限制条件"</string>
<string name="car_permission_label_access_private_display_id" msgid="6712116114341634316">"对不公开屏幕 ID 的读取访问权限"</string>
@@ -74,8 +70,6 @@
<string name="car_permission_desc_read_car_occupant_awareness_state" msgid="188865882598414986">"允许读取 Occupant Awareness System 的状态和检测数据"</string>
<string name="car_permission_label_control_car_occupant_awareness_system" msgid="7163330266691094542">"控制 Occupant Awareness System 图表"</string>
<string name="car_permission_desc_control_car_occupant_awareness_system" msgid="7123482622084531911">"允许控制 Occupant Awareness System 检测图表的启动和停止"</string>
- <string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"汽车输入服务"</string>
- <string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"处理输入事件"</string>
<string name="car_permission_label_diag_read" msgid="7248894224877702604">"读取诊断数据"</string>
<string name="car_permission_desc_diag_read" msgid="1121426363040966178">"读取汽车的诊断数据。"</string>
<string name="car_permission_label_diag_clear" msgid="4783070510879698157">"清除诊断数据"</string>
@@ -84,8 +78,6 @@
<string name="car_permission_desc_vms_publisher" msgid="5589489298597386828">"发布 VMS 消息"</string>
<string name="car_permission_label_vms_subscriber" msgid="5648841182059222299">"VMS 订阅者"</string>
<string name="car_permission_desc_vms_subscriber" msgid="7551009457847673620">"订阅 VMS 消息"</string>
- <string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"VMS 客户端服务"</string>
- <string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"绑定到 VMS 客户端"</string>
<string name="car_permission_label_storage_monitoring" msgid="2327639346522530549">"闪存监控"</string>
<string name="car_permission_desc_storage_monitoring" msgid="2075712271139671318">"监控闪存使用情况"</string>
<string name="car_permission_label_driving_state" msgid="7754624599537393650">"监听驾车状态"</string>
diff --git a/service/res/values-zh-rHK/strings.xml b/service/res/values-zh-rHK/strings.xml
index 247dd58..fc2b163 100644
--- a/service/res/values-zh-rHK/strings.xml
+++ b/service/res/values-zh-rHK/strings.xml
@@ -42,8 +42,6 @@
<string name="car_permission_desc_projection" msgid="2352178999656292944">"允許應用程式將手機介面投射至汽車螢幕。"</string>
<string name="car_permission_label_access_projection_status" msgid="4231618890836627402">"存取投射狀態"</string>
<string name="car_permission_desc_access_projection_status" msgid="8497351979100616278">"允許應用程式取得正在投射資訊至汽車螢幕的應用程式狀態。"</string>
- <string name="car_permission_label_bind_projection_service" msgid="5362076216606651526">"繫結至投射服務"</string>
- <string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"允許應用程式繫結至投射服務的頂層介面 (不建議一般應用程式使用)。"</string>
<string name="car_permission_label_audio_volume" msgid="310587969373137690">"控制汽車音響的音量"</string>
<string name="car_permission_label_audio_settings" msgid="6524703796944023977">"管理汽車的音響設定"</string>
<string name="car_permission_label_mock_vehicle_hal" msgid="7198852512207405935">"模擬執行汽車 HAL"</string>
@@ -62,8 +60,6 @@
<string name="car_permission_desc_car_cluster_control" msgid="9222776665281176031">"在儀表板啟動應用程式"</string>
<string name="car_permission_car_monitor_cluster_navigation_state" msgid="7025307242306902441">"儀器叢集導覽狀態"</string>
<string name="car_permission_desc_car_monitor_cluster_navigation_state" msgid="8745047153878713339">"聆聽儀器叢集導覽狀態變更"</string>
- <string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"正在輸出儀表板"</string>
- <string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"接收儀表板資料"</string>
<string name="car_permission_label_car_ux_restrictions_configuration" msgid="6801393970411049725">"使用者體驗限制設定"</string>
<string name="car_permission_desc_car_ux_restrictions_configuration" msgid="5711926927484813777">"設定使用者體驗限制"</string>
<string name="car_permission_label_access_private_display_id" msgid="6712116114341634316">"私人顯示 ID 的讀取權限"</string>
@@ -74,8 +70,6 @@
<string name="car_permission_desc_read_car_occupant_awareness_state" msgid="188865882598414986">"允許讀取 Occupant Awareness System 的狀態和偵測數據"</string>
<string name="car_permission_label_control_car_occupant_awareness_system" msgid="7163330266691094542">"控制 Occupant Awareness System 圖表"</string>
<string name="car_permission_desc_control_car_occupant_awareness_system" msgid="7123482622084531911">"允許控制何時開始和停止 Occupant Awareness System 的偵測圖表"</string>
- <string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"汽車輸入服務"</string>
- <string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"處理輸入活動"</string>
<string name="car_permission_label_diag_read" msgid="7248894224877702604">"讀取診斷資料"</string>
<string name="car_permission_desc_diag_read" msgid="1121426363040966178">"讀取來自汽車的診斷資料。"</string>
<string name="car_permission_label_diag_clear" msgid="4783070510879698157">"清除診斷資料"</string>
@@ -84,8 +78,6 @@
<string name="car_permission_desc_vms_publisher" msgid="5589489298597386828">"發佈交通訊息顯示屏訊息"</string>
<string name="car_permission_label_vms_subscriber" msgid="5648841182059222299">"交通訊息顯示屏訂閱應用程式"</string>
<string name="car_permission_desc_vms_subscriber" msgid="7551009457847673620">"訂閱交通訊息顯示屏訊息"</string>
- <string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"交通訊息顯示屏用戶端服務"</string>
- <string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"繫結至交通訊息顯示屏用戶端"</string>
<string name="car_permission_label_storage_monitoring" msgid="2327639346522530549">"監控快閃儲存空間"</string>
<string name="car_permission_desc_storage_monitoring" msgid="2075712271139671318">"監控快閃儲存空間使用狀態"</string>
<string name="car_permission_label_driving_state" msgid="7754624599537393650">"聽取駕駛狀態"</string>
diff --git a/service/res/values-zh-rTW/strings.xml b/service/res/values-zh-rTW/strings.xml
index 58fb989..4d8809e 100644
--- a/service/res/values-zh-rTW/strings.xml
+++ b/service/res/values-zh-rTW/strings.xml
@@ -42,8 +42,6 @@
<string name="car_permission_desc_projection" msgid="2352178999656292944">"允許應用程式將手機介面投放至車輛螢幕。"</string>
<string name="car_permission_label_access_projection_status" msgid="4231618890836627402">"存取投影狀態"</string>
<string name="car_permission_desc_access_projection_status" msgid="8497351979100616278">"允許應用程式取得其他投放至車輛螢幕的應用程式狀態。"</string>
- <string name="car_permission_label_bind_projection_service" msgid="5362076216606651526">"繫結至投影服務"</string>
- <string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"允許應用程式繫結至投放服務的頂層介面 (一般應用程式並不需要)。"</string>
<string name="car_permission_label_audio_volume" msgid="310587969373137690">"控制車輛音量"</string>
<string name="car_permission_label_audio_settings" msgid="6524703796944023977">"管理車輛音訊設定"</string>
<string name="car_permission_label_mock_vehicle_hal" msgid="7198852512207405935">"模擬車輛 HAL"</string>
@@ -62,8 +60,6 @@
<string name="car_permission_desc_car_cluster_control" msgid="9222776665281176031">"在儀錶板中啟動應用程式"</string>
<string name="car_permission_car_monitor_cluster_navigation_state" msgid="7025307242306902441">"儀表板導航狀態"</string>
<string name="car_permission_desc_car_monitor_cluster_navigation_state" msgid="8745047153878713339">"監聽儀表板導航狀態變更"</string>
- <string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"儀錶板轉譯"</string>
- <string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"接收儀錶板資料"</string>
<string name="car_permission_label_car_ux_restrictions_configuration" msgid="6801393970411049725">"使用者體驗限制設定"</string>
<string name="car_permission_desc_car_ux_restrictions_configuration" msgid="5711926927484813777">"設定使用者體驗限制"</string>
<string name="car_permission_label_access_private_display_id" msgid="6712116114341634316">"不公開螢幕 ID 的讀取權限"</string>
@@ -74,8 +70,6 @@
<string name="car_permission_desc_read_car_occupant_awareness_state" msgid="188865882598414986">"允許讀取 Occupant Awareness System 的狀態和偵測資料"</string>
<string name="car_permission_label_control_car_occupant_awareness_system" msgid="7163330266691094542">"控管 Occupant Awareness System 圖表"</string>
<string name="car_permission_desc_control_car_occupant_awareness_system" msgid="7123482622084531911">"允許控管 Occupant Awareness System 偵測圖表的啟用和停用狀況"</string>
- <string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"車輛輸入服務"</string>
- <string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"處理輸入事件"</string>
<string name="car_permission_label_diag_read" msgid="7248894224877702604">"讀取診斷資料"</string>
<string name="car_permission_desc_diag_read" msgid="1121426363040966178">"讀取車輛的診斷資料。"</string>
<string name="car_permission_label_diag_clear" msgid="4783070510879698157">"清除診斷資料"</string>
@@ -84,8 +78,6 @@
<string name="car_permission_desc_vms_publisher" msgid="5589489298597386828">"發布 VMS 訊息"</string>
<string name="car_permission_label_vms_subscriber" msgid="5648841182059222299">"VMS 訂閱者"</string>
<string name="car_permission_desc_vms_subscriber" msgid="7551009457847673620">"訂閱 VMS 訊息"</string>
- <string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"VMS 用戶端服務"</string>
- <string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"繫結至 VMS 用戶端"</string>
<string name="car_permission_label_storage_monitoring" msgid="2327639346522530549">"快閃記憶體儲存空間監控"</string>
<string name="car_permission_desc_storage_monitoring" msgid="2075712271139671318">"監控快閃記憶體用量"</string>
<string name="car_permission_label_driving_state" msgid="7754624599537393650">"監聽駕駛狀態"</string>
diff --git a/service/res/values-zu/strings.xml b/service/res/values-zu/strings.xml
index 104cd26..406f309 100644
--- a/service/res/values-zu/strings.xml
+++ b/service/res/values-zu/strings.xml
@@ -42,8 +42,6 @@
<string name="car_permission_desc_projection" msgid="2352178999656292944">"Ivumela uhlelo lokusebenza ukuthi luphrojekthe isixhumi esibonakalayo kusukela kufoni kusibonisi semoto."</string>
<string name="car_permission_label_access_projection_status" msgid="4231618890836627402">"finyelela isimo sokuphrojektha"</string>
<string name="car_permission_desc_access_projection_status" msgid="8497351979100616278">"Ivumela uhlelo lokusebenza ukuthi luthole isimo sezinye izinhlelo zokusebenza eziphrojektha kusibonisi semoto."</string>
- <string name="car_permission_label_bind_projection_service" msgid="5362076216606651526">"bophezela kusevisi yokuphrojekthwa"</string>
- <string name="car_permission_desc_bind_projection_service" msgid="2282657787853408639">"Ivumela umbambi ukuthi aboshezelwe kusixhumi esibonakalayo seleveli ephezulu yesevisi yokuphrojektha. Akumele kudingelwe izinhlelo zokusebenza ezijwayelekile."</string>
<string name="car_permission_label_audio_volume" msgid="310587969373137690">"lawula ivolomu yemoto"</string>
<string name="car_permission_label_audio_settings" msgid="6524703796944023977">"phatha amasethingi omsindo emoto"</string>
<string name="car_permission_label_mock_vehicle_hal" msgid="7198852512207405935">"phinda i-HAL yemoto"</string>
@@ -62,8 +60,6 @@
<string name="car_permission_desc_car_cluster_control" msgid="9222776665281176031">"Qalisa uhlelo lokusebenza kwinto yokusebenza"</string>
<string name="car_permission_car_monitor_cluster_navigation_state" msgid="7025307242306902441">"Isimo sokufuna seqoqo lezinsimbi"</string>
<string name="car_permission_desc_car_monitor_cluster_navigation_state" msgid="8745047153878713339">"Lalela izinguquko zesimo sokufuna kweqoqo lezinsimbi"</string>
- <string name="car_permission_label_bind_instrument_cluster_rendering" msgid="8627480897198377418">"Ukusebenzisa into yokusebenza"</string>
- <string name="car_permission_desc_bind_instrument_cluster_rendering" msgid="5073596870485006783">"Thola idatha yento yokusebenza"</string>
<string name="car_permission_label_car_ux_restrictions_configuration" msgid="6801393970411049725">"Ukulungiswa kwemikhawulo ye-UX"</string>
<string name="car_permission_desc_car_ux_restrictions_configuration" msgid="5711926927484813777">"Lungisa imikhawulo ye-UX"</string>
<string name="car_permission_label_access_private_display_id" msgid="6712116114341634316">"Ukufinyelela kokufunda ku-id yesiboniso esiyimfihlo"</string>
@@ -74,8 +70,6 @@
<string name="car_permission_desc_read_car_occupant_awareness_state" msgid="188865882598414986">"Ivumela isimo sokufundwa nokutholakala kwedatha Yesistimu Yokwazisa Yomgibeli"</string>
<string name="car_permission_label_control_car_occupant_awareness_system" msgid="7163330266691094542">"Lawula Igrafu Yesistimu Yokwazisa Yomgibeli"</string>
<string name="car_permission_desc_control_car_occupant_awareness_system" msgid="7123482622084531911">"Ivumela ukulawula ukuqalwa nokumiswa kwegrafu yokutholakala Kwesistimu Yokwazisa Yomgibeli"</string>
- <string name="car_permission_label_bind_input_service" msgid="6698489034024273750">"Isevisi yokufaka yemoto"</string>
- <string name="car_permission_desc_bind_input_service" msgid="1670323419931890170">"Phatha imicimbi yokungena"</string>
<string name="car_permission_label_diag_read" msgid="7248894224877702604">"funda idatha yokuxilonga"</string>
<string name="car_permission_desc_diag_read" msgid="1121426363040966178">"Ukufunda idatha yokuxilonga kusuka emotweni."</string>
<string name="car_permission_label_diag_clear" msgid="4783070510879698157">"sula idatha yokuxilonga"</string>
@@ -84,8 +78,6 @@
<string name="car_permission_desc_vms_publisher" msgid="5589489298597386828">"Shicilela imilayezo ye-VMS"</string>
<string name="car_permission_label_vms_subscriber" msgid="5648841182059222299">"Obhalisele we-VMS"</string>
<string name="car_permission_desc_vms_subscriber" msgid="7551009457847673620">"Bhalisela imilayezo ye-VMS"</string>
- <string name="car_permission_label_bind_vms_client" msgid="4889732900973280313">"Isevisi yeklayenti le-VMS"</string>
- <string name="car_permission_desc_bind_vms_client" msgid="4062835325264330564">"Bophezela kumaklayenti e-VMS"</string>
<string name="car_permission_label_storage_monitoring" msgid="2327639346522530549">"Ukwengamela isitoreji se-flash"</string>
<string name="car_permission_desc_storage_monitoring" msgid="2075712271139671318">"Ngamela ukusetshenziswa kwesitoreji semoto"</string>
<string name="car_permission_label_driving_state" msgid="7754624599537393650">"lalela isimo sokushayela"</string>
diff --git a/service/res/values/strings.xml b/service/res/values/strings.xml
index d1eb734..b3f0d11 100644
--- a/service/res/values/strings.xml
+++ b/service/res/values/strings.xml
@@ -70,10 +70,6 @@
<string name="car_permission_label_access_projection_status">access projection status</string>
<!-- Permission text: apps can listen car-projection status[CHAR LIMIT=NONE] -->
<string name="car_permission_desc_access_projection_status">Allows an app to get the status of other apps projecting to the car\u2019s display.</string>
- <!-- Permission text: allows framework to bind to the services in projection apps[CHAR LIMIT=NONE] -->
- <string name="car_permission_label_bind_projection_service">bind to a projection service</string>
- <!-- Permission text: allows framework to bind to the services in projection apps[CHAR LIMIT=NONE] -->
- <string name="car_permission_desc_bind_projection_service">Allows the holder to bind to the top-level interface of a projection service. Should never be needed for normal apps."</string>
<!-- Permission text: apps can control car-audio-volume [CHAR LIMIT=NONE] -->
<string name="car_permission_label_audio_volume">control car\u2019s audio volume</string>
<!-- Permission text: apps can control car-audio-settings [CHAR LIMIT=NONE] -->
@@ -106,8 +102,6 @@
<string name="car_permission_desc_car_cluster_control">Launch apps in the instrument cluster</string>
<string name="car_permission_car_monitor_cluster_navigation_state">Instrument cluster navigation state</string>
<string name="car_permission_desc_car_monitor_cluster_navigation_state">Listen for instrument cluster navigation state changes</string>
- <string name="car_permission_label_bind_instrument_cluster_rendering">Instrument Cluster Rendering</string>
- <string name="car_permission_desc_bind_instrument_cluster_rendering">Receive instrument cluster data</string>
<string name="car_permission_label_car_ux_restrictions_configuration">UX Restrictions Configuration</string>
<string name="car_permission_desc_car_ux_restrictions_configuration">Configure UX Restrictions</string>
<string name="car_permission_label_access_private_display_id">Read access to private display id</string>
@@ -122,11 +116,6 @@
<string name="car_permission_label_control_car_occupant_awareness_system">Control Occupant Awareness System Graph</string>
<string name="car_permission_desc_control_car_occupant_awareness_system">Allows controlling the start and stopping of the Occupant Awareness System detection graph</string>
- <!-- Permission text: apps can handle input events [CHAR LIMIT=NONE] -->
- <string name="car_permission_label_bind_input_service">Car Input Service</string>
- <!-- Permission text: apps can handle input events [CHAR LIMIT=NONE] -->
- <string name="car_permission_desc_bind_input_service">Handle input events</string>
-
<!-- Permission text: apps can control diagnostic data [CHAR LIMIT=NONE] -->
<string name="car_permission_label_diag_read">read diagnostic data</string>
<!-- Permission text: apps can read diagnostic data from the car [CHAR LIMIT=NONE] -->
@@ -147,11 +136,6 @@
<!-- Permission text: apps can receive VMS messages from the car [CHAR LIMIT=NONE] -->
<string name="car_permission_desc_vms_subscriber">Subscribe to VMS messages</string>
- <!-- Permission text: apps can act as VMS router core [CHAR LIMIT=NONE] -->
- <string name="car_permission_label_bind_vms_client">VMS Client Service</string>
- <!-- Permission text: apps can act as VMS router core [CHAR LIMIT=NONE] -->
- <string name="car_permission_desc_bind_vms_client">Bind to VMS clients</string>
-
<!-- Permission text: apps can monitor flash storage usage [CHAR LIMIT=NONE] -->
<string name="car_permission_label_storage_monitoring">Flash storage monitoring</string>
<!-- Permission text: apps can monitor flash storage usage [CHAR LIMIT=NONE] -->
@@ -550,6 +534,11 @@
<!-- Permission text: app can control launching applications in Car [CHAR LIMIT=NONE] -->
<string name="car_permission_desc_control_car_app_launch">Control launching applications.</string>
+ <!-- Permission text: apps manage thread prioirty [CHAR LIMIT=NONE] -->
+ <string name="car_permission_label_manage_thread_priority">manage thread priority</string>
+ <!-- Permission text: apps manage thread prioirty [CHAR LIMIT=NONE] -->
+ <string name="car_permission_desc_manage_thread_priority">Manage thread priority.</string>
+
<!-- Notification messages -->
<!-- Notification text: Notification shown to the user when vehicle CAN bus fails -->
<string name="car_can_bus_failure">CAN bus failed</string>
diff --git a/service/src/com/android/car/CarFeatureController.java b/service/src/com/android/car/CarFeatureController.java
index 1e92619..dfa3f43 100644
--- a/service/src/com/android/car/CarFeatureController.java
+++ b/service/src/com/android/car/CarFeatureController.java
@@ -76,6 +76,7 @@
Car.CAR_INPUT_SERVICE,
Car.CAR_MEDIA_SERVICE,
Car.CAR_OCCUPANT_ZONE_SERVICE,
+ Car.CAR_PERFORMANCE_SERVICE,
Car.CAR_USER_SERVICE,
Car.CAR_UX_RESTRICTION_SERVICE,
Car.CAR_WATCHDOG_SERVICE,
diff --git a/service/src/com/android/car/CarMediaService.java b/service/src/com/android/car/CarMediaService.java
index a023a69..784f05d 100644
--- a/service/src/com/android/car/CarMediaService.java
+++ b/service/src/com/android/car/CarMediaService.java
@@ -288,6 +288,9 @@
}
}
PlaybackState oldState = mediaController.getPlaybackState();
+ if (oldState == null) {
+ return;
+ }
savePlaybackState(
// The new state is the same as the old state, except for play/pause
new PlaybackState.Builder(oldState)
diff --git a/service/src/com/android/car/CarShellCommand.java b/service/src/com/android/car/CarShellCommand.java
index d89e9f0..fe53c34 100644
--- a/service/src/com/android/car/CarShellCommand.java
+++ b/service/src/com/android/car/CarShellCommand.java
@@ -43,6 +43,7 @@
import android.app.UiModeManager;
import android.car.Car;
import android.car.CarOccupantZoneManager;
+import android.car.CarVersion;
import android.car.VehiclePropertyIds;
import android.car.builtin.content.pm.PackageManagerHelper;
import android.car.builtin.os.BuildHelper;
@@ -147,6 +148,8 @@
import java.util.Objects;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Executor;
+import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicBoolean;
@@ -168,6 +171,7 @@
private static final String COMMAND_GET_DO_ACTIVITIES = "get-do-activities";
private static final String COMMAND_GET_CARPROPERTYCONFIG = "get-carpropertyconfig";
private static final String COMMAND_GET_PROPERTY_VALUE = "get-property-value";
+ private static final String COMMAND_SET_PROPERTY_VALUE = "set-property-value";
private static final String COMMAND_PROJECTION_AP_TETHERING = "projection-tethering";
private static final String COMMAND_PROJECTION_AP_STABLE_CONFIG =
"projection-stable-lohs-config";
@@ -260,6 +264,8 @@
private static final String COMMAND_TEST_ECHO_REVERSE_BYTES = "test-echo-reverse-bytes";
+ private static final String COMMAND_GET_TARGET_CAR_VERSION = "get-target-car-version";
+
private static final String[] CREATE_OR_MANAGE_USERS_PERMISSIONS = new String[] {
android.Manifest.permission.CREATE_USERS,
android.Manifest.permission.MANAGE_USERS
@@ -347,6 +353,8 @@
android.Manifest.permission.INJECT_EVENTS);
USER_BUILD_COMMAND_TO_PERMISSION_MAP.put(COMMAND_TEST_ECHO_REVERSE_BYTES,
android.car.Car.PERMISSION_CAR_DIAGNOSTIC_READ_ALL);
+ USER_BUILD_COMMAND_TO_PERMISSION_MAP.put(COMMAND_GET_TARGET_CAR_VERSION,
+ android.Manifest.permission.QUERY_ALL_PACKAGES);
}
private static final String PARAM_DAY_MODE = "day";
@@ -544,6 +552,7 @@
pw.println("\tget-property-value [PROPERTY_ID in Hex or Decimal] [areaId]");
pw.println("\t Get a vehicle property value by property id and areaId");
pw.println("\t or list all property values for all areaId");
+ pw.printf("\t%s\n", getSetPropertyValueUsage());
pw.printf("\t%s\n", getSuspendCommandUsage(COMMAND_SUSPEND));
pw.println("\t Suspend the system to RAM.");
pw.printf("\t %s forces the device to perform suspend-to-RAM.\n", PARAM_REAL);
@@ -756,6 +765,10 @@
pw.println("\t test the ECHO_REVERSE_BYTES property. PROP_ID is the ID (int) for "
+ "ECHO_REVERSE_BYTES, REQUEST_SIZE is how many byteValues in the request. "
+ "This command can be used for testing LargeParcelable by passing large request.");
+
+ pw.printf("\t%s [--user USER] <APP1> [APPN]", COMMAND_GET_TARGET_CAR_VERSION);
+ pw.println("\t Gets the target API version (major and minor) defined by the given apps "
+ + "for the given user (or current user when --user is not set).");
}
private static int showInvalidArguments(IndentingPrintWriter pw) {
@@ -936,6 +949,9 @@
mHal.dumpPropertyValueByCommand(writer, Integer.decode(propId),
Integer.decode(areaId));
break;
+ case COMMAND_SET_PROPERTY_VALUE:
+ runSetVehiclePropertyValue(args, writer);
+ break;
case COMMAND_PROJECTION_UI_MODE:
if (args.length != 2) {
return showInvalidArguments(writer);
@@ -1129,6 +1145,9 @@
case COMMAND_TEST_ECHO_REVERSE_BYTES:
testEchoReverseBytes(args, writer);
break;
+ case COMMAND_GET_TARGET_CAR_VERSION:
+ getTargetCarVersion(args, writer);
+ break;
default:
writer.println("Unknown command: \"" + cmd + "\"");
showHelp(writer);
@@ -1927,12 +1946,7 @@
private CarUserManager getCarUserManager(IndentingPrintWriter writer,
@UserIdInt int userId) {
- Context context;
- if (userId == mContext.getUser().getIdentifier()) {
- context = mContext;
- } else {
- context = mContext.createContextAsUser(UserHandle.of(userId), /* flags= */ 0);
- }
+ Context context = getContextForUser(userId);
int actualUserId = Binder.getCallingUid();
if (actualUserId != userId) {
writer.printf("Emulating call for user id %d, but caller's user id is %d, so that's "
@@ -1942,6 +1956,13 @@
return getCarUserManager(context);
}
+ private Context getContextForUser(int userId) {
+ if (userId == mContext.getUser().getIdentifier()) {
+ return mContext;
+ }
+ return mContext.createContextAsUser(UserHandle.of(userId), /* flags= */ 0);
+ }
+
private CarUserManager getCarUserManager(Context context) {
Car car = Car.createCar(context);
CarUserManager carUserManager = (CarUserManager) car.getCarManager(Car.CAR_USER_SERVICE);
@@ -2487,6 +2508,47 @@
}
+ // Handles set-property-value command.
+ private void runSetVehiclePropertyValue(String[] args, IndentingPrintWriter writer) {
+ if (args.length != 4) {
+ writer.println("Invalid command syntax:");
+ writer.printf("Usage: %s\n", getSetPropertyValueUsage());
+ return;
+ }
+ String strId = args[1];
+ String strAreaId = args[2];
+ String value = args[3];
+ int id;
+ int areaId;
+ try {
+ id = Integer.decode(strId);
+ areaId = Integer.decode(strAreaId);
+ } catch (NumberFormatException e) {
+ writer.printf("Cannot set a property: Invalid property ID(%s) or area ID(%s) format\n",
+ strId, strAreaId);
+ return;
+ }
+ Slogf.i(TAG, "Setting vehicle property: id=%s, areaId=%s, value=%s", strId, strAreaId,
+ value);
+ if (strAreaId.equalsIgnoreCase(PARAM_VEHICLE_PROPERTY_AREA_GLOBAL)
+ && !isPropertyAreaTypeGlobal(strId)) {
+ writer.printf("Property area type is inconsistent with given area ID: %s\n",
+ strAreaId);
+ return;
+ }
+ try {
+ mHal.setPropertyFromCommand(id, areaId, value, writer);
+ writer.printf("Property(%s) is set to %s successfully\n", strId, value);
+ } catch (Exception e) {
+ writer.printf("Cannot set a property: %s\n", e);
+ }
+ }
+
+ private static String getSetPropertyValueUsage() {
+ return COMMAND_SET_PROPERTY_VALUE + " <PROPERTY_ID in Hex or Decimal> <areaId> "
+ + "<data (can be comma-separated)>";
+ }
+
// Set a target camera device for the rearview
private void setRearviewCameraId(String[] args, IndentingPrintWriter writer) {
if (args.length != 2) {
@@ -2668,22 +2730,24 @@
writer.println("\tremove-all");
writer.println("\t Removes all metrics configs.");
writer.println("\tping-script-executor [published data filepath] [state filepath]");
+ writer.println("\t Runs a Lua script from stdin.");
+ writer.println("\tlist");
+ writer.println("\t Lists the active config metrics.");
+ writer.println("\tget-result <name>");
+ writer.println("\t Blocks until a metrics report is available and returns it.");
+ writer.println("\t If there are multiple reports, the CLI is guaranteed to receive "
+ + "at least one report. There is no guarantee that it will be able to get "
+ + "all of them.");
writer.println("\nEXAMPLES:");
+ writer.println("\t$ adb shell cmd car_service telemetry add name < config1.protobin");
+ writer.println("\t\tWhere config1.protobin is a serialized MetricsConfig proto.");
+ writer.println("\n\t$ adb shell cmd car_service telemetry get-result name");
writer.println("\t$ adb shell cmd car_service telemetry ping-script-executor "
+ "< example_script.lua");
writer.println("\t$ adb shell cmd car_service telemetry ping-script-executor "
+ "/data/local/tmp/published_data < example_script.lua");
writer.println("\t$ adb shell cmd car_service telemetry ping-script-executor "
+ "/data/local/tmp/bundle /data/local/tmp/bundle2 < example_script.lua");
- writer.println("\t Removes all metrics configs.");
- writer.println("\tlist");
- writer.println("\t Lists the config metrics in the service.");
- writer.println("\tget-result <name>");
- writer.println("\t Gets if available or waits for the results for the metrics config.");
- writer.println("\nEXAMPLES:");
- writer.println("\t$ adb shell cmd car_service telemetry add name < config1.protobin");
- writer.println("\t\tWhere config1.protobin is a serialized MetricsConfig proto.");
- writer.println("\n\t$ adb shell cmd car_service telemetry get-result name");
}
private void handleTelemetryCommands(String[] args, IndentingPrintWriter writer) {
@@ -2811,13 +2875,16 @@
} else if (telemetryError != null) {
parseTelemetryError(telemetryError, writer);
}
+ // the latch counts after receiving 1 report even if there are
+ // multiple reports
latch.countDown();
};
carTelemetryManager.clearReportReadyListener();
- carTelemetryManager.setReportReadyListener(Runnable::run, metricsConfigName -> {
+ Executor executor = Executors.newSingleThreadExecutor();
+ carTelemetryManager.setReportReadyListener(executor, metricsConfigName -> {
if (metricsConfigName.equals(configName)) {
carTelemetryManager.getFinishedReport(
- metricsConfigName, Runnable::run, callback);
+ metricsConfigName, executor, callback);
}
});
try {
@@ -3158,6 +3225,56 @@
writer.println("Test Succeeded!");
}
+ private void getTargetCarVersion(String[] args, IndentingPrintWriter writer) {
+ if (args.length < 2) {
+ showInvalidArguments(writer);
+ return;
+ }
+
+ int firstAppArg = 1;
+
+ // TODO(b/234499460): move --user logic to private helper / support 'all'
+ int userId = UserHandle.CURRENT.getIdentifier();
+ if (args[1].equals("--user")) {
+ if (args.length < 4) {
+ showInvalidArguments(writer);
+ return;
+ }
+ String userArg = args[2];
+ firstAppArg += 2;
+ if (!"current".equals(userArg) && !"cur".equals(userArg)) {
+ try {
+ userId = Integer.parseInt(args[2]);
+ } catch (NumberFormatException e) {
+ showInvalidArguments(writer);
+ return;
+ }
+ }
+ }
+ if (userId == UserHandle.CURRENT.getIdentifier()) {
+ userId = ActivityManager.getCurrentUser();
+ }
+ writer.printf("User %d:\n", userId);
+
+ Context userContext = getContextForUser(userId);
+ for (int i = firstAppArg; i < args.length; i++) {
+ String app = args[i];
+ try {
+ CarVersion Version = CarPackageManagerService.getTargetCarVersion(
+ userContext, app);
+ writer.printf(" %s: major=%d, minor=%d\n", app,
+ Version.getMajorVersion(), Version.getMinorVersion());
+ } catch (ServiceSpecificException e) {
+ if (e.errorCode == CarPackageManager.ERROR_CODE_NO_PACKAGE) {
+ writer.printf(" %s: not found\n", app);
+ } else {
+ writer.printf(" %s: unexpected exception: %s \n", app, e);
+ }
+ continue;
+ }
+ }
+ }
+
// Check if the given property is global
private static boolean isPropertyAreaTypeGlobal(@Nullable String property) {
if (property == null) {
diff --git a/service/src/com/android/car/HidlVehicleStub.java b/service/src/com/android/car/HidlVehicleStub.java
index 7dca8a2..c843abd 100644
--- a/service/src/com/android/car/HidlVehicleStub.java
+++ b/service/src/com/android/car/HidlVehicleStub.java
@@ -24,6 +24,9 @@
import android.hardware.automotive.vehicle.V2_0.IVehicle;
import android.hardware.automotive.vehicle.V2_0.IVehicleCallback;
import android.hardware.automotive.vehicle.V2_0.StatusCode;
+import android.hardware.automotive.vehicle.V2_0.VehiclePropConfig;
+import android.hardware.automotive.vehicle.V2_0.VehiclePropValue;
+import android.hardware.automotive.vehicle.V2_0.VehiclePropertyStatus;
import android.hardware.automotive.vehicle.VehiclePropError;
import android.os.NativeHandle;
import android.os.RemoteException;
@@ -39,10 +42,18 @@
import java.io.FileDescriptor;
import java.util.ArrayList;
+import java.util.List;
import java.util.NoSuchElementException;
final class HidlVehicleStub extends VehicleStub {
+ private static final String TAG = CarLog.tagFor(HidlVehicleStub.class);
+
+ // The property ID for "SUPPORTED_PROPRETY_IDS". This is the same as SUPPORTED_PROPERTY_IDS as
+ // defined in
+ // {@code platform/hardware/interfaces/automotive/vehicle/aidl/android/hardware/automotive/vehicle/VehicleProperty.aidl}.
+ private static final int VHAL_PROP_SUPPORTED_PROPERTY_IDS = 0x11410F48;
+
private final IVehicle mHidlVehicle;
private final HalPropValueBuilder mPropValueBuilder;
@@ -135,14 +146,31 @@
*/
@Override
public HalPropConfig[] getAllPropConfigs() throws RemoteException {
- ArrayList<android.hardware.automotive.vehicle.V2_0.VehiclePropConfig> hidlConfigs =
- mHidlVehicle.getAllPropConfigs();
- int configSize = hidlConfigs.size();
- HalPropConfig[] configs = new HalPropConfig[configSize];
- for (int i = 0; i < configSize; i++) {
- configs[i] = new HidlHalPropConfig(hidlConfigs.get(i));
+ ArrayList<VehiclePropConfig> configForSupportedProps;
+ try {
+ configForSupportedProps = getPropConfigs(new ArrayList<>(
+ List.of(VHAL_PROP_SUPPORTED_PROPERTY_IDS)));
+ } catch (Exception e) {
+ Slogf.d(TAG, "Use getAllPropConfigs to fetch all property configs");
+
+ // If the VHAL_PROP_SUPPORTED_PROPERTY_IDS is not supported, fallback to normal API.
+ return vehiclePropConfigsToHalPropConfigs(mHidlVehicle.getAllPropConfigs());
}
- return configs;
+
+ if (configForSupportedProps.size() == 0) {
+ Slogf.w(TAG, "getPropConfigs[VHAL_PROP_SUPPORTED_IDS] returns 0 config"
+ + "assume it is not supported, fall back to getAllPropConfigs.");
+ return vehiclePropConfigsToHalPropConfigs(mHidlVehicle.getAllPropConfigs());
+ }
+
+ // If the VHAL_PROP_SUPPORTED_PROPERTY_IDS is supported, VHAL has
+ // too many property configs that cannot be returned in getAllPropConfigs() in one binder
+ // transaction.
+ // We need to get the property list and then divide the list into smaller requests.
+ Slogf.d(TAG, "VHAL_PROP_SUPPORTED_PROPERTY_IDS is supported, "
+ + "use multiple getPropConfigs to fetch all property configs");
+
+ return getAllPropConfigsThroughMultipleRequests(configForSupportedProps.get(0));
}
/**
@@ -158,7 +186,7 @@
private static class GetValueResult {
public int status;
- public android.hardware.automotive.vehicle.V2_0.VehiclePropValue value;
+ public VehiclePropValue value;
}
/**
@@ -173,9 +201,7 @@
@Nullable
public HalPropValue get(HalPropValue requestedPropValue)
throws RemoteException, ServiceSpecificException {
- android.hardware.automotive.vehicle.V2_0.VehiclePropValue hidlPropValue =
- (android.hardware.automotive.vehicle.V2_0.VehiclePropValue) requestedPropValue
- .toVehiclePropValue();
+ VehiclePropValue hidlPropValue = (VehiclePropValue) requestedPropValue.toVehiclePropValue();
GetValueResult result = new GetValueResult();
mHidlVehicle.get(
hidlPropValue,
@@ -206,9 +232,7 @@
*/
@Override
public void set(HalPropValue propValue) throws RemoteException {
- android.hardware.automotive.vehicle.V2_0.VehiclePropValue hidlPropValue =
- (android.hardware.automotive.vehicle.V2_0.VehiclePropValue) propValue
- .toVehiclePropValue();
+ VehiclePropValue hidlPropValue = (VehiclePropValue) propValue.toVehiclePropValue();
int status = mHidlVehicle.set(hidlPropValue);
if (status != StatusCode.OK) {
throw new ServiceSpecificException(status, "failed to set value for property: "
@@ -228,9 +252,9 @@
try {
return IVehicle.getService(instanceName);
} catch (RemoteException e) {
- Slogf.e(CarLog.TAG_SERVICE, "Failed to get IVehicle/" + instanceName + " service", e);
+ Slogf.e(TAG, e, "Failed to get IVehicle/" + instanceName + " service");
} catch (NoSuchElementException e) {
- Slogf.e(CarLog.TAG_SERVICE, "IVehicle/" + instanceName + " service not registered yet");
+ Slogf.e(TAG, "IVehicle/" + instanceName + " service not registered yet");
}
return null;
}
@@ -246,18 +270,16 @@
}
@Override
- public void onPropertyEvent(
- ArrayList<android.hardware.automotive.vehicle.V2_0.VehiclePropValue> propValues) {
+ public void onPropertyEvent(ArrayList<VehiclePropValue> propValues) {
ArrayList<HalPropValue> values = new ArrayList<>();
- for (android.hardware.automotive.vehicle.V2_0.VehiclePropValue value : propValues) {
+ for (VehiclePropValue value : propValues) {
values.add(mBuilder.build(value));
}
mCallback.onPropertyEvent(values);
}
@Override
- public void onPropertySet(
- android.hardware.automotive.vehicle.V2_0.VehiclePropValue propValue) {
+ public void onPropertySet(VehiclePropValue propValue) {
// Deprecated, do nothing.
}
@@ -287,4 +309,76 @@
mHidlVehicle.unsubscribe(this, prop);
}
}
+
+ private static HalPropConfig[] vehiclePropConfigsToHalPropConfigs(
+ List<VehiclePropConfig> hidlConfigs) {
+ int configSize = hidlConfigs.size();
+ HalPropConfig[] configs = new HalPropConfig[configSize];
+ for (int i = 0; i < configSize; i++) {
+ configs[i] = new HidlHalPropConfig(hidlConfigs.get(i));
+ }
+ return configs;
+ }
+
+ private static final class GetPropConfigsResult {
+ public int status;
+ public ArrayList<VehiclePropConfig> propConfigs;
+ }
+
+ private HalPropConfig[] getAllPropConfigsThroughMultipleRequests(
+ VehiclePropConfig configForSupportedProps)
+ throws RemoteException, ServiceSpecificException {
+ if (configForSupportedProps.configArray.size() < 1) {
+ throw new IllegalArgumentException(
+ "VHAL Property: SUPPORTED_PROPERTY_IDS must have one element: "
+ + "[num_of_configs_per_request] in the config array");
+ }
+
+ int numConfigsPerRequest = configForSupportedProps.configArray.get(0);
+ if (numConfigsPerRequest <= 0) {
+ throw new IllegalArgumentException("Number of configs per request must be > 0");
+ }
+ HalPropValue propIdsRequestValue = mPropValueBuilder.build(
+ VHAL_PROP_SUPPORTED_PROPERTY_IDS, /* areaId= */ 0);
+ HalPropValue propIdsResultValue;
+ try {
+ propIdsResultValue = get(propIdsRequestValue);
+ } catch (Exception e) {
+ Slogf.e(TAG, e, "failed to get SUPPORTED_PROPRETY_IDS");
+ throw e;
+ }
+ int status = propIdsResultValue.getStatus();
+ if (status != VehiclePropertyStatus.AVAILABLE) {
+ throw new ServiceSpecificException(StatusCode.INTERNAL_ERROR,
+ "got non-okay status: " + StatusCode.toString(status)
+ + " for SUPPORTED_PROPERTY_IDS");
+ }
+ int propCount = propIdsResultValue.getInt32ValuesSize();
+ ArrayList<VehiclePropConfig> allConfigs = new ArrayList<>();
+ ArrayList<Integer> requestPropIds = new ArrayList<Integer>();
+ for (int i = 0; i < propCount; i++) {
+ requestPropIds.add(propIdsResultValue.getInt32Value(i));
+ if (requestPropIds.size() == numConfigsPerRequest || (i + 1) == propCount) {
+ ArrayList<VehiclePropConfig> subConfigs = getPropConfigs(requestPropIds);
+ allConfigs.addAll(subConfigs);
+ requestPropIds.clear();
+ }
+ }
+ return vehiclePropConfigsToHalPropConfigs(allConfigs);
+ }
+
+ private ArrayList<VehiclePropConfig> getPropConfigs(ArrayList<Integer> propIds)
+ throws RemoteException {
+ GetPropConfigsResult result = new GetPropConfigsResult();
+ mHidlVehicle.getPropConfigs(propIds,
+ (status, propConfigs) -> {
+ result.status = status;
+ result.propConfigs = propConfigs;
+ });
+ if (result.status != StatusCode.OK) {
+ throw new IllegalArgumentException("Part of the property IDs: " + propIds
+ + " is not supported");
+ }
+ return result.propConfigs;
+ }
}
diff --git a/service/src/com/android/car/ICarImpl.java b/service/src/com/android/car/ICarImpl.java
index be348da..f35c745 100644
--- a/service/src/com/android/car/ICarImpl.java
+++ b/service/src/com/android/car/ICarImpl.java
@@ -248,6 +248,11 @@
mCarUXRestrictionsService = constructWithTrace(t, CarUxRestrictionsManagerService.class,
() -> new CarUxRestrictionsManagerService(serviceContext, mCarDrivingStateService,
mCarPropertyService, mCarOccupantZoneService));
+ mCarActivityService = constructWithTrace(t, CarActivityService.class,
+ () -> new CarActivityService(serviceContext));
+ mCarPackageManagerService = constructWithTrace(t, CarPackageManagerService.class,
+ () -> new CarPackageManagerService(serviceContext, mCarUXRestrictionsService,
+ mCarActivityService, mCarOccupantZoneService));
if (carUserService != null) {
mCarUserService = carUserService;
CarLocalServices.addService(CarUserService.class, carUserService);
@@ -256,7 +261,7 @@
int maxRunningUsers = UserManagerHelper.getMaxRunningUsers(serviceContext);
mCarUserService = constructWithTrace(t, CarUserService.class,
() -> new CarUserService(serviceContext, mHal.getUserHal(), userManager,
- maxRunningUsers, mCarUXRestrictionsService));
+ maxRunningUsers, mCarUXRestrictionsService, mCarPackageManagerService));
}
if (mFeatureController.isFeatureEnabled(Car.EXPERIMENTAL_CAR_USER_SERVICE)) {
mExperimentalCarUserService = constructWithTrace(t, ExperimentalCarUserService.class,
@@ -284,11 +289,6 @@
} else {
mOccupantAwarenessService = null;
}
- mCarActivityService = constructWithTrace(t, CarActivityService.class,
- () -> new CarActivityService(serviceContext));
- mCarPackageManagerService = constructWithTrace(t, CarPackageManagerService.class,
- () -> new CarPackageManagerService(serviceContext, mCarUXRestrictionsService,
- mCarActivityService, mCarOccupantZoneService));
mPerUserCarServiceHelper = constructWithTrace(
t, PerUserCarServiceHelper.class,
() -> new PerUserCarServiceHelper(serviceContext, mCarUserService));
@@ -369,12 +369,14 @@
() -> new CarWatchdogService(serviceContext, mCarServiceBuiltinPackageContext));
} else {
mCarWatchdogService = carWatchdogService;
+ CarLocalServices.addService(CarWatchdogService.class, mCarWatchdogService);
}
if (carPerformanceService == null) {
mCarPerformanceService = constructWithTrace(t, CarPerformanceService.class,
() -> new CarPerformanceService(serviceContext));
} else {
mCarPerformanceService = carPerformanceService;
+ CarLocalServices.addService(CarPerformanceService.class, mCarPerformanceService);
}
mCarDevicePolicyService = constructWithTrace(
t, CarDevicePolicyService.class, () -> new CarDevicePolicyService(mContext,
@@ -405,7 +407,8 @@
if (mFeatureController.isFeatureEnabled(Car.CAR_TELEMETRY_SERVICE)) {
if (carTelemetryService == null) {
mCarTelemetryService = constructWithTrace(t, CarTelemetryService.class,
- () -> new CarTelemetryService(serviceContext, mCarPropertyService));
+ () -> new CarTelemetryService(
+ serviceContext, mCarPowerManagementService, mCarPropertyService));
} else {
mCarTelemetryService = carTelemetryService;
}
@@ -786,11 +789,16 @@
@ExcludeFromCodeCoverageGeneratedReport(reason = DUMP_INFO)
private void dumpVersions(IndentingPrintWriter writer) {
writer.println("*Dump versions*");
- writer.println("Android SDK_INT:" + Build.VERSION.SDK_INT);
- writer.println("Car API major:" + Car.API_VERSION_MAJOR_INT);
- writer.println("Car API minor:" + Car.API_VERSION_MINOR_INT);
- writer.println("Car Platform minor:" + Car.PLATFORM_VERSION_MINOR_INT);
- writer.println("CarBuiltin Platform minor:" + CarBuiltin.PLATFORM_VERSION_MINOR_INT);
+ writer.println("Android SDK_INT: " + Build.VERSION.SDK_INT);
+ writer.println("Car Version: " + Car.getCarVersion());
+ writer.println("Platform Version: " + Car.getPlatformVersion());
+ writer.println("CarBuiltin Platform minor: " + CarBuiltin.PLATFORM_VERSION_MINOR_INT);
+ writer.println("Legacy versions (might differ from above as they can't be emulated)");
+ writer.increaseIndent();
+ writer.println("Car API major: " + Car.API_VERSION_MAJOR_INT);
+ writer.println("Car API minor: " + Car.API_VERSION_MINOR_INT);
+ writer.println("Car Platform minor: " + Car.PLATFORM_VERSION_MINOR_INT);
+ writer.decreaseIndent();
}
@ExcludeFromCodeCoverageGeneratedReport(reason = DUMP_INFO)
@@ -954,6 +962,8 @@
mCarUserService.initBootUser();
}
+ // TODO(235524989): Remove this method as on user removed will now go through
+ // onUserLifecycleEvent due to changes in CarServiceProxy and CarUserService.
@Override
public void onUserRemoved(UserHandle user) throws RemoteException {
assertCallingFromSystemProcess();
diff --git a/service/src/com/android/car/am/CarActivityService.java b/service/src/com/android/car/am/CarActivityService.java
index c313da2..1d2f4b1 100644
--- a/service/src/com/android/car/am/CarActivityService.java
+++ b/service/src/com/android/car/am/CarActivityService.java
@@ -44,7 +44,6 @@
import android.os.UserHandle;
import android.util.ArrayMap;
import android.util.Log;
-import android.util.SparseArray;
import android.view.Display;
import com.android.car.CarLog;
@@ -58,6 +57,8 @@
import com.android.internal.annotations.VisibleForTesting;
import java.util.ArrayList;
+import java.util.Collections;
+import java.util.LinkedHashMap;
import java.util.List;
import java.util.Objects;
@@ -77,8 +78,12 @@
@GuardedBy("mLock")
ICarServiceHelper mICarServiceHelper;
+ // LinkedHashMap is used instead of SparseXXX because a predictable iteration order is needed.
+ // The tasks here need be ordered as per their stack order. The stack order is maintained
+ // using a combination of onTaskAppeared and onTaskInfoChanged callbacks.
@GuardedBy("mLock")
- private final SparseArray<TaskInfo> mTasks = new SparseArray<>();
+ private final LinkedHashMap<Integer, ActivityManager.RunningTaskInfo> mTasks =
+ new LinkedHashMap<>();
@GuardedBy("mLock")
private final ArrayMap<IBinder, IBinder.DeathRecipient> mTokens = new ArrayMap<>();
@GuardedBy("mLock")
@@ -261,14 +266,10 @@
if (!isAllowedToUpdateLocked(token)) {
return;
}
- TaskInfo oldTaskInfo = null;
- int index = mTasks.indexOfKey(taskInfo.taskId);
- if (index >= 0) {
- oldTaskInfo = mTasks.valueAt(index);
- mTasks.setValueAt(index, taskInfo);
- } else {
- mTasks.put(taskInfo.taskId, taskInfo);
- }
+ // The key should be removed and added again so that it jumps to the front of the
+ // LinkedHashMap.
+ TaskInfo oldTaskInfo = mTasks.remove(taskInfo.taskId);
+ mTasks.put(taskInfo.taskId, taskInfo);
if ((oldTaskInfo == null || !TaskInfoHelper.isVisible(oldTaskInfo)
|| !Objects.equals(oldTaskInfo.topActivity, taskInfo.topActivity))
&& TaskInfoHelper.isVisible(taskInfo)) {
@@ -284,19 +285,24 @@
cleanUpToken(token);
}
- public List<TaskInfo> getTopTasks() {
- ArrayList<TaskInfo> tasks = new ArrayList<>();
+ /**
+ * Returns all the visible tasks. The order is not guaranteed.
+ */
+ @Override
+ public List<ActivityManager.RunningTaskInfo> getVisibleTasks() {
+ ArrayList<ActivityManager.RunningTaskInfo> tasksToReturn = new ArrayList<>();
synchronized (mLock) {
- for (int i = 0, n = mTasks.size(); i < n; ++i) {
- TaskInfo taskInfo = mTasks.valueAt(i);
+ for (ActivityManager.RunningTaskInfo taskInfo : mTasks.values()) {
// Activities launched in the private display or non-focusable display can't be
// focusable. So we just monitor all visible Activities/Tasks.
if (TaskInfoHelper.isVisible(taskInfo)) {
- tasks.add(taskInfo);
+ tasksToReturn.add(taskInfo);
}
}
}
- return tasks;
+ // Reverse the order so that the resultant order is top to bottom.
+ Collections.reverse(tasksToReturn);
+ return tasksToReturn;
}
/**
@@ -333,8 +339,7 @@
public TaskInfo getTaskInfoForTopActivity(ComponentName activity) {
synchronized (mLock) {
- for (int i = 0, size = mTasks.size(); i < size; ++i) {
- TaskInfo info = mTasks.valueAt(i);
+ for (ActivityManager.RunningTaskInfo info : mTasks.values()) {
if (activity.equals(info.topActivity)) {
return info;
}
@@ -386,8 +391,8 @@
writer.println("*CarActivityService*");
writer.println(" Tasks:");
synchronized (mLock) {
- for (int i = 0; i < mTasks.size(); i++) {
- writer.println(" " + TaskInfoHelper.toString(mTasks.valueAt(i)));
+ for (ActivityManager.RunningTaskInfo taskInfo : mTasks.values()) {
+ writer.println(" " + TaskInfoHelper.toString(taskInfo));
}
}
}
diff --git a/service/src/com/android/car/am/FixedActivityService.java b/service/src/com/android/car/am/FixedActivityService.java
index 9ae9d5e..b61043d 100644
--- a/service/src/com/android/car/am/FixedActivityService.java
+++ b/service/src/com/android/car/am/FixedActivityService.java
@@ -47,6 +47,8 @@
import android.content.pm.PackageManager;
import android.hardware.display.DisplayManager;
import android.net.Uri;
+import android.os.BaseBundle;
+import android.os.Bundle;
import android.os.Handler;
import android.os.SystemClock;
import android.os.UserHandle;
@@ -66,7 +68,10 @@
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
+import java.lang.reflect.Array;
import java.util.List;
+import java.util.Objects;
+import java.util.Set;
/**
* Monitors top activity for a display and guarantee activity in fixed mode is re-launched if it has
@@ -89,12 +94,15 @@
public final Intent intent;
@NonNull
- public final ActivityOptions activityOptions;
+ public final Bundle activityOptions;
@UserIdInt
public final int userId;
public boolean isVisible;
+ // Whether startActivity was called for this Activity. If the flag is false,
+ // FixedActivityService will call startActivity() even if the Activity is currently visible.
+ public boolean isStarted;
public long lastLaunchTimeMs;
@@ -108,7 +116,7 @@
public boolean failureLogged;
- RunningActivityInfo(@NonNull Intent intent, @NonNull ActivityOptions activityOptions,
+ RunningActivityInfo(@NonNull Intent intent, @NonNull Bundle activityOptions,
@UserIdInt int userId) {
this.intent = intent;
this.activityOptions = activityOptions;
@@ -348,7 +356,7 @@
* launched. It will return false for {@link Display#INVALID_DISPLAY} {@code displayId}.
*/
private boolean launchIfNecessary(int displayId) {
- List<TaskInfo> infos = mActivityService.getTopTasks();
+ List<? extends TaskInfo> infos = mActivityService.getVisibleTasks();
if (infos == null) {
Slogf.e(TAG_AM, "cannot get RootTaskInfo from AM");
return false;
@@ -425,7 +433,7 @@
for (int i = 0; i < mRunningActivities.size(); i++) {
RunningActivityInfo activityInfo = mRunningActivities.valueAt(i);
long timeSinceLastLaunchMs = now - activityInfo.lastLaunchTimeMs;
- if (activityInfo.isVisible) {
+ if (activityInfo.isVisible && activityInfo.isStarted) {
if (timeSinceLastLaunchMs >= CRASH_FORGET_INTERVAL_MS) {
activityInfo.consecutiveRetries = 0;
}
@@ -465,9 +473,9 @@
postRecheck(RECHECK_INTERVAL_MS);
postRecheck(CRASH_FORGET_INTERVAL_MS);
ContextHelper.startActivityAsUser(mContext, activityInfo.intent,
- activityInfo.activityOptions.toBundle(),
- UserHandle.of(activityInfo.userId));
+ activityInfo.activityOptions, UserHandle.of(activityInfo.userId));
activityInfo.isVisible = true;
+ activityInfo.isStarted = true;
activityInfo.lastLaunchTimeMs = SystemClock.elapsedRealtime();
} catch (Exception e) { // Catch all for any app related issues.
Slogf.w(TAG_AM, "Cannot start activity:" + activityInfo.intent, e);
@@ -579,6 +587,7 @@
if (!isComponentAvailable(component, userId)) {
return false;
}
+ Bundle optionsBundle = options.toBundle();
boolean startMonitoringEvents = false;
synchronized (mLock) {
if (mRunningActivities.size() == 0) {
@@ -586,8 +595,8 @@
}
RunningActivityInfo activityInfo = mRunningActivities.get(displayId);
boolean replaceEntry = true;
- if (activityInfo != null && activityInfo.intent.equals(intent)
- && options.equals(activityInfo.activityOptions)
+ if (activityInfo != null && intentEquals(activityInfo.intent, intent)
+ && bundleEquals(optionsBundle, activityInfo.activityOptions)
&& userId == activityInfo.userId) {
replaceEntry = false;
if (activityInfo.isVisible) { // already shown.
@@ -595,7 +604,7 @@
}
}
if (replaceEntry) {
- activityInfo = new RunningActivityInfo(intent, options, userId);
+ activityInfo = new RunningActivityInfo(intent, optionsBundle, userId);
mRunningActivities.put(displayId, activityInfo);
}
}
@@ -628,4 +637,63 @@
stopMonitoringEvents();
}
}
+
+ // Intent doesn't have the deep equals method.
+ private static boolean intentEquals(Intent intent1, Intent intent2) {
+ // both are null? return true
+ if (intent1 == null && intent2 == null) {
+ return true;
+ }
+ // Only one is null? return false
+ if (intent1 == null || intent2 == null) {
+ return false;
+ }
+ return intent1.getComponent().equals(intent2.getComponent())
+ && bundleEquals(intent1.getExtras(), intent2.getExtras());
+ }
+
+ private static boolean bundleEquals(BaseBundle bundle1, BaseBundle bundle2) {
+ // both are null? return true
+ if (bundle1 == null && bundle2 == null) {
+ return true;
+ }
+ // Only one is null? return false
+ if (bundle1 == null || bundle2 == null) {
+ return false;
+ }
+ if (bundle1.size() != bundle2.size()) {
+ return false;
+ }
+ Set<String> keys = bundle1.keySet();
+ for (String key : keys) {
+ Object value1 = bundle1.get(key);
+ Object value2 = bundle2.get(key);
+ if (value1 != null && value1.getClass().isArray()
+ && value2 != null && value2.getClass().isArray()) {
+ if (!arrayEquals(value1, value2)) {
+ return false;
+ }
+ } else if (value1 instanceof BaseBundle && value2 instanceof BaseBundle) {
+ if (!bundleEquals((BaseBundle) value1, (BaseBundle) value2)) {
+ return false;
+ }
+ } else if (!Objects.equals(value1, value2)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ private static boolean arrayEquals(Object value1, Object value2) {
+ final int length = Array.getLength(value1);
+ if (length != Array.getLength(value2)) {
+ return false;
+ }
+ for (int i = 0; i < length; i++) {
+ if (!Objects.equals(Array.get(value1, i), Array.get(value2, i))) {
+ return false;
+ }
+ }
+ return true;
+ }
}
diff --git a/service/src/com/android/car/audio/CarAudioFocus.java b/service/src/com/android/car/audio/CarAudioFocus.java
index 2be1e80..d6f98ed 100644
--- a/service/src/com/android/car/audio/CarAudioFocus.java
+++ b/service/src/com/android/car/audio/CarAudioFocus.java
@@ -396,6 +396,13 @@
}
}
+ if (!delayFocusForCurrentRequest) {
+ // If the entry is replacing an existing one, and if a delayed Request is pending
+ // this replaced entry is not a blocker of the delayed.
+ // So add it before reconsidering the delayed.
+ mFocusHolders.put(afi.getClientId(), newEntry);
+ }
+
// Now that all new blockers have been added, clear out any other requests that have been
// permanently lost as a result of this request. Treat them as abandoned - if they're on
// any blocker lists, remove them. If any focus requests become unblocked as a result,
@@ -411,8 +418,6 @@
return AUDIOFOCUS_REQUEST_DELAYED;
}
- mFocusHolders.put(afi.getClientId(), newEntry);
-
Slogf.i(TAG, "AUDIOFOCUS_REQUEST_GRANTED");
return AUDIOFOCUS_REQUEST_GRANTED;
}
@@ -527,11 +532,14 @@
if (mDelayedRequest == null) {
return;
}
-
- int delayedFocusRequestResults = evaluateFocusRequestLocked(mDelayedRequest);
+ // Prevent cleanup of permanent lost to recall attemptToGainFocusForDelayedAudioFocusRequest
+ // Whatever granted / denied / delayed again, no need to restore, mDelayedRequest restored
+ // if delayed again.
+ AudioFocusInfo delayedFocusInfo = mDelayedRequest;
+ mDelayedRequest = null;
+ int delayedFocusRequestResults = evaluateFocusRequestLocked(delayedFocusInfo);
if (delayedFocusRequestResults == AUDIOFOCUS_REQUEST_GRANTED) {
- FocusEntry focusEntry = mFocusHolders.get(mDelayedRequest.getClientId());
- mDelayedRequest = null;
+ FocusEntry focusEntry = mFocusHolders.get(delayedFocusInfo.getClientId());
if (dispatchFocusGainedLocked(focusEntry.getAudioFocusInfo())
== AUDIOFOCUS_REQUEST_FAILED) {
Slogf.e(TAG, "Failure to signal gain of audio focus gain for "
@@ -543,6 +551,12 @@
logFocusEvent("Did not gained delayed audio focus for "
+ focusEntry.getClientId());
}
+ } else if (delayedFocusRequestResults == AUDIOFOCUS_REQUEST_FAILED) {
+ // Delayed request has permanently be denied
+ logFocusEvent("Delayed audio focus retry failed for " + delayedFocusInfo.getClientId());
+ sendFocusLossLocked(delayedFocusInfo, AUDIOFOCUS_LOSS);
+ } else {
+ assert mDelayedRequest.equals(delayedFocusInfo);
}
}
diff --git a/service/src/com/android/car/audio/CarAudioGainConfigInfo.java b/service/src/com/android/car/audio/CarAudioGainConfigInfo.java
index 0683c4e..33c6082 100644
--- a/service/src/com/android/car/audio/CarAudioGainConfigInfo.java
+++ b/service/src/com/android/car/audio/CarAudioGainConfigInfo.java
@@ -16,7 +16,6 @@
package com.android.car.audio;
-import android.annotation.NonNull;
import android.hardware.automotive.audiocontrol.AudioGainConfigInfo;
import java.util.Objects;
@@ -25,47 +24,61 @@
* Audio Gain Config Information for a given Device based on its address.
*/
public class CarAudioGainConfigInfo {
- private final int mZoneId;
- private final String mAddress;
- private final int mVolumeIndex;
-
- private CarAudioGainConfigInfo(int zoneId, @NonNull String address, int volumeIndex) {
- mZoneId = zoneId;
- mAddress = Objects.requireNonNull(address);
- mVolumeIndex = volumeIndex;
- }
+ private final AudioGainConfigInfo mAudioGainConfigInfo;
/**
- * Builds the car audio gain info configuration based on the {@link AudioGainConfigInfo}
- * @param audioGainConfig audio gain info
+ * Constructor of the car audio gain info configuration based on the {@link
+ * AudioGainConfigInfo}.
*
+ * @param audioGainConfigInfo {@link AudioGainConfigInfo} to convert.
* @return new car audio gain info
*/
- public static CarAudioGainConfigInfo build(AudioGainConfigInfo audioGainConfig) {
- return new CarAudioGainConfigInfo(audioGainConfig.zoneId,
- audioGainConfig.devicePortAddress, audioGainConfig.volumeIndex);
+ public CarAudioGainConfigInfo(AudioGainConfigInfo audioGainConfigInfo) {
+ mAudioGainConfigInfo = audioGainConfigInfo;
}
- /**
- * Creates {@link AudioGainConfigInfo} instance from contents of {@link CarAudioGainConfigInfo}.
- */
- public AudioGainConfigInfo generateAudioGainConfigInfo() {
- AudioGainConfigInfo agci = new AudioGainConfigInfo();
- agci.zoneId = mZoneId;
- agci.devicePortAddress = mAddress;
- agci.volumeIndex = mVolumeIndex;
- return agci;
+ public AudioGainConfigInfo getAudioGainConfigInfo() {
+ return mAudioGainConfigInfo;
}
public int getZoneId() {
- return mZoneId;
+ return mAudioGainConfigInfo.zoneId;
}
public String getDeviceAddress() {
- return mAddress;
+ return mAudioGainConfigInfo.devicePortAddress;
}
public int getVolumeIndex() {
- return mVolumeIndex;
+ return mAudioGainConfigInfo.volumeIndex;
+ }
+
+ /** Returns the string representation of the car audio gain configuration */
+ public String toString() {
+ return "zone: "
+ + getZoneId()
+ + ", address: "
+ + getDeviceAddress()
+ + ", Volume Index: "
+ + getVolumeIndex();
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (!(o instanceof CarAudioGainConfigInfo)) {
+ return false;
+ }
+ CarAudioGainConfigInfo other = (CarAudioGainConfigInfo) o;
+ return getZoneId() == other.getZoneId()
+ && getDeviceAddress().equals(other.getDeviceAddress())
+ && getVolumeIndex() == other.getVolumeIndex();
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(getZoneId(), getDeviceAddress(), getVolumeIndex());
}
}
diff --git a/service/src/com/android/car/audio/CarAudioGainMonitor.java b/service/src/com/android/car/audio/CarAudioGainMonitor.java
new file mode 100644
index 0000000..8ab0a02
--- /dev/null
+++ b/service/src/com/android/car/audio/CarAudioGainMonitor.java
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2022 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.audio;
+
+import android.annotation.NonNull;
+import android.car.builtin.util.Slogf;
+import android.hardware.automotive.audiocontrol.Reasons;
+import android.util.SparseArray;
+
+import com.android.car.CarLog;
+import com.android.car.audio.hal.AudioControlWrapper;
+import com.android.car.audio.hal.HalAudioGainCallback;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * Provides audio gain callback registration helpers and implements AudioGain listener business
+ * logic.
+ */
+/* package */ final class CarAudioGainMonitor {
+ @NonNull private final AudioControlWrapper mAudioControlWrapper;
+ @NonNull private final SparseArray<CarAudioZone> mCarAudioZones;
+
+ CarAudioGainMonitor(
+ AudioControlWrapper audioControlWrapper,
+ SparseArray<CarAudioZone> carAudioZones) {
+ mAudioControlWrapper =
+ Objects.requireNonNull(
+ audioControlWrapper, "Audio Control Wrapper can not be null");
+ mCarAudioZones = Objects.requireNonNull(carAudioZones, "Car Audio Zones can not be null");
+ }
+
+ public void reset() {
+ // TODO (b/224885748): handle specific logic on IAudioControl service died event
+ }
+
+ /**
+ * Registers {@code HalAudioGainCallback} on {@code AudioControlWrapper} to receive HAL audio
+ * gain change notifications.
+ */
+ public void registerAudioGainListener(HalAudioGainCallback callback) {
+ Objects.requireNonNull(callback, "Hal Audio Gain callback can not be null");
+ mAudioControlWrapper.registerAudioGainCallback(callback);
+ }
+
+ /** Unregisters {@code HalAudioGainCallback} from {@code AudioControlWrapper}. */
+ public void unregisterAudioGainListener() {
+ mAudioControlWrapper.unregisterAudioGainCallback();
+ }
+
+ /**
+ * Audio Gain event dispatcher. Implements the callback that triggered from {@link
+ * IAudioGainCallback#onAudioDeviceGainsChanged} with the list of reasons and the list of {@link
+ * CarAudioGainConfigInfo} involved. It is in charge of dispatching /delegating to the zone the
+ * {@link CarAudioGainConfigInfo} belongs the processing of the callback.
+ */
+ void handleAudioDeviceGainsChanged(List<Integer> reasons, List<CarAudioGainConfigInfo> gains) {
+ // Delegate to CarAudioZone / CarVolumeGroup
+ // Group gains by Audio Zones first
+ SparseArray<List<CarAudioGainConfigInfo>> gainsByZones = new SparseArray<>();
+ for (int index = 0; index < gains.size(); index++) {
+ CarAudioGainConfigInfo gain = gains.get(index);
+ int zone = gain.getZoneId();
+ if (!gainsByZones.contains(zone)) {
+ gainsByZones.put(zone, new ArrayList<>(1));
+ }
+ gainsByZones.get(zone).add(gain);
+ }
+ for (int i = 0; i < gainsByZones.size(); i++) {
+ int zoneId = gainsByZones.keyAt(i);
+ if (!mCarAudioZones.contains(zoneId)) {
+ Slogf.e(
+ CarLog.TAG_AUDIO,
+ "onAudioDeviceGainsChanged reported change on invalid "
+ + "zone: %d, reasons=%s, gains=%s",
+ zoneId,
+ reasons,
+ gains);
+ continue;
+ }
+ CarAudioZone carAudioZone = mCarAudioZones.get(zoneId);
+ carAudioZone.onAudioGainChanged(reasons, gainsByZones.valueAt(i));
+ }
+ }
+
+ static boolean shouldBlockVolumeRequest(List<Integer> reasons) {
+ return reasons.contains(Reasons.FORCED_MASTER_MUTE)
+ || reasons.contains(Reasons.TCU_MUTE)
+ || reasons.contains(Reasons.REMOTE_MUTE);
+ }
+
+ static boolean shouldLimitVolume(List<Integer> reasons) {
+ return reasons.contains(Reasons.THERMAL_LIMITATION)
+ || reasons.contains(Reasons.SUSPEND_EXIT_VOL_LIMITATION);
+ }
+
+ static boolean shouldDuckGain(List<Integer> reasons) {
+ return reasons.contains(Reasons.ADAS_DUCKING) || reasons.contains(Reasons.NAV_DUCKING);
+ }
+}
diff --git a/service/src/com/android/car/audio/CarAudioService.java b/service/src/com/android/car/audio/CarAudioService.java
index 9316b5c..148faa6 100644
--- a/service/src/com/android/car/audio/CarAudioService.java
+++ b/service/src/com/android/car/audio/CarAudioService.java
@@ -76,6 +76,7 @@
import com.android.car.audio.hal.AudioControlWrapper;
import com.android.car.audio.hal.AudioControlWrapperV1;
import com.android.car.audio.hal.HalAudioFocus;
+import com.android.car.audio.hal.HalAudioGainCallback;
import com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport;
import com.android.car.internal.annotation.AttributeUsage;
import com.android.car.internal.util.IndentingPrintWriter;
@@ -146,6 +147,7 @@
private CarDucking mCarDucking;
private CarVolumeGroupMuting mCarVolumeGroupMuting;
private HalAudioFocus mHalAudioFocus;
+ private @Nullable CarAudioGainMonitor mCarAudioGainMonitor;
private CarOccupantZoneService mOccupantZoneService;
@@ -196,6 +198,17 @@
private CarAudioPlaybackCallback mCarAudioPlaybackCallback;
private CarAudioPowerListener mCarAudioPowerListener;
+ private final HalAudioGainCallback mHalAudioGainCallback =
+ new HalAudioGainCallback() {
+ @Override
+ public void onAudioDeviceGainsChanged(
+ List<Integer> halReasons, List<CarAudioGainConfigInfo> gains) {
+ synchronized (mImplLock) {
+ handleAudioDeviceGainsChangedLocked(halReasons, gains);
+ }
+ }
+ };
+
public CarAudioService(Context context) {
this(context, getAudioConfigurationPath());
}
@@ -691,10 +704,8 @@
Slogf.d(CarLog.TAG_AUDIO, "HalAudioGainCallback is not supported on this device");
return;
}
- mAudioControlWrapper.registerAudioGainCallback((reasons, gains) -> {
- // TODO(b/224886068): Add missing audio gain management
- Slogf.d(CarLog.TAG_AUDIO, "onAudioGainChanged reasons" + reasons + ", gains=" + gains);
- });
+ mCarAudioGainMonitor = new CarAudioGainMonitor(mAudioControlWrapper, mCarAudioZones);
+ mCarAudioGainMonitor.registerAudioGainListener(mHalAudioGainCallback);
}
/**
@@ -1482,11 +1493,21 @@
}
}
+ private void resetHalAudioGain() {
+ if (mCarAudioGainMonitor != null) {
+ mCarAudioGainMonitor.reset();
+ mCarAudioGainMonitor.registerAudioGainListener(mHalAudioGainCallback);
+ }
+ }
+
+ private void handleAudioDeviceGainsChangedLocked(
+ List<Integer> halReasons, List<CarAudioGainConfigInfo> gains) {
+ mCarAudioGainMonitor.handleAudioDeviceGainsChanged(halReasons, gains);
+ }
+
private void audioControlDied() {
resetHalAudioFocus();
- synchronized (mImplLock) {
- setupHalAudioGainCallbackLocked();
- }
+ resetHalAudioGain();
}
boolean isAudioZoneIdValid(int zoneId) {
diff --git a/service/src/com/android/car/audio/CarAudioZone.java b/service/src/com/android/car/audio/CarAudioZone.java
index db0ead9..4964650 100644
--- a/service/src/com/android/car/audio/CarAudioZone.java
+++ b/service/src/com/android/car/audio/CarAudioZone.java
@@ -252,4 +252,17 @@
private boolean containsDeviceAddress(String deviceAddress) {
return mDeviceAddresses.contains(deviceAddress);
}
+
+ void onAudioGainChanged(List<Integer> halReasons, List<CarAudioGainConfigInfo> gains) {
+ for (int index = 0; index < gains.size(); index++) {
+ CarAudioGainConfigInfo gainInfo = gains.get(index);
+ for (int groupIndex = 0; groupIndex < mVolumeGroups.size(); groupIndex++) {
+ CarVolumeGroup group = mVolumeGroups.get(groupIndex);
+ if (group.getAddresses().contains(gainInfo.getDeviceAddress())) {
+ group.onAudioGainChanged(halReasons, gainInfo);
+ break; // loop of CarVolumeGroup.
+ }
+ }
+ }
+ }
}
diff --git a/service/src/com/android/car/audio/CarDucking.java b/service/src/com/android/car/audio/CarDucking.java
index 24bc4ed..be90dc0 100644
--- a/service/src/com/android/car/audio/CarDucking.java
+++ b/service/src/com/android/car/audio/CarDucking.java
@@ -49,8 +49,10 @@
mAudioControlWrapper = Objects.requireNonNull(audioControlWrapper);
for (int i = 0; i < carAudioZones.size(); i++) {
int zoneId = carAudioZones.keyAt(i);
- mCurrentDuckingInfo.put(zoneId,
- new CarDuckingInfo(zoneId, new ArrayList<>(), new ArrayList<>(), new int[0]));
+ mCurrentDuckingInfo.put(
+ zoneId,
+ new CarDuckingInfo(
+ zoneId, new ArrayList<>(), new ArrayList<>(), new ArrayList<>()));
}
}
@@ -104,11 +106,6 @@
int zoneId = oldDuckingInfo.mZoneId;
CarAudioZone zone = mCarAudioZones.get(zoneId);
- int[] usagesHoldingFocus = CarDuckingUtils.getUsagesHoldingFocus(focusHolders);
- List<String> addressesToDuck = CarDuckingUtils.getAddressesToDuck(usagesHoldingFocus, zone);
- List<String> addressesToUnduck = CarDuckingUtils.getAddressesToUnduck(addressesToDuck,
- oldDuckingInfo.mAddressesToDuck);
-
- return new CarDuckingInfo(zoneId, addressesToDuck, addressesToUnduck, usagesHoldingFocus);
+ return CarDuckingUtils.generateDuckingInfo(oldDuckingInfo, focusHolders, zone);
}
}
diff --git a/service/src/com/android/car/audio/CarDuckingInfo.java b/service/src/com/android/car/audio/CarDuckingInfo.java
index 5f4b4f1..8c35e74 100644
--- a/service/src/com/android/car/audio/CarDuckingInfo.java
+++ b/service/src/com/android/car/audio/CarDuckingInfo.java
@@ -17,15 +17,17 @@
package com.android.car.audio;
import static android.car.builtin.media.AudioManagerHelper.usageToXsdString;
+import static android.media.audio.common.AudioContentType.UNKNOWN;
import static com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport.DUMP_INFO;
import android.annotation.NonNull;
-import android.hardware.automotive.audiocontrol.DuckingInfo;
+import android.hardware.audio.common.PlaybackTrackMetadata;
import com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport;
import com.android.car.internal.util.IndentingPrintWriter;
+import java.util.Arrays;
import java.util.List;
import java.util.Objects;
@@ -36,33 +38,33 @@
public final int mZoneId;
public final List<String> mAddressesToDuck;
public final List<String> mAddressesToUnduck;
- public final int[] mUsagesHoldingFocus;
+ public final List<PlaybackTrackMetadata> mPlaybackMetaDataHoldingFocus;
- public CarDuckingInfo(int zoneId, @NonNull List<String> addressesToDuck,
- @NonNull List<String> addressesToUnduck, @NonNull int[] usagesHoldingFocus) {
+ public CarDuckingInfo(
+ int zoneId,
+ @NonNull List<String> addressesToDuck,
+ @NonNull List<String> addressesToUnduck,
+ @NonNull List<PlaybackTrackMetadata> playbackMetaDataHoldingFocus) {
mZoneId = zoneId;
mAddressesToDuck = Objects.requireNonNull(addressesToDuck);
mAddressesToUnduck = Objects.requireNonNull(addressesToUnduck);
- mUsagesHoldingFocus = Objects.requireNonNull(usagesHoldingFocus);
+ mPlaybackMetaDataHoldingFocus = Objects.requireNonNull(playbackMetaDataHoldingFocus);
}
- /**
- * Creates {@link DuckingInfo} instance from contents of {@link CarDuckingInfo}.
- *
- * <p>Converts usages to XSD strings as part of this process.
- */
- public DuckingInfo generateDuckingInfo() {
- DuckingInfo duckingInfo = new DuckingInfo();
- duckingInfo.zoneId = mZoneId;
- duckingInfo.deviceAddressesToDuck = mAddressesToDuck.toArray(new String[0]);
- duckingInfo.deviceAddressesToUnduck = mAddressesToUnduck.toArray(new String[0]);
- String[] usageStrings = new String[mUsagesHoldingFocus.length];
- for (int i = 0; i < mUsagesHoldingFocus.length; i++) {
- usageStrings[i] = usageToXsdString(mUsagesHoldingFocus[i]);
- }
- duckingInfo.usagesHoldingFocus = usageStrings;
+ public int getZoneId() {
+ return mZoneId;
+ }
- return duckingInfo;
+ public @NonNull List<String> getAddressesToDuck() {
+ return mAddressesToDuck;
+ }
+
+ public @NonNull List<String> getAddressesToUnduck() {
+ return mAddressesToUnduck;
+ }
+
+ public @NonNull List<PlaybackTrackMetadata> getPlaybackMetaDataHoldingFocus() {
+ return mPlaybackMetaDataHoldingFocus;
}
@ExcludeFromCodeCoverageGeneratedReport(reason = DUMP_INFO)
@@ -73,10 +75,19 @@
String.join(", ", mAddressesToDuck));
writer.printf("Addresses to unduck: %s\n",
String.join(", ", mAddressesToUnduck));
- writer.println("Usages holding focus:");
+ writer.println("Audio Attributes holding focus:");
writer.increaseIndent();
- for (int usage : mUsagesHoldingFocus) {
- writer.printf("%s, ", usageToXsdString(usage));
+ for (int index = 0; index < mPlaybackMetaDataHoldingFocus.size(); index++) {
+ PlaybackTrackMetadata playbackTrackMetaData = mPlaybackMetaDataHoldingFocus.get(index);
+ writer.printf(
+ "usage=%s, content type=%s, tags=%s\n",
+ usageToXsdString(playbackTrackMetaData.usage),
+ (playbackTrackMetaData.contentType != UNKNOWN
+ ? playbackTrackMetaData.contentType
+ : ""),
+ (playbackTrackMetaData.tags.length != 0
+ ? Arrays.toString(playbackTrackMetaData.tags)
+ : ""));
}
writer.decreaseIndent();
writer.println();
diff --git a/service/src/com/android/car/audio/CarDuckingUtils.java b/service/src/com/android/car/audio/CarDuckingUtils.java
index e0998fc..0861c68 100644
--- a/service/src/com/android/car/audio/CarDuckingUtils.java
+++ b/service/src/com/android/car/audio/CarDuckingUtils.java
@@ -109,6 +109,20 @@
private CarDuckingUtils() {
}
+ static CarDuckingInfo generateDuckingInfo(
+ CarDuckingInfo oldDuckingInfo, List<AudioFocusInfo> focusHolders, CarAudioZone zone) {
+ int[] usagesHoldingFocus = getUsagesHoldingFocus(focusHolders);
+ List<String> addressesToDuck = getAddressesToDuck(usagesHoldingFocus, zone);
+ List<String> addressesToUnduck =
+ getAddressesToUnduck(addressesToDuck, oldDuckingInfo.mAddressesToDuck);
+
+ return new CarDuckingInfo(
+ zone.getId(),
+ addressesToDuck,
+ addressesToUnduck,
+ CarHalAudioUtils.usagesToMetadatas(usagesHoldingFocus, zone));
+ }
+
static int[] getUsagesHoldingFocus(List<AudioFocusInfo> focusHolders) {
Set<Integer> uniqueUsages = new HashSet<>();
for (AudioFocusInfo focusInfo : focusHolders) {
diff --git a/service/src/com/android/car/audio/CarHalAudioUtils.java b/service/src/com/android/car/audio/CarHalAudioUtils.java
new file mode 100644
index 0000000..89f820d
--- /dev/null
+++ b/service/src/com/android/car/audio/CarHalAudioUtils.java
@@ -0,0 +1,138 @@
+/*
+ * Copyright (C) 2022 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.audio;
+
+import static android.car.builtin.media.AudioManagerHelper.usageToXsdString;
+
+import android.annotation.Nullable;
+import android.hardware.audio.common.PlaybackTrackMetadata;
+import android.hardware.automotive.audiocontrol.DuckingInfo;
+import android.media.audio.common.AudioChannelLayout;
+import android.media.audio.common.AudioDevice;
+import android.media.audio.common.AudioDeviceAddress;
+import android.media.audio.common.AudioDeviceDescription;
+
+import com.android.car.internal.annotation.AttributeUsage;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+
+/** Car HAL audio Utils */
+public final class CarHalAudioUtils {
+ private CarHalAudioUtils() {}
+
+ /**
+ * Creates {@link DuckingInfo} instance from contents of {@link CarDuckingInfo}.
+ *
+ * <p>Converts usages to XSD strings as part of this process.
+ */
+ public static DuckingInfo generateDuckingInfo(CarDuckingInfo carDuckingInfo) {
+ Objects.requireNonNull(carDuckingInfo, "Car Ducking Info can not be null");
+ DuckingInfo duckingInfo = new DuckingInfo();
+ duckingInfo.zoneId = carDuckingInfo.getZoneId();
+ duckingInfo.deviceAddressesToDuck =
+ carDuckingInfo.getAddressesToDuck().toArray(new String[0]);
+ duckingInfo.deviceAddressesToUnduck =
+ carDuckingInfo.getAddressesToUnduck().toArray(new String[0]);
+ List<PlaybackTrackMetadata> playbackTrackMetadataList =
+ carDuckingInfo.getPlaybackMetaDataHoldingFocus();
+ duckingInfo.playbackMetaDataHoldingFocus =
+ playbackTrackMetadataList.toArray(PlaybackTrackMetadata[]::new);
+ duckingInfo.usagesHoldingFocus = metadatasToUsageStrings(playbackTrackMetadataList);
+ return duckingInfo;
+ }
+
+ /**
+ * Converts the {@link AttributeUsage} into a metadate for a particular
+ * audio zone.
+ *
+ */
+ public static PlaybackTrackMetadata usageToMetadata(
+ @AttributeUsage int usage, @Nullable CarAudioZone zone) {
+ PlaybackTrackMetadata playbackTrackMetadata = new PlaybackTrackMetadata();
+ playbackTrackMetadata.usage = usage;
+ playbackTrackMetadata.tags = new String[0];
+ playbackTrackMetadata.channelMask = AudioChannelLayout.none(0);
+ AudioDeviceDescription audioDeviceDescription = new AudioDeviceDescription();
+ audioDeviceDescription.connection = new String();
+ AudioDevice audioDevice = new AudioDevice();
+ audioDevice.type = audioDeviceDescription;
+ audioDevice.address =
+ AudioDeviceAddress.id(
+ zone != null
+ ? zone.getAddressForContext(
+ CarAudioContext.getContextForUsage(usage))
+ : new String(""));
+ playbackTrackMetadata.sourceDevice = audioDevice;
+ return playbackTrackMetadata;
+ }
+
+ /**
+ * Converts the list of {@link AttributeUsage} usages into
+ * Playback metadata for a particular zone.
+ *
+ */
+ public static List<PlaybackTrackMetadata> usagesToMetadatas(
+ @AttributeUsage int[] usages, @Nullable CarAudioZone zone) {
+ List<PlaybackTrackMetadata> playbackTrackMetadataList = new ArrayList<>(usages.length);
+ for (int index = 0; index < usages.length; index++) {
+ int usage = usages[index];
+ playbackTrackMetadataList.add(usageToMetadata(usage, zone));
+ }
+ return playbackTrackMetadataList;
+ }
+
+ /**
+ * Converts a playback track metadata into the corresponding
+ * audio usages.
+ *
+ */
+ public static @AttributeUsage int metadataToUsage(
+ PlaybackTrackMetadata playbackTrackMetadataList) {
+ return playbackTrackMetadataList.usage;
+ }
+
+ /**
+ * Converts a list playback track metadata into an array
+ * of audio usages.
+ *
+ */
+ public static @AttributeUsage int[] metadatasToUsages(
+ List<PlaybackTrackMetadata> playbackTrackMetadataList) {
+ @AttributeUsage int[] usagesForMetadata = new int[playbackTrackMetadataList.size()];
+ for (int index = 0; index < playbackTrackMetadataList.size(); index++) {
+ PlaybackTrackMetadata playbackTrackMetadata = playbackTrackMetadataList.get(index);
+ usagesForMetadata[index] = playbackTrackMetadata.usage;
+ }
+ return usagesForMetadata;
+ }
+
+ /**
+ * Converts a list of playback track metadata into an array of
+ * audio usages in string representation.
+ */
+ public static String[] metadatasToUsageStrings(
+ List<PlaybackTrackMetadata> playbackTrackMetadataList) {
+ String[] usageLiteralsForMetadata = new String[playbackTrackMetadataList.size()];
+ for (int index = 0; index < playbackTrackMetadataList.size(); index++) {
+ PlaybackTrackMetadata playbackTrackMetadata = playbackTrackMetadataList.get(index);
+ usageLiteralsForMetadata[index] = usageToXsdString(playbackTrackMetadata.usage);
+ }
+ return usageLiteralsForMetadata;
+ }
+}
diff --git a/service/src/com/android/car/audio/CarVolumeGroup.java b/service/src/com/android/car/audio/CarVolumeGroup.java
index dfc3558..5f1ad1b 100644
--- a/service/src/com/android/car/audio/CarVolumeGroup.java
+++ b/service/src/com/android/car/audio/CarVolumeGroup.java
@@ -15,6 +15,7 @@
*/
package com.android.car.audio;
+import static com.android.car.audio.hal.HalAudioGainCallback.reasonToString;
import static com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport.BOILERPLATE_CODE;
import static com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport.DUMP_INFO;
@@ -50,6 +51,8 @@
*/
/* package */ final class CarVolumeGroup {
+ public static final int UNINITIALIZED = -1;
+
private final boolean mUseCarVolumeGroupMute;
private final boolean mHasCriticalAudioContexts;
private final CarAudioSettings mSettingsManager;
@@ -66,13 +69,48 @@
@GuardedBy("mLock")
private int mStoredGainIndex;
+
@GuardedBy("mLock")
- private int mCurrentGainIndex = -1;
+ private int mCurrentGainIndex = UNINITIALIZED;
+
@GuardedBy("mLock")
private boolean mIsMuted;
@GuardedBy("mLock")
private @UserIdInt int mUserId = UserHandle.CURRENT.getIdentifier();
+ /**
+ * Attenuated gain is set to {@see CarAudioDeviceInfo#UNINITIALIZED} till attenuation explicitly
+ * reported by {@see HalAudioGainCallback#onAudioDeviceGainsChanged} for one or more {@see
+ * android.hardware.automotive.audiocontrol#Reasons}. When the reason is cleared, it returns
+ * back to {@see CarAudioDeviceInfo#UNINITIALIZED}.
+ */
+ @GuardedBy("mLock")
+ private int mAttenuatedGainIndex = UNINITIALIZED;
+
+ /**
+ * Limitation gain is set to max gain value till limitation explicitly reported by {@see
+ * HalAudioGainCallback#onAudioDeviceGainsChanged} for one or more {@see
+ * android.hardware.automotive.audiocontrol#Reasons}. When the reason is cleared, it returns
+ * back to max.
+ */
+ @GuardedBy("mLock")
+ private int mLimitedGainIndex;
+
+ /**
+ * Blocked gain is set to {@see CarAudioDeviceInfo#UNINITIALIZED} till blocking case explicitly
+ * reported by {@see HalAudioGainCallback#onAudioDeviceGainsChanged} for one or more {@see
+ * android.hardware.automotive.audiocontrol#Reasons}. When the reason is cleared, it returns
+ * back to {@see CarAudioDeviceInfo#UNINITIALIZED}.
+ */
+ @GuardedBy("mLock")
+ private int mBlockedGainIndex = UNINITIALIZED;
+
+ /**
+ * Reasons list currently reported for this port by {@see
+ * HalAudioGainCallback#onAudioDeviceGainsChanged}.
+ */
+ private List<Integer> mReasons = new ArrayList<>();
+
private CarVolumeGroup(int zoneId, int id, CarAudioSettings settingsManager, int stepSize,
int defaultGain, int minGain, int maxGain, SparseArray<String> contextToAddress,
Map<String, CarAudioDeviceInfo> addressToCarAudioDeviceInfo,
@@ -85,6 +123,7 @@
mDefaultGain = defaultGain;
mMinGain = minGain;
mMaxGain = maxGain;
+ mLimitedGainIndex = getIndexForGain(mMaxGain);
mContextToAddress = contextToAddress;
mAddressToCarAudioDeviceInfo = addressToCarAudioDeviceInfo;
mUseCarVolumeGroupMute = useCarVolumeGroupMute;
@@ -100,6 +139,121 @@
}
}
+ @GuardedBy("mLock")
+ private void setBlockedLocked(int blockedIndex) {
+ mBlockedGainIndex = blockedIndex;
+ }
+
+ @GuardedBy("mLock")
+ private void resetBlockedLocked() {
+ setBlockedLocked(UNINITIALIZED);
+ }
+
+ @GuardedBy("mLock")
+ private boolean isBlockedLocked() {
+ return mBlockedGainIndex != UNINITIALIZED;
+ }
+
+ @GuardedBy("mLock")
+ private void setLimitLocked(int limitIndex) {
+ mLimitedGainIndex = limitIndex;
+ }
+
+ @GuardedBy("mLock")
+ private void resetLimitLocked() {
+ setLimitLocked(getIndexForGain(mMaxGain));
+ }
+
+ @GuardedBy("mLock")
+ private boolean isLimitedLocked() {
+ return mLimitedGainIndex != getIndexForGain(mMaxGain);
+ }
+
+ @GuardedBy("mLock")
+ private boolean isOverLimitLocked() {
+ return isOverLimitLocked(mCurrentGainIndex);
+ }
+
+ @GuardedBy("mLock")
+ private boolean isOverLimitLocked(int index) {
+ return isLimitedLocked() && (index > mLimitedGainIndex);
+ }
+
+ @GuardedBy("mLock")
+ private void setAttenuatedGainLocked(int attenuatedGainIndex) {
+ mAttenuatedGainIndex = attenuatedGainIndex;
+ }
+
+ @GuardedBy("mLock")
+ private void resetAttenuationLocked() {
+ setAttenuatedGainLocked(UNINITIALIZED);
+ }
+
+ @GuardedBy("mLock")
+ private boolean isAttenuatedLocked() {
+ return mAttenuatedGainIndex != UNINITIALIZED;
+ }
+
+ void setBlocked(int blockedIndex) {
+ synchronized (mLock) {
+ setBlockedLocked(blockedIndex);
+ }
+ }
+
+ void resetBlocked() {
+ synchronized (mLock) {
+ resetBlockedLocked();
+ }
+ }
+
+ boolean isBlocked() {
+ synchronized (mLock) {
+ return isBlockedLocked();
+ }
+ }
+
+ void setLimit(int limitIndex) {
+ synchronized (mLock) {
+ setLimitLocked(limitIndex);
+ }
+ }
+
+ void resetLimit() {
+ synchronized (mLock) {
+ resetLimitLocked();
+ }
+ }
+
+ boolean isLimited() {
+ synchronized (mLock) {
+ return isLimitedLocked();
+ }
+ }
+
+ boolean isOverLimit() {
+ synchronized (mLock) {
+ return isOverLimitLocked();
+ }
+ }
+
+ void setAttenuatedGain(int attenuatedGainIndex) {
+ synchronized (mLock) {
+ setAttenuatedGainLocked(attenuatedGainIndex);
+ }
+ }
+
+ void resetAttenuation() {
+ synchronized (mLock) {
+ resetAttenuationLocked();
+ }
+ }
+
+ boolean isAttenuated() {
+ synchronized (mLock) {
+ return isAttenuatedLocked();
+ }
+ }
+
@Nullable
CarAudioDeviceInfo getCarAudioDeviceInfoForAddress(String address) {
return mAddressToCarAudioDeviceInfo.get(address);
@@ -175,6 +329,21 @@
if (mIsMuted) {
return getIndexForGain(mMinGain);
}
+ if (isBlockedLocked()) {
+ return mBlockedGainIndex;
+ }
+ if (isAttenuatedLocked()) {
+ // Need to figure out if attenuation shall be hidden to end user
+ // as while ducked from IAudioControl
+ // Also, keep unchanged current index / use it as a cache of previous value
+ //
+ // TODO(b/) clarify in case of volume adjustment if the reference index is the
+ // ducked index or the current index. Taking current may lead to gap of index > 1.
+ return mAttenuatedGainIndex;
+ }
+ if (isOverLimitLocked()) {
+ return mLimitedGainIndex;
+ }
return getCurrentGainIndexLocked();
}
}
@@ -191,10 +360,26 @@
Preconditions.checkArgument(isValidGainIndex(gainIndex),
"Gain out of range (%d:%d) index %d", mMinGain, mMaxGain, gainIndex);
synchronized (mLock) {
+ if (isBlockedLocked()) {
+ // prevent any volume change while {@link IAudioGainCallback} reported block event.
+ // TODO(b/) callback mecanism to inform HMI/User of failure and reason why if needed
+ return;
+ }
+ if (isOverLimitLocked(gainIndex)) {
+ // TODO(b/) callback to inform if over limit index and why if needed.
+ gainIndex = mLimitedGainIndex;
+ }
+ if (isAttenuatedLocked()) {
+ resetAttenuationLocked();
+ }
if (mIsMuted) {
setMuteLocked(false);
}
- setCurrentGainIndexLocked(gainIndex);
+ // In case of attenuation/Limitation, requested index is now the new reference for
+ // cached current index.
+ mCurrentGainIndex = gainIndex;
+
+ setCurrentGainIndexLocked(mCurrentGainIndex);
}
}
@@ -205,10 +390,7 @@
CarAudioDeviceInfo info = mAddressToCarAudioDeviceInfo.get(address);
info.setCurrentGain(gainInMillibels);
}
-
- mCurrentGainIndex = gainIndex;
-
- storeGainIndexForUserLocked(mCurrentGainIndex, mUserId);
+ storeGainIndexForUserLocked(gainIndex, mUserId);
}
boolean hasCriticalAudioContexts() {
@@ -249,7 +431,28 @@
mAddressToCarAudioDeviceInfo.keySet().stream()
.map(mAddressToCarAudioDeviceInfo::get)
.forEach((info -> info.dump(writer)));
-
+ writer.printf("Reported reasons:\n");
+ writer.increaseIndent();
+ for (int index = 0; index < mReasons.size(); index++) {
+ int reason = mReasons.get(index);
+ writer.printf("%s\n", reasonToString(reason));
+ }
+ writer.decreaseIndent();
+ writer.printf("Gain infos:\n");
+ writer.increaseIndent();
+ writer.printf(
+ "Blocked: %b%s\n",
+ isBlockedLocked(),
+ (isBlockedLocked() ? " (at: " + mBlockedGainIndex + ")" : ""));
+ writer.printf(
+ "Limited: %b%s\n",
+ isLimitedLocked(),
+ (isLimitedLocked() ? " (at: " + mLimitedGainIndex + ")" : ""));
+ writer.printf(
+ "Attenuated: %b%s\n",
+ isAttenuatedLocked(),
+ (isAttenuatedLocked() ? " (at: " + mAttenuatedGainIndex + ")" : ""));
+ writer.decreaseIndent();
// Empty line for comfortable reading
writer.println();
writer.decreaseIndent();
@@ -362,6 +565,51 @@
mIsMuted = mSettingsManager.getVolumeGroupMuteForUser(mUserId, mZoneId, mId);
}
+ void onAudioGainChanged(List<Integer> halReasons, CarAudioGainConfigInfo gain) {
+ if (getCarAudioDeviceInfoForAddress(gain.getDeviceAddress()) == null) {
+ Slogf.e(
+ CarLog.TAG_AUDIO,
+ "onAudioGainChanged no port found for address %s on group %d",
+ gain.getDeviceAddress(),
+ mId);
+ return;
+ }
+ synchronized (mLock) {
+ mReasons = new ArrayList<>(halReasons);
+ int halIndex = gain.getVolumeIndex();
+ if (CarAudioGainMonitor.shouldBlockVolumeRequest(halReasons)) {
+ setBlockedLocked(halIndex);
+ } else {
+ resetBlockedLocked();
+ }
+ if (CarAudioGainMonitor.shouldLimitVolume(halReasons)) {
+ setLimitLocked(halIndex);
+ } else {
+ resetLimitLocked();
+ }
+ if (CarAudioGainMonitor.shouldDuckGain(halReasons)) {
+ setAttenuatedGainLocked(halIndex);
+ } else {
+ resetAttenuationLocked();
+ }
+ int indexToBroadCast = mCurrentGainIndex;
+ if (isBlockedLocked()) {
+ indexToBroadCast = mBlockedGainIndex;
+ } else if (isAttenuatedLocked()) {
+ indexToBroadCast = mAttenuatedGainIndex;
+ } else if (isOverLimitLocked()) {
+ // TODO(b/) callback to inform if over limit index and why if needed.
+ indexToBroadCast = mLimitedGainIndex;
+ }
+ // Blocked/Attenuated index shall have been already apply by Audio HAL on HW.
+ // However, keep in sync & broadcast to all ports this volume group deals with.
+ //
+ // Do not update current gain cache, keep it for restoring rather using reported index
+ // when the event is cleared.
+ setCurrentGainIndexLocked(indexToBroadCast);
+ }
+ }
+
static final class Builder {
private static final int UNSET_STEP_SIZE = -1;
diff --git a/service/src/com/android/car/audio/OWNERS b/service/src/com/android/car/audio/OWNERS
deleted file mode 100644
index ba81180..0000000
--- a/service/src/com/android/car/audio/OWNERS
+++ /dev/null
@@ -1,3 +0,0 @@
-# Audio owners
-oscarazu@google.com
-xuweilin@google.com
diff --git a/service/src/com/android/car/audio/hal/AudioControlWrapperAidl.java b/service/src/com/android/car/audio/hal/AudioControlWrapperAidl.java
index d280920..e299fe8 100644
--- a/service/src/com/android/car/audio/hal/AudioControlWrapperAidl.java
+++ b/service/src/com/android/car/audio/hal/AudioControlWrapperAidl.java
@@ -40,20 +40,19 @@
import com.android.car.CarLog;
import com.android.car.audio.CarAudioGainConfigInfo;
import com.android.car.audio.CarDuckingInfo;
+import com.android.car.audio.CarHalAudioUtils;
import com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport;
import com.android.car.internal.annotation.AttributeUsage;
import com.android.car.internal.util.IndentingPrintWriter;
import com.android.internal.util.Preconditions;
-import java.util.Arrays;
+import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
-/**
- * Wrapper for AIDL interface for AudioControl HAL
- */
-public final class AudioControlWrapperAidl implements AudioControlWrapper {
+/** Wrapper for AIDL interface for AudioControl HAL */
+public final class AudioControlWrapperAidl implements AudioControlWrapper, IBinder.DeathRecipient {
static final String TAG = CarLog.tagFor(AudioControlWrapperAidl.class);
private static final String AUDIO_CONTROL_SERVICE =
@@ -122,7 +121,7 @@
if (Log.isLoggable(TAG, Log.DEBUG)) {
Slogf.d(TAG, "Registering Audio Gain Callback on AudioControl HAL");
}
- Objects.requireNonNull(gainCallback);
+ Objects.requireNonNull(gainCallback, "Audio Gain Callback can not be null");
IAudioGainCallback agc = new AudioGainCallbackWrapper(gainCallback);
try {
mAudioControl.registerGainCallback(agc);
@@ -203,13 +202,13 @@
DuckingInfo[] duckingInfos = new DuckingInfo[carDuckingInfos.size()];
for (int i = 0; i < carDuckingInfos.size(); i++) {
CarDuckingInfo info = Objects.requireNonNull(carDuckingInfos.get(i));
- duckingInfos[i] = info.generateDuckingInfo();
+ duckingInfos[i] = CarHalAudioUtils.generateDuckingInfo(info);
}
try {
mAudioControl.onDevicesToDuckChange(duckingInfos);
} catch (RemoteException e) {
- Slogf.e(TAG, "onDevicesToDuckChange failed", e);
+ Slogf.e(TAG, e, "onDevicesToDuckChange failed");
}
}
@@ -222,14 +221,14 @@
try {
mAudioControl.onDevicesToMuteChange(mutingInfoToHal);
} catch (RemoteException e) {
- Slogf.e(TAG, "onDevicesToMuteChange failed", e);
+ Slogf.e(TAG, e, "onDevicesToMuteChange failed");
}
}
@Override
public void linkToDeath(@Nullable AudioControlDeathRecipient deathRecipient) {
try {
- mBinder.linkToDeath(this::binderDied, 0);
+ mBinder.linkToDeath(this, 0);
mDeathRecipient = deathRecipient;
} catch (RemoteException e) {
throw new IllegalStateException("Call to IAudioControl#linkToDeath failed", e);
@@ -238,11 +237,12 @@
@Override
public void unlinkToDeath() {
- mBinder.unlinkToDeath(this::binderDied, 0);
+ mBinder.unlinkToDeath(this, 0);
mDeathRecipient = null;
}
- private void binderDied() {
+ @Override
+ public void binderDied() {
Slogf.w(TAG, "AudioControl HAL died. Fetching new handle");
mListenerRegistered = false;
mGainCallbackRegistered = false;
@@ -324,20 +324,39 @@
@Override
public void onAudioDeviceGainsChanged(int[] halReasons, AudioGainConfigInfo[] gains) {
- if (Log.isLoggable(TAG, Log.DEBUG)) {
- final List<String> gainsLiteralList = Arrays.asList(gains).stream()
- .map(gain -> gain.toString())
- .collect(Collectors.toList());
- Slogf.d(TAG, "onAudioDeviceGainsChanged for reasons=" + Arrays.toString(halReasons)
- + ", gains=[" + gainsLiteralList.stream().collect(Collectors.joining(", "))
- + "]");
+ List<CarAudioGainConfigInfo> carAudioGainConfigs = new ArrayList<>();
+ for (int index = 0; index < gains.length; index++) {
+ AudioGainConfigInfo gain = gains[index];
+ carAudioGainConfigs.add(new CarAudioGainConfigInfo(gain));
}
- final List<CarAudioGainConfigInfo> cagcis = Arrays.asList(gains).stream()
- .map(gain -> CarAudioGainConfigInfo.build(gain))
- .collect(Collectors.toList());
- final List<Integer> reasons =
- Arrays.stream(halReasons).boxed().collect(Collectors.toList());
- mCallback.onAudioDeviceGainsChanged(reasons, cagcis);
+ List<Integer> reasonsList = new ArrayList<>();
+ for (int index = 0; index < halReasons.length; index++) {
+ int halReason = halReasons[index];
+ if (!HalAudioGainCallback.isReasonValid(halReason)) {
+ Slogf.e(
+ TAG,
+ "onAudioDeviceGainsChanged invalid reasons %d reported, skipped",
+ halReason);
+ continue;
+ }
+ reasonsList.add(halReason);
+ }
+ if (Log.isLoggable(TAG, Log.DEBUG)) {
+ String gainsLiteral =
+ carAudioGainConfigs.stream()
+ .map(gain -> gain.toString())
+ .collect(Collectors.joining(","));
+ String reasonsLiteral =
+ reasonsList.stream()
+ .map(HalAudioGainCallback::reasonToString)
+ .collect(Collectors.joining(","));
+ Slogf.d(
+ TAG,
+ "onAudioDeviceGainsChanged for reasons=[%s], gains=[%s]",
+ reasonsLiteral,
+ gainsLiteral);
+ }
+ mCallback.onAudioDeviceGainsChanged(reasonsList, carAudioGainConfigs);
}
}
}
diff --git a/service/src/com/android/car/audio/hal/HalAudioGainCallback.java b/service/src/com/android/car/audio/hal/HalAudioGainCallback.java
index 3c13730..5eb8cfc 100644
--- a/service/src/com/android/car/audio/hal/HalAudioGainCallback.java
+++ b/service/src/com/android/car/audio/hal/HalAudioGainCallback.java
@@ -16,14 +16,96 @@
package com.android.car.audio.hal;
+import android.annotation.IntDef;
+import android.hardware.automotive.audiocontrol.AudioGainConfigInfo;
+import android.hardware.automotive.audiocontrol.Reasons;
+
import com.android.car.audio.CarAudioGainConfigInfo;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.util.List;
/**
* Audio Gain Callback interface to abstract away the specific HAL version
*/
public interface HalAudioGainCallback {
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(
+ value = {
+ Reasons.FORCED_MASTER_MUTE,
+ Reasons.REMOTE_MUTE,
+ Reasons.TCU_MUTE,
+ Reasons.ADAS_DUCKING,
+ Reasons.NAV_DUCKING,
+ Reasons.PROJECTION_DUCKING,
+ Reasons.THERMAL_LIMITATION,
+ Reasons.SUSPEND_EXIT_VOL_LIMITATION,
+ Reasons.EXTERNAL_AMP_VOL_FEEDBACK,
+ Reasons.OTHER
+ })
+ public @interface HalReason {}
+
+ /** Determines if the {@code HalReason} is valid */
+ static boolean isReasonValid(@HalReason int reason) {
+ switch (reason) {
+ case Reasons.FORCED_MASTER_MUTE:
+ case Reasons.REMOTE_MUTE:
+ case Reasons.TCU_MUTE:
+ case Reasons.ADAS_DUCKING:
+ case Reasons.NAV_DUCKING:
+ case Reasons.PROJECTION_DUCKING:
+ case Reasons.THERMAL_LIMITATION:
+ case Reasons.SUSPEND_EXIT_VOL_LIMITATION:
+ case Reasons.EXTERNAL_AMP_VOL_FEEDBACK:
+ case Reasons.OTHER:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ /** Converts the {@code HalReason} to String */
+ static String reasonToString(@HalReason int reason) {
+ switch (reason) {
+ case Reasons.FORCED_MASTER_MUTE:
+ return "FORCED_MASTER_MUTE";
+ case Reasons.REMOTE_MUTE:
+ return "REMOTE_MUTE";
+ case Reasons.TCU_MUTE:
+ return "TCU_MUTE";
+ case Reasons.ADAS_DUCKING:
+ return "ADAS_DUCKING";
+ case Reasons.NAV_DUCKING:
+ return "NAV_DUCKING";
+ case Reasons.PROJECTION_DUCKING:
+ return "PROJECTION_DUCKING";
+ case Reasons.THERMAL_LIMITATION:
+ return "THERMAL_LIMITATION";
+ case Reasons.SUSPEND_EXIT_VOL_LIMITATION:
+ return "SUSPEND_EXIT_VOL_LIMITATION";
+ case Reasons.EXTERNAL_AMP_VOL_FEEDBACK:
+ return "EXTERNAL_AMP_VOL_FEEDBACK";
+ case Reasons.OTHER:
+ return "OTHER";
+ default:
+ return "Unsupported reason int " + reason;
+ }
+ }
+
+ /**
+ * Converts the {@code AudioGainConfigInfo} to its string representation
+ */
+ static String gainToString(AudioGainConfigInfo audioGainConfigInfo) {
+ // Java toString helper missing at aidl side
+ return "zone: "
+ + audioGainConfigInfo.zoneId
+ + ", address: "
+ + audioGainConfigInfo.devicePortAddress
+ + ", Volume Index: "
+ + audioGainConfigInfo.volumeIndex;
+ }
+
/**
* Notify of Audio Gain changed for given {@code halReasons} for the given {@code gains}.
*/
diff --git a/service/src/com/android/car/bluetooth/BluetoothUtils.java b/service/src/com/android/car/bluetooth/BluetoothUtils.java
index 94aeff9..8703ae8 100644
--- a/service/src/com/android/car/bluetooth/BluetoothUtils.java
+++ b/service/src/com/android/car/bluetooth/BluetoothUtils.java
@@ -25,6 +25,7 @@
import android.bluetooth.BluetoothPbapClient;
import android.bluetooth.BluetoothProfile;
import android.bluetooth.BluetoothUuid;
+import android.bluetooth.le.AdvertisingSetCallback;
import android.os.ParcelUuid;
import android.util.SparseArray;
@@ -54,6 +55,9 @@
private static final SparseArray<String> sAdapterStates = new SparseArray<String>(4);
private static final SparseArray<String> sBondStates = new SparseArray<String>(3);
private static final SparseArray<String> sConnectionStates = new SparseArray<String>(4);
+ private static final SparseArray<String> sScanModes = new SparseArray<String>(3);
+ private static final SparseArray<String> sAdvertiseCallbackStatuses =
+ new SparseArray<String>(3);
private static final SparseArray<String> sProfileNames = new SparseArray<String>(6);
private static final HashMap<String, Integer> sProfileActions = new HashMap<String, Integer>(5);
static {
@@ -62,6 +66,7 @@
sAdapterStates.put(BluetoothAdapter.STATE_OFF, "Off");
sAdapterStates.put(BluetoothAdapter.STATE_TURNING_ON, "Turning On");
sAdapterStates.put(BluetoothAdapter.STATE_TURNING_OFF, "Turning Off");
+ sAdapterStates.put(BluetoothAdapter.ERROR, "Error");
// Device Bonding states
sBondStates.put(BluetoothDevice.BOND_BONDED, "Bonded");
@@ -74,6 +79,27 @@
sConnectionStates.put(BluetoothAdapter.STATE_CONNECTING, "Connecting");
sConnectionStates.put(BluetoothAdapter.STATE_DISCONNECTING, "Disconnecting");
+ // Scan Mode Names
+ sScanModes.put(BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE,
+ "Connectable/Discoverable");
+ sScanModes.put(BluetoothAdapter.SCAN_MODE_CONNECTABLE, "Connectable");
+ sScanModes.put(BluetoothAdapter.SCAN_MODE_NONE, "None");
+ sScanModes.put(BluetoothAdapter.ERROR, "Error");
+
+ // Advertising Callback Status Codes
+ sAdvertiseCallbackStatuses.put(AdvertisingSetCallback.ADVERTISE_FAILED_ALREADY_STARTED,
+ "ADVERTISE_FAILED_ALREADY_STARTED");
+ sAdvertiseCallbackStatuses.put(AdvertisingSetCallback.ADVERTISE_FAILED_DATA_TOO_LARGE,
+ "ADVERTISE_FAILED_DATA_TOO_LARGE");
+ sAdvertiseCallbackStatuses.put(AdvertisingSetCallback.ADVERTISE_FAILED_FEATURE_UNSUPPORTED,
+ "ADVERTISE_FAILED_FEATURE_UNSUPPORTED");
+ sAdvertiseCallbackStatuses.put(AdvertisingSetCallback.ADVERTISE_FAILED_INTERNAL_ERROR,
+ "ADVERTISE_FAILED_INTERNAL_ERROR");
+ sAdvertiseCallbackStatuses.put(AdvertisingSetCallback.ADVERTISE_FAILED_TOO_MANY_ADVERTISERS,
+ "ADVERTISE_FAILED_TOO_MANY_ADVERTISERS");
+ sAdvertiseCallbackStatuses.put(AdvertisingSetCallback.ADVERTISE_SUCCESS,
+ "ADVERTISE_SUCCESS");
+
// Profile Names
sProfileNames.put(BluetoothProfile.PAN, "PAN");
sProfileNames.put(BluetoothProfile.A2DP_SINK, "A2DP Sink");
@@ -90,6 +116,21 @@
sProfileActions.put(PBAP_CLIENT_CONNECTION_STATE_CHANGED, BluetoothProfile.PBAP_CLIENT);
}
+ static byte[] getBytesFromAddress(String address) {
+ int i, j = 0;
+ byte[] output = new byte[6]; // 6 byte Bluetooth Address
+
+ for (i = 0; i < address.length(); i++) {
+ if (address.charAt(i) != ':') {
+ output[j] = (byte) Integer.parseInt(address.substring(i, i + 2), 16 /* base 16 */);
+ j++;
+ i++;
+ }
+ }
+ return output;
+ }
+
+
static String getDeviceDebugInfo(BluetoothDevice device) {
if (device == null) {
return "(null)";
@@ -117,6 +158,16 @@
return "(" + state + ") " + name;
}
+ static String getScanModeName(int mode) {
+ String name = sScanModes.get(mode, "Unknown");
+ return "(" + mode + ") " + name;
+ }
+
+ static String getAdvertisingCallbackStatusName(int status) {
+ String name = sAdvertiseCallbackStatuses.get(status, "Unknown");
+ return "(" + status + ") " + name;
+ }
+
static String getConnectionPolicyName(int priority) {
String name = "";
switch (priority) {
diff --git a/service/src/com/android/car/bluetooth/FastPairAccountKeyStorage.java b/service/src/com/android/car/bluetooth/FastPairAccountKeyStorage.java
new file mode 100644
index 0000000..31a69f0
--- /dev/null
+++ b/service/src/com/android/car/bluetooth/FastPairAccountKeyStorage.java
@@ -0,0 +1,309 @@
+/*
+ * Copyright (C) 2022 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.bluetooth;
+
+import static com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport.DUMP_INFO;
+
+import android.annotation.NonNull;
+import android.car.builtin.util.Slogf;
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.os.UserManager;
+import android.util.Log;
+
+import com.android.car.CarLog;
+import com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport;
+import com.android.car.internal.util.IndentingPrintWriter;
+
+import java.math.BigInteger;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Objects;
+
+import javax.crypto.spec.SecretKeySpec;
+
+/**
+ * A collection of 128-bit Account Keys that are received over the Fast Pair protocol.
+ *
+ * The specification requires that we store at least 5 Account Keys, but places no upper bound on
+ * how many we can store. It only mentions that they all must fit in our chosen packet size. To
+ * support this, we have a variable fixed upper bound of the number of stored keys. If you input a
+ * number less than five, it will be adjusted up.
+ *
+ * The specification also requires that we remove the least recently used key if we ever run out of
+ * space. To support this, keys are stored in an LRU cache. Adding a key when storage is full will
+ * automatically remove the least recently used key.
+ *
+ * The specification requires that keys are persisted. To support this, keys are written to the
+ * user's Shared Preferences. There is one preferences for the count of keys, and then a preference
+ * for each key in priority order, where an index preference is mapped to a key value, i.e. the
+ * perference "0" would map to a 128-bit key.
+ *
+ * Keys are loaded from Shared Preferences upon creation of this object.
+ */
+public class FastPairAccountKeyStorage {
+ private static final String TAG = CarLog.tagFor(FastPairAccountKeyStorage.class);
+ private static final boolean DBG = Slogf.isLoggable(TAG, Log.DEBUG);
+
+ private static final String FAST_PAIR_PREFERENCES = "com.android.car.bluetooth";
+ private static final String NUM_ACCOUNT_KEYS = "AccountKeysCount";
+
+ private final Context mContext;
+
+ /**
+ * Represents a 128-bit Account Key that can be received through the FastPair process.
+ */
+ public static class AccountKey {
+ private final byte[] mKey;
+
+ AccountKey(byte[] key) {
+ mKey = key;
+ }
+
+ AccountKey(String key) {
+ mKey = new BigInteger(key).toByteArray();
+ }
+
+ /**
+ * Get a byte representation of this Account Key
+ */
+ public byte[] toBytes() {
+ return mKey;
+ }
+
+ /**
+ * Get a SecretKeySpec representation of this Account Key
+ */
+ public SecretKeySpec getKeySpec() {
+ return new SecretKeySpec(mKey, "AES");
+ }
+
+ @Override
+ public int hashCode() {
+ return Arrays.hashCode(mKey);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (!(obj instanceof AccountKey)) {
+ return false;
+ }
+ AccountKey other = (AccountKey) obj;
+ return other != null && Arrays.equals(toBytes(), other.toBytes());
+ }
+
+ @Override
+ public String toString() {
+ return Arrays.toString(mKey);
+ }
+ }
+
+ /*
+ * A LinkedHashSet is used as an LRU. Iterating on the LinkedHashSet will produce the items in
+ * the order they were inserted-- first inserted, first iterated on.
+ */
+ private final LinkedHashSet<AccountKey> mKeys;
+ private final Object mKeyLock = new Object();
+ private final int mStorageSize;
+
+ public FastPairAccountKeyStorage(Context context, int size) {
+ if (size < 5) {
+ throw new IllegalArgumentException("size < 5");
+ }
+ mContext = Objects.requireNonNull(context);
+ mStorageSize = size;
+ mKeys = new LinkedHashSet<AccountKey>(mStorageSize);
+ load(); // A no-op if storage isn't unlocked yet
+ }
+
+ /**
+ * Get the total number of account keys that can be stored
+ */
+ public int capacity() {
+ return mStorageSize;
+ }
+
+ /**
+ * Add an account key
+ */
+ public boolean add(@NonNull AccountKey key) {
+ if (key == null) return false;
+ Slogf.i("Adding key '%s'", key.toString());
+ synchronized (mKeyLock) {
+ // LinkedHashSet re-adds do not impact the ordering. To force the ordering to update,
+ // we'll remove the key first if its already in the set, then re-add it.
+ if (mKeys.contains(key)) {
+ mKeys.remove(key);
+ }
+ mKeys.add(key);
+ trimToSize();
+ commit();
+ return true;
+ }
+ }
+
+ /**
+ * Remove an account key
+ */
+ public boolean remove(@NonNull AccountKey key) {
+ if (key == null) return false;
+ Slogf.i("Removing key '%s'", key.toString());
+ synchronized (mKeyLock) {
+ mKeys.remove(key);
+ commit();
+ return true;
+ }
+ }
+
+ /**
+ * Get a list of all the available account keys
+ */
+ public List<AccountKey> getAllAccountKeys() {
+ synchronized (mKeyLock) {
+ return new ArrayList<>(mKeys);
+ }
+ }
+
+ /**
+ * Clears all account keys from storage
+ */
+ public void clear() {
+ synchronized (mKeyLock) {
+ mKeys.clear();
+ commit();
+ }
+ }
+
+ /**
+ * Removes the least recently used items until the size of our cache is less than or equal to
+ * our configured maximum size.
+ */
+ private void trimToSize() {
+ while (mKeys.size() > mStorageSize) {
+ AccountKey key = mKeys.iterator().next();
+ mKeys.remove(key);
+ Slogf.d("Evicted key '%s'", key.toString());
+ }
+ }
+
+ /**
+ * Loads persisted account keys from Shared Preferences
+ *
+ * Account keys are stored in key value pairs of <integer> to <string>, where the integer is the
+ * position in the LRU (higher is more recently used), and the string is a string version of the
+ * bytes. There is also an "AccountKeysCount" preference indicating how many keys are stored.
+ * Keys will have integer keys in the range [0, AccountKeysCount - 1].
+ *
+ * This cannot be called until the user is unlocked.
+ */
+ public boolean load() {
+ if (!isUserUnlocked()) {
+ // TODO (243016325): Determine a way to recover from a failed load()
+ Slogf.w(TAG, "Loaded while user was not unlocked. Shared Preferences unavailable");
+ return false;
+ }
+
+ List<AccountKey> keys = new ArrayList<>();
+ SharedPreferences preferences =
+ mContext.getSharedPreferences(FAST_PAIR_PREFERENCES, Context.MODE_PRIVATE);
+ int numKeys = preferences.getInt(NUM_ACCOUNT_KEYS, 0);
+
+ for (int i = 0; i < numKeys; i++) {
+ String key = preferences.getString(Integer.toString(i), null);
+ if (key != null) {
+ keys.add(new AccountKey(key));
+ }
+ }
+ Slogf.d(TAG, "Read %d/%d keys from SharedPreferences", keys.size(), numKeys);
+
+ synchronized (mKeyLock) {
+ mKeys.clear();
+ for (AccountKey key : keys) {
+ mKeys.add(key);
+ }
+ trimToSize();
+ commit();
+ }
+ return true;
+ }
+
+ /**
+ * Persists the set of Account Keys to Shared Preferences.
+ *
+ * Account keys are stored in key value pairs of <integer> to <string>, where the integer is the
+ * position in the LRU (higher is more recently used), and the string is a string version of the
+ * bytes. There is also an "AccountKeysCount" preference indicating how many keys are stored.
+ * Keys will have integer keys in the range [0, AccountKeysCount - 1].
+ */
+ private boolean commit() {
+ if (!isUserUnlocked()) {
+ // TODO (243016325): Determine a way to recover from a failed commit()
+ Slogf.w(TAG, "Committed while user was not unlocked. Shared Preferences unavailable");
+ return false;
+ }
+
+ SharedPreferences preferences =
+ mContext.getSharedPreferences(FAST_PAIR_PREFERENCES, Context.MODE_PRIVATE);
+ SharedPreferences.Editor editor = preferences.edit();
+
+ // Get the current count of stored keys
+ int accountKeyCount = preferences.getInt(NUM_ACCOUNT_KEYS, 0);
+ int finalSize = mKeys.size();
+
+ for (int i = accountKeyCount - 1; i >= finalSize; i--) {
+ editor.remove(Integer.toString(i));
+ }
+
+ // Add the count of keys
+ editor.putInt(NUM_ACCOUNT_KEYS, finalSize);
+
+ // Add the keys themselves and apply
+ int i = 0;
+ for (AccountKey key : mKeys) {
+ editor.putString(Integer.toString(i), new BigInteger(key.toBytes()).toString());
+ i++;
+ }
+ editor.apply();
+
+ if (DBG) {
+ Slogf.d(TAG, "Committed keys to SharedPreferences, keys=%s", mKeys);
+ }
+ return true;
+ }
+
+ private boolean isUserUnlocked() {
+ return mContext.getSystemService(UserManager.class).isUserUnlocked();
+ }
+
+ @Override
+ public String toString() {
+ return "FastPairAccountKeyStorage (Size=" + mKeys.size() + " / " + mStorageSize + ")";
+ }
+
+ @ExcludeFromCodeCoverageGeneratedReport(reason = DUMP_INFO)
+ void dump(IndentingPrintWriter writer) {
+ writer.println(toString());
+ writer.increaseIndent();
+ List<AccountKey> keys = getAllAccountKeys();
+ for (AccountKey key : keys) {
+ writer.println("\n" + key);
+ }
+ writer.decreaseIndent();
+ }
+}
diff --git a/service/src/com/android/car/bluetooth/FastPairAdvertiser.java b/service/src/com/android/car/bluetooth/FastPairAdvertiser.java
index 5acc813..de17b85 100644
--- a/service/src/com/android/car/bluetooth/FastPairAdvertiser.java
+++ b/service/src/com/android/car/bluetooth/FastPairAdvertiser.java
@@ -16,6 +16,7 @@
package com.android.car.bluetooth;
+import static com.android.car.bluetooth.FastPairAccountKeyStorage.AccountKey;
import static com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport.DUMP_INFO;
import android.bluetooth.BluetoothAdapter;
@@ -26,42 +27,74 @@
import android.bluetooth.le.AdvertisingSetCallback;
import android.bluetooth.le.AdvertisingSetParameters;
import android.bluetooth.le.BluetoothLeAdvertiser;
+import android.car.Car;
+import android.car.PlatformVersion;
+import android.car.builtin.bluetooth.le.AdvertisingSetCallbackHelper;
+import android.car.builtin.bluetooth.le.AdvertisingSetHelper;
import android.car.builtin.util.Slogf;
import android.content.Context;
+import android.os.Handler;
+import android.os.Message;
import android.os.ParcelUuid;
+import android.util.Log;
+import com.android.car.CarLog;
+import com.android.car.CarServiceUtils;
import com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport;
import com.android.car.internal.util.IndentingPrintWriter;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
+import java.security.MessageDigest;
+import java.util.ArrayList;
import java.util.Arrays;
+import java.util.List;
+import java.util.Objects;
+import java.util.Random;
/**
* The FastPairAdvertiser is responsible for the BLE advertisement of either the model ID while
* in pairing mode or the stored account keys while not in pairing mode.
*
- * Note that two different advertisers should be created and only one should be advertising at a
- * time.
+ * This advertiser should always be advertising either the model ID or the account key filter if the
+ * Bluetooth adapter is on.
+ *
+ * Additionally, the Fast Pair Advertiser is the only entity allowed to receive notifications about
+ * our private address, which is used by the protocol to verify the remote device we're talking to.
+ *
+ * Advertisement packet formats and timing/intervals are described by the Fast Pair specification
*/
-class FastPairAdvertiser {
+public class FastPairAdvertiser {
+ private static final String TAG = CarLog.tagFor(FastPairAdvertiser.class);
+ private static final boolean DBG = Slogf.isLoggable(TAG, Log.DEBUG);
+
+ public static final int STATE_STOPPED = 0;
+ public static final int STATE_STARTING = 1;
+ public static final int STATE_STARTED = 2;
+ public static final int STATE_STOPPING = 3;
+
// Service ID assigned for FastPair.
- public static final ParcelUuid FastPairServiceUuid = ParcelUuid
+ public static final ParcelUuid SERVICE_UUID = ParcelUuid
.fromString("0000FE2C-0000-1000-8000-00805f9b34fb");
- private static final String TAG = FastPairAdvertiser.class.getSimpleName();
- private static final boolean DBG = FastPairUtils.DBG;
- private final Callbacks mCallbacks;
+ private static final byte ACCOUNT_KEY_FILTER_FLAGS = 0x00;
+ private static final byte SALT_FIELD_DESCRIPTOR = 0x11;
+
private final Context mContext;
- private final byte[] mFastPairModelData;
-
- private BluetoothAdapter mBluetoothAdapter;
+ private final BluetoothAdapter mBluetoothAdapter;
private BluetoothLeAdvertiser mBluetoothLeAdvertiser;
private AdvertisingSetParameters mAdvertisingSetParameters;
+ private AdvertisingSetCallback mAdvertisingSetCallback;
private AdvertiseData mData;
- private boolean mAdvertising = false;
+ private int mTxPower = 0;
+ private Callbacks mCallbacks;
- interface Callbacks {
+ private final AdvertisingHandler mAdvertisingHandler;
+
+ /**
+ * Receive events from this FastPairAdvertiser
+ */
+ public interface Callbacks {
/**
* Notify the Resolvable Private Address of the BLE advertiser.
*
@@ -70,139 +103,519 @@
void onRpaUpdated(BluetoothDevice device);
}
- FastPairAdvertiser(Context context, int modelId, Callbacks callbacks) {
+ FastPairAdvertiser(Context context) {
mContext = context;
- mCallbacks = callbacks;
+ mBluetoothAdapter = mContext.getSystemService(BluetoothManager.class).getAdapter();
+ Objects.requireNonNull(mBluetoothAdapter, "Bluetooth adapter cannot be null");
+ mAdvertisingHandler = new AdvertisingHandler();
+ initializeAdvertisingSetCallback();
+ }
+
+ /**
+ * Advertise the Fast Pair model ID.
+ *
+ * Model ID advertisements have the following format:
+ *
+ * Octet | Type | Description | Value
+ * --------------------------------------------------------------------------------------------
+ * 0-2 | uint24 | 24-bit Model ID | varies, example: 0x123456
+ * --------------------------------------------------------------------------------------------
+ *
+ * Ensure advertising is stopped before switching the underlying advertising data. This can be
+ * done by calling stopAdvertising().
+ */
+ public void advertiseModelId(int modelId, Callbacks callback) {
+ if (DBG) {
+ Slogf.d(TAG, "advertiseModelId(id=0x%s)", Integer.toHexString(modelId));
+ }
+
ByteBuffer modelIdBytes = ByteBuffer.allocate(4).order(ByteOrder.BIG_ENDIAN).putInt(
modelId);
- mFastPairModelData = Arrays.copyOfRange(modelIdBytes.array(), 1, 4);
- initializeBluetoothLeAdvertiser();
+ mAdvertisingHandler.startAdvertising(Arrays.copyOfRange(modelIdBytes.array(), 1, 4),
+ AdvertisingSetParameters.INTERVAL_LOW, callback);
}
/**
- * Advertise the model id when in pairing mode.
+ * Advertise the stored account keys.
+ *
+ * Account Keys advertisements have the following format:
+ *
+ * Octet | Type | Description | Value
+ * --------------------------------------------------------------------------------------------
+ * 0 | uint8 | Flags, all bits reserved for future use | 0x00
+ * --------------------------------------------------------------------------------------------
+ * 1-N | | Account Key Data | 0x00, if empty
+ * | | | bloom(account keys), otherwise
+ * --------------------------------------------------------------------------------------------
+ *
+ * The Account Key Data has the following format:
+ *
+ * Octet | Type | Description | Value
+ * --------------------------------------------------------------------------------------------
+ * 0 | uint8 | 0bLLLLTTTT (T=type, L=Length) | length=0bLLLL, 4 bit field length
+ * | | | type=0bTTTT, 0b0000 (show UI)
+ * | | | type=0bTTTT, 0b0010 (hide UI)
+ * --------------------------------------------------------------------------------------------
+ * 1-N | | Account Key Filter | 0x00, if empty
+ * --------------------------------------------------------------------------------------------
+ * N+1 | uint8 | Salt Field Length and Type | 0b00010001
+ * --------------------------------------------------------------------------------------------
+ * N+2 | uint8 | Salt | varies
+ * --------------------------------------------------------------------------------------------
+ *
+ * The Account Key Filter is a bloom filter representation of the stored keys. The filter alone
+ * requires 1.2 * <number of keys> + 3 bytes. This means an Account Key Filter packet is a total
+ * size of 4 (flags, filter field id + length, salt field id + length, salt) + 1.2 * <keys> + 3
+ * bytes.
+ *
+ * Keep this in mind when defining your max keys size, as it will directly impact the size of
+ * advertisement data and packet. Make sure your controller supports your maximum advertisement
+ * size.
+ *
+ * Ensure advertising is stopped before switching the underlying advertising data. This can be
+ * done by calling stopAdvertising().
*/
- void advertiseModelId() {
+ public void advertiseAccountKeys(List<AccountKey> accountKeys, Callbacks callback) {
if (DBG) {
- Slogf.d(TAG, "AdvertiseModelId");
+ Slogf.d(TAG, "advertiseAccountKeys(keys=%s)", accountKeys);
}
- mAdvertisingSetParameters = new AdvertisingSetParameters.Builder()
- .setLegacyMode(true)
- .setInterval(AdvertisingSetParameters.INTERVAL_LOW)
- .setScannable(true)
- .setConnectable(true)
- .build();
- mData = new AdvertiseData.Builder()
- .addServiceUuid(FastPairServiceUuid)
- .addServiceData(FastPairServiceUuid, mFastPairModelData)
- .setIncludeTxPowerLevel(true)
- .build();
- startAdvertising();
+
+ // If we have account keys, then create a salt value and generate the account key filter
+ byte[] accountKeyFilter = null;
+ byte[] salt = null;
+ if (accountKeys != null && accountKeys.size() > 0) {
+ salt = new byte[1];
+ new Random().nextBytes(salt);
+ accountKeyFilter = getAccountKeyFilter(accountKeys, salt[0]);
+ }
+
+ // If we have an account key filter, then create an advertisement payload using it and the
+ // salt. Otherwise, create an empty advertisement.
+ ByteBuffer accountKeyAdvertisement = null;
+ if (accountKeyFilter != null) {
+ int size = accountKeyFilter.length;
+ accountKeyAdvertisement = ByteBuffer.allocate(size + 4); // filter + 3b flags + 1b salt
+ accountKeyAdvertisement.put(ACCOUNT_KEY_FILTER_FLAGS); // Reserved Flags byte
+ accountKeyAdvertisement.put((byte) (size << 4)); // Length Type and Size, 0bLLLLTTTT
+ accountKeyAdvertisement.put(accountKeyFilter); // Account Key Bloom Results
+ accountKeyAdvertisement.put(SALT_FIELD_DESCRIPTOR); // Salt Field/Size, 0bLLLLTTTT
+ accountKeyAdvertisement.put(salt); // The actual 1 byte of salt
+ } else {
+ accountKeyAdvertisement = ByteBuffer.allocate(2);
+ accountKeyAdvertisement.put((byte) 0x00); // Reserved Flags Byte
+ accountKeyAdvertisement.put((byte) 0x00); // Empty Keys Byte
+ }
+
+ mAdvertisingHandler.startAdvertising(accountKeyAdvertisement.array(),
+ AdvertisingSetParameters.INTERVAL_MEDIUM, callback);
}
/**
- * Advertise the stored account keys while not in pairing mode
+ * Calculate the account key filter, defined as the bloom of the set of account keys.
+ *
+ * @param keys The list of Fast Pair Account keys
+ * @param salt The salt to be used here, as well as appended to the Account Data Advertisment
+ * @return A byte array representing the account key filter
*/
- void advertiseAccountKeys() {
- if (DBG) {
- Slogf.d(TAG, "AdvertiseAccountKeys");
+ byte[] getAccountKeyFilter(List<AccountKey> keys, byte salt) {
+ if (keys == null || keys.size() <= 0) {
+ Slogf.e(TAG, "Cannot generate account key filter, keys=%s, salt=%s", keys, salt);
+ return null;
}
- mAdvertisingSetParameters = new AdvertisingSetParameters.Builder()
- .setLegacyMode(true)
- .setInterval(AdvertisingSetParameters.INTERVAL_MEDIUM)
- .setScannable(true)
- .setConnectable(true)
- .build();
- mData = new AdvertiseData.Builder()
- .addServiceUuid(FastPairServiceUuid)
- .addServiceData(FastPairServiceUuid,
- FastPairUtils.getAccountKeyAdvertisement(mContext))
- .setIncludeTxPowerLevel(true)
- .build();
- startAdvertising();
+
+ int size = (int) (1.2 * keys.size()) + 3;
+ byte[] filter = new byte[size];
+
+ for (AccountKey key : keys) {
+ byte[] v = Arrays.copyOf(key.toBytes(), 17);
+ v[16] = salt;
+ try {
+ byte[] hashed = MessageDigest.getInstance("SHA-256").digest(v);
+ ByteBuffer byteBuffer = ByteBuffer.wrap(hashed);
+ for (int j = 0; j < 8; j++) {
+ long k = Integer.toUnsignedLong(byteBuffer.getInt()) % (size * 8);
+ filter[(int) (k / 8)] |= (byte) (1 << (k % 8));
+ }
+ } catch (Exception e) {
+ Slogf.e(TAG, "Error calculating account key filter: %s", e);
+ return null;
+ }
+ }
+ return filter;
}
/**
- * Stop advertising when it is time to shut down.
+ * Stop advertising any data.
*/
- void stopAdvertising() {
+ public void stopAdvertising() {
if (DBG) {
Slogf.d(TAG, "stoppingAdvertising");
}
- if (mBluetoothLeAdvertiser == null) return;
- mBluetoothLeAdvertiser.stopAdvertisingSet(mAdvertisingSetCallback);
+ mAdvertisingHandler.stopAdvertising();
}
/**
- * Attempt to set mBluetoothLeAdvertiser from the BluetoothAdapter
+ * Start a BLE advertisement using the given data, interval, and callbacks.
*
- * Returns
- * true if mBluetoothLeAdvertiser is set
- * false if mBluetoothLeAdvertiser is still null
+ * Must be called on the Advertising Handler.
+ *
+ * @param data The data to advertise
+ * @param interval The interval at which to advertise
+ * @param callbacks The callback object to notify of FastPairAdvertiser events
*/
- private boolean initializeBluetoothLeAdvertiser() {
- if (mBluetoothLeAdvertiser != null) return true;
-
- BluetoothManager bluetoothManager = mContext.getSystemService(BluetoothManager.class);
- if (bluetoothManager == null) return false;
-
- mBluetoothAdapter = bluetoothManager.getAdapter();
- if (mBluetoothAdapter == null) return false;
+ private boolean startAdvertisingInternal(byte[] data, int interval, Callbacks callbacks) {
+ if (DBG) {
+ Slogf.d(TAG, "startAdvertisingInternal(data=%s, internval=%d, cb=%s)",
+ Arrays.toString(data), interval, callbacks);
+ }
mBluetoothLeAdvertiser = mBluetoothAdapter.getBluetoothLeAdvertiser();
- return (mBluetoothLeAdvertiser != null);
+ if (mBluetoothLeAdvertiser == null) {
+ Slogf.e(TAG, "startAdvertisingInternal: Failed to get an advertiser.");
+ mBluetoothLeAdvertiser = null;
+ return false;
+ }
+
+ mAdvertisingSetParameters = new AdvertisingSetParameters.Builder()
+ .setLegacyMode(true)
+ .setInterval(interval)
+ .setScannable(true)
+ .setConnectable(true)
+ .build();
+ mData = new AdvertiseData.Builder()
+ .addServiceUuid(SERVICE_UUID)
+ .addServiceData(SERVICE_UUID, data)
+ .setIncludeTxPowerLevel(true)
+ .build();
+ mCallbacks = callbacks;
+
+ mBluetoothLeAdvertiser.startAdvertisingSet(mAdvertisingSetParameters, mData, null, null,
+ null, mAdvertisingSetCallback);
+ return true;
}
/**
- * Acquire the LE advertiser from the Bluetooth adapter, and if available start the configured
- * advertiser.
+ * Stop advertising any data.
+ *
+ * This must be called on the Advertising Handler.
*/
- private void startAdvertising() {
- if (!initializeBluetoothLeAdvertiser()) return;
- if (!mAdvertising) {
- if (DBG) Slogf.d(TAG, "startingAdvertising");
- mBluetoothLeAdvertiser.startAdvertisingSet(mAdvertisingSetParameters, mData, null, null,
- null, mAdvertisingSetCallback);
+ private void stopAdvertisingInternal() {
+ if (DBG) {
+ Slogf.d(TAG, "stoppingAdvertisingInternal");
+ }
+
+ if (mBluetoothLeAdvertiser == null) return;
+
+ mBluetoothLeAdvertiser.stopAdvertisingSet(mAdvertisingSetCallback);
+ mTxPower = 0;
+ mBluetoothLeAdvertiser = null;
+ }
+
+ public boolean isAdvertising() {
+ return getAdvertisingState() == STATE_STARTED;
+ }
+
+ public int getAdvertisingState() {
+ return mAdvertisingHandler.getState();
+ }
+
+ private void initializeAdvertisingSetCallback() {
+ // Certain functionality of {@link AdvertisingSetCallback} were disabled in
+ // {@code TIRAMISU} (major == 33, minor == 0) due to hidden API usage. These functionality
+ // were later restored, but require platform version to be at least TM-QPR-1
+ // (major == 33, minor == 1).
+ PlatformVersion version = Car.getPlatformVersion();
+ if (DBG) {
+ Slogf.d(TAG, "AdvertisingSetCallback running on platform version (major=%d, minor=%d)",
+ version.getMajorVersion(), version.getMinorVersion());
+ }
+ if (version.isAtLeast(PlatformVersion.VERSION_CODES.TIRAMISU_1)) {
+ AdvertisingSetCallbackHelper.Callback proxy =
+ new AdvertisingSetCallbackHelper.Callback() {
+ @Override
+ public void onAdvertisingSetStarted(AdvertisingSet advertisingSet, int txPower,
+ int status) {
+ onAdvertisingSetStartedHandler(advertisingSet, txPower, status);
+ if (advertisingSet != null) {
+ AdvertisingSetHelper.getOwnAddress(advertisingSet);
+ }
+ }
+
+ @Override
+ public void onAdvertisingSetStopped(AdvertisingSet advertisingSet) {
+ onAdvertisingSetStoppedHandler(advertisingSet);
+ }
+
+ @Override
+ public void onOwnAddressRead(AdvertisingSet advertisingSet, int addressType,
+ String address) {
+ onOwnAddressReadHandler(addressType, address);
+ }
+ };
+
+ mAdvertisingSetCallback =
+ AdvertisingSetCallbackHelper.createRealCallbackFromProxy(proxy);
+ } else {
+ mAdvertisingSetCallback = new AdvertisingSetCallback() {
+ @Override
+ public void onAdvertisingSetStarted(AdvertisingSet advertisingSet, int txPower,
+ int status) {
+ onAdvertisingSetStartedHandler(advertisingSet, txPower, status);
+ // TODO(b/241933163): once there are formal APIs to get own address, this
+ // warning can be removed.
+ Slogf.w(TAG, "AdvertisingSet#getOwnAddress not called."
+ + " This feature is not supported in this platform version.");
+ }
+
+ @Override
+ public void onAdvertisingSetStopped(AdvertisingSet advertisingSet) {
+ onAdvertisingSetStoppedHandler(advertisingSet);
+ }
+ };
}
}
- /* Callback to handle changes in advertising. */
- private AdvertisingSetCallback mAdvertisingSetCallback = new AdvertisingSetCallback() {
- @Override
- public void onAdvertisingSetStarted(AdvertisingSet advertisingSet, int txPower,
- int status) {
- if (DBG) {
- Slogf.d(TAG, "onAdvertisingSetStarted(): txPower: %s, status: %s", txPower, status);
+ // For {@link AdvertisingSetCallback#onAdvertisingSetStarted} and its proxy
+ private void onAdvertisingSetStartedHandler(AdvertisingSet advertisingSet, int txPower,
+ int status) {
+ if (DBG) {
+ Slogf.d(TAG, "onAdvertisingSetStarted(): txPower: %d, status: %d", txPower, status);
+ }
+ if (status != AdvertisingSetCallback.ADVERTISE_SUCCESS || advertisingSet == null) {
+ Slogf.w(TAG, "Failed to start advertising, status=%s, advertiser=%s",
+ BluetoothUtils.getAdvertisingCallbackStatusName(status), advertisingSet);
+ mAdvertisingHandler.advertisingStopped();
+ return;
+ }
+ mTxPower = txPower;
+ mAdvertisingHandler.advertisingStarted();
+ }
+
+ // For {@link AdvertisingSetCallback#onAdvertisingSetStopped} and its proxy
+ private void onAdvertisingSetStoppedHandler(AdvertisingSet advertisingSet) {
+ if (DBG) Slogf.d(TAG, "onAdvertisingSetStopped()");
+ mAdvertisingHandler.advertisingStopped();
+ }
+
+ // For {@link AdvertisingSetCallback#onOwnAddressRead} and its proxy
+ private void onOwnAddressReadHandler(int addressType, String address) {
+ if (DBG) Slogf.d(TAG, "onOwnAddressRead Type= %d, Address= %s", addressType, address);
+ mCallbacks.onRpaUpdated(mBluetoothAdapter.getRemoteDevice(address));
+ }
+
+ /**
+ * A handler that synchronizes advertising events
+ */
+ // TODO (243161113): Clean this handler up to make it more clear and enable direct advertising
+ // data changes without stopping
+ private class AdvertisingHandler extends Handler {
+ private static final int MSG_ADVERTISING_STOPPED = 0;
+ private static final int MSG_START_ADVERTISING = 1;
+ private static final int MSG_ADVERTISING_STARTED = 2;
+ private static final int MSG_STOP_ADVERTISING = 3;
+ private static final int MSG_TIMEOUT = 4;
+
+ private static final int OPERATION_TIMEOUT_MS = 4000;
+
+ private int mState = STATE_STOPPED;
+ private final ArrayList<Message> mDeferredMessages = new ArrayList<Message>();
+
+ private class AdvertisingRequest {
+ public final byte[] mData;
+ public final int mInterval;
+ public final Callbacks mCallback;
+
+ AdvertisingRequest(byte[] data, int interval, Callbacks callback) {
+ mInterval = interval;
+ mData = data;
+ mCallback = callback;
}
- mAdvertising = true;
- if (advertisingSet == null) return;
- //TODO: b/196233989
- //advertisingSet.getOwnAddress();
- Slogf.w(TAG, "AdvertisingSet#getOwnAddress not called."
- + " This feature is not supported in this platform version.");
+ }
+
+ AdvertisingHandler() {
+ super(CarServiceUtils.getHandlerThread(FastPairProvider.THREAD_NAME).getLooper());
+ }
+
+ public void startAdvertising(byte[] data, int interval, Callbacks callback) {
+ if (DBG) Slogf.d(TAG, "HANDLER: startAdvertising(data=%s)", Arrays.toString(data));
+ AdvertisingRequest request = new AdvertisingRequest(data, interval, callback);
+ sendMessage(obtainMessage(MSG_START_ADVERTISING, request));
+ }
+
+ public void advertisingStarted() {
+ if (DBG) Slogf.d(TAG, "HANDLER: advertisingStart()");
+ sendMessage(obtainMessage(MSG_ADVERTISING_STARTED));
+ }
+
+ public void stopAdvertising() {
+ if (DBG) Slogf.d(TAG, "HANDLER: stopAdvertising()");
+ sendMessage(obtainMessage(MSG_STOP_ADVERTISING));
+ }
+
+ public void advertisingStopped() {
+ if (DBG) Slogf.d(TAG, "HANDLER: advertisingStop()");
+ sendMessage(obtainMessage(MSG_ADVERTISING_STOPPED));
+ }
+
+ private void queueOperationTimeout() {
+ removeMessages(MSG_TIMEOUT);
+ sendMessageDelayed(obtainMessage(MSG_TIMEOUT), OPERATION_TIMEOUT_MS);
}
@Override
- public void onAdvertisingSetStopped(AdvertisingSet advertisingSet) {
- if (DBG) Slogf.d(TAG, "onAdvertisingSetStopped():");
- mAdvertising = false;
+ public void handleMessage(Message msg) {
+ if (DBG) {
+ Slogf.i(TAG, "HANDLER: Received message %s, state=%s", messageToString(msg.what),
+ stateToString(mState));
+ }
+ switch (msg.what) {
+ case MSG_ADVERTISING_STOPPED:
+ removeMessages(MSG_TIMEOUT);
+ transitionTo(STATE_STOPPED);
+ processDeferredMessages();
+ break;
+
+ case MSG_START_ADVERTISING:
+ if (mState == STATE_STARTED) {
+ break;
+ } else if (mState != STATE_STOPPED) {
+ deferMessage(msg);
+ return;
+ }
+ AdvertisingRequest request = (AdvertisingRequest) msg.obj;
+ if (startAdvertisingInternal(request.mData, request.mInterval,
+ request.mCallback)) {
+ transitionTo(STATE_STARTING);
+ }
+ queueOperationTimeout();
+ break;
+
+ case MSG_ADVERTISING_STARTED:
+ removeMessages(MSG_TIMEOUT);
+ transitionTo(STATE_STARTED);
+ processDeferredMessages();
+ break;
+
+ case MSG_STOP_ADVERTISING:
+ if (mState == STATE_STOPPED) {
+ break;
+ } else if (mState != STATE_STARTED) {
+ deferMessage(msg);
+ return;
+ }
+ stopAdvertisingInternal();
+ transitionTo(STATE_STOPPING);
+ queueOperationTimeout();
+ break;
+ case MSG_TIMEOUT:
+ if (mState == STATE_STARTING) {
+ Slogf.w(TAG, "HANDLER: Timed out waiting for startAdvertising");
+ stopAdvertisingInternal();
+ } else if (mState == STATE_STOPPING) {
+ Slogf.w(TAG, "HANDLER: Timed out waiting for stopAdvertising");
+ } else {
+ Slogf.e(TAG, "HANDLER: Unexpected timeout in state %s",
+ stateToString(mState));
+ }
+ transitionTo(STATE_STOPPED);
+ processDeferredMessages();
+ break;
+
+ default:
+ Slogf.e(TAG, "HANDLER: Unexpected message: %d", msg.what);
+ }
}
- /*
- * TODO: b/196233989
- @Override
- public void onOwnAddressRead(AdvertisingSet advertisingSet, int addressType,
- String address) {
- if (DBG) Slogf.d(TAG, "onOwnAddressRead Type= %s, Address= %s", addressType, address);
- mCallbacks.onRpaUpdated(mBluetoothAdapter.getRemoteDevice(address));
+ private void transitionTo(int state) {
+ if (DBG) Slogf.d(TAG, "HANDLER: %s -> %s", stateToString(mState), stateToString(state));
+ mState = state;
}
- */
- };
+
+ private void deferMessage(Message message) {
+ if (DBG) {
+ Slogf.i(TAG, "HANDLER: Deferred message, message=%s",
+ messageToString(message.what));
+ }
+
+ Message copy = obtainMessage();
+ copy.copyFrom(message);
+ mDeferredMessages.add(copy);
+
+ if (DBG) {
+ StringBuilder sb = new StringBuilder();
+ sb.append("[");
+ for (Message m : mDeferredMessages) {
+ sb.append(" ").append(messageToString(m.what));
+ }
+ sb.append(" ]");
+ Slogf.d(TAG, "HANDLER: Deferred List: %s", sb.toString());
+ }
+ }
+
+ private void processDeferredMessages() {
+ if (DBG) {
+ Slogf.d(TAG, "HANDLER: Process deferred Messages, size=%d",
+ mDeferredMessages.size());
+ }
+ for (int i = mDeferredMessages.size() - 1; i >= 0; i--) {
+ Message message = mDeferredMessages.get(i);
+ if (DBG) {
+ Slogf.i(TAG, "HANDLER: Adding deferred message to front, message=%s",
+ messageToString(message.what));
+ }
+ sendMessageAtFrontOfQueue(message);
+ }
+ mDeferredMessages.clear();
+ }
+
+ public int getState() {
+ return mState;
+ }
+
+ private String messageToString(int message) {
+ switch (message) {
+ case MSG_ADVERTISING_STOPPED:
+ return "MSG_ADVERTISING_STOPPED";
+ case MSG_START_ADVERTISING:
+ return "MSG_START_ADVERTISING";
+ case MSG_ADVERTISING_STARTED:
+ return "MSG_ADVERTISING_STARTED";
+ case MSG_STOP_ADVERTISING:
+ return "MSG_STOP_ADVERTISING";
+ case MSG_TIMEOUT:
+ return "MSG_TIMEOUT";
+ default:
+ return "Unknown";
+ }
+ }
+ }
+
+ private String stateToString(int state) {
+ switch (state) {
+ case STATE_STOPPED:
+ return "STATE_STOPPED";
+ case STATE_STARTING:
+ return "STATE_STARTING";
+ case STATE_STARTED:
+ return "STATE_STARTED";
+ case STATE_STOPPING:
+ return "STATE_STOPPING";
+ default:
+ return "Unknown";
+ }
+ }
@ExcludeFromCodeCoverageGeneratedReport(reason = DUMP_INFO)
public void dump(IndentingPrintWriter writer) {
- if (mAdvertising) {
- writer.println("Currently advertising : " + mData);
+ writer.println("FastPairAdvertiser:");
+ writer.increaseIndent();
+ writer.println("AdvertisingState : " + stateToString(getAdvertisingState()));
+ if (isAdvertising()) {
+ writer.println("Advertising Interval : " + mAdvertisingSetParameters.getInterval());
+ writer.println("TX Power : " + mTxPower + "/"
+ + mAdvertisingSetParameters.getTxPowerLevel());
+ writer.println("Advertising Data : " + mData);
}
+ writer.decreaseIndent();
}
}
diff --git a/service/src/com/android/car/bluetooth/FastPairGattServer.java b/service/src/com/android/car/bluetooth/FastPairGattServer.java
index 9f82ee9..8fe585d 100644
--- a/service/src/com/android/car/bluetooth/FastPairGattServer.java
+++ b/service/src/com/android/car/bluetooth/FastPairGattServer.java
@@ -15,7 +15,8 @@
*/
package com.android.car.bluetooth;
-import static com.android.car.bluetooth.FastPairUtils.AccountKey;
+import static com.android.car.bluetooth.FastPairAccountKeyStorage.AccountKey;
+import static com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport.DUMP_INFO;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
@@ -26,6 +27,7 @@
import android.bluetooth.BluetoothGattServerCallback;
import android.bluetooth.BluetoothGattService;
import android.bluetooth.BluetoothManager;
+import android.bluetooth.BluetoothProfile;
import android.car.builtin.util.Slogf;
import android.content.BroadcastReceiver;
import android.content.Context;
@@ -34,8 +36,11 @@
import android.os.Handler;
import android.os.ParcelUuid;
import android.util.Base64;
+import android.util.Log;
+import com.android.car.CarLog;
import com.android.car.CarServiceUtils;
+import com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport;
import com.android.car.internal.util.IndentingPrintWriter;
import java.math.BigInteger;
@@ -54,6 +59,7 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
+import java.util.Objects;
import java.util.Random;
import javax.crypto.Cipher;
@@ -66,7 +72,7 @@
* Seeker to connect, after which time it manages the authentication an performs the steps as
* required by the Fast Pair Specification.
*/
-class FastPairGattServer {
+public class FastPairGattServer {
// Service ID assigned for FastPair.
public static final ParcelUuid FAST_PAIR_SERVICE_UUID = ParcelUuid
.fromString("0000FE2C-0000-1000-8000-00805f9b34fb");
@@ -82,10 +88,14 @@
.fromString("00002902-0000-1000-8000-00805f9b34fb");
public static final ParcelUuid DEVICE_NAME_CHARACTERISTIC_CONFIG = ParcelUuid
.fromString("00002A00-0000-1000-8000-00805f9b34fb");
- private static final String TAG = "FastPairGattServer";
- private static final boolean DBG = FastPairUtils.DBG;
+ private static final String TAG = CarLog.tagFor(FastPairGattServer.class);
+ private static final boolean DBG = Slogf.isLoggable(TAG, Log.DEBUG);
private static final int MAX_KEY_COUNT = 10;
- private static final int KEY_LIFESPAN = 10_000;
+ private static final int KEY_LIFESPAN_AWAIT_PAIRING = 10_000;
+ // Spec *does* say indefinitely but not having a timeout is risky. This matches the BT stack's
+ // internal pairing timeout
+ private static final int KEY_LIFESPAN_PAIRING = 35_000;
+ private static final int KEY_LIFESPAN_AWAIT_ACCOUNT_KEY = 10_000;
private static final int INVALID = -1;
private final boolean mAutomaticPasskeyConfirmation;
@@ -93,17 +103,17 @@
private final String mPrivateAntiSpoof;
private final Context mContext;
- private ArrayList<AccountKey> mKeys = new ArrayList<>();
+ private final FastPairAccountKeyStorage mFastPairAccountKeyStorage;
+
private BluetoothGattServer mBluetoothGattServer;
+ private final BluetoothManager mBluetoothManager;
private final BluetoothAdapter mBluetoothAdapter;
private int mPairingPasskey = INVALID;
- private int mFailureCount = 0;
- private int mSuccessCount = 0;
+ private final DecryptionFailureCounter mFailureCounter = new DecryptionFailureCounter();
private BluetoothGattService mFastPairService = new BluetoothGattService(
FAST_PAIR_SERVICE_UUID.getUuid(), BluetoothGattService.SERVICE_TYPE_PRIMARY);
private Callbacks mCallbacks;
private SecretKeySpec mSharedSecretKey;
- private byte[] mEncryptedResponse;
private BluetoothDevice mLocalRpaDevice;
private BluetoothDevice mRemotePairingDevice;
private BluetoothDevice mRemoteGattDevice;
@@ -116,14 +126,53 @@
void onPairingCompleted(boolean successful);
}
- /**
- * Check if a client is connected to this GATT server
- * @return true if connected;
- */
- public boolean isConnected() {
- return (mRemoteGattDevice != null);
+ private class DecryptionFailureCounter {
+ public static final int FAILURE_LIMIT = 10;
+ private static final int FAILURE_RESET_TIMEOUT = 300_000; // 5 minutes
+
+ private int mCount = 0;
+
+ private Runnable mResetRunnable = new Runnable() {
+ @Override
+ public void run() {
+ Slogf.i(TAG, "Five minutes have expired. Reset failure count to 0");
+ reset();
+ }
+ };
+
+ public void increment() {
+ if (hasExceededLimit()) {
+ Slogf.w(TAG, "Failure count is already at the limit.");
+ return;
+ }
+
+ mCount++;
+ Slogf.i(TAG, "Failure count increased, failures=%d", mCount);
+ if (hasExceededLimit()) {
+ Slogf.w(TAG, "Failure count has reached 10, wait 5 minutes for more tries");
+ mHandler.postDelayed(mResetRunnable, FAILURE_RESET_TIMEOUT);
+ }
+ }
+
+ public void reset() {
+ Slogf.i(TAG, "Reset failure count");
+ mHandler.removeCallbacks(mResetRunnable);
+ mCount = 0;
+ }
+
+ public boolean hasExceededLimit() {
+ return mCount >= FAILURE_LIMIT;
+ }
+
+ @Override
+ public String toString() {
+ return String.valueOf(mCount);
+ }
}
+ /**
+ * Notify this FastPairGattServer of a new RPA from the FastPairAdvertiser
+ */
public void updateLocalRpa(BluetoothDevice device) {
mLocalRpaDevice = device;
}
@@ -131,11 +180,13 @@
private Runnable mClearSharedSecretKey = new Runnable() {
@Override
public void run() {
- mSharedSecretKey = null;
+ Slogf.w(TAG, "Shared secret key has expired. Clearing key material.");
+ clearSharedSecretKey();
}
};
+
private final Handler mHandler = new Handler(
- CarServiceUtils.getHandlerThread(FastPairUtils.THREAD_NAME).getLooper());
+ CarServiceUtils.getHandlerThread(FastPairProvider.THREAD_NAME).getLooper());
private BluetoothGattCharacteristic mModelIdCharacteristic;
private BluetoothGattCharacteristic mKeyBasedPairingCharacteristic;
private BluetoothGattCharacteristic mPasskeyCharacteristic;
@@ -153,12 +204,13 @@
if (DBG) {
Slogf.d(TAG, "onConnectionStateChange %d Device: %s", newState, device);
}
- if (newState == 0) {
- mPairingPasskey = -1;
- mSharedSecretKey = null;
+ if (newState == BluetoothProfile.STATE_DISCONNECTED) {
+ mPairingPasskey = INVALID;
+ clearSharedSecretKey();
mRemoteGattDevice = null;
+ mRemotePairingDevice = null;
mCallbacks.onPairingCompleted(false);
- } else if (newState > 0) {
+ } else if (newState == BluetoothProfile.STATE_CONNECTED) {
mRemoteGattDevice = device;
}
}
@@ -179,7 +231,6 @@
characteristic.getValue());
}
-
@Override
public void onCharacteristicWriteRequest(BluetoothDevice device, int requestId,
BluetoothGattCharacteristic characteristic, boolean preparedWrite,
@@ -188,27 +239,25 @@
super.onCharacteristicWriteRequest(device, requestId, characteristic, preparedWrite,
responseNeeded, offset, value);
if (DBG) {
- Slogf.d(TAG, "onWrite uuid() %s Length %d", characteristic.getUuid(), value.length);
+ Slogf.d(TAG, "onWrite, uuid=%s, length=%d", characteristic.getUuid(),
+ (value != null ? value.length : -1));
}
- if (characteristic == mAccountKeyCharacteristic) {
- if (DBG) {
- Slogf.d(TAG, "onWriteAccountKeyCharacteristic");
- }
- processAccountKey(value);
- mBluetoothGattServer
- .sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS, offset,
- characteristic.getValue());
-
- } else if (characteristic == mKeyBasedPairingCharacteristic) {
+ if (characteristic == mKeyBasedPairingCharacteristic) {
if (DBG) {
- Slogf.d(TAG, "KeyBasedPairingCharacteristic");
+ Slogf.d(TAG, "onWriteKeyBasedPairingCharacteristic");
}
- processKeyBasedPairing(value);
- mKeyBasedPairingCharacteristic.setValue(mEncryptedResponse);
- mBluetoothGattServer
+ byte[] response = processKeyBasedPairing(value);
+ if (response == null) {
+ Slogf.w(TAG, "Could not process key based pairing request. Ignoring.");
+ mBluetoothGattServer
.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS, offset,
- mEncryptedResponse);
+ null);
+ return;
+ }
+ mKeyBasedPairingCharacteristic.setValue(response);
+ mBluetoothGattServer.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS,
+ offset, response);
mBluetoothGattServer
.notifyCharacteristicChanged(device, mDeviceNameCharacteristic, false);
mBluetoothGattServer
@@ -218,11 +267,17 @@
if (DBG) {
Slogf.d(TAG, "onWritePasskey %s", characteristic.getUuid());
}
- mBluetoothGattServer
- .sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS, offset,
- mEncryptedResponse);
processPairingKey(value);
+ mBluetoothGattServer
+ .sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS, offset, null);
+ } else if (characteristic == mAccountKeyCharacteristic) {
+ if (DBG) {
+ Slogf.d(TAG, "onWriteAccountKeyCharacteristic");
+ }
+ processAccountKey(value);
+ mBluetoothGattServer
+ .sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS, offset, null);
} else {
Slogf.w(TAG, "onWriteOther %s", characteristic.getUuid());
}
@@ -246,17 +301,66 @@
BroadcastReceiver mPairingAttemptsReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
+ String action = intent.getAction();
if (DBG) {
- Slogf.d(TAG, intent.getAction());
+ Slogf.d(TAG, action);
}
- if (BluetoothDevice.ACTION_PAIRING_REQUEST.equals(intent.getAction())) {
- mRemotePairingDevice = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
- mPairingPasskey = intent.getIntExtra(BluetoothDevice.EXTRA_PAIRING_KEY, INVALID);
- if (DBG) {
- Slogf.d(TAG, "DeviceAddress: %s PairingCode: %s",
- mRemotePairingDevice, mPairingPasskey);
- }
- sendPairingResponse(mPairingPasskey);
+
+ switch (action) {
+ case BluetoothDevice.ACTION_PAIRING_REQUEST:
+ mRemotePairingDevice = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
+ mPairingPasskey =
+ intent.getIntExtra(BluetoothDevice.EXTRA_PAIRING_KEY, INVALID);
+ if (DBG) {
+ Slogf.d(TAG, "Pairing Request - device=%s, pin_code=%s",
+ mRemotePairingDevice, mPairingPasskey);
+ }
+ sendPairingResponse(mPairingPasskey);
+ // TODO (243578517): Abort the broadcast when everything is valid and we support
+ // automatic acceptance.
+ break;
+
+ case BluetoothDevice.ACTION_BOND_STATE_CHANGED:
+ BluetoothDevice device =
+ intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
+ int state = intent.getIntExtra(BluetoothDevice.EXTRA_BOND_STATE, INVALID);
+ int previousState =
+ intent.getIntExtra(BluetoothDevice.EXTRA_PREVIOUS_BOND_STATE, INVALID);
+
+ if (DBG) {
+ Slogf.d(TAG, "Bond State Change - device=%s, old_state=%s, new_state=%s",
+ device, previousState, state);
+ }
+
+ // If the bond state has changed for the device we're current fast pairing with
+ // and it is now bonded, then pairing is complete. Reset the failure count to 0.
+ // Await a potential account key.
+ if (device != null && device.equals(mRemotePairingDevice)) {
+ if (state == BluetoothDevice.BOND_BONDED) {
+ if (DBG) {
+ Slogf.d(TAG, "Pairing complete, device=%s", mRemotePairingDevice);
+ }
+ setSharedSecretKeyLifespan(KEY_LIFESPAN_AWAIT_ACCOUNT_KEY);
+ mRemotePairingDevice = null;
+ mFailureCounter.reset();
+ } else if (state == BluetoothDevice.BOND_NONE) {
+ if (DBG) {
+ Slogf.d(TAG, "Pairing attempt failed, device=%s",
+ mRemotePairingDevice);
+ }
+ mRemotePairingDevice = null;
+ }
+ }
+ break;
+
+ case BluetoothAdapter.ACTION_LOCAL_NAME_CHANGED:
+ String name = intent.getStringExtra(BluetoothAdapter.EXTRA_LOCAL_NAME);
+ updateLocalName(name);
+ break;
+
+ default:
+ Slogf.w(TAG, "Unknown action. Skipped");
+ break;
}
}
};
@@ -271,319 +375,26 @@
* authenticated through the Fast Pair protocol without further user interaction.
*/
FastPairGattServer(Context context, int modelId, String antiSpoof,
- Callbacks callbacks, boolean automaticAcceptance) {
- mContext = context;
- mCallbacks = callbacks;
+ Callbacks callbacks, boolean automaticAcceptance,
+ FastPairAccountKeyStorage fastPairAccountKeyStorage) {
+ mContext = Objects.requireNonNull(context);
+ mFastPairAccountKeyStorage = Objects.requireNonNull(fastPairAccountKeyStorage);
+ mCallbacks = Objects.requireNonNull(callbacks);
mPrivateAntiSpoof = antiSpoof;
mAutomaticPasskeyConfirmation = automaticAcceptance;
- BluetoothManager bluetoothManager = context.getSystemService(BluetoothManager.class);
- mBluetoothAdapter = bluetoothManager.getAdapter();
- mBluetoothGattServer = bluetoothManager
- .openGattServer(context, mBluetoothGattServerCallback);
- if (DBG) {
- Slogf.d(TAG, "mBTManager: %s GATT: %s", bluetoothManager, mBluetoothGattServer);
- }
+ mBluetoothManager = context.getSystemService(BluetoothManager.class);
+ mBluetoothAdapter = mBluetoothManager.getAdapter();
ByteBuffer modelIdBytes = ByteBuffer.allocate(4).order(ByteOrder.LITTLE_ENDIAN).putInt(
modelId);
mModelId = Arrays.copyOfRange(modelIdBytes.array(), 0, 3);
setup();
}
- void setSharedSecretKey(byte[] key) {
- mSharedSecretKey = new SecretKeySpec(key, "AES");
- mHandler.postDelayed(mClearSharedSecretKey, KEY_LIFESPAN);
- }
-
- /**
- * Utilize the key set via setSharedSecretKey to attempt to encrypt the provided data
- * @param decoded data to be encrypted
- * @return encrypted data upon success; null otherwise
- */
- byte[] encrypt(byte[] decoded) {
- try {
- Cipher cipher = Cipher.getInstance("AES/ECB/NoPadding");
- cipher.init(Cipher.ENCRYPT_MODE, mSharedSecretKey);
- mHandler.removeCallbacks(mClearSharedSecretKey);
- mHandler.postDelayed(mClearSharedSecretKey, KEY_LIFESPAN);
- return cipher.doFinal(decoded);
-
- } catch (Exception e) {
- Slogf.e(TAG, "Error encrypting: %s", e);
- }
- if (DBG) {
- Slogf.w(TAG, "Encryption Failed, clear key");
- }
- mHandler.removeCallbacks(mClearSharedSecretKey);
- mSharedSecretKey = null;
- return null;
- }
- /**
- * Utilize the key set via setSharedSecretKey to attempt to decrypt the provided data
- * @param encoded data to be decrypted
- * @return decrypted data upon success; null otherwise
- */
- byte[] decrypt(byte[] encoded) {
- try {
- Cipher cipher = Cipher.getInstance("AES/ECB/NoPadding");
- cipher.init(Cipher.DECRYPT_MODE, mSharedSecretKey);
- mHandler.removeCallbacks(mClearSharedSecretKey);
- mHandler.postDelayed(mClearSharedSecretKey, KEY_LIFESPAN);
- return cipher.doFinal(encoded);
-
- } catch (Exception e) {
- Slogf.e(TAG, "Error decrypting: %s", e);
- }
- mHandler.removeCallbacks(mClearSharedSecretKey);
- mSharedSecretKey = null;
- return null;
- }
-
- /**
- * The final step of the Fast Pair procedure involves receiving an account key from the
- * Fast Pair seeker, authenticating it, and then storing it for future use.
- * @param accountKey
- */
- void processAccountKey(byte[] accountKey) {
- byte[] decodedAccountKey = decrypt(accountKey);
- if (decodedAccountKey != null && decodedAccountKey[0] == 0x04) {
- if (DBG) {
- Slogf.d(TAG, "ReceivedAccountKey %s", decodedAccountKey[0]);
- }
- FastPairUtils.AccountKey receivedKey = new FastPairUtils.AccountKey(decodedAccountKey);
- if (!mKeys.contains(receivedKey)) {
- mKeys.add(receivedKey);
- }
- // due to space restrictions in the protocol we can only store 10 keys
- while (mKeys.size() > MAX_KEY_COUNT) {
- mKeys.remove(0);
- }
- FastPairUtils.writeStoredAccountKeys(mContext, mKeys);
- mSuccessCount++;
- } else {
- if (DBG) {
- Slogf.d(TAG, "Invalid Account Key");
- }
- }
- }
-
- /**
- * New pairings based upon model ID requires the Fast Pair provider to authenticate to the
- * seeker that it is in possession of the private key associated with the model ID advertised,
- * this is accomplished via Eliptic-curve Diffie-Hellman
- * @param localPrivateKey
- * @param remotePublicKey
- * @return
- */
- AccountKey calculateAntiSpoofing(byte[] localPrivateKey, byte[] remotePublicKey) {
- try {
- if (DBG) {
- Slogf.d(TAG, "Calculating secret key from remotePublicKey");
- }
- // Initialize the EC key generator
- KeyFactory keyFactory = KeyFactory.getInstance("EC");
- KeyPairGenerator kpg = KeyPairGenerator.getInstance("EC");
- ECParameterSpec ecParameterSpec = ((ECPublicKey) kpg.generateKeyPair().getPublic())
- .getParams();
- // Use the private anti-spoofing key
- ECPrivateKeySpec ecPrivateKeySpec = new ECPrivateKeySpec(
- new BigInteger(1, localPrivateKey),
- ecParameterSpec);
- // Calculate the public point utilizing the data received from the remote device
- ECPoint publicPoint = new ECPoint(new BigInteger(1, Arrays.copyOf(remotePublicKey, 32)),
- new BigInteger(1, Arrays.copyOfRange(remotePublicKey, 32, 64)));
- ECPublicKeySpec ecPublicKeySpec = new ECPublicKeySpec(publicPoint, ecParameterSpec);
- PrivateKey privateKey = keyFactory.generatePrivate(ecPrivateKeySpec);
- PublicKey publicKey = keyFactory.generatePublic(ecPublicKeySpec);
-
- // Generate a shared secret
- KeyAgreement keyAgreement = KeyAgreement.getInstance("ECDH");
- keyAgreement.init(privateKey);
- keyAgreement.doPhase(publicKey, true);
- byte[] sharedSecret = keyAgreement.generateSecret();
-
- // Use the first 16 bytes of a hash of the shared secret as the session key
- final byte[] digest = MessageDigest.getInstance("SHA-256").digest(sharedSecret);
-
- byte[] AESAntiSpoofingKey = Arrays.copyOf(digest, 16);
- if (DBG) {
- Slogf.d(TAG, "Key calculated");
- }
- return new AccountKey(AESAntiSpoofingKey);
- } catch (Exception e) {
- Slogf.w(TAG, "Error calculating anti-spoofing key: %s", e);
- return null;
- }
- }
-
- /**
- * Determine if this pairing request is based on the anti-spoof keys associated with the model
- * id or stored account keys.
- * @param accountKey
- * @return
- */
- boolean processKeyBasedPairing(byte[] pairingRequest) {
- if (mFailureCount >= 10) return false;
-
- List<SecretKeySpec> possibleKeys = new ArrayList<>();
- if (pairingRequest.length == 80) {
- // if the pairingRequest is 80 bytes long try the anit-spoof key
- final byte[] remotePublicKey = Arrays.copyOfRange(pairingRequest, 16, 80);
-
- possibleKeys
- .add(calculateAntiSpoofing(Base64.decode(mPrivateAntiSpoof, 0), remotePublicKey)
- .getKeySpec());
- } else {
- // otherwise the pairing request is the encrypted request, try all the stored account
- // keys
- List<AccountKey> storedAccountKeys = FastPairUtils.readStoredAccountKeys(mContext);
- for (AccountKey key : storedAccountKeys) {
- possibleKeys.add(new SecretKeySpec(key.toBytes(), "AES"));
- }
- }
-
- byte[] encryptedRequest = Arrays.copyOfRange(pairingRequest, 0, 16);
- if (DBG) {
- Slogf.d(TAG, "Checking %d Keys", possibleKeys.size());
- }
- // check all the keys for a valid pairing request
- for (SecretKeySpec key : possibleKeys) {
- if (DBG) {
- Slogf.d(TAG, "Checking possibleKey");
- }
- if (validatePairingRequest(encryptedRequest, key)) {
- return true;
- }
- }
- Slogf.w(TAG, "No Matching Key found");
- mFailureCount++;
- mSharedSecretKey = null;
- return false;
- }
-
- /**
- * Check if the pairing request is a valid request.
- * A request is valid if its decrypted value is of type 0x00 or 0x10 and it contains either the
- * seekers public or current BLE address
- * @param encryptedRequest the request to decrypt and validate
- * @param secretKeySpec the key to use while attempting to decrypt the request
- * @return true if the key matches, false otherwise
- */
- boolean validatePairingRequest(byte[] encryptedRequest, SecretKeySpec secretKeySpec) {
- // Decrypt the request
- mSharedSecretKey = secretKeySpec;
- byte[] decryptedRequest = decrypt(encryptedRequest);
- if (decryptedRequest == null) {
- return false;
- }
- if (DBG) {
- Slogf.d(TAG, "Decrypted %s Flags %s", decryptedRequest[0], decryptedRequest[1]);
- }
- // Check that the request is either a Key-based Pairing Request or an Action Request
- if (decryptedRequest[0] == 0 || decryptedRequest[0] == 0x10) {
- String localAddress = mBluetoothAdapter.getAddress();
- byte[] localAddressBytes = FastPairUtils.getBytesFromAddress(localAddress);
- // Extract the remote address bytes from the message
- byte[] remoteAddressBytes = Arrays.copyOfRange(decryptedRequest, 2, 8);
- BluetoothDevice localDevice = mBluetoothAdapter.getRemoteDevice(localAddress);
- BluetoothDevice reportedDevice = mBluetoothAdapter.getRemoteDevice(remoteAddressBytes);
- if (DBG) {
- Slogf.d(TAG, "Local RPA = %s", mLocalRpaDevice);
- Slogf.d(TAG, "Decrypted, LocalMacAddress: %s remoteAddress: %s",
- localAddress, reportedDevice);
- }
- if (mLocalRpaDevice == null) {
- Slogf.w(TAG, "Cannot get own address; AdvertisingSet#getOwnAddress"
- + " is not supported in this platform version.");
- }
- // Test that the received device address matches this devices address
- if (reportedDevice.equals(localDevice) || reportedDevice.equals(mLocalRpaDevice)) {
- if (DBG) {
- Slogf.d(TAG, "SecretKey Validated");
- }
- // encrypt and respond to the seeker with the local public address
- byte[] rawResponse = new byte[16];
- new Random().nextBytes(rawResponse);
- rawResponse[0] = 0x01;
- System.arraycopy(localAddressBytes, 0, rawResponse, 1, 6);
- mEncryptedResponse = encrypt(rawResponse);
- return encryptedRequest != null;
- }
- }
- return false;
- }
-
- /**
- * Extract the 6 digit Bluetooth Simple Secure Passkey from the received message and confirm
- * it matches the key received through the Bluetooth pairing procedure.
- * If the passkeys match and automatic passkey confirmation is enabled, approve of the pairing.
- * If the passkeys do not match reject the pairing.
- * @param pairingKey
- * @return true if the procedure completed, although pairing may not have been approved
- */
- boolean processPairingKey(byte[] pairingKey) {
- byte[] decryptedRequest = decrypt(pairingKey);
- if (decryptedRequest == null) {
- return false;
- }
- int passkey = Byte.toUnsignedInt(decryptedRequest[1]) * 65536
- + Byte.toUnsignedInt(decryptedRequest[2]) * 256
- + Byte.toUnsignedInt(decryptedRequest[3]);
-
- if (DBG) {
- Slogf.d(TAG, "PairingKey , MessageType %s FastPair Passkey = %d Bluetooth Passkey = %d",
- decryptedRequest[0], passkey, mPairingPasskey);
- }
- // compare the Bluetooth received passkey with the Fast Pair received passkey
- if (mPairingPasskey == passkey) {
- if (mAutomaticPasskeyConfirmation) {
- if (DBG) {
- Slogf.d(TAG, "Passkeys match, accepting");
- }
- mRemotePairingDevice.setPairingConfirmation(true);
- }
- } else if (mPairingPasskey != INVALID) {
- Slogf.w(TAG, "Passkeys don't match, rejecting");
- mRemotePairingDevice.setPairingConfirmation(false);
- }
- return true;
- }
-
- void sendPairingResponse(int passkey) {
- if (!isConnected()) return;
- if (DBG) {
- Slogf.d(TAG, "sendPairingResponse %d", passkey);
- }
- // Send an encrypted response to the seeker with the Bluetooth passkey as required
- byte[] decryptedResponse = new byte[16];
- new Random().nextBytes(decryptedResponse);
- ByteBuffer pairingPasskeyBytes = ByteBuffer.allocate(4).order(ByteOrder.BIG_ENDIAN).putInt(
- passkey);
- decryptedResponse[0] = 0x3;
- decryptedResponse[1] = pairingPasskeyBytes.get(1);
- decryptedResponse[2] = pairingPasskeyBytes.get(2);
- decryptedResponse[3] = pairingPasskeyBytes.get(3);
-
- mEncryptedResponse = encrypt(decryptedResponse);
- if (mEncryptedResponse == null) {
- return;
- }
- mPasskeyCharacteristic.setValue(mEncryptedResponse);
- mBluetoothGattServer
- .notifyCharacteristicChanged(mRemoteGattDevice, mPasskeyCharacteristic, false);
- }
-
/**
* Initialize all of the GATT characteristics with appropriate default values and the required
* configurations.
*/
- void setup() {
- // Setup filter to receive pairing attempts and passkey. Make this a high priority broadcast
- // receiver so others can't intercept it before we can handle it.
- IntentFilter filter = new IntentFilter();
- filter.addAction(BluetoothDevice.ACTION_PAIRING_REQUEST);
- filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
- mContext.registerReceiver(mPairingAttemptsReceiver, filter);
-
+ private void setup() {
mModelIdCharacteristic = new BluetoothGattCharacteristic(FAST_PAIR_MODEL_ID_UUID.getUuid(),
BluetoothGattCharacteristic.PROPERTY_READ,
BluetoothGattCharacteristic.PERMISSION_READ);
@@ -625,27 +436,483 @@
new BluetoothGattCharacteristic(DEVICE_NAME_CHARACTERISTIC_CONFIG.getUuid(),
BluetoothGattCharacteristic.PROPERTY_READ,
BluetoothGattCharacteristic.PERMISSION_READ);
- mDeviceNameCharacteristic.setValue(mBluetoothAdapter.getName());
+ String name = mBluetoothAdapter.getName();
+ if (name == null) {
+ name = "";
+ }
+ mDeviceNameCharacteristic.setValue(name);
mFastPairService.addCharacteristic(mDeviceNameCharacteristic);
}
- void start() {
- if (mBluetoothGattServer == null) {
- return;
+ void updateLocalName(String name) {
+ Slogf.d(TAG, "Device name changed to '%s'", name);
+ if (name != null) {
+ mDeviceNameCharacteristic.setValue(name);
}
+ }
+
+ /**
+ * Start the FastPairGattServer
+ *
+ * This makes the underlying service and characteristics available and registers us for events.
+ */
+ public boolean start() {
+ if (isStarted()) {
+ return false;
+ }
+
+ // Setup filter to receive pairing attempts and passkey. Make this a high priority broadcast
+ // receiver so others can't intercept it before we can handle it.
+ IntentFilter filter = new IntentFilter();
+ filter.addAction(BluetoothDevice.ACTION_PAIRING_REQUEST);
+ filter.addAction(BluetoothAdapter.ACTION_LOCAL_NAME_CHANGED);
+ filter.addAction(BluetoothDevice.ACTION_BOND_STATE_CHANGED);
+ filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
+ mContext.registerReceiver(mPairingAttemptsReceiver, filter);
+
+ mBluetoothGattServer = mBluetoothManager
+ .openGattServer(mContext, mBluetoothGattServerCallback);
+
+ if (mBluetoothGattServer == null) {
+ Slogf.e(TAG, "Start failed, could not get a GATT server.");
+ mContext.unregisterReceiver(mPairingAttemptsReceiver);
+ return false;
+ }
+
mBluetoothGattServer.addService(mFastPairService);
+ return true;
}
- void stop() {
- if (mBluetoothGattServer == null) {
+ /**
+ * Stop the FastPairGattServer
+ *
+ * This removes our underlying service and clears our state.
+ */
+ public boolean stop() {
+ if (!isStarted()) {
+ return true;
+ }
+
+ clearSharedSecretKey();
+
+ if (isConnected()) {
+ mBluetoothGattServer.cancelConnection(mRemoteGattDevice);
+ mRemoteGattDevice = null;
+ mCallbacks.onPairingCompleted(false);
+ }
+ mPairingPasskey = -1;
+ mSharedSecretKey = null;
+ mBluetoothGattServer.removeService(mFastPairService);
+ mContext.unregisterReceiver(mPairingAttemptsReceiver);
+ return true;
+ }
+
+ /**
+ * Check if this service is started
+ */
+ public boolean isStarted() {
+ return (mBluetoothGattServer == null)
+ ? false
+ : mBluetoothGattServer.getService(FAST_PAIR_SERVICE_UUID.getUuid()) != null;
+ }
+
+ /**
+ * Check if a client is connected to this GATT server
+ * @return true if connected;
+ */
+ public boolean isConnected() {
+ if (DBG) {
+ Slogf.d(TAG, "isConnected() -> %s", (mRemoteGattDevice != null));
+ }
+ return (mRemoteGattDevice != null);
+ }
+
+ private void setSharedSecretKey(SecretKeySpec key, int lifespan) {
+ if (key == null) {
+ Slogf.w(TAG, "Cannot set a null shared secret.");
return;
}
- mBluetoothGattServer.removeService(mFastPairService);
+ Slogf.i(TAG, "Shared secret key set, key=%s lifespan=%d", key, lifespan);
+ mSharedSecretKey = key;
+ setSharedSecretKeyLifespan(lifespan);
}
+ private void setSharedSecretKeyLifespan(int lifespan) {
+ if (mSharedSecretKey == null) {
+ Slogf.w(TAG, "Ignoring lifespan on null key");
+ return;
+ }
+ if (DBG) {
+ Slogf.d(TAG, "Update key lifespan to %d", lifespan);
+ }
+ mHandler.removeCallbacks(mClearSharedSecretKey);
+ if (lifespan > 0) {
+ mHandler.postDelayed(mClearSharedSecretKey, lifespan);
+ }
+ }
+
+ private void clearSharedSecretKey() {
+ Slogf.i(TAG, "Shared secret key has been cleared");
+ mHandler.removeCallbacks(mClearSharedSecretKey);
+ mSharedSecretKey = null;
+ }
+
+ public boolean isFastPairSessionActive() {
+ return mSharedSecretKey != null;
+ }
+
+ /**
+ * Attempt to encrypt the provided data with the provided key
+ *
+ * @param data data to be encrypted
+ * @param secretKeySpec key to ecrypt the data with
+ * @return encrypted data upon success; null otherwise
+ */
+ private byte[] encrypt(byte[] data, SecretKeySpec secretKeySpec) {
+ if (secretKeySpec == null) {
+ Slogf.e(TAG, "Encryption failed: no key");
+ return null;
+ }
+ try {
+ Cipher cipher = Cipher.getInstance("AES/ECB/NoPadding");
+ cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec);
+ return cipher.doFinal(data);
+
+ } catch (Exception e) {
+ Slogf.e(TAG, "Encryption failed: %s", e);
+ }
+ return null;
+ }
+ /**
+ * Attempt to decrypt the provided data with the provided key
+ *
+ * @param encryptedData data to be decrypted
+ * @param secretKeySpec key to decrypt the data with
+ * @return decrypted data upon success; null otherwise
+ */
+ private byte[] decrypt(byte[] encryptedData, SecretKeySpec secretKeySpec) {
+ if (secretKeySpec == null) {
+ Slogf.e(TAG, "Decryption failed: no key");
+ return null;
+ }
+ try {
+ Cipher cipher = Cipher.getInstance("AES/ECB/NoPadding");
+ cipher.init(Cipher.DECRYPT_MODE, secretKeySpec);
+ return cipher.doFinal(encryptedData);
+
+ } catch (Exception e) {
+ Slogf.e(TAG, "Decryption Failed: %s", e);
+ }
+ return null;
+ }
+
+ /**
+ * Determine if this pairing request is based on the anti-spoof keys associated with the model
+ * id or stored account keys.
+ *
+ * @param accountKey
+ * @return
+ */
+ private byte[] processKeyBasedPairing(byte[] pairingRequest) {
+ if (mFailureCounter.hasExceededLimit()) {
+ Slogf.w(TAG, "Failure count has exceeded 10. Ignoring Key-Based Pairing requests");
+ return null;
+ }
+
+ if (pairingRequest == null) {
+ Slogf.w(TAG, "Received a null pairing request");
+ mFailureCounter.increment();
+ clearSharedSecretKey();
+ return null;
+ }
+
+ List<SecretKeySpec> possibleKeys = new ArrayList<>();
+ if (pairingRequest.length == 80) {
+ if (DBG) {
+ Slogf.d(TAG, "Use Anti-spoofing key");
+ }
+ // if the pairingRequest is 80 bytes long try the anit-spoof key
+ final byte[] remotePublicKey = Arrays.copyOfRange(pairingRequest, 16, 80);
+
+ possibleKeys
+ .add(calculateAntiSpoofing(Base64.decode(mPrivateAntiSpoof, 0), remotePublicKey)
+ .getKeySpec());
+ } else if (pairingRequest.length == 16) {
+ if (DBG) {
+ Slogf.d(TAG, "Use stored account keys");
+ }
+ // otherwise the pairing request is the encrypted request, try all the stored account
+ // keys
+ List<AccountKey> storedAccountKeys = mFastPairAccountKeyStorage.getAllAccountKeys();
+ for (AccountKey key : storedAccountKeys) {
+ possibleKeys.add(new SecretKeySpec(key.toBytes(), "AES"));
+ }
+ } else {
+ Slogf.w(TAG, "Received key based pairing request of invalid length %d",
+ pairingRequest.length);
+ mFailureCounter.increment();
+ clearSharedSecretKey();
+ return null;
+ }
+
+ byte[] encryptedRequest = Arrays.copyOfRange(pairingRequest, 0, 16);
+ if (DBG) {
+ Slogf.d(TAG, "Checking %d Keys", possibleKeys.size());
+ }
+ // check all the keys for a valid pairing request
+ for (SecretKeySpec key : possibleKeys) {
+ if (DBG) {
+ Slogf.d(TAG, "Checking possible key");
+ }
+ if (validateRequestAgainstKey(encryptedRequest, key)) {
+ // If the key was able to decrypt the request and the addresses match then set it as
+ // the shared secret and set a lifespan timeout
+ setSharedSecretKey(key, KEY_LIFESPAN_AWAIT_PAIRING);
+
+ // Use the key to craft encrypted response to the seeker with the local public
+ // address and salt. If encryption goes wrong, move on to the next key
+ String localAddress = mBluetoothAdapter.getAddress();
+ byte[] localAddressBytes = BluetoothUtils.getBytesFromAddress(localAddress);
+ byte[] rawResponse = new byte[16];
+ new Random().nextBytes(rawResponse);
+ rawResponse[0] = 0x01;
+ System.arraycopy(localAddressBytes, 0, rawResponse, 1, 6);
+ byte[] response = encrypt(rawResponse, key);
+ if (response == null) {
+ clearSharedSecretKey();
+ return null;
+ }
+ return response;
+ }
+ }
+ Slogf.w(TAG, "No matching key found");
+ mFailureCounter.increment();
+ clearSharedSecretKey();
+ return null;
+ }
+
+ /**
+ * New pairings based upon model ID requires the Fast Pair provider to authenticate to that the
+ * seeker it is in possession of the private key associated with the model ID advertised. This
+ * is accomplished via Eliptic-curve Diffie-Hellman
+ *
+ * @param localPrivateKey
+ * @param remotePublicKey
+ * @return
+ */
+ private AccountKey calculateAntiSpoofing(byte[] localPrivateKey, byte[] remotePublicKey) {
+ try {
+ if (DBG) {
+ Slogf.d(TAG, "Calculating secret key from remote public key");
+ }
+ // Initialize the EC key generator
+ KeyFactory keyFactory = KeyFactory.getInstance("EC");
+ KeyPairGenerator kpg = KeyPairGenerator.getInstance("EC");
+ ECParameterSpec ecParameterSpec = ((ECPublicKey) kpg.generateKeyPair().getPublic())
+ .getParams();
+ // Use the private anti-spoofing key
+ ECPrivateKeySpec ecPrivateKeySpec = new ECPrivateKeySpec(
+ new BigInteger(1, localPrivateKey),
+ ecParameterSpec);
+ // Calculate the public point utilizing the data received from the remote device
+ ECPoint publicPoint = new ECPoint(new BigInteger(1, Arrays.copyOf(remotePublicKey, 32)),
+ new BigInteger(1, Arrays.copyOfRange(remotePublicKey, 32, 64)));
+ ECPublicKeySpec ecPublicKeySpec = new ECPublicKeySpec(publicPoint, ecParameterSpec);
+ PrivateKey privateKey = keyFactory.generatePrivate(ecPrivateKeySpec);
+ PublicKey publicKey = keyFactory.generatePublic(ecPublicKeySpec);
+
+ // Generate a shared secret
+ KeyAgreement keyAgreement = KeyAgreement.getInstance("ECDH");
+ keyAgreement.init(privateKey);
+ keyAgreement.doPhase(publicKey, true);
+ byte[] sharedSecret = keyAgreement.generateSecret();
+
+ // Use the first 16 bytes of a hash of the shared secret as the session key
+ final byte[] digest = MessageDigest.getInstance("SHA-256").digest(sharedSecret);
+
+ byte[] AESAntiSpoofingKey = Arrays.copyOf(digest, 16);
+ if (DBG) {
+ Slogf.d(TAG, "Key calculated");
+ }
+ return new AccountKey(AESAntiSpoofingKey);
+ } catch (Exception e) {
+ Slogf.w(TAG, "Error calculating anti-spoofing key: %s", e);
+ return null;
+ }
+ }
+
+ /**
+ * Check if the given key can be used to decrypt the pairing request and prove the request is
+ * valid.
+ *
+ * A request is valid if its decrypted value is of type 0x00 or 0x10 and it contains either the
+ * seekers public or current BLE address. If a key successfully decrypts and validates a request
+ * then that is the key we should use as our shared secret key.
+ *
+ * @param encryptedRequest the request to decrypt and validate
+ * @param secretKeySpec the key to use while attempting to decrypt the request
+ * @return true if the key matches, false otherwise
+ */
+ private boolean validateRequestAgainstKey(byte[] encryptedRequest,
+ SecretKeySpec secretKeySpec) {
+ // Decrypt the request
+ byte[] decryptedRequest = decrypt(encryptedRequest, secretKeySpec);
+ if (decryptedRequest == null) {
+ return false;
+ }
+
+ if (DBG) {
+ StringBuilder sb = new StringBuilder();
+ for (byte b : decryptedRequest) {
+ sb.append(String.format("%02X ", b));
+ }
+ Slogf.d(TAG, "Decrypted Request=[ %s]", sb.toString());
+ }
+ // Check that the request is either a Key-based Pairing Request or an Action Request
+ if (decryptedRequest[0] == 0x00 || decryptedRequest[0] == 0x10) {
+ String localAddress = mBluetoothAdapter.getAddress();
+ byte[] localAddressBytes = BluetoothUtils.getBytesFromAddress(localAddress);
+ // Extract the remote address bytes from the message
+ byte[] remoteAddressBytes = Arrays.copyOfRange(decryptedRequest, 2, 8);
+ BluetoothDevice localDevice = mBluetoothAdapter.getRemoteDevice(localAddress);
+ BluetoothDevice reportedDevice = mBluetoothAdapter.getRemoteDevice(remoteAddressBytes);
+ if (DBG) {
+ Slogf.d(TAG, "rpa=%s, public=%s, reported=%s", mLocalRpaDevice, localAddress,
+ reportedDevice);
+ }
+ if (mLocalRpaDevice == null) {
+ Slogf.w(TAG, "Cannot get own address");
+ }
+ // Test that the received device address matches this devices address
+ if (reportedDevice.equals(localDevice) || reportedDevice.equals(mLocalRpaDevice)) {
+ if (DBG) {
+ Slogf.d(TAG, "SecretKey Validated");
+ }
+ return encryptedRequest != null;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Extract the 6 digit Bluetooth Simple Secure Passkey from the received message and confirm
+ * it matches the key received through the Bluetooth pairing procedure.
+ *
+ * If the passkeys match and automatic passkey confirmation is enabled, approve of the pairing.
+ * If the passkeys do not match reject the pairing and invalidate our key material.
+ *
+ * @param pairingKey
+ * @return true if the procedure completed, although pairing may not have been approved
+ */
+ private boolean processPairingKey(byte[] pairingKey) {
+ if (pairingKey == null || pairingKey.length != 16) {
+ clearSharedSecretKey();
+ return false;
+ }
+
+ byte[] decryptedRequest = decrypt(pairingKey, mSharedSecretKey);
+ if (decryptedRequest == null) {
+ clearSharedSecretKey();
+ return false;
+ }
+ int passkey = Byte.toUnsignedInt(decryptedRequest[1]) * 65536
+ + Byte.toUnsignedInt(decryptedRequest[2]) * 256
+ + Byte.toUnsignedInt(decryptedRequest[3]);
+
+ if (DBG) {
+ Slogf.d(TAG, "Received passkey request, type=%s, passkey=%d, our_passkey=%d",
+ decryptedRequest[0], passkey, mPairingPasskey);
+ }
+ // compare the Bluetooth received passkey with the Fast Pair received passkey
+ if (mPairingPasskey == passkey) {
+ if (DBG) {
+ Slogf.d(TAG, "Passkeys match, auto_accept=%s", mAutomaticPasskeyConfirmation);
+ }
+ if (mAutomaticPasskeyConfirmation) {
+ mRemotePairingDevice.setPairingConfirmation(true);
+ }
+ } else if (mPairingPasskey != INVALID) {
+ Slogf.w(TAG, "Passkeys don't match, rejecting");
+ mRemotePairingDevice.setPairingConfirmation(false);
+ clearSharedSecretKey();
+ }
+ return true;
+ }
+
+ /**
+ * Send the seeker the pin code we received so they can validate it. Encrypt it with our shared
+ * secret.
+ *
+ * @param passkey the key-based pairing passkey, as described by the core BT specification
+ */
+ private void sendPairingResponse(int passkey) {
+ if (!isConnected()) return;
+ if (DBG) {
+ Slogf.d(TAG, "sendPairingResponse %d", passkey);
+ }
+
+ // Once pairing begins, we can hold on to the shared secret key until pairing
+ // completes
+ setSharedSecretKeyLifespan(KEY_LIFESPAN_PAIRING);
+
+ // Send an encrypted response to the seeker with the Bluetooth passkey as required
+ byte[] decryptedResponse = new byte[16];
+ new Random().nextBytes(decryptedResponse);
+ ByteBuffer pairingPasskeyBytes = ByteBuffer.allocate(4).order(ByteOrder.BIG_ENDIAN).putInt(
+ passkey);
+ decryptedResponse[0] = 0x3;
+ decryptedResponse[1] = pairingPasskeyBytes.get(1);
+ decryptedResponse[2] = pairingPasskeyBytes.get(2);
+ decryptedResponse[3] = pairingPasskeyBytes.get(3);
+
+ byte[] response = encrypt(decryptedResponse, mSharedSecretKey);
+ if (response == null) {
+ clearSharedSecretKey();
+ return;
+ }
+ mPasskeyCharacteristic.setValue(response);
+ mBluetoothGattServer
+ .notifyCharacteristicChanged(mRemoteGattDevice, mPasskeyCharacteristic, false);
+ }
+
+ /**
+ * The final step of the Fast Pair procedure involves receiving an account key from the
+ * Fast Pair seeker, authenticating it, and then storing it for future use. Only one attempt
+ * at writing this key is allowed by the spec. Discard the shared secret after this one attempt.
+ *
+ * @param accountKey the account key, encrypted with our sharded secret
+ */
+ private void processAccountKey(byte[] accountKey) {
+ if (accountKey == null || accountKey.length != 16) {
+ clearSharedSecretKey();
+ return;
+ }
+
+ byte[] decodedAccountKey = decrypt(accountKey, mSharedSecretKey);
+ if (decodedAccountKey != null && decodedAccountKey[0] == 0x04) {
+ AccountKey receivedKey = new AccountKey(decodedAccountKey);
+ if (DBG) {
+ Slogf.d(TAG, "Received Account Key, key=%s", receivedKey);
+ }
+ mFastPairAccountKeyStorage.add(receivedKey);
+ } else {
+ if (DBG) {
+ Slogf.d(TAG, "Received invalid Account Key");
+ }
+ }
+
+ // Always clear the shared secret key following any attempt to write an account key
+ clearSharedSecretKey();
+ }
+
+ @ExcludeFromCodeCoverageGeneratedReport(reason = DUMP_INFO)
void dump(IndentingPrintWriter writer) {
+ writer.println("FastPairGattServer:");
+ writer.increaseIndent();
+ writer.println("Started : " + isStarted());
+ writer.println("Active : " + isFastPairSessionActive());
writer.println("Currently connected to : " + mRemoteGattDevice);
- writer.println("Successful pairing attempts : " + mSuccessCount);
- writer.println("Unsuccessful pairing attempts : " + mFailureCount);
+ writer.println("Failsure counter : " + mFailureCounter);
+ writer.decreaseIndent();
}
}
diff --git a/service/src/com/android/car/bluetooth/FastPairProvider.java b/service/src/com/android/car/bluetooth/FastPairProvider.java
index 21dbedf..625c4bf 100644
--- a/service/src/com/android/car/bluetooth/FastPairProvider.java
+++ b/service/src/com/android/car/bluetooth/FastPairProvider.java
@@ -27,10 +27,10 @@
import android.content.Intent;
import android.content.IntentFilter;
import android.content.res.Resources;
-import android.os.Handler;
+import android.text.TextUtils;
+import android.util.Log;
import com.android.car.CarLog;
-import com.android.car.CarServiceUtils;
import com.android.car.R;
import com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport;
import com.android.car.internal.util.IndentingPrintWriter;
@@ -44,7 +44,8 @@
*/
public class FastPairProvider {
private static final String TAG = CarLog.tagFor(FastPairProvider.class);
- private static final boolean DBG = FastPairUtils.DBG;
+ private static final boolean DBG = Slogf.isLoggable(TAG, Log.DEBUG);
+ static final String THREAD_NAME = "FastPairProvider";
private final int mModelId;
private final String mAntiSpoofKey;
@@ -52,11 +53,10 @@
private final Context mContext;
private boolean mStarted;
private int mScanMode;
- private BluetoothAdapter mBluetoothAdapter;
- private FastPairAdvertiser mFastPairModelAdvertiser;
- private FastPairAdvertiser mFastPairAccountAdvertiser;
+ private final BluetoothAdapter mBluetoothAdapter;
+ private final FastPairAdvertiser mFastPairAdvertiser;
private FastPairGattServer mFastPairGattServer;
- private Handler mFastPairAdvertiserHandler;
+ private final FastPairAccountKeyStorage mFastPairAccountKeyStorage;
FastPairAdvertiser.Callbacks mAdvertiserCallbacks = new FastPairAdvertiser.Callbacks() {
@Override
@@ -71,55 +71,86 @@
if (DBG) {
Slogf.d(TAG, "onPairingCompleted %s", successful);
}
+ // TODO (243171615): Reassess advertising transitions against specification
if (successful || mScanMode != BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE) {
advertiseAccountKeys();
}
}
-
};
/**
- * listen for changes in the Bluetooth adapter specifically for the Bluetooth adapter turning
- * on, turning off, and changes to discoverability
+ * Listen for changes in the Bluetooth adapter state and scan mode.
+ *
+ * When the adapter is
+ * - ON: Ensure our GATT Server is up and that we are advertising either the model ID or account
+ * key filter, based on current scan mode.
+ * - OTHERWISE: Ensure our GATT server is off.
+ *
+ * When the scan mode is:
+ * - CONNECTABLE / DISCOVERABLE: Advertise the model ID if we are actively discovering as well.
+ * If we are not, then stop advertising temporarily. See below for why this is done.
+ * - CONNECTABLE: Advertise account key filter
+ * - NONE: Do not advertise anything.
*/
BroadcastReceiver mDiscoveryModeChanged = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
- if (DBG) {
- Slogf.d(TAG, "onReceive, %s", action);
- }
switch (action) {
- case BluetoothAdapter.ACTION_SCAN_MODE_CHANGED:
- mScanMode = intent
- .getIntExtra(BluetoothAdapter.EXTRA_SCAN_MODE,
- BluetoothAdapter.SCAN_MODE_NONE);
+ case Intent.ACTION_USER_UNLOCKED:
if (DBG) {
- Slogf.d(TAG, "NewScanMode = %d", mScanMode);
+ Slogf.d(TAG, "User unlocked");
}
+ mFastPairAccountKeyStorage.load();
+ break;
+
+ // TODO (243171615): Reassess advertising transitions against specification
+ case BluetoothAdapter.ACTION_SCAN_MODE_CHANGED:
+ int newScanMode = intent.getIntExtra(BluetoothAdapter.EXTRA_SCAN_MODE,
+ BluetoothAdapter.ERROR);
+ boolean isDiscovering = mBluetoothAdapter.isDiscovering();
+ boolean isFastPairing = mFastPairGattServer.isConnected();
+ if (DBG) {
+ Slogf.d(TAG, "Scan mode changed, old=%s, new=%s, discovering=%b,"
+ + " fastpairing=%b", BluetoothUtils.getScanModeName(mScanMode),
+ BluetoothUtils.getScanModeName(newScanMode), isDiscovering,
+ isFastPairing);
+ }
+ mScanMode = newScanMode;
if (mScanMode == BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE) {
- if (mBluetoothAdapter.isDiscovering()) {
+ // While the specification says we should always be advertising *something*
+ // it turns out the other applications implement other Fast Pair based
+ // features that also want to advertise (Smart Setup, for example, which is
+ // another Fast Pair based feature outside of BT Pairing facilitation).
+ // Seeker devices can only handle one 0xFE2C advertisement at a time. To
+ // reduce the chance of clashing, we only advertise our Model ID when we're
+ // sure we have the intent to pair. Otherwise, if we're in the discoverable
+ // state without intent to pair, then it may be another application. We stop
+ // advertising all together.
+ if (isDiscovering) {
advertiseModelId();
} else {
stopAdvertising();
}
- } else if (mScanMode == BluetoothAdapter.SCAN_MODE_CONNECTABLE
- && mFastPairGattServer != null
- && !mFastPairGattServer.isConnected()) {
- // The adapter is no longer discoverable, and the Fast Pair session is
- // complete
+ } else if (mBluetoothAdapter.getState() == BluetoothAdapter.STATE_ON) {
advertiseAccountKeys();
}
break;
case BluetoothAdapter.ACTION_STATE_CHANGED:
- int state = intent
- .getIntExtra(BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.STATE_OFF);
- if (state != BluetoothAdapter.STATE_ON) {
- if (mFastPairGattServer != null) {
- mFastPairGattServer.stop();
- mFastPairGattServer = null;
- }
+ int newState = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE,
+ BluetoothAdapter.ERROR);
+ int oldState = intent.getIntExtra(BluetoothAdapter.EXTRA_PREVIOUS_STATE,
+ BluetoothAdapter.ERROR);
+ if (DBG) {
+ Slogf.d(TAG, "Adapter state changed, old=%s, new=%s",
+ BluetoothUtils.getAdapterStateName(oldState),
+ BluetoothUtils.getAdapterStateName(newState));
+ }
+ if (newState == BluetoothAdapter.STATE_ON) {
+ startGatt();
+ } else {
+ stopGatt();
}
break;
}
@@ -134,30 +165,51 @@
*/
public FastPairProvider(Context context) {
mContext = context;
- Resources res = mContext.getResources();
+ Resources res = mContext.getResources();
mModelId = res.getInteger(R.integer.fastPairModelId);
mAntiSpoofKey = res.getString(R.string.fastPairAntiSpoofKey);
mAutomaticAcceptance = res.getBoolean(R.bool.fastPairAutomaticAcceptance);
+
mBluetoothAdapter = mContext.getSystemService(BluetoothManager.class).getAdapter();
+ mFastPairAccountKeyStorage = new FastPairAccountKeyStorage(mContext, 5);
+ mFastPairAdvertiser = new FastPairAdvertiser(mContext);
+ mFastPairGattServer = new FastPairGattServer(mContext, mModelId, mAntiSpoofKey,
+ mGattServerCallbacks, mAutomaticAcceptance, mFastPairAccountKeyStorage);
+ }
+
+ /**
+ * Determine if Fast Pair Provider is enabled based on the configuration parameters read in.
+ */
+ boolean isEnabled() {
+ return !(mModelId == 0 || TextUtils.isEmpty(mAntiSpoofKey));
+ }
+
+ /**
+ * Is the Fast Pair Provider Started
+ *
+ * Being started means our advertiser exists and we are listening for events that would signal
+ * for us to create our GATT Server/Service.
+ */
+ boolean isStarted() {
+ return mStarted;
}
/**
* Start the Fast Pair provider which will register for Bluetooth broadcasts.
*/
public void start() {
- if (mModelId == 0) {
- Slogf.w(TAG, "Model ID undefined, disabling");
+ if (mStarted) return;
+ if (!isEnabled()) {
+ Slogf.w(TAG, "Fast Pair Provider not configured, disabling, model=%d, key=%s",
+ mModelId, TextUtils.isEmpty(mAntiSpoofKey) ? "N/A" : "Set");
return;
}
- Slogf.d(TAG, "modelId == %d", mModelId);
- mFastPairAdvertiserHandler = new Handler(
- CarServiceUtils.getHandlerThread(FastPairUtils.THREAD_NAME).getLooper());
IntentFilter filter = new IntentFilter();
+ filter.addAction(Intent.ACTION_USER_UNLOCKED);
filter.addAction(BluetoothAdapter.ACTION_SCAN_MODE_CHANGED);
filter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);
mContext.registerReceiver(mDiscoveryModeChanged, filter);
-
mStarted = true;
}
@@ -165,96 +217,59 @@
* Stop the Fast Pair provider which will unregister the broadcast receiver.
*/
public void stop() {
- if (mStarted) {
- mContext.unregisterReceiver(mDiscoveryModeChanged);
- mStarted = false;
- }
- }
-
- void stopAdvertising() {
- mFastPairAdvertiserHandler.post(new Runnable() {
- @Override
- public void run() {
- if (mFastPairAccountAdvertiser != null) {
- mFastPairAccountAdvertiser.stopAdvertising();
- }
- if (mFastPairModelAdvertiser != null) {
- mFastPairModelAdvertiser.stopAdvertising();
- }
- }
- });
+ if (!mStarted) return;
+ mContext.unregisterReceiver(mDiscoveryModeChanged);
+ mStarted = false;
}
void advertiseModelId() {
- mFastPairAdvertiserHandler.post(new Runnable() {
- @Override
- public void run() {
- if (mFastPairAccountAdvertiser != null) {
- mFastPairAccountAdvertiser.stopAdvertising();
- }
- if (mFastPairModelAdvertiser == null) {
- mFastPairModelAdvertiser = new FastPairAdvertiser(mContext, mModelId,
- mAdvertiserCallbacks);
- }
-
- startGatt();
- mFastPairModelAdvertiser.advertiseModelId();
- }
- });
+ if (DBG) Slogf.i(TAG, "Advertise model ID");
+ mFastPairAdvertiser.stopAdvertising();
+ mFastPairAdvertiser.advertiseModelId(mModelId, mAdvertiserCallbacks);
}
void advertiseAccountKeys() {
- mFastPairAdvertiserHandler.post(new Runnable() {
- @Override
- public void run() {
- if (mFastPairModelAdvertiser != null) {
- mFastPairModelAdvertiser.stopAdvertising();
- }
- if (mFastPairAccountAdvertiser == null) {
- mFastPairAccountAdvertiser = new FastPairAdvertiser(mContext, mModelId,
- mAdvertiserCallbacks);
- }
+ if (DBG) Slogf.i(TAG, "Advertise account key filter");
+ mFastPairAdvertiser.stopAdvertising();
+ mFastPairAdvertiser.advertiseAccountKeys(mFastPairAccountKeyStorage.getAllAccountKeys(),
+ mAdvertiserCallbacks);
+ }
- startGatt();
- mFastPairAccountAdvertiser.advertiseAccountKeys();
- }
- });
+ void stopAdvertising() {
+ if (DBG) Slogf.i(TAG, "Stop all advertising");
+ mFastPairAdvertiser.stopAdvertising();
}
void startGatt() {
- if (mFastPairGattServer == null) {
- mFastPairGattServer = new FastPairGattServer(mContext, mModelId,
- mAntiSpoofKey,
- mGattServerCallbacks,
- mAutomaticAcceptance);
- mFastPairGattServer.start();
- }
+ if (DBG) Slogf.i(TAG, "Start Fast Pair GATT server");
+ mFastPairGattServer.start();
+ }
+
+ void stopGatt() {
+ if (DBG) Slogf.i(TAG, "Stop Fast Pair GATT server");
+ mFastPairGattServer.stop();
}
/**
* Dump current status of the Fast Pair provider
*
+ * This will get printed with the output of:
+ * adb shell dumpsys activity service com.android.car/.PerUserCarService
+ *
* @param writer
*/
@ExcludeFromCodeCoverageGeneratedReport(reason = DUMP_INFO)
public void dump(IndentingPrintWriter writer) {
- writer.println(TAG + " services");
- if (mModelId == 0) {
- writer.increaseIndent();
- writer.println("Service Disabled");
- writer.decreaseIndent();
- return;
- }
+ writer.println("FastPairProvider:");
writer.increaseIndent();
- writer.println("Model ID : " + mModelId);
- if (mFastPairModelAdvertiser != null) {
- mFastPairModelAdvertiser.dump(writer);
- }
- if (mFastPairAccountAdvertiser != null) {
- mFastPairAccountAdvertiser.dump(writer);
- }
- if (mFastPairGattServer != null) {
+ writer.println("Status : " + (isEnabled() ? "Enabled" : "Disabled"));
+ writer.println("Model ID : " + mModelId);
+ writer.println("Anti-Spoof Key : " + (TextUtils.isEmpty(mAntiSpoofKey) ? "N/A" : "Set"));
+ writer.println("State : " + (isEnabled() ? "Started" : "Stopped"));
+ if (isEnabled()) {
+ mFastPairAdvertiser.dump(writer);
mFastPairGattServer.dump(writer);
+ mFastPairAccountKeyStorage.dump(writer);
}
writer.decreaseIndent();
}
diff --git a/service/src/com/android/car/bluetooth/FastPairUtils.java b/service/src/com/android/car/bluetooth/FastPairUtils.java
deleted file mode 100644
index b9c3fb5..0000000
--- a/service/src/com/android/car/bluetooth/FastPairUtils.java
+++ /dev/null
@@ -1,162 +0,0 @@
-/*
- * Copyright (C) 2021 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.bluetooth;
-
-import android.car.builtin.util.Slogf;
-import android.content.Context;
-import android.content.SharedPreferences;
-import android.util.Log;
-
-import java.math.BigInteger;
-import java.nio.ByteBuffer;
-import java.security.MessageDigest;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-import java.util.Random;
-
-import javax.crypto.spec.SecretKeySpec;
-
-class FastPairUtils {
- static final String TAG = FastPairUtils.class.getSimpleName();
- static final boolean DBG = Slogf.isLoggable("FastPair", Log.DEBUG);
- static final String PREFERENCES = "com.android.car.bluetooth";
- static final String ACCOUNT_KEYS = "AccountKeysCount";
- static final String THREAD_NAME = "FastPairProvider";
-
- private static final byte SALT_FIELD_DESCRIPTOR = 0x11;
- private static final int BD_ADDR_LEN = 6;
- private static final int BD_UUID_LEN = 16;
-
- //construct the advertisement based on stored account keys
- static byte[] getAccountKeyAdvertisement(Context context) {
- byte[] salt = new byte[1];
- List<FastPairUtils.AccountKey> keys = new ArrayList<>();
- new Random().nextBytes(salt);
- keys = readStoredAccountKeys(context);
-
- //calculate bloom results
- byte[] bloomResults = bloom(keys, salt[0]);
- int size = bloomResults.length;
-
- //assemble advertisement
- ByteBuffer accountKeyAdvertisement = ByteBuffer.allocate(size + 4);
- accountKeyAdvertisement.put((byte) 0); //reserved Flags byte
- accountKeyAdvertisement.put((byte) (size << 4));
- accountKeyAdvertisement.put(bloomResults);
- accountKeyAdvertisement.put(SALT_FIELD_DESCRIPTOR);
- accountKeyAdvertisement.put(salt);
-
- return accountKeyAdvertisement.array();
- }
-
- //given a list of account keys and a salt, calculate the bloom results
- static byte[] bloom(List<AccountKey> keys, byte salt) {
- int size = (int) 1.2 * keys.size() + 3;
- byte[] filter = new byte[size];
-
- for (AccountKey key : keys) {
- byte[] v = Arrays.copyOf(key.key, 17);
- v[16] = salt;
- try {
- byte[] hashed = MessageDigest.getInstance("SHA-256").digest(v);
- ByteBuffer byteBuffer = ByteBuffer.wrap(hashed);
- for (int j = 0; j < 8; j++) {
- long k = Integer.toUnsignedLong(byteBuffer.getInt()) % (size * 8);
- filter[(int) (k / 8)] |= 1 << (k % 8);
- }
- } catch (Exception e) {
- Slogf.e(TAG, "error calculating bloom: %s", e);
- }
- }
- return filter;
- }
-
- static List<AccountKey> readStoredAccountKeys(Context context) {
- List<AccountKey> keys = new ArrayList<>();
- SharedPreferences sharedPref = context.getSharedPreferences(PREFERENCES,
- Context.MODE_PRIVATE);
- int accountKeyCount = sharedPref.getInt(ACCOUNT_KEYS, 0);
-
- for (int i = 1; i <= accountKeyCount; i++) {
- String readAccountKey = sharedPref.getString("" + i, null);
- if (readAccountKey != null) {
- keys.add(new FastPairUtils.AccountKey(readAccountKey));
- } else {
- Slogf.w(TAG, "Read account key == %s", readAccountKey);
- }
- }
-
- Slogf.d(TAG, "Read %d/%d keys.", keys.size(), accountKeyCount);
- return keys;
- }
-
- static void writeStoredAccountKeys(Context context, List<AccountKey> keys) {
- SharedPreferences sharedPref = context
- .getSharedPreferences(PREFERENCES, Context.MODE_PRIVATE);
- int accountKeyCount = keys.size();
- SharedPreferences.Editor editor = sharedPref.edit();
- for (int i = 0; i < accountKeyCount; i++) {
- editor.putString("" + accountKeyCount,
- new BigInteger(keys.get(i).toBytes()).toString());
- }
- editor.putInt(ACCOUNT_KEYS, accountKeyCount);
- editor.apply();
- }
-
- static byte[] getBytesFromAddress(String address) {
- int i, j = 0;
- byte[] output = new byte[BD_ADDR_LEN];
-
- for (i = 0; i < address.length(); i++) {
- if (address.charAt(i) != ':') {
- output[j] = (byte) Integer.parseInt(address.substring(i, i + 2), BD_UUID_LEN);
- j++;
- i++;
- }
- }
- return output;
- }
-
- static class AccountKey {
-
- public final byte[] key;
-
- AccountKey(byte[] newKey) {
- key = newKey;
- }
-
- AccountKey(String newKey) {
- key = new BigInteger(newKey).toByteArray();
- }
-
- public byte[] toBytes() {
- return key;
- }
-
- public SecretKeySpec getKeySpec() {
- return new SecretKeySpec(key, "AES");
- }
-
- @Override
- public boolean equals(Object obj) {
- if (!(obj instanceof AccountKey)) {
- return false;
- }
- return Arrays.equals(key, ((AccountKey) obj).key);
- }
- }
-}
diff --git a/service/src/com/android/car/evs/CarEvsService.java b/service/src/com/android/car/evs/CarEvsService.java
index 00802ae..c1026dd 100644
--- a/service/src/com/android/car/evs/CarEvsService.java
+++ b/service/src/com/android/car/evs/CarEvsService.java
@@ -847,6 +847,11 @@
Slogf.d(TAG_EVS, "Initializing the service");
}
+ if (!mHalWrapper.init()) {
+ Slogf.e(TAG_EVS, "Failed to initialize a service handle");
+ return;
+ }
+
if (mEvsHalService.isEvsServiceRequestSupported()) {
try {
mEvsHalService.setListener(this);
@@ -878,18 +883,6 @@
mGearSelectionPropertyListener);
}
- if (!mHalWrapper.init()) {
- Slogf.e(TAG_EVS, "Failed to initialize a service handle");
- if (mUseGearSelection && mPropertyService != null) {
- if (DBG) {
- Slogf.d(TAG_EVS, "Unregister a property listener on init() failure.");
- }
- mPropertyService.unregisterListener(VehicleProperty.GEAR_SELECTION,
- mGearSelectionPropertyListener);
- }
- return;
- }
-
// Attempts to transit to the INACTIVE state
connectToHalServiceIfNecessary(EVS_HAL_SERVICE_BIND_RETRY_INTERVAL_MS);
}
@@ -991,7 +984,7 @@
public void stopActivity() {
CarServiceUtils.assertPermission(mContext, Car.PERMISSION_REQUEST_CAR_EVS_ACTIVITY);
- mStateEngine.execute(REQUEST_PRIORITY_NORMAL, SERVICE_STATE_INACTIVE);
+ mStateEngine.execute(REQUEST_PRIORITY_NORMAL, SERVICE_STATE_INACTIVE, mStreamCallback);
}
/**
@@ -1294,10 +1287,18 @@
return;
}
+
+ boolean isReverseGear = (Integer) value.getValue() == VehicleGear.GEAR_REVERSE;
+ mLastEvsHalEvent = new EvsHalEvent(timestamp, CarEvsManager.SERVICE_TYPE_REARVIEW,
+ isReverseGear);
+
+ if (mStateEngine.getState() == SERVICE_STATE_UNAVAILABLE) {
+ return;
+ }
+
// TODO(b/179029031): CarEvsService may need to process VehicleGear.GEAR_PARK when
// Surround View service is integrated.
- int gear = (Integer) value.getValue();
- if (gear == VehicleGear.GEAR_REVERSE) {
+ if (isReverseGear) {
// Request to start the rearview activity when the gear is shifted into the reverse
// position.
if (mStateEngine.execute(REQUEST_PRIORITY_HIGH, SERVICE_STATE_REQUESTED,
@@ -1313,9 +1314,6 @@
Slogf.d(TAG_EVS, "Failed to stop the rearview activity.");
}
}
-
- mLastEvsHalEvent = new EvsHalEvent(timestamp, CarEvsManager.SERVICE_TYPE_REARVIEW,
- gear == VehicleGear.GEAR_REVERSE);
}
/** Processes a streaming event and propagates it to registered clients */
@@ -1370,10 +1368,14 @@
/** EVS frame handler called after a native handler */
@Override
public void onFrameEvent(int id, HardwareBuffer buffer) {
- if (!processNewFrame(id, buffer)) {
- // No client uses this buffer.
- Slogf.d(TAG_EVS, "Returns buffer " + id + " because no client uses it.");
- mHalWrapper.doneWithFrame(id);
+ try {
+ if (!processNewFrame(id, buffer)) {
+ // No client uses this buffer.
+ Slogf.d(TAG_EVS, "Returns buffer " + id + " because no client uses it.");
+ mHalWrapper.doneWithFrame(id);
+ }
+ } finally {
+ buffer.close();
}
}
diff --git a/service/src/com/android/car/hal/PropertyHalServiceIds.java b/service/src/com/android/car/hal/PropertyHalServiceIds.java
index 809cb9d..fa0183f 100644
--- a/service/src/com/android/car/hal/PropertyHalServiceIds.java
+++ b/service/src/com/android/car/hal/PropertyHalServiceIds.java
@@ -112,6 +112,18 @@
private static final Set<Integer> TRAILER_PRESENT =
new HashSet<>(getIntegersFromDataEnums(TrailerState.class));
+ // This is the property ID for GENERAL_SAFETY_REGULATION_COMPLIANCE added in
+ // API version 34. We cannot change API for this version now, so we have to hard code the
+ // property ID here.
+ //
+ // Client wishing to use this property must use property ID: 289410887 (0x11400F47) for
+ // {@link CarPropertyManager}. The property is defined as read-only static global system
+ // property with one int value from the following enums:
+ // <ul>
+ // <li> 0: GSR_COMPLIANCE_NOT_REQUIRED
+ // <li> 1: GSR_COMPLIANCE_REQUIRED_V1
+ private static final int PROP_GENERAL_SAFETY_REGULATION_COMPLIANCE = 0x11400F47;
+
// default vendor permission
private static final int PERMISSION_CAR_VENDOR_DEFAULT = 0x00000000;
@@ -598,6 +610,9 @@
Car.PERMISSION_PRIVILEGED_CAR_INFO, null));
mProps.put(VehicleProperty.TRAILER_PRESENT, new Pair<>(
Car.PERMISSION_PRIVILEGED_CAR_INFO, null));
+
+ mProps.put(PROP_GENERAL_SAFETY_REGULATION_COMPLIANCE,
+ new Pair<>(Car.PERMISSION_CAR_INFO, null));
// mPropToValidValue should contain all properties which has @data_enum in types.hal
mPropToValidValue.put(VehicleProperty.INFO_FUEL_TYPE, FUEL_TYPE);
mPropToValidValue.put(VehicleProperty.INFO_EV_CONNECTOR_TYPE, EV_CONNECTOR_TYPE);
diff --git a/service/src/com/android/car/hal/TimeHalService.java b/service/src/com/android/car/hal/TimeHalService.java
index b5c51c3..cef7eaa 100644
--- a/service/src/com/android/car/hal/TimeHalService.java
+++ b/service/src/com/android/car/hal/TimeHalService.java
@@ -118,6 +118,9 @@
if (mExternalCarTimeSupported) {
HalPropValue propValue = mHal.get(EXTERNAL_CAR_TIME);
suggestExternalTimeLocked(propValue);
+
+ mHal.subscribeProperty(this, EXTERNAL_CAR_TIME);
+ Slogf.d(CarLog.TAG_TIME, "Subscribed to VHAL property EXTERNAL_CAR_TIME.");
}
}
}
diff --git a/service/src/com/android/car/hal/VehicleHal.java b/service/src/com/android/car/hal/VehicleHal.java
index b2c7a9c..63bd043 100644
--- a/service/src/com/android/car/hal/VehicleHal.java
+++ b/service/src/com/android/car/hal/VehicleHal.java
@@ -46,6 +46,7 @@
import com.android.car.CarServiceUtils;
import com.android.car.VehicleStub;
import com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport;
+import com.android.car.internal.util.IndentingPrintWriter;
import com.android.car.internal.util.Lists;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
@@ -656,6 +657,25 @@
return true;
}
+ /**
+ * Sets a property passed from the shell command.
+ *
+ * @param property Property ID in hex or decimal.
+ * @param areaId Area ID
+ * @param data Comma-separated value.
+ */
+ public void setPropertyFromCommand(int property, int areaId, String data,
+ IndentingPrintWriter writer) throws IllegalArgumentException, ServiceSpecificException {
+ long timestamp = SystemClock.elapsedRealtimeNanos();
+ HalPropValue v = createPropValueForInjecting(mPropValueBuilder, property, areaId,
+ List.of(data.split(DATA_DELIMITER)), timestamp);
+ if (v == null) {
+ throw new IllegalArgumentException("Unsupported property type: property=" + property
+ + ", areaId=" + areaId);
+ }
+ set(v);
+ }
+
private final ArraySet<HalServiceBase> mServicesToDispatch = new ArraySet<>();
// should be posted to the mHandlerThread
@@ -998,6 +1018,14 @@
boolean boolValue = Boolean.parseBoolean(dataList.get(0));
return builder.build(propId, zoneId, timestamp, VehiclePropertyStatus.AVAILABLE,
boolValue ? 1 : 0);
+ case VehiclePropertyType.INT64:
+ case VehiclePropertyType.INT64_VEC:
+ long[] longValues = new long[dataList.size()];
+ for (int i = 0; i < dataList.size(); i++) {
+ longValues[i] = Long.decode(dataList.get(i));
+ }
+ return builder.build(propId, zoneId, timestamp, VehiclePropertyStatus.AVAILABLE,
+ longValues);
case VehiclePropertyType.INT32:
case VehiclePropertyType.INT32_VEC:
int[] intValues = new int[dataList.size()];
diff --git a/service/src/com/android/car/os/CarPerformanceService.java b/service/src/com/android/car/os/CarPerformanceService.java
index 3e870b5..46a686c 100644
--- a/service/src/com/android/car/os/CarPerformanceService.java
+++ b/service/src/com/android/car/os/CarPerformanceService.java
@@ -16,31 +16,55 @@
package com.android.car.os;
-import static com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport.DUMP_INFO;
+import static android.car.PlatformVersion.VERSION_CODES;
+import static android.car.os.CpuAvailabilityMonitoringConfig.CPUSET_ALL;
+import static android.car.os.CpuAvailabilityMonitoringConfig.CPUSET_BACKGROUND;
+import static android.car.os.CpuAvailabilityMonitoringConfig.IGNORE_PERCENT_LOWER_BOUND;
+import static android.car.os.CpuAvailabilityMonitoringConfig.IGNORE_PERCENT_UPPER_BOUND;
+import static android.car.os.CpuAvailabilityMonitoringConfig.TIMEOUT_ACTION_NOTIFICATION;
+import static android.car.os.CpuAvailabilityMonitoringConfig.TIMEOUT_ACTION_REMOVE;
+import static com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport.DUMP_INFO;
+import static com.android.car.internal.util.VersionUtils.assertPlatformVersionAtLeast;
+
+import android.annotation.NonNull;
import android.car.Car;
+import android.car.builtin.os.BinderHelper;
import android.car.builtin.util.Slogf;
import android.car.os.CpuAvailabilityMonitoringConfig;
import android.car.os.ICarPerformanceService;
import android.car.os.ICpuAvailabilityChangeListener;
+import android.car.os.ThreadPolicyWithPriority;
import android.content.Context;
+import android.os.Binder;
+import android.os.RemoteCallbackList;
+import android.os.RemoteException;
import android.util.Log;
+import com.android.car.CarLocalServices;
import com.android.car.CarLog;
import com.android.car.CarServiceBase;
import com.android.car.CarServiceUtils;
import com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport;
import com.android.car.internal.util.IndentingPrintWriter;
+import com.android.car.watchdog.CarWatchdogService;
+import com.android.internal.util.Preconditions;
+
+import java.util.Objects;
/**
* Service to implement CarPerformanceManager API.
*/
public final class CarPerformanceService extends ICarPerformanceService.Stub
implements CarServiceBase {
- private static final String TAG = CarLog.tagFor(CarPerformanceService.class);
+ static final String TAG = CarLog.tagFor(CarPerformanceService.class);
+
private static final boolean DEBUG = Slogf.isLoggable(TAG, Log.DEBUG);
+ private CarWatchdogService mCarWatchdogService;
private final Context mContext;
+ private final RemoteCallbackList<ICpuAvailabilityChangeListener>
+ mCpuAvailabilityChangeListeners = new RemoteCallbackList<>();
public CarPerformanceService(Context context) {
mContext = context;
@@ -48,9 +72,8 @@
@Override
public void init() {
- // TODO(b/156400843): Connect to the watchdog daemon helper instance for the thread priority
- // API. CarPerformanceService and CarWatchdogService must use the same watchdog daemon
- // helper instance.
+ mCarWatchdogService = CarLocalServices.getService(CarWatchdogService.class);
+ // TODO(b/217422127): Start performance monitoring on a looper handler.
if (DEBUG) {
Slogf.d(TAG, "CarPerformanceService is initialized");
}
@@ -59,6 +82,7 @@
@Override
public void release() {
// TODO(b/156400843): Disconnect from the watchdog daemon helper instance.
+ mCpuAvailabilityChangeListeners.kill();
}
@Override
@@ -66,7 +90,10 @@
public void dump(IndentingPrintWriter writer) {
writer.printf("*%s*\n", getClass().getSimpleName());
writer.increaseIndent();
- // TODO(b/217422127): Dump CPU availability info.
+ writer.println("CPU availability change listeners:");
+ writer.increaseIndent();
+ BinderHelper.dumpRemoteCallbackList(mCpuAvailabilityChangeListeners, writer);
+ writer.decreaseIndent();
writer.decreaseIndent();
}
@@ -75,11 +102,25 @@
* change notifications.
*/
@Override
- public void addCpuAvailabilityChangeListener(CpuAvailabilityMonitoringConfig config,
- ICpuAvailabilityChangeListener listener) {
+ public void addCpuAvailabilityChangeListener(@NonNull CpuAvailabilityMonitoringConfig config,
+ @NonNull ICpuAvailabilityChangeListener listener) {
CarServiceUtils.assertPermission(mContext, Car.PERMISSION_COLLECT_CAR_CPU_INFO);
- // TODO(b/217422127): Implement this.
- throw new UnsupportedOperationException("Not yet implemented");
+ Objects.requireNonNull(config, "Configuration must be non-null");
+ Objects.requireNonNull(listener, "Listener must be non-null");
+ verifyCpuAvailabilityMonitoringConfig(config);
+
+ int callingPid = Binder.getCallingPid();
+ int callingUid = Binder.getCallingUid();
+ CpuAvailabilityChangeListenerInfo listenerInfo =
+ new CpuAvailabilityChangeListenerInfo(config, callingPid, callingUid);
+ if (!mCpuAvailabilityChangeListeners.register(listener, listenerInfo)) {
+ Slogf.w(TAG,
+ "Failed to add CPU availability change listener %s as it is already registered",
+ listenerInfo);
+ throw new IllegalStateException(
+ "Failed to add CPU availability change listener as it is already registered"
+ + listenerInfo);
+ }
}
/**
@@ -88,7 +129,107 @@
@Override
public void removeCpuAvailabilityChangeListener(ICpuAvailabilityChangeListener listener) {
CarServiceUtils.assertPermission(mContext, Car.PERMISSION_COLLECT_CAR_CPU_INFO);
- // TODO(b/217422127): Implement this.
- throw new UnsupportedOperationException("Not yet implemented");
+ Objects.requireNonNull(listener, "Listener must be non-null");
+
+ // Note: RemoteCallbackList already handles removing the listener on binderDeath. However,
+ // when any internal state needs to be cleared for a listener beyond just unregistering
+ // the listener, override RemoteCallbackList.onCallbackDied methods to clean up the internal
+ // state on binder death and on removeCpuAvailabilityChangeListener.
+ mCpuAvailabilityChangeListeners.unregister(listener);
+ }
+
+ /**
+ * Sets the thread priority for a specific thread.
+ *
+ * The thread must belong to the calling process.
+ *
+ * @throws IllegalArgumentException If the given policy/priority is not valid.
+ * @throws IllegalStateException If the provided tid does not belong to the calling process.
+ * @throws RemoteException If binder error happens.
+ * @throws SecurityException If permission check failed.
+ * @throws ServiceSpecificException If the operation failed.
+ * @throws UnsupportedOperationException If the current android release doesn't support the API.
+ */
+ @Override
+ public void setThreadPriority(int tid, ThreadPolicyWithPriority threadPolicyWithPriority)
+ throws RemoteException {
+ assertPlatformVersionAtLeast(VERSION_CODES.TIRAMISU_1);
+ CarServiceUtils.assertPermission(mContext, Car.PERMISSION_MANAGE_THREAD_PRIORITY);
+
+ int pid = Binder.getCallingPid();
+ int uid = Binder.getCallingUid();
+ mCarWatchdogService.setThreadPriority(pid, tid, uid, threadPolicyWithPriority.getPolicy(),
+ threadPolicyWithPriority.getPriority());
+ }
+
+ /**
+ * Gets the thread scheduling policy and priority for the specified thread.
+ *
+ * The thread must belong to the calling process.
+ *
+ * @throws IllegalStateException If the operation failed or the provided tid does not belong to
+ * the calling process.
+ * @throws RemoteException If binder error happens.
+ * @throws SecurityException If permission check failed.
+ * @throws UnsupportedOperationException If the current android release doesn't support the API.
+ */
+ @Override
+ public ThreadPolicyWithPriority getThreadPriority(int tid) throws RemoteException {
+ assertPlatformVersionAtLeast(VERSION_CODES.TIRAMISU_1);
+ CarServiceUtils.assertPermission(mContext, Car.PERMISSION_MANAGE_THREAD_PRIORITY);
+
+ int pid = Binder.getCallingPid();
+ int uid = Binder.getCallingUid();
+ try {
+ int[] result = mCarWatchdogService.getThreadPriority(pid, tid, uid);
+ return new ThreadPolicyWithPriority(result[0], result[1]);
+ } catch (IllegalArgumentException e) {
+ throw new IllegalStateException(
+ "current scheduling policy doesn't support getting priority, error: ", e);
+ }
+ }
+
+ private void verifyCpuAvailabilityMonitoringConfig(CpuAvailabilityMonitoringConfig config) {
+ int lowerBoundPercent = config.getLowerBoundPercent();
+ int upperBoundPercent = config.getUpperBoundPercent();
+
+ Preconditions.checkArgument(lowerBoundPercent != IGNORE_PERCENT_LOWER_BOUND
+ || upperBoundPercent == IGNORE_PERCENT_UPPER_BOUND,
+ "Cannot ignore both lower bound percent(%d) and upper bound percent(%d) values",
+ lowerBoundPercent, upperBoundPercent);
+
+ Preconditions.checkArgument(lowerBoundPercent > 0 && upperBoundPercent < 100
+ && lowerBoundPercent < upperBoundPercent,
+ "Must provide valid lower bound percent(%d) and upper bound percent(%d) values",
+ lowerBoundPercent, upperBoundPercent);
+
+ int cpuset = config.getCpuset();
+ Preconditions.checkArgumentInRange(cpuset, CPUSET_ALL, CPUSET_BACKGROUND, "cpuset");
+
+ int timeoutAction = config.getTimeoutAction();
+ Preconditions.checkArgumentInRange(timeoutAction, TIMEOUT_ACTION_NOTIFICATION,
+ TIMEOUT_ACTION_REMOVE, "timeout action");
+ }
+
+ private static final class CpuAvailabilityChangeListenerInfo {
+ public final CpuAvailabilityMonitoringConfig config;
+ public final int pid;
+ public final int uid;
+
+ CpuAvailabilityChangeListenerInfo(@NonNull CpuAvailabilityMonitoringConfig config, int pid,
+ int uid) {
+ this.config = config;
+ this.pid = pid;
+ this.uid = uid;
+ }
+
+ @Override
+ public String toString() {
+ return new StringBuilder("CpuAvailabilityChangeListenerInfo{ ")
+ .append(", config = ").append(config)
+ .append(", pid = ").append(pid)
+ .append(", uid = ").append(uid)
+ .append(" }").toString();
+ }
}
}
diff --git a/service/src/com/android/car/os/CpuInfoReader.java b/service/src/com/android/car/os/CpuInfoReader.java
new file mode 100644
index 0000000..70fba87
--- /dev/null
+++ b/service/src/com/android/car/os/CpuInfoReader.java
@@ -0,0 +1,605 @@
+/*
+ * Copyright (C) 2022 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.os;
+
+import static com.android.car.os.CarPerformanceService.TAG;
+
+import android.annotation.IntDef;
+import android.annotation.Nullable;
+import android.car.builtin.util.Slogf;
+import android.system.Os;
+import android.system.OsConstants;
+import android.util.ArrayMap;
+import android.util.SparseArray;
+import android.util.SparseIntArray;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.io.File;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.nio.file.Files;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Objects;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/** Reader to read CPU information from proc and sys fs files exposed by the Kernel. */
+public final class CpuInfoReader {
+ static final int FLAG_CPUSET_CATEGORY_TOP_APP = 1 << 0;
+ static final int FLAG_CPUSET_CATEGORY_BACKGROUND = 1 << 1;
+
+ private static final String CPUFREQ_DIR_PATH = "/sys/devices/system/cpu/cpufreq";
+ private static final String POLICY_DIR_PREFIX = "policy";
+ private static final String RELATED_CPUS_FILE = "related_cpus";
+ private static final String AFFECTED_CPUS_FILE = "affected_cpus";
+ private static final String CUR_CPUFREQ_FILE = "cpuinfo_cur_freq";
+ private static final String MAX_CPUFREQ_FILE = "cpuinfo_max_freq";
+ private static final String CUR_SCALING_FREQ_FILE = "scaling_cur_freq";
+ private static final String MAX_SCALING_FREQ_FILE = "scaling_max_freq";
+ private static final String TIME_IN_STATE_FILE = "stats/time_in_state";
+ private static final String CPUSET_DIR_PATH = "/dev/cpuset";
+ private static final String CPUSET_TOP_APP_DIR = "top-app";
+ private static final String CPUSET_BACKGROUND_DIR = "background";
+ private static final String CPUS_FILE = "cpus";
+ private static final String PROC_STAT_FILE_PATH = "/proc/stat";
+ private static final Pattern PROC_STAT_PATTERN =
+ Pattern.compile("cpu(?<core>[0-9]+)\\s(?<userClockTicks>[0-9]+)\\s"
+ + "(?<niceClockTicks>[0-9]+)\\s(?<sysClockTicks>[0-9]+)\\s"
+ + "(?<idleClockTicks>[0-9]+)\\s(?<iowaitClockTicks>[0-9]+)\\s"
+ + "(?<irqClockTicks>[0-9]+)\\s(?<softirqClockTicks>[0-9]+)\\s"
+ + "(?<stealClockTicks>[0-9]+)\\s(?<guestClockTicks>[0-9]+)\\s"
+ + "(?<guestNiceClockTicks>[0-9]+)");
+ private static final Pattern TIME_IN_STATE_PATTERN =
+ Pattern.compile("(?<freqKHz>[0-9]+)\\s(?<time>[0-9]+)");
+ private static final long MILLIS_PER_JIFFY = 1000L / Os.sysconf(OsConstants._SC_CLK_TCK);
+
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(prefix = {"FLAG_CPUSET_CATEGORY_"}, flag = true, value = {
+ FLAG_CPUSET_CATEGORY_TOP_APP,
+ FLAG_CPUSET_CATEGORY_BACKGROUND
+ })
+ private @interface CpusetCategory{}
+
+ private final File mCpusetDir;
+ private final SparseIntArray mCpusetCategoriesByCpus = new SparseIntArray();
+ private final SparseArray<Long> mMaxCpuFrequenciesByCpus = new SparseArray<>();
+ private final ArrayMap<String, ArrayMap<Long, Long>> mTimeInStateByPolicy = new ArrayMap<>();
+
+ private File mCpuFreqDir;
+ private File mProcStatFile;
+ private File[] mCpuFreqPolicyDirs;
+ private SparseArray<CpuUsageStats> mCumulativeCpuUsageStats = new SparseArray<>();
+ private boolean mIsEnabled;
+ private boolean mHasTimeInStateFile;
+
+ public CpuInfoReader() {
+ this(new File(CPUSET_DIR_PATH), new File(CPUFREQ_DIR_PATH), new File(PROC_STAT_FILE_PATH));
+ }
+
+ @VisibleForTesting
+ CpuInfoReader(File cpusetDir, File cpuFreqDir, File procStatFile) {
+ mCpusetDir = cpusetDir;
+ mCpuFreqDir = cpuFreqDir;
+ mProcStatFile = procStatFile;
+ }
+
+ /** Inits CpuInfoReader and returns a boolean to indicate whether the reader is enabled. */
+ public boolean init() {
+ mCpuFreqPolicyDirs = mCpuFreqDir.listFiles(
+ file -> file.isDirectory() && file.getName().startsWith(POLICY_DIR_PREFIX));
+ if (mCpuFreqPolicyDirs == null || mCpuFreqPolicyDirs.length == 0) {
+ Slogf.w(TAG, "Missing CPU frequency policy directories at %s",
+ mCpuFreqDir.getAbsolutePath());
+ return false;
+ }
+ if (!mProcStatFile.exists()) {
+ Slogf.e(TAG, "Missing proc stat file at %s", mProcStatFile.getAbsolutePath());
+ return false;
+ }
+ readCpusetCategories();
+ if (mCpusetCategoriesByCpus.size() == 0) {
+ Slogf.e(TAG, "Failed to read cpuset information read from %s",
+ mCpusetDir.getAbsolutePath());
+ return false;
+ }
+ readMaxCpuFrequencies();
+ if (mMaxCpuFrequenciesByCpus.size() == 0) {
+ Slogf.e(TAG, "Failed to read max CPU frequencies from policy directories at %s",
+ mCpuFreqDir.getAbsolutePath());
+ return false;
+ }
+ // The Kernel must be configured to generate the `time_in_state` file. If the Kernel is not
+ // configured to generate this file, this file won't be available for the entire system
+ // uptime. Thus, check for the presence of this file only during init.
+ mHasTimeInStateFile = new File(mCpuFreqPolicyDirs[0], TIME_IN_STATE_FILE).exists();
+ mIsEnabled = true;
+ return true;
+ }
+
+ /** Reads CPU information from proc and sys fs files exposed by the Kernel. */
+ public List<CpuInfo> readCpuInfos() {
+ if (!mIsEnabled) {
+ return Collections.emptyList();
+ }
+ SparseArray<CpuUsageStats> latestCpuUsageStats = readLatestCpuUsageStats();
+ if (latestCpuUsageStats == null) {
+ Slogf.e(TAG, "Failed to read latest CPU usage stats");
+ return Collections.emptyList();
+ }
+ SparseArray<Long> cpuFrequenciesByCpus = readCurrentCpuFrequencies();
+ List<CpuInfo> cpuInfos = new ArrayList<>();
+ for (int i = 0; i < cpuFrequenciesByCpus.size(); i++) {
+ int cpu = cpuFrequenciesByCpus.keyAt(i);
+ long curFrequency = cpuFrequenciesByCpus.valueAt(i);
+ if (!mMaxCpuFrequenciesByCpus.contains(cpu) || !latestCpuUsageStats.contains(cpu)) {
+ Slogf.w(TAG, "Missing max CPU frequency or CPU usage stats for CPU core %d", cpu);
+ continue;
+ }
+ int cpuCategories = mCpusetCategoriesByCpus.get(cpu, -1);
+ if (cpuCategories == -1) {
+ Slogf.w(TAG, "Missing cpuset information for CPU core %d", cpu);
+ continue;
+ }
+ cpuInfos.add(new CpuInfo(cpu, cpuCategories, curFrequency,
+ mMaxCpuFrequenciesByCpus.get(cpu), latestCpuUsageStats.get(cpu)));
+ }
+ return cpuInfos;
+ }
+
+ @VisibleForTesting
+ void setCpuFreqDir(File cpuFreqDir) {
+ File[] cpuFreqPolicyDirs = cpuFreqDir.listFiles(
+ file -> file.isDirectory() && file.getName().startsWith(POLICY_DIR_PREFIX));
+ if (mCpuFreqPolicyDirs == null || mCpuFreqPolicyDirs.length == 0) {
+ Slogf.w(TAG, "Failed to set CPU frequency directory. Missing policy directories at %s",
+ mCpuFreqDir.getAbsolutePath());
+ return;
+ }
+ mCpuFreqDir = cpuFreqDir;
+ mCpuFreqPolicyDirs = cpuFreqPolicyDirs;
+ Slogf.i(TAG, "Set CPU frequency directory to %s", cpuFreqDir.getAbsolutePath());
+ }
+
+ @VisibleForTesting
+ void setProcStatFile(File procStatFile) {
+ mProcStatFile = procStatFile;
+ Slogf.i(TAG, "Set proc stat file to %s", procStatFile.getAbsolutePath());
+ }
+
+ private void readCpusetCategories() {
+ File[] cpusetDirs = mCpusetDir.listFiles(File::isDirectory);
+ if (cpusetDirs == null) {
+ Slogf.e(TAG, "Missing cpuset directories at %s", mCpusetDir.getAbsolutePath());
+ return;
+ }
+ for (int i = 0; i < cpusetDirs.length; i++) {
+ File dir = cpusetDirs[i];
+ @CpusetCategory int cpusetCategory;
+ switch (dir.getName()) {
+ case CPUSET_TOP_APP_DIR:
+ cpusetCategory = FLAG_CPUSET_CATEGORY_TOP_APP;
+ break;
+ case CPUSET_BACKGROUND_DIR:
+ cpusetCategory = FLAG_CPUSET_CATEGORY_BACKGROUND;
+ break;
+ default:
+ continue;
+ }
+ File cpuCoresFile = new File(dir.getPath(), CPUS_FILE);
+ List<Integer> cpuCores = readCpuCores(cpuCoresFile);
+ if (cpuCores.isEmpty()) {
+ Slogf.e(TAG, "Failed to read CPU cores from %s", cpuCoresFile.getAbsolutePath());
+ continue;
+ }
+ for (int j = 0; j < cpuCores.size(); j++) {
+ int categories = mCpusetCategoriesByCpus.get(cpuCores.get(j));
+ categories |= cpusetCategory;
+ mCpusetCategoriesByCpus.append(cpuCores.get(j), categories);
+ }
+ }
+ }
+
+ private void readMaxCpuFrequencies() {
+ for (int i = 0; i < mCpuFreqPolicyDirs.length; i++) {
+ File policyDir = mCpuFreqPolicyDirs[i];
+ long maxCpuFreqKHz = readMaxCpuFrequency(policyDir);
+ if (maxCpuFreqKHz == 0) {
+ Slogf.w(TAG, "Invalid max CPU frequency read from %s", policyDir.getAbsolutePath());
+ continue;
+ }
+ File cpuCoresFile = new File(policyDir, RELATED_CPUS_FILE);
+ List<Integer> cpuCores = readCpuCores(cpuCoresFile);
+ if (cpuCores.isEmpty()) {
+ Slogf.e(TAG, "Failed to read CPU cores from %s", cpuCoresFile.getAbsolutePath());
+ continue;
+ }
+ for (int j = 0; j < cpuCores.size(); j++) {
+ mMaxCpuFrequenciesByCpus.append(cpuCores.get(j), maxCpuFreqKHz);
+ }
+ }
+ }
+
+ private long readMaxCpuFrequency(File policyDir) {
+ long curCpuFreqKHz = readCpuFreqKHz(new File(policyDir, MAX_CPUFREQ_FILE));
+ return curCpuFreqKHz > 0 ? curCpuFreqKHz
+ : readCpuFreqKHz(new File(policyDir, MAX_SCALING_FREQ_FILE));
+ }
+
+ private SparseArray<Long> readCurrentCpuFrequencies() {
+ SparseArray<Long> curCpuFrequenciesByCpus = new SparseArray<>();
+ for (int i = 0; i < mCpuFreqPolicyDirs.length; i++) {
+ File policyDir = mCpuFreqPolicyDirs[i];
+ long curCpuFreqKHz = readCurrentCpuFrequency(policyDir);
+ if (curCpuFreqKHz == 0) {
+ Slogf.w(TAG, "Missing current frequency information at %s",
+ policyDir.getAbsolutePath());
+ continue;
+ }
+ File cpuCoresFile = new File(policyDir, AFFECTED_CPUS_FILE);
+ List<Integer> cpuCores = readCpuCores(cpuCoresFile);
+ if (cpuCores.isEmpty()) {
+ Slogf.e(TAG, "Failed to read CPU cores from %s", cpuCoresFile.getAbsolutePath());
+ continue;
+ }
+ for (int j = 0; j < cpuCores.size(); j++) {
+ curCpuFrequenciesByCpus.append(cpuCores.get(j), curCpuFreqKHz);
+ }
+ }
+ return curCpuFrequenciesByCpus;
+ }
+
+ private long readCurrentCpuFrequency(File policyDir) {
+ ArrayMap<Long, Long> latestTimeInState = readTimeInState(policyDir);
+ if (latestTimeInState == null) {
+ long curCpuFreqKHz = readCpuFreqKHz(new File(policyDir, CUR_CPUFREQ_FILE));
+ return curCpuFreqKHz > 0 ? curCpuFreqKHz :
+ readCpuFreqKHz(new File(policyDir, CUR_SCALING_FREQ_FILE));
+ }
+ String policyDirName = policyDir.getName();
+ if (mTimeInStateByPolicy.containsKey(policyDirName)) {
+ ArrayMap<Long, Long> prevTimeInState = mTimeInStateByPolicy.get(policyDirName);
+ ArrayMap<Long, Long> deltaTimeInState =
+ calculateDeltaTimeInState(prevTimeInState, latestTimeInState);
+ mTimeInStateByPolicy.put(policyDirName, latestTimeInState);
+ return calculateAvgCpuFreq(deltaTimeInState);
+ }
+ mTimeInStateByPolicy.put(policyDirName, latestTimeInState);
+ return calculateAvgCpuFreq(latestTimeInState);
+ }
+
+ @Nullable
+ private ArrayMap<Long, Long> readTimeInState(File policyDir) {
+ if (!mHasTimeInStateFile) {
+ return null;
+ }
+ File timeInStateFile = new File(policyDir, TIME_IN_STATE_FILE);
+ try {
+ List<String> lines = Files.readAllLines(timeInStateFile.toPath());
+ if (lines.isEmpty()) {
+ Slogf.w(TAG, "Empty time in state file at %s", timeInStateFile.getAbsolutePath());
+ return null;
+ }
+ ArrayMap<Long, Long> cpuTimeByFrequencies = new ArrayMap<>();
+ for (int i = 0; i < lines.size(); i++) {
+ Matcher m = TIME_IN_STATE_PATTERN.matcher(lines.get(i).trim());
+ if (!m.find()) {
+ continue;
+ }
+ cpuTimeByFrequencies.put(Long.parseLong(m.group("freqKHz")),
+ jiffyStrToMillis(m.group("time")));
+ }
+ return cpuTimeByFrequencies;
+ } catch (Exception e) {
+ Slogf.e(TAG, e, "Failed to read CPU time in state from file: %s",
+ timeInStateFile.getAbsolutePath());
+ }
+ return null;
+ }
+
+ private static long readCpuFreqKHz(File file) {
+ if (!file.exists()) {
+ Slogf.e(TAG, "CPU frequency file %s doesn't exist", file.getAbsolutePath());
+ return 0;
+ }
+ try {
+ List<String> lines = Files.readAllLines(file.toPath());
+ if (!lines.isEmpty()) {
+ long frequency = Long.parseLong(lines.get(0).trim());
+ return frequency > 0 ? frequency : 0;
+ }
+ } catch (Exception e) {
+ Slogf.e(TAG, e, "Failed to read integer content from file: %s", file.getAbsolutePath());
+ }
+ return 0;
+ }
+
+ private static ArrayMap<Long, Long> calculateDeltaTimeInState(
+ ArrayMap<Long, Long> prevTimeInState, ArrayMap<Long, Long> latestTimeInState) {
+ ArrayMap<Long, Long> deltaTimeInState = new ArrayMap();
+ for (int i = 0; i < latestTimeInState.size(); i++) {
+ long freq = latestTimeInState.keyAt(i);
+ long durationMillis = latestTimeInState.valueAt(i);
+ long deltaDurationMillis;
+ if (prevTimeInState.containsKey(freq)) {
+ long prevDurationMillis = prevTimeInState.get(freq);
+ deltaDurationMillis = durationMillis > prevDurationMillis
+ ? (durationMillis - prevDurationMillis) : durationMillis;
+ } else {
+ deltaDurationMillis = durationMillis;
+ }
+ deltaTimeInState.put(freq, deltaDurationMillis);
+ }
+ return deltaTimeInState;
+ }
+
+ private static long calculateAvgCpuFreq(ArrayMap<Long, Long> timeInState) {
+ double totalTimeInState = 0;
+ for (int i = 0; i < timeInState.size(); i++) {
+ totalTimeInState += timeInState.valueAt(i);
+ }
+ double avgFreqKHz = 0;
+ for (int i = 0; i < timeInState.size(); i++) {
+ avgFreqKHz += (timeInState.keyAt(i) * timeInState.valueAt(i)) / totalTimeInState;
+ }
+ return (long) avgFreqKHz;
+ }
+
+ /**
+ * Reads the list of CPU cores from the given file.
+ *
+ * Reads CPU cores represented in one of the below formats.
+ * <ul>
+ * <li> Single core id. Eg: 1
+ * <li> Core id range. Eg: 1-4
+ * <li> Comma separated values. Eg: 1, 3-5, 7
+ * </ul>
+ */
+ private static List<Integer> readCpuCores(File file) {
+ if (!file.exists()) {
+ Slogf.e(TAG, "Failed to read CPU cores as the file '%s' doesn't exist",
+ file.getAbsolutePath());
+ return Collections.emptyList();
+ }
+ try {
+ List<String> lines = Files.readAllLines(file.toPath());
+ List<Integer> cpuCores = new ArrayList<>();
+ for (int i = 0; i < lines.size(); i++) {
+ String[] pairs = lines.get(i).trim().split(",");
+ for (int j = 0; j < pairs.length; j++) {
+ String[] minMaxPairs = pairs[j].split("-");
+ if (minMaxPairs.length >= 2) {
+ int min = Integer.parseInt(minMaxPairs[0]);
+ int max = Integer.parseInt(minMaxPairs[1]);
+ if (min > max) {
+ continue;
+ }
+ for (int id = min; id <= max; id++) {
+ cpuCores.add(id);
+ }
+ } else if (minMaxPairs.length == 1) {
+ cpuCores.add(Integer.parseInt(minMaxPairs[0]));
+ } else {
+ Slogf.w(TAG, "Invalid CPU core range format %s", pairs[j]);
+ }
+ }
+ }
+ return cpuCores;
+ } catch (Exception e) {
+ Slogf.e(TAG, e, "Failed to read CPU cores from %s", file.getAbsolutePath());
+ }
+ return Collections.emptyList();
+ }
+
+ @Nullable
+ private SparseArray<CpuUsageStats> readLatestCpuUsageStats() {
+ SparseArray<CpuUsageStats> cumulativeCpuUsageStats = readCumulativeCpuUsageStats();
+ if (cumulativeCpuUsageStats.size() == 0) {
+ Slogf.e(TAG, "Failed to read cumulative CPU usage stats");
+ return null;
+ }
+ SparseArray<CpuUsageStats> deltaCpuUsageStats = new SparseArray();
+ for (int i = 0; i < cumulativeCpuUsageStats.size(); i++) {
+ int cpu = cumulativeCpuUsageStats.keyAt(i);
+ CpuUsageStats newStats = cumulativeCpuUsageStats.valueAt(i);
+ CpuUsageStats oldStats = mCumulativeCpuUsageStats.get(cpu);
+ deltaCpuUsageStats.append(cpu, oldStats == null ? newStats : newStats.delta(oldStats));
+ }
+ mCumulativeCpuUsageStats = cumulativeCpuUsageStats;
+ return deltaCpuUsageStats;
+ }
+
+ private SparseArray<CpuUsageStats> readCumulativeCpuUsageStats() {
+ SparseArray<CpuUsageStats> cpuUsageStats = new SparseArray<>();
+ try {
+ List<String> lines = Files.readAllLines(mProcStatFile.toPath());
+ for (int i = 0; i < lines.size(); i++) {
+ Matcher m = PROC_STAT_PATTERN.matcher(lines.get(i).trim());
+ if (!m.find()) {
+ continue;
+ }
+ cpuUsageStats.append(Integer.parseInt(m.group("core")),
+ new CpuUsageStats(jiffyStrToMillis(m.group("userClockTicks")),
+ jiffyStrToMillis(m.group("niceClockTicks")),
+ jiffyStrToMillis(m.group("sysClockTicks")),
+ jiffyStrToMillis(m.group("idleClockTicks")),
+ jiffyStrToMillis(m.group("iowaitClockTicks")),
+ jiffyStrToMillis(m.group("irqClockTicks")),
+ jiffyStrToMillis(m.group("softirqClockTicks")),
+ jiffyStrToMillis(m.group("stealClockTicks")),
+ jiffyStrToMillis(m.group("guestClockTicks")),
+ jiffyStrToMillis(m.group("guestNiceClockTicks"))));
+ }
+ } catch (Exception e) {
+ Slogf.e(TAG, e, "Failed to read cpu usage stats from %s",
+ mProcStatFile.getAbsolutePath());
+ }
+ return cpuUsageStats;
+ }
+
+ private static long jiffyStrToMillis(String jiffyStr) {
+ return Long.parseLong(jiffyStr) * MILLIS_PER_JIFFY;
+ }
+
+ /** Contains information for each CPU core on the system. */
+ public static final class CpuInfo {
+ public final int cpuCore;
+ public final @CpusetCategory int cpusetCategories;
+ public final long curCpuFreqKHz;
+ public final long maxCpuFreqKHz;
+ public final CpuUsageStats latestCpuUsageStats;
+
+ CpuInfo(int cpuCore, @CpusetCategory int cpusetCategories, long curCpuFreqKHz,
+ long maxCpuFreqKHz, CpuUsageStats latestCpuUsageStats) {
+ this.cpuCore = cpuCore;
+ this.cpusetCategories = cpusetCategories;
+ this.curCpuFreqKHz = curCpuFreqKHz;
+ this.maxCpuFreqKHz = maxCpuFreqKHz;
+ this.latestCpuUsageStats = latestCpuUsageStats;
+ }
+
+ @Override
+ public String toString() {
+ return new StringBuilder("CpuInfo{ cpuCore = ").append(cpuCore)
+ .append(", cpusetCategories = ").append(cpusetCategories)
+ .append(", curCpuFreqKHz = ").append(curCpuFreqKHz)
+ .append(", maxCpuFreqKHz = ").append(maxCpuFreqKHz)
+ .append(", latestCpuUsageStats = ").append(latestCpuUsageStats)
+ .append(" }").toString();
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (!(obj instanceof CpuInfo)) {
+ return false;
+ }
+ CpuInfo other = (CpuInfo) obj;
+ return cpuCore == other.cpuCore && cpusetCategories == other.cpusetCategories
+ && curCpuFreqKHz == other.curCpuFreqKHz
+ && maxCpuFreqKHz == other.maxCpuFreqKHz
+ && latestCpuUsageStats.equals(other.latestCpuUsageStats);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(cpuCore, cpusetCategories, curCpuFreqKHz, maxCpuFreqKHz,
+ latestCpuUsageStats);
+ }
+ }
+
+ /** CPU time spent in different modes. */
+ public static final class CpuUsageStats {
+ public final long userTimeMillis;
+ public final long niceTimeMillis;
+ public final long systemTimeMillis;
+ public final long idleTimeMillis;
+ public final long iowaitTimeMillis;
+ public final long irqTimeMillis;
+ public final long softirqTimeMillis;
+ public final long stealTimeMillis;
+ public final long guestTimeMillis;
+ public final long guestNiceTimeMillis;
+
+ public CpuUsageStats(long userTimeMillis, long niceTimeMillis, long systemTimeMillis,
+ long idleTimeMillis, long iowaitTimeMillis, long irqTimeMillis,
+ long softirqTimeMillis, long stealTimeMillis, long guestTimeMillis,
+ long guestNiceTimeMillis) {
+ this.userTimeMillis = userTimeMillis;
+ this.niceTimeMillis = niceTimeMillis;
+ this.systemTimeMillis = systemTimeMillis;
+ this.idleTimeMillis = idleTimeMillis;
+ this.iowaitTimeMillis = iowaitTimeMillis;
+ this.irqTimeMillis = irqTimeMillis;
+ this.softirqTimeMillis = softirqTimeMillis;
+ this.stealTimeMillis = stealTimeMillis;
+ this.guestTimeMillis = guestTimeMillis;
+ this.guestNiceTimeMillis = guestNiceTimeMillis;
+ }
+
+ public long getTotalTime() {
+ return userTimeMillis + niceTimeMillis + systemTimeMillis + idleTimeMillis
+ + iowaitTimeMillis + irqTimeMillis + softirqTimeMillis + stealTimeMillis
+ + guestTimeMillis + guestNiceTimeMillis;
+ }
+
+ @Override
+ public String toString() {
+ return new StringBuilder("CpuUsageStats{ userTimeMillis = ")
+ .append(userTimeMillis)
+ .append(", niceTimeMillis = ").append(niceTimeMillis)
+ .append(", systemTimeMillis = ").append(systemTimeMillis)
+ .append(", idleTimeMillis = ").append(idleTimeMillis)
+ .append(", iowaitTimeMillis = ").append(iowaitTimeMillis)
+ .append(", irqTimeMillis = ").append(irqTimeMillis)
+ .append(", softirqTimeMillis = ").append(softirqTimeMillis)
+ .append(", stealTimeMillis = ").append(stealTimeMillis)
+ .append(", guestTimeMillis = ").append(guestTimeMillis)
+ .append(", guestNiceTimeMillis = ").append(guestNiceTimeMillis)
+ .append(" }").toString();
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (!(obj instanceof CpuUsageStats)) {
+ return false;
+ }
+ CpuUsageStats other = (CpuUsageStats) obj;
+ return userTimeMillis == other.userTimeMillis && niceTimeMillis == other.niceTimeMillis
+ && systemTimeMillis == other.systemTimeMillis
+ && idleTimeMillis == other.idleTimeMillis
+ && iowaitTimeMillis == other.iowaitTimeMillis
+ && irqTimeMillis == other.irqTimeMillis
+ && softirqTimeMillis == other.softirqTimeMillis
+ && stealTimeMillis == other.stealTimeMillis
+ && guestTimeMillis == other.guestTimeMillis
+ && guestNiceTimeMillis == other.guestNiceTimeMillis;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(userTimeMillis, niceTimeMillis, systemTimeMillis, idleTimeMillis,
+ iowaitTimeMillis, irqTimeMillis, softirqTimeMillis, stealTimeMillis,
+ guestTimeMillis,
+ guestNiceTimeMillis);
+ }
+
+ CpuUsageStats delta(CpuUsageStats rhs) {
+ return new CpuUsageStats(diff(userTimeMillis, rhs.userTimeMillis),
+ diff(niceTimeMillis, rhs.niceTimeMillis),
+ diff(systemTimeMillis, rhs.systemTimeMillis),
+ diff(idleTimeMillis, rhs.idleTimeMillis),
+ diff(iowaitTimeMillis, rhs.iowaitTimeMillis),
+ diff(irqTimeMillis, rhs.irqTimeMillis),
+ diff(softirqTimeMillis, rhs.softirqTimeMillis),
+ diff(stealTimeMillis, rhs.stealTimeMillis),
+ diff(guestTimeMillis, rhs.guestTimeMillis),
+ diff(guestNiceTimeMillis, rhs.guestNiceTimeMillis));
+ }
+
+ private static long diff(long lhs, long rhs) {
+ return lhs > rhs ? lhs - rhs : 0;
+ }
+ }
+}
diff --git a/service/src/com/android/car/pm/CarPackageManagerService.java b/service/src/com/android/car/pm/CarPackageManagerService.java
index 1c2da54..cd47fe3 100644
--- a/service/src/com/android/car/pm/CarPackageManagerService.java
+++ b/service/src/com/android/car/pm/CarPackageManagerService.java
@@ -35,6 +35,7 @@
import android.app.PendingIntent;
import android.app.TaskInfo;
import android.car.Car;
+import android.car.CarVersion;
import android.car.builtin.app.ActivityManagerHelper;
import android.car.builtin.app.TaskInfoHelper;
import android.car.builtin.content.pm.PackageManagerHelper;
@@ -60,6 +61,7 @@
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.ActivityInfo;
+import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
@@ -86,6 +88,7 @@
import android.util.Log;
import android.util.Pair;
import android.util.SparseArray;
+import android.util.SparseBooleanArray;
import android.util.SparseLongArray;
import android.view.Display;
import android.view.accessibility.AccessibilityEvent;
@@ -105,6 +108,7 @@
import com.android.car.internal.util.Sets;
import com.android.car.power.CarPowerManagementService;
import com.android.car.user.CarUserService;
+import com.android.car.util.Utils;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
@@ -123,13 +127,17 @@
import java.util.Objects;
import java.util.Set;
-public class CarPackageManagerService extends ICarPackageManager.Stub implements CarServiceBase {
-
- static final boolean DBG = false;
+/**
+ * Package manager service for cars.
+ */
+public final class CarPackageManagerService extends ICarPackageManager.Stub
+ implements CarServiceBase {
@VisibleForTesting
static final String TAG = CarLog.tagFor(CarPackageManagerService.class);
+ static final boolean DBG = Log.isLoggable(TAG, Log.DEBUG);
+
// Delimiters to parse packages and activities in the configuration XML resource.
private static final String PACKAGE_DELIMITER = ",";
private static final String PACKAGE_ACTIVITY_DELIMITER = "/";
@@ -166,6 +174,11 @@
private final List<String> mAllowedAppInstallSources;
+ // A SparseBooleanArray to handle the already blocked display IDs when iterating on the visible
+ // tasks. This is defined as an instance variable to avoid frequent creations.
+ // This Array is cleared everytime before its use.
+ private final SparseBooleanArray mBlockedDisplayIds = new SparseBooleanArray();
+
@GuardedBy("mLock")
private final SparseArray<ComponentName> mTopActivityWithDialogPerDisplay = new SparseArray<>();
@@ -1291,17 +1304,33 @@
}
private void blockTopActivitiesIfNecessary() {
- List<TaskInfo> topTasks = mActivityService.getTopTasks();
- for (TaskInfo topTask : topTasks) {
+ List<? extends TaskInfo> visibleTasks = mActivityService.getVisibleTasks();
+ mBlockedDisplayIds.clear();
+ for (TaskInfo topTask : visibleTasks) {
if (topTask == null) {
Slogf.e(TAG, "Top tasks contains null.");
continue;
}
- blockTopActivityIfNecessary(topTask);
+
+ int displayIdOfTask = TaskInfoHelper.getDisplayId(topTask);
+ if (mBlockedDisplayIds.indexOfKey(displayIdOfTask) != -1) {
+ if (DBG) {
+ Slogf.d(TAG, "This display has already been blocked.");
+ }
+ continue;
+ }
+
+ boolean blocked = blockTopActivityIfNecessary(topTask);
+ if (blocked) {
+ mBlockedDisplayIds.append(displayIdOfTask, true);
+ }
}
}
- private void blockTopActivityIfNecessary(TaskInfo topTask) {
+ /**
+ * @return {@code True} if the {@code topTask} was blocked, {@code False} otherwise.
+ */
+ private boolean blockTopActivityIfNecessary(TaskInfo topTask) {
int displayId = TaskInfoHelper.getDisplayId(topTask);
synchronized (mLock) {
if (!Objects.equals(mActivityBlockingActivity, topTask.topActivity)
@@ -1313,30 +1342,34 @@
}
}
if (isUxRestrictedOnDisplay(displayId)) {
- doBlockTopActivityIfNotAllowed(displayId, topTask);
+ return doBlockTopActivityIfNotAllowed(displayId, topTask);
}
+ return false;
}
- private void doBlockTopActivityIfNotAllowed(int displayId, TaskInfo topTask) {
+ /**
+ * @return {@code True} if the {@code topTask} was blocked, {@code False} otherwise.
+ */
+ private boolean doBlockTopActivityIfNotAllowed(int displayId, TaskInfo topTask) {
if (topTask.topActivity == null) {
- return;
+ return false;
}
if (topTask.topActivity.equals(mActivityBlockingActivity)) {
mBlockingActivityLaunchTimes.put(displayId, 0);
mBlockingActivityTargets.put(displayId, null);
- return;
+ return false;
}
boolean allowed = isActivityAllowed(topTask);
if (Slogf.isLoggable(TAG, Log.DEBUG)) {
Slogf.d(TAG, "new activity:" + topTask.toString() + " allowed:" + allowed);
}
if (allowed) {
- return;
+ return false;
}
if (!mEnableActivityBlocking) {
Slogf.d(TAG, "Current activity " + topTask.topActivity
+ " not allowed, blocking disabled.");
- return;
+ return false;
}
if (Slogf.isLoggable(TAG, Log.DEBUG)) {
Slogf.d(TAG, "Current activity " + topTask.topActivity
@@ -1351,7 +1384,7 @@
long blockingActivityLaunchTime = mBlockingActivityLaunchTimes.get(displayId);
if (SystemClock.uptimeMillis() - blockingActivityLaunchTime < ABA_LAUNCH_TIMEOUT_MS) {
Slogf.d(TAG, "Waiting for BlockingActivity to be shown: displayId=%d", displayId);
- return;
+ return false;
}
}
@@ -1378,6 +1411,7 @@
mBlockingActivityLaunchTimes.put(displayId, SystemClock.uptimeMillis());
mBlockingActivityTargets.put(displayId, topTask.topActivity);
mActivityService.blockActivity(topTask, newActivityIntent);
+ return true;
}
private boolean isActivityAllowed(TaskInfo topTaskInfoContainer) {
@@ -1509,6 +1543,52 @@
mCarUxRestrictionsService.setUxRChangeBroadcastEnabled(enable);
}
+ @Override
+ public CarVersion getTargetCarVersion(String packageName) {
+ return getTargetCarVersion(Binder.getCallingUserHandle(), packageName);
+ }
+
+ @Override
+ public CarVersion getSelfTargetCarVersion(String packageName) {
+ Utils.checkCalledByPackage(mContext, packageName);
+
+ return getTargetCarVersion(Binder.getCallingUserHandle(), packageName);
+ }
+
+ /**
+ * Public, as it's also used by {@code ICarImpl}.
+ */
+ public CarVersion getTargetCarVersion(UserHandle user, String packageName) {
+ Context context = mContext.createContextAsUser(user, /* flags= */ 0);
+ return getTargetCarVersion(context, packageName);
+ }
+
+ /**
+ * Used by {@code CarShellCommand} as well.
+ */
+ @Nullable
+ public static CarVersion getTargetCarVersion(Context context, String packageName) {
+ String permission = android.Manifest.permission.QUERY_ALL_PACKAGES;
+ if (context.checkCallingOrSelfPermission(permission) != PackageManager.PERMISSION_GRANTED) {
+ Slogf.w(TAG, "getTargetCarVersion(%s): UID %d doesn't have %s permission",
+ packageName, Binder.getCallingUid(), permission);
+ throw new SecurityException("requires permission " + permission);
+ }
+ ApplicationInfo info = null;
+ try {
+ info = context.getPackageManager().getApplicationInfo(packageName,
+ PackageManager.ApplicationInfoFlags.of(PackageManager.GET_META_DATA));
+ } catch (NameNotFoundException e) {
+ if (DBG) {
+ Slogf.d(TAG, "getTargetCarVersion(%s, %s): not found: %s", context.getUser(),
+ packageName, e);
+ }
+ throw new ServiceSpecificException(CarPackageManager.ERROR_CODE_NO_PACKAGE,
+ e.getMessage());
+ }
+ return CarVersionParser.getTargetCarVersion(info);
+ }
+
/**
* Get the distraction optimized activities for the given package.
*
@@ -1768,7 +1848,9 @@
void onWindowChangeEvent(@NonNull AccessibilityEvent event) {
Slogf.d(TAG, "onWindowChange event received");
boolean receivedFromActivityBlockingActivity =
- mActivityBlockingActivity.getPackageName().contentEquals(event.getPackageName())
+ event.getPackageName() != null && event.getClassName() != null
+ && mActivityBlockingActivity.getPackageName().contentEquals(
+ event.getPackageName())
&& mActivityBlockingActivity.getClassName().contentEquals(
event.getClassName());
if (!receivedFromActivityBlockingActivity) {
diff --git a/service/src/com/android/car/pm/CarVersionParser.java b/service/src/com/android/car/pm/CarVersionParser.java
new file mode 100644
index 0000000..89ce13c
--- /dev/null
+++ b/service/src/com/android/car/pm/CarVersionParser.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2022 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.pm;
+
+import static android.car.content.pm.CarPackageManager.MANIFEST_METADATA_TARGET_CAR_VERSION;
+
+import static com.android.car.pm.CarPackageManagerService.DBG;
+
+import android.annotation.Nullable;
+import android.car.CarVersion;
+import android.car.builtin.util.Slogf;
+import android.content.pm.ApplicationInfo;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * Helper class used to parse the target Car API version in an appication manifest.
+ *
+ */
+final class CarVersionParser {
+
+ private static final String TAG = CarVersionParser.class.getSimpleName();
+
+ private static final Pattern API_VERSION_REGEX = Pattern
+ .compile("^(?<major>\\d+)(:(?<minor>\\d+))?$");
+
+ /**
+ * Gets the target Car API version of the app.
+ */
+ public static CarVersion getTargetCarVersion(ApplicationInfo info) {
+ String pkgName = info.packageName;
+ int major, minor;
+ if (info.metaData == null) {
+ major = info.targetSdkVersion;
+ minor = 0;
+ if (DBG) {
+ Slogf.d(TAG, "parse(%s): no metadata, returning (%d, %d)", pkgName, major, minor);
+ }
+ return CarVersion.forMajorAndMinorVersions(major, minor);
+ }
+ return parse(pkgName, info.metaData.getString(MANIFEST_METADATA_TARGET_CAR_VERSION),
+ info.targetSdkVersion);
+ }
+
+ @VisibleForTesting
+ static CarVersion parse(String pkgName, @Nullable String value, int targetSdkVersion) {
+ if (value == null) {
+ return CarVersion.forMajorAndMinorVersions(targetSdkVersion, 0);
+ }
+ Matcher matcher = API_VERSION_REGEX.matcher(value);
+ if (!matcher.matches()) {
+ if (DBG) {
+ Slogf.d(TAG, "parse(%s): no match on %s, returning targetSdkVersion(%d) instead",
+ pkgName, value, targetSdkVersion);
+ }
+ return CarVersion.forMajorAndMinorVersions(targetSdkVersion, 0);
+ }
+ try {
+ int major = Integer.parseInt(matcher.group("major"));
+ String minorMatch = matcher.group("minor");
+ int minor = minorMatch != null ? Integer.parseInt(minorMatch) : 0;
+ return CarVersion.forMajorAndMinorVersions(major, minor);
+ } catch (Exception e) {
+ // Shouldn't happen, as it matched regex
+ Slogf.w(TAG, e, "parse(%s): exception parsing valued value (%s) for pkg %s using %s"
+ + "; return targetSdkVersion(%d) instead", pkgName, API_VERSION_REGEX, value,
+ targetSdkVersion);
+ return CarVersion.forMajorAndMinorVersions(targetSdkVersion, 0);
+ }
+
+ }
+
+ private CarVersionParser() {
+ throw new UnsupportedOperationException("contains only static methods");
+ }
+}
diff --git a/service/src/com/android/car/pm/VendorServiceController.java b/service/src/com/android/car/pm/VendorServiceController.java
index ec1c323..295179a 100644
--- a/service/src/com/android/car/pm/VendorServiceController.java
+++ b/service/src/com/android/car/pm/VendorServiceController.java
@@ -20,7 +20,9 @@
import static android.car.user.CarUserManager.USER_LIFECYCLE_EVENT_TYPE_SWITCHING;
import static android.car.user.CarUserManager.USER_LIFECYCLE_EVENT_TYPE_UNLOCKED;
import static android.content.Context.BIND_AUTO_CREATE;
+import static android.os.Process.INVALID_UID;
+import static com.android.car.CarLog.TAG_AM;
import static com.android.car.util.Utils.isEventAnyOfTypes;
import android.annotation.Nullable;
@@ -30,11 +32,14 @@
import android.car.user.CarUserManager.UserLifecycleEvent;
import android.car.user.CarUserManager.UserLifecycleListener;
import android.car.user.UserLifecycleEventFilter;
+import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
+import android.content.IntentFilter;
import android.content.ServiceConnection;
import android.content.res.Resources;
+import android.net.Uri;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
@@ -51,9 +56,10 @@
import com.android.internal.annotations.VisibleForTesting;
import java.util.ArrayList;
-import java.util.HashMap;
import java.util.List;
+import java.util.Map;
import java.util.Objects;
+import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executor;
/**
@@ -70,15 +76,55 @@
static final String TAG = CarLog.tagFor(VendorServiceController.class);
private static final boolean DBG = Slogf.isLoggable(TAG, Log.DEBUG);
+ private static final String PACKAGE_DATA_SCHEME = "package";
private final List<VendorServiceInfo> mVendorServiceInfos = new ArrayList<>();
- private final HashMap<ConnectionKey, VendorServiceConnection> mConnections =
- new HashMap<>();
+ // TODO(b/240607225): Synchronize access to mConnections. It can lead to unexpected behavior.
+ private final Map<ConnectionKey, VendorServiceConnection> mConnections =
+ new ConcurrentHashMap<>();
private final Context mContext;
private final UserManager mUserManager;
private final Handler mHandler;
private CarUserService mCarUserService;
+ private final BroadcastReceiver mPackageChangeReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ String action = intent.getAction();
+ if (DBG) {
+ Slogf.d(TAG_AM, "Package change received with action = %s", action);
+ }
+
+ Uri packageData = intent.getData();
+ if (packageData == null) {
+ Slogf.wtf(TAG_AM, "null packageData");
+ return;
+ }
+ String packageName = packageData.getSchemeSpecificPart();
+ if (packageName == null) {
+ Slogf.w(TAG_AM, "null packageName");
+ return;
+ }
+ int uid = intent.getIntExtra(Intent.EXTRA_UID, INVALID_UID);
+ int userId = UserHandle.getUserHandleForUid(uid).getIdentifier();
+
+ switch (action) {
+ case Intent.ACTION_PACKAGE_CHANGED:
+ // Fall through
+ case Intent.ACTION_PACKAGE_REPLACED:
+ // Fall through
+ case Intent.ACTION_PACKAGE_ADDED:
+ tryToRebindConnectionsForUser(userId);
+ break;
+ case Intent.ACTION_PACKAGE_REMOVED:
+ stopOrUnbindService(packageName, userId);
+ break;
+ default:
+ Slogf.w(TAG_AM, "This package change event (%s) can't be handled.",
+ action);
+ }
+ }
+ };
VendorServiceController(Context context, Looper looper) {
mContext = context;
@@ -100,13 +146,19 @@
mCarUserService.addUserLifecycleListener(userSwitchingOrUnlockingEventFilter, this);
startOrBindServicesIfNeeded();
+ registerPackageChangeReceiver();
}
void release() {
+ if (mVendorServiceInfos.isEmpty()) {
+ Slogf.d(TAG_AM, "Releasing VendorServiceController without deep cleaning as no vendor "
+ + "service info present. ");
+ return;
+ }
if (mCarUserService != null) {
mCarUserService.removeUserLifecycleListener(this);
}
-
+ unregisterPackageChangeReceiver();
for (ConnectionKey key : mConnections.keySet()) {
stopOrUnbindService(key.mVendorServiceInfo, key.mUserHandle);
}
@@ -140,6 +192,32 @@
}
}
+ private void registerPackageChangeReceiver() {
+ IntentFilter filter = new IntentFilter();
+ filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
+ filter.addAction(Intent.ACTION_PACKAGE_REPLACED);
+ filter.addAction(Intent.ACTION_PACKAGE_ADDED);
+ filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
+ filter.addDataScheme(PACKAGE_DATA_SCHEME);
+ mContext.registerReceiverForAllUsers(mPackageChangeReceiver, filter,
+ /* broadcastPermission= */ null, /* scheduler= */ null,
+ Context.RECEIVER_NOT_EXPORTED);
+ }
+
+ private void unregisterPackageChangeReceiver() {
+ mContext.unregisterReceiver(mPackageChangeReceiver);
+ }
+
+ private void tryToRebindConnectionsForUser(@UserIdInt int userId) {
+ for (VendorServiceConnection connection : mConnections.values()) {
+ if (connection.isUser(userId)) {
+ Slogf.d(TAG, "Trying to rebind connection to %s",
+ connection.mVendorServiceInfo);
+ connection.tryToRebind();
+ }
+ }
+ }
+
private void handleOnUserSwitching(@UserIdInt int userId) {
// Stop all services which do not run under foreground or system user.
int fgUser = ActivityManager.getCurrentUser();
@@ -217,6 +295,22 @@
}
}
+ /**
+ * Unbinds the VendorServiceController from all the services with the given {@code packageName}
+ * and running as {@code userId}.
+ */
+ private void stopOrUnbindService(String packageName, @UserIdInt int userId) {
+ for (VendorServiceConnection connection : mConnections.values()) {
+ if (connection.isUser(userId)
+ && packageName.equals(connection.mVendorServiceInfo.getIntent().getComponent()
+ .getPackageName())) {
+ Slogf.d(TAG, "Stopping the connection to service %s",
+ connection.mVendorServiceInfo);
+ connection.stopOrUnbindService();
+ }
+ }
+ }
+
private VendorServiceConnection getOrCreateConnection(ConnectionKey key) {
VendorServiceConnection connection = mConnections.get(key);
if (connection == null) {
@@ -250,7 +344,8 @@
/**
* Represents connection to the vendor service.
*/
- private static final class VendorServiceConnection implements ServiceConnection, Executor {
+ @VisibleForTesting
+ public static final class VendorServiceConnection implements ServiceConnection, Executor {
private static final int REBIND_DELAY_MS = 5000;
private static final int MAX_RECENT_FAILURES = 5;
private static final int FAILURE_COUNTER_RESET_TIMEOUT = 5 * 60 * 1000; // 5 min.
@@ -282,12 +377,21 @@
};
}
+ @VisibleForTesting
+ public boolean isPendingRebind() {
+ return mFailureHandler.hasMessages(MSG_REBIND);
+ }
+
@Override
public String toString() {
return "VendorServiceConnection[user=" + mUser
+ ", service=" + mVendorServiceInfo + "]";
}
+ private boolean isUser(@UserIdInt int userId) {
+ return mUser.getIdentifier() == userId;
+ }
+
boolean startOrBindService() {
if (mStarted || mBound) {
return true; // Already started or bound
diff --git a/service/src/com/android/car/power/CarPowerManagementService.java b/service/src/com/android/car/power/CarPowerManagementService.java
index 460503b..8caf3ca 100644
--- a/service/src/com/android/car/power/CarPowerManagementService.java
+++ b/service/src/com/android/car/power/CarPowerManagementService.java
@@ -16,6 +16,9 @@
package com.android.car.power;
+import static android.car.hardware.power.CarPowerManager.STATE_PRE_SHUTDOWN_PREPARE;
+import static android.car.hardware.power.CarPowerManager.STATE_SHUTDOWN_PREPARE;
+
import static com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport.DUMP_INFO;
import android.annotation.NonNull;
@@ -95,6 +98,7 @@
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.function.BiFunction;
/**
* Power Management service class for cars. Controls the power states and interacts with other
@@ -373,7 +377,7 @@
mBinderHandler.unlinkToDeath();
}
synchronized (mLock) {
- cancelWaitingForCompletion();
+ clearWaitingForCompletion(/*clearQueue=*/false);
mCurrentState = null;
mCarPowerPolicyDaemon = null;
mHandler.cancelAll();
@@ -449,13 +453,36 @@
@CarPowerManager.CarPowerState int carPowerStateListenerState) {
CpmsState newState = new CpmsState(apState, carPowerStateListenerState,
/* canPostpone= */ false);
+ BiFunction<CpmsState, CpmsState, Boolean> eventFilter = null;
+
+ // We are ready to shut down. Suppress this transition if
+ // there is a request to cancel the shutdown (WAIT_FOR_VHAL).
+ // Completely ignore this WAIT_FOR_FINISH
+ if (newState.mState == CpmsState.WAIT_FOR_FINISH) {
+ eventFilter = (stateToAdd, pendingSate) ->
+ stateToAdd.mState == CpmsState.WAIT_FOR_FINISH
+ && pendingSate.mState == CpmsState.WAIT_FOR_VHAL;
+ }
+
+ // Check if there is another pending SHUTDOWN_PREPARE.
+ // This could happen, when another SHUTDOWN_PREPARE request is received from VHAL
+ // while notifying PRE_SHUTDOWN_PREPARE.
+ // If SHUTDOWN_PREPARE request already exist in the queue, and it skips Garage Mode,
+ // then newState is ignored .
+ if (newState.mState == CpmsState.SHUTDOWN_PREPARE) {
+ eventFilter = (stateToAdd, pendingState) ->
+ pendingState.mState == CpmsState.SHUTDOWN_PREPARE
+ && !pendingState.mCanPostpone
+ && pendingState.mCarPowerStateListenerState
+ == STATE_PRE_SHUTDOWN_PREPARE;
+ }
+
synchronized (mLock) {
- if (newState.mState == CpmsState.WAIT_FOR_FINISH) {
- // We are ready to shut down. Suppress this transition if
- // there is a request to cancel the shutdown (WAIT_FOR_VHAL).
+ // If eventFilter exists, lets check if event that satisfies filter is in queue.
+ if (eventFilter != null) {
for (int idx = 0; idx < mPendingPowerStates.size(); idx++) {
- if (mPendingPowerStates.get(idx).mState == CpmsState.WAIT_FOR_VHAL) {
- // Completely ignore this WAIT_FOR_FINISH
+ CpmsState pendingState = mPendingPowerStates.get(idx);
+ if (eventFilter.apply(newState, pendingState)) {
return;
}
}
@@ -467,15 +494,17 @@
}
private void doHandlePowerStateChange() {
- CpmsState state;
+ CpmsState newState;
+ CpmsState prevState;
synchronized (mLock) {
- state = mPendingPowerStates.pollFirst();
- if (state == null) {
+ prevState = mCurrentState;
+ newState = mPendingPowerStates.pollFirst();
+ if (newState == null) {
Slogf.w(TAG, "No more power state to process");
return;
}
- Slogf.i(TAG, "doHandlePowerStateChange: newState=%s", state.name());
- if (!needPowerStateChangeLocked(state)) {
+ Slogf.i(TAG, "doHandlePowerStateChange: newState=%s", newState.name());
+ if (!needPowerStateChangeLocked(newState)) {
// We may need to process the pending power state request.
if (!mPendingPowerStates.isEmpty()) {
Slogf.i(TAG, "There is a pending power state change request. requesting the "
@@ -484,32 +513,44 @@
}
return;
}
+
// now real power change happens. Whatever was queued before should be all cancelled.
mPendingPowerStates.clear();
- cancelWaitingForCompletion();
- mCurrentState = state;
+
+ // Received updated SHUTDOWN_PREPARE there could be several reasons for that
+ // 1. CPMS is in SHUTDOWN_PREPARE, and received state change to perform transition
+ // from PRE_SHUTDOWN_PREPARE into SHUTDOWN_PREPARE
+ // 2. New SHUTDOWN_PREPARE request is received, and it is different from existing one.
+ if (newState.mState == CpmsState.SHUTDOWN_PREPARE && newState.mState == prevState.mState
+ && newState.mCarPowerStateListenerState == STATE_PRE_SHUTDOWN_PREPARE) {
+ // Nothing to do here, skipping clearing completion queue
+ } else {
+ clearWaitingForCompletion(/*clearQueue=*/false);
+ }
+
+ mCurrentState = newState;
}
mHandler.cancelProcessingComplete();
- Slogf.i(TAG, "setCurrentState %s", state);
- CarStatsLogHelper.logPowerState(state.mState);
- EventLogHelper.writeCarPowerManagerStateChange(state.mState);
- switch (state.mState) {
+ Slogf.i(TAG, "setCurrentState %s", newState);
+ CarStatsLogHelper.logPowerState(newState.mState);
+ EventLogHelper.writeCarPowerManagerStateChange(newState.mState);
+ switch (newState.mState) {
case CpmsState.WAIT_FOR_VHAL:
- handleWaitForVhal(state);
+ handleWaitForVhal(newState);
break;
case CpmsState.ON:
handleOn();
break;
case CpmsState.SHUTDOWN_PREPARE:
- handleShutdownPrepare(state);
+ handleShutdownPrepare(newState, prevState);
break;
case CpmsState.SIMULATE_SLEEP:
case CpmsState.SIMULATE_HIBERNATION:
- simulateShutdownPrepare(state);
+ simulateShutdownPrepare(newState, prevState);
break;
case CpmsState.WAIT_FOR_FINISH:
- handleWaitForFinish(state);
+ handleWaitForFinish(newState);
break;
case CpmsState.SUSPEND:
// Received FINISH from VHAL
@@ -627,18 +668,20 @@
private void applyDefaultPowerPolicyForState(@CarPowerManager.CarPowerState int state,
@Nullable String fallbackPolicyId) {
+ Slogf.i(TAG, "Applying the default power policy for %s (fallback policy = %s)",
+ powerStateToString(state), fallbackPolicyId);
CarPowerPolicy policy;
synchronized (mLock) {
policy = mPolicyReader
.getDefaultPowerPolicyForState(mCurrentPowerPolicyGroupId, state);
}
if (policy == null && fallbackPolicyId == null) {
- Slogf.w(TAG, "No default power policy for %s is found",
- PolicyReader.vhalPowerStateToString(state));
+ Slogf.w(TAG, "No default power policy for %s is found", powerStateToString(state));
return;
}
String policyId = policy == null ? fallbackPolicyId : policy.getPolicyId();
- applyPowerPolicy(policyId, /* upToDaemon= */ true, /* force= */ false);
+ applyPowerPolicy(policyId, /* delayNotification= */ false, /* upToDaemon= */ true,
+ /* force= */ false);
}
/**
@@ -662,23 +705,48 @@
}
}
- private void handleShutdownPrepare(CpmsState newState) {
- switch (newState.mCarPowerStateListenerState) {
+ private void handleShutdownPrepare(CpmsState currentState, CpmsState prevState) {
+ switch (currentState.mCarPowerStateListenerState) {
case CarPowerManager.STATE_PRE_SHUTDOWN_PREPARE:
- handlePreShutdownPrepare(newState);
+ updateShutdownPrepareStatus(currentState);
+ if (prevState.mCarPowerStateListenerState == STATE_SHUTDOWN_PREPARE) {
+ // Received request to update SHUTDOWN target
+ currentState = new CpmsState(currentState.mState,
+ prevState.mCarPowerStateListenerState,
+ prevState.mCanPostpone, currentState.mShutdownType);
+ synchronized (mLock) {
+ mCurrentState = currentState;
+ }
+ clearWaitingForCompletion(/*clearQueue=*/true);
+ } else if (prevState.mCarPowerStateListenerState == STATE_PRE_SHUTDOWN_PREPARE) {
+ // Update of state occurred while in PRE_SHUTDOWN_PREPARE
+ boolean areListenersEmpty;
+ synchronized (mLock) {
+ areListenersEmpty = mListenersWeAreWaitingFor.isEmpty();
+ }
+ if (areListenersEmpty) {
+ handleCoreShutdownPrepare();
+ } else {
+ // PRE_SHUTDOWN_PREPARE is still being processed, no actions required
+ return;
+ }
+ } else {
+ handlePreShutdownPrepare();
+ }
break;
case CarPowerManager.STATE_SHUTDOWN_PREPARE:
handleCoreShutdownPrepare();
break;
default:
Slogf.w(TAG, "Not supported listener state(%d)",
- newState.mCarPowerStateListenerState);
+ currentState.mCarPowerStateListenerState);
}
}
- private void handlePreShutdownPrepare(CpmsState newState) {
+ private void updateShutdownPrepareStatus(CpmsState newState) {
// Shutdown on finish if the system doesn't support deep sleep/hibernation
// or doesn't allow it.
+ int intervalMs;
synchronized (mLock) {
if (mShutdownOnNextSuspend
|| newState.mShutdownType == PowerState.SHUTDOWN_TYPE_POWER_OFF) {
@@ -697,9 +765,18 @@
Slogf.wtf(TAG, "handleShutdownPrepare - incorrect state " + newState);
}
mGarageModeShouldExitImmediately = !newState.mCanPostpone;
+ intervalMs = mShutdownPollingIntervalMs;
}
- Slogf.i(TAG, newState.mCanPostpone ? "starting shutdown prepare with Garage Mode"
- : "starting shutdown prepare without Garage Mode");
+ }
+
+ private void handlePreShutdownPrepare() {
+ int intervalMs;
+ synchronized (mLock) {
+ intervalMs = mShutdownPollingIntervalMs;
+ Slogf.i(TAG,
+ mGarageModeShouldExitImmediately ? "starting shutdown prepare with Garage Mode"
+ : "starting shutdown prepare without Garage Mode");
+ }
long timeoutMs = getPreShutdownPrepareTimeoutConfig();
int state = CarPowerManager.STATE_PRE_SHUTDOWN_PREPARE;
@@ -711,9 +788,8 @@
onApPowerStateChange(CpmsState.SHUTDOWN_PREPARE,
CarPowerManager.STATE_SHUTDOWN_PREPARE);
};
- Slogf.i(TAG, "Start waiting for listener completion for %s", powerStateToString(state));
- waitForCompletion(taskAtCompletion, /* taskAtInterval= */ null, timeoutMs,
- /* intervalMs= */ -1);
+
+ waitForCompletionWithShutdownPostpone(state, timeoutMs, taskAtCompletion, intervalMs);
}
private void handleCoreShutdownPrepare() {
@@ -722,9 +798,9 @@
}
// Simulates system shutdown to suspend
- private void simulateShutdownPrepare(CpmsState state) {
+ private void simulateShutdownPrepare(CpmsState newState, CpmsState oldState) {
Slogf.i(TAG, "Simulating shutdown prepare");
- handleShutdownPrepare(state);
+ handleShutdownPrepare(newState, oldState);
}
private void doShutdownPrepare() {
@@ -771,10 +847,14 @@
break;
}
};
- Slogf.i(TAG, "Start waiting for listener completion for %s",
- powerStateToString(state.mCarPowerStateListenerState));
- waitForCompletion(taskAtCompletion, /* taskAtInterval= */ null, timeoutMs,
- /* intervalMs= */ -1);
+
+ int intervalMs;
+ synchronized (mLock) {
+ intervalMs = mShutdownPollingIntervalMs;
+ }
+
+ waitForCompletionWithShutdownPostpone(state.mCarPowerStateListenerState, timeoutMs,
+ taskAtCompletion, intervalMs);
}
private void handleFinish() {
@@ -921,11 +1001,8 @@
finishShutdownPrepare();
Slogf.i(TAG, "All listeners completed for %s", powerStateToString(state));
};
- Runnable taskAtInterval = () -> {
- mHal.sendShutdownPostpone(SHUTDOWN_EXTEND_MAX_MS);
- };
- Slogf.i(TAG, "Start waiting for listeners to complete for %s", powerStateToString(state));
- waitForCompletion(taskAtCompletion, taskAtInterval, timeoutMs, intervalMs);
+
+ waitForCompletionWithShutdownPostpone(state, timeoutMs, taskAtCompletion, intervalMs);
// allowUserSwitch value doesn't matter for onSuspend = true
mUserService.onSuspend();
@@ -999,8 +1076,15 @@
executor.shutdown();
}
- private void cancelWaitingForCompletion() {
- mIsListenerWaitingCancelled.set(true);
+ private void clearWaitingForCompletion(boolean clearQueue) {
+ if (clearQueue) {
+ synchronized (mLock) {
+ mListenersWeAreWaitingFor.clear();
+ }
+ } else {
+ mIsListenerWaitingCancelled.set(true);
+ }
+
mListenerCompletionSem.release();
}
@@ -1174,7 +1258,7 @@
private void doHandleProcessingComplete() {
int listenerState = CarPowerManager.STATE_SHUTDOWN_ENTER;
synchronized (mLock) {
- cancelWaitingForCompletion();
+ clearWaitingForCompletion(/*clearQueue=*/false);
boolean shutdownOnFinish = (mActionOnFinish == ACTION_ON_FINISH_SHUTDOWN);
if (!shutdownOnFinish && mLastSleepEntryTime > mShutdownStartTime) {
// entered sleep after processing start. So this could be duplicate request.
@@ -1203,7 +1287,12 @@
}
private void doHandleMainDisplayStateChange(boolean on) {
- Slogf.w(TAG, "Unimplemented: doHandleMainDisplayStateChange() - on = %b", on);
+ Slogf.w(TAG, "Unimplemented: doHandleMainDisplayStateChange() - on = %b", on);
+ }
+
+ private void doHandlePowerPolicyNotification(String policyId) {
+ // Sending notification of power policy change triggered through CarPowerManager API.
+ notifyPowerPolicyChange(policyId, /* upToDaemon= */ true, /* force= */ false);
}
/**
@@ -1357,10 +1446,13 @@
Preconditions.checkArgument(policyId != null, "policyId cannot be null");
Preconditions.checkArgument(!policyId.startsWith(PolicyReader.SYSTEM_POWER_POLICY_PREFIX),
"System power policy cannot be applied by apps");
- int status = applyPowerPolicy(policyId, /* upToDaemon= */ true, /* force= */ false);
+ int status = applyPowerPolicy(policyId, /* delayNotification= */ true,
+ /* upToDaemon= */ true, /* force= */ false);
if (status != PolicyOperationStatus.OK) {
throw new IllegalArgumentException(PolicyOperationStatus.errorCodeToString(status));
}
+ Slogf.d(TAG, "Queueing power policy notification (id: %s) in the handler", policyId);
+ mHandler.handlePowerPolicyNotification(policyId);
}
/**
@@ -1495,12 +1587,16 @@
// the power policy or the policy group passed from car power policy daemon, and notifies
// the current power policy to the daemon.
if (currentPowerPolicyId == null || currentPowerPolicyId.isEmpty()) {
- int status = applyPowerPolicy(state.policyId, /* upToDaemon= */ false,
- /* force= */ false);
+ Slogf.i(TAG, "Attempting to apply the power policy(%s) from the daemon",
+ state.policyId);
+ int status = applyPowerPolicy(state.policyId, /* delayNotification= */ false,
+ /* upToDaemon= */ false, /* force= */ false);
if (status != PolicyOperationStatus.OK) {
Slogf.w(TAG, PolicyOperationStatus.errorCodeToString(status));
}
} else {
+ Slogf.i(TAG, "CPMS applied power policy(%s) before connecting to the daemon. Notifying "
+ + "to the daemon...", currentPowerPolicyId);
notifyPowerPolicyChangeToDaemon(currentPowerPolicyId, /* force= */ true);
}
if (currentPolicyGroupId == null || currentPolicyGroupId.isEmpty()) {
@@ -1527,10 +1623,11 @@
}
@PolicyOperationStatus.ErrorCode
- private int applyPowerPolicy(@Nullable String policyId, boolean upToDaemon, boolean force) {
+ private int applyPowerPolicy(@Nullable String policyId, boolean delayNotification,
+ boolean upToDaemon, boolean force) {
CarPowerPolicy policy = mPolicyReader.getPowerPolicy(policyId);
if (policy == null) {
- int error = PolicyOperationStatus.ERROR_APPLY_POWER_POLICY;
+ int error = PolicyOperationStatus.ERROR_NOT_REGISTERED_POWER_POLICY_ID;
Slogf.w(TAG, PolicyOperationStatus.errorCodeToString(error, policyId));
return error;
}
@@ -1544,7 +1641,9 @@
mCurrentPowerPolicyId = policyId;
}
mPowerComponentHandler.applyPowerPolicy(policy);
- notifyPowerPolicyChange(policyId, upToDaemon, force);
+ if (!delayNotification) {
+ notifyPowerPolicyChange(policyId, upToDaemon, force);
+ }
Slogf.i(TAG, "The current power policy is %s", policyId);
return PolicyOperationStatus.OK;
}
@@ -1583,7 +1682,8 @@
mPendingPowerPolicyId = null;
}
if (policyId != null) { // Pending policy exist
- int status = applyPowerPolicy(policyId, /* upToDaemon= */ true, /* force= */ true);
+ int status = applyPowerPolicy(policyId, /* delayNotification= */ false,
+ /* upToDaemon= */ true, /* force= */ true);
if (status != PolicyOperationStatus.OK) {
Slogf.w(TAG, "Failed to cancel system power policy: %s",
PolicyOperationStatus.errorCodeToString(status));
@@ -1771,6 +1871,7 @@
private static final int MSG_DISPLAY_BRIGHTNESS_CHANGE = 1;
private static final int MSG_MAIN_DISPLAY_STATE_CHANGE = 2;
private static final int MSG_PROCESSING_COMPLETE = 3;
+ private static final int MSG_POWER_POLICY_NOTIFICATION = 4;
// Do not handle this immediately but with some delay as there can be a race between
// display off due to rear view camera and delivery to here.
@@ -1809,11 +1910,17 @@
removeMessages(MSG_PROCESSING_COMPLETE);
}
+ private void handlePowerPolicyNotification(String policyId) {
+ Message msg = obtainMessage(MSG_POWER_POLICY_NOTIFICATION, policyId);
+ sendMessage(msg);
+ }
+
private void cancelAll() {
removeMessages(MSG_POWER_STATE_CHANGE);
removeMessages(MSG_DISPLAY_BRIGHTNESS_CHANGE);
removeMessages(MSG_MAIN_DISPLAY_STATE_CHANGE);
removeMessages(MSG_PROCESSING_COMPLETE);
+ removeMessages(MSG_POWER_POLICY_NOTIFICATION);
}
@Override
@@ -1836,6 +1943,9 @@
case MSG_PROCESSING_COMPLETE:
service.doHandleProcessingComplete();
break;
+ case MSG_POWER_POLICY_NOTIFICATION:
+ service.doHandlePowerPolicyNotification((String) msg.obj);
+ break;
}
}
}
@@ -1967,6 +2077,14 @@
: PowerState.SHUTDOWN_TYPE_POWER_OFF);
}
+ CpmsState(int state, int carPowerStateListenerState, boolean canPostpone,
+ int shutdownType) {
+ this.mCanPostpone = canPostpone;
+ this.mCarPowerStateListenerState = carPowerStateListenerState;
+ this.mState = state;
+ this.mShutdownType = shutdownType;
+ }
+
public String name() {
return new StringBuilder()
.append(stateToString())
@@ -2187,7 +2305,8 @@
}
boolean isPreemptive = mPolicyReader.isPreemptivePowerPolicy(powerPolicyId);
int status = isPreemptive ? applyPreemptivePowerPolicy(powerPolicyId)
- : applyPowerPolicy(powerPolicyId, /* upToDaemon= */ true, /* force= */ false);
+ : applyPowerPolicy(powerPolicyId, /* delayNotification= */ false,
+ /* upToDaemon= */ true, /* force= */ false);
if (status != PolicyOperationStatus.OK) {
writer.println(PolicyOperationStatus.errorCodeToString(status));
return false;
@@ -2329,8 +2448,7 @@
* SHUTDOWN_PREPARE.
*/
public static boolean isCompletionAllowed(@CarPowerManager.CarPowerState int state) {
- return CarPowerManager.isCompletionAllowed(state)
- || state == CarPowerManager.STATE_SHUTDOWN_PREPARE;
+ return CarPowerManager.isCompletionAllowed(state);
}
/**
@@ -2419,4 +2537,17 @@
return "Unknown";
}
}
+
+ private void waitForCompletionWithShutdownPostpone(
+ @CarPowerManager.CarPowerState int carPowerStateListenerState, long timeoutMs,
+ Runnable taskAtCompletion, long intervalMs) {
+ Runnable taskAtInterval = () -> {
+ mHal.sendShutdownPostpone(SHUTDOWN_EXTEND_MAX_MS);
+ };
+
+ Slogf.i(TAG, "Start waiting for listener completion for %s",
+ powerStateToString(carPowerStateListenerState));
+
+ waitForCompletion(taskAtCompletion, taskAtInterval, timeoutMs, intervalMs);
+ }
}
diff --git a/service/src/com/android/car/power/PolicyReader.java b/service/src/com/android/car/power/PolicyReader.java
index eb93d86..9a2e9f3 100644
--- a/service/src/com/android/car/power/PolicyReader.java
+++ b/service/src/com/android/car/power/PolicyReader.java
@@ -306,8 +306,7 @@
@VisibleForTesting
void initPolicies() {
mRegisteredPowerPolicies = new ArrayMap<>();
- mRegisteredPowerPolicies.put(POWER_POLICY_ID_ALL_ON, POWER_POLICY_ALL_ON);
- mRegisteredPowerPolicies.put(POWER_POLICY_ID_INITIAL_ON, POWER_POLICY_INITIAL_ON);
+ registerBasicPowerPolicies();
mPolicyGroups = new ArrayMap<>();
@@ -369,6 +368,7 @@
validatePolicyGroups(policyGroups, registeredPolicies);
mRegisteredPowerPolicies = registeredPolicies;
+ registerBasicPowerPolicies();
mPolicyGroups = policyGroups;
reconstructSystemPowerPolicy(systemPolicyOverride);
}
@@ -612,6 +612,11 @@
CarServiceUtils.toIntArray(disabledComponents)));
}
+ private void registerBasicPowerPolicies() {
+ mRegisteredPowerPolicies.put(POWER_POLICY_ID_ALL_ON, POWER_POLICY_ALL_ON);
+ mRegisteredPowerPolicies.put(POWER_POLICY_ID_INITIAL_ON, POWER_POLICY_INITIAL_ON);
+ }
+
private void removeComponent(List<Integer> components, int component) {
int index = components.lastIndexOf(component);
if (index != -1) {
diff --git a/service/src/com/android/car/telemetry/CarTelemetryService.java b/service/src/com/android/car/telemetry/CarTelemetryService.java
index f4cb320..591f84f 100644
--- a/service/src/com/android/car/telemetry/CarTelemetryService.java
+++ b/service/src/com/android/car/telemetry/CarTelemetryService.java
@@ -43,6 +43,7 @@
import android.content.Context;
import android.os.Handler;
import android.os.HandlerThread;
+import android.os.ParcelFileDescriptor;
import android.os.PersistableBundle;
import android.os.RemoteException;
import android.os.ResultReceiver;
@@ -57,7 +58,10 @@
import com.android.car.OnShutdownReboot;
import com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport;
import com.android.car.internal.util.IndentingPrintWriter;
+import com.android.car.power.CarPowerManagementService;
import com.android.car.systeminterface.SystemInterface;
+import com.android.car.telemetry.MetricsReportProto.MetricsReportContainer;
+import com.android.car.telemetry.MetricsReportProto.MetricsReportList;
import com.android.car.telemetry.databroker.DataBroker;
import com.android.car.telemetry.databroker.DataBrokerImpl;
import com.android.car.telemetry.databroker.ScriptExecutionTask;
@@ -65,12 +69,16 @@
import com.android.car.telemetry.sessioncontroller.SessionController;
import com.android.car.telemetry.systemmonitor.SystemMonitor;
import com.android.car.telemetry.systemmonitor.SystemMonitorEvent;
+import com.android.car.telemetry.util.IoUtils;
+import com.android.car.telemetry.util.MetricsReportProtoUtils;
import com.android.internal.annotations.VisibleForTesting;
+import com.google.protobuf.ByteString;
import com.google.protobuf.InvalidProtocolBufferException;
+import java.io.DataOutputStream;
import java.io.File;
-import java.time.Duration;
+import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import java.util.Set;
@@ -83,7 +91,6 @@
public static final boolean DEBUG = false; // STOPSHIP if true
- private static final String PUBLISHER_DIR = "publisher";
public static final String TELEMETRY_DIR = "telemetry";
/**
@@ -100,6 +107,7 @@
public static final int TASK_PRIORITY_LOW = 100;
private final Context mContext;
+ private final CarPowerManagementService mCarPowerManagementService;
private final CarPropertyService mCarPropertyService;
private final Dependencies mDependencies;
private final HandlerThread mTelemetryThread = CarServiceUtils.getHandlerThread(
@@ -119,7 +127,7 @@
public void onReportFinished(@NonNull String metricsConfigName) {
cleanupMetricsConfig(metricsConfigName); // schedules next script execution task
if (mResultStore.getErrorResult(metricsConfigName, false) != null
- || mResultStore.getFinalResult(metricsConfigName, false) != null) {
+ || mResultStore.getMetricsReports(metricsConfigName, false) != null) {
onReportReady(metricsConfigName);
}
}
@@ -128,7 +136,7 @@
public void onReportFinished(
@NonNull String metricsConfigName, @NonNull PersistableBundle report) {
cleanupMetricsConfig(metricsConfigName); // schedules next script execution task
- mResultStore.putFinalResult(metricsConfigName, report);
+ mResultStore.putMetricsReport(metricsConfigName, report, /* finished = */ true);
onReportReady(metricsConfigName);
}
@@ -145,8 +153,7 @@
@NonNull String metricsConfigName,
@NonNull PersistableBundle report,
@Nullable PersistableBundle state) {
- // TODO(b/229134432): ResultStore should be able to store multiple reports
- mResultStore.putFinalResult(metricsConfigName, report);
+ mResultStore.putMetricsReport(metricsConfigName, report, /* finished = */ false);
if (state != null) {
mResultStore.putInterimResult(metricsConfigName, state);
}
@@ -176,12 +183,11 @@
CarPropertyService carPropertyService,
Handler handler,
Context context,
- File publisherDirectory,
SessionController sessionController, ResultStore resultStore,
UidPackageMapper uidMapper) {
return new PublisherFactory(
- carPropertyService, handler, context, publisherDirectory, sessionController,
- resultStore, uidMapper);
+ carPropertyService, handler, context, sessionController, resultStore,
+ uidMapper);
}
/** Returns a new UidPackageMapper instance. */
@@ -190,18 +196,24 @@
}
}
- public CarTelemetryService(Context context, CarPropertyService carPropertyService) {
- this(context, carPropertyService, new Dependencies(), null, null);
+ public CarTelemetryService(
+ Context context,
+ CarPowerManagementService carPowerManagementService,
+ CarPropertyService carPropertyService) {
+ this(context, carPowerManagementService, carPropertyService, new Dependencies(),
+ /* dataBroker = */ null, /* sessionController = */ null);
}
@VisibleForTesting
CarTelemetryService(
Context context,
+ CarPowerManagementService carPowerManagementService,
CarPropertyService carPropertyService,
Dependencies deps,
DataBroker dataBroker,
SessionController sessionController) {
mContext = context;
+ mCarPowerManagementService = carPowerManagementService;
mCarPropertyService = carPropertyService;
mDependencies = deps;
mUidMapper = mDependencies.getUidPackageMapper(mContext, mTelemetryHandler);
@@ -216,23 +228,20 @@
CarLog.TAG_TELEMETRY, TraceHelper.TRACE_TAG_CAR_SERVICE);
mTelemetryThreadTraceLog.traceBegin("init");
SystemInterface systemInterface = CarLocalServices.getService(SystemInterface.class);
- // starts metrics collection after boot complete
- systemInterface.scheduleActionForBootCompleted(
- this::startMetricsCollection, Duration.ZERO);
+ // starts metrics collection after CarService initializes.
+ CarServiceUtils.runOnMain(this::startMetricsCollection);
// full root directory path is /data/system/car/telemetry
File rootDirectory = new File(systemInterface.getSystemCarDir(), TELEMETRY_DIR);
- File publisherDirectory = new File(rootDirectory, PUBLISHER_DIR);
- publisherDirectory.mkdirs();
// initialize all necessary components
mUidMapper.init();
mMetricsConfigStore = new MetricsConfigStore(rootDirectory);
- mResultStore = new ResultStore(rootDirectory);
+ mResultStore = new ResultStore(mContext, rootDirectory);
if (mSessionController == null) {
- mSessionController = new SessionController(mContext, mTelemetryHandler);
+ mSessionController = new SessionController(
+ mCarPowerManagementService, mTelemetryHandler);
}
mPublisherFactory = mDependencies.getPublisherFactory(mCarPropertyService,
- mTelemetryHandler, mContext, publisherDirectory, mSessionController,
- mResultStore, mUidMapper);
+ mTelemetryHandler, mContext, mSessionController, mResultStore, mUidMapper);
if (mDataBroker == null) {
mDataBroker = new DataBrokerImpl(mContext, mPublisherFactory, mResultStore,
mTelemetryThreadTraceLog);
@@ -263,7 +272,7 @@
mUidMapper.release();
mTelemetryThreadTraceLog.traceEnd();
});
- mTelemetryThread.quitSafely();
+ CarServiceUtils.runOnLooperSync(mTelemetryThread.getLooper(), () -> {});
}
@Override
@@ -285,14 +294,19 @@
}
writer.println();
}
- // Print info on stored final results. Configs are inactive after producing final result.
- ArrayMap<String, PersistableBundle> finalResults = mResultStore.getAllFinalResults();
+ // Print info on stored final results.
+ ArrayMap<String, MetricsReportList> finalResults = mResultStore.getAllMetricsReports();
writer.println("Final Results");
writer.println();
for (int i = 0; i < finalResults.size(); i++) {
- writer.println(" Config name: " + finalResults.keyAt(i));
- writer.println(" Bundle keys: "
- + Arrays.toString(finalResults.valueAt(i).keySet().toArray()));
+ writer.println("\tConfig name: " + finalResults.keyAt(i));
+ MetricsReportList reportList = finalResults.valueAt(i);
+ writer.println("\tTotal number of metrics reports: " + reportList.getReportCount());
+ for (int j = 0; j < reportList.getReportCount(); j++) {
+ writer.println("\tBundle keys for report " + j + ":");
+ PersistableBundle report = MetricsReportProtoUtils.getBundle(reportList, j);
+ writer.println("\t\t" + Arrays.toString(report.keySet().toArray()));
+ }
writer.println();
}
// Print info on stored errors. Configs are inactive after producing errors.
@@ -300,13 +314,13 @@
writer.println("Errors");
writer.println();
for (int i = 0; i < errors.size(); i++) {
- writer.println(" Config name: " + errors.keyAt(i));
+ writer.println("\tConfig name: " + errors.keyAt(i));
TelemetryProto.TelemetryError error = errors.valueAt(i);
- writer.println(" Error");
- writer.println(" Type: " + error.getErrorType());
- writer.println(" Message: " + error.getMessage());
+ writer.println("\tError");
+ writer.println("\t\tType: " + error.getErrorType());
+ writer.println("\t\tMessage: " + error.getMessage());
if (error.hasStackTrace() && !error.getStackTrace().isEmpty()) {
- writer.println(" Stack trace: " + error.getStackTrace());
+ writer.println("\t\tStack trace: " + error.getStackTrace());
}
writer.println();
}
@@ -435,22 +449,21 @@
"Getting report for metrics config " + metricsConfigName);
}
mTelemetryThreadTraceLog.traceBegin("getFinishedReport");
- PersistableBundle report;
+ MetricsReportList reportList;
TelemetryProto.TelemetryError error;
- if ((report = mResultStore.getFinalResult(metricsConfigName, true)) != null) {
- sendResult(listener, metricsConfigName, /* report = */ report, /* error = */ null,
- /* status = */ STATUS_GET_METRICS_CONFIG_FINISHED);
+ if ((reportList = mResultStore.getMetricsReports(metricsConfigName, true)) != null) {
+ streamReports(listener, metricsConfigName, reportList);
} else if (mResultStore.getInterimResult(metricsConfigName) != null) {
- sendResult(listener, metricsConfigName, /* report = */ null, /* error = */null,
+ sendResult(listener, metricsConfigName, /* reportFd = */ null, /* error = */null,
/* status = */ STATUS_GET_METRICS_CONFIG_INTERIM_RESULTS);
} else if ((error = mResultStore.getErrorResult(metricsConfigName, true)) != null) {
- sendResult(listener, metricsConfigName, /* report = */ null, /* error = */ error,
+ sendResult(listener, metricsConfigName, /* reportFd = */ null, /* error = */ error,
/* status = */ STATUS_GET_METRICS_CONFIG_RUNTIME_ERROR);
} else if (mMetricsConfigStore.containsConfig(metricsConfigName)) {
- sendResult(listener, metricsConfigName, /* report = */ null, /* error = */ null,
+ sendResult(listener, metricsConfigName, /* reportFd = */ null, /* error = */ null,
/* status = */ STATUS_GET_METRICS_CONFIG_PENDING);
} else {
- sendResult(listener, metricsConfigName, /* report = */ null, /* error = */ null,
+ sendResult(listener, metricsConfigName, /* reportFd = */ null, /* error = */ null,
/* status = */ STATUS_GET_METRICS_CONFIG_DOES_NOT_EXIST);
}
mTelemetryThreadTraceLog.traceEnd();
@@ -469,18 +482,19 @@
Slogf.d(CarLog.TAG_TELEMETRY, "Getting all reports");
}
mTelemetryThreadTraceLog.traceBegin("getAllFinishedReports");
- ArrayMap<String, PersistableBundle> reports = mResultStore.getAllFinalResults();
- for (int i = 0; i < reports.size(); i++) {
- mResultStore.removeResult(reports.keyAt(i));
- sendResult(listener, reports.keyAt(i), reports.valueAt(i),
- /* error = */ null, STATUS_GET_METRICS_CONFIG_FINISHED);
- }
- ArrayMap<String, TelemetryProto.TelemetryError> errors =
- mResultStore.getAllErrorResults();
- for (int i = 0; i < errors.size(); i++) {
- mResultStore.removeResult(errors.keyAt(i));
- sendResult(listener, errors.keyAt(i), /* report = */ null,
- errors.valueAt(i), STATUS_GET_METRICS_CONFIG_RUNTIME_ERROR);
+ Set<String> finishedReports = mResultStore.getFinishedMetricsConfigNames();
+ // TODO(b/236843813): Optimize sending multiple reports
+ for (String configName : finishedReports) {
+ MetricsReportList reportList =
+ mResultStore.getMetricsReports(configName, true);
+ if (reportList != null) {
+ streamReports(listener, configName, reportList);
+ continue;
+ }
+ TelemetryProto.TelemetryError telemetryError =
+ mResultStore.getErrorResult(configName, true);
+ sendResult(listener, configName, /* reportFd = */ null, telemetryError,
+ STATUS_GET_METRICS_CONFIG_RUNTIME_ERROR);
}
mTelemetryThreadTraceLog.traceEnd();
});
@@ -541,6 +555,48 @@
.collect(toList());
}
+ /**
+ * Streams the reports in the reportList to the client using a pipe to prevent exceeding
+ * binder memory limit.
+ */
+ private void streamReports(
+ @NonNull ICarTelemetryReportListener listener,
+ @NonNull String metricsConfigName,
+ @NonNull MetricsReportList reportList) {
+ if (reportList.getReportCount() == 0) {
+ sendResult(listener, metricsConfigName, null, null, STATUS_GET_METRICS_CONFIG_PENDING);
+ return;
+ }
+ // if the last report is produced via 'on_script_finished', the config is finished
+ int getReportStatus =
+ reportList.getReport(reportList.getReportCount() - 1).getIsLastReport()
+ ? STATUS_GET_METRICS_CONFIG_FINISHED
+ : STATUS_GET_METRICS_CONFIG_PENDING;
+ ParcelFileDescriptor[] fds = null;
+ try {
+ fds = ParcelFileDescriptor.createPipe();
+ } catch (IOException e) {
+ Slogf.w(CarLog.TAG_TELEMETRY, "Failed to create pipe to stream reports", e);
+ return;
+ }
+ // send the file descriptor to the client so it can start reading
+ sendResult(listener, metricsConfigName, fds[0], /* error = */ null, getReportStatus);
+ try (DataOutputStream dataOutputStream = new DataOutputStream(
+ new ParcelFileDescriptor.AutoCloseOutputStream(fds[1]))) {
+ for (MetricsReportContainer reportContainer : reportList.getReportList()) {
+ ByteString reportBytes = reportContainer.getReportBytes();
+ // write the report size in bytes to the pipe, so the read end of the pipe
+ // knows how many bytes to read for this report
+ dataOutputStream.writeInt(reportBytes.size());
+ dataOutputStream.write(reportBytes.toByteArray());
+ }
+ } catch (IOException e) {
+ Slogf.w(CarLog.TAG_TELEMETRY, "Failed to write reports to pipe", e);
+ }
+ // close the read end of the pipe, write end of the pipe should be auto-closed
+ IoUtils.closeQuietly(fds[0]);
+ }
+
@Nullable
private byte[] getBytes(@Nullable TelemetryProto.TelemetryError error) {
if (error == null) {
@@ -552,11 +608,11 @@
private void sendResult(
@NonNull ICarTelemetryReportListener listener,
@NonNull String metricsConfigName,
- @Nullable PersistableBundle report,
+ @Nullable ParcelFileDescriptor reportFd,
@Nullable TelemetryProto.TelemetryError error,
@CarTelemetryManager.MetricsReportStatus int status) {
try {
- listener.onResult(metricsConfigName, report, getBytes(error), status);
+ listener.onResult(metricsConfigName, reportFd, getBytes(error), status);
} catch (RemoteException e) {
Slogf.w(CarLog.TAG_TELEMETRY, "error with ICarTelemetryReportListener", e);
}
@@ -624,6 +680,7 @@
*/
private void cleanupMetricsConfig(String metricsConfigName) {
mMetricsConfigStore.removeMetricsConfig(metricsConfigName);
+ mResultStore.removeInterimResult(metricsConfigName);
mDataBroker.removeMetricsConfig(metricsConfigName);
mDataBroker.scheduleNextTask();
}
diff --git a/service/src/com/android/car/telemetry/ResultStore.java b/service/src/com/android/car/telemetry/ResultStore.java
index 324c802..8f9e73e 100644
--- a/service/src/com/android/car/telemetry/ResultStore.java
+++ b/service/src/com/android/car/telemetry/ResultStore.java
@@ -20,12 +20,18 @@
import android.annotation.Nullable;
import android.car.builtin.util.Slogf;
import android.car.telemetry.TelemetryProto;
+import android.content.Context;
import android.os.PersistableBundle;
+import android.provider.Settings;
import android.util.ArrayMap;
import android.util.AtomicFile;
import com.android.car.CarLog;
+import com.android.car.internal.util.IndentingPrintWriter;
+import com.android.car.telemetry.MetricsReportProto.MetricsReportContainer;
+import com.android.car.telemetry.MetricsReportProto.MetricsReportList;
import com.android.car.telemetry.util.IoUtils;
+import com.android.car.telemetry.util.MetricsReportProtoUtils;
import com.android.internal.annotations.VisibleForTesting;
import java.io.File;
@@ -36,7 +42,7 @@
import java.util.concurrent.TimeUnit;
/**
- * Disk storage for interim and final metrics statistics.
+ * Disk storage for interim and final metrics statistics, as well as for internal data.
* All methods in this class should be invoked from the telemetry thread.
*/
public class ResultStore {
@@ -51,29 +57,45 @@
static final String FINAL_RESULT_DIR = "final";
@VisibleForTesting
static final String PUBLISHER_STORAGE_DIR = "publisher";
+ /**
+ * The following are bundle keys for the annotations.
+ * The metrics report is annotated with the boot count, id, and timestamp.
+ * Together, boot count and id will help clients determine if any report had been dropped.
+ */
+ @VisibleForTesting
+ static final String BUNDLE_KEY_BOOT_COUNT = "metrics.report.boot_count";
+ @VisibleForTesting
+ static final String BUNDLE_KEY_ID = "metrics.report.id";
+ @VisibleForTesting
+ static final String BUNDLE_KEY_TIMESTAMP = "metrics.report.timestamp_millis";
/** Map keys are MetricsConfig names, which are also the file names in disk. */
private final ArrayMap<String, InterimResult> mInterimResultCache = new ArrayMap<>();
- private final ArrayMap<String, PersistableBundle> mFinalResultCache = new ArrayMap<>();
+ private final ArrayMap<String, MetricsReportList.Builder> mMetricsReportCache =
+ new ArrayMap<>();
private final ArrayMap<String, TelemetryProto.TelemetryError> mErrorCache = new ArrayMap<>();
- /** Keyed by publisher's class name. **/
+ /** Keyed by publisher's class name. */
private final ArrayMap<String, PersistableBundle> mPublisherCache = new ArrayMap<>();
+ /** Keyed by metrics config name, value is how many reports it produced since boot. */
+ private final ArrayMap<String, Integer> mReportCountMap = new ArrayMap<>();
+ private final Context mContext;
private final File mInterimResultDirectory;
private final File mErrorResultDirectory;
- private final File mFinalResultDirectory;
+ private final File mMetricsReportDirectory;
private final File mPublisherDataDirectory;
- public ResultStore(@NonNull File rootDirectory) {
+ public ResultStore(@NonNull Context context, @NonNull File rootDirectory) {
+ mContext = context;
mInterimResultDirectory = new File(rootDirectory, INTERIM_RESULT_DIR);
mErrorResultDirectory = new File(rootDirectory, ERROR_RESULT_DIR);
- mFinalResultDirectory = new File(rootDirectory, FINAL_RESULT_DIR);
+ mMetricsReportDirectory = new File(rootDirectory, FINAL_RESULT_DIR);
mPublisherDataDirectory = new File(rootDirectory, PUBLISHER_STORAGE_DIR);
mInterimResultDirectory.mkdirs();
mErrorResultDirectory.mkdirs();
- mFinalResultDirectory.mkdirs();
+ mMetricsReportDirectory.mkdirs();
mPublisherDataDirectory.mkdir();
- // load results into memory to reduce the frequency of disk access
+ // load interim results and internal data into memory to reduce the frequency of disk access
loadInterimResultsIntoMemory();
}
@@ -112,56 +134,52 @@
*
* @param metricsConfigName name of the MetricsConfig.
* @param deleteResult if true, the final result will be deleted from disk.
- * @return the final result as PersistableBundle if exists, null otherwise
+ * @return {@link MetricsReportList} that contains all report for the given config.
*/
@Nullable
- public PersistableBundle getFinalResult(
+ public MetricsReportList getMetricsReports(
@NonNull String metricsConfigName, boolean deleteResult) {
- // check in memory storage
- PersistableBundle result = mFinalResultCache.get(metricsConfigName);
- if (result != null) {
- if (deleteResult) {
- mFinalResultCache.remove(metricsConfigName);
- }
- return result;
+ // the reports may have been stored in memory
+ MetricsReportList.Builder reportList = mMetricsReportCache.get(metricsConfigName);
+ // if not, the reports may have been stored in disk
+ if (reportList == null) {
+ reportList = readMetricsReportList(metricsConfigName);
}
- // check persistent storage
- File file = new File(mFinalResultDirectory, metricsConfigName);
- // if no final result exists for this metrics config, return immediately
- if (!file.exists()) {
- return null;
+ if (deleteResult) {
+ mMetricsReportCache.remove(metricsConfigName);
+ IoUtils.deleteSilently(mMetricsReportDirectory, metricsConfigName);
}
- try {
- result = IoUtils.readBundle(file);
- if (deleteResult) {
- file.delete();
- }
- return result;
- } catch (IOException e) {
- Slogf.w(CarLog.TAG_TELEMETRY, "Failed to read from disk.", e);
- // TODO(b/197153560): record failure
- }
- return null;
+ return reportList == null ? null : reportList.build();
}
/**
- * Retrieves all final results, mapped to each config name.
+ * Retrieves all metrics reports for all configs, keyed by each config name. This call is
+ * not destructive, because this method is only used by
+ * {@link CarTelemetryService#dump(IndentingPrintWriter)}.
*
- * @return the final results mapped to config names.
+ * @return All available metrics reports keyed by config names.
*/
- public ArrayMap<String, PersistableBundle> getAllFinalResults() {
- ArrayMap<String, PersistableBundle> results = new ArrayMap<>(mFinalResultCache);
- File[] files = mFinalResultDirectory.listFiles();
+ @NonNull
+ public ArrayMap<String, MetricsReportList> getAllMetricsReports() {
+ // reports could be stored in two places, in memory and in disk
+ ArrayMap<String, MetricsReportList> results = new ArrayMap<>();
+ // first check the in-memory cache
+ for (int i = 0; i < mMetricsReportCache.size(); i++) {
+ results.put(mMetricsReportCache.keyAt(i), mMetricsReportCache.valueAt(i).build());
+ }
+ // also check the disk
+ File[] files = mMetricsReportDirectory.listFiles();
if (files == null) {
return results;
}
for (File file : files) {
- try {
- PersistableBundle finalResultBundle = IoUtils.readBundle(file);
- results.put(file.getName(), finalResultBundle);
- } catch (IOException e) {
- Slogf.w(CarLog.TAG_TELEMETRY, "Failed to read from disk.", e);
- // TODO(b/197153560): record failure
+ // if the metrics reports exist in memory, they have already been added to `results`
+ if (results.containsKey(file.getName())) {
+ continue; // skip already-added results
+ }
+ MetricsReportList.Builder reportList = readMetricsReportList(file.getName());
+ if (reportList != null) {
+ results.put(file.getName(), reportList.build());
}
}
return results;
@@ -205,7 +223,8 @@
}
/**
- * Retrieves all errors, mapped to each config name.
+ * Retrieves all errors, mapped to each config name. This call is not destructive because
+ * this method is only used by {@link CarTelemetryService#dump(IndentingPrintWriter)}.
*
* @return the map of errors to each config.
*/
@@ -274,21 +293,42 @@
}
/**
- * Stores final metrics in memory for the given
+ * Stores metrics report in memory for the given
* {@link android.car.telemetry.TelemetryProto.MetricsConfig}.
+ *
+ * If the report is produced via {@code on_metrics_report()} Lua callback, the config is not
+ * considered finished. If the report is produced via {@code on_script_finished()} Lua
+ * callback, the config is finished.
*/
- public void putFinalResult(
- @NonNull String metricsConfigName, @NonNull PersistableBundle result) {
- IoUtils.deleteSilently(mInterimResultDirectory, metricsConfigName);
- mInterimResultCache.remove(metricsConfigName);
- mFinalResultCache.put(metricsConfigName, result);
+ public void putMetricsReport(
+ @NonNull String metricsConfigName,
+ @NonNull PersistableBundle report,
+ boolean finished) {
+ // annotate the report with boot count, ID and timestamp
+ annotateReport(metricsConfigName, report);
+ // Every new report should be appended at the end of the report list. The previous reports
+ // may exist in the cache or in the disk. We need to check both places.
+ MetricsReportList.Builder reportList = mMetricsReportCache.get(metricsConfigName);
+ // if no previous reports found in memory, check if there is previous report in disk
+ if (reportList == null) {
+ reportList = readMetricsReportList(metricsConfigName);
+ }
+ // if no previous report found in memory and in disk, create a new MetricsReportList
+ if (reportList == null) {
+ reportList = MetricsReportList.newBuilder();
+ }
+ // add new metrics report
+ reportList = reportList.addReport(
+ MetricsReportContainer.newBuilder()
+ .setReportBytes(MetricsReportProtoUtils.getByteString(report))
+ .setIsLastReport(finished));
+ mMetricsReportCache.put(metricsConfigName, reportList);
}
/** Stores the error object produced by the script. */
public void putErrorResult(
@NonNull String metricsConfigName, @NonNull TelemetryProto.TelemetryError error) {
- IoUtils.deleteSilently(mInterimResultDirectory, metricsConfigName);
- mInterimResultCache.remove(metricsConfigName);
+ removeInterimResult(metricsConfigName);
mErrorCache.put(metricsConfigName, error);
}
@@ -305,6 +345,30 @@
}
/**
+ * Deletes interim result associated with the given MetricsConfig name.
+ */
+ public void removeInterimResult(@NonNull String metricsConfigName) {
+ mInterimResultCache.remove(metricsConfigName);
+ IoUtils.deleteSilently(mInterimResultDirectory, metricsConfigName);
+ }
+
+ /**
+ * Deletes metrics reports associated with the given MetricsConfig name.
+ */
+ public void removeMetricsReports(@NonNull String metricsConfigName) {
+ mMetricsReportCache.remove(metricsConfigName);
+ IoUtils.deleteSilently(mMetricsReportDirectory, metricsConfigName);
+ }
+
+ /**
+ * Deletes error result associated with the given MetricsConfig name.
+ */
+ public void removeErrorResult(@NonNull String metricsConfigName) {
+ mErrorCache.remove(metricsConfigName);
+ IoUtils.deleteSilently(mErrorResultDirectory, metricsConfigName);
+ }
+
+ /**
* Deletes associated publisher data.
*/
public void removePublisherData(@NonNull String publisherName) {
@@ -313,26 +377,24 @@
}
/**
- * Deletes script result associated with the given config name. If result does not exist, this
+ * Deletes all data associated with the given config name. If result does not exist, this
* method does not do anything.
*/
public void removeResult(@NonNull String metricsConfigName) {
- mInterimResultCache.remove(metricsConfigName);
- mFinalResultCache.remove(metricsConfigName);
- mErrorCache.remove(metricsConfigName);
- IoUtils.deleteSilently(mInterimResultDirectory, metricsConfigName);
- IoUtils.deleteSilently(mFinalResultDirectory, metricsConfigName);
- IoUtils.deleteSilently(mErrorResultDirectory, metricsConfigName);
+ removeInterimResult(metricsConfigName);
+ removeMetricsReports(metricsConfigName);
+ removeErrorResult(metricsConfigName);
+ mReportCountMap.remove(metricsConfigName);
}
/** Deletes all interim and final results. */
public void removeAllResults() {
mInterimResultCache.clear();
- mFinalResultCache.clear();
+ mMetricsReportCache.clear();
mErrorCache.clear();
mPublisherCache.clear();
IoUtils.deleteAllSilently(mInterimResultDirectory);
- IoUtils.deleteAllSilently(mFinalResultDirectory);
+ IoUtils.deleteAllSilently(mMetricsReportDirectory);
IoUtils.deleteAllSilently(mErrorResultDirectory);
IoUtils.deleteAllSilently(mPublisherDataDirectory);
}
@@ -340,12 +402,13 @@
/**
* Returns the names of MetricsConfigs whose script reached a terminal state.
*/
+ @NonNull
public Set<String> getFinishedMetricsConfigNames() {
HashSet<String> configNames = new HashSet<>();
- configNames.addAll(mFinalResultCache.keySet());
+ configNames.addAll(mMetricsReportCache.keySet());
configNames.addAll(mErrorCache.keySet());
// prevent NPE
- String[] fileNames = mFinalResultDirectory.list();
+ String[] fileNames = mMetricsReportDirectory.list();
if (fileNames != null) {
configNames.addAll(Arrays.asList(fileNames));
}
@@ -359,11 +422,11 @@
/** Persists data to disk and deletes stale data. */
public void flushToDisk() {
writeInterimResultsToFile();
- writeFinalResultsToFile();
+ writeMetricsReportsToFile();
writeErrorsToFile();
writePublisherCacheToFile();
IoUtils.deleteOldFiles(STALE_THRESHOLD_MILLIS,
- mInterimResultDirectory, mFinalResultDirectory, mErrorResultDirectory,
+ mInterimResultDirectory, mMetricsReportDirectory, mErrorResultDirectory,
mPublisherDataDirectory);
}
@@ -384,11 +447,10 @@
});
}
-
- private void writeFinalResultsToFile() {
- mFinalResultCache.forEach((metricsConfigName, bundle) -> {
+ private void writeMetricsReportsToFile() {
+ mMetricsReportCache.forEach((metricsConfigName, reportList) -> {
try {
- IoUtils.writeBundle(mFinalResultDirectory, metricsConfigName, bundle);
+ IoUtils.writeProto(mMetricsReportDirectory, metricsConfigName, reportList.build());
} catch (IOException e) {
Slogf.w(CarLog.TAG_TELEMETRY, "Failed to write result to file", e);
// TODO(b/197153560): record failure
@@ -418,27 +480,67 @@
});
}
+ /**
+ * Gets the {@link MetricsReportList} for the given metricsConfigName from disk.
+ * If no report exists, return null.
+ */
+ @Nullable
+ private MetricsReportList.Builder readMetricsReportList(@NonNull String metricsConfigName) {
+ // check persistent storage
+ File file = new File(mMetricsReportDirectory, metricsConfigName);
+ // if no error exists for this metrics config, return immediately
+ if (!file.exists()) {
+ return null;
+ }
+ try {
+ // return the mutable builder because ResultStore will be modifying the list frequently
+ return MetricsReportList.parseFrom(new AtomicFile(file).readFully()).toBuilder();
+ } catch (IOException e) {
+ Slogf.w(CarLog.TAG_TELEMETRY, "Failed to get report list from disk.", e);
+ // TODO(b/197153560): record failure
+ }
+ return null;
+ }
+
+ /**
+ * Annotates the report with boot count, id, and timestamp.
+ *
+ * ResultStore will keep track of how many reports are produced by each config since boot.
+ */
+ private void annotateReport(
+ @NonNull String metricsConfigName, @NonNull PersistableBundle report) {
+ report.putLong(BUNDLE_KEY_TIMESTAMP, System.currentTimeMillis());
+ report.putInt(
+ BUNDLE_KEY_BOOT_COUNT,
+ Settings.Global.getInt(
+ mContext.getContentResolver(), Settings.Global.BOOT_COUNT, -1));
+ int id = mReportCountMap.getOrDefault(metricsConfigName, 0);
+ id++;
+ report.putInt(BUNDLE_KEY_ID, id);
+ mReportCountMap.put(metricsConfigName, id);
+ }
+
/** Wrapper around a result and whether the result should be written to disk. */
- static final class InterimResult {
+ private static final class InterimResult {
private final PersistableBundle mBundle;
private final boolean mDirty;
- InterimResult(@NonNull PersistableBundle bundle) {
+ private InterimResult(@NonNull PersistableBundle bundle) {
mBundle = bundle;
mDirty = false;
}
- InterimResult(@NonNull PersistableBundle bundle, boolean dirty) {
+ private InterimResult(@NonNull PersistableBundle bundle, boolean dirty) {
mBundle = bundle;
mDirty = dirty;
}
@NonNull
- PersistableBundle getBundle() {
+ private PersistableBundle getBundle() {
return mBundle;
}
- boolean isDirty() {
+ private boolean isDirty() {
return mDirty;
}
}
diff --git a/service/src/com/android/car/telemetry/databroker/DataBrokerImpl.java b/service/src/com/android/car/telemetry/databroker/DataBrokerImpl.java
index 7f32be7..74e2bbd 100644
--- a/service/src/com/android/car/telemetry/databroker/DataBrokerImpl.java
+++ b/service/src/com/android/car/telemetry/databroker/DataBrokerImpl.java
@@ -466,6 +466,14 @@
mPublisherCountArray.append(
task.getPublisherType(),
mPublisherCountArray.get(task.getPublisherType()) - 1);
+
+ if (task.bypassScriptExecutor()) {
+ // delegate to DataBrokerListener to handle storing data and scheduling next task
+ mDataBrokerListener.onMetricsReport(task.getMetricsConfig().getName(),
+ task.getData(), /* state= */ null);
+ return;
+ }
+
// update current config name because a script is currently running
mCurrentMetricsConfigName = task.getMetricsConfig().getName();
mScriptExecutionTraceLog.traceBegin(
diff --git a/service/src/com/android/car/telemetry/databroker/DataSubscriber.java b/service/src/com/android/car/telemetry/databroker/DataSubscriber.java
index 49693e9..ab77318 100644
--- a/service/src/com/android/car/telemetry/databroker/DataSubscriber.java
+++ b/service/src/com/android/car/telemetry/databroker/DataSubscriber.java
@@ -28,6 +28,12 @@
* All methods of this class must be accessed on telemetry thread.
*/
public class DataSubscriber {
+ /**
+ * Binder transaction size limit is 1MB for all binders per process, so for large script input
+ * file pipe will be used to transfer the data to script executor instead of binder call. This
+ * is the input size threshold above which piping is used.
+ */
+ public static final int SCRIPT_INPUT_SIZE_THRESHOLD_BYTES = 20 * 1024; // 20 kb
private final DataBroker mDataBroker;
private final TelemetryProto.MetricsConfig mMetricsConfig;
diff --git a/service/src/com/android/car/telemetry/databroker/ScriptExecutionTask.java b/service/src/com/android/car/telemetry/databroker/ScriptExecutionTask.java
index 5aadf8c..796792c 100644
--- a/service/src/com/android/car/telemetry/databroker/ScriptExecutionTask.java
+++ b/service/src/com/android/car/telemetry/databroker/ScriptExecutionTask.java
@@ -93,6 +93,11 @@
return mIsLargeData;
}
+ /** Determines if the task is eligible to bypass script executor. */
+ public boolean bypassScriptExecutor() {
+ return getHandlerName().isEmpty();
+ }
+
@Override
public int compareTo(@NonNull ScriptExecutionTask other) {
if (getPriority() < other.getPriority()) {
diff --git a/service/src/com/android/car/telemetry/publisher/CarTelemetrydPublisher.java b/service/src/com/android/car/telemetry/publisher/CarTelemetrydPublisher.java
index 10da547..308c6ed 100644
--- a/service/src/com/android/car/telemetry/publisher/CarTelemetrydPublisher.java
+++ b/service/src/com/android/car/telemetry/publisher/CarTelemetrydPublisher.java
@@ -25,17 +25,21 @@
import android.car.telemetry.TelemetryProto;
import android.os.Handler;
import android.os.IBinder;
+import android.os.PersistableBundle;
import android.os.RemoteException;
+import android.util.ArraySet;
+import android.util.SparseArray;
import com.android.automotive.telemetry.CarDataProto;
import com.android.car.CarLog;
import com.android.car.telemetry.databroker.DataSubscriber;
import com.android.car.telemetry.sessioncontroller.SessionAnnotation;
+import com.android.car.telemetry.sessioncontroller.SessionController;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.Preconditions;
import java.util.ArrayList;
-import java.util.stream.Collectors;
+import java.util.Iterator;
/**
* Publisher for cartelemtryd service (aka ICarTelemetry).
@@ -51,13 +55,11 @@
private static final String SERVICE_NAME = ICarTelemetryInternal.DESCRIPTOR + "/default";
private static final int BINDER_FLAGS = 0;
- private ICarTelemetryInternal mCarTelemetryInternal;
-
- private final ArrayList<DataSubscriber> mSubscribers = new ArrayList<>();
-
+ private final SparseArray<ArrayList<DataSubscriber>> mCarIdSubscriberLookUp =
+ new SparseArray<>();
// All the methods in this class are expected to be called on this handler's thread.
private final Handler mTelemetryHandler;
-
+ private final SessionController mSessionController;
private final ICarDataListener mListener = new ICarDataListener.Stub() {
@Override
public void onCarDataReceived(
@@ -69,6 +71,7 @@
// TODO(b/189142577): Create custom Handler and post message to improve performance
mTelemetryHandler.post(() -> onCarDataListReceived(dataList));
}
+
@Override
public String getInterfaceHash() {
return ICarDataListener.HASH;
@@ -79,11 +82,16 @@
return ICarDataListener.VERSION;
}
};
+ private final IBinder.DeathRecipient mDeathRecipient = this::onBinderDied;
+
+ private ICarTelemetryInternal mCarTelemetryInternal;
CarTelemetrydPublisher(
- @NonNull PublisherListener listener, @NonNull Handler telemetryHandler) {
+ @NonNull PublisherListener listener, @NonNull Handler telemetryHandler,
+ @NonNull SessionController sessionController) {
super(listener);
this.mTelemetryHandler = telemetryHandler;
+ this.mSessionController = sessionController;
}
/** Called when binder for ICarTelemetry service is died. */
@@ -91,19 +99,24 @@
// TODO(b/189142577): Create custom Handler and post message to improve performance
mTelemetryHandler.post(() -> {
if (mCarTelemetryInternal != null) {
- mCarTelemetryInternal.asBinder().unlinkToDeath(this::onBinderDied, BINDER_FLAGS);
+ mCarTelemetryInternal.asBinder().unlinkToDeath(mDeathRecipient, BINDER_FLAGS);
mCarTelemetryInternal = null;
}
+ // TODO(b/241441036): Revisit actions taken when the binder dies.
onPublisherFailure(
getMetricsConfigs(),
new IllegalStateException("ICarTelemetryInternal binder died"));
});
}
- /** Connects to ICarTelemetryInternal service and starts listening for CarData. */
- private void connectToCarTelemetryd() {
+ /**
+ * Connects to ICarTelemetryInternal service and starts listening for CarData.
+ *
+ * @return true for success or if cartelemetryd is already connected, false otherwise.
+ */
+ private boolean connectToCarTelemetryd() {
if (mCarTelemetryInternal != null) {
- return;
+ return true;
}
IBinder binder = ServiceManagerHelper.checkService(SERVICE_NAME);
if (binder == null) {
@@ -112,36 +125,51 @@
new IllegalStateException(
"Failed to connect to the ICarTelemetryInternal: service is not "
+ "ready"));
- return;
+ return false;
}
try {
- binder.linkToDeath(this::onBinderDied, BINDER_FLAGS);
+ binder.linkToDeath(mDeathRecipient, BINDER_FLAGS);
} catch (RemoteException e) {
onPublisherFailure(
getMetricsConfigs(),
new IllegalStateException(
"Failed to connect to the ICarTelemetryInternal: linkToDeath failed",
e));
- return;
+ return false;
}
mCarTelemetryInternal = ICarTelemetryInternal.Stub.asInterface(binder);
try {
mCarTelemetryInternal.setListener(mListener);
} catch (RemoteException e) {
- binder.unlinkToDeath(this::onBinderDied, BINDER_FLAGS);
+ binder.unlinkToDeath(mDeathRecipient, BINDER_FLAGS);
mCarTelemetryInternal = null;
onPublisherFailure(
getMetricsConfigs(),
new IllegalStateException(
"Failed to connect to the ICarTelemetryInternal: Cannot set CarData "
+ "listener", e));
+ return false;
}
+ return true;
}
@NonNull
private ArrayList<TelemetryProto.MetricsConfig> getMetricsConfigs() {
- return new ArrayList<>(mSubscribers.stream().map(DataSubscriber::getMetricsConfig).collect(
- Collectors.toSet()));
+ ArraySet<TelemetryProto.MetricsConfig> uniqueConfigs =
+ new ArraySet<TelemetryProto.MetricsConfig>();
+ for (int i = 0; i < mCarIdSubscriberLookUp.size(); i++) {
+ ArrayList<DataSubscriber> subscribers = mCarIdSubscriberLookUp.valueAt(i);
+ for (int j = 0; j < subscribers.size(); j++) {
+ uniqueConfigs.add(subscribers.get(j).getMetricsConfig());
+ }
+ }
+ ArrayList<TelemetryProto.MetricsConfig> allConfigs =
+ new ArrayList<TelemetryProto.MetricsConfig>();
+ Iterator<TelemetryProto.MetricsConfig> iterator = uniqueConfigs.iterator();
+ while (iterator.hasNext()) {
+ allConfigs.add(iterator.next());
+ }
+ return allConfigs;
}
/**
@@ -158,7 +186,7 @@
} catch (RemoteException e) {
Slogf.w(CarLog.TAG_TELEMETRY, "Failed to remove ICarTelemetryInternal listener", e);
}
- mCarTelemetryInternal.asBinder().unlinkToDeath(this::onBinderDied, BINDER_FLAGS);
+ mCarTelemetryInternal.asBinder().unlinkToDeath(mDeathRecipient, BINDER_FLAGS);
mCarTelemetryInternal = null;
}
@@ -177,45 +205,135 @@
int carDataId = publisherParam.getCartelemetryd().getId();
CarDataProto.CarData.PushedCase carDataCase =
CarDataProto.CarData.PushedCase.forNumber(carDataId);
+ // TODO(b/241249252): Revise the check to accommodate data in OEM ID range, 10K-20K.
Preconditions.checkArgument(
carDataCase != null
&& carDataCase != CarDataProto.CarData.PushedCase.PUSHED_NOT_SET,
"Invalid CarData ID " + carDataId
+ ". Please see CarData.proto for the list of available IDs.");
- mSubscribers.add(subscriber);
+ ArrayList<DataSubscriber> currentSubscribers = mCarIdSubscriberLookUp.get(carDataId);
+ if (currentSubscribers == null) {
+ currentSubscribers = new ArrayList<>();
+ mCarIdSubscriberLookUp.put(carDataId, currentSubscribers);
+ }
+ currentSubscribers.add(subscriber);
- connectToCarTelemetryd();
+ if (!connectToCarTelemetryd()) {
+ // logging is done in connectToCarTelemetryd, do not double log here
+ return;
+ }
+ Slogf.d(CarLog.TAG_TELEMETRY, "Subscribing to CarData.id=%d", carDataId);
+ // No need to make a binder call if the given CarDataId is already subscribed to.
+ if (currentSubscribers.size() > 1) {
+ return;
+ }
- Slogf.d(CarLog.TAG_TELEMETRY, "Subscribing to CarDat.id=%d", carDataId);
+ try {
+ mCarTelemetryInternal.addCarDataIds(new int[]{carDataId});
+ } catch (RemoteException e) {
+ onPublisherFailure(
+ getMetricsConfigs(),
+ new IllegalStateException(
+ "Failed to make addCarDataIds binder call to ICarTelemetryInternal "
+ + "for CarDataID = "
+ + carDataId, e));
+ return;
+ }
}
@Override
public void removeDataSubscriber(@NonNull DataSubscriber subscriber) {
- mSubscribers.remove(subscriber);
- if (mSubscribers.isEmpty()) {
+ int idToRemove = subscriber.getPublisherParam().getCartelemetryd().getId();
+ // TODO(b/241251062): Revise to consider throwing IllegalArgumentException and checking
+ // for subscriber type like some other publisher implementations do.
+ ArrayList<DataSubscriber> currentSubscribers = mCarIdSubscriberLookUp.get(idToRemove);
+ if (currentSubscribers == null) {
+ // No subscribers were found for a given id.
+ Slogf.e(CarLog.TAG_TELEMETRY,
+ "Subscriber for CarData.id=%d is not present among subscriptions. This is not"
+ + " expected.",
+ idToRemove);
+ return;
+ }
+ currentSubscribers.remove(subscriber);
+ if (currentSubscribers.isEmpty()) {
+ mCarIdSubscriberLookUp.remove(idToRemove);
+ try {
+ mCarTelemetryInternal.removeCarDataIds(new int[]{idToRemove});
+ } catch (RemoteException e) {
+ Slogf.e(CarLog.TAG_TELEMETRY,
+ "removeCarDataIds binder call failed for CarData.id=%d", idToRemove);
+ }
+ }
+ if (mCarIdSubscriberLookUp.size() == 0) {
disconnectFromCarTelemetryd();
}
}
@Override
public void removeAllDataSubscribers() {
- mSubscribers.clear();
+ int[] idsToRemove = new int[mCarIdSubscriberLookUp.size()];
+ for (int index = 0; index < mCarIdSubscriberLookUp.size(); index++) {
+ idsToRemove[index] = mCarIdSubscriberLookUp.keyAt(index);
+ }
+ try {
+ mCarTelemetryInternal.removeCarDataIds(idsToRemove);
+ } catch (RemoteException e) {
+ Slogf.e(CarLog.TAG_TELEMETRY,
+ "removeCarDataIds binder call failed while unsubscribing from all data.");
+ }
+ mCarIdSubscriberLookUp.clear();
+
disconnectFromCarTelemetryd();
}
@Override
public boolean hasDataSubscriber(@NonNull DataSubscriber subscriber) {
- return mSubscribers.contains(subscriber);
+ int id = subscriber.getPublisherParam().getCartelemetryd().getId();
+ return mCarIdSubscriberLookUp.contains(id) && mCarIdSubscriberLookUp.get(id).contains(
+ subscriber);
}
/**
* Called when publisher receives new car data list. It's executed on the telemetry thread.
*/
private void onCarDataListReceived(@NonNull CarDataInternal[] dataList) {
- // TODO(b/189142577): implement
+ for (CarDataInternal data : dataList) {
+ processCarData(data);
+ }
+ }
+
+ private void processCarData(@NonNull CarDataInternal dataItem) {
+ ArrayList<DataSubscriber> currentSubscribers = mCarIdSubscriberLookUp.get(dataItem.id);
+ if (currentSubscribers == null) {
+ // It is possible the carId is no longer subscribed to while data is in-flight.
+ return;
+ }
+ int[] content = new int[dataItem.content.length];
+ for (int i = 0; i < content.length; i++) {
+ content[i] = dataItem.content[i];
+ }
+ PersistableBundle bundle = new PersistableBundle();
+ bundle.putInt(Constants.CAR_TELEMETRYD_BUNDLE_KEY_ID, dataItem.id);
+ bundle.putIntArray(Constants.CAR_TELEMETRYD_BUNDLE_KEY_CONTENT,
+ content);
+ SessionAnnotation sessionAnnotation = mSessionController.getSessionAnnotation();
+ sessionAnnotation.addAnnotationsToBundle(bundle);
+ for (int i = 0; i < currentSubscribers.size(); i++) {
+ currentSubscribers.get(i).push(bundle,
+ content.length * Integer.BYTES
+ > DataSubscriber.SCRIPT_INPUT_SIZE_THRESHOLD_BYTES);
+ }
}
@Override
- protected void handleSessionStateChange(SessionAnnotation annotation) {}
+ protected void handleSessionStateChange(SessionAnnotation annotation) {
+ // We don't handle session state changes. We make synchronous calls to SessionController
+ // as soon as new data arrives to retrieve the current session annotations.
+ // Make sure to invoke sessionController.registerCallback(this::handleSessionStateChange)
+ // in the constructor once this method is implemented.
+ }
+
+
}
diff --git a/service/src/com/android/car/telemetry/publisher/Constants.java b/service/src/com/android/car/telemetry/publisher/Constants.java
new file mode 100644
index 0000000..edc4b3f
--- /dev/null
+++ b/service/src/com/android/car/telemetry/publisher/Constants.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2022 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.telemetry.publisher;
+
+/**
+ * Container class for all constants that are related to transfer of data within
+ * {@link com.android.car.telemetry.CarTelemetryService} and between {@link
+ * com.android.car.telemetry.CarTelemetryService} and
+ * {@link com.android.car.scriptexecutor.ScriptExecutor}
+ * by using {@link android.os.PersistableBundle} objects.
+ *
+ * Each publisher is responsible for populating {@link android.os.PersistableBundle} instances with
+ * data. This file keeps names of keys used in the bundles by various publishers all in one place.
+ * This measure should allow clients of data to understand structure of {@link
+ * android.os.PersistableBundle} objects without having to look for places where the objects are
+ * populated.
+ */
+public final class Constants {
+ public static final String CAR_TELEMETRYD_BUNDLE_KEY_ID = "id";
+ public static final String CAR_TELEMETRYD_BUNDLE_KEY_CONTENT = "content";
+
+ private Constants() {
+ }
+}
diff --git a/service/src/com/android/car/telemetry/publisher/MemoryPublisher.java b/service/src/com/android/car/telemetry/publisher/MemoryPublisher.java
index bb65b05..5c53fd1 100644
--- a/service/src/com/android/car/telemetry/publisher/MemoryPublisher.java
+++ b/service/src/com/android/car/telemetry/publisher/MemoryPublisher.java
@@ -28,6 +28,7 @@
import com.android.car.telemetry.ResultStore;
import com.android.car.telemetry.databroker.DataSubscriber;
import com.android.car.telemetry.sessioncontroller.SessionAnnotation;
+import com.android.car.telemetry.sessioncontroller.SessionController;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.Preconditions;
@@ -75,8 +76,10 @@
MemoryPublisher(
@NonNull PublisherListener listener,
@NonNull Handler telemetryHandler,
- @NonNull ResultStore resultStore) {
- this(listener, telemetryHandler, resultStore, Paths.get("/proc/meminfo"));
+ @NonNull ResultStore resultStore,
+ @NonNull SessionController sessionController) {
+ this(listener, telemetryHandler, resultStore, sessionController,
+ Paths.get("/proc/meminfo"));
}
@VisibleForTesting
@@ -84,6 +87,7 @@
@NonNull PublisherListener listener,
@NonNull Handler telemetryHandler,
@NonNull ResultStore resultStore,
+ @NonNull SessionController sessionController,
@NonNull Path meminfoPath) {
super(listener);
mTelemetryHandler = telemetryHandler;
@@ -93,6 +97,8 @@
MemoryPublisher.class.getSimpleName(), false);
mTraceLog = new TimingsTraceLog(
CarLog.TAG_TELEMETRY, TraceHelper.TRACE_TAG_CAR_SERVICE);
+ // Subscribes the publisher to driving session updates by SessionController.
+ sessionController.registerCallback(this::handleSessionStateChange);
}
@Override
diff --git a/service/src/com/android/car/telemetry/publisher/PublisherFactory.java b/service/src/com/android/car/telemetry/publisher/PublisherFactory.java
index 735ec2b..546ffea 100644
--- a/service/src/com/android/car/telemetry/publisher/PublisherFactory.java
+++ b/service/src/com/android/car/telemetry/publisher/PublisherFactory.java
@@ -30,7 +30,6 @@
import com.android.car.telemetry.sessioncontroller.SessionController;
import com.android.internal.util.Preconditions;
-import java.io.File;
import java.util.Objects;
/**
@@ -50,7 +49,6 @@
private final Object mLock = new Object();
private final CarPropertyService mCarPropertyService;
- private final File mPublisherDirectory;
private final Handler mTelemetryHandler;
private final Context mContext; // CarService context
private final UidPackageMapper mUidMapper;
@@ -70,14 +68,12 @@
@NonNull CarPropertyService carPropertyService,
@NonNull Handler handler,
@NonNull Context context,
- @NonNull File publisherDirectory,
@NonNull SessionController sessionController,
@NonNull ResultStore resultStore,
@NonNull UidPackageMapper uidMapper) {
mCarPropertyService = carPropertyService;
mTelemetryHandler = handler;
mContext = context;
- mPublisherDirectory = publisherDirectory;
mSessionController = sessionController;
mResultStore = resultStore;
mUidMapper = uidMapper;
@@ -99,7 +95,7 @@
case TelemetryProto.Publisher.CARTELEMETRYD_FIELD_NUMBER:
if (mCarTelemetrydPublisher == null) {
mCarTelemetrydPublisher = new CarTelemetrydPublisher(
- mPublisherListener, mTelemetryHandler);
+ mPublisherListener, mTelemetryHandler, mSessionController);
}
return mCarTelemetrydPublisher;
case TelemetryProto.Publisher.STATS_FIELD_NUMBER:
@@ -108,8 +104,7 @@
Preconditions.checkState(stats != null, "StatsManager not found");
StatsManagerProxy statsManager = new StatsManagerImpl(stats);
mStatsPublisher = new StatsPublisher(
- mPublisherListener, statsManager, mPublisherDirectory,
- mTelemetryHandler);
+ mPublisherListener, statsManager, mResultStore, mTelemetryHandler);
}
return mStatsPublisher;
case TelemetryProto.Publisher.CONNECTIVITY_FIELD_NUMBER:
@@ -128,7 +123,8 @@
case TelemetryProto.Publisher.MEMORY_FIELD_NUMBER:
if (mMemoryPublisher == null) {
mMemoryPublisher = new MemoryPublisher(
- mPublisherListener, mTelemetryHandler, mResultStore);
+ mPublisherListener, mTelemetryHandler, mResultStore,
+ mSessionController);
}
return mMemoryPublisher;
default:
diff --git a/service/src/com/android/car/telemetry/publisher/StatsPublisher.java b/service/src/com/android/car/telemetry/publisher/StatsPublisher.java
index 7b40eb5..328ef2c 100644
--- a/service/src/com/android/car/telemetry/publisher/StatsPublisher.java
+++ b/service/src/com/android/car/telemetry/publisher/StatsPublisher.java
@@ -42,6 +42,7 @@
import com.android.car.CarLog;
import com.android.car.telemetry.AtomsProto.ProcessCpuTime;
import com.android.car.telemetry.AtomsProto.ProcessMemoryState;
+import com.android.car.telemetry.ResultStore;
import com.android.car.telemetry.StatsLogProto;
import com.android.car.telemetry.StatsdConfigProto;
import com.android.car.telemetry.StatsdConfigProto.StatsdConfig;
@@ -49,14 +50,11 @@
import com.android.car.telemetry.publisher.statsconverters.ConfigMetricsReportListConverter;
import com.android.car.telemetry.publisher.statsconverters.StatsConversionException;
import com.android.car.telemetry.sessioncontroller.SessionAnnotation;
-import com.android.car.telemetry.util.IoUtils;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.Preconditions;
import com.google.protobuf.InvalidProtocolBufferException;
-import java.io.File;
-import java.io.IOException;
import java.time.Duration;
import java.util.ArrayList;
import java.util.HashSet;
@@ -101,22 +99,12 @@
@VisibleForTesting
static final long WTF_OCCURRED_EVENT_METRIC_ID = 14;
- // The file that contains stats config key and stats config version
- @VisibleForTesting
- static final String SAVED_STATS_CONFIGS_FILE = "stats_config_keys_versions";
-
// TODO(b/202115033): Flatten the load spike by pulling reports for each MetricsConfigs
// using separate periodical timers.
private static final Duration PULL_REPORTS_PERIOD = Duration.ofMinutes(10);
private static final String BUNDLE_CONFIG_KEY_PREFIX = "statsd-publisher-config-id-";
private static final String BUNDLE_CONFIG_VERSION_PREFIX = "statsd-publisher-config-version-";
- /**
- * Binder transaction size limit is 1MB for all binders per process, so for large script input
- * file pipe will be used to transfer the data to script executor instead of binder call. This
- * is the input size threshold above which piping is used.
- */
- private static final int SCRIPT_INPUT_SIZE_THRESHOLD_BYTES = 20 * 1024; // 20 kb
@VisibleForTesting
static final StatsdConfigProto.FieldMatcher PROCESS_MEMORY_STATE_FIELDS_MATCHER =
@@ -148,12 +136,9 @@
.build();
private final StatsManagerProxy mStatsManager;
- private final File mSavedStatsConfigsFile;
+ private final ResultStore mResultStore;
private final Handler mTelemetryHandler;
- // True if the publisher is periodically pulling reports from StatsD.
- private boolean mIsPullingReports = false;
-
/** Assign the method to {@link Runnable}, otherwise the handler fails to remove it. */
private final Runnable mPullReportsPeriodically = this::pullReportsPeriodically;
@@ -163,50 +148,35 @@
// Maps config_key to the set of DataSubscriber.
private final LongSparseArray<DataSubscriber> mConfigKeyToSubscribers = new LongSparseArray<>();
- private final PersistableBundle mSavedStatsConfigs;
+ private PersistableBundle mSavedStatsConfigs;
+
+ // True if the publisher is periodically pulling reports from StatsD.
+ private boolean mIsPullingReports = false;
StatsPublisher(
@NonNull PublisherListener listener,
@NonNull StatsManagerProxy statsManager,
- @NonNull File publisherDirectory,
+ @NonNull ResultStore resultStore,
@NonNull Handler telemetryHandler) {
super(listener);
mStatsManager = statsManager;
+ mResultStore = resultStore;
mTelemetryHandler = telemetryHandler;
- mSavedStatsConfigsFile = new File(publisherDirectory, SAVED_STATS_CONFIGS_FILE);
- mSavedStatsConfigs = loadBundle();
- }
-
- /** Loads the PersistableBundle containing stats config keys and versions from disk. */
- @NonNull
- private PersistableBundle loadBundle() {
- if (!mSavedStatsConfigsFile.exists()) {
- return new PersistableBundle();
- }
- try {
- return IoUtils.readBundle(mSavedStatsConfigsFile);
- } catch (IOException e) {
- // TODO(b/199947533): handle failure
- Slogf.e(CarLog.TAG_TELEMETRY, "Failed to read file "
- + mSavedStatsConfigsFile.getAbsolutePath(), e);
- return new PersistableBundle();
+ // Loads the PersistableBundle containing stats config keys and versions from disk
+ mSavedStatsConfigs = mResultStore.getPublisherData(
+ StatsPublisher.class.getSimpleName(), false);
+ if (mSavedStatsConfigs == null) {
+ mSavedStatsConfigs = new PersistableBundle();
}
}
/** Writes the PersistableBundle containing stats config keys and versions to disk. */
- private void saveBundle() {
+ private void savePublisherState() {
if (mSavedStatsConfigs.size() == 0) {
- mSavedStatsConfigsFile.delete();
+ mResultStore.removePublisherData(StatsPublisher.class.getSimpleName());
return;
}
- try {
- IoUtils.writeBundle(mSavedStatsConfigsFile, mSavedStatsConfigs);
- } catch (IOException e) {
- // TODO(b/199947533): handle failure
- Slogf.e(CarLog.TAG_TELEMETRY,
- "Cannot write to " + mSavedStatsConfigsFile.getAbsolutePath()
- + ". Added stats config info is lost.", e);
- }
+ mResultStore.putPublisherData(StatsPublisher.class.getSimpleName(), mSavedStatsConfigs);
}
@Override
@@ -314,7 +284,7 @@
}
}
}
- if (bytes < SCRIPT_INPUT_SIZE_THRESHOLD_BYTES) {
+ if (bytes < DataSubscriber.SCRIPT_INPUT_SIZE_THRESHOLD_BYTES) {
return false;
}
return true;
@@ -438,8 +408,8 @@
// will ry deleting StatsD configs again.
}
}
- saveBundle();
mSavedStatsConfigs.clear();
+ savePublisherState();
mIsPullingReports = false;
mTelemetryHandler.removeCallbacks(mPullReportsPeriodically);
}
@@ -507,7 +477,7 @@
mStatsManager.addConfig(configKey, config.toByteArray());
mSavedStatsConfigs.putInt(bundleVersion, subscriber.getMetricsConfig().getVersion());
mSavedStatsConfigs.putLong(bundleConfigKey, configKey);
- saveBundle();
+ savePublisherState();
} catch (StatsUnavailableException e) {
Slogf.w(CarLog.TAG_TELEMETRY, "Failed to add config" + configKey, e);
// We will notify the failure immediately, as we're expecting StatsManager to be stable.
@@ -527,7 +497,7 @@
mStatsManager.removeConfig(configKey);
mSavedStatsConfigs.remove(bundleVersion);
mSavedStatsConfigs.remove(bundleConfigKey);
- saveBundle();
+ savePublisherState();
} catch (StatsUnavailableException e) {
Slogf.w(CarLog.TAG_TELEMETRY, "Failed to remove config " + configKey
+ ". Ignoring the failure. Will retry removing again when"
diff --git a/service/src/com/android/car/telemetry/publisher/VehiclePropertyPublisher.java b/service/src/com/android/car/telemetry/publisher/VehiclePropertyPublisher.java
index 64bed3f..95f9184 100644
--- a/service/src/com/android/car/telemetry/publisher/VehiclePropertyPublisher.java
+++ b/service/src/com/android/car/telemetry/publisher/VehiclePropertyPublisher.java
@@ -16,14 +16,18 @@
package com.android.car.telemetry.publisher;
+import static java.lang.Integer.toHexString;
+
import android.annotation.NonNull;
import android.car.VehiclePropertyIds;
import android.car.builtin.util.Slogf;
import android.car.hardware.CarPropertyConfig;
+import android.car.hardware.CarPropertyValue;
import android.car.hardware.property.CarPropertyEvent;
import android.car.hardware.property.ICarPropertyEventListener;
import android.car.telemetry.TelemetryProto;
import android.car.telemetry.TelemetryProto.Publisher.PublisherCase;
+import android.hardware.automotive.vehicle.VehiclePropertyType;
import android.os.Handler;
import android.os.PersistableBundle;
import android.os.RemoteException;
@@ -36,6 +40,7 @@
import com.android.car.telemetry.sessioncontroller.SessionAnnotation;
import com.android.internal.util.Preconditions;
+import java.nio.charset.StandardCharsets;
import java.util.List;
/**
@@ -47,8 +52,16 @@
public class VehiclePropertyPublisher extends AbstractPublisher {
private static final boolean DEBUG = false; // STOPSHIP if true
- /** Bundle key for {@link CarPropertyEvent}. */
- public static final String CAR_PROPERTY_EVENT_KEY = "car_property_event";
+ public static final String BUNDLE_TIMESTAMP_KEY = "timestamp";
+ public static final String BUNDLE_STRING_KEY = "stringVal";
+ public static final String BUNDLE_BOOLEAN_KEY = "boolVal";
+ public static final String BUNDLE_INT_KEY = "intVal";
+ public static final String BUNDLE_INT_ARRAY_KEY = "intArrayVal";
+ public static final String BUNDLE_LONG_KEY = "longVal";
+ public static final String BUNDLE_LONG_ARRAY_KEY = "longArrayVal";
+ public static final String BUNDLE_FLOAT_KEY = "floatVal";
+ public static final String BUNDLE_FLOAT_ARRAY_KEY = "floatArrayVal";
+ public static final String BUNDLE_BYTE_ARRAY_KEY = "byteArrayVal";
private final CarPropertyService mCarPropertyService;
private final Handler mTelemetryHandler;
@@ -176,16 +189,112 @@
private void onVehicleEvent(@NonNull CarPropertyEvent event) {
// move the work from CarPropertyService's worker thread to the telemetry thread
mTelemetryHandler.post(() -> {
- // TODO(b/197269115): convert CarPropertyEvent into PersistableBundle
- PersistableBundle bundle = new PersistableBundle();
- ArraySet<DataSubscriber> subscribersClone = new ArraySet<>(
- mCarPropertyToSubscribers.get(event.getCarPropertyValue().getPropertyId()));
- for (DataSubscriber subscriber : subscribersClone) {
+ CarPropertyValue propValue = event.getCarPropertyValue();
+ PersistableBundle bundle = parseCarPropertyValue(
+ propValue, mCarPropertyList.get(propValue.getPropertyId()).getConfigArray());
+ for (DataSubscriber subscriber
+ : mCarPropertyToSubscribers.get(propValue.getPropertyId())) {
subscriber.push(bundle);
}
});
}
+ /**
+ * Parses the car property value into a PersistableBundle.
+ */
+ private PersistableBundle parseCarPropertyValue(
+ CarPropertyValue propValue, List<Integer> configArray) {
+ Object value = propValue.getValue();
+ PersistableBundle bundle = new PersistableBundle();
+ bundle.putLong(BUNDLE_TIMESTAMP_KEY, propValue.getTimestamp());
+ int type = propValue.getPropertyId() & VehiclePropertyType.MASK;
+ if (VehiclePropertyType.BOOLEAN == type) {
+ bundle.putBoolean(BUNDLE_BOOLEAN_KEY, (Boolean) value);
+ } else if (VehiclePropertyType.FLOAT == type) {
+ bundle.putDouble(BUNDLE_FLOAT_KEY, ((Float) value).doubleValue());
+ } else if (VehiclePropertyType.INT32 == type) {
+ bundle.putInt(BUNDLE_INT_KEY, (Integer) value);
+ } else if (VehiclePropertyType.INT64 == type) {
+ bundle.putLong(BUNDLE_LONG_KEY, (Long) value);
+ } else if (VehiclePropertyType.FLOAT_VEC == type) {
+ Float[] floats = (Float[]) value;
+ double[] doubles = new double[floats.length];
+ for (int i = 0; i < floats.length; i++) {
+ doubles[i] = floats[i].doubleValue();
+ }
+ bundle.putDoubleArray(BUNDLE_FLOAT_ARRAY_KEY, doubles);
+ } else if (VehiclePropertyType.INT32_VEC == type) {
+ Integer[] integers = (Integer[]) value;
+ int[] ints = new int[integers.length];
+ for (int i = 0; i < integers.length; i++) {
+ ints[i] = integers[i];
+ }
+ bundle.putIntArray(BUNDLE_INT_ARRAY_KEY, ints);
+ } else if (VehiclePropertyType.INT64_VEC == type) {
+ Long[] oldLongs = (Long[]) value;
+ long[] longs = new long[oldLongs.length];
+ for (int i = 0; i < oldLongs.length; i++) {
+ longs[i] = oldLongs[i];
+ }
+ bundle.putLongArray(BUNDLE_LONG_ARRAY_KEY, longs);
+ } else if (VehiclePropertyType.STRING == type) {
+ bundle.putString(BUNDLE_STRING_KEY, (String) value);
+ } else if (VehiclePropertyType.BYTES == type) {
+ bundle.putString(
+ BUNDLE_BYTE_ARRAY_KEY, new String((byte[]) value, StandardCharsets.UTF_8));
+ } else if (VehiclePropertyType.MIXED == type) {
+ Object[] mixed = (Object[]) value;
+ int k = 0;
+ if (configArray.get(0) == 1) { // Has single String
+ bundle.putString(BUNDLE_STRING_KEY, (String) mixed[k++]);
+ }
+ if (configArray.get(1) == 1) { // Has single Boolean
+ bundle.putBoolean(BUNDLE_BOOLEAN_KEY, (Boolean) mixed[k++]);
+ }
+ if (configArray.get(2) == 1) { // Has single Integer
+ bundle.putInt(BUNDLE_INT_KEY, (Integer) mixed[k++]);
+ }
+ if (configArray.get(3) != 0) { // Integer[] length is non-zero
+ int[] ints = new int[configArray.get(3)];
+ for (int i = 0; i < configArray.get(3); i++) {
+ ints[i] = (Integer) mixed[k++];
+ }
+ bundle.putIntArray(BUNDLE_INT_ARRAY_KEY, ints);
+ }
+ if (configArray.get(4) == 1) { // Has single Long
+ bundle.putLong(BUNDLE_LONG_KEY, (Long) mixed[k++]);
+ }
+ if (configArray.get(5) != 0) { // Long[] length is non-zero
+ long[] longs = new long[configArray.get(5)];
+ for (int i = 0; i < configArray.get(5); i++) {
+ longs[i] = (Long) mixed[k++];
+ }
+ bundle.putLongArray(BUNDLE_LONG_ARRAY_KEY, longs);
+ }
+ if (configArray.get(6) == 1) { // Has single Float
+ bundle.putDouble(BUNDLE_FLOAT_KEY, ((Float) mixed[k++]).doubleValue());
+ }
+ if (configArray.get(7) != 0) { // Float[] length is non-zero
+ double[] doubles = new double[configArray.get(7)];
+ for (int i = 0; i < configArray.get(7); i++) {
+ doubles[i] = ((Float) mixed[k++]).doubleValue();
+ }
+ bundle.putDoubleArray(BUNDLE_FLOAT_ARRAY_KEY, doubles);
+ }
+ if (configArray.get(8) != 0) { // Byte[] length is non-zero
+ byte[] bytes = new byte[configArray.get(8)];
+ for (int i = 0; i < configArray.get(8); i++) {
+ bytes[i] = (Byte) mixed[k++];
+ }
+ bundle.putString(BUNDLE_BYTE_ARRAY_KEY, new String(bytes, StandardCharsets.UTF_8));
+ }
+ } else {
+ throw new IllegalArgumentException(
+ "Unexpected property type: " + toHexString(type));
+ }
+ return bundle;
+ }
+
@Override
protected void handleSessionStateChange(SessionAnnotation annotation) {}
}
diff --git a/service/src/com/android/car/telemetry/sessioncontroller/SessionController.java b/service/src/com/android/car/telemetry/sessioncontroller/SessionController.java
index 2e1a208..f3c4d7b 100644
--- a/service/src/com/android/car/telemetry/sessioncontroller/SessionController.java
+++ b/service/src/com/android/car/telemetry/sessioncontroller/SessionController.java
@@ -20,13 +20,11 @@
import android.annotation.NonNull;
import android.car.hardware.power.CarPowerManager;
import android.car.hardware.power.ICarPowerStateListener;
-import android.content.Context;
import android.os.Handler;
import android.os.RemoteException;
import android.os.SystemClock;
import android.os.SystemProperties;
-import com.android.car.CarLocalServices;
import com.android.car.power.CarPowerManagementService;
import java.lang.annotation.Retention;
@@ -55,7 +53,6 @@
public @interface SessionControllerState {
}
- private final Context mContext;
private int mSessionId = 0;
private int mSessionState = STATE_EXIT_DRIVING_SESSION;
private long mStateChangedAtMillisSinceBoot; // uses SystemClock.elapsedRealtime();
@@ -94,10 +91,10 @@
void onSessionStateChanged(SessionAnnotation annotation);
}
- public SessionController(Context context, Handler telemetryHandler) {
- mContext = context;
+ public SessionController(
+ CarPowerManagementService carPowerManagementService, Handler telemetryHandler) {
mTelemetryHandler = telemetryHandler;
- mCarPowerManagementService = CarLocalServices.getService(CarPowerManagementService.class);
+ mCarPowerManagementService = carPowerManagementService;
mCarPowerManagementService.registerInternalListener(mCarPowerStateListener);
}
diff --git a/service/src/com/android/car/telemetry/util/MetricsReportProtoUtils.java b/service/src/com/android/car/telemetry/util/MetricsReportProtoUtils.java
new file mode 100644
index 0000000..ef38807
--- /dev/null
+++ b/service/src/com/android/car/telemetry/util/MetricsReportProtoUtils.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2022 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.telemetry.util;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.car.builtin.util.Slogf;
+import android.os.PersistableBundle;
+
+import com.android.car.CarLog;
+import com.android.car.telemetry.MetricsReportProto.MetricsReportContainer;
+import com.android.car.telemetry.MetricsReportProto.MetricsReportList;
+
+import com.google.protobuf.ByteString;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+
+/** Utility class for working with {@link com.android.car.telemetry.MetricsReportProto}. */
+public class MetricsReportProtoUtils {
+
+ private MetricsReportProtoUtils() { }
+
+ /**
+ * Serialize a PersistableBundle into bytes. If conversion failed, return null.
+ */
+ @Nullable
+ public static byte[] getBytes(PersistableBundle bundle) {
+ try (ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream()) {
+ bundle.writeToStream(byteArrayOutputStream);
+ return byteArrayOutputStream.toByteArray();
+ } catch (IOException e) {
+ Slogf.w(CarLog.TAG_TELEMETRY, "Serializing PersistableBundle failed.", e);
+ }
+ return null;
+ }
+
+ /**
+ * Serialize a PersistableBundle into ByteString, which is an immutable byte array.
+ * ByteString is the corresponding Java type for {@code bytes} in protobuf.
+ */
+ @Nullable
+ public static ByteString getByteString(PersistableBundle bundle) {
+ byte[] bytes = getBytes(bundle);
+ return bytes == null ? null : ByteString.copyFrom(bytes);
+ }
+
+ /**
+ * Deserialize the ByteString into a PersistableBundle. Returns null if failed.
+ */
+ @Nullable
+ public static PersistableBundle getBundle(ByteString byteString) {
+ byte[] bytes = byteString.toByteArray();
+ try (ByteArrayInputStream bis = new ByteArrayInputStream(bytes)) {
+ return PersistableBundle.readFromStream(bis);
+ } catch (IOException e) {
+ Slogf.w(CarLog.TAG_TELEMETRY, "Deserializing bytes into PersistableBundle failed.", e);
+ }
+ return null;
+ }
+
+ /**
+ * Reads a PersistableBundle from the given MetricsReportList at the given index.
+ */
+ @Nullable
+ public static PersistableBundle getBundle(MetricsReportList reportList, int index) {
+ if (index >= reportList.getReportCount()) {
+ return null;
+ }
+ return getBundle(reportList.getReport(index).getReportBytes());
+ }
+
+ /**
+ * Constructs a MetricsReportList from bundles. All bundles are marked as not the last report.
+ */
+ @NonNull
+ public static MetricsReportList buildMetricsReportList(PersistableBundle... bundles) {
+ MetricsReportList.Builder reportListBuilder = MetricsReportList.newBuilder();
+ for (PersistableBundle bundle : bundles) {
+ MetricsReportContainer reportContainer = MetricsReportContainer.newBuilder()
+ .setReportBytes(getByteString(bundle))
+ .build();
+ reportListBuilder.addReport(reportContainer);
+ }
+ return reportListBuilder.build();
+ }
+}
diff --git a/service/src/com/android/car/user/CarUserService.java b/service/src/com/android/car/user/CarUserService.java
index c1e23c9..af2899a 100644
--- a/service/src/com/android/car/user/CarUserService.java
+++ b/service/src/com/android/car/user/CarUserService.java
@@ -32,8 +32,11 @@
import android.annotation.UserIdInt;
import android.app.ActivityManager;
import android.app.admin.DevicePolicyManager;
+import android.car.Car;
+import android.car.CarVersion;
import android.car.ICarResultReceiver;
import android.car.ICarUserService;
+import android.car.PlatformVersion;
import android.car.builtin.app.ActivityManagerHelper;
import android.car.builtin.content.pm.PackageManagerHelper;
import android.car.builtin.os.TraceHelper;
@@ -110,6 +113,7 @@
import com.android.car.internal.util.DebugUtils;
import com.android.car.internal.util.FunctionalUtils;
import com.android.car.internal.util.IndentingPrintWriter;
+import com.android.car.pm.CarPackageManagerService;
import com.android.car.power.CarPowerManagementService;
import com.android.car.user.InitialUserSetter.InitialUserInfo;
import com.android.internal.annotations.GuardedBy;
@@ -250,6 +254,8 @@
private final CarUxRestrictionsManagerService mCarUxRestrictionService;
+ private final CarPackageManagerService mCarPackageManagerService;
+
private static final int PRE_CREATION_STAGE_BEFORE_SUSPEND = 1;
private static final int PRE_CREATION_STAGE_ON_SYSTEM_START = 2;
@@ -310,12 +316,13 @@
public CarUserService(@NonNull Context context, @NonNull UserHalService hal,
@NonNull UserManager userManager,
int maxRunningUsers,
- @NonNull CarUxRestrictionsManagerService uxRestrictionService) {
+ @NonNull CarUxRestrictionsManagerService uxRestrictionService,
+ @NonNull CarPackageManagerService carPackageManagerService) {
this(context, hal, userManager, new UserHandleHelper(context, userManager),
context.getSystemService(DevicePolicyManager.class),
context.getSystemService(ActivityManager.class), maxRunningUsers,
/* initialUserSetter= */ null, /* userPreCreator= */ null, uxRestrictionService,
- null);
+ null, carPackageManagerService);
}
@VisibleForTesting
@@ -328,7 +335,8 @@
@Nullable InitialUserSetter initialUserSetter,
@Nullable UserPreCreator userPreCreator,
@NonNull CarUxRestrictionsManagerService uxRestrictionService,
- @Nullable Handler handler) {
+ @Nullable Handler handler,
+ @NonNull CarPackageManagerService carPackageManagerService) {
Slogf.d(TAG, "CarUserService(): DBG=%b, user=%s", DBG, context.getUser());
mContext = context;
mHal = hal;
@@ -347,6 +355,7 @@
mSwitchGuestUserBeforeSleep = resources.getBoolean(
R.bool.config_switchGuestUserBeforeGoingSleep);
mCarUxRestrictionService = uxRestrictionService;
+ mCarPackageManagerService = carPackageManagerService;
mPreCreationStage = resources.getInteger(R.integer.config_userPreCreationStage);
int preCreationDelayMs = resources
.getInteger(R.integer.config_userPreCreationDelay);
@@ -2023,10 +2032,17 @@
int userId = toUserId;
// Handle special cases first...
- if (eventType == CarUserManager.USER_LIFECYCLE_EVENT_TYPE_SWITCHING) {
- onUserSwitching(fromUserId, toUserId);
- } else if (eventType == CarUserManager.USER_LIFECYCLE_EVENT_TYPE_UNLOCKED) {
- onUserUnlocked(userId);
+ switch (eventType) {
+ case CarUserManager.USER_LIFECYCLE_EVENT_TYPE_SWITCHING:
+ onUserSwitching(fromUserId, toUserId);
+ break;
+ case CarUserManager.USER_LIFECYCLE_EVENT_TYPE_UNLOCKED:
+ onUserUnlocked(userId);
+ break;
+ case CarUserManager.USER_LIFECYCLE_EVENT_TYPE_REMOVED:
+ onUserRemoved(UserHandle.of(userId));
+ break;
+ default:
}
// ...then notify listeners.
@@ -2077,6 +2093,32 @@
t.traceBegin("notify-app-listeners-user-" + userId + "-event-" + eventType);
for (int i = 0; i < listenersSize; i++) {
AppLifecycleListener listener = mAppLifecycleListeners.valueAt(i);
+ if (eventType == CarUserManager.USER_LIFECYCLE_EVENT_TYPE_CREATED
+ || eventType == CarUserManager.USER_LIFECYCLE_EVENT_TYPE_REMOVED) {
+ PlatformVersion platformVersion = Car.getPlatformVersion();
+ // Perform platform version check to ensure the support for these new events
+ // is consistent with the platform version declared in their ApiRequirements.
+ if (!platformVersion.isAtLeast(PlatformVersion.VERSION_CODES.TIRAMISU_1)) {
+ if (DBG) {
+ Slogf.d(TAG, "Skipping app listener %s for event %s due to unsupported"
+ + " car platform version %s.", listener, event, platformVersion);
+ }
+ continue;
+ }
+ // Perform target car version check to ensure only apps expecting the new
+ // lifecycle event types will have the events sent to them.
+ // TODO(b/235524989): Cache the target car version for packages in
+ // CarPackageManagerService.
+ CarVersion targetCarVersion = mCarPackageManagerService.getTargetCarVersion(
+ listener.packageName);
+ if (!targetCarVersion.isAtLeast(CarVersion.VERSION_CODES.TIRAMISU_1)) {
+ if (DBG) {
+ Slogf.d(TAG, "Skipping app listener %s for event %s due to incompatible"
+ + " target car version %s.", listener, event, targetCarVersion);
+ }
+ continue;
+ }
+ }
if (!listener.applyFilters(event)) {
if (DBG) {
Slogf.d(TAG, "Skipping app listener %s for event %s due to the filters"
diff --git a/service/src/com/android/car/util/Utils.java b/service/src/com/android/car/util/Utils.java
index 3996fdf..624623a 100644
--- a/service/src/com/android/car/util/Utils.java
+++ b/service/src/com/android/car/util/Utils.java
@@ -28,6 +28,8 @@
import android.car.user.CarUserManager.UserLifecycleEvent;
import android.content.ContentResolver;
import android.content.Context;
+import android.content.pm.PackageManager;
+import android.os.Binder;
import android.os.UserHandle;
import com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport;
@@ -222,4 +224,25 @@
Collectors.joining(",")));
return false;
}
+
+ /**
+ * Checks if the calling UID owns the give package.
+ *
+ * @throws SecurityException if the calling UID doesn't own the given package.
+ */
+ public static void checkCalledByPackage(Context context, String packageName) {
+ int callingUid = Binder.getCallingUid();
+ PackageManager pm = context.getPackageManager();
+ String[] packages = pm.getPackagesForUid(callingUid);
+ if (packages != null) {
+ for (String candidate: packages) {
+ if (candidate.equals(packageName)) {
+ return;
+ }
+ }
+ }
+ throw new SecurityException(
+ "Package " + packageName + " is not associated to UID " + callingUid);
+ }
+
}
diff --git a/service/src/com/android/car/watchdog/CarWatchdogService.java b/service/src/com/android/car/watchdog/CarWatchdogService.java
index 082abae..fc5787a 100644
--- a/service/src/com/android/car/watchdog/CarWatchdogService.java
+++ b/service/src/com/android/car/watchdog/CarWatchdogService.java
@@ -16,14 +16,16 @@
package com.android.car.watchdog;
-import static android.car.builtin.os.UserManagerHelper.USER_NULL;
+import static android.car.PlatformVersion.VERSION_CODES;
+import static android.car.user.CarUserManager.USER_LIFECYCLE_EVENT_TYPE_POST_UNLOCKED;
import static android.car.user.CarUserManager.USER_LIFECYCLE_EVENT_TYPE_STARTING;
import static android.car.user.CarUserManager.USER_LIFECYCLE_EVENT_TYPE_STOPPED;
+import static android.car.user.CarUserManager.USER_LIFECYCLE_EVENT_TYPE_SWITCHING;
+import static android.car.user.CarUserManager.USER_LIFECYCLE_EVENT_TYPE_UNLOCKING;
import static android.content.Intent.ACTION_PACKAGE_CHANGED;
import static android.content.Intent.ACTION_REBOOT;
import static android.content.Intent.ACTION_SHUTDOWN;
import static android.content.Intent.ACTION_USER_REMOVED;
-import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
import static com.android.car.CarLog.TAG_WATCHDOG;
import static com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport.DUMP_INFO;
@@ -40,7 +42,6 @@
import android.automotive.watchdog.internal.UserPackageIoUsageStats;
import android.automotive.watchdog.internal.UserState;
import android.car.Car;
-import android.car.builtin.content.pm.PackageManagerHelper;
import android.car.builtin.util.Slogf;
import android.car.hardware.power.CarPowerManager;
import android.car.hardware.power.CarPowerPolicy;
@@ -62,6 +63,7 @@
import android.content.Intent;
import android.content.IntentFilter;
import android.os.RemoteException;
+import android.os.ServiceSpecificException;
import android.os.UserHandle;
import android.os.UserManager;
import android.util.ArraySet;
@@ -126,8 +128,10 @@
private final WatchdogStorage mWatchdogStorage;
private final WatchdogProcessHandler mWatchdogProcessHandler;
private final WatchdogPerfHandler mWatchdogPerfHandler;
- private final CarWatchdogDaemonHelper mCarWatchdogDaemonHelper;
private final CarWatchdogDaemonHelper.OnConnectionChangeListener mConnectionListener;
+
+ private CarWatchdogDaemonHelper mCarWatchdogDaemonHelper;
+
/*
* TODO(b/192481350): Listen for GarageMode change notification rather than depending on the
* system_server broadcast when the CarService internal API for listening GarageMode change is
@@ -141,7 +145,7 @@
case ACTION_DISMISS_RESOURCE_OVERUSE_NOTIFICATION:
case ACTION_LAUNCH_APP_SETTINGS:
case ACTION_RESOURCE_OVERUSE_DISABLE_APP:
- mWatchdogPerfHandler.handleIntent(intent);
+ mWatchdogPerfHandler.processUserNotificationIntent(intent);
break;
case ACTION_GARAGE_MODE_ON:
case ACTION_GARAGE_MODE_OFF:
@@ -193,22 +197,7 @@
break;
}
case ACTION_PACKAGE_CHANGED: {
- String packageName = intent.getData().getSchemeSpecificPart();
- int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, USER_NULL);
- if (userId == USER_NULL) {
- break;
- }
- try {
- if (PackageManagerHelper.getApplicationEnabledSettingForUser(packageName,
- userId) == COMPONENT_ENABLED_STATE_ENABLED) {
- mWatchdogPerfHandler.removeFromDisabledPackagesSettingsString(
- packageName, userId);
- }
- } catch (RemoteException e) {
- Slogf.e(TAG, e,
- "Failed to verify enabled setting for user %d, package '%s'",
- userId, packageName);
- }
+ mWatchdogPerfHandler.processPackageChangedIntent(intent);
break;
}
}
@@ -283,7 +272,7 @@
}
@VisibleForTesting
- CarWatchdogService(Context context, Context carServiceBuiltinPackageContext,
+ public CarWatchdogService(Context context, Context carServiceBuiltinPackageContext,
WatchdogStorage watchdogStorage, TimeSource timeSource) {
mContext = context;
mWatchdogStorage = watchdogStorage;
@@ -305,6 +294,11 @@
mIsDisplayEnabled = true;
}
+ @VisibleForTesting
+ public void setCarWatchdogDaemonHelper(CarWatchdogDaemonHelper helper) {
+ mCarWatchdogDaemonHelper = helper;
+ }
+
@Override
public void init() {
mWatchdogProcessHandler.init();
@@ -515,6 +509,41 @@
return mWatchdogPerfHandler.disablePackageForUser(packageName, userId);
}
+ /**
+ * Sets the thread priority for a specific thread.
+ *
+ * The thread must belong to the calling process.
+ *
+ * @throws IllegalArgumentException If the policy/priority is not valid.
+ * @throws IllegalStateException If the provided tid does not belong to the calling process.
+ * @throws RemoteException If binder error happens.
+ * @throws ServiceSpecificException If car watchdog daemon failed to set the thread priority.
+ * @throws UnsupportedOperationException If the current android release doesn't support the API.
+ */
+ public void setThreadPriority(int pid, int tid, int uid, int policy, int priority)
+ throws RemoteException {
+ mCarWatchdogDaemonHelper.setThreadPriority(pid, tid, uid, policy, priority);
+ }
+
+ /**
+ * Gets the thread scheduling policy and priority for the specified thread.
+ *
+ * The thread must belong to the calling process.
+ *
+ * @throws IllegalStateException If the provided tid does not belong to the calling process or
+ * car watchdog daemon failed to get the priority.
+ * @throws RemoteException If binder error happens.
+ * @throws UnsupportedOperationException If the current android release doesn't support the API.
+ */
+ public int[] getThreadPriority(int pid, int tid, int uid) throws RemoteException {
+ try {
+ return mCarWatchdogDaemonHelper.getThreadPriority(pid, tid, uid);
+ } catch (ServiceSpecificException e) {
+ // Car watchdog daemon failed to get the priority.
+ throw new IllegalStateException(e);
+ }
+ }
+
@VisibleForTesting
int getClientCount(int timeout) {
return mWatchdogProcessHandler.getClientCount(timeout);
@@ -680,12 +709,21 @@
Slogf.w(TAG, "Cannot get CarUserService");
return;
}
- UserLifecycleEventFilter userStartingOrStoppedEventFilter =
+ UserLifecycleEventFilter userEventFilter =
new UserLifecycleEventFilter.Builder()
.addEventType(USER_LIFECYCLE_EVENT_TYPE_STARTING)
+ .addEventType(USER_LIFECYCLE_EVENT_TYPE_SWITCHING)
+ .addEventType(USER_LIFECYCLE_EVENT_TYPE_UNLOCKING)
+ .addEventType(USER_LIFECYCLE_EVENT_TYPE_POST_UNLOCKED)
.addEventType(USER_LIFECYCLE_EVENT_TYPE_STOPPED).build();
- userService.addUserLifecycleListener(userStartingOrStoppedEventFilter, (event) -> {
+ userService.addUserLifecycleListener(userEventFilter, (event) -> {
if (!isEventAnyOfTypes(TAG, event, USER_LIFECYCLE_EVENT_TYPE_STARTING,
+ USER_LIFECYCLE_EVENT_TYPE_SWITCHING, USER_LIFECYCLE_EVENT_TYPE_UNLOCKING,
+ USER_LIFECYCLE_EVENT_TYPE_POST_UNLOCKED, USER_LIFECYCLE_EVENT_TYPE_STOPPED)) {
+ return;
+ }
+ if (!Car.getPlatformVersion().isAtLeast(VERSION_CODES.TIRAMISU_1)
+ && !isEventAnyOfTypes(TAG, event, USER_LIFECYCLE_EVENT_TYPE_STARTING,
USER_LIFECYCLE_EVENT_TYPE_STOPPED)) {
return;
}
@@ -699,6 +737,18 @@
userState = UserState.USER_STATE_STARTED;
userStateDesc = "STARTING";
break;
+ case USER_LIFECYCLE_EVENT_TYPE_SWITCHING:
+ userState = UserState.USER_STATE_SWITCHING;
+ userStateDesc = "SWITCHING";
+ break;
+ case USER_LIFECYCLE_EVENT_TYPE_UNLOCKING:
+ userState = UserState.USER_STATE_UNLOCKING;
+ userStateDesc = "UNLOCKING";
+ break;
+ case USER_LIFECYCLE_EVENT_TYPE_POST_UNLOCKED:
+ userState = UserState.USER_STATE_POST_UNLOCKED;
+ userStateDesc = "POST_UNLOCKED";
+ break;
case USER_LIFECYCLE_EVENT_TYPE_STOPPED:
mWatchdogProcessHandler.updateUserState(userId, /*isStopped=*/ true);
userState = UserState.USER_STATE_STOPPED;
diff --git a/service/src/com/android/car/watchdog/TimeSource.java b/service/src/com/android/car/watchdog/TimeSource.java
index 6537ce2..006b6cd 100644
--- a/service/src/com/android/car/watchdog/TimeSource.java
+++ b/service/src/com/android/car/watchdog/TimeSource.java
@@ -28,7 +28,7 @@
public static final ZoneOffset ZONE_OFFSET = ZoneOffset.UTC;
/** Returns the current instant from the time source implementation. */
- abstract Instant now();
+ public abstract Instant now();
/** Returns the current date time for the UTC timezone. */
public ZonedDateTime getCurrentDateTime() {
diff --git a/service/src/com/android/car/watchdog/WatchdogPerfHandler.java b/service/src/com/android/car/watchdog/WatchdogPerfHandler.java
index 2ccce62..c0874dc9 100644
--- a/service/src/com/android/car/watchdog/WatchdogPerfHandler.java
+++ b/service/src/com/android/car/watchdog/WatchdogPerfHandler.java
@@ -18,6 +18,7 @@
import static android.app.StatsManager.PULL_SKIP;
import static android.app.StatsManager.PULL_SUCCESS;
+import static android.car.builtin.os.UserManagerHelper.USER_NULL;
import static android.car.settings.CarSettings.Secure.KEY_PACKAGES_DISABLED_ON_RESOURCE_OVERUSE;
import static android.car.watchdog.CarWatchdogManager.FLAG_RESOURCE_OVERUSE_IO;
import static android.car.watchdog.CarWatchdogManager.STATS_PERIOD_CURRENT_DAY;
@@ -265,6 +266,11 @@
*/
@GuardedBy("mLock")
private final ArraySet<String> mActionableUserPackages = new ArraySet<>();
+ /**
+ * Tracks user packages disabled due to resource overuse.
+ */
+ @GuardedBy("mLock")
+ private final SparseArray<ArraySet<String>> mDisabledUserPackagesByUserId = new SparseArray<>();
@GuardedBy("mLock")
private ZonedDateTime mLatestStatsReportDate;
@GuardedBy("mLock")
@@ -348,6 +354,7 @@
synchronized (mLock) {
mCurrentUxRestrictions = uxRestrictions;
applyCurrentUxRestrictionsLocked();
+ syncDisabledUserPackagesLocked();
}
carUxRestrictionsManagerService.registerUxRestrictionsChangeListener(
mCarUxRestrictionsChangeListener, Display.DEFAULT_DISPLAY);
@@ -369,6 +376,10 @@
/*
* TODO(b/183436216): Implement this method.
*/
+ synchronized (mLock) {
+ writer.println("List of disabled packages per user due to resource overuse: "
+ + mDisabledUserPackagesByUserId);
+ }
mOveruseConfigurationCache.dump(writer);
}
@@ -582,6 +593,7 @@
throw new IllegalArgumentException("Package '" + packageName + "' not found");
}
String key = getUserPackageUniqueId(userId, genericPackageName);
+ PackageResourceUsage usage;
synchronized (mLock) {
// When the queried package is not cached in {@link mUsageByUserPackage}, the set API
// will update the killable state even when the package should never be killed.
@@ -591,7 +603,7 @@
// between the set and the get API calls, the daemon will provide correct killable
// state when pushing the latest stats. Ergo, the invalid killable state doesn't have
// any effect.
- PackageResourceUsage usage = mUsageByUserPackage.get(key);
+ usage = mUsageByUserPackage.get(key);
if (usage == null) {
usage = new PackageResourceUsage(userId, genericPackageName,
getDefaultKillableStateLocked(genericPackageName));
@@ -603,6 +615,10 @@
}
mUsageByUserPackage.put(key, usage);
}
+ if (!isKillable) {
+ int uid = getOrFetchUid(usage, packageName);
+ enablePackageForUser(uid, usage.genericPackageName);
+ }
mWatchdogStorage.markDirty();
if (DEBUG) {
Slogf.d(TAG, "Successfully set killable package state for user %d", userId);
@@ -612,8 +628,9 @@
private void setPackageKillableStateForAllUsers(String packageName, boolean isKillable) {
int[] userIds = getAliveUserIds();
String genericPackageName = null;
+ List<PackageResourceUsage> updatedUsages = new ArrayList<>(userIds.length);
synchronized (mLock) {
- for (int i = 0; i < userIds.length; ++i) {
+ for (int i = 0; i < userIds.length; i++) {
int userId = userIds[i];
String name = mPackageInfoHandler.getNameForUserPackage(packageName, userId);
if (name == null) {
@@ -630,6 +647,7 @@
throw new IllegalArgumentException(
"Package killable state is not updatable");
}
+ updatedUsages.add(usage);
}
if (genericPackageName != null) {
if (!isKillable) {
@@ -640,6 +658,16 @@
mWatchdogStorage.markDirty();
}
}
+ // Enabling user packages requires accessing package manager which requires making binder
+ // calls. Binder calls should not be made while holding a lock, given it might lead to
+ // deadlock. Hence, enabling packages after the synchronized block.
+ if (!isKillable) {
+ for (int i = 0; i < updatedUsages.size(); i++) {
+ PackageResourceUsage usage = updatedUsages.get(i);
+ int uid = getOrFetchUid(usage, packageName);
+ enablePackageForUser(uid, usage.genericPackageName);
+ }
+ }
if (DEBUG) {
Slogf.d(TAG, "Successfully set killable package state for all users");
}
@@ -868,38 +896,16 @@
Slogf.i(TAG,
"Reset resource overuse settings and stats for user '%d' package '%s'",
usage.userId, usage.genericPackageName);
- List<String> packages;
- if (usage.isSharedPackage()) {
- int uid = usage.getUid();
- if (uid == INVALID_UID) {
- // Only enable packages that were disabled by the watchdog service. Ergo, if
- // the usage doesn't have a valid UID, the package was not recently disabled
- // by the watchdog service (unless the service crashed) and can be safely
- // skipped.
- Slogf.e(TAG, "Skipping enabling user %d's package %s", usage.userId,
- usage.genericPackageName);
- continue;
- }
- packages = mPackageInfoHandler.getPackagesForUid(uid, usage.genericPackageName);
- } else {
- packages = Collections.singletonList(usage.genericPackageName);
+ if (usage.isSharedPackage() && usage.getUid() == INVALID_UID) {
+ // Only enable packages that were disabled by the watchdog service. Ergo, if
+ // the usage doesn't have a valid UID, the package was not recently disabled
+ // by the watchdog service (unless the service crashed) and can be safely
+ // skipped.
+ Slogf.e(TAG, "Skipping enabling user %d's package %s", usage.userId,
+ usage.genericPackageName);
+ continue;
}
- for (int pkgIdx = 0; pkgIdx < packages.size(); pkgIdx++) {
- String packageName = packages.get(pkgIdx);
- try {
- if (PackageManagerHelper.getApplicationEnabledSettingForUser(packageName,
- usage.userId) != COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED) {
- continue;
- }
- PackageManagerHelper.setApplicationEnabledSettingForUser(
- packageName, COMPONENT_ENABLED_STATE_ENABLED, /* flags= */ 0,
- usage.userId, mContext.getPackageName());
- Slogf.i(TAG, "Enabled user '%d' package '%s'", usage.userId, packageName);
- } catch (RemoteException | IllegalArgumentException e) {
- Slogf.e(TAG, e, "Failed to verify and enable user %d, package '%s'",
- usage.userId, packageName);
- }
- }
+ enablePackageForUser(usage.getUid(), usage.genericPackageName);
}
}
}
@@ -940,7 +946,7 @@
}
/** Handles intents from user notification actions. */
- public void handleIntent(Intent intent) {
+ public void processUserNotificationIntent(Intent intent) {
String action = intent.getAction();
String packageName = intent.getStringExtra(Intent.EXTRA_PACKAGE_NAME);
UserHandle userHandle = intent.getParcelableExtra(Intent.EXTRA_USER);
@@ -1009,8 +1015,53 @@
}
}
+ /** Handles when system broadcast package changed action */
+ public void processPackageChangedIntent(Intent intent) {
+ int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, USER_NULL);
+ if (userId == USER_NULL) {
+ Slogf.w(TAG, "Skipping package changed action with USER_NULL user");
+ return;
+ }
+ String packageName = intent.getData().getSchemeSpecificPart();
+ try {
+ if (PackageManagerHelper.getApplicationEnabledSettingForUser(packageName, userId)
+ != COMPONENT_ENABLED_STATE_ENABLED) {
+ return;
+ }
+ } catch (Exception e) {
+ // Catch IllegalArgumentException thrown by PackageManager when the package
+ // is not found. CarWatchdogService shouldn't crash when the package
+ // no longer exists when the {@link ACTION_PACKAGE_CHANGED} broadcast is
+ // handled.
+ Slogf.e(TAG, e,
+ "Failed to verify enabled setting for user %d, package '%s'",
+ userId, packageName);
+ return;
+ }
+ synchronized (mLock) {
+ ArraySet<String> disabledPackages = mDisabledUserPackagesByUserId.get(userId);
+ if (disabledPackages == null || !disabledPackages.contains(packageName)) {
+ return;
+ }
+ removeFromDisabledPackagesSettingsStringLocked(packageName, userId);
+ disabledPackages.remove(packageName);
+ if (disabledPackages.isEmpty()) {
+ mDisabledUserPackagesByUserId.remove(userId);
+ }
+ }
+ if (DEBUG) {
+ Slogf.d(TAG, "Successfully enabled package due to package changed action");
+ }
+ }
+
/** Disables a package for specific user until used. */
public boolean disablePackageForUser(String packageName, @UserIdInt int userId) {
+ synchronized (mLock) {
+ ArraySet<String> disabledPackages = mDisabledUserPackagesByUserId.get(userId);
+ if (disabledPackages != null && disabledPackages.contains(packageName)) {
+ return true;
+ }
+ }
try {
int currentEnabledState =
PackageManagerHelper.getApplicationEnabledSettingForUser(packageName, userId);
@@ -1026,7 +1077,15 @@
PackageManagerHelper.setApplicationEnabledSettingForUser(packageName,
COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED, /* flags= */ 0, userId,
mContext.getPackageName());
- appendToDisabledPackagesSettingsString(packageName, userId);
+ synchronized (mLock) {
+ ArraySet<String> disabledPackages = mDisabledUserPackagesByUserId.get(userId);
+ if (disabledPackages == null) {
+ disabledPackages = new ArraySet<>(1);
+ }
+ appendToDisabledPackagesSettingsString(packageName, userId);
+ disabledPackages.add(packageName);
+ mDisabledUserPackagesByUserId.put(userId, disabledPackages);
+ }
Slogf.i(TAG, "Disabled package '%s' on user %d until used due to resource overuse",
packageName, userId);
} catch (Exception e) {
@@ -1038,33 +1097,6 @@
}
/**
- * Removes {@code packageName} from {@link KEY_PACKAGES_DISABLED_ON_RESOURCE_OVERUSE}
- * {@code Settings} of the given user.
- */
- public void removeFromDisabledPackagesSettingsString(String packageName,
- @UserIdInt int userId) {
- ContentResolver contentResolverForUser = getContentResolverForUser(mContext, userId);
- // Appending and removing package names to/from the settings string
- // KEY_PACKAGES_DISABLED_ON_RESOURCE_OVERUSE is done only by this class. So, synchronize
- // these operations using the class wide lock.
- synchronized (mLock) {
- ArraySet<String> packages = extractPackages(
- Settings.Secure.getString(contentResolverForUser,
- KEY_PACKAGES_DISABLED_ON_RESOURCE_OVERUSE));
- if (!packages.remove(packageName)) {
- return;
- }
- String settingsString = constructSettingsString(packages);
- Settings.Secure.putString(contentResolverForUser,
- KEY_PACKAGES_DISABLED_ON_RESOURCE_OVERUSE, settingsString);
- if (DEBUG) {
- Slogf.d(TAG, "Removed %s from %s. New value is '%s'", packageName,
- KEY_PACKAGES_DISABLED_ON_RESOURCE_OVERUSE, settingsString);
- }
- }
- }
-
- /**
* Sets the delay to handle resource overuse after the package is notified of resource overuse.
*/
public void setOveruseHandlingDelay(long millis) {
@@ -1713,6 +1745,49 @@
}
}
+ private void enablePackageForUser(int uid, String genericPackageName) {
+ int userId = UserHandle.getUserHandleForUid(uid).getIdentifier();
+ synchronized (mLock) {
+ ArraySet<String> disabledPackages = mDisabledUserPackagesByUserId.get(userId);
+ if (disabledPackages == null) {
+ return;
+ }
+ }
+ List<String> packages;
+ if (isSharedPackage(genericPackageName)) {
+ packages = mPackageInfoHandler.getPackagesForUid(uid, genericPackageName);
+ } else {
+ packages = Collections.singletonList(genericPackageName);
+ }
+ for (int i = 0; i < packages.size(); i++) {
+ String packageName = packages.get(i);
+ try {
+ if (PackageManagerHelper.getApplicationEnabledSettingForUser(packageName,
+ userId) != COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED) {
+ continue;
+ }
+ synchronized (mLock) {
+ ArraySet<String> disabledPackages = mDisabledUserPackagesByUserId.get(userId);
+ if (disabledPackages == null || !disabledPackages.contains(packageName)) {
+ continue;
+ }
+ removeFromDisabledPackagesSettingsStringLocked(packageName, userId);
+ disabledPackages.remove(packageName);
+ if (disabledPackages.isEmpty()) {
+ mDisabledUserPackagesByUserId.remove(userId);
+ }
+ }
+ PackageManagerHelper.setApplicationEnabledSettingForUser(
+ packageName, COMPONENT_ENABLED_STATE_ENABLED, /* flags= */ 0, userId,
+ mContext.getPackageName());
+ Slogf.i(TAG, "Enabled user '%d' package '%s'", userId, packageName);
+ } catch (RemoteException | IllegalArgumentException e) {
+ Slogf.e(TAG, e, "Failed to verify and enable user %d, package '%s'", userId,
+ packageName);
+ }
+ }
+ }
+
private void sendResourceOveruseNotificationsAsUser(@UserIdInt int userId,
SparseArray<String> headsUpNotificationPackagesById,
SparseArray<String> notificationCenterPackagesById) {
@@ -1753,6 +1828,61 @@
}
}
+ /**
+ * Removes {@code packageName} from {@link KEY_PACKAGES_DISABLED_ON_RESOURCE_OVERUSE}
+ * {@code Settings} of the given user.
+ *
+ * <p> Appending and removing package names to/from the settings string
+ * KEY_PACKAGES_DISABLED_ON_RESOURCE_OVERUSE is done only by this class. So, synchronize
+ * these operations using the class wide lock.
+ */
+ @GuardedBy("mLock")
+ private void removeFromDisabledPackagesSettingsStringLocked(String packageName,
+ @UserIdInt int userId) {
+ ContentResolver contentResolverForUser = getContentResolverForUser(mContext, userId);
+ ArraySet<String> packages = extractPackages(
+ Settings.Secure.getString(contentResolverForUser,
+ KEY_PACKAGES_DISABLED_ON_RESOURCE_OVERUSE));
+ if (!packages.remove(packageName)) {
+ return;
+ }
+ String settingsString = constructSettingsString(packages);
+ Settings.Secure.putString(contentResolverForUser,
+ KEY_PACKAGES_DISABLED_ON_RESOURCE_OVERUSE, settingsString);
+ if (DEBUG) {
+ Slogf.d(TAG, "Removed %s from %s. New value is '%s'", packageName,
+ KEY_PACKAGES_DISABLED_ON_RESOURCE_OVERUSE, settingsString);
+ }
+ }
+
+ /**
+ * Syncs the {@link KEY_PACKAGES_DISABLED_ON_RESOURCE_OVERUSE} {@code Settings} of all users
+ * with the internal cache.
+ *
+ * <p> Appending and removing package names to/from the settings string
+ * KEY_PACKAGES_DISABLED_ON_RESOURCE_OVERUSE is done only by this class. So, synchronize
+ * these operations using the class wide lock.
+ */
+ @GuardedBy("mLock")
+ private void syncDisabledUserPackagesLocked() {
+ int[] userIds = getAliveUserIds();
+ for (int i = 0; i < userIds.length; i++) {
+ int userId = userIds[i];
+ ContentResolver contentResolverForUser = getContentResolverForUser(mContext, userId);
+ ArraySet<String> packages = extractPackages(
+ Settings.Secure.getString(contentResolverForUser,
+ KEY_PACKAGES_DISABLED_ON_RESOURCE_OVERUSE));
+ if (packages.isEmpty()) {
+ continue;
+ }
+ mDisabledUserPackagesByUserId.put(userId, packages);
+ }
+ if (DEBUG) {
+ Slogf.d(TAG, "Synced the %s settings to the disabled user packages cache.",
+ KEY_PACKAGES_DISABLED_ON_RESOURCE_OVERUSE);
+ }
+ }
+
private static ArraySet<String> extractPackages(String settingsString) {
return TextUtils.isEmpty(settingsString) ? new ArraySet<>()
: new ArraySet<>(Arrays.asList(settingsString.split(
@@ -2015,6 +2145,22 @@
numPulledUidSummaryStats);
}
+ /**
+ * Gets the UID for the resource usage's user package.
+ *
+ * <p>If the package resource usage's UID is not valid, fetches the UID for the user package
+ * from the package manager. Returns {@code INVALID_UID} if the package manager cannot find the
+ * package. </p>
+ */
+ private int getOrFetchUid(PackageResourceUsage usage, String packageName) {
+ int uid = usage.getUid();
+ if (uid == INVALID_UID) {
+ uid = getPackageUidAsUser(mContext.getPackageManager(), packageName,
+ usage.userId);
+ }
+ return uid;
+ }
+
private SparseArray<Map<String, Integer>> getPackageUidsForUsers(
SparseArray<List<String>> genericPackageNamesByUserId) {
PackageManager pm = mContext.getPackageManager();
@@ -2052,7 +2198,7 @@
uidsByGenericPackageNames.put(genericPackageName, usage.getUid());
continue;
}
- if (genericPackageName.startsWith(SHARED_PACKAGE_PREFIX)) {
+ if (isSharedPackage(genericPackageName)) {
resolveSharedUserIds.add(
genericPackageName.substring(SHARED_PACKAGE_PREFIX.length()));
continue;
@@ -2412,6 +2558,10 @@
}
}
+ private static boolean isSharedPackage(String genericPackageName) {
+ return genericPackageName.startsWith(SHARED_PACKAGE_PREFIX);
+ }
+
private static void replaceKey(Map<String, PerStateBytes> map, String oldKey, String newKey) {
PerStateBytes perStateBytes = map.get(oldKey);
if (perStateBytes != null) {
diff --git a/service/src/com/android/car/watchdog/WatchdogProcessHandler.java b/service/src/com/android/car/watchdog/WatchdogProcessHandler.java
index 60b3dc4..3ff6e2f 100644
--- a/service/src/com/android/car/watchdog/WatchdogProcessHandler.java
+++ b/service/src/com/android/car/watchdog/WatchdogProcessHandler.java
@@ -457,7 +457,11 @@
int timeout) {
this.client = client;
this.pid = pid;
- // TODO(b/213939034): Read pid start time and populate this field.
+ // CarService doesn't have sepolicy access to read per-pid proc files, so it cannot
+ // fetch the pid's actual start time. When a client process registers with
+ // the CarService, it is safe to assume the process is still alive. So, populate
+ // elapsed real time and the consumer (CarServiceHelperService) of this data should
+ // verify that the actual start time is less than the reported start time.
this.startTimeMillis = SystemClock.elapsedRealtime();
this.userId = userId;
this.timeout = timeout;
diff --git a/tests/AdasLocationTestApp/AndroidManifest.xml b/tests/AdasLocationTestApp/AndroidManifest.xml
index 2d10040..481f11a 100644
--- a/tests/AdasLocationTestApp/AndroidManifest.xml
+++ b/tests/AdasLocationTestApp/AndroidManifest.xml
@@ -15,8 +15,7 @@
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.google.android.car.adaslocation"
- android:sharedUserId="android.uid.system">
+ package="com.google.android.car.adaslocation">
<!-- The app needs to access device location to verify ADAS and main location switch work as
expected. -->
@@ -25,6 +24,10 @@
<uses-permission android:name="android.permission.LOCATION_BYPASS"/>
<application android:label="AdasLocationTestApp">
+ <!-- This app is a test app with no privacy policy. The fake policy url
+ is for testing features in Location Settings. -->
+ <meta-data android:name="privacy_policy"
+ android:value="https://source.android.com/devices/automotive/location_bypass_policy"/>
<activity android:name=".AdasLocationActivity"
android:theme="@style/Theme.AppCompat"
android:exported="true">
diff --git a/tests/BugReportApp/AndroidManifest.xml b/tests/BugReportApp/AndroidManifest.xml
index b31ee3b..396ea6e 100644
--- a/tests/BugReportApp/AndroidManifest.xml
+++ b/tests/BugReportApp/AndroidManifest.xml
@@ -36,6 +36,7 @@
<uses-permission android:name="android.permission.READ_DEVICE_CONFIG"/>
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
<uses-permission android:name="android.permission.BROADCAST_CLOSE_SYSTEM_DIALOGS"/>
+ <uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>
<application android:label="@string/app_name"
android:icon="@drawable/ic_launcher"
diff --git a/tests/BugReportApp/res/values-hy/strings.xml b/tests/BugReportApp/res/values-hy/strings.xml
index 41ecfac..e39e460 100644
--- a/tests/BugReportApp/res/values-hy/strings.xml
+++ b/tests/BugReportApp/res/values-hy/strings.xml
@@ -19,7 +19,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_name" msgid="2596316479611335185">"Հաղորդում վրիպակի մասին"</string>
<string name="bugreport_info_quit" msgid="5590138890181142473">"Փակել"</string>
- <string name="bugreport_info_start" msgid="667324824650830832">"Գործարկել վրիպակի մասին հաղորդումը"</string>
+ <string name="bugreport_info_start" msgid="667324824650830832">"Գործարկել վրիպակի մասին զեկույցը"</string>
<string name="bugreport_info_status" msgid="7211044508792815451">"Կարգավիճակը՝"</string>
<string name="bugreport_info_expires_soon_notice" msgid="927139313070992675">"Վրիպակի մասին այս հաղորդման ժամկետը շուտով կլրանա"</string>
<string name="bugreport_dialog_submit" msgid="2789636252713280633">"Ուղարկել"</string>
@@ -31,7 +31,7 @@
<string name="bugreport_dialog_title" msgid="3315160684205929910">"Բարձրաձայն նկարագրեք սխալը"</string>
<string name="bugreport_dialog_add_audio_to_existing" msgid="4958460267276935700">"Վրիպակների մասին հաշվետվության վերաբերյալ ձայնային հաղորդագրություն, ժամը՝ %s։"</string>
<string name="bugreport_dialog_recording_finished" msgid="3982335902169398758">"Գրանցումն ավարտվեց"</string>
- <string name="bugreport_dialog_in_progress_title" msgid="1663500052146177338">"Վրիպակի մասին հաղորդումը բեռնվում է"</string>
+ <string name="bugreport_dialog_in_progress_title" msgid="1663500052146177338">"Վրիպակի մասին զեկույցը բեռնվում է"</string>
<string name="bugreport_dialog_in_progress_title_finished" msgid="1610236990020413471">"Սխալի մասին զեկույցը բեռնվել է"</string>
<string name="bugreport_add_audio_button_text" msgid="8606400151705699144">"Ավելացնել աուդիո"</string>
<string name="bugreport_add_audio_upload_button_text" msgid="3830917832551764694">"Ավելացնել աուդիո և վերբեռնել"</string>
@@ -39,12 +39,12 @@
<string name="bugreport_upload_button_text" msgid="4136749466634820848">"Վերբեռնել"</string>
<string name="bugreport_upload_gcs_button_text" msgid="5844929656507607424">"Վերբեռնել GCS"</string>
<string name="toast_permissions_denied" msgid="7054832711916992770">"Տրամադրեք թույլտվություններ"</string>
- <string name="toast_bug_report_in_progress" msgid="5218530088025955746">"Վրիպակի մասին հաղորդումը բեռնվում է"</string>
- <string name="toast_bug_report_started" msgid="891404618481185195">"Վրիպակի մասին հաղորդումը ստեղծվում է"</string>
+ <string name="toast_bug_report_in_progress" msgid="5218530088025955746">"Վրիպակի մասին զեկույցը բեռնվում է"</string>
+ <string name="toast_bug_report_started" msgid="891404618481185195">"Վրիպակի մասին զեկույցը ստեղծվում է"</string>
<string name="toast_status_failed" msgid="6365384202315043395">"Վրիպակի զեկույցի հետ կապված սխալ առաջացավ"</string>
<string name="toast_status_screencap_failed" msgid="2187083897594745149">"Չհաջողվեց ստեղծել սքրինշոթ"</string>
<string name="toast_status_dump_state_failed" msgid="3496460783060512078">"Dumpstate ծառայության սխալ"</string>
- <string name="notification_bugreport_in_progress" msgid="8486454116357963238">"Վրիպակի մասին հաղորդումը բեռնվում է"</string>
- <string name="notification_bugreport_finished_title" msgid="1188447311929693472">"Վրիպակի մասին հաղորդումը բեռնվել է"</string>
- <string name="notification_bugreport_channel_name" msgid="776902295433824255">"Վրիպակի մասին հաղորդման կարգավիճակի ալիք"</string>
+ <string name="notification_bugreport_in_progress" msgid="8486454116357963238">"Վրիպակի մասին զեկույցը բեռնվում է"</string>
+ <string name="notification_bugreport_finished_title" msgid="1188447311929693472">"Վրիպակի մասին զեկույցը բեռնվել է"</string>
+ <string name="notification_bugreport_channel_name" msgid="776902295433824255">"Վրիպակի մասին զեկույցի կարգավիճակի ալիք"</string>
</resources>
diff --git a/tests/BugReportApp/res/values-kn/strings.xml b/tests/BugReportApp/res/values-kn/strings.xml
index 0b5dd81..77e563c 100644
--- a/tests/BugReportApp/res/values-kn/strings.xml
+++ b/tests/BugReportApp/res/values-kn/strings.xml
@@ -29,7 +29,7 @@
<string name="bugreport_dialog_show_bugreports" msgid="6964385141627170297">"ಬಗ್ ವರದಿಗಳನ್ನು ತೋರಿಸಿ"</string>
<string name="bugreport_dialog_close" msgid="289925437277364266">"ಮುಚ್ಚಿರಿ"</string>
<string name="bugreport_dialog_title" msgid="3315160684205929910">"ಸಮಸ್ಯೆಯ ಕುರಿತು ಮಾತನಾಡಿ ಮತ್ತು ವಿವರಿಸಿ"</string>
- <string name="bugreport_dialog_add_audio_to_existing" msgid="4958460267276935700">"%s ನಲ್ಲಿ ಬಗ್ ವರದಿ ಮಾಡುವಿಕೆಗಾಗಿ ಆಡಿಯೋ ಸಂದೇಶ"</string>
+ <string name="bugreport_dialog_add_audio_to_existing" msgid="4958460267276935700">"%s ನಲ್ಲಿ ಬಗ್ ವರದಿ ಮಾಡುವಿಕೆಗಾಗಿ ಆಡಿಯೊ ಸಂದೇಶ"</string>
<string name="bugreport_dialog_recording_finished" msgid="3982335902169398758">"ರೆಕಾರ್ಡಿಂಗ್ ಪೂರ್ಣಗೊಂಡಿದೆ"</string>
<string name="bugreport_dialog_in_progress_title" msgid="1663500052146177338">"ಬಗ್ ವರದಿಮಾಡುವಿಕೆ ಪ್ರಕ್ರಿಯೆಯಲ್ಲಿದೆ"</string>
<string name="bugreport_dialog_in_progress_title_finished" msgid="1610236990020413471">"ಬಗ್ ವರದಿಯನ್ನು ಸಂಗ್ರಹಿಸಲಾಗಿದೆ"</string>
diff --git a/tests/BugReportApp/res/values-or/strings.xml b/tests/BugReportApp/res/values-or/strings.xml
index d4a7771..79ce668 100644
--- a/tests/BugReportApp/res/values-or/strings.xml
+++ b/tests/BugReportApp/res/values-or/strings.xml
@@ -23,7 +23,7 @@
<string name="bugreport_info_status" msgid="7211044508792815451">"ସ୍ଥିତି:"</string>
<string name="bugreport_info_expires_soon_notice" msgid="927139313070992675">"ଏହି ବଗ୍ ରିପୋର୍ଟର ମିଆଦ ଶୀଘ୍ର ସମାପ୍ତ ହେବ"</string>
<string name="bugreport_dialog_submit" msgid="2789636252713280633">"ଦାଖଲ କରନ୍ତୁ"</string>
- <string name="bugreport_dialog_cancel" msgid="4741928791364757040">"ବାତିଲ କରନ୍ତୁ"</string>
+ <string name="bugreport_dialog_cancel" msgid="4741928791364757040">"ବାତିଲ୍ କରନ୍ତୁ"</string>
<string name="bugreport_dialog_upload" msgid="2517386929450370781">"ଅପ୍ଲୋଡ୍"</string>
<string name="bugreport_dialog_save" msgid="3291363266190644226">"ସେଭ୍ କରନ୍ତୁ"</string>
<string name="bugreport_dialog_show_bugreports" msgid="6964385141627170297">"ବଗ୍ ରିପୋର୍ଟ୍ଗୁଡ଼ିକୁ ଦେଖାନ୍ତୁ"</string>
diff --git a/tests/BugReportApp/res/values/styles.xml b/tests/BugReportApp/res/values/styles.xml
index 9b146a2..5d8a9d6 100644
--- a/tests/BugReportApp/res/values/styles.xml
+++ b/tests/BugReportApp/res/values/styles.xml
@@ -32,7 +32,7 @@
</style>
<style name="TextAppearance.BugReportUi.Body" parent="android:TextAppearance.DeviceDefault">
- <item name="android:textColor">@*android:color/car_body1</item>
+ <item name="android:textColor">?android:attr/textColorPrimary</item>
<item name="android:textSize">@dimen/bug_report_small_text_size</item>
</style>
</resources>
diff --git a/tests/BugReportApp/src/com/android/car/bugreport/BugReportActivity.java b/tests/BugReportApp/src/com/android/car/bugreport/BugReportActivity.java
index 2b1fe4a..202f573 100644
--- a/tests/BugReportApp/src/com/android/car/bugreport/BugReportActivity.java
+++ b/tests/BugReportApp/src/com/android/car/bugreport/BugReportActivity.java
@@ -17,6 +17,9 @@
import static com.android.car.bugreport.BugReportService.MAX_PROGRESS_VALUE;
+import static java.util.stream.Collectors.collectingAndThen;
+import static java.util.stream.Collectors.toList;
+
import android.Manifest;
import android.app.Activity;
import android.car.Car;
@@ -47,6 +50,8 @@
import android.widget.Toast;
import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSortedSet;
import com.google.common.io.ByteStreams;
import java.io.File;
@@ -54,7 +59,6 @@
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
-import java.util.Arrays;
import java.util.Date;
import java.util.Objects;
import java.util.Random;
@@ -80,7 +84,9 @@
"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 int PERMISSIONS_REQUEST_ID = 1;
+ private static final ImmutableSortedSet<String> REQUIRED_PERMISSIONS = ImmutableSortedSet.of(
+ Manifest.permission.RECORD_AUDIO, Manifest.permission.POST_NOTIFICATIONS);
private static final String EXTRA_BUGREPORT_ID = "bugreport-id";
@@ -412,14 +418,25 @@
mMetaBugReport.getTimestamp()));
}
- if (!hasRecordPermissions()) {
- requestRecordPermissions();
- } else {
+ ImmutableList<String> missingPermissions = findMissingPermissions();
+ if (missingPermissions.isEmpty()) {
startRecordingWithPermission();
+ } else {
+ requestPermissions(missingPermissions.toArray(new String[missingPermissions.size()]),
+ PERMISSIONS_REQUEST_ID);
}
}
/**
+ * Finds required permissions not granted.
+ */
+ private ImmutableList<String> findMissingPermissions() {
+ return REQUIRED_PERMISSIONS.stream().filter(permission -> checkSelfPermission(permission)
+ != PackageManager.PERMISSION_GRANTED).collect(
+ collectingAndThen(toList(), ImmutableList::copyOf));
+ }
+
+ /**
* Cancels bugreporting by stopping audio recording and deleting temp files.
*/
private void cancelAudioMessageRecording() {
@@ -491,37 +508,26 @@
finish();
}
- private void requestRecordPermissions() {
- requestPermissions(
- new String[]{Manifest.permission.RECORD_AUDIO}, AUDIO_PERMISSIONS_REQUEST_ID);
- }
-
- private boolean hasRecordPermissions() {
- return checkSelfPermission(Manifest.permission.RECORD_AUDIO)
- == PackageManager.PERMISSION_GRANTED;
- }
-
@Override
public void onRequestPermissionsResult(
int requestCode, String[] permissions, int[] grantResults) {
- if (requestCode != AUDIO_PERMISSIONS_REQUEST_ID) {
+ if (requestCode != PERMISSIONS_REQUEST_ID) {
return;
}
- for (int i = 0; i < grantResults.length; i++) {
- if (Manifest.permission.RECORD_AUDIO.equals(permissions[i])
- && grantResults[i] == PackageManager.PERMISSION_GRANTED) {
- // Start recording from UI thread, otherwise when MediaRecord#start() fails,
- // stack trace gets confusing.
- mHandler.post(this::startRecordingWithPermission);
- return;
- }
+
+ ImmutableList<String> missingPermissions = findMissingPermissions();
+ if (missingPermissions.isEmpty()) {
+ // Start recording from UI thread, otherwise when MediaRecord#start() fails,
+ // stack trace gets confusing.
+ mHandler.post(this::startRecordingWithPermission);
+ } else {
+ handleMissingPermissions(missingPermissions);
}
- handleNoPermission(permissions);
}
- private void handleNoPermission(String[] permissions) {
+ private void handleMissingPermissions(ImmutableList missingPermissions) {
String text = this.getText(R.string.toast_permissions_denied) + " : "
- + Arrays.toString(permissions);
+ + String.join(", ", missingPermissions);
Log.w(TAG, text);
Toast.makeText(this, text, Toast.LENGTH_LONG).show();
if (mMetaBugReport == null) {
@@ -542,7 +548,7 @@
Log.i(TAG, "Started voice recording, and saving audio to " + mAudioFile);
mLastAudioFocusRequest = new AudioFocusRequest.Builder(
- AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE)
+ AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE)
.setOnAudioFocusChangeListener(focusChange ->
Log.d(TAG, "AudioManager focus change " + focusChange))
.setAudioAttributes(new AudioAttributes.Builder()
@@ -620,7 +626,7 @@
* 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}.
+ * @param type bug report type, {@link MetaBugReport.BugReportType}.
*/
static MetaBugReport createBugReport(Context context, int type) {
String timestamp = MetaBugReport.toBugReportTimestamp(new Date());
diff --git a/tests/BugReportApp/src/com/android/car/bugreport/Status.java b/tests/BugReportApp/src/com/android/car/bugreport/Status.java
index 1c92a3a..dab82aa 100644
--- a/tests/BugReportApp/src/com/android/car/bugreport/Status.java
+++ b/tests/BugReportApp/src/com/android/car/bugreport/Status.java
@@ -20,19 +20,19 @@
// Bugreport is being written
STATUS_WRITE_PENDING(0),
- // Writing bugreport failed. This is the final state.
+ // Writing bugreport failed. This is a final state.
STATUS_WRITE_FAILED(1),
- // Bugreport is waiting to be uploaded
+ // Bugreport is waiting to be uploaded, or is currently uploading.
STATUS_UPLOAD_PENDING(2),
- // Bugreport uploaded successfully. This is the final state.
+ // Bugreport uploaded successfully. This is a final state.
STATUS_UPLOAD_SUCCESS(3),
- // Bugreport failed to upload. This is the final state.
+ // Bugreport failed to upload. This is a final state.
STATUS_UPLOAD_FAILED(4),
- // Bugreport is cancelled by user. This is the final state.
+ // Bugreport is cancelled by user. This is a final state.
STATUS_USER_CANCELLED(5),
// Bugreport is pending user choice on whether to upload or copy.
@@ -41,7 +41,7 @@
// Bugreport was moved successfully.
STATUS_MOVE_SUCCESSFUL(7),
- // Bugreport move has failed. This is the final state.
+ // Bugreport move has failed. This is a final state.
STATUS_MOVE_FAILED(8),
// Bugreport is moving to USB drive.
@@ -83,7 +83,7 @@
case 1:
return "Write failed";
case 2:
- return "Upload pending";
+ return "Uploading, or waiting for network";
case 3:
return "Upload successful";
case 4:
diff --git a/tests/CarEvsCameraPreviewApp/src/com/google/android/car/evs/CarEvsCameraActivity.java b/tests/CarEvsCameraPreviewApp/src/com/google/android/car/evs/CarEvsCameraActivity.java
index e7a9ccd..4c3eaa1 100644
--- a/tests/CarEvsCameraPreviewApp/src/com/google/android/car/evs/CarEvsCameraActivity.java
+++ b/tests/CarEvsCameraPreviewApp/src/com/google/android/car/evs/CarEvsCameraActivity.java
@@ -16,8 +16,11 @@
package com.google.android.car.evs;
+import static android.car.evs.CarEvsManager.ERROR_NONE;
+
import android.app.Activity;
import android.car.Car;
+import android.car.Car.CarServiceLifecycleListener;
import android.car.evs.CarEvsManager;
import android.os.Bundle;
import android.util.Log;
@@ -26,21 +29,42 @@
private static final String TAG = CarEvsCameraActivity.class.getSimpleName();
private static final int CAR_WAIT_TIMEOUT_MS = 3_000;
+ /** CarService status listener */
+ private final CarServiceLifecycleListener mCarServiceLifecycleListener = (car, ready) -> {
+ if (!ready) {
+ return;
+ }
+
+ try {
+ CarEvsManager evsManager = (CarEvsManager) car.getCarManager(
+ Car.CAR_EVS_SERVICE);
+ if (evsManager.startActivity(CarEvsManager.SERVICE_TYPE_REARVIEW) != ERROR_NONE) {
+ Log.e(TAG, "Failed to start a camera preview activity");
+ }
+ } finally {
+ mCar = car;
+ finish();
+ }
+ };
+
+ private Car mCar;
+
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Car.createCar(getApplicationContext(), /* handler = */ null, CAR_WAIT_TIMEOUT_MS,
- (car, ready) -> {
- if (!ready) {
- finish();
- return;
- }
- CarEvsManager evsManager = (CarEvsManager) car.getCarManager(
- Car.CAR_EVS_SERVICE);
- int result = evsManager.startActivity(CarEvsManager.SERVICE_TYPE_REARVIEW);
- Log.i(TAG, "startActivity(): " + result);
- finish();
- });
+ mCarServiceLifecycleListener);
+ }
+
+ @Override
+ protected void onDestroy() {
+ Log.d(TAG, "onDestroy");
+ if (mCar != null) {
+ // Explicitly stops monitoring the car service's status
+ mCar.disconnect();
+ }
+
+ super.onDestroy();
}
}
diff --git a/tests/CarEvsCameraPreviewApp/src/com/google/android/car/evs/CarEvsCameraPreviewActivity.java b/tests/CarEvsCameraPreviewApp/src/com/google/android/car/evs/CarEvsCameraPreviewActivity.java
index 90fd608..f5c9337 100644
--- a/tests/CarEvsCameraPreviewApp/src/com/google/android/car/evs/CarEvsCameraPreviewActivity.java
+++ b/tests/CarEvsCameraPreviewApp/src/com/google/android/car/evs/CarEvsCameraPreviewActivity.java
@@ -16,6 +16,7 @@
package com.google.android.car.evs;
+import static android.car.evs.CarEvsManager.ERROR_NONE;
import static android.hardware.display.DisplayManager.DisplayListener;
import android.app.Activity;
@@ -41,6 +42,8 @@
import android.view.WindowManager;
import android.widget.LinearLayout;
+import androidx.annotation.GuardedBy;
+
import java.util.ArrayList;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
@@ -48,7 +51,35 @@
public class CarEvsCameraPreviewActivity extends Activity {
private static final String TAG = CarEvsCameraPreviewActivity.class.getSimpleName();
+ /**
+ * Defines internal states.
+ */
+ private final static int STREAM_STATE_STOPPED = 0;
+ private final static int STREAM_STATE_VISIBLE = 1;
+ private final static int STREAM_STATE_INVISIBLE = 2;
+ private final static int STREAM_STATE_LOST = 3;
+
+ private static String streamStateToString(int state) {
+ switch (state) {
+ case STREAM_STATE_STOPPED:
+ return "STOPPED";
+
+ case STREAM_STATE_VISIBLE:
+ return "VISIBLE";
+
+ case STREAM_STATE_INVISIBLE:
+ return "INVISIBLE";
+
+ case STREAM_STATE_LOST:
+ return "LOST";
+
+ default:
+ return "UNKNOWN: " + state;
+ }
+ }
+
/** Buffer queue to store references of received frames */
+ @GuardedBy("mLock")
private final ArrayList<CarEvsBufferDescriptor> mBufferQueue = new ArrayList<>();
private final Object mLock = new Object();
@@ -68,11 +99,16 @@
private int mDisplayState = Display.STATE_OFF;
/** Tells whether or not a video stream is running */
- private boolean mStreamRunning = false;
+ @GuardedBy("mLock")
+ private int mStreamState = STREAM_STATE_STOPPED;
+ @GuardedBy("mLock")
private Car mCar;
+
+ @GuardedBy("mLock")
private CarEvsManager mEvsManager;
+ @GuardedBy("mLock")
private IBinder mSessionToken;
private boolean mUseSystemWindow;
@@ -93,9 +129,15 @@
@Override
public void onNewFrame(CarEvsBufferDescriptor buffer) {
- // Enqueues a new frame and posts a rendering job
- synchronized (mBufferQueue) {
- mBufferQueue.add(buffer);
+ synchronized (mLock) {
+ if (mStreamState == STREAM_STATE_INVISIBLE) {
+ // When the activity becomes invisible (e.g. goes background), we immediately
+ // returns received frame buffers instead of stopping a video stream.
+ returnBufferLocked(buffer);
+ } else {
+ // Enqueues a new frame and posts a rendering job
+ mBufferQueue.add(buffer);
+ }
}
}
};
@@ -119,34 +161,37 @@
int state = decideViewVisibility();
synchronized (mLock) {
mDisplayState = state;
- handleVideoStreamLocked();
+ handleVideoStreamLocked(state == Display.STATE_ON ?
+ STREAM_STATE_VISIBLE : STREAM_STATE_INVISIBLE);
}
}
};
/** CarService status listener */
private final CarServiceLifecycleListener mCarServiceLifecycleListener = (car, ready) -> {
- if (!ready) {
- Log.d(TAG, "Disconnected from the Car Service");
- // Upon the CarService's accidental termination, CarEvsService gets released and
- // CarEvsManager deregisters all listeners and callbacks. So, we simply release
- // CarEvsManager instance and update the status in handleVideoStreamLocked().
+ try {
synchronized (mLock) {
- mCar = null;
- mEvsManager = null;
- handleVideoStreamLocked();
- }
- } else {
- Log.d(TAG, "Connected to the Car Service");
- try {
- synchronized (mLock) {
- mCar = car;
- mEvsManager = (CarEvsManager) car.getCarManager(Car.CAR_EVS_SERVICE);
- handleVideoStreamLocked();
+ mCar = ready ? car : null;
+ mEvsManager = ready ? (CarEvsManager) car.getCarManager(Car.CAR_EVS_SERVICE) : null;
+ if (!ready) {
+ if (!mUseSystemWindow) {
+ // If we were launched by the user manually, we enter the LOST state and
+ // wait for the car service's restoration.
+ handleVideoStreamLocked(STREAM_STATE_LOST);
+ } else {
+ // If we were launched by the system,we will clean up the states and
+ // then finish; the car service will request a new instance when it comes
+ // back from the incident while the system still requires the rearview.
+ handleVideoStreamLocked(STREAM_STATE_STOPPED);
+ finish();
+ }
+ } else {
+ // We request to start a video stream if we get connected to the car service.
+ handleVideoStreamLocked(STREAM_STATE_VISIBLE);
}
- } catch (CarNotConnectedException err) {
- Log.e(TAG, "Failed to connect to the Car Service");
}
+ } catch (CarNotConnectedException err) {
+ Log.e(TAG, "Failed to connect to the Car Service");
}
};
@@ -246,78 +291,116 @@
}
@Override
- protected void onStart() {
- Log.d(TAG, "onStart");
- super.onStart();
- handleVideoStreamLocked();
+ protected void onRestart() {
+ Log.d(TAG, "onRestart");
+ super.onRestart();
+ synchronized (mLock) {
+ // When we come back to the top task, we start rendering the view.
+ handleVideoStreamLocked(STREAM_STATE_VISIBLE);
+ }
}
-
@Override
protected void onStop() {
Log.d(TAG, "onStop");
- super.onStop();
+ try {
+ if (mUseSystemWindow) {
+ // When a new activity is launched, this activity will become the background
+ // activity and, however, likely still visible to the users if it is using the
+ // system window. Therefore, we should not transition to the INVISIBLE state.
+ //
+ // Similarly, this activity continues previewing the camera when the user triggers
+ // the home button. If the users want to manually close the preview window, they
+ // can trigger the close button at the bottom of the window.
+ return;
+ }
+
+ synchronized (mLock) {
+ handleVideoStreamLocked(STREAM_STATE_INVISIBLE);
+ }
+ } finally {
+ super.onStop();
+ }
}
@Override
protected void onDestroy() {
- super.onDestroy();
Log.d(TAG, "onDestroy");
- // Request to stop current service and unregister a status listener
- synchronized (mBufferQueue) {
- mBufferQueue.clear();
- }
- synchronized (mLock) {
- if (mEvsManager != null) {
- mEvsManager.stopVideoStream();
- mEvsManager.stopActivity();
- mEvsManager.clearStatusListener();
+ try {
+ // Request to stop current service and unregister a status listener
+ synchronized (mLock) {
+ if (mEvsManager != null) {
+ handleVideoStreamLocked(STREAM_STATE_STOPPED);
+ mEvsManager.clearStatusListener();
+ }
+ if (mCar != null) {
+ mCar.disconnect();
+ }
}
- if (mCar != null) {
- mCar.disconnect();
- }
- }
- mDisplayManager.unregisterDisplayListener(mDisplayListener);
- if (mUseSystemWindow) {
- WindowManager wm = getSystemService(WindowManager.class);
- wm.removeView(mRootView);
- }
- unregisterReceiver(mBroadcastReceiver);
+ mDisplayManager.unregisterDisplayListener(mDisplayListener);
+ if (mUseSystemWindow) {
+ WindowManager wm = getSystemService(WindowManager.class);
+ wm.removeView(mRootView);
+ }
+
+ unregisterReceiver(mBroadcastReceiver);
+ } finally {
+ super.onDestroy();
+ }
}
- private void handleVideoStreamLocked() {
- if (mEvsManager == null) {
- Log.w(TAG, "CarEvsManager is not available.");
+ @GuardedBy("mLock")
+ private void handleVideoStreamLocked(int newState) {
+ Log.d(TAG, "Requested: " + streamStateToString(mStreamState) + " -> " +
+ streamStateToString(newState));
+ if (newState == mStreamState) {
+ // Safely ignore a request of transitioning to the current state.
return;
}
- if (mDisplayState == Display.STATE_ON) {
- // We show a camera preview only when the activity has been resumed and the display is
- // on.
- if (!mStreamRunning) {
- Log.d(TAG, "Request to start a video stream");
- mEvsManager.startVideoStream(CarEvsManager.SERVICE_TYPE_REARVIEW,
- mSessionToken, mCallbackExecutor, mStreamHandler);
- mStreamRunning = true;
- }
+ boolean needToUpdateState = false;
+ switch (newState) {
+ case STREAM_STATE_STOPPED:
+ if (mEvsManager != null) {
+ mEvsManager.stopVideoStream();
+ mBufferQueue.clear();
+ needToUpdateState = true;
+ } else {
+ Log.w(TAG, "EvsManager is not available");
+ }
+ break;
- return;
+ case STREAM_STATE_VISIBLE:
+ // Starts a video stream
+ if (mEvsManager != null) {
+ int result = mEvsManager.startVideoStream(CarEvsManager.SERVICE_TYPE_REARVIEW,
+ mSessionToken, mCallbackExecutor, mStreamHandler);
+ if (result != ERROR_NONE) {
+ Log.e(TAG, "Failed to start a video stream, error = " + result);
+ } else {
+ needToUpdateState = true;
+ }
+ } else {
+ Log.w(TAG, "EvsManager is not available");
+ }
+ break;
+
+ case STREAM_STATE_INVISIBLE:
+ needToUpdateState = true;
+ break;
+
+ case STREAM_STATE_LOST:
+ needToUpdateState = true;
+ break;
+
+ default:
+ throw new IllegalArgumentException();
}
- // Otherwise, we do not need a video stream.
- if (mStreamRunning) {
- Log.d(TAG, "Request to stop a video stream");
- mEvsManager.stopVideoStream();
- mStreamRunning = false;
-
- // We already stopped an active video stream so are safe to drop all buffer references.
- synchronized (mBufferQueue) {
- mBufferQueue.clear();
- }
-
- // Clear a buffer reference CarEvsCameraGLSurfaceView holds.
- mEvsView.clearBuffer();
+ if (needToUpdateState) {
+ mStreamState = newState;
+ Log.d(TAG, "Completed: " + streamStateToString(mStreamState));
}
}
@@ -337,8 +420,8 @@
}
/** Get a new frame */
- public CarEvsBufferDescriptor getNewFrame() {
- synchronized (mBufferQueue) {
+ CarEvsBufferDescriptor getNewFrame() {
+ synchronized (mLock) {
if (mBufferQueue.isEmpty()) {
return null;
}
@@ -353,7 +436,18 @@
}
/** Request to return a buffer we're done with */
- public void returnBuffer(CarEvsBufferDescriptor buffer) {
- mEvsManager.returnFrameBuffer(buffer);
+ void returnBuffer(CarEvsBufferDescriptor buffer) {
+ synchronized (mLock) {
+ returnBufferLocked(buffer);
+ }
+ }
+
+ @GuardedBy("mLock")
+ private void returnBufferLocked(CarEvsBufferDescriptor buffer) {
+ try {
+ mEvsManager.returnFrameBuffer(buffer);
+ } catch (Exception e) {
+ Log.w(TAG, "CarEvsService is not available.");
+ }
}
}
diff --git a/tests/CarLibTests/OWNERS b/tests/CarLibTests/OWNERS
new file mode 100644
index 0000000..7578bc5
--- /dev/null
+++ b/tests/CarLibTests/OWNERS
@@ -0,0 +1,5 @@
+# AppFocus
+per-file src/android/car/CarAppFocusManagerTest.java = ycheo@google.com
+
+# Navigation
+per-file src/android/car/CarNavigationStatusManagerTest.java = ycheo@google.com
diff --git a/tests/CarSecurityPermissionTest/OWNERS b/tests/CarSecurityPermissionTest/OWNERS
new file mode 100644
index 0000000..e6c8998
--- /dev/null
+++ b/tests/CarSecurityPermissionTest/OWNERS
@@ -0,0 +1,17 @@
+# Audio
+per-file src/com/android/car/media/CarAudio*.java = oscarazu@google.com, ericjeong@google.com
+
+# Cluster
+per-file src/com/android/car/cluster/* = ycheo@google.com
+
+# Input
+per-file src/com/android/car/input/* = ycheo@google.com
+
+# OccupantZone
+per-file src/com/android/car/CarOccupantZoneManagerPermissionTest.java = ycheo@google.com, oscarazu@google.com, ericjeong@google.com
+
+# Power
+per-file src/com/android/car/power/* = ericjeong@google.com
+
+# Watchdog
+per-file src/com/android/car/watchdog/* = lakshmana@google.com
diff --git a/tests/CarSecurityPermissionTest/src/com/android/car/content/pm/CarPackageManagerPermissionTest.java b/tests/CarSecurityPermissionTest/src/com/android/car/content/pm/CarPackageManagerPermissionTest.java
index cdbb56d..1857261 100644
--- a/tests/CarSecurityPermissionTest/src/com/android/car/content/pm/CarPackageManagerPermissionTest.java
+++ b/tests/CarSecurityPermissionTest/src/com/android/car/content/pm/CarPackageManagerPermissionTest.java
@@ -79,4 +79,9 @@
assertThat(mPm.isActivityBackedBySafeActivity(new ComponentName("blah", "someClass")))
.isFalse();
}
+
+ @Test
+ public void testGetTargetCarApiVersion() {
+ assertThrows(SecurityException.class, () -> mPm.getTargetCarVersion("Y U NO THROW?"));
+ }
}
diff --git a/tests/CarSecurityPermissionTest/src/com/android/car/os/CarPerformanceManagerPermissionTest.java b/tests/CarSecurityPermissionTest/src/com/android/car/os/CarPerformanceManagerPermissionTest.java
new file mode 100644
index 0000000..f3355c7
--- /dev/null
+++ b/tests/CarSecurityPermissionTest/src/com/android/car/os/CarPerformanceManagerPermissionTest.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2022 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.os;
+
+import static android.car.Car.CAR_PERFORMANCE_SERVICE;
+import static android.car.Car.PERMISSION_MANAGE_THREAD_PRIORITY;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.testng.Assert.expectThrows;
+
+import android.car.Car;
+import android.car.os.CarPerformanceManager;
+import android.car.os.ThreadPolicyWithPriority;
+import android.content.Context;
+import android.os.Handler;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.Objects;
+
+/**
+ * This class contains security permission tests for the
+ * {@link android.car.os#CarPerformanceManager}'s system APIs.
+ */
+@RunWith(AndroidJUnit4.class)
+public final class CarPerformanceManagerPermissionTest {
+ private final Context mContext =
+ InstrumentationRegistry.getInstrumentation().getTargetContext();
+
+ private CarPerformanceManager mCarPerformanceManager;
+
+ @Before
+ public void setUp() {
+ Car car = Objects.requireNonNull(Car.createCar(mContext, (Handler) null));
+ mCarPerformanceManager = (CarPerformanceManager) car.getCarManager(CAR_PERFORMANCE_SERVICE);
+ }
+
+ @Test
+ public void testSetThreadPriority() throws Exception {
+ ThreadPolicyWithPriority p = new ThreadPolicyWithPriority(
+ ThreadPolicyWithPriority.SCHED_FIFO, /* priority= */ 1);
+ Exception e = expectThrows(
+ SecurityException.class, () -> mCarPerformanceManager.setThreadPriority(p));
+
+ assertThat(e.getMessage()).contains(PERMISSION_MANAGE_THREAD_PRIORITY);
+ }
+
+ @Test
+ public void testGetThreadPriority() throws Exception {
+ Exception e = expectThrows(
+ SecurityException.class, () -> mCarPerformanceManager.getThreadPriority());
+
+ assertThat(e.getMessage()).contains(PERMISSION_MANAGE_THREAD_PRIORITY);
+ }
+}
diff --git a/tests/DiagnosticTools/res/values-en-rCA/strings.xml b/tests/DiagnosticTools/res/values-en-rCA/strings.xml
index 4833f5f..bd4ccb9 100644
--- a/tests/DiagnosticTools/res/values-en-rCA/strings.xml
+++ b/tests/DiagnosticTools/res/values-en-rCA/strings.xml
@@ -17,5 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="display_freeze_frame_info" msgid="1425573367248263107">"Display Freeze Frame Info"</string>
+ <string name="display_freeze_frame_info" msgid="1425573367248263107">"Display freeze frame Info"</string>
</resources>
diff --git a/tests/DiagnosticTools/res/values-ro/strings.xml b/tests/DiagnosticTools/res/values-ro/strings.xml
index 014f068..d06e299 100644
--- a/tests/DiagnosticTools/res/values-ro/strings.xml
+++ b/tests/DiagnosticTools/res/values-ro/strings.xml
@@ -17,5 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="display_freeze_frame_info" msgid="1425573367248263107">"Afișează informații despre cadrul blocat"</string>
+ <string name="display_freeze_frame_info" msgid="1425573367248263107">"Afișați informații despre cadrul blocat"</string>
</resources>
diff --git a/tests/EmbeddedKitchenSinkApp/AndroidManifest.xml b/tests/EmbeddedKitchenSinkApp/AndroidManifest.xml
index 87aef01..7e841b4 100644
--- a/tests/EmbeddedKitchenSinkApp/AndroidManifest.xml
+++ b/tests/EmbeddedKitchenSinkApp/AndroidManifest.xml
@@ -195,6 +195,9 @@
<meta-data android:name="android.car.application"
android:resource="@xml/automotive_app_desc"/>
+ <!-- Car Mainline version -->
+ <meta-data android:name="android.car.targetCarVersion" android:value="33:1"/>
+
<activity android:name=".orientation.LandscapeActivity"
android:label="@string/landscpae_activity"
android:screenOrientation="landscape"
diff --git a/tests/EmbeddedKitchenSinkApp/OWNERS b/tests/EmbeddedKitchenSinkApp/OWNERS
new file mode 100644
index 0000000..8359d14
--- /dev/null
+++ b/tests/EmbeddedKitchenSinkApp/OWNERS
@@ -0,0 +1,20 @@
+# Audio
+per-file src/com/google/android/car/kitchensink/AudioAutoStartActivity.java = oscarazu@google.com, ericjeong@google.com
+per-file src/com/google/android/car/kitchensink/audio/* = oscarazu@google.com, ericjeong@google.com
+per-file src/com/google/android/car/kitchensink/volume/* = oscarazu@google.com, ericjeong@google.com
+
+# Cluster
+per-file src/com/google/android/car/kitchensink/cluster/* = ycheo@google.com
+
+# OccupantZone
+per-file src/com/google/android/car/kitchensink/OccupantZoneStartActivity.java = ycheo@google.com, oscarazu@google.com, ericjeong@google.com
+
+# PackageManager
+per-file src/com/google/android/car/kitchensink/packageinfo/* = ycheo@google.com
+
+# Power
+per-file src/com/google/android/car/kitchensink/power/* = ericjeong@google.com
+
+# Watchdog
+per-file src/com/google/android/car/kitchensink/CarWatchdogClient.java = lakshmana@google.com
+per-file src/com/google/android/car/kitchensink/watchdog/* = lakshmana@google.com
diff --git a/tests/EmbeddedKitchenSinkApp/res/layout/mainline.xml b/tests/EmbeddedKitchenSinkApp/res/layout/mainline.xml
new file mode 100644
index 0000000..8471f87
--- /dev/null
+++ b/tests/EmbeddedKitchenSinkApp/res/layout/mainline.xml
@@ -0,0 +1,188 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2022 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="horizontal" >
+
+ <!-- Column 1: app info -->
+ <LinearLayout
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:orientation="vertical" >
+ <TextView
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="App info"/>
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal" >
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:text="Target SDK:"/>
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:id="@+id/app_target_sdk"
+ android:text="N/A"/>
+ </LinearLayout>
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal" >
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:text="Compilation SDK:"/>
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:id="@+id/app_compilation_sdk"
+ android:text="N/A"/>
+ </LinearLayout>
+ <TextView
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal"
+ android:text="Car Target APIs"/>
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal" >
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:text="Major:"/>
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:id="@+id/app_car_target_major_sdk"
+ android:text="N/A"/>
+ </LinearLayout>
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal" >
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:text="Minor:"/>
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:id="@+id/app_car_target_minor_sdk"
+ android:text="N/A"/>
+ </LinearLayout>
+ </LinearLayout>
+
+ <!-- Column 2: platform info -->
+ <LinearLayout
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:orientation="vertical" >
+ <TextView
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="Platform info"/>
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal" >
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:text="SDK API Codename:"/>
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:id="@+id/android_sdk_codename"
+ android:text="N/A"/>
+ </LinearLayout>
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal" >
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:text="SDK API Version:"/>
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:id="@+id/android_sdk_version"
+ android:text="N/A"/>
+ </LinearLayout>
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal" >
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:text="CAR_PLATFORM_VERSION:"/>
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:id="@+id/platform_version"
+ android:text="N/A"/>
+ </LinearLayout>
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal" >
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:text="CAR_API_VERSION:"/>
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:id="@+id/car_version"
+ android:text="N/A"/>
+ </LinearLayout>
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal" >
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:text="Car Major API:"/>
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:id="@+id/car_major_version"
+ android:text="N/A"/>
+ </LinearLayout>
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal" >
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:text="Car Minor API:"/>
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:id="@+id/car_minor_version"
+ android:text="N/A"/>
+ </LinearLayout>
+ </LinearLayout>
+</LinearLayout>
diff --git a/tests/EmbeddedKitchenSinkApp/res/layout/notification_fragment.xml b/tests/EmbeddedKitchenSinkApp/res/layout/notification_fragment.xml
index 17c0ea0..489d5cb 100644
--- a/tests/EmbeddedKitchenSinkApp/res/layout/notification_fragment.xml
+++ b/tests/EmbeddedKitchenSinkApp/res/layout/notification_fragment.xml
@@ -128,6 +128,15 @@
android:textSize="30sp"/>
<Button
+ android:id="@+id/category_message_same_group_button"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_margin="10dp"
+ android:textColor="#ffa9a8"
+ android:text="Message in same group"
+ android:textSize="30sp"/>
+
+ <Button
android:id="@+id/category_message_mute_action_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
diff --git a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/KitchenSinkActivity.java b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/KitchenSinkActivity.java
index 0d9c640..27c0270 100644
--- a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/KitchenSinkActivity.java
+++ b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/KitchenSinkActivity.java
@@ -62,6 +62,7 @@
import com.google.android.car.kitchensink.experimental.ExperimentalFeatureTestFragment;
import com.google.android.car.kitchensink.hvac.HvacTestFragment;
import com.google.android.car.kitchensink.insets.WindowInsetsFullScreenFragment;
+import com.google.android.car.kitchensink.mainline.CarMainlineFragment;
import com.google.android.car.kitchensink.notification.NotificationFragment;
import com.google.android.car.kitchensink.orientation.OrientationTestFragment;
import com.google.android.car.kitchensink.packageinfo.PackageInfoFragment;
@@ -196,6 +197,7 @@
new FragmentMenuEntry("experimental feature", ExperimentalFeatureTestFragment.class),
new FragmentMenuEntry("hvac", HvacTestFragment.class),
new FragmentMenuEntry("inst cluster", InstrumentClusterFragment.class),
+ new FragmentMenuEntry("mainline", CarMainlineFragment.class),
new FragmentMenuEntry("notification", NotificationFragment.class),
new FragmentMenuEntry("orientation test", OrientationTestFragment.class),
new FragmentMenuEntry("package info", PackageInfoFragment.class),
diff --git a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/mainline/CarMainlineFragment.java b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/mainline/CarMainlineFragment.java
new file mode 100644
index 0000000..68dbc89
--- /dev/null
+++ b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/mainline/CarMainlineFragment.java
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) 2022 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.mainline;
+
+import android.car.Car;
+import android.car.CarVersion;
+import android.car.PlatformVersion;
+import android.car.content.pm.CarPackageManager;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.os.Build.VERSION;
+import android.os.Bundle;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.TextView;
+
+import androidx.fragment.app.Fragment;
+
+import com.google.android.car.kitchensink.KitchenSinkActivity;
+import com.google.android.car.kitchensink.R;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+
+/**
+ * Displays info about Car Mainline APIs.
+ */
+public class CarMainlineFragment extends Fragment {
+
+ private static final String TAG = CarMainlineFragment.class.getSimpleName();
+
+ // TODO(b/228506662): also add a ListView with existing apps
+
+ // Reported by SDK
+ private TextView mAppTargetSdk;
+ private TextView mAppCompilationSdk;
+ private TextView mAndroidSdkCodename;
+ private TextView mAndroidSdkVersion;
+
+ // Reported by Car
+ private TextView mAppCarTargetMajorSdk;
+ private TextView mAppCarTargetMinorSdk;
+ private TextView mPlatformVersion;
+ private TextView mCarVersion;
+ private TextView mCarMajorVersion;
+ private TextView mCarMinorVersion;
+
+ private CarPackageManager mCarPm;
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ View view = inflater.inflate(R.layout.mainline, container, false);
+
+ mAppTargetSdk = view.findViewById(R.id.app_target_sdk);
+ mAppCompilationSdk = view.findViewById(R.id.app_compilation_sdk);
+ mAppCarTargetMajorSdk = view.findViewById(R.id.app_car_target_major_sdk);
+ mAppCarTargetMinorSdk = view.findViewById(R.id.app_car_target_minor_sdk);
+ mAndroidSdkCodename = view.findViewById(R.id.android_sdk_codename);
+ mAndroidSdkVersion = view.findViewById(R.id.android_sdk_version);
+ mPlatformVersion = view.findViewById(R.id.platform_version);
+ mCarVersion = view.findViewById(R.id.car_version);
+ mCarMajorVersion = view.findViewById(R.id.car_major_version);
+ mCarMinorVersion = view.findViewById(R.id.car_minor_version);
+
+ return view;
+ }
+
+ @Override
+ public void onStart() {
+ super.onStart();
+
+ ApplicationInfo appInfo = getContext().getApplicationContext().getApplicationInfo();
+ CarVersion carApiVersion = Car.getCarVersion();
+ PlatformVersion platformApiVersion = Car.getPlatformVersion();
+
+ Car car = ((KitchenSinkActivity) getHost()).getCar();
+ mCarPm = (CarPackageManager) car.getCarManager(Car.PACKAGE_SERVICE);
+
+ mAppTargetSdk.setText(String.valueOf(appInfo.targetSdkVersion));
+ mAppCompilationSdk.setText(String.valueOf(appInfo.compileSdkVersion));
+ mAndroidSdkCodename.setText(String.valueOf(VERSION.CODENAME));
+ mAndroidSdkVersion.setText(String.valueOf(VERSION.SDK_INT));
+ mCarMajorVersion.setText(String.valueOf(carApiVersion.getMajorVersion()));
+ mCarMinorVersion.setText(String.valueOf(carApiVersion.getMinorVersion()));
+
+ boolean isCarApiTQpr = carApiVersion.isAtLeast(CarVersion.VERSION_CODES.TIRAMISU_1);
+ Log.v(TAG, "onStart(): isCarApiTQpr=" + isCarApiTQpr);
+ if (isCarApiTQpr) {
+ mPlatformVersion.setText(platformApiVersion.toString());
+ mCarVersion.setText(carApiVersion.toString());
+ setTargetCarApiVersion();
+ } else {
+ // TODO(b/228506662): install on device running T to make sure it works
+ String unsupported = String.format("N/A on %s", carApiVersion);
+ mPlatformVersion.setText(unsupported);
+ mCarVersion.setText(unsupported);
+ mAppCarTargetMajorSdk.setText(unsupported);
+ mAppCarTargetMinorSdk.setText(unsupported);
+ }
+ }
+
+ private void setTargetCarApiVersion() {
+ String ksPkg = getContext().getPackageName();
+ CarVersion apiVersion;
+ try {
+ apiVersion = mCarPm.getTargetCarVersion(ksPkg);
+ } catch (NameNotFoundException e) {
+ Log.w(TAG, "Could not get target car version for " + ksPkg, e);
+ String text = "N/A";
+ mAppCarTargetMajorSdk.setText(text);
+ mAppCarTargetMinorSdk.setText(text);
+ return;
+ }
+ mAppCarTargetMajorSdk.setText(String.valueOf(apiVersion.getMajorVersion()));
+ mAppCarTargetMinorSdk.setText(String.valueOf(apiVersion.getMinorVersion()));
+ }
+
+ @Override
+ public void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) {
+ writer.printf("%smAppTargetSdk: %s\n", prefix, mAppTargetSdk.getText());
+ writer.printf("%smAppCompilationSdk: %s\n", prefix, mAppCompilationSdk.getText());
+ writer.printf("%smAppCarTargetMajorSdk: %s\n", prefix, mAppCarTargetMajorSdk.getText());
+ writer.printf("%smAppCarTargetMinorSdk: %s\n", prefix, mAppCarTargetMinorSdk.getText());
+ writer.printf("%smAndroidSdkCodename: %s\n", prefix, mAndroidSdkCodename.getText());
+ writer.printf("%smAndroidSdkVersion: %s\n", prefix, mAndroidSdkVersion.getText());
+ writer.printf("%smCarMajorVersion: %s\n", prefix, mCarMajorVersion.getText());
+ writer.printf("%smCarMinorVersion: %s\n", prefix, mCarMinorVersion.getText());
+ }
+}
diff --git a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/notification/NotificationFragment.java b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/notification/NotificationFragment.java
index f7378af..9206031 100644
--- a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/notification/NotificationFragment.java
+++ b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/notification/NotificationFragment.java
@@ -41,7 +41,8 @@
private static final String IMPORTANCE_LOW_ID = "importance_low";
private static final String IMPORTANCE_MIN_ID = "importance_min";
private static final String IMPORTANCE_NONE_ID = "importance_none";
- private int mCurrentNotificationId = 0;
+ private int mCurrentNotificationId;
+ private int mCurrentGroupNotificationCount;
private NotificationManager mManager;
private Context mContext;
private Handler mHandler = new Handler();
@@ -96,6 +97,7 @@
initMessagingStyleButtonForDiffPerson(view);
initMessagingStyleButtonForSamePerson(view);
initMessagingStyleButtonForLongMessageSamePerson(view);
+ initMessagingStyleButtonForMessageSameGroup(view);
initMessagingStyleButtonWithMuteAction(view);
initTestMessagesButton(view);
initProgressButton(view);
@@ -280,7 +282,7 @@
MessagingStyle messagingStyle =
new MessagingStyle(personList.get(0))
- .setConversationTitle("Customizable Group chat");
+ .setConversationTitle("Customizable Group chat: " + id);
if (personList.size() > 1) {
messagingStyle.setGroupConversation(true);
}
@@ -395,6 +397,62 @@
});
}
+ private void initMessagingStyleButtonForMessageSameGroup(View view) {
+ int numOfPeople = 3;
+ Person user = new Person.Builder()
+ .setName("User")
+ .setIcon(IconCompat.createWithResource(view.getContext(), R.drawable.avatar1))
+ .build();
+
+ MessagingStyle messagingStyle =
+ new MessagingStyle(user)
+ .setConversationTitle("Same group chat")
+ .setGroupConversation(true);
+
+ List<Person> personList = new ArrayList<>();
+ for (int i = 1; i <= numOfPeople; i++) {
+ personList.add(new Person.Builder()
+ .setName("Person " + i)
+ .setIcon(IconCompat.createWithResource(view.getContext(),
+ i % 2 == 1 ? R.drawable.avatar1 : R.drawable.avatar2))
+ .build());
+ }
+
+ view.findViewById(R.id.category_message_same_group_button).setOnClickListener(v -> {
+ mCurrentGroupNotificationCount++;
+ PendingIntent replyIntent = createServiceIntent(123456, "reply");
+ PendingIntent markAsReadIntent = createServiceIntent(123456, "read");
+ Person person = personList.get(mCurrentGroupNotificationCount % numOfPeople);
+ String messageText =
+ person.getName() + "'s " + mCurrentGroupNotificationCount + " message";
+ messagingStyle.addMessage(
+ new MessagingStyle.Message(messageText, System.currentTimeMillis(), person));
+
+ NotificationCompat.Builder notification = new NotificationCompat
+ .Builder(mContext, IMPORTANCE_HIGH_ID)
+ .setContentTitle("Same Group chat (Title)")
+ .setContentText("Same Group chat (Text)")
+ .setShowWhen(true)
+ .setCategory(Notification.CATEGORY_MESSAGE)
+ .setSmallIcon(R.drawable.car_ic_mode)
+ .setStyle(messagingStyle)
+ .setAutoCancel(true)
+ .addAction(
+ new Action.Builder(R.drawable.ic_check_box, "read", markAsReadIntent)
+ .setSemanticAction(Action.SEMANTIC_ACTION_MARK_AS_READ)
+ .setShowsUserInterface(false)
+ .build())
+ .addAction(
+ new Action.Builder(R.drawable.ic_check_box, "reply", replyIntent)
+ .setSemanticAction(Action.SEMANTIC_ACTION_REPLY)
+ .setShowsUserInterface(false)
+ .addRemoteInput(new RemoteInput.Builder("input").build())
+ .build());
+
+ mManager.notify(123456, notification.build());
+ });
+ }
+
private void initMessagingStyleButtonForSamePerson(View view) {
view.findViewById(R.id.category_message_same_person_button).setOnClickListener(v -> {
int id = mCurrentNotificationId++;
@@ -444,7 +502,6 @@
PendingIntent markAsReadIntent = createServiceIntent(id, "read");
-
Person person = new Person.Builder().setName("John Doe").build();
MessagingStyle messagingStyle =
new MessagingStyle(person).setConversationTitle("Hello!");
diff --git a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/property/PropertyTestFragment.java b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/property/PropertyTestFragment.java
index c67840f..88c2a9f 100644
--- a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/property/PropertyTestFragment.java
+++ b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/property/PropertyTestFragment.java
@@ -162,7 +162,7 @@
} catch (Exception e) {
Log.e(TAG, "Failed to set VHAL property", e);
Toast.makeText(mActivity, "Failed to set VHAL property: " + e.getMessage(),
- Toast.LENGTH_SHORT).show();
+ Toast.LENGTH_LONG).show();
}
});
diff --git a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/volume/CarAudioZoneVolumeFragment.java b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/volume/CarAudioZoneVolumeFragment.java
index 2419511..d13aec0 100644
--- a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/volume/CarAudioZoneVolumeFragment.java
+++ b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/volume/CarAudioZoneVolumeFragment.java
@@ -266,10 +266,17 @@
Log.d(TAG, "Start ringtone for zone " + mZoneId + " and usage "
+ AudioAttributes.usageToString(usage));
}
- AudioAttributes attributes = new AudioAttributes.Builder()
- .setUsage(usage)
- .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
- .build();
+
+ AudioAttributes.Builder builder = new AudioAttributes.Builder()
+ .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION);
+
+ if (AudioAttributes.isSystemUsage(usage)) {
+ builder.setSystemUsage(usage);
+ } else {
+ builder.setUsage(usage);
+ }
+
+ AudioAttributes attributes = builder.build();
Uri uri = RingtoneManager.getActualDefaultRingtoneUri(getContext(),
AudioAttributes.toLegacyStreamType(attributes));
diff --git a/tests/OccupantAwareness/OWNERS b/tests/OccupantAwareness/OWNERS
new file mode 100644
index 0000000..b7a974d
--- /dev/null
+++ b/tests/OccupantAwareness/OWNERS
@@ -0,0 +1,3 @@
+ycheo@google.com
+oscarazu@google.com
+ericjeong@google.com
diff --git a/tests/RailwayReferenceApp/AndroidManifest.xml b/tests/RailwayReferenceApp/AndroidManifest.xml
index 41143ee..745babe 100644
--- a/tests/RailwayReferenceApp/AndroidManifest.xml
+++ b/tests/RailwayReferenceApp/AndroidManifest.xml
@@ -20,12 +20,13 @@
<uses-sdk
android:minSdkVersion="28"
android:targetSdkVersion="33"/>
- <uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
- <uses-permission android:name="android.permission.MANAGE_ETHERNET_NETWORKS" />
<uses-permission android:name="android.permission.CREATE_USERS" />
<uses-permission android:name="android.permission.INTERACT_ACROSS_USERS" />
+ <uses-permission android:name="android.permission.INTERNET" />
+ <uses-permission android:name="android.permission.MANAGE_ETHERNET_NETWORKS" />
+ <uses-permission android:name="android.permission.QUERY_ALL_PACKAGES" />
<application android:label="RailwayReferenceApp">
<activity android:name=".MainActivity"
diff --git a/tests/RailwayReferenceApp/res/values/strings.xml b/tests/RailwayReferenceApp/res/values/strings.xml
index 240f1cc..6894200 100644
--- a/tests/RailwayReferenceApp/res/values/strings.xml
+++ b/tests/RailwayReferenceApp/res/values/strings.xml
@@ -17,7 +17,7 @@
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_name" translatable="false">Railway Reference App</string>
<string name="update_button_title">Update</string>
- <string name="connect_button_title">Test Connect</string>
+ <string name="connect_button_title">Bind Interface</string>
<string name="enable_button_title">Enable</string>
<string name="disable_button_title">Disable</string>
<string name="activity_title">Vehicular Networking App</string>
@@ -26,7 +26,7 @@
<string name="ip_configuration_title">Update Configuration (IPv4 only)</string>
<string name="interface_name_title">Interface Name</string>
<string name="network_capabilities_title">Network Capabilities</string>
- <string name="enable_disable_section_title">Enable/Disable/Connect Interface</string>
+ <string name="enable_disable_section_title">Enable/Disable/Bind Interface</string>
<string name="current_ethernet_networks_section_title">Current Ethernet Networks</string>
<string name="success">Success</string>
<string name="error">Error</string>
diff --git a/tests/RailwayReferenceApp/src/com/google/android/car/networking/railway/CurrentEthernetNetworksViewModel.java b/tests/RailwayReferenceApp/src/com/google/android/car/networking/railway/CurrentEthernetNetworksViewModel.java
index 1d62a60..03d6a6d 100644
--- a/tests/RailwayReferenceApp/src/com/google/android/car/networking/railway/CurrentEthernetNetworksViewModel.java
+++ b/tests/RailwayReferenceApp/src/com/google/android/car/networking/railway/CurrentEthernetNetworksViewModel.java
@@ -18,11 +18,15 @@
import android.app.Application;
import android.net.ConnectivityManager;
+import android.net.ConnectivityManager.NetworkCallback;
import android.net.LinkAddress;
import android.net.LinkProperties;
import android.net.Network;
import android.net.NetworkCapabilities;
import android.net.NetworkRequest;
+import android.os.Handler;
+import android.os.Looper;
+import android.util.Log;
import androidx.lifecycle.AndroidViewModel;
import androidx.lifecycle.LiveData;
@@ -34,22 +38,27 @@
import java.util.Set;
public final class CurrentEthernetNetworksViewModel extends AndroidViewModel {
+ private static final String TAG = CurrentEthernetNetworksViewModel.class.getName();
private final MutableLiveData<List<Network>> mNetworks =
new MutableLiveData<>(new ArrayList<>());
private final Application mApplication;
private final ConnectivityManager mConnectivityManager;
- private final ConnectivityManager.NetworkCallback mNetworkCallback;
+ private final NetworkCallback mNetworkCallback = new CurrentEthernetNetworksCallback();
+ private final Handler mHandler;
+
+ private void runOnUiThread(Runnable r) {
+ mHandler.post(r);
+ }
public LiveData<List<Network>> getNetworksLiveData() {
return mNetworks;
}
- public CurrentEthernetNetworksViewModel(Application application,
- ConnectivityManager.NetworkCallback networkCallback) {
+ public CurrentEthernetNetworksViewModel(Application application) {
super(application);
mApplication = application;
- mNetworkCallback = networkCallback;
+ mHandler = new Handler(Looper.getMainLooper());
mConnectivityManager =
mApplication.getSystemService(ConnectivityManager.class);
@@ -60,7 +69,7 @@
.addTransportType(
NetworkCapabilities.TRANSPORT_ETHERNET)
.build();
- mConnectivityManager.registerNetworkCallback(request, networkCallback);
+ mConnectivityManager.registerNetworkCallback(request, mNetworkCallback);
}
@Override
@@ -70,12 +79,12 @@
mConnectivityManager.unregisterNetworkCallback(mNetworkCallback);
}
- public void onNetworkChanged() {
+ private void onNetworkChanged() {
mNetworks.setValue(mNetworks.getValue());
// setValue triggers an update on the observer that in turn updates the text view
}
- public void addNetwork(Network network) {
+ private void addNetwork(Network network) {
List<Network> networks = mNetworks.getValue();
assert networks != null;
@@ -83,7 +92,7 @@
mNetworks.setValue(networks);
}
- public void removeNetwork(Network network) {
+ private void removeNetwork(Network network) {
List<Network> networks = mNetworks.getValue();
assert networks != null;
@@ -127,4 +136,41 @@
}
return sb.toString();
}
+
+ private class CurrentEthernetNetworksCallback extends NetworkCallback {
+ @Override
+ public void onAvailable(Network network) {
+ super.onAvailable(network);
+ Log.d(TAG, "Network " + network + " available");
+
+ runOnUiThread(() -> addNetwork(network));
+ }
+
+ @Override
+ public void onLost(Network network) {
+ super.onLost(network);
+ Log.d(TAG, "Network " + network + " lost");
+
+ runOnUiThread(() -> removeNetwork(network));
+ }
+
+ @Override
+ public void onCapabilitiesChanged(Network network,
+ NetworkCapabilities networkCapabilities) {
+ super.onCapabilitiesChanged(network, networkCapabilities);
+ Log.d(TAG, "Network " + network + " capabilities changed to "
+ + Arrays.toString(networkCapabilities.getCapabilities()));
+
+ runOnUiThread(() -> onNetworkChanged());
+ }
+
+ @Override
+ public void onLinkPropertiesChanged(Network network,
+ LinkProperties linkProperties) {
+ super.onLinkPropertiesChanged(network, linkProperties);
+ Log.d(TAG, "Network " + network + " link properties changed");
+
+ runOnUiThread(() -> onNetworkChanged());
+ }
+ }
}
diff --git a/tests/RailwayReferenceApp/src/com/google/android/car/networking/railway/MainActivity.java b/tests/RailwayReferenceApp/src/com/google/android/car/networking/railway/MainActivity.java
index a26f3a9..2ec5257 100644
--- a/tests/RailwayReferenceApp/src/com/google/android/car/networking/railway/MainActivity.java
+++ b/tests/RailwayReferenceApp/src/com/google/android/car/networking/railway/MainActivity.java
@@ -19,15 +19,13 @@
import android.app.Application;
import android.content.pm.PackageManager;
import android.net.ConnectivityManager;
+import android.net.ConnectivityManager.NetworkCallback;
import android.net.EthernetNetworkManagementException;
import android.net.EthernetNetworkSpecifier;
-import android.net.LinkProperties;
import android.net.Network;
import android.net.NetworkCapabilities;
import android.net.NetworkRequest;
import android.os.Bundle;
-import android.os.Handler;
-import android.os.Looper;
import android.os.OutcomeReceiver;
import android.util.Log;
import android.widget.Button;
@@ -46,13 +44,16 @@
import java.time.Duration;
import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
-import java.util.Arrays;
import java.util.List;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
public final class MainActivity extends FragmentActivity {
private static final String TAG = MainActivity.class.getName();
private static final Duration REQUEST_NETWORK_TIMEOUT =
- Duration.of(200, ChronoUnit.MILLIS);
+ Duration.of(2000, ChronoUnit.MILLIS);
private ConfigurationUpdater mConfigurationUpdater;
private InterfaceEnabler mInterfaceEnabler;
@@ -103,9 +104,8 @@
mCurrentEthernetNetworksViewModel =
new ViewModelProvider(this,
- new CurrentEthernetNetworksViewModelFactory(
- (Application) getApplicationContext(),
- new CurrentEthernetNetworksCallback()))
+ (ViewModelProvider.Factory) new CurrentEthernetNetworksViewModelFactory(
+ (Application) getApplicationContext()))
.get(CurrentEthernetNetworksViewModel.class);
mCurrentEthernetNetworksViewModel.getNetworksLiveData().observe(this,
networkNetworkInfoMap -> currentEthernetNetworksOutput
@@ -160,10 +160,11 @@
}
private void onUpdateButtonClick() {
- validateInterfaceName(getUpdateConfigurationIface());
setButtonsAndEditTextsEnabled(false);
Log.d(TAG, "configuration update started");
+
try {
+ validateInterfaceName(getUpdateConfigurationIface());
mConfigurationUpdater.updateNetworkConfiguration(
mAllowedPackageNames.getText().toString(),
mIpConfiguration.getText().toString(),
@@ -182,34 +183,35 @@
try {
validateInterfaceName(getEnableDisableConnectIface());
- NetworkRequest request =
- new NetworkRequest.Builder()
- .clearCapabilities()
- .addTransportType(NetworkCapabilities.TRANSPORT_ETHERNET)
- .setNetworkSpecifier(
- new EthernetNetworkSpecifier(getEnableDisableConnectIface()))
- .build();
- mConnectivityManager.requestNetwork(request,
- new InterfaceConnectorCallback(),
- new Handler(Looper.getMainLooper()),
- Math.toIntExact(REQUEST_NETWORK_TIMEOUT.toMillis()));
+ new NetworkConnector().checkNetworkConnectionAvailable(
+ new EthernetNetworkSpecifier(getEnableDisableConnectIface()));
} catch (SecurityException | IllegalArgumentException e) {
showOperationResultDialog(e.getLocalizedMessage(), /* isSuccess= */ false);
}
}
private void onEnableButtonClick() {
- validateInterfaceName(getEnableDisableConnectIface());
setButtonsAndEditTextsEnabled(false);
Log.d(TAG, "enable interface started");
- mInterfaceEnabler.enableInterface(getEnableDisableConnectIface());
+
+ try {
+ validateInterfaceName(getEnableDisableConnectIface());
+ mInterfaceEnabler.enableInterface(getEnableDisableConnectIface());
+ } catch (IllegalArgumentException e) {
+ showOperationResultDialog(e.getLocalizedMessage(), /* isSuccess= */ false);
+ }
}
private void onDisableButtonClick() {
- validateInterfaceName(getEnableDisableConnectIface());
setButtonsAndEditTextsEnabled(false);
Log.d(TAG, "disable interface started");
- mInterfaceEnabler.disableInterface(getEnableDisableConnectIface());
+
+ try {
+ validateInterfaceName(getEnableDisableConnectIface());
+ mInterfaceEnabler.disableInterface(getEnableDisableConnectIface());
+ } catch (IllegalArgumentException e) {
+ showOperationResultDialog(e.getLocalizedMessage(), /* isSuccess= */ false);
+ }
}
private void validateInterfaceName(String iface) {
@@ -218,91 +220,63 @@
}
}
- private class InterfaceConnectorCallback extends ConnectivityManager.NetworkCallback {
- @Override
- public void onAvailable(Network network) {
- super.onAvailable(network);
+ private class NetworkConnector {
+ private final CompletableFuture<Network> mNetworkFuture = new CompletableFuture();
+ private final NetworkCallback mCb = new NetworkCallback() {
+ @Override
+ public void onAvailable(Network network) {
+ super.onAvailable(network);
+ mNetworkFuture.complete(network);
- try (Socket socket = new Socket()) {
- network.bindSocket(socket);
- } catch (IOException e) {
- showOperationResultDialog(e.getLocalizedMessage(), /* isSuccess= */ false);
- return;
- } finally {
- mConnectivityManager.unregisterNetworkCallback(this);
+ try (Socket socket = new Socket()) {
+ network.bindSocket(socket);
+ } catch (IOException e) {
+ runOnUiThread(() -> showOperationResultDialog(
+ e.getLocalizedMessage(), /* isSuccess= */ false));
+ return;
+ } finally {
+ mConnectivityManager.unregisterNetworkCallback(this);
+ }
+
+ runOnUiThread(() -> showOperationResultDialog(
+ mConnectivityManager.getLinkProperties(network).getInterfaceName(),
+ /* isSuccess= */ true));
}
+ };
- showOperationResultDialog(
- mConnectivityManager.getLinkProperties(network).getInterfaceName(),
- /* isSuccess= */ true);
- }
-
- @Override
- public void onUnavailable() {
- super.onUnavailable();
- mConnectivityManager.unregisterNetworkCallback(this);
-
- showOperationResultDialog(mInterfaceName2.getText().toString() + " is not available",
- /* isSuccess= */ false);
- }
- }
-
- private class CurrentEthernetNetworksCallback extends ConnectivityManager.NetworkCallback {
- @Override
- public void onAvailable(Network network) {
- super.onAvailable(network);
- Log.d(TAG, "Network " + network + " available");
-
- runOnUiThread(() -> mCurrentEthernetNetworksViewModel.addNetwork(network));
- }
-
- @Override
- public void onLost(Network network) {
- super.onLost(network);
- Log.d(TAG, "Network " + network + " lost");
-
- runOnUiThread(() -> mCurrentEthernetNetworksViewModel.removeNetwork(network));
- }
-
- @Override
- public void onCapabilitiesChanged(Network network,
- NetworkCapabilities networkCapabilities) {
- super.onCapabilitiesChanged(network, networkCapabilities);
- Log.d(TAG, "Network " + network + " capabilities changed to "
- + Arrays.toString(networkCapabilities.getCapabilities()));
-
- runOnUiThread(() -> mCurrentEthernetNetworksViewModel.onNetworkChanged());
- }
-
- @Override
- public void onLinkPropertiesChanged(Network network,
- LinkProperties linkProperties) {
- super.onLinkPropertiesChanged(network, linkProperties);
- Log.d(TAG, "Network " + network + " link properties changed");
-
- runOnUiThread(
- () -> mCurrentEthernetNetworksViewModel.onNetworkChanged());
+ void checkNetworkConnectionAvailable(EthernetNetworkSpecifier specifier) {
+ NetworkRequest request =
+ new NetworkRequest.Builder()
+ .clearCapabilities()
+ .addTransportType(NetworkCapabilities.TRANSPORT_ETHERNET)
+ .setNetworkSpecifier(specifier)
+ .build();
+ try {
+ mConnectivityManager.registerNetworkCallback(request, mCb);
+ mNetworkFuture.get(REQUEST_NETWORK_TIMEOUT.toMillis(), TimeUnit.MILLISECONDS);
+ } catch (TimeoutException | ExecutionException | InterruptedException e) {
+ Log.e(TAG, e.getClass().getSimpleName());
+ mConnectivityManager.unregisterNetworkCallback(mCb);
+ runOnUiThread(() -> showOperationResultDialog(
+ mInterfaceName2.getText().toString() + " is not available",
+ /* isSuccess= */ false));
+ }
}
}
private static class CurrentEthernetNetworksViewModelFactory extends
ViewModelProvider.AndroidViewModelFactory {
private final Application mApplication;
- private final ConnectivityManager.NetworkCallback mNetworkCallback;
- private CurrentEthernetNetworksViewModelFactory(
- Application application, ConnectivityManager.NetworkCallback networkCallback) {
+ private CurrentEthernetNetworksViewModelFactory(Application application) {
super(application);
mApplication = application;
- mNetworkCallback = networkCallback;
}
@NonNull
@Override
public <T extends ViewModel> T create(Class<T> modelClass) {
- return modelClass.cast(
- new CurrentEthernetNetworksViewModel(mApplication, mNetworkCallback));
+ return modelClass.cast(new CurrentEthernetNetworksViewModel(mApplication));
}
}
-
}
diff --git a/tests/RailwayReferenceApp/src/com/google/android/car/networking/railway/UidToPackageNameConverter.java b/tests/RailwayReferenceApp/src/com/google/android/car/networking/railway/UidToPackageNameConverter.java
index d04f7af..03939cc 100644
--- a/tests/RailwayReferenceApp/src/com/google/android/car/networking/railway/UidToPackageNameConverter.java
+++ b/tests/RailwayReferenceApp/src/com/google/android/car/networking/railway/UidToPackageNameConverter.java
@@ -37,10 +37,23 @@
String[] packageNamesArray = packageNames.split(",");
for (String packageName : packageNamesArray) {
+ boolean nameNotFound = true;
packageName = packageName.trim();
for (final UserHandle user : users) {
- final int uid = packageManager.getApplicationInfoAsUser(packageName, 0, user).uid;
- uids.add(uid);
+ try {
+ final int uid =
+ packageManager.getApplicationInfoAsUser(packageName, 0, user).uid;
+ uids.add(uid);
+ nameNotFound = false;
+ } catch (PackageManager.NameNotFoundException e) {
+ // Although this may seem like an error scenario, it is ok as all packages are
+ // not expected to be installed for all users.
+ continue;
+ }
+ }
+
+ if (nameNotFound) {
+ throw new PackageManager.NameNotFoundException("Not installed: " + packageName);
}
}
return uids;
diff --git a/tests/SampleCustomInputService/OWNERS b/tests/SampleCustomInputService/OWNERS
new file mode 100644
index 0000000..a061949
--- /dev/null
+++ b/tests/SampleCustomInputService/OWNERS
@@ -0,0 +1 @@
+ycheo@google.com
diff --git a/tests/android_car_api_test/Android.bp b/tests/android_car_api_test/Android.bp
index 13a55c4..f56bf31 100644
--- a/tests/android_car_api_test/Android.bp
+++ b/tests/android_car_api_test/Android.bp
@@ -32,6 +32,7 @@
certificate: "platform",
min_sdk_version: "33",
+ target_sdk_version: "33",
// When built explicitly put it in the data partition
@@ -47,6 +48,8 @@
"android.car.testapi",
"android.car.test.utils",
"androidx.test.runner",
+// TODO(b/236153976): comment back once guava is supported
+// "guava-android-testlib",
"compatibility-device-util-axt",
"platform-test-annotations",
"testng",
diff --git a/tests/android_car_api_test/AndroidManifest.xml b/tests/android_car_api_test/AndroidManifest.xml
index dc3e6ec..62dbb8c 100644
--- a/tests/android_car_api_test/AndroidManifest.xml
+++ b/tests/android_car_api_test/AndroidManifest.xml
@@ -17,10 +17,158 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
package="android.car.apitest"
- android:sharedUserId="com.google.android.car.uid.kitchensink"
android:debuggable="true">
<uses-sdk android:minSdkVersion="33"/>
+ <uses-permission android:name="android.car.permission.ACCESS_CAR_PROJECTION_STATUS"/>
+ <uses-permission android:name="android.car.permission.CAR_CAMERA"/>
+ <uses-permission android:name="android.car.permission.CAR_CONTROL_AUDIO_SETTINGS"/>
+ <uses-permission android:name="android.car.permission.CAR_CONTROL_AUDIO_VOLUME"/>
+ <uses-permission android:name="android.car.permission.CAR_DIAGNOSTICS"/>
+ <uses-permission android:name="android.car.permission.CAR_DISPLAY_IN_CLUSTER"/>
+ <!-- use for display mirroring in kitchen sink -->
+ <uses-permission android:name="android.permission.READ_FRAME_BUFFER" />
+ <!-- use for CarServiceTest -->
+ <uses-permission android:name="android.car.permission.CAR_DRIVING_STATE"/>
+ <uses-permission android:name="android.car.permission.CAR_ENERGY"/>
+ <uses-permission android:name="android.car.permission.CAR_MONITOR_CLUSTER_NAVIGATION_STATE"/>
+ <!-- use for AndroidCarApiTest -->
+ <uses-permission android:name="android.car.permission.CAR_INFO"/>
+ <!-- use for AndroidCarApiTest -->
+ <uses-permission android:name="android.car.permission.CAR_PROJECTION"/>
+ <uses-permission android:name="android.car.permission.CAR_INSTRUMENT_CLUSTER_CONTROL"/>
+ <uses-permission android:name="android.car.permission.CAR_MILEAGE"/>
+ <uses-permission android:name="android.car.permission.CAR_MOCK_VEHICLE_HAL"/>
+ <uses-permission android:name="android.car.permission.CAR_NAVIGATION_MANAGER"/>
+ <!-- use for CarServiceTest -->
+ <uses-permission android:name="android.car.permission.CAR_EXTERIOR_ENVIRONMENT"/>
+ <uses-permission android:name="android.car.permission.CAR_POWER"/>
+ <!-- use for CarServiceTest -->
+ <uses-permission android:name="android.car.permission.CAR_POWERTRAIN"/>
+ <uses-permission android:name="android.car.permission.CAR_SPEED"/>
+ <!-- use for CarServiceTest -->
+ <uses-permission android:name="android.car.permission.CAR_TEST_SERVICE"/>
+ <!-- use for CarServiceTest -->
+ <uses-permission android:name="android.car.permission.CAR_VENDOR_EXTENSION"/>
+ <!-- use for CarServiceTest -->
+ <uses-permission android:name="android.car.permission.CAR_UX_RESTRICTIONS_CONFIGURATION"/>
+ <!-- use for AndroidCarApiTest -->
+ <uses-permission android:name="android.car.permission.CONTROL_CAR_APP_LAUNCH"/>
+ <uses-permission android:name="android.car.permission.CONTROL_CAR_CLIMATE"/>
+ <uses-permission android:name="android.car.permission.READ_CAR_STEERING"/>
+ <uses-permission android:name="android.car.permission.STORAGE_MONITORING"/>
+ <uses-permission android:name="android.car.permission.CAR_DYNAMICS_STATE"/>
+ <uses-permission android:name="android.car.permission.CONTROL_APP_BLOCKING"/>
+ <!-- use for CarServiceTest -->
+ <uses-permission android:name="android.car.permission.USE_CAR_TELEMETRY_SERVICE"/>
+ <!-- Allow querying and writing to any property -->
+ <uses-permission android:name="android.car.permission.CAR_ENERGY_PORTS" />
+ <uses-permission android:name="android.car.permission.PERMISSION_CONTROL_ENERGY_PORTS" />
+ <uses-permission android:name="android.car.permission.CAR_EXTERIOR_LIGHTS" />
+ <uses-permission android:name="android.car.permission.CAR_TIRES" />
+ <uses-permission android:name="android.car.permission.CONTROL_CAR_DOORS" />
+ <uses-permission android:name="android.car.permission.CONTROL_CAR_EXTERIOR_LIGHTS" />
+ <uses-permission android:name="android.car.permission.CONTROL_CAR_MIRRORS" />
+ <uses-permission android:name="android.car.permission.CONTROL_CAR_SEATS" />
+ <uses-permission android:name="android.car.permission.CONTROL_CAR_WINDOWS" />
+ <uses-permission android:name="android.car.permission.READ_CAR_DISPLAY_UNITS" />
+ <uses-permission android:name="android.car.permission.CAR_IDENTIFICATION" />
+ <uses-permission android:name="android.car.permission.PERMISSION_ADJUST_RANGE_REMAINING" />
+ <uses-permission android:name="android.car.permission.PERMISSION_CAR_ENGINE_DETAILED" />
+ <!-- use for CarServiceTest -->
+ <uses-permission android:name="android.car.permission.VMS_PUBLISHER"/>
+ <!-- use for CarServiceTest -->
+ <uses-permission android:name="android.car.permission.VMS_SUBSCRIBER"/>
+ <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
+ <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
+ <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
+ <uses-permission android:name="android.permission.ACCESS_VOICE_INTERACTION_SERVICE"/>
+ <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
+ <uses-permission android:name="android.permission.ACTIVITY_EMBEDDING"/>
+ <uses-permission android:name="android.permission.BACKUP"/>
+ <uses-permission android:name="android.permission.BLUETOOTH"/>
+ <uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
+ <uses-permission android:name="android.permission.BLUETOOTH_ADVERTISE"/>
+ <uses-permission android:name="android.permission.BLUETOOTH_CONNECT"/>
+ <uses-permission android:name="android.permission.BLUETOOTH_SCAN"/>
+ <uses-permission android:name="android.permission.BLUETOOTH_PRIVILEGED"/>
+ <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE"/>
+ <uses-permission android:name="android.permission.CHANGE_WIFI_STATE"/>
+ <uses-permission android:name="android.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS"/>
+ <uses-permission android:name="android.permission.LOCATION_BYPASS" />
+ <!-- Use for sensor access in Sensors fragment. -->
+ <uses-permission android:name="android.permission.HIGH_SAMPLING_RATE_SENSORS"/>
+ <uses-permission android:name="android.permission.INJECT_EVENTS"/>
+ <!-- use for CarServiceUnitTest and CarServiceTest -->
+ <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS"/>
+ <!-- use for CarServiceUnitTest -->
+ <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL"/>
+ <uses-permission android:name="android.permission.INTERNAL_SYSTEM_WINDOW"/>
+ <uses-permission android:name="android.permission.LOCATION_HARDWARE"/>
+ <uses-permission android:name="android.permission.MANAGE_USB"/>
+ <uses-permission android:name="android.permission.MANAGE_USERS"/>
+ <!-- use for CarServiceTest -->
+ <uses-permission android:name="android.permission.MEDIA_CONTENT_CONTROL"/>
+ <uses-permission android:name="android.permission.MODIFY_AUDIO_ROUTING"/>
+ <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS"/>
+ <uses-permission android:name="android.permission.RECORD_AUDIO" />
+ <uses-permission android:name="android.permission.READ_PRIVILEGED_PHONE_STATE"/>
+ <uses-permission android:name="android.permission.MODIFY_DAY_NIGHT_MODE"/>
+ <uses-permission android:name="android.permission.MODIFY_PHONE_STATE"/>
+ <uses-permission android:name="android.permission.OVERRIDE_WIFI_CONFIG"/>
+ <uses-permission android:name="android.permission.PROVIDE_TRUST_AGENT"/>
+ <!-- Allow query of any normal app on the device in R+ -->
+ <uses-permission android:name="android.permission.QUERY_ALL_PACKAGES"/>
+ <uses-permission android:name="android.permission.READ_LOGS"/>
+ <uses-permission android:name="android.permission.READ_SMS"/>
+ <uses-permission android:name="android.permission.REAL_GET_TASKS"/>
+ <uses-permission android:name="android.permission.REBOOT"/>
+ <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
+ <uses-permission android:name="android.permission.SEND_CATEGORY_CAR_NOTIFICATIONS"/>
+ <uses-permission android:name="android.permission.SEND_SMS"/>
+ <!-- use for CarServiceTest -->
+ <uses-permission android:name="android.permission.MONITOR_INPUT"/>
+ <uses-permission android:name="android.permission.SET_ACTIVITY_WATCHER"/>
+ <!-- use for CarWatchdogReliabilityTest -->
+ <uses-permission android:name="android.car.permission.USE_CAR_WATCHDOG" />
+ <!-- needed for User fragment to lock user data -->
+ <uses-permission android:name="android.permission.STORAGE_INTERNAL"/>
+ <uses-permission android:name="android.permission.USE_FULL_SCREEN_INTENT"/>
+ <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS"/>
+ <uses-permission android:name="android.permission.WRITE_SETTINGS"/>
+ <!-- use for vendor properties -->
+ <uses-permission android:name="android.car.permission.CAR_VENDOR_EXTENSION"/>
+ <uses-permission android:name="android.car.permission.GET_CAR_VENDOR_CATEGORY_SEAT"/>
+ <uses-permission android:name="android.car.permission.GET_CAR_VENDOR_CATEGORY_INFO"/>
+ <uses-permission android:name="android.car.permission.SET_CAR_VENDOR_CATEGORY_INFO"/>
+
+ <uses-permission android:name="android.car.permission.CONTROL_CAR_FEATURES"/>
+
+ <!-- use for rotary fragment to enable/disable packages related to rotary -->
+ <uses-permission android:name="android.permission.CHANGE_COMPONENT_ENABLED_STATE"/>
+
+ <!-- Used on DEVICE POLICY screen to lock screen -->
+ <uses-permission android:name="android.permission.LOCK_DEVICE"/>
+ <!-- Used on DEVICE POLICY screen to reset password -->
+ <uses-permission android:name="android.permission.RESET_PASSWORD"/>
+ <!-- Used on DEVICE POLICY screen to wipe data -->
+ <uses-permission android:name="android.permission.MASTER_CLEAR"/>
+
+ <!-- Allows to use the CarEvsService -->
+ <uses-permission android:name="android.car.permission.REQUEST_CAR_EVS_ACTIVITY"/>
+ <uses-permission android:name="android.car.permission.CONTROL_CAR_EVS_ACTIVITY"/>
+ <uses-permission android:name="android.car.permission.USE_CAR_EVS_CAMERA"/>
+ <uses-permission android:name="android.car.permission.MONITOR_CAR_EVS_STATUS"/>
+
+ <uses-permission android:name="android.permission.CALL_PHONE" />
+
+ <!-- Allows sending of notifications in T+ -->
+ <uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>
+
+ <!-- To make curl downloads work in CarTelemetryTestFragment -->
+ <uses-permission android:name="android.permission.INTERNET"/>
+ <!-- To enable suspend to RAM emulation via shell command in CarTelemetryTestFragment -->
+ <uses-permission android:name="android.permission.DEVICE_POWER"/>
<instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
android:targetPackage="android.car.apitest"
@@ -29,6 +177,10 @@
<application android:label="CarApiTest"
android:debuggable="true">
+
+ <!-- Used by CarPackageManagerTest -->
+ <meta-data android:name="android.car.targetCarVersion" android:value="108:42"/>
+
<uses-library android:name="android.test.runner"/>
<activity android:name=".TestCarProxyActivity"
android:exported="true">
diff --git a/tests/android_car_api_test/OWNERS b/tests/android_car_api_test/OWNERS
new file mode 100644
index 0000000..2ca71f4
--- /dev/null
+++ b/tests/android_car_api_test/OWNERS
@@ -0,0 +1,18 @@
+# ActivityManager
+per-file src/android/car/apitest/CarActivityManagerTest.java = ycheo@google.com
+
+# AppFocus
+per-file src/android/car/apitest/CarAppFocusManagerTest.java = ycheo@google.com
+
+# Audio
+per-file src/android/car/apitest/media/CarAudioManagerTest.java = oscarazu@google.com, ericjeong@google.com
+
+# Navigation
+per-file src/android/car/apitest/CarNavigationManagerTest.java = ycheo@google.com
+
+# PackageManager
+per-file src/android/car/apitest/CarPackageManagerTest.java = ycheo@google.com
+
+# System
+per-file src/com/android/car/internal/* = ericjeong@google.com
+per-file test_aidl/android/car/apitest/* = ericjeong@google.com
diff --git a/tests/android_car_api_test/src/android/car/apitest/CarApiTestBase.java b/tests/android_car_api_test/src/android/car/apitest/CarApiTestBase.java
index 2b9bec7..ef77a6a 100644
--- a/tests/android_car_api_test/src/android/car/apitest/CarApiTestBase.java
+++ b/tests/android_car_api_test/src/android/car/apitest/CarApiTestBase.java
@@ -48,9 +48,11 @@
import org.junit.rules.TestName;
import java.io.BufferedReader;
+import java.io.ByteArrayOutputStream;
import java.io.FileDescriptor;
import java.io.FileInputStream;
import java.io.IOException;
+import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
@@ -248,4 +250,25 @@
Log.e(TAG, "test failed: " + message);
org.junit.Assert.fail(message);
}
+
+ protected static String executeShellCommand(String commandFormat, Object... args)
+ throws IOException {
+ UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
+ return executeShellCommand(uiAutomation, commandFormat, args);
+ }
+
+ private static String executeShellCommand(UiAutomation uiAutomation, String commandFormat,
+ Object... args) throws IOException {
+ ParcelFileDescriptor stdout = uiAutomation.executeShellCommand(
+ String.format(commandFormat, args));
+ try (InputStream inputStream = new ParcelFileDescriptor.AutoCloseInputStream(stdout)) {
+ ByteArrayOutputStream result = new ByteArrayOutputStream();
+ byte[] buffer = new byte[1024];
+ int length;
+ while ((length = inputStream.read(buffer)) != -1) {
+ result.write(buffer, 0, length);
+ }
+ return result.toString("UTF-8");
+ }
+ }
}
diff --git a/tests/android_car_api_test/src/android/car/apitest/CarAppFocusManagerTest.java b/tests/android_car_api_test/src/android/car/apitest/CarAppFocusManagerTest.java
index 6759501..a236971 100644
--- a/tests/android_car_api_test/src/android/car/apitest/CarAppFocusManagerTest.java
+++ b/tests/android_car_api_test/src/android/car/apitest/CarAppFocusManagerTest.java
@@ -273,7 +273,7 @@
.isEqualTo(APP_FOCUS_REQUEST_SUCCEEDED);
assertThat(manager.getAppTypeOwner(APP_FOCUS_TYPE_NAVIGATION))
- .containsExactly("android.car.apitest", "com.google.android.car.kitchensink");
+ .containsExactly("android.car.apitest");
manager.abandonAppFocus(owner, APP_FOCUS_TYPE_NAVIGATION);
diff --git a/tests/android_car_api_test/src/android/car/apitest/CarBugreportManagerTest.java b/tests/android_car_api_test/src/android/car/apitest/CarBugreportManagerTest.java
index 32292df..08c806a 100644
--- a/tests/android_car_api_test/src/android/car/apitest/CarBugreportManagerTest.java
+++ b/tests/android_car_api_test/src/android/car/apitest/CarBugreportManagerTest.java
@@ -25,9 +25,9 @@
import android.car.Car;
import android.car.CarBugreportManager;
import android.car.CarBugreportManager.CarBugreportManagerCallback;
-import android.os.CancellationSignal;
import android.os.FileUtils;
import android.os.ParcelFileDescriptor;
+import android.os.SystemProperties;
import android.test.suitebuilder.annotation.LargeTest;
import androidx.test.platform.app.InstrumentationRegistry;
@@ -207,7 +207,10 @@
try (InputStream entryStream = zipFile.getInputStream(entry)) {
String data = streamToText(entryStream, /* maxSizeBytes= */ 1024);
assertThat(data).contains("== dumpstate: ");
- assertThat(data).contains("dry_run=1");
+ // TODO(b/244668890): Delete this isCuttlefish check after the bug is fixed.
+ if (!isCuttlefish(SystemProperties.get("ro.product.name"))) {
+ assertThat(data).contains("dry_run=1");
+ }
assertThat(data).contains("Build fingerprint: ");
}
return;
@@ -216,14 +219,19 @@
fail("bugreport-TIMESTAMP.txt not found in the final zip file.");
}
- private static String streamToText(InputStream in, long maxSizeBytes) throws IOException {
+ private static String streamToText(InputStream in, int maxSizeBytes) throws IOException {
+ assertThat(maxSizeBytes).isGreaterThan(0);
+
ByteArrayOutputStream result = new ByteArrayOutputStream();
- CancellationSignal cancelSignal = new CancellationSignal();
- FileUtils.copy(in, result, cancelSignal, /* executor= */ null, (progressBytes) -> {
- if (progressBytes >= maxSizeBytes) {
- cancelSignal.cancel();
- }
- });
+ byte[] data = new byte[maxSizeBytes];
+ int nRead;
+ int totalRead = 0;
+
+ while ((nRead = in.read(data, 0, data.length)) != -1 && totalRead <= maxSizeBytes) {
+ result.write(data, 0, nRead);
+ totalRead += maxSizeBytes;
+ }
+
return result.toString(StandardCharsets.UTF_8.name());
}
@@ -233,6 +241,14 @@
ParcelFileDescriptor.MODE_WRITE_ONLY | ParcelFileDescriptor.MODE_APPEND);
}
+ private static boolean isCuttlefish(String productName) {
+ return (null != productName)
+ && (productName.startsWith("aosp_cf_x86")
+ || productName.startsWith("aosp_cf_arm")
+ || productName.startsWith("cf_x86")
+ || productName.startsWith("cf_arm"));
+ }
+
/**
* Creates a piped ParcelFileDescriptor that anyone can write. Clients must call
* {@link copyToPersistentFile}, otherwise writers will be blocked when writing to the pipe.
diff --git a/tests/android_car_api_test/src/android/car/apitest/CarCabinManagerTest.java b/tests/android_car_api_test/src/android/car/apitest/CarCabinManagerTest.java
index cc258c2..daf1495 100644
--- a/tests/android_car_api_test/src/android/car/apitest/CarCabinManagerTest.java
+++ b/tests/android_car_api_test/src/android/car/apitest/CarCabinManagerTest.java
@@ -63,10 +63,15 @@
private void assertTypeAndZone(CarPropertyConfig property) {
int propId = property.getPropertyId();
switch (propId) {
- // Zoned boolean properties
- case CarCabinManager.ID_DOOR_LOCK:
+ // Global boolean properties
case CarCabinManager.ID_MIRROR_LOCK:
case CarCabinManager.ID_MIRROR_FOLD:
+ assertThat(property.getPropertyType()).isAssignableTo(Boolean.class);
+ assertThat(property.isGlobalProperty()).isTrue();
+ break;
+
+ // Zoned boolean properties
+ case CarCabinManager.ID_DOOR_LOCK:
case CarCabinManager.ID_SEAT_BELT_BUCKLED:
case CarCabinManager.ID_WINDOW_LOCK:
assertThat(property.getPropertyType()).isAssignableTo(Boolean.class);
diff --git a/tests/android_car_api_test/src/android/car/apitest/CarHvacManagerTest.java b/tests/android_car_api_test/src/android/car/apitest/CarHvacManagerTest.java
index f260869..52c8cee 100644
--- a/tests/android_car_api_test/src/android/car/apitest/CarHvacManagerTest.java
+++ b/tests/android_car_api_test/src/android/car/apitest/CarHvacManagerTest.java
@@ -72,7 +72,7 @@
private void assertTypeAndZone(CarPropertyConfig property) {
switch (property.getPropertyId()) {
case CarHvacManager.ID_MIRROR_DEFROSTER_ON: // non-zoned bool
- checkTypeAndGlobal(Boolean.class, true, property);
+ checkTypeAndGlobal(Integer.class, false, property);
break;
case CarHvacManager.ID_STEERING_WHEEL_HEAT: // non-zoned int
case CarHvacManager.ID_TEMPERATURE_DISPLAY_UNITS:
diff --git a/tests/android_car_api_test/src/android/car/apitest/CarPackageManagerTest.java b/tests/android_car_api_test/src/android/car/apitest/CarPackageManagerTest.java
index b1b177d..d880d90 100644
--- a/tests/android_car_api_test/src/android/car/apitest/CarPackageManagerTest.java
+++ b/tests/android_car_api_test/src/android/car/apitest/CarPackageManagerTest.java
@@ -17,20 +17,88 @@
package android.car.apitest;
import android.car.Car;
+import android.car.CarVersion;
import android.car.content.pm.CarPackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
import android.test.suitebuilder.annotation.MediumTest;
import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
+import static org.junit.Assert.assertThrows;
+
+import org.junit.Before;
import org.junit.Test;
@MediumTest
public class CarPackageManagerTest extends CarApiTestBase {
+ private CarPackageManager mCarPackageManager;
+
+ @Before
+ public void setFixtures() {
+ mCarPackageManager = (CarPackageManager) getCar().getCarManager(Car.PACKAGE_SERVICE);
+ }
+
@Test
public void testCreate() throws Exception {
- CarPackageManager carPackageManager = (CarPackageManager) getCar()
- .getCarManager(Car.PACKAGE_SERVICE);
- assertThat(carPackageManager).isNotNull();
+ assertThat(mCarPackageManager).isNotNull();
+ }
+
+ @Test
+ public void testGetTargetCarVersion_self() throws Exception {
+ CarVersion apiVersion = mCarPackageManager.getTargetCarVersion();
+
+ assertWithMessage("getTargetCarVersion()").that(apiVersion).isNotNull();
+ assertWithMessage("major version")
+ .that(apiVersion.getMajorVersion())
+ .isEqualTo(108);
+ assertWithMessage("minor version for")
+ .that(apiVersion.getMinorVersion())
+ .isEqualTo(42);
+ }
+
+ @Test
+ public void testgetTargetCarVersion_noPackage() throws Exception {
+ String pkg = "I can't believe a package with this name exist. If so, well, too bad!";
+
+ NameNotFoundException e = assertThrows(NameNotFoundException.class,
+ () -> mCarPackageManager.getTargetCarVersion(pkg));
+
+ assertWithMessage("exception msg").that(e.getMessage()).contains(pkg);
+ }
+
+ @Test
+ public void testGetTargetCarMajorAndMinorVersion_notSet() throws Exception {
+ String pkg = "com.android.car";
+ // TODO(b/228506662): it would be better add another app that explicitly sets sdkTarget
+ // version instead, so it doesn't depend on com.android.car's version (which this test
+ // doesn't control)
+ int targetSdk = Car.getPlatformVersion().getMajorVersion();
+
+ CarVersion apiVersion = mCarPackageManager.getTargetCarVersion(pkg);
+
+ assertWithMessage("getTargetCarVersion(%s)", pkg).that(apiVersion).isNotNull();
+ assertWithMessage("major version for %s", pkg)
+ .that(apiVersion.getMajorVersion())
+ .isEqualTo(targetSdk);
+ assertWithMessage("minor version for %s", pkg)
+ .that(apiVersion.getMinorVersion())
+ .isEqualTo(0);
+ }
+
+ @Test
+ public void testGetTargetCarMajorAndMinorVersion_set() throws Exception {
+ String pkg = sContext.getPackageName();
+
+ CarVersion apiVersion = mCarPackageManager.getTargetCarVersion(pkg);
+
+ assertWithMessage("getTargetCarVersion(%s)", pkg).that(apiVersion).isNotNull();
+ assertWithMessage("major version for %s", pkg)
+ .that(apiVersion.getMajorVersion())
+ .isEqualTo(108);
+ assertWithMessage("minor version for %s", pkg)
+ .that(apiVersion.getMinorVersion())
+ .isEqualTo(42);
}
}
diff --git a/tests/android_car_api_test/src/android/car/apitest/CarTest.java b/tests/android_car_api_test/src/android/car/apitest/CarTest.java
index 2dc5bae..de9132e 100644
--- a/tests/android_car_api_test/src/android/car/apitest/CarTest.java
+++ b/tests/android_car_api_test/src/android/car/apitest/CarTest.java
@@ -21,10 +21,9 @@
import static org.testng.Assert.assertThrows;
import android.car.Car;
+import android.car.CarVersion;
import android.car.ICar;
-import android.car.annotation.AddedIn;
-import android.car.annotation.AddedInOrBefore;
-import android.car.annotation.MinimumPlatformSdkVersion;
+import android.car.PlatformVersion;
import android.car.hardware.CarSensorManager;
import android.content.ComponentName;
import android.content.Context;
@@ -70,55 +69,6 @@
mConnectionWait.tryAcquire(timeoutMs, TimeUnit.MILLISECONDS);
}
- @AddedIn(majorVersion = 31)
- @MinimumPlatformSdkVersion(30)
- private static class AnnotationTest1 {
- @AddedIn(majorVersion = 31)
- @MinimumPlatformSdkVersion(29)
- public int val;
-
- @AddedIn(majorVersion = 31)
- public void method1() {
- }
- }
-
- @AddedIn(majorVersion = 31, minorVersion = 0)
- @MinimumPlatformSdkVersion(30)
- private static class AnnotationTest2 {
- @AddedIn(majorVersion = 31, minorVersion = 0)
- @MinimumPlatformSdkVersion(29)
- public int val;
-
- @AddedIn(majorVersion = 31, minorVersion = 0)
- public void method1() {
- }
- }
-
-
- @AddedInOrBefore(majorVersion = 31)
- @MinimumPlatformSdkVersion(30)
- private static class AnnotationTest3 {
- @AddedInOrBefore(majorVersion = 31)
- @MinimumPlatformSdkVersion(29)
- public int val;
-
- @AddedInOrBefore(majorVersion = 31)
- public void method1() {
- }
- }
-
- @AddedInOrBefore(majorVersion = 31, minorVersion = 0)
- @MinimumPlatformSdkVersion(30)
- private static class AnnotationTest4 {
- @AddedInOrBefore(majorVersion = 31, minorVersion = 0)
- @MinimumPlatformSdkVersion(29)
- public int val;
-
- @AddedInOrBefore(majorVersion = 31, minorVersion = 0)
- public void method1() {
- }
- }
-
@Test
public void testCarConnection() throws Exception {
Car car = Car.createCar(mContext, mConnectionListener);
@@ -166,7 +116,8 @@
}
@Test
- public void testApiVersion() throws Exception {
+ @SuppressWarnings("deprecation")
+ public void testApiVersion_deprecated() throws Exception {
int ApiVersionTooHigh = 1000000;
int MinorApiVersionTooHigh = 1000000;
assertThat(Car.isApiVersionAtLeast(Car.API_VERSION_MAJOR_INT)).isTrue();
@@ -189,4 +140,23 @@
assertThat(Car.isApiAndPlatformVersionAtLeast(Car.API_VERSION_MAJOR_INT,
Car.API_VERSION_MINOR_INT, Build.VERSION.SDK_INT + 1)).isFalse();
}
+
+ @Test
+ public void testApiVersion_car() throws Exception {
+ CarVersion carVersion = Car.getCarVersion();
+
+ assertThat(carVersion).isNotNull();
+ assertThat(carVersion.getMajorVersion()).isAtLeast(Build.VERSION.SDK_INT);
+ assertThat(carVersion.getMajorVersion()).isAtMost(Build.VERSION_CODES.CUR_DEVELOPMENT);
+ assertThat(carVersion.getMinorVersion()).isAtLeast(0);
+ }
+
+ @Test
+ public void testApiVersion_platform() throws Exception {
+ PlatformVersion platformVersion = Car.getPlatformVersion();
+
+ assertThat(platformVersion).isNotNull();
+ assertThat(platformVersion.getMajorVersion()).isEqualTo(Build.VERSION.SDK_INT);
+ assertThat(platformVersion.getMinorVersion()).isAtLeast(0);
+ }
}
diff --git a/tests/android_car_api_test/src/android/car/apitest/CarUserManagerTest.java b/tests/android_car_api_test/src/android/car/apitest/CarUserManagerTest.java
index a853f48..2131b26 100644
--- a/tests/android_car_api_test/src/android/car/apitest/CarUserManagerTest.java
+++ b/tests/android_car_api_test/src/android/car/apitest/CarUserManagerTest.java
@@ -18,6 +18,8 @@
import static android.car.test.util.UserTestingHelper.clearUserLockCredentials;
import static android.car.test.util.UserTestingHelper.setMaxSupportedUsers;
import static android.car.test.util.UserTestingHelper.setUserLockCredentials;
+import static android.car.user.CarUserManager.USER_LIFECYCLE_EVENT_TYPE_CREATED;
+import static android.car.user.CarUserManager.USER_LIFECYCLE_EVENT_TYPE_REMOVED;
import static android.car.user.CarUserManager.USER_LIFECYCLE_EVENT_TYPE_STARTING;
import static android.car.user.CarUserManager.USER_LIFECYCLE_EVENT_TYPE_SWITCHING;
import static android.car.user.CarUserManager.USER_LIFECYCLE_EVENT_TYPE_UNLOCKED;
@@ -29,20 +31,31 @@
import android.app.ActivityManager;
import android.app.IActivityManager;
import android.car.Car;
+import android.car.test.ApiCheckerRule;
+import android.car.test.ApiCheckerRule.SupportedVersionTest;
+import android.car.test.ApiCheckerRule.UnsupportedVersionTest;
+import android.car.test.ApiCheckerRule.UnsupportedVersionTest.Behavior;
import android.car.testapi.BlockingUserLifecycleListener;
import android.car.user.CarUserManager;
import android.car.user.CarUserManager.UserLifecycleEvent;
+import android.car.user.CarUserManager.UserLifecycleListener;
import android.car.user.UserLifecycleEventFilter;
import android.content.pm.UserInfo;
import android.os.Process;
+import android.os.SystemClock;
+import android.os.SystemProperties;
import android.os.UserHandle;
import android.os.UserManager;
import android.util.Log;
+import com.android.compatibility.common.util.ApiTest;
+
import org.junit.AfterClass;
import org.junit.BeforeClass;
+import org.junit.Rule;
import org.junit.Test;
+import java.util.ArrayList;
import java.util.List;
public final class CarUserManagerTest extends CarMultiUserTestBase {
@@ -57,6 +70,11 @@
private static final int sMaxNumberUsersBefore = UserManager.getMaxSupportedUsers();
private static boolean sChangedMaxNumberUsers;
+ // TODO(b/242350638): move to super class (although it would need to call
+ // disableAnnotationsCheck()
+ @Rule
+ public final ApiCheckerRule mApiCheckerRule = new ApiCheckerRule.Builder().build();
+
@BeforeClass
public static void setupMaxNumberOfUsers() {
int requiredUsers = 3; // system user, current user, 1 extra user
@@ -77,6 +95,7 @@
}
@Test
+ @ApiTest(apis = {"android.car.user.CarUserManager#createUser(String, int)"})
public void testCreateUser() throws Exception {
UserInfo newUser = createUser("DaNewUserInTheBlock");
assertWithMessage("(%s).isGuest()", newUser.toFullString()).that(newUser.isGuest())
@@ -91,6 +110,7 @@
}
@Test
+ @ApiTest(apis = {"android.car.user.CarUserManager#createGuest(String)"})
public void testCreateGuest() throws Exception {
UserInfo newGuest = createGuest("DaNewGuestInTheBlock");
assertWithMessage("(%s).isGuest()", newGuest.toFullString()).that(newGuest.isGuest())
@@ -105,6 +125,150 @@
}
@Test
+ @ApiTest(apis = {"android.car.user.CarUserManager#USER_LIFECYCLE_EVENT_TYPE_CREATED"})
+ @SupportedVersionTest(unsupportedVersionTest =
+ "testLifecycleUserCreatedListener_unsupportedVersion")
+ public void testLifecycleUserCreatedListener_supportedVersion() throws Exception {
+ Car car = Car.createCar(getContext().getApplicationContext());
+ CarUserManager mgr = (CarUserManager) car.getCarManager(Car.CAR_USER_SERVICE);
+
+ BlockingUserLifecycleListener listener = BlockingUserLifecycleListener
+ .forSpecificEvents()
+ .setTimeout(START_TIMEOUT_MS)
+ .addExpectedEvent(USER_LIFECYCLE_EVENT_TYPE_CREATED)
+ .build();
+
+ int newUserId = UserHandle.USER_NULL;
+ try {
+ Log.d(TAG, "registering listener: " + listener);
+ mgr.addListener(Runnable::run, listener);
+ Log.v(TAG, "ok");
+
+ newUserId = createUser("TestUserToCreate").id;
+
+ Log.d(TAG, "Waiting for events");
+ List<UserLifecycleEvent> events = listener.waitForEvents();
+ Log.d(TAG, "events: " + events);
+ assertWithMessage("events").that(events).hasSize(1);
+ UserLifecycleEvent event = events.get(0);
+ assertWithMessage("type of event %s", event).that(event.getEventType())
+ .isEqualTo(USER_LIFECYCLE_EVENT_TYPE_CREATED);
+ assertWithMessage("user id on %s", event).that(event.getUserId())
+ .isEqualTo(newUserId);
+ } finally {
+ Log.d(TAG, "unregistering listener: " + listener);
+ mgr.removeListener(listener);
+ Log.v(TAG, "ok");
+
+ if (newUserId != UserHandle.USER_NULL) {
+ removeUser(newUserId);
+ }
+ }
+ }
+
+ @Test
+ @ApiTest(apis = {"android.car.user.CarUserManager#USER_LIFECYCLE_EVENT_TYPE_CREATED"})
+ @UnsupportedVersionTest(behavior = Behavior.EXPECT_PASS,
+ supportedVersionTest = "testLifecycleUserCreatedListener_supportedVersion")
+ public void testLifecycleUserCreatedListener_unsupportedVersion() throws Exception {
+ Car car = Car.createCar(getContext().getApplicationContext());
+ CarUserManager mgr = (CarUserManager) car.getCarManager(Car.CAR_USER_SERVICE);
+
+ LifecycleListener listener = new LifecycleListener();
+
+ int newUserId = UserHandle.USER_NULL;
+ try {
+ mgr.addListener(Runnable::run, listener);
+ Log.v(TAG, "ok");
+
+ newUserId = createUser("TestUserToCreate").id;
+
+ Log.d(TAG, "Waiting for events");
+ listener.assertEventNotReceived(
+ newUserId, CarUserManager.USER_LIFECYCLE_EVENT_TYPE_CREATED);
+ } finally {
+ Log.d(TAG, "unregistering listener: " + listener);
+ mgr.removeListener(listener);
+ Log.v(TAG, "ok");
+
+ if (newUserId != UserHandle.USER_NULL) {
+ removeUser(newUserId);
+ }
+ }
+ }
+
+ @Test
+ @SupportedVersionTest(unsupportedVersionTest =
+ "testLifecycleUserRemovedListener_unsupportedVersion")
+ @ApiTest(apis = {"android.car.user.CarUserManager#USER_LIFECYCLE_EVENT_TYPE_REMOVED"})
+ public void testLifecycleUserRemovedListener_supportedVersion() throws Exception {
+ int newUserId = createUser("TestUserToRemove").id;
+ Car car = Car.createCar(getContext().getApplicationContext());
+ CarUserManager mgr = (CarUserManager) car.getCarManager(Car.CAR_USER_SERVICE);
+
+ BlockingUserLifecycleListener listener = BlockingUserLifecycleListener
+ .forSpecificEvents()
+ .forUser(newUserId)
+ .setTimeout(START_TIMEOUT_MS)
+ .addExpectedEvent(USER_LIFECYCLE_EVENT_TYPE_REMOVED)
+ .build();
+
+ try {
+ Log.d(TAG, "registering listener: " + listener);
+ mgr.addListener(Runnable::run, listener);
+ Log.v(TAG, "ok");
+
+ removeUser(newUserId);
+
+ Log.d(TAG, "Waiting for events");
+ List<UserLifecycleEvent> events = listener.waitForEvents();
+ Log.d(TAG, "events: " + events);
+ assertWithMessage("events").that(events).hasSize(1);
+ UserLifecycleEvent event = events.get(0);
+ assertWithMessage("type of event %s", event).that(event.getEventType())
+ .isEqualTo(USER_LIFECYCLE_EVENT_TYPE_REMOVED);
+ assertWithMessage("user id on %s", event).that(event.getUserId())
+ .isEqualTo(newUserId);
+ } finally {
+ Log.d(TAG, "unregistering listener: " + listener);
+ mgr.removeListener(listener);
+ Log.v(TAG, "ok");
+ }
+ }
+
+ @Test
+ @UnsupportedVersionTest(behavior = Behavior.EXPECT_PASS, supportedVersionTest =
+ "testLifecycleUserRemovedListener_supportedVersion")
+ @ApiTest(apis = {"android.car.user.CarUserManager#USER_LIFECYCLE_EVENT_TYPE_REMOVED"})
+ public void testLifecycleUserRemovedListener_unsupportedVersion() throws Exception {
+ int newUserId = createUser("TestUserToRemove").id;
+ Car car = Car.createCar(getContext().getApplicationContext());
+ CarUserManager mgr = (CarUserManager) car.getCarManager(Car.CAR_USER_SERVICE);
+
+ LifecycleListener listener = new LifecycleListener();
+
+ try {
+ Log.d(TAG, "registering listener: " + listener);
+ mgr.addListener(Runnable::run, listener);
+ Log.v(TAG, "ok");
+
+ removeUser(newUserId);
+
+ Log.d(TAG, "Waiting for events");
+ listener.assertEventNotReceived(
+ newUserId, CarUserManager.USER_LIFECYCLE_EVENT_TYPE_CREATED);
+ } finally {
+ Log.d(TAG, "unregistering listener: " + listener);
+ mgr.removeListener(listener);
+ Log.v(TAG, "ok");
+ }
+ }
+
+ @Test
+ @ApiTest(apis = {
+ "android.car.user.CarUserManager#addListener(Executor,UserLifecycleListener)",
+ "android.car.user.CarUserManager#removeListener(UserLifecycleListener)"
+ })
public void testLifecycleMultipleListeners() throws Exception {
int newUserId = createUser("Test").id;
Car car2 = Car.createCar(getContext().getApplicationContext());
@@ -197,7 +361,14 @@
* created and switched to.
*/
@Test
+ @ApiTest(apis = {
+ "android.car.user.CarUserManager#USER_LIFECYCLE_EVENT_TYPE_UNLOCKED",
+ "android.car.user.CarUserManager#USER_LIFECYCLE_EVENT_TYPE_SWITCHING",
+ })
public void testGuestUserResumeToNewGuestUser() throws Exception {
+ // TODO(b/241837415): Create a host-side test and move this test there.
+ if (!isDeviceEmulator()) return;
+
// Create new guest user
UserInfo guestUser = createGuest();
int guestUserId = guestUser.id;
@@ -251,7 +422,13 @@
* resume to same guest user.
*/
@Test
+ @ApiTest(apis = {
+ "android.car.user.CarUserManager#USER_LIFECYCLE_EVENT_TYPE_UNLOCKED",
+ })
public void testSecuredGuestUserResumeToSameUser() throws Exception {
+ // TODO(b/241837415): Create a host-side test and move this test there.
+ if (!isDeviceEmulator()) return;
+
// Create new guest user
UserInfo guestUser = createGuest();
int guestUserId = guestUser.id;
@@ -289,7 +466,13 @@
* Tests resume behavior when current user is persistent user.
*/
@Test
+ @ApiTest(apis = {
+ "android.car.user.CarUserManager#USER_LIFECYCLE_EVENT_TYPE_UNLOCKED",
+ })
public void testPersistentUserResumeToUser() throws Exception {
+ // TODO(b/241837415): Create a host-side test and move this test there.
+ if (!isDeviceEmulator()) return;
+
int newUserId = createUser().id;
BlockingUserLifecycleListener listener = BlockingUserLifecycleListener
.forSpecificEvents()
@@ -312,4 +495,53 @@
mCarUserManager.removeListener(listener);
}
}
+
+ private static boolean isDeviceEmulator() {
+ return SystemProperties.get("ro.product.system.device").equals("generic");
+ }
+
+ // TODO(b/244594590): Clean this listener up once BlockingUserLifecycleListener supports
+ // no events received.
+ private final class LifecycleListener implements UserLifecycleListener {
+ private static final int TIMEOUT_MS = 60_000;
+ private static final int WAIT_TIME_MS = 1_000;
+
+ private final List<UserLifecycleEvent> mEvents =
+ new ArrayList<CarUserManager.UserLifecycleEvent>();
+
+ private final Object mLock = new Object();
+
+ @Override
+ public void onEvent(UserLifecycleEvent event) {
+ Log.d(TAG, "Event received: " + event);
+ synchronized (mLock) {
+ mEvents.add(event);
+ }
+ }
+
+ public void assertEventNotReceived(int userId, int eventType)
+ throws InterruptedException {
+ long startTime = SystemClock.elapsedRealtime();
+ while (SystemClock.elapsedRealtime() - startTime < TIMEOUT_MS) {
+ boolean result = checkEvent(userId, eventType);
+ if (result) {
+ fail("Event" + eventType
+ + " was not expected but was received within timeoutMs: " + TIMEOUT_MS);
+ }
+ Thread.sleep(WAIT_TIME_MS);
+ }
+ }
+
+ private boolean checkEvent(int userId, int eventType) {
+ synchronized (mLock) {
+ for (int i = 0; i < mEvents.size(); i++) {
+ if (mEvents.get(i).getUserHandle().getIdentifier() == userId
+ && mEvents.get(i).getEventType() == eventType) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+ }
}
diff --git a/tests/android_car_api_test/src/android/car/apitest/VehiclePropertyIdsTest.java b/tests/android_car_api_test/src/android/car/apitest/VehiclePropertyIdsTest.java
index 9aad531..735f091 100644
--- a/tests/android_car_api_test/src/android/car/apitest/VehiclePropertyIdsTest.java
+++ b/tests/android_car_api_test/src/android/car/apitest/VehiclePropertyIdsTest.java
@@ -37,7 +37,8 @@
@SmallTest
public class VehiclePropertyIdsTest {
// IDs that only exist in CarPropertyManager, not VHAL.
- private static final List<String> MISSING_VHAL_IDS = List.of();
+ private static final List<String> MISSING_VHAL_IDS = List.of(
+ "GENERAL_SAFETY_REGULATION_COMPLIANCE");
// IDs that only exist in VHAL, not exposed by CarPropertyManager.
private static final List<String> MISSING_VEHICLE_PROPERTY_IDS = List.of(
diff --git a/tests/android_car_api_test/src/com/android/internal/car/CarServiceHelperServiceSystemTest.java b/tests/android_car_api_test/src/com/android/internal/car/CarServiceHelperServiceSystemTest.java
new file mode 100644
index 0000000..c4ea80c
--- /dev/null
+++ b/tests/android_car_api_test/src/com/android/internal/car/CarServiceHelperServiceSystemTest.java
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2022 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.internal.car;
+
+import static com.android.compatibility.common.util.SystemUtil.eventually;
+
+import static com.google.common.truth.Truth.assertWithMessage;
+
+import static org.hamcrest.CoreMatchers.containsStringIgnoringCase;
+import static org.junit.Assume.assumeThat;
+import static org.junit.Assume.assumeTrue;
+
+import android.car.apitest.CarApiTestBase;
+import android.os.Build;
+
+import com.android.compatibility.common.util.ApiTest;
+
+import org.junit.Test;
+
+import java.io.IOException;
+
+public final class CarServiceHelperServiceSystemTest extends CarApiTestBase {
+
+ @Test
+ @ApiTest(apis = {"com.android.internal.car.CarServiceHelperInterface#setSafetyMode(boolean)"})
+ public void testCarServiceHelperServiceDump_safeMode() throws Exception {
+ assumeSystemServerDumpSupported();
+ assumeUserDebugBuild();
+
+ // Should be parked already, but it doesn't hurt to make sure
+ executeShellCommand("cmd car_service emulate-driving-state park");
+
+ eventually(()-> assertWithMessage("CarServiceHelperService dump")
+ .that(dumpCarServiceHelper())
+ .contains("Safe to run device policy operations: true"));
+ }
+
+ @Test
+ @ApiTest(apis = {"com.android.internal.car.CarServiceHelperInterface#setSafetyMode(boolean)"})
+ public void testCarServiceHelperServiceDump_unsafeMode() throws Exception {
+ assumeSystemServerDumpSupported();
+ assumeUserDebugBuild();
+ try {
+ executeShellCommand("cmd car_service emulate-driving-state drive");
+
+ eventually(() -> assertWithMessage("CarServiceHelperService dump")
+ .that(dumpCarServiceHelper())
+ .contains("Safe to run device policy operations: false"));
+ } finally {
+ executeShellCommand("cmd car_service emulate-driving-state park");
+ }
+ }
+
+ @Test
+ @ApiTest(apis = {"com.android.internal.car.CarServiceHelperService#dump(PrintWriter,String[])"})
+ public void testCarServiceHelperServiceDump_safeOperation() throws Exception {
+ assumeSystemServerDumpSupported();
+ assumeUserDebugBuild();
+ // Should be parked already, but it doesn't hurt to make sure
+ executeShellCommand("cmd car_service emulate-driving-state park");
+
+ eventually(()-> assertWithMessage("CarServiceHelperService dump")
+ .that(dumpCarServiceHelper("--is-operation-safe", "7"))
+ .contains("Operation REBOOT is SAFE. Reason: NONE"));
+ }
+
+ @Test
+ @ApiTest(apis = {"com.android.internal.car.CarServiceHelperService#dump(PrintWriter,String[])"})
+ public void testCarServiceHelperServiceDump_unsafeOperation() throws Exception {
+ assumeSystemServerDumpSupported();
+ assumeUserDebugBuild();
+ try {
+ executeShellCommand("cmd car_service emulate-driving-state drive");
+
+ eventually(()-> assertWithMessage("CarServiceHelperService dump")
+ .that(dumpCarServiceHelper("--is-operation-safe", "7"))
+ .contains("Operation REBOOT is UNSAFE. Reason: DRIVING_DISTRACTION"));
+ } finally {
+ executeShellCommand("cmd car_service emulate-driving-state park");
+ }
+ }
+
+ private static void assumeSystemServerDumpSupported() throws IOException {
+ assumeThat("System_server_dumper not implemented.",
+ executeShellCommand("service check system_server_dumper"),
+ containsStringIgnoringCase("system_server_dumper: found"));
+ }
+
+ private static void assumeUserDebugBuild() {
+ assumeTrue("Not a user debug build", !Build.TYPE.equalsIgnoreCase("user"));
+ }
+
+ private String dumpCarServiceHelper(String...args) throws IOException {
+ StringBuilder cmd = new StringBuilder(
+ "dumpsys system_server_dumper --name CarServiceHelper");
+ for (String arg : args) {
+ cmd.append(' ').append(arg);
+ }
+ return executeShellCommand(cmd.toString());
+ }
+}
diff --git a/tests/carservice_test/AndroidManifest.xml b/tests/carservice_test/AndroidManifest.xml
index 5025df7..03848cd 100644
--- a/tests/carservice_test/AndroidManifest.xml
+++ b/tests/carservice_test/AndroidManifest.xml
@@ -20,6 +20,7 @@
<uses-permission android:name="android.Manifest.permission.MODIFY_AUDIO_ROUTING"/>
<uses-permission android:name="android.car.permission.ACCESS_PRIVATE_DISPLAY_ID"/>
+ <uses-permission android:name="android.car.permission.MANAGE_THREAD_PRIORITY"/>
<uses-permission android:name="android.car.permission.CONTROL_CAR_CLIMATE"/>
<uses-permission android:name="android.car.permission.CONTROL_CAR_DOORS"/>
<uses-permission android:name="android.car.permission.CONTROL_CAR_WINDOWS"/>
@@ -37,6 +38,7 @@
<uses-permission android:name="android.car.permission.CONTROL_SHUTDOWN_PROCESS"/>
<uses-permission android:name="android.car.permission.GET_CAR_VENDOR_CATEGORY_1"/>
<uses-permission android:name="android.car.permission.SET_CAR_VENDOR_CATEGORY_1"/>
+ <uses-permission android:name="android.car.permission.CAR_TIRES"/>
<instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
android:targetPackage="com.android.car.test"
diff --git a/tests/carservice_test/OWNERS b/tests/carservice_test/OWNERS
new file mode 100644
index 0000000..855e690
--- /dev/null
+++ b/tests/carservice_test/OWNERS
@@ -0,0 +1,30 @@
+# AppFocus
+per-file src/com/android/car/AppFocusTest.java = ycheo@google.com
+
+# Audio
+per-file src/android/media/tests/AudioPolicyTest.java = oscarazu@google.com, ericjeong@google.com
+per-file src/com/android/car/CarAudioManagerTest.java = oscarazu@google.com, ericjeong@google.com
+per-file src/com/android/car/audio/* = oscarazu@google.com, ericjeong@google.com
+
+# Cluster
+per-file src/com/android/car/cluster/* = ycheo@google.com
+
+# Input
+per-file src/com/android/car/input/* = ycheo@google.com
+
+# HAL
+per-file src/com/android/car/hal/test/*MockedVehiclHal.java = ericjeong@google.com
+
+# PackageManager
+per-file src/com/android/car/CarPackageManagerTest.java = ycheo@google.com
+per-file src/com/android/car/pm/* = ycheo@google.com
+
+# Power
+per-file src/com/android/car/garagemode/* = ericjeong@google.com
+per-file src/com/android/car/power/* = ericjeong@google.com
+
+# StorageMonitoring
+per-file src/com/android/car/CarStorageMonitoringTest.java = lakshmana@google.com
+
+# Watchdog
+per-file src/com/android/car/watchdog/* = lakshmana@google.com
diff --git a/tests/carservice_test/src/com/android/car/CarEvsManagerTest.java b/tests/carservice_test/src/com/android/car/CarEvsManagerTest.java
index cb15747..d48c30a 100644
--- a/tests/carservice_test/src/com/android/car/CarEvsManagerTest.java
+++ b/tests/carservice_test/src/com/android/car/CarEvsManagerTest.java
@@ -30,7 +30,6 @@
import android.content.Context;
import android.os.SystemClock;
import android.test.suitebuilder.annotation.MediumTest;
-import android.util.Log;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.runner.AndroidJUnit4;
@@ -66,6 +65,7 @@
private static final int FRAME_TIMEOUT_MS = 1000;
private static final int SMALL_NAP_MS = 500;
private static final int ACTIVITY_REQUEST_TIMEOUT_SEC = 3;
+ private static final int STREAM_REQUEST_TIMEOUT_SEC = 1;
// Will return frame buffers in the order they arrived.
private static final int INDEX_TO_FIRST_ELEM = 0;
@@ -73,6 +73,8 @@
private final ArrayList<CarEvsBufferDescriptor> mReceivedBuffers = new ArrayList<>();
private final ExecutorService mCallbackExecutor = Executors.newFixedThreadPool(1);
private final Semaphore mFrameReceivedSignal = new Semaphore(0);
+ private final Semaphore mServiceInRequestedState = new Semaphore(0);
+ private final Semaphore mServiceInActiveState = new Semaphore(0);
private final Car mCar = Car.createCar(ApplicationProvider.getApplicationContext());
private final CarEvsManager mEvsManager =
@@ -80,8 +82,6 @@
private final EvsStreamCallbackImpl mStreamCallback = new EvsStreamCallbackImpl();
private final EvsStatusListenerImpl mStatusListener = new EvsStatusListenerImpl();
- private CountDownLatch mActivityRequested;
-
@Before
public void setUp() {
assumeTrue(mCar.isFeatureEnabled(Car.CAR_EVS_SERVICE));
@@ -90,6 +90,11 @@
assertThat(mStreamCallback).isNotNull();
assertThat(mStatusListener).isNotNull();
+ // Drains all permits
+ mFrameReceivedSignal.drainPermits();
+ mServiceInRequestedState.drainPermits();
+ mServiceInActiveState.drainPermits();
+
// Ensures no stream is active
mEvsManager.stopVideoStream();
}
@@ -108,41 +113,51 @@
@Test
public void testSetStatusListener() throws Exception {
- // Set a status listener
+ // Registers a status listener and start monitoring the CarEvsService's state changes.
mEvsManager.setStatusListener(mCallbackExecutor, mStatusListener);
- // Request to start a service
+ // Requests to start the rearview activity.
assertThat(
mEvsManager.startActivity(CarEvsManager.SERVICE_TYPE_REARVIEW)
).isEqualTo(CarEvsManager.ERROR_NONE);
- // Wait for a notification
- mActivityRequested = new CountDownLatch(1);
- assertThat(mActivityRequested.await(ACTIVITY_REQUEST_TIMEOUT_SEC, TimeUnit.SECONDS))
- .isTrue();
+ // Waits until the CarEvsService enters the REQUESTED state.
+ assertThat(
+ mServiceInRequestedState.tryAcquire(ACTIVITY_REQUEST_TIMEOUT_SEC, TimeUnit.SECONDS)
+ ).isTrue();
- // Then, requests to stop a video stream started upon a receipt of STATE_REQUESTED
- // transition notification.
- mEvsManager.stopVideoStream();
+ // Waits until the CarEvsService starts a video stream; it enters the ACTIVE state.
+ assertThat(
+ mServiceInActiveState.tryAcquire(STREAM_REQUEST_TIMEOUT_SEC, TimeUnit.SECONDS)
+ ).isTrue();
- // Unregister a listener
+ // Requests to stop the rearview activity.
+ mEvsManager.stopActivity();
+
+ // Unregisters a status listener.
mEvsManager.clearStatusListener();
}
@Test
public void testStartAndStopVideoStream() throws Exception {
- // Requests to start a video stream. We're intentionally using the listener that
- // is registered during the test setup.
+ // Registers a status listener and start monitoring the CarEvsService's state changes.
+ mEvsManager.setStatusListener(mCallbackExecutor, mStatusListener);
+
+ // Requests to start a video stream.
assertThat(
mEvsManager.startVideoStream(CarEvsManager.SERVICE_TYPE_REARVIEW,
/* token = */ null, mCallbackExecutor, mStreamCallback)
).isEqualTo(CarEvsManager.ERROR_NONE);
- // Waits for a few frames frame buffers
+ // Waits until the service starts the video stream.
+ assertThat(
+ mServiceInActiveState.tryAcquire(STREAM_REQUEST_TIMEOUT_SEC, TimeUnit.SECONDS)
+ ).isTrue();
+
+ // Then, waits for a few frames frame buffers
for (int i = 0; i < NUMBER_OF_FRAMES_TO_WAIT; ++i) {
assertThat(
- mFrameReceivedSignal.tryAcquire(
- FRAME_TIMEOUT_MS, TimeUnit.MILLISECONDS)
+ mFrameReceivedSignal.tryAcquire(FRAME_TIMEOUT_MS, TimeUnit.MILLISECONDS)
).isTrue();
// Nothing to do; returns a buffer immediately
@@ -188,16 +203,11 @@
public void onStatusChanged(CarEvsStatus status) {
switch (status.getState()) {
case CarEvsManager.SERVICE_STATE_REQUESTED:
- // Request to start a video stream
- assertThat(
- mEvsManager.startVideoStream(CarEvsManager.SERVICE_TYPE_REARVIEW,
- /* token = */ null, mCallbackExecutor, mStreamCallback)
- ).isEqualTo(CarEvsManager.ERROR_NONE);
- mActivityRequested.countDown();
+ mServiceInRequestedState.release();
break;
case CarEvsManager.SERVICE_STATE_ACTIVE:
- // Nothing to do
+ mServiceInActiveState.release();
break;
case CarEvsManager.SERVICE_STATE_UNAVAILABLE:
diff --git a/tests/carservice_test/src/com/android/car/CarPropertyManagerTest.java b/tests/carservice_test/src/com/android/car/CarPropertyManagerTest.java
index 56e0118..5cd4c62 100644
--- a/tests/carservice_test/src/com/android/car/CarPropertyManagerTest.java
+++ b/tests/carservice_test/src/com/android/car/CarPropertyManagerTest.java
@@ -17,12 +17,14 @@
package com.android.car;
import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
import static org.junit.Assert.fail;
import static org.testng.Assert.assertThrows;
import android.car.Car;
import android.car.VehicleAreaType;
+import android.car.VehicleAreaWheel;
import android.car.VehiclePropertyIds;
import android.car.hardware.CarPropertyConfig;
import android.car.hardware.CarPropertyValue;
@@ -59,6 +61,7 @@
import org.junit.rules.TestName;
import org.junit.runner.RunWith;
+import java.time.Duration;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
@@ -243,6 +246,7 @@
case SUPPORT_CUSTOM_PERMISSION:
case PROP_WITH_READ_ONLY_PERMISSION:
case PROP_WITH_WRITE_ONLY_PERMISSION:
+ case VehiclePropertyIds.TIRE_PRESSURE:
break;
default:
Assert.fail("Unexpected CarPropertyConfig: " + cfg.toString());
@@ -816,6 +820,94 @@
mManager.setIntProperty(prop, /* areaId= */ 0, /* val= */ 0));
}
+ @Test
+ public void registerCallback_handlesContinuousPropertyUpdateRate() {
+ float wheelLeftFrontValue = 11.11f;
+ long wheelLeftFrontTimestampNanos = Duration.ofSeconds(1).toNanos();
+
+ float notNewEnoughWheelLeftFrontValue = 22.22f;
+ long notNewEnoughWheelLeftFrontTimestampNanos = Duration.ofMillis(1999).toNanos();
+
+ float newEnoughWheelLeftFrontValue = 33.33f;
+ long newEnoughWheelLeftFrontTimestampNanos = Duration.ofSeconds(2).toNanos();
+
+ TestCallback testCallback = new TestCallback(2);
+ assertThat(mManager.registerCallback(testCallback, VehiclePropertyIds.TIRE_PRESSURE,
+ 1f)).isTrue();
+
+ getAidlMockedVehicleHal().injectEvent(
+ newTirePressureVehiclePropValue(VehicleAreaWheel.WHEEL_LEFT_FRONT,
+ wheelLeftFrontValue, wheelLeftFrontTimestampNanos));
+ getAidlMockedVehicleHal().injectEvent(
+ newTirePressureVehiclePropValue(VehicleAreaWheel.WHEEL_LEFT_FRONT,
+ notNewEnoughWheelLeftFrontValue, notNewEnoughWheelLeftFrontTimestampNanos));
+ getAidlMockedVehicleHal().injectEvent(
+ newTirePressureVehiclePropValue(VehicleAreaWheel.WHEEL_LEFT_FRONT,
+ newEnoughWheelLeftFrontValue, newEnoughWheelLeftFrontTimestampNanos));
+
+ List<CarPropertyValue<?>> carPropertyValues = testCallback.getCarPropertyValues();
+ assertThat(carPropertyValues).hasSize(2);
+
+ assertTirePressureCarPropertyValue(carPropertyValues.get(0),
+ VehicleAreaWheel.WHEEL_LEFT_FRONT, wheelLeftFrontValue,
+ wheelLeftFrontTimestampNanos);
+
+ assertTirePressureCarPropertyValue(carPropertyValues.get(1),
+ VehicleAreaWheel.WHEEL_LEFT_FRONT, newEnoughWheelLeftFrontValue,
+ newEnoughWheelLeftFrontTimestampNanos);
+ }
+
+ @Test
+ public void registerCallback_handlesOutOfTimeOrderEventsWithDifferentAreaIds() {
+ float wheelLeftFrontValue = 11.11f;
+ long wheelLeftFrontTimestampNanos = Duration.ofSeconds(4).toNanos();
+
+ float wheelRightFrontValue = 22.22f;
+ long wheelRightFrontTimestampNanos = Duration.ofSeconds(3).toNanos();
+
+ float wheelLeftRearValue = 33.33f;
+ long wheelLeftRearTimestampNanos = Duration.ofSeconds(2).toNanos();
+
+ float wheelRightRearValue = 44.44f;
+ long wheelRightRearTimestampNanos = Duration.ofSeconds(1).toNanos();
+
+ TestCallback testCallback = new TestCallback(4);
+ assertThat(mManager.registerCallback(testCallback, VehiclePropertyIds.TIRE_PRESSURE,
+ 1f)).isTrue();
+
+ // inject events in time order from newest to oldest
+ getAidlMockedVehicleHal().injectEvent(
+ newTirePressureVehiclePropValue(VehicleAreaWheel.WHEEL_LEFT_FRONT,
+ wheelLeftFrontValue, wheelLeftFrontTimestampNanos));
+ getAidlMockedVehicleHal().injectEvent(
+ newTirePressureVehiclePropValue(VehicleAreaWheel.WHEEL_RIGHT_FRONT,
+ wheelRightFrontValue, wheelRightFrontTimestampNanos));
+ getAidlMockedVehicleHal().injectEvent(
+ newTirePressureVehiclePropValue(VehicleAreaWheel.WHEEL_LEFT_REAR,
+ wheelLeftRearValue, wheelLeftRearTimestampNanos));
+ getAidlMockedVehicleHal().injectEvent(
+ newTirePressureVehiclePropValue(VehicleAreaWheel.WHEEL_RIGHT_REAR,
+ wheelRightRearValue, wheelRightRearTimestampNanos));
+
+ List<CarPropertyValue<?>> carPropertyValues = testCallback.getCarPropertyValues();
+ assertThat(carPropertyValues).hasSize(4);
+
+ assertTirePressureCarPropertyValue(carPropertyValues.get(0),
+ VehicleAreaWheel.WHEEL_LEFT_FRONT, wheelLeftFrontValue,
+ wheelLeftFrontTimestampNanos);
+
+ assertTirePressureCarPropertyValue(carPropertyValues.get(1),
+ VehicleAreaWheel.WHEEL_RIGHT_FRONT, wheelRightFrontValue,
+ wheelRightFrontTimestampNanos);
+
+ assertTirePressureCarPropertyValue(carPropertyValues.get(2),
+ VehicleAreaWheel.WHEEL_LEFT_REAR, wheelLeftRearValue, wheelLeftRearTimestampNanos);
+
+ assertTirePressureCarPropertyValue(carPropertyValues.get(3),
+ VehicleAreaWheel.WHEEL_RIGHT_REAR, wheelRightRearValue,
+ wheelRightRearTimestampNanos);
+ }
+
private void userHalPropertiesTest(String method, Visitor<Integer> visitor) {
List<String> failedProperties = new ArrayList<String>();
for (int propertyId : USER_HAL_PROPERTIES) {
@@ -844,6 +936,13 @@
addAidlProperty(INT_PROP_STATUS_UNAVAILABLE, handler);
addAidlProperty(FLOAT_PROP_STATUS_UNAVAILABLE, handler);
addAidlProperty(BOOLEAN_PROP_STATUS_ERROR, handler);
+ addAidlProperty(VehiclePropertyIds.TIRE_PRESSURE, handler).addAreaConfig(
+ VehicleAreaWheel.WHEEL_LEFT_REAR).addAreaConfig(
+ VehicleAreaWheel.WHEEL_RIGHT_REAR).addAreaConfig(
+ VehicleAreaWheel.WHEEL_RIGHT_FRONT).addAreaConfig(
+ VehicleAreaWheel.WHEEL_LEFT_FRONT).setChangeMode(
+ CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_CONTINUOUS).setMaxSampleRate(
+ 10).setMinSampleRate(1);
VehiclePropValue tempValue = new VehiclePropValue();
tempValue.value = new RawPropValues();
@@ -959,6 +1058,26 @@
}
}
+ private static VehiclePropValue newTirePressureVehiclePropValue(int areaId, float floatValue,
+ long timestampNanos) {
+ VehiclePropValue vehiclePropValue = new VehiclePropValue();
+ vehiclePropValue.prop = VehiclePropertyIds.TIRE_PRESSURE;
+ vehiclePropValue.areaId = areaId;
+ vehiclePropValue.value = new RawPropValues();
+ vehiclePropValue.value.floatValues = new float[]{floatValue};
+ vehiclePropValue.timestamp = timestampNanos;
+ return vehiclePropValue;
+ }
+
+ private static void assertTirePressureCarPropertyValue(CarPropertyValue<?> carPropertyValue,
+ int areaId, float floatValue, long timestampNanos) {
+ assertThat(carPropertyValue.getPropertyId()).isEqualTo(VehiclePropertyIds.TIRE_PRESSURE);
+ assertThat(carPropertyValue.getAreaId()).isEqualTo(areaId);
+ assertThat(carPropertyValue.getStatus()).isEqualTo(CarPropertyValue.STATUS_AVAILABLE);
+ assertThat(carPropertyValue.getTimestamp()).isEqualTo(timestampNanos);
+ assertThat(carPropertyValue.getValue()).isEqualTo(floatValue);
+ }
+
private static class TestErrorCallback implements CarPropertyManager.CarPropertyEventCallback {
private static final String CALLBACK_TAG = "ErrorEventTest";
@@ -1011,6 +1130,43 @@
}
}
+ private static class TestCallback implements CarPropertyManager.CarPropertyEventCallback {
+ private final List<CarPropertyValue<?>> mCarPropertyValues = new ArrayList<>();
+ private final int mNumberOfExpectedCarPropertyValues;
+ private final CountDownLatch mCountDownLatch;
+
+ TestCallback(int numberOfExpectedCarPropertyValues) {
+ mNumberOfExpectedCarPropertyValues = numberOfExpectedCarPropertyValues;
+ mCountDownLatch = new CountDownLatch(numberOfExpectedCarPropertyValues);
+ }
+
+ @Override
+ public void onChangeEvent(CarPropertyValue carPropertyValue) {
+ mCarPropertyValues.add(carPropertyValue);
+ mCountDownLatch.countDown();
+ }
+
+ @Override
+ public void onErrorEvent(int propertyId, int areaId) {
+ Log.e(TAG, "TestCallback onErrorEvent - property ID: " + propertyId + " areaId: "
+ + areaId);
+ }
+
+ public List<CarPropertyValue<?>> getCarPropertyValues() {
+ try {
+ assertWithMessage("Expected " + mNumberOfExpectedCarPropertyValues
+ + " CarPropertyValues before timeout, but only received: "
+ + mCarPropertyValues.size()).that(
+ mCountDownLatch.await(CALLBACK_SHORT_TIMEOUT_MS,
+ TimeUnit.MILLISECONDS)).isTrue();
+
+ } catch (InterruptedException e) {
+ fail("TestCallback was interrupted: " + e);
+ }
+ return mCarPropertyValues;
+ }
+ }
+
private class TestSequenceCallback implements CarPropertyManager.CarPropertyEventCallback {
private ConcurrentHashMap<Integer, CarPropertyValue> mRecorder = new ConcurrentHashMap<>();
diff --git a/tests/carservice_test/src/com/android/car/MockedCarTestBase.java b/tests/carservice_test/src/com/android/car/MockedCarTestBase.java
index c429e8f..b14d078 100644
--- a/tests/carservice_test/src/com/android/car/MockedCarTestBase.java
+++ b/tests/carservice_test/src/com/android/car/MockedCarTestBase.java
@@ -102,11 +102,11 @@
private SystemInterface mFakeSystemInterface;
private MockedCarTestContext mMockedCarTestContext;
private CarTelemetryService mCarTelemetryService;
+ private CarWatchdogService mCarWatchdogService = mock(CarWatchdogService.class);
+ private CarPerformanceService mCarPerformanceService;
private final CarUserService mCarUserService = mock(CarUserService.class);
private final MockIOInterface mMockIOInterface = new MockIOInterface();
- private final CarWatchdogService mCarWatchdogService = mock(CarWatchdogService.class);
- private final CarPerformanceService mCarPerformanceService = mock(CarPerformanceService.class);
private final GarageModeService mGarageModeService = mock(GarageModeService.class);
private final FakeCarPowerPolicyDaemon mPowerPolicyDaemon = new FakeCarPowerPolicyDaemon();
@@ -172,6 +172,23 @@
}
/**
+ * Set the CarWatchDogService to be used during the test.
+ */
+ protected void setCarWatchDogService(CarWatchdogService service) {
+ mCarWatchdogService = service;
+ }
+
+ /**
+ * Set the CarPerformanceService to be used during the test.
+ *
+ * Must be called during {@link configureMockedHal}. If not called, the real service would be
+ * used.
+ */
+ protected void setCarPerformanceService(CarPerformanceService service) {
+ mCarPerformanceService = service;
+ }
+
+ /**
* Called after {@code ICarImpl} is created and before {@code ICarImpl.init()} is called.
*
* <p> Subclass that intend to apply spyOn() to the service under testing should override this.
diff --git a/tests/carservice_test/src/com/android/car/audio/CarAudioZoneTest.java b/tests/carservice_test/src/com/android/car/audio/CarAudioZoneTest.java
index 5d270d3..fb86448 100644
--- a/tests/carservice_test/src/com/android/car/audio/CarAudioZoneTest.java
+++ b/tests/carservice_test/src/com/android/car/audio/CarAudioZoneTest.java
@@ -31,12 +31,18 @@
import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import static org.testng.Assert.assertThrows;
import static org.testng.Assert.expectThrows;
import android.car.media.CarAudioManager;
+import android.hardware.automotive.audiocontrol.AudioGainConfigInfo;
+import android.hardware.automotive.audiocontrol.Reasons;
import android.media.AudioAttributes;
import android.media.AudioDeviceInfo;
import android.media.AudioPlaybackConfiguration;
@@ -302,6 +308,63 @@
assertThat(mTestAudioZone.isAudioDeviceInfoValidForZone(nullAddressDeviceInfo)).isTrue();
}
+ @Test
+ public void onAudioGainChanged_withDeviceAddressesInZone() {
+ mTestAudioZone.addVolumeGroup(mMockMusicGroup);
+ mTestAudioZone.addVolumeGroup(mMockNavGroup);
+
+ List<Integer> reasons = List.of(Reasons.REMOTE_MUTE, Reasons.NAV_DUCKING);
+
+ AudioGainConfigInfo musicGainInfo = new AudioGainConfigInfo();
+ musicGainInfo.zoneId = CarAudioManager.PRIMARY_AUDIO_ZONE;
+ musicGainInfo.devicePortAddress = MUSIC_ADDRESS;
+ musicGainInfo.volumeIndex = 666;
+ CarAudioGainConfigInfo carMusicGainInfo = new CarAudioGainConfigInfo(musicGainInfo);
+ AudioGainConfigInfo navGainInfo = new AudioGainConfigInfo();
+ navGainInfo.zoneId = CarAudioManager.PRIMARY_AUDIO_ZONE;
+ navGainInfo.devicePortAddress = NAV_ADDRESS;
+ navGainInfo.volumeIndex = 999;
+ CarAudioGainConfigInfo carNavGainInfo = new CarAudioGainConfigInfo(navGainInfo);
+
+ List<CarAudioGainConfigInfo> carGains = List.of(carMusicGainInfo, carNavGainInfo);
+
+ mTestAudioZone.onAudioGainChanged(reasons, carGains);
+
+ verify(mMockMusicGroup).onAudioGainChanged(eq(reasons), eq(carMusicGainInfo));
+ verify(mMockNavGroup).onAudioGainChanged(eq(reasons), eq(carNavGainInfo));
+ verify(mMockVoiceGroup, never()).onAudioGainChanged(any(), any());
+ }
+
+ @Test
+ public void onAudioGainChanged_withoutAnyDeviceAddressInZone() {
+ List<Integer> reasons = List.of(Reasons.REMOTE_MUTE, Reasons.NAV_DUCKING);
+
+ AudioGainConfigInfo musicGainInfo = new AudioGainConfigInfo();
+ musicGainInfo.zoneId = CarAudioManager.PRIMARY_AUDIO_ZONE;
+ musicGainInfo.devicePortAddress = MUSIC_ADDRESS;
+ musicGainInfo.volumeIndex = 666;
+ CarAudioGainConfigInfo carMusicGainInfo = new CarAudioGainConfigInfo(musicGainInfo);
+ AudioGainConfigInfo navGainInfo = new AudioGainConfigInfo();
+ navGainInfo.zoneId = CarAudioManager.PRIMARY_AUDIO_ZONE;
+ navGainInfo.devicePortAddress = NAV_ADDRESS;
+ navGainInfo.volumeIndex = 999;
+ CarAudioGainConfigInfo carNavGainInfo = new CarAudioGainConfigInfo(navGainInfo);
+ AudioGainConfigInfo voiceGainInfo = new AudioGainConfigInfo();
+ voiceGainInfo.zoneId = CarAudioManager.PRIMARY_AUDIO_ZONE;
+ voiceGainInfo.devicePortAddress = VOICE_ADDRESS;
+ voiceGainInfo.volumeIndex = 777;
+ CarAudioGainConfigInfo carVoiceGainInfo = new CarAudioGainConfigInfo(voiceGainInfo);
+
+ List<CarAudioGainConfigInfo> carGains =
+ List.of(carMusicGainInfo, carNavGainInfo, carVoiceGainInfo);
+
+ mTestAudioZone.onAudioGainChanged(reasons, carGains);
+
+ verify(mMockMusicGroup, never()).onAudioGainChanged(any(), any());
+ verify(mMockNavGroup, never()).onAudioGainChanged(any(), any());
+ verify(mMockVoiceGroup, never()).onAudioGainChanged(any(), any());
+ }
+
private static class VolumeGroupBuilder {
private SparseArray<String> mDeviceAddresses = new SparseArray<>();
diff --git a/tests/carservice_test/src/com/android/car/audio/OWNERS b/tests/carservice_test/src/com/android/car/audio/OWNERS
deleted file mode 100644
index a1eb6f7..0000000
--- a/tests/carservice_test/src/com/android/car/audio/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-# Audio owners
-oscarazu@google.com
\ No newline at end of file
diff --git a/tests/carservice_test/src/com/android/car/input/OWNERS b/tests/carservice_test/src/com/android/car/input/OWNERS
deleted file mode 100644
index 25c90b7..0000000
--- a/tests/carservice_test/src/com/android/car/input/OWNERS
+++ /dev/null
@@ -1,3 +0,0 @@
-# Car input owners
-kanant@google.com
-ycheo@google.com
diff --git a/tests/carservice_test/src/com/android/car/os/CarPerformanceManagerTest.java b/tests/carservice_test/src/com/android/car/os/CarPerformanceManagerTest.java
new file mode 100644
index 0000000..8e4fbda
--- /dev/null
+++ b/tests/carservice_test/src/com/android/car/os/CarPerformanceManagerTest.java
@@ -0,0 +1,224 @@
+/*
+ * Copyright (C) 2022 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.os;
+
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
+
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+import static org.testng.Assert.expectThrows;
+
+import android.car.Car;
+import android.car.os.CarPerformanceManager;
+import android.car.os.CarPerformanceManager.SetSchedulerFailedException;
+import android.car.os.ThreadPolicyWithPriority;
+import android.car.watchdoglib.CarWatchdogDaemonHelper;
+import android.content.Context;
+import android.os.RemoteException;
+import android.os.ServiceSpecificException;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
+
+import com.android.car.MockedCarTestBase;
+import com.android.car.watchdog.CarWatchdogService;
+import com.android.car.watchdog.TimeSource;
+import com.android.car.watchdog.WatchdogStorage;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+
+import java.time.Instant;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class CarPerformanceManagerTest extends MockedCarTestBase {
+ private CarPerformanceManager mCarPerformanceManager;
+ private CarWatchdogService mCarWatchdogService;
+ @Mock private CarWatchdogDaemonHelper mCarWatchdogDaemonHelper;
+ @Mock private Context mMockBuiltinPackageContext;
+ @Mock private WatchdogStorage mMockWatchdogStorage;
+ private final TestTimeSource mTimeSource = new TestTimeSource();
+
+ private static final class TestTimeSource extends TimeSource {
+ private static final Instant TEST_DATE_TIME = Instant.parse("2021-11-12T13:14:15.16Z");
+ private Instant mNow;
+ TestTimeSource() {
+ mNow = TEST_DATE_TIME;
+ }
+
+ @Override
+ public Instant now() {
+ /* Return the same time, so the tests are deterministic. */
+ return mNow;
+ }
+
+ @Override
+ public String toString() {
+ return "Mocked date to " + now();
+ }
+ }
+
+ @Override
+ public void configureMockedHal() {
+ mCarWatchdogService = new CarWatchdogService(
+ getContext(), mMockBuiltinPackageContext, mMockWatchdogStorage, mTimeSource);
+ mCarWatchdogService.setCarWatchdogDaemonHelper(mCarWatchdogDaemonHelper);
+ setCarWatchDogService(mCarWatchdogService);
+ }
+
+ @Override
+ public void setUp() throws Exception {
+ super.setUp();
+ mCarPerformanceManager = (CarPerformanceManager) getCar().getCarManager(
+ Car.CAR_PERFORMANCE_SERVICE);
+ assertThat(mCarPerformanceManager).isNotNull();
+ }
+
+ @Test
+ public void testSetThreadPriority() throws Exception {
+ ThreadPolicyWithPriority p = new ThreadPolicyWithPriority(
+ ThreadPolicyWithPriority.SCHED_FIFO, /* priority= */ 1);
+ mCarPerformanceManager.setThreadPriority(p);
+
+ verify(mCarWatchdogDaemonHelper).setThreadPriority(anyInt(), anyInt(), anyInt(),
+ eq(ThreadPolicyWithPriority.SCHED_FIFO), eq(1));
+ }
+
+ @Test
+ public void testSetThreadPriorityIllegalArgumentException() throws Exception {
+ doThrow(new IllegalArgumentException("test")).when(mCarWatchdogDaemonHelper)
+ .setThreadPriority(anyInt(), anyInt(), anyInt(), anyInt(), anyInt());
+ ThreadPolicyWithPriority p = new ThreadPolicyWithPriority(
+ ThreadPolicyWithPriority.SCHED_FIFO, /* priority= */ 1);
+
+ IllegalArgumentException thrown = expectThrows(IllegalArgumentException.class,
+ () -> mCarPerformanceManager.setThreadPriority(p));
+
+ assertWithMessage("exception on illegal set thread priority argument").that(thrown)
+ .hasMessageThat().contains("test");
+ }
+
+ @Test
+ public void testSetThreadPriorityIllegalStateException() throws Exception {
+ doThrow(new IllegalStateException("test")).when(mCarWatchdogDaemonHelper).setThreadPriority(
+ anyInt(), anyInt(), anyInt(), anyInt(), anyInt());
+ ThreadPolicyWithPriority p = new ThreadPolicyWithPriority(
+ ThreadPolicyWithPriority.SCHED_FIFO, /* priority= */ 1);
+
+ IllegalStateException thrown = expectThrows(IllegalStateException.class,
+ () -> mCarPerformanceManager.setThreadPriority(p));
+
+ assertWithMessage("exception on illegal state exception").that(thrown).hasMessageThat()
+ .contains("test");
+ }
+
+ @Test
+ public void testSetThreadPriorityRemoteException() throws Exception {
+ doThrow(new RemoteException("test")).when(mCarWatchdogDaemonHelper).setThreadPriority(
+ anyInt(), anyInt(), anyInt(), anyInt(), anyInt());
+ ThreadPolicyWithPriority p = new ThreadPolicyWithPriority(
+ ThreadPolicyWithPriority.SCHED_FIFO, /* priority= */ 1);
+
+ // Nothing must be thrown. Remote exception is just logged.
+ mCarPerformanceManager.setThreadPriority(p);
+ }
+
+ @Test
+ public void testSetThreadPriorityServiceSpecificException() throws Exception {
+ doThrow(new ServiceSpecificException(0)).when(mCarWatchdogDaemonHelper).setThreadPriority(
+ anyInt(), anyInt(), anyInt(), anyInt(), anyInt());
+ ThreadPolicyWithPriority p = new ThreadPolicyWithPriority(
+ ThreadPolicyWithPriority.SCHED_FIFO, /* priority= */ 1);
+
+ expectThrows(SetSchedulerFailedException.class,
+ () -> mCarPerformanceManager.setThreadPriority(p));
+ }
+
+ @Test
+ public void testGetThreadPriority() throws Exception {
+ int[] p = new int[]{ThreadPolicyWithPriority.SCHED_FIFO, 1};
+ when(mCarWatchdogDaemonHelper.getThreadPriority(
+ anyInt(), anyInt(), anyInt())).thenReturn(p);
+
+ ThreadPolicyWithPriority result = mCarPerformanceManager.getThreadPriority();
+
+ assertThat(result.getPolicy()).isEqualTo(ThreadPolicyWithPriority.SCHED_FIFO);
+ assertThat(result.getPriority()).isEqualTo(1);
+ }
+
+ @Test
+ public void testGetThreadPriorityDefaultPolicy() throws Exception {
+ int[] p = new int[]{ThreadPolicyWithPriority.SCHED_DEFAULT, 0};
+ when(mCarWatchdogDaemonHelper.getThreadPriority(
+ anyInt(), anyInt(), anyInt())).thenReturn(p);
+
+ ThreadPolicyWithPriority result = mCarPerformanceManager.getThreadPriority();
+
+ assertThat(result.getPolicy()).isEqualTo(ThreadPolicyWithPriority.SCHED_DEFAULT);
+ assertThat(result.getPriority()).isEqualTo(0);
+ }
+
+ @Test
+ public void testGetThreadPriorityInvalidPolicy() throws Exception {
+ int[] p = new int[]{-1, 1};
+ when(mCarWatchdogDaemonHelper.getThreadPriority(
+ anyInt(), anyInt(), anyInt())).thenReturn(p);
+
+ expectThrows(IllegalStateException.class, () -> mCarPerformanceManager.getThreadPriority());
+ }
+
+ @Test
+ public void testGetThreadPriorityInvalidPriority() throws Exception {
+ int[] p = new int[]{ThreadPolicyWithPriority.SCHED_FIFO, 0};
+ when(mCarWatchdogDaemonHelper.getThreadPriority(
+ anyInt(), anyInt(), anyInt())).thenReturn(p);
+
+ expectThrows(IllegalStateException.class, () -> mCarPerformanceManager.getThreadPriority());
+ }
+
+ @Test
+ public void testGetThreadPriorityRemoteException() throws Exception {
+ when(mCarWatchdogDaemonHelper.getThreadPriority(anyInt(), anyInt(), anyInt())).thenThrow(
+ new RemoteException(""));
+
+ ThreadPolicyWithPriority result = mCarPerformanceManager.getThreadPriority();
+
+ assertThat(result.getPolicy()).isEqualTo(ThreadPolicyWithPriority.SCHED_DEFAULT);
+ assertThat(result.getPriority()).isEqualTo(0);
+ }
+
+ @Test
+ public void testGetThreadPriorityIllegalStateException() throws Exception {
+ when(mCarWatchdogDaemonHelper.getThreadPriority(anyInt(), anyInt(), anyInt())).thenThrow(
+ new IllegalStateException(""));
+
+ expectThrows(IllegalStateException.class, () -> mCarPerformanceManager.getThreadPriority());
+ }
+
+ @Test
+ public void testGetThreadPriorityServiceSpecificException() throws Exception {
+ when(mCarWatchdogDaemonHelper.getThreadPriority(anyInt(), anyInt(), anyInt())).thenThrow(
+ new ServiceSpecificException(0));
+
+ expectThrows(IllegalStateException.class, () -> mCarPerformanceManager.getThreadPriority());
+ }
+}
diff --git a/tests/carservice_test/src/com/android/car/power/CarPowerManagementTest.java b/tests/carservice_test/src/com/android/car/power/CarPowerManagementTest.java
index 0330976..7683ae1 100644
--- a/tests/carservice_test/src/com/android/car/power/CarPowerManagementTest.java
+++ b/tests/carservice_test/src/com/android/car/power/CarPowerManagementTest.java
@@ -15,6 +15,8 @@
*/
package com.android.car.power;
+import static com.google.common.truth.Truth.assertThat;
+
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;
@@ -36,6 +38,8 @@
import android.hardware.automotive.vehicle.VehicleProperty;
import android.hardware.automotive.vehicle.VehiclePropertyAccess;
import android.hardware.automotive.vehicle.VehiclePropertyChangeMode;
+import android.os.Handler;
+import android.os.Looper;
import android.os.ServiceSpecificException;
import android.os.SystemClock;
@@ -63,6 +67,7 @@
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
@RunWith(AndroidJUnit4.class)
@MediumTest
@@ -182,6 +187,22 @@
VehicleApPowerStateReport.SHUTDOWN_START);
}
+ @Test
+ public void testDeepSleepEntryAfterGarageMode() throws Exception {
+ assertWaitForVhal();
+
+ registerListenerToFakeGarageMode();
+
+ // Put device into SHUTDOWN_PREPARE
+ mPowerStateHandler.sendStateAndCheckResponse(
+ VehicleApPowerStateReq.SHUTDOWN_PREPARE,
+ VehicleApPowerStateShutdownParam.CAN_SLEEP,
+ VehicleApPowerStateReport.SHUTDOWN_PREPARE);
+
+ mPowerStateHandler.waitForStateSetAndGetAll(DEFAULT_WAIT_TIMEOUT_MS,
+ VehicleApPowerStateReport.DEEP_SLEEP_ENTRY);
+ }
+
/**********************************************************************************************
* Test cancelling of shutdown.
**********************************************************************************************/
@@ -407,6 +428,222 @@
cpms.removePowerPolicyListener(powerPolicyListener);
}
+ @Test
+ public void testShutdownPostponeDuringHibernationEnter() throws Exception {
+ testShutdownPostponeWhileListenerPendingInState(CarPowerManager.STATE_HIBERNATION_ENTER,
+ VehicleApPowerStateShutdownParam.CAN_HIBERNATE,
+ VehicleApPowerStateReport.HIBERNATION_ENTRY);
+ }
+
+ @Test
+ public void testShutdownPostponeDuringShutdownEnter() throws Exception {
+ testShutdownPostponeWhileListenerPendingInState(CarPowerManager.STATE_SHUTDOWN_ENTER,
+ VehicleApPowerStateShutdownParam.SHUTDOWN_ONLY,
+ VehicleApPowerStateReport.SHUTDOWN_START);
+ }
+
+ @Test
+ public void testShutdownPostponeDuringSuspendEnter() throws Exception {
+ testShutdownPostponeWhileListenerPendingInState(CarPowerManager.STATE_SUSPEND_ENTER,
+ VehicleApPowerStateShutdownParam.CAN_SLEEP,
+ VehicleApPowerStateReport.DEEP_SLEEP_ENTRY);
+ }
+
+ @Test
+ public void testShutdownPostponeDuringPreShutdownPrepare() throws Exception {
+ testShutdownPostponeWhileListenerPendingInState(CarPowerManager.STATE_PRE_SHUTDOWN_PREPARE,
+ VehicleApPowerStateShutdownParam.CAN_SLEEP,
+ VehicleApPowerStateReport.DEEP_SLEEP_ENTRY);
+ }
+
+ @Test
+ public void testShutdownPostponeDuringPreShutdownPrepareWithImmediately() throws Exception {
+ testShutdownPostponeWhileListenerPendingInState(CarPowerManager.STATE_PRE_SHUTDOWN_PREPARE,
+ VehicleApPowerStateShutdownParam.SHUTDOWN_IMMEDIATELY,
+ VehicleApPowerStateReport.SHUTDOWN_START);
+ }
+
+ @Test
+ public void testSleepShutdownFromPreShutdownPrepare() throws Exception {
+ assertWaitForVhal();
+
+ registerListenerToFakeGarageMode();
+
+ AtomicBoolean errorOccurred = new AtomicBoolean(false);
+
+ // Semaphore to signal receive of PRE_SHUTDOWN_PREPARE
+ Semaphore eventWaitSemaphore = new Semaphore(0);
+ // Semaphore to signal completion of PRE_SHUTDOWN_PREPARE
+ Semaphore completionSemaphore = new Semaphore(0);
+
+ CarPowerManagementService cpms =
+ (CarPowerManagementService) getCarService(Car.POWER_SERVICE);
+ ICarPowerStateListener listener = new ICarPowerStateListener.Stub() {
+ @Override
+ public void onStateChanged(int state, long expirationTimeMs) {
+ if (!CarPowerManagementService.isCompletionAllowed(state)) {
+ return;
+ }
+
+ Handler handler = new Handler(Looper.getMainLooper());
+ ICarPowerStateListener cpmsListener = this;
+ Runnable completionRunnable = () -> cpms.completeHandlingPowerStateChange(state,
+ cpmsListener);
+
+ if (state == CarPowerManager.STATE_PRE_SHUTDOWN_PREPARE) {
+ new Thread(() -> {
+ try {
+ eventWaitSemaphore.release();
+ if (completionSemaphore.tryAcquire(DEFAULT_WAIT_TIMEOUT_MS,
+ TimeUnit.MILLISECONDS)) {
+ handler.post(completionRunnable);
+ } else {
+ errorOccurred.set(true);
+ }
+ } catch (InterruptedException e) {
+ errorOccurred.set(true);
+ }
+ completionSemaphore.drainPermits();
+ }).start();
+ } else {
+ cpms.completeHandlingPowerStateChange(state, this);
+ }
+ }
+ };
+ cpms.registerInternalListener(listener);
+
+ mPowerStateHandler.sendPowerState(
+ VehicleApPowerStateReq.SHUTDOWN_PREPARE,
+ VehicleApPowerStateShutdownParam.CAN_SLEEP);
+
+ assertThat(eventWaitSemaphore.tryAcquire(DEFAULT_WAIT_TIMEOUT_MS,
+ TimeUnit.MILLISECONDS)).isTrue();
+
+ mPowerStateHandler.sendPowerState(
+ VehicleApPowerStateReq.SHUTDOWN_PREPARE,
+ VehicleApPowerStateShutdownParam.SHUTDOWN_IMMEDIATELY);
+
+ completionSemaphore.release();
+
+ mPowerStateHandler.waitForStateSetAndGetAll(DEFAULT_WAIT_TIMEOUT_MS,
+ VehicleApPowerStateReport.SHUTDOWN_START);
+ assertThat(errorOccurred.get()).isFalse();
+ }
+
+ @Test
+ public void testShutdownImmediatelyFromPreShutdownPrepare() throws Exception {
+ assertWaitForVhal();
+
+ registerListenerToFakeGarageMode();
+
+ AtomicBoolean errorOccurred = new AtomicBoolean(false);
+
+ // Semaphore to signal receive of PRE_SHUTDOWN_PREPARE
+ Semaphore eventWaitSemaphore = new Semaphore(0);
+ // Semaphore to signal completion of PRE_SHUTDOWN_PREPARE
+ Semaphore completionSemaphore = new Semaphore(0);
+
+ CarPowerManagementService cpms =
+ (CarPowerManagementService) getCarService(Car.POWER_SERVICE);
+ ICarPowerStateListener listener = new ICarPowerStateListener.Stub() {
+ @Override
+ public void onStateChanged(int state, long expirationTimeMs) {
+ if (!CarPowerManagementService.isCompletionAllowed(state)) {
+ return;
+ }
+
+ ICarPowerStateListener cpmsListener = this;
+
+ if (state == CarPowerManager.STATE_PRE_SHUTDOWN_PREPARE) {
+ new Thread(() -> {
+ try {
+ eventWaitSemaphore.release();
+ if (completionSemaphore.tryAcquire(DEFAULT_WAIT_TIMEOUT_MS,
+ TimeUnit.MILLISECONDS)) {
+ cpms.completeHandlingPowerStateChange(state, cpmsListener);
+ } else {
+ errorOccurred.set(true);
+ }
+ } catch (InterruptedException e) {
+ errorOccurred.set(true);
+ }
+ completionSemaphore.drainPermits();
+ }).start();
+ } else {
+ cpms.completeHandlingPowerStateChange(state, this);
+ }
+ }
+ };
+ cpms.registerInternalListener(listener);
+
+ mPowerStateHandler.sendPowerState(
+ VehicleApPowerStateReq.SHUTDOWN_PREPARE,
+ VehicleApPowerStateShutdownParam.CAN_SLEEP);
+
+ assertThat(eventWaitSemaphore.tryAcquire(DEFAULT_WAIT_TIMEOUT_MS,
+ TimeUnit.MILLISECONDS)).isTrue();
+
+ mPowerStateHandler.sendPowerState(
+ VehicleApPowerStateReq.SHUTDOWN_PREPARE,
+ VehicleApPowerStateShutdownParam.SHUTDOWN_IMMEDIATELY);
+
+ completionSemaphore.release();
+
+ mPowerStateHandler.waitForStateSetAndGetAll(DEFAULT_WAIT_TIMEOUT_MS,
+ VehicleApPowerStateReport.SHUTDOWN_START);
+ assertThat(errorOccurred.get()).isFalse();
+ }
+
+ private void testShutdownPostponeWhileListenerPendingInState(final int targetState,
+ int stateRequestParam, int finalPowerState) throws Exception {
+ assertWaitForVhal();
+
+ Semaphore notificationSem = new Semaphore(0);
+
+ AtomicBoolean errorOccurred = new AtomicBoolean(false);
+ CarPowerManagementService cpms =
+ (CarPowerManagementService) getCarService(Car.POWER_SERVICE);
+
+ ICarPowerStateListener listener = new ICarPowerStateListener.Stub() {
+ @Override
+ public void onStateChanged(int state, long expirationTimeMs) {
+ if (!CarPowerManagementService.isCompletionAllowed(state)) {
+ return;
+ }
+
+ ICarPowerStateListener cpmsListener = this;
+ if (state == targetState) {
+ new Thread(() -> {
+ try {
+ if (!notificationSem.tryAcquire(DEFAULT_WAIT_TIMEOUT_MS,
+ TimeUnit.MILLISECONDS)) {
+ errorOccurred.set(true);
+ }
+ cpms.completeHandlingPowerStateChange(state, cpmsListener);
+ } catch (InterruptedException e) {
+ errorOccurred.set(true);
+ }
+ }).start();
+ } else {
+ cpms.completeHandlingPowerStateChange(state, this);
+ }
+ }
+ };
+ cpms.registerInternalListener(listener);
+
+ //start shutown prepare
+ mPowerStateHandler.sendPowerState(VehicleApPowerStateReq.SHUTDOWN_PREPARE,
+ stateRequestParam);
+ // wait for SHUTDOWN_POSTPONE
+ mPowerStateHandler.waitForStateSetAndGetAll(DEFAULT_WAIT_TIMEOUT_MS,
+ VehicleApPowerStateReport.SHUTDOWN_POSTPONE);
+ // complete listener
+ notificationSem.release();
+
+ mPowerStateHandler.waitForStateSetAndGetAll(DEFAULT_WAIT_TIMEOUT_MS, finalPowerState);
+ assertThat(errorOccurred.get()).isFalse();
+ }
+
// Check that 'expectedState' was reached and is the current state.
private void assertResponse(int expectedState, int expectedParam, boolean checkParam)
throws Exception {
diff --git a/tests/carservice_test/src/com/android/car/telemetry/CarTelemetryManagerSpyServiceTest.java b/tests/carservice_test/src/com/android/car/telemetry/CarTelemetryManagerSpyServiceTest.java
new file mode 100644
index 0000000..3a5ab4a
--- /dev/null
+++ b/tests/carservice_test/src/com/android/car/telemetry/CarTelemetryManagerSpyServiceTest.java
@@ -0,0 +1,198 @@
+/*
+ * Copyright (C) 2022 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.telemetry;
+
+import static android.car.telemetry.CarTelemetryManager.STATUS_GET_METRICS_CONFIG_FINISHED;
+import static android.car.telemetry.CarTelemetryManager.STATUS_GET_METRICS_CONFIG_RUNTIME_ERROR;
+
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.junit.Assume.assumeTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.ArgumentMatchers.isNull;
+import static org.mockito.ArgumentMatchers.refEq;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+import android.car.Car;
+import android.car.telemetry.CarTelemetryManager;
+import android.car.telemetry.ICarTelemetryReportListener;
+import android.car.telemetry.TelemetryProto;
+import android.os.ParcelFileDescriptor;
+import android.os.PersistableBundle;
+
+import com.android.car.CarLocalServices;
+import com.android.car.ICarImpl;
+import com.android.car.MockedCarTestBase;
+
+import org.junit.Test;
+import org.mockito.Mock;
+
+import java.io.ByteArrayOutputStream;
+import java.io.DataOutputStream;
+import java.util.concurrent.Executor;
+
+/**
+ * Tests public entry points for CarTelemetryManager. This class spies on CarTelemetryService.
+ * This class is separate from CarTelemetryManagerTest because the spying on the service
+ * somehow prevents the real (un-mocked) methods from being called, which causes some tests to
+ * be flaky.
+ * Tests that use a real CarTelemetryService should be in CarTelemetryManagerTest.
+ * Tests that use a spied CarTelemetryService should be in CarTelemetryManagerSpyServiceTest.
+ */
+public class CarTelemetryManagerSpyServiceTest extends MockedCarTestBase {
+
+ private static final Executor DIRECT_EXECUTOR = Runnable::run;
+ private static final String CONFIG_NAME = "my_metrics_config";
+
+ private CarTelemetryManager mManager; // subject
+ private CarTelemetryService mService; // spy
+ private ParcelFileDescriptor[] mParcelFileDescriptors;
+
+ @Mock
+ private CarTelemetryManager.MetricsReportCallback mMockMetricsReportCallback;
+
+ @Override
+ public void setUp() throws Exception {
+ super.setUp();
+ assumeTrue(getCar().isFeatureEnabled(Car.CAR_TELEMETRY_SERVICE));
+
+ mManager = (CarTelemetryManager) getCar().getCarManager(
+ Car.CAR_TELEMETRY_SERVICE);
+
+ mParcelFileDescriptors = ParcelFileDescriptor.createPipe();
+ }
+
+ @Override
+ protected void spyOnBeforeCarImplInit(ICarImpl carImpl) {
+ mService = CarLocalServices.getService(CarTelemetryService.class);
+ assertThat(mService).isNotNull();
+ spyOn(mService);
+ }
+
+ @Override
+ public void tearDown() throws Exception {
+ super.tearDown();
+ mParcelFileDescriptors[0].close();
+ mParcelFileDescriptors[1].close();
+ }
+
+ @Override
+ protected CarTelemetryService createCarTelemetryService() {
+ // Forces the base class implementation to instantiate real instance of
+ // CarTelemetryService in ICarImpl.
+ return null;
+ }
+
+ @Test
+ public void testGetFinishedReport_multipleReports() throws Exception {
+ // set up the report and convert it to byte array
+ PersistableBundle report = new PersistableBundle();
+ report.putString("this is", "a test");
+ ByteArrayOutputStream bos = new ByteArrayOutputStream();
+ report.writeToStream(bos);
+ byte[] reportBytes = bos.toByteArray();
+ // set up service so that it streams 3 reports
+ doAnswer((invocation) -> {
+ DataOutputStream dos = new DataOutputStream(
+ new ParcelFileDescriptor.AutoCloseOutputStream(mParcelFileDescriptors[1]));
+ for (int i = 0; i < 3; i++) {
+ dos.writeInt(reportBytes.length);
+ dos.write(reportBytes);
+ }
+ dos.close();
+ ICarTelemetryReportListener listener = invocation.getArgument(/* index= */ 1);
+ listener.onResult(CONFIG_NAME, mParcelFileDescriptors[0], null,
+ STATUS_GET_METRICS_CONFIG_FINISHED);
+ return null;
+ }).when(mService).getFinishedReport(any(), any());
+
+ mManager.getFinishedReport(
+ CONFIG_NAME, DIRECT_EXECUTOR, mMockMetricsReportCallback);
+
+ verify(mMockMetricsReportCallback, times(3)).onResult(
+ eq(CONFIG_NAME),
+ refEq(report),
+ isNull(),
+ eq(STATUS_GET_METRICS_CONFIG_FINISHED));
+ }
+
+ @Test
+ public void testGetFinishedReport_validFdButNoReport() {
+ // set up service so that it streams 0 report
+ doAnswer((invocation) -> {
+ mParcelFileDescriptors[1].close();
+ ICarTelemetryReportListener listener = invocation.getArgument(/* index= */ 1);
+ listener.onResult(CONFIG_NAME, mParcelFileDescriptors[0], null,
+ STATUS_GET_METRICS_CONFIG_FINISHED);
+ return null;
+ }).when(mService).getFinishedReport(any(), any());
+
+ mManager.getFinishedReport(
+ CONFIG_NAME, DIRECT_EXECUTOR, mMockMetricsReportCallback);
+
+ verify(mMockMetricsReportCallback).onResult(
+ eq(CONFIG_NAME),
+ isNull(),
+ isNull(),
+ eq(STATUS_GET_METRICS_CONFIG_RUNTIME_ERROR));
+ }
+
+ @Test
+ public void testGetFinishedReport_telemetryError() {
+ byte[] errorBytes = TelemetryProto.TelemetryError.getDefaultInstance().toByteArray();
+ // setup service so that it calls back with telemetry error
+ doAnswer((invocation) -> {
+ ICarTelemetryReportListener listener = invocation.getArgument(/* index= */ 1);
+ listener.onResult(CONFIG_NAME, null, errorBytes,
+ STATUS_GET_METRICS_CONFIG_RUNTIME_ERROR);
+ return null;
+ }).when(mService).getFinishedReport(any(), any());
+
+ mManager.getFinishedReport(
+ CONFIG_NAME, DIRECT_EXECUTOR, mMockMetricsReportCallback);
+
+ verify(mMockMetricsReportCallback).onResult(
+ eq(CONFIG_NAME),
+ isNull(),
+ eq(errorBytes),
+ eq(STATUS_GET_METRICS_CONFIG_RUNTIME_ERROR));
+ }
+
+ @Test
+ public void testGetFinishedReport_badFd_shouldReturnRuntimeErrorStatus() throws Exception {
+ // close the read end of the pipe so CarTelemetryManager fails to read from it
+ mParcelFileDescriptors[0].close();
+ doAnswer((invocation) -> {
+ ICarTelemetryReportListener listener = invocation.getArgument(/* index= */ 1);
+ listener.onResult(CONFIG_NAME, mParcelFileDescriptors[0], null,
+ STATUS_GET_METRICS_CONFIG_FINISHED);
+ return null;
+ }).when(mService).getFinishedReport(any(), any());
+
+ mManager.getFinishedReport(
+ CONFIG_NAME, DIRECT_EXECUTOR, mMockMetricsReportCallback);
+
+ verify(mMockMetricsReportCallback, never()).onResult(any(), any(), any(), anyInt());
+ }
+}
diff --git a/tests/carservice_test/src/com/android/car/CarTelemetryManagerTest.java b/tests/carservice_test/src/com/android/car/telemetry/CarTelemetryManagerTest.java
similarity index 72%
rename from tests/carservice_test/src/com/android/car/CarTelemetryManagerTest.java
rename to tests/carservice_test/src/com/android/car/telemetry/CarTelemetryManagerTest.java
index f53e8ef..46f7d9f 100644
--- a/tests/carservice_test/src/com/android/car/CarTelemetryManagerTest.java
+++ b/tests/carservice_test/src/com/android/car/telemetry/CarTelemetryManagerTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2017 The Android Open Source Project
+ * Copyright (C) 2022 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.
@@ -14,17 +14,25 @@
* limitations under the License.
*/
-package com.android.car;
+package com.android.car.telemetry;
import static android.car.telemetry.CarTelemetryManager.STATUS_ADD_METRICS_CONFIG_ALREADY_EXISTS;
import static android.car.telemetry.CarTelemetryManager.STATUS_ADD_METRICS_CONFIG_PARSE_FAILED;
import static android.car.telemetry.CarTelemetryManager.STATUS_ADD_METRICS_CONFIG_SUCCEEDED;
import static android.car.telemetry.CarTelemetryManager.STATUS_ADD_METRICS_CONFIG_VERSION_TOO_OLD;
+import static android.car.telemetry.CarTelemetryManager.STATUS_GET_METRICS_CONFIG_DOES_NOT_EXIST;
import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.assertThrows;
import static org.junit.Assume.assumeTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.ArgumentMatchers.isNull;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
import android.annotation.NonNull;
import android.car.Car;
@@ -35,21 +43,28 @@
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.MediumTest;
-import com.android.car.telemetry.CarTelemetryService;
+import com.android.car.MockedCarTestBase;
import org.junit.Test;
import org.junit.runner.RunWith;
import java.util.Map;
import java.util.concurrent.Executor;
+import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;
-/** Test the public entry points for the CarTelemetryManager. */
+/**
+ * Tests the public entry points for the CarTelemetryManager. It uses a real instance of
+ * CarTelemetryService, however the service cannot find ScriptExecutor package so this class
+ * cannot test script execution and report retrieval.
+ * Tests that use a real CarTelemetryService should be in CarTelemetryManagerTest.
+ * Tests that use a spied CarTelemetryService should be in CarTelemetryManagerSpyServiceTest.
+ */
@RunWith(AndroidJUnit4.class)
@MediumTest
public class CarTelemetryManagerTest extends MockedCarTestBase {
private static final byte[] INVALID_METRICS_CONFIG = "bad config".getBytes();
- private static final Executor DIRECT_EXECUTOR = Runnable::run;
+ private static final Executor CALLBACK_EXECUTOR = Executors.newSingleThreadExecutor();
private static final String CONFIG_NAME = "my_metrics_config";
private static final TelemetryProto.MetricsConfig METRICS_CONFIG_V1 =
TelemetryProto.MetricsConfig.newBuilder()
@@ -81,36 +96,36 @@
@Test
public void testAddMetricsConfig() throws Exception {
// invalid config, should fail
- mCarTelemetryManager.addMetricsConfig(CONFIG_NAME, INVALID_METRICS_CONFIG, DIRECT_EXECUTOR,
- mAddMetricsConfigCallback);
+ mCarTelemetryManager.addMetricsConfig(CONFIG_NAME, INVALID_METRICS_CONFIG,
+ CALLBACK_EXECUTOR, mAddMetricsConfigCallback);
mAddMetricsConfigCallback.mSemaphore.acquire();
assertThat(mAddMetricsConfigCallback.mAddConfigStatusMap.get(CONFIG_NAME)).isEqualTo(
STATUS_ADD_METRICS_CONFIG_PARSE_FAILED);
// new valid config, should succeed
mCarTelemetryManager.addMetricsConfig(CONFIG_NAME, METRICS_CONFIG_V1.toByteArray(),
- DIRECT_EXECUTOR, mAddMetricsConfigCallback);
+ CALLBACK_EXECUTOR, mAddMetricsConfigCallback);
mAddMetricsConfigCallback.mSemaphore.acquire();
assertThat(mAddMetricsConfigCallback.mAddConfigStatusMap.get(CONFIG_NAME)).isEqualTo(
STATUS_ADD_METRICS_CONFIG_SUCCEEDED);
// duplicate config, should fail
mCarTelemetryManager.addMetricsConfig(CONFIG_NAME, METRICS_CONFIG_V1.toByteArray(),
- DIRECT_EXECUTOR, mAddMetricsConfigCallback);
+ CALLBACK_EXECUTOR, mAddMetricsConfigCallback);
mAddMetricsConfigCallback.mSemaphore.acquire();
assertThat(mAddMetricsConfigCallback.mAddConfigStatusMap.get(CONFIG_NAME)).isEqualTo(
STATUS_ADD_METRICS_CONFIG_ALREADY_EXISTS);
// newer version of the config should replace older version
mCarTelemetryManager.addMetricsConfig(CONFIG_NAME, METRICS_CONFIG_V2.toByteArray(),
- DIRECT_EXECUTOR, mAddMetricsConfigCallback);
+ CALLBACK_EXECUTOR, mAddMetricsConfigCallback);
mAddMetricsConfigCallback.mSemaphore.acquire();
assertThat(mAddMetricsConfigCallback.mAddConfigStatusMap.get(CONFIG_NAME)).isEqualTo(
STATUS_ADD_METRICS_CONFIG_SUCCEEDED);
// older version of the config should not be accepted
mCarTelemetryManager.addMetricsConfig(CONFIG_NAME, METRICS_CONFIG_V1.toByteArray(),
- DIRECT_EXECUTOR, mAddMetricsConfigCallback);
+ CALLBACK_EXECUTOR, mAddMetricsConfigCallback);
mAddMetricsConfigCallback.mSemaphore.acquire();
assertThat(mAddMetricsConfigCallback.mAddConfigStatusMap.get(CONFIG_NAME)).isEqualTo(
STATUS_ADD_METRICS_CONFIG_VERSION_TOO_OLD);
@@ -130,7 +145,7 @@
METRICS_CONFIG_V1.toBuilder().addSubscribers(badSubscriber).build();
mCarTelemetryManager.addMetricsConfig(
- CONFIG_NAME, config.toByteArray(), DIRECT_EXECUTOR, mAddMetricsConfigCallback);
+ CONFIG_NAME, config.toByteArray(), CALLBACK_EXECUTOR, mAddMetricsConfigCallback);
mAddMetricsConfigCallback.mSemaphore.acquire();
assertThat(mAddMetricsConfigCallback.mAddConfigStatusMap.get(CONFIG_NAME)).isEqualTo(
@@ -142,15 +157,35 @@
CarTelemetryManager.ReportReadyListener listener = metricsConfigName -> { };
// test clearReportReadyListener, should not error
- mCarTelemetryManager.setReportReadyListener(DIRECT_EXECUTOR, listener);
+ mCarTelemetryManager.setReportReadyListener(CALLBACK_EXECUTOR, listener);
// setListener multiple times should fail
assertThrows(IllegalStateException.class,
- () -> mCarTelemetryManager.setReportReadyListener(DIRECT_EXECUTOR, listener));
+ () -> mCarTelemetryManager.setReportReadyListener(CALLBACK_EXECUTOR, listener));
// test clearReportReadyListener, should not error
mCarTelemetryManager.clearReportReadyListener();
- mCarTelemetryManager.setReportReadyListener(DIRECT_EXECUTOR, listener);
+ mCarTelemetryManager.setReportReadyListener(CALLBACK_EXECUTOR, listener);
+ }
+
+ @Test
+ public void testGetFinishedReport_noSuchConfig() throws Exception {
+ Semaphore semaphore = new Semaphore(0);
+ CarTelemetryManager.MetricsReportCallback callback = mock(
+ CarTelemetryManager.MetricsReportCallback.class);
+ doAnswer((invocation) -> {
+ semaphore.release();
+ return null;
+ }).when(callback).onResult(any(), any(), any(), anyInt());
+
+ mCarTelemetryManager.getFinishedReport(CONFIG_NAME, CALLBACK_EXECUTOR, callback);
+
+ semaphore.acquire();
+ verify(callback).onResult(
+ eq(CONFIG_NAME),
+ isNull(),
+ isNull(),
+ eq(STATUS_GET_METRICS_CONFIG_DOES_NOT_EXIST));
}
private static final class AddMetricsConfigCallbackImpl
diff --git a/tests/carservice_test/src/com/android/car/watchdog/OWNERS b/tests/carservice_test/src/com/android/car/watchdog/OWNERS
new file mode 100644
index 0000000..bd4e0cc
--- /dev/null
+++ b/tests/carservice_test/src/com/android/car/watchdog/OWNERS
@@ -0,0 +1 @@
+lakshmana@google.com
diff --git a/tests/carservice_unit_test/Android.bp b/tests/carservice_unit_test/Android.bp
index 281092d..ea5e228 100644
--- a/tests/carservice_unit_test/Android.bp
+++ b/tests/carservice_unit_test/Android.bp
@@ -38,13 +38,24 @@
instrumentation_for: "CarService",
+ sdk_version: "core_platform",
+
libs: [
"android.car",
- "android.car.builtin",
+ "android.car.builtin.impl",
"android.car.watchdoglib",
"android.test.runner",
"android.test.base",
"android.test.mock",
+ // The following three lines are needed for tests that build against framework-bluetooth's
+ // @hide APIs. Order matters for the first two: classes in framework-bluetooth are
+ // resolved before framework, meaning @hide APIs in framework-bluetooth are resolved
+ // before @SystemApi stubs in framework. If sdk_version="", then the third line would get
+ // automatically included; since it isn't, it needs to be manually added here.
+ // (Ref: "framework-bluetooth-tests-defaults" in packages/modules/Bluetooth/framework/Android.bp)
+ "framework-bluetooth.impl",
+ "framework",
+ "framework-res",
],
static_libs: [
diff --git a/tests/carservice_unit_test/OWNERS b/tests/carservice_unit_test/OWNERS
new file mode 100644
index 0000000..7b75cb8
--- /dev/null
+++ b/tests/carservice_unit_test/OWNERS
@@ -0,0 +1,53 @@
+# ActivityManager
+per-file src/com/android/car/am/* = ycheo@google.com
+
+# AppFocus
+per-file src/com/android/car/AppFocusServiceTest.java = ycheo@google.com
+
+# Audio
+per-file src/com/android/car/audio/* = oscarazu@google.com, ericjeong@google.com
+
+# Cluster
+per-file src/android/car/cluster/* = ycheo@google.com
+per-file src/com/android/car/hal/ClusterHalServiceTest.java = ycheo@google.com
+
+# Input
+per-file src/android/car/builtin/input/* = ycheo@google.com
+per-file src/com/android/car/CarInput*.java = ycheo@google.com
+per-file src/com/android/car/hal/InputHalServiceTest.java = ycheo@google.com
+
+# OccupantZone
+per-file src/com/android/car/CarOccupantZoneServiceTest.java = ycheo@google.com, oscarazu@google.com, ericjeong@google.com
+
+# PackageManager
+per-file src/com/android/car/pm/* = ycheo@google.com
+
+# Power
+per-file src/com/android/car/garagemode/* = ericjeong@google.com
+per-file src/com/android/car/hardware/power/* = ericjeong@google.com
+per-file src/com/android/car/hal/PowerHalServiceTest.java = ericjeong@google.com
+per-file src/com/android/car/power/* = ericjeong@google.com
+
+# ProcInspector
+per-file src/com/android/car/procinspector/* = lakshmana@google.com
+
+# StorageMonitoring
+per-file src/com/android/car/storagemonitoring/* = lakshmana@google.com
+
+# SystemInterface
+per-file src/com/android/car/systeminterface/* = ericjeong@google.com
+
+# Watchdog
+per-file assets/os/* = lakshmana@google.com
+per-file src/android/car/os/* = lakshmana@google.com
+per-file src/android/car/watchdoglib/* = lakshmana@google.com
+per-file src/com/android/car/os/* = lakshmana@google.com
+per-file src/com/android/car/watchdog/* = lakshmana@google.com
+
+# View
+per-file src/android/car/builtin/view/* = ycheo@google.com
+
+# VHAL
+per-file src/com/android/car/hal/Hal*.java = ericjeong@google.com
+per-file src/com/android/car/hal/VehicleHal*.java = ericjeong@google.com
+per-file src/com/android/car/VehicleStubTest.java = ericjeong@google.com
diff --git a/tests/carservice_unit_test/assets/os/corrupted_cpufreq/policy0/affected_cpus b/tests/carservice_unit_test/assets/os/corrupted_cpufreq/policy0/affected_cpus
new file mode 100644
index 0000000..87209ba
--- /dev/null
+++ b/tests/carservice_unit_test/assets/os/corrupted_cpufreq/policy0/affected_cpus
@@ -0,0 +1 @@
+0-
diff --git a/tests/carservice_unit_test/assets/os/corrupted_cpufreq/policy0/cpuinfo_cur_freq b/tests/carservice_unit_test/assets/os/corrupted_cpufreq/policy0/cpuinfo_cur_freq
new file mode 100644
index 0000000..80b164d
--- /dev/null
+++ b/tests/carservice_unit_test/assets/os/corrupted_cpufreq/policy0/cpuinfo_cur_freq
@@ -0,0 +1 @@
+"1.23
diff --git a/tests/carservice_unit_test/assets/os/corrupted_cpufreq/policy0/cpuinfo_max_freq b/tests/carservice_unit_test/assets/os/corrupted_cpufreq/policy0/cpuinfo_max_freq
new file mode 100644
index 0000000..582d8c8
--- /dev/null
+++ b/tests/carservice_unit_test/assets/os/corrupted_cpufreq/policy0/cpuinfo_max_freq
@@ -0,0 +1 @@
++2.5
diff --git a/tests/carservice_unit_test/assets/os/corrupted_cpufreq/policy0/related_cpus b/tests/carservice_unit_test/assets/os/corrupted_cpufreq/policy0/related_cpus
new file mode 100644
index 0000000..87209ba
--- /dev/null
+++ b/tests/carservice_unit_test/assets/os/corrupted_cpufreq/policy0/related_cpus
@@ -0,0 +1 @@
+0-
diff --git a/tests/carservice_unit_test/assets/os/corrupted_cpufreq/policy0/scaling_cur_freq b/tests/carservice_unit_test/assets/os/corrupted_cpufreq/policy0/scaling_cur_freq
new file mode 100644
index 0000000..2142470
--- /dev/null
+++ b/tests/carservice_unit_test/assets/os/corrupted_cpufreq/policy0/scaling_cur_freq
@@ -0,0 +1 @@
+ 0
diff --git a/tests/carservice_unit_test/assets/os/corrupted_cpufreq/policy0/scaling_max_freq b/tests/carservice_unit_test/assets/os/corrupted_cpufreq/policy0/scaling_max_freq
new file mode 100644
index 0000000..2142470
--- /dev/null
+++ b/tests/carservice_unit_test/assets/os/corrupted_cpufreq/policy0/scaling_max_freq
@@ -0,0 +1 @@
+ 0
diff --git a/tests/carservice_unit_test/assets/os/corrupted_cpufreq/policy1/affected_cpus b/tests/carservice_unit_test/assets/os/corrupted_cpufreq/policy1/affected_cpus
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/tests/carservice_unit_test/assets/os/corrupted_cpufreq/policy1/affected_cpus
@@ -0,0 +1 @@
+1
diff --git a/tests/carservice_unit_test/assets/os/corrupted_cpufreq/policy1/cpuinfo_cur_freq b/tests/carservice_unit_test/assets/os/corrupted_cpufreq/policy1/cpuinfo_cur_freq
new file mode 100644
index 0000000..d4f015c
--- /dev/null
+++ b/tests/carservice_unit_test/assets/os/corrupted_cpufreq/policy1/cpuinfo_cur_freq
@@ -0,0 +1 @@
+3000000
diff --git a/tests/carservice_unit_test/assets/os/corrupted_cpufreq/policy1/cpuinfo_max_freq b/tests/carservice_unit_test/assets/os/corrupted_cpufreq/policy1/cpuinfo_max_freq
new file mode 100644
index 0000000..749fce6
--- /dev/null
+++ b/tests/carservice_unit_test/assets/os/corrupted_cpufreq/policy1/cpuinfo_max_freq
@@ -0,0 +1 @@
+1000000
diff --git a/tests/carservice_unit_test/assets/os/corrupted_cpufreq/policy1/related_cpus b/tests/carservice_unit_test/assets/os/corrupted_cpufreq/policy1/related_cpus
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/tests/carservice_unit_test/assets/os/corrupted_cpufreq/policy1/related_cpus
@@ -0,0 +1 @@
+1
diff --git a/tests/carservice_unit_test/assets/os/corrupted_cpufreq/policy2/affected_cpus b/tests/carservice_unit_test/assets/os/corrupted_cpufreq/policy2/affected_cpus
new file mode 100644
index 0000000..6792fa3
--- /dev/null
+++ b/tests/carservice_unit_test/assets/os/corrupted_cpufreq/policy2/affected_cpus
@@ -0,0 +1,2 @@
+ 2,
+ 3
diff --git a/tests/carservice_unit_test/assets/os/corrupted_cpufreq/policy2/cpuinfo_cur_freq b/tests/carservice_unit_test/assets/os/corrupted_cpufreq/policy2/cpuinfo_cur_freq
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/carservice_unit_test/assets/os/corrupted_cpufreq/policy2/cpuinfo_cur_freq
diff --git a/tests/carservice_unit_test/assets/os/corrupted_cpufreq/policy2/cpuinfo_max_freq b/tests/carservice_unit_test/assets/os/corrupted_cpufreq/policy2/cpuinfo_max_freq
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/carservice_unit_test/assets/os/corrupted_cpufreq/policy2/cpuinfo_max_freq
diff --git a/tests/carservice_unit_test/assets/os/corrupted_cpufreq/policy2/related_cpus b/tests/carservice_unit_test/assets/os/corrupted_cpufreq/policy2/related_cpus
new file mode 100644
index 0000000..6792fa3
--- /dev/null
+++ b/tests/carservice_unit_test/assets/os/corrupted_cpufreq/policy2/related_cpus
@@ -0,0 +1,2 @@
+ 2,
+ 3
diff --git a/tests/carservice_unit_test/assets/os/corrupted_cpufreq/policy2/scaling_cur_freq b/tests/carservice_unit_test/assets/os/corrupted_cpufreq/policy2/scaling_cur_freq
new file mode 100644
index 0000000..e2c709d
--- /dev/null
+++ b/tests/carservice_unit_test/assets/os/corrupted_cpufreq/policy2/scaling_cur_freq
@@ -0,0 +1 @@
+ 9
diff --git a/tests/carservice_unit_test/assets/os/corrupted_cpufreq/policy2/scaling_max_freq b/tests/carservice_unit_test/assets/os/corrupted_cpufreq/policy2/scaling_max_freq
new file mode 100644
index 0000000..671900d
--- /dev/null
+++ b/tests/carservice_unit_test/assets/os/corrupted_cpufreq/policy2/scaling_max_freq
@@ -0,0 +1 @@
+ 2
diff --git a/tests/carservice_unit_test/assets/os/corrupted_cpuset/background/cpus b/tests/carservice_unit_test/assets/os/corrupted_cpuset/background/cpus
new file mode 100644
index 0000000..f88e3f5
--- /dev/null
+++ b/tests/carservice_unit_test/assets/os/corrupted_cpuset/background/cpus
@@ -0,0 +1,2 @@
+ 2,
+-3
diff --git a/tests/carservice_unit_test/assets/os/corrupted_cpuset/top-app/cpus b/tests/carservice_unit_test/assets/os/corrupted_cpuset/top-app/cpus
new file mode 100644
index 0000000..c7e8959
--- /dev/null
+++ b/tests/carservice_unit_test/assets/os/corrupted_cpuset/top-app/cpus
@@ -0,0 +1,2 @@
+ 0-
+ 1-2-3
diff --git a/tests/carservice_unit_test/assets/os/corrupted_proc_stat b/tests/carservice_unit_test/assets/os/corrupted_proc_stat
new file mode 100644
index 0000000..a210fc7
--- /dev/null
+++ b/tests/carservice_unit_test/assets/os/corrupted_proc_stat
@@ -0,0 +1,12 @@
+cpu 6119889 1575038 10623107 81174407 250978 2293369 192710 16073 0 0
+cpu0 3224961 795093 5222705 40903695 132281 814674 42897 8195 0 0
+cpu1 2894928 779945 5400402 40270712 118696 1478694 149813 7878 0 0
+cpu2 2895928 corrupted 40271712 116696 1479694 147813 8878 0 0
+cpu3 3234961 785093 5212705 40913695 133281 813674 corrupted
+intr 1411620772 49 19 0 0 4 0 0 0 1 0 0 1497 3 0 0 0 1 0 0 0 0 459002 0 0 19479985 0 30742819 0 1 0 22977745 0 79 0 10 0 1578 2077 0 207913133 0 53571 0 43 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 142749 719664 0 4096981 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ctxt 3289727889
+btime 1648158254
+processes 7700412
+procs_running 1
+procs_blocked 0
+softirq 190070910 9 21017845 30017 4408 64129752 0 672853 46618585 0 57597441
diff --git a/tests/carservice_unit_test/assets/os/valid_cpufreq_with_time_in_state/policy0/affected_cpus b/tests/carservice_unit_test/assets/os/valid_cpufreq_with_time_in_state/policy0/affected_cpus
new file mode 100644
index 0000000..573541a
--- /dev/null
+++ b/tests/carservice_unit_test/assets/os/valid_cpufreq_with_time_in_state/policy0/affected_cpus
@@ -0,0 +1 @@
+0
diff --git a/tests/carservice_unit_test/assets/os/valid_cpufreq_with_time_in_state/policy0/cpuinfo_cur_freq b/tests/carservice_unit_test/assets/os/valid_cpufreq_with_time_in_state/policy0/cpuinfo_cur_freq
new file mode 100644
index 0000000..dadd973
--- /dev/null
+++ b/tests/carservice_unit_test/assets/os/valid_cpufreq_with_time_in_state/policy0/cpuinfo_cur_freq
@@ -0,0 +1 @@
+1230000
diff --git a/tests/carservice_unit_test/assets/os/valid_cpufreq_with_time_in_state/policy0/cpuinfo_max_freq b/tests/carservice_unit_test/assets/os/valid_cpufreq_with_time_in_state/policy0/cpuinfo_max_freq
new file mode 100644
index 0000000..a93d6f7
--- /dev/null
+++ b/tests/carservice_unit_test/assets/os/valid_cpufreq_with_time_in_state/policy0/cpuinfo_max_freq
@@ -0,0 +1 @@
+2500000
diff --git a/tests/carservice_unit_test/assets/os/valid_cpufreq_with_time_in_state/policy0/related_cpus b/tests/carservice_unit_test/assets/os/valid_cpufreq_with_time_in_state/policy0/related_cpus
new file mode 100644
index 0000000..c227083
--- /dev/null
+++ b/tests/carservice_unit_test/assets/os/valid_cpufreq_with_time_in_state/policy0/related_cpus
@@ -0,0 +1 @@
+0
\ No newline at end of file
diff --git a/tests/carservice_unit_test/assets/os/valid_cpufreq_with_time_in_state/policy0/scaling_cur_freq b/tests/carservice_unit_test/assets/os/valid_cpufreq_with_time_in_state/policy0/scaling_cur_freq
new file mode 100644
index 0000000..573541a
--- /dev/null
+++ b/tests/carservice_unit_test/assets/os/valid_cpufreq_with_time_in_state/policy0/scaling_cur_freq
@@ -0,0 +1 @@
+0
diff --git a/tests/carservice_unit_test/assets/os/valid_cpufreq_with_time_in_state/policy0/scaling_max_freq b/tests/carservice_unit_test/assets/os/valid_cpufreq_with_time_in_state/policy0/scaling_max_freq
new file mode 100644
index 0000000..573541a
--- /dev/null
+++ b/tests/carservice_unit_test/assets/os/valid_cpufreq_with_time_in_state/policy0/scaling_max_freq
@@ -0,0 +1 @@
+0
diff --git a/tests/carservice_unit_test/assets/os/valid_cpufreq_with_time_in_state/policy0/stats/time_in_state b/tests/carservice_unit_test/assets/os/valid_cpufreq_with_time_in_state/policy0/stats/time_in_state
new file mode 100644
index 0000000..5121f66
--- /dev/null
+++ b/tests/carservice_unit_test/assets/os/valid_cpufreq_with_time_in_state/policy0/stats/time_in_state
@@ -0,0 +1,4 @@
+200000 500
+350000 500
+500000 1000
+2500000 100
diff --git a/tests/carservice_unit_test/assets/os/valid_cpufreq_with_time_in_state/policy1/affected_cpus b/tests/carservice_unit_test/assets/os/valid_cpufreq_with_time_in_state/policy1/affected_cpus
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/tests/carservice_unit_test/assets/os/valid_cpufreq_with_time_in_state/policy1/affected_cpus
@@ -0,0 +1 @@
+1
diff --git a/tests/carservice_unit_test/assets/os/valid_cpufreq_with_time_in_state/policy1/cpuinfo_cur_freq b/tests/carservice_unit_test/assets/os/valid_cpufreq_with_time_in_state/policy1/cpuinfo_cur_freq
new file mode 100644
index 0000000..2bc4ce9
--- /dev/null
+++ b/tests/carservice_unit_test/assets/os/valid_cpufreq_with_time_in_state/policy1/cpuinfo_cur_freq
@@ -0,0 +1 @@
+1450000
diff --git a/tests/carservice_unit_test/assets/os/valid_cpufreq_with_time_in_state/policy1/cpuinfo_max_freq b/tests/carservice_unit_test/assets/os/valid_cpufreq_with_time_in_state/policy1/cpuinfo_max_freq
new file mode 100644
index 0000000..c754f1a
--- /dev/null
+++ b/tests/carservice_unit_test/assets/os/valid_cpufreq_with_time_in_state/policy1/cpuinfo_max_freq
@@ -0,0 +1 @@
+2800000
diff --git a/tests/carservice_unit_test/assets/os/valid_cpufreq_with_time_in_state/policy1/related_cpus b/tests/carservice_unit_test/assets/os/valid_cpufreq_with_time_in_state/policy1/related_cpus
new file mode 100644
index 0000000..56a6051
--- /dev/null
+++ b/tests/carservice_unit_test/assets/os/valid_cpufreq_with_time_in_state/policy1/related_cpus
@@ -0,0 +1 @@
+1
\ No newline at end of file
diff --git a/tests/carservice_unit_test/assets/os/valid_cpufreq_with_time_in_state/policy1/stats/time_in_state b/tests/carservice_unit_test/assets/os/valid_cpufreq_with_time_in_state/policy1/stats/time_in_state
new file mode 100644
index 0000000..7ed12cf
--- /dev/null
+++ b/tests/carservice_unit_test/assets/os/valid_cpufreq_with_time_in_state/policy1/stats/time_in_state
@@ -0,0 +1,4 @@
+200000 500
+350000 500
+500000 1000
+2800000 100
diff --git a/tests/carservice_unit_test/assets/os/valid_cpufreq_with_time_in_state/policy2/affected_cpus b/tests/carservice_unit_test/assets/os/valid_cpufreq_with_time_in_state/policy2/affected_cpus
new file mode 100644
index 0000000..06717bd
--- /dev/null
+++ b/tests/carservice_unit_test/assets/os/valid_cpufreq_with_time_in_state/policy2/affected_cpus
@@ -0,0 +1 @@
+2,3
diff --git a/tests/carservice_unit_test/assets/os/valid_cpufreq_with_time_in_state/policy2/cpuinfo_cur_freq b/tests/carservice_unit_test/assets/os/valid_cpufreq_with_time_in_state/policy2/cpuinfo_cur_freq
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/carservice_unit_test/assets/os/valid_cpufreq_with_time_in_state/policy2/cpuinfo_cur_freq
diff --git a/tests/carservice_unit_test/assets/os/valid_cpufreq_with_time_in_state/policy2/cpuinfo_max_freq b/tests/carservice_unit_test/assets/os/valid_cpufreq_with_time_in_state/policy2/cpuinfo_max_freq
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/carservice_unit_test/assets/os/valid_cpufreq_with_time_in_state/policy2/cpuinfo_max_freq
diff --git a/tests/carservice_unit_test/assets/os/valid_cpufreq_with_time_in_state/policy2/related_cpus b/tests/carservice_unit_test/assets/os/valid_cpufreq_with_time_in_state/policy2/related_cpus
new file mode 100644
index 0000000..82e6fae
--- /dev/null
+++ b/tests/carservice_unit_test/assets/os/valid_cpufreq_with_time_in_state/policy2/related_cpus
@@ -0,0 +1 @@
+2-3
\ No newline at end of file
diff --git a/tests/carservice_unit_test/assets/os/valid_cpufreq_with_time_in_state/policy2/scaling_cur_freq b/tests/carservice_unit_test/assets/os/valid_cpufreq_with_time_in_state/policy2/scaling_cur_freq
new file mode 100644
index 0000000..749fce6
--- /dev/null
+++ b/tests/carservice_unit_test/assets/os/valid_cpufreq_with_time_in_state/policy2/scaling_cur_freq
@@ -0,0 +1 @@
+1000000
diff --git a/tests/carservice_unit_test/assets/os/valid_cpufreq_with_time_in_state/policy2/scaling_max_freq b/tests/carservice_unit_test/assets/os/valid_cpufreq_with_time_in_state/policy2/scaling_max_freq
new file mode 100644
index 0000000..deebb18
--- /dev/null
+++ b/tests/carservice_unit_test/assets/os/valid_cpufreq_with_time_in_state/policy2/scaling_max_freq
@@ -0,0 +1 @@
+2000000
diff --git a/tests/carservice_unit_test/assets/os/valid_cpufreq_with_time_in_state/policy2/stats/time_in_state b/tests/carservice_unit_test/assets/os/valid_cpufreq_with_time_in_state/policy2/stats/time_in_state
new file mode 100644
index 0000000..58ad62f
--- /dev/null
+++ b/tests/carservice_unit_test/assets/os/valid_cpufreq_with_time_in_state/policy2/stats/time_in_state
@@ -0,0 +1,4 @@
+200000 500
+350000 500
+500000 1000
+2000000 100
diff --git a/tests/carservice_unit_test/assets/os/valid_cpufreq_with_time_in_state_2/policy0/affected_cpus b/tests/carservice_unit_test/assets/os/valid_cpufreq_with_time_in_state_2/policy0/affected_cpus
new file mode 100644
index 0000000..573541a
--- /dev/null
+++ b/tests/carservice_unit_test/assets/os/valid_cpufreq_with_time_in_state_2/policy0/affected_cpus
@@ -0,0 +1 @@
+0
diff --git a/tests/carservice_unit_test/assets/os/valid_cpufreq_with_time_in_state_2/policy0/cpuinfo_cur_freq b/tests/carservice_unit_test/assets/os/valid_cpufreq_with_time_in_state_2/policy0/cpuinfo_cur_freq
new file mode 100644
index 0000000..749fce6
--- /dev/null
+++ b/tests/carservice_unit_test/assets/os/valid_cpufreq_with_time_in_state_2/policy0/cpuinfo_cur_freq
@@ -0,0 +1 @@
+1000000
diff --git a/tests/carservice_unit_test/assets/os/valid_cpufreq_with_time_in_state_2/policy0/cpuinfo_max_freq b/tests/carservice_unit_test/assets/os/valid_cpufreq_with_time_in_state_2/policy0/cpuinfo_max_freq
new file mode 100644
index 0000000..a93d6f7
--- /dev/null
+++ b/tests/carservice_unit_test/assets/os/valid_cpufreq_with_time_in_state_2/policy0/cpuinfo_max_freq
@@ -0,0 +1 @@
+2500000
diff --git a/tests/carservice_unit_test/assets/os/valid_cpufreq_with_time_in_state_2/policy0/scaling_cur_freq b/tests/carservice_unit_test/assets/os/valid_cpufreq_with_time_in_state_2/policy0/scaling_cur_freq
new file mode 100644
index 0000000..573541a
--- /dev/null
+++ b/tests/carservice_unit_test/assets/os/valid_cpufreq_with_time_in_state_2/policy0/scaling_cur_freq
@@ -0,0 +1 @@
+0
diff --git a/tests/carservice_unit_test/assets/os/valid_cpufreq_with_time_in_state_2/policy0/scaling_max_freq b/tests/carservice_unit_test/assets/os/valid_cpufreq_with_time_in_state_2/policy0/scaling_max_freq
new file mode 100644
index 0000000..573541a
--- /dev/null
+++ b/tests/carservice_unit_test/assets/os/valid_cpufreq_with_time_in_state_2/policy0/scaling_max_freq
@@ -0,0 +1 @@
+0
diff --git a/tests/carservice_unit_test/assets/os/valid_cpufreq_with_time_in_state_2/policy0/stats/time_in_state b/tests/carservice_unit_test/assets/os/valid_cpufreq_with_time_in_state_2/policy0/stats/time_in_state
new file mode 100644
index 0000000..485556b
--- /dev/null
+++ b/tests/carservice_unit_test/assets/os/valid_cpufreq_with_time_in_state_2/policy0/stats/time_in_state
@@ -0,0 +1,4 @@
+200000 1500
+350000 1500
+500000 2000
+2500000 200
diff --git a/tests/carservice_unit_test/assets/os/valid_cpufreq_with_time_in_state_2/policy1/affected_cpus b/tests/carservice_unit_test/assets/os/valid_cpufreq_with_time_in_state_2/policy1/affected_cpus
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/tests/carservice_unit_test/assets/os/valid_cpufreq_with_time_in_state_2/policy1/affected_cpus
@@ -0,0 +1 @@
+1
diff --git a/tests/carservice_unit_test/assets/os/valid_cpufreq_with_time_in_state_2/policy1/cpuinfo_cur_freq b/tests/carservice_unit_test/assets/os/valid_cpufreq_with_time_in_state_2/policy1/cpuinfo_cur_freq
new file mode 100644
index 0000000..c754f1a
--- /dev/null
+++ b/tests/carservice_unit_test/assets/os/valid_cpufreq_with_time_in_state_2/policy1/cpuinfo_cur_freq
@@ -0,0 +1 @@
+2800000
diff --git a/tests/carservice_unit_test/assets/os/valid_cpufreq_with_time_in_state_2/policy1/cpuinfo_max_freq b/tests/carservice_unit_test/assets/os/valid_cpufreq_with_time_in_state_2/policy1/cpuinfo_max_freq
new file mode 100644
index 0000000..c754f1a
--- /dev/null
+++ b/tests/carservice_unit_test/assets/os/valid_cpufreq_with_time_in_state_2/policy1/cpuinfo_max_freq
@@ -0,0 +1 @@
+2800000
diff --git a/tests/carservice_unit_test/assets/os/valid_cpufreq_with_time_in_state_2/policy1/stats/time_in_state b/tests/carservice_unit_test/assets/os/valid_cpufreq_with_time_in_state_2/policy1/stats/time_in_state
new file mode 100644
index 0000000..68564dc
--- /dev/null
+++ b/tests/carservice_unit_test/assets/os/valid_cpufreq_with_time_in_state_2/policy1/stats/time_in_state
@@ -0,0 +1,4 @@
+200000 1500
+350000 1500
+500000 2000
+2800000 200
diff --git a/tests/carservice_unit_test/assets/os/valid_cpufreq_with_time_in_state_2/policy2/affected_cpus b/tests/carservice_unit_test/assets/os/valid_cpufreq_with_time_in_state_2/policy2/affected_cpus
new file mode 100644
index 0000000..06717bd
--- /dev/null
+++ b/tests/carservice_unit_test/assets/os/valid_cpufreq_with_time_in_state_2/policy2/affected_cpus
@@ -0,0 +1 @@
+2,3
diff --git a/tests/carservice_unit_test/assets/os/valid_cpufreq_with_time_in_state_2/policy2/cpuinfo_cur_freq b/tests/carservice_unit_test/assets/os/valid_cpufreq_with_time_in_state_2/policy2/cpuinfo_cur_freq
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/carservice_unit_test/assets/os/valid_cpufreq_with_time_in_state_2/policy2/cpuinfo_cur_freq
diff --git a/tests/carservice_unit_test/assets/os/valid_cpufreq_with_time_in_state_2/policy2/cpuinfo_max_freq b/tests/carservice_unit_test/assets/os/valid_cpufreq_with_time_in_state_2/policy2/cpuinfo_max_freq
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/carservice_unit_test/assets/os/valid_cpufreq_with_time_in_state_2/policy2/cpuinfo_max_freq
diff --git a/tests/carservice_unit_test/assets/os/valid_cpufreq_with_time_in_state_2/policy2/scaling_cur_freq b/tests/carservice_unit_test/assets/os/valid_cpufreq_with_time_in_state_2/policy2/scaling_cur_freq
new file mode 100644
index 0000000..deebb18
--- /dev/null
+++ b/tests/carservice_unit_test/assets/os/valid_cpufreq_with_time_in_state_2/policy2/scaling_cur_freq
@@ -0,0 +1 @@
+2000000
diff --git a/tests/carservice_unit_test/assets/os/valid_cpufreq_with_time_in_state_2/policy2/scaling_max_freq b/tests/carservice_unit_test/assets/os/valid_cpufreq_with_time_in_state_2/policy2/scaling_max_freq
new file mode 100644
index 0000000..deebb18
--- /dev/null
+++ b/tests/carservice_unit_test/assets/os/valid_cpufreq_with_time_in_state_2/policy2/scaling_max_freq
@@ -0,0 +1 @@
+2000000
diff --git a/tests/carservice_unit_test/assets/os/valid_cpufreq_with_time_in_state_2/policy2/stats/time_in_state b/tests/carservice_unit_test/assets/os/valid_cpufreq_with_time_in_state_2/policy2/stats/time_in_state
new file mode 100644
index 0000000..3c735d8
--- /dev/null
+++ b/tests/carservice_unit_test/assets/os/valid_cpufreq_with_time_in_state_2/policy2/stats/time_in_state
@@ -0,0 +1,4 @@
+200000 1500
+350000 1500
+500000 2000
+2000000 200
diff --git a/tests/carservice_unit_test/assets/os/valid_cpufreq_without_time_in_state/policy0/affected_cpus b/tests/carservice_unit_test/assets/os/valid_cpufreq_without_time_in_state/policy0/affected_cpus
new file mode 100644
index 0000000..573541a
--- /dev/null
+++ b/tests/carservice_unit_test/assets/os/valid_cpufreq_without_time_in_state/policy0/affected_cpus
@@ -0,0 +1 @@
+0
diff --git a/tests/carservice_unit_test/assets/os/valid_cpufreq_without_time_in_state/policy0/cpuinfo_cur_freq b/tests/carservice_unit_test/assets/os/valid_cpufreq_without_time_in_state/policy0/cpuinfo_cur_freq
new file mode 100644
index 0000000..dadd973
--- /dev/null
+++ b/tests/carservice_unit_test/assets/os/valid_cpufreq_without_time_in_state/policy0/cpuinfo_cur_freq
@@ -0,0 +1 @@
+1230000
diff --git a/tests/carservice_unit_test/assets/os/valid_cpufreq_without_time_in_state/policy0/cpuinfo_max_freq b/tests/carservice_unit_test/assets/os/valid_cpufreq_without_time_in_state/policy0/cpuinfo_max_freq
new file mode 100644
index 0000000..a93d6f7
--- /dev/null
+++ b/tests/carservice_unit_test/assets/os/valid_cpufreq_without_time_in_state/policy0/cpuinfo_max_freq
@@ -0,0 +1 @@
+2500000
diff --git a/tests/carservice_unit_test/assets/os/valid_cpufreq_without_time_in_state/policy0/related_cpus b/tests/carservice_unit_test/assets/os/valid_cpufreq_without_time_in_state/policy0/related_cpus
new file mode 100644
index 0000000..c227083
--- /dev/null
+++ b/tests/carservice_unit_test/assets/os/valid_cpufreq_without_time_in_state/policy0/related_cpus
@@ -0,0 +1 @@
+0
\ No newline at end of file
diff --git a/tests/carservice_unit_test/assets/os/valid_cpufreq_without_time_in_state/policy0/scaling_cur_freq b/tests/carservice_unit_test/assets/os/valid_cpufreq_without_time_in_state/policy0/scaling_cur_freq
new file mode 100644
index 0000000..573541a
--- /dev/null
+++ b/tests/carservice_unit_test/assets/os/valid_cpufreq_without_time_in_state/policy0/scaling_cur_freq
@@ -0,0 +1 @@
+0
diff --git a/tests/carservice_unit_test/assets/os/valid_cpufreq_without_time_in_state/policy0/scaling_max_freq b/tests/carservice_unit_test/assets/os/valid_cpufreq_without_time_in_state/policy0/scaling_max_freq
new file mode 100644
index 0000000..573541a
--- /dev/null
+++ b/tests/carservice_unit_test/assets/os/valid_cpufreq_without_time_in_state/policy0/scaling_max_freq
@@ -0,0 +1 @@
+0
diff --git a/tests/carservice_unit_test/assets/os/valid_cpufreq_without_time_in_state/policy1/affected_cpus b/tests/carservice_unit_test/assets/os/valid_cpufreq_without_time_in_state/policy1/affected_cpus
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/tests/carservice_unit_test/assets/os/valid_cpufreq_without_time_in_state/policy1/affected_cpus
@@ -0,0 +1 @@
+1
diff --git a/tests/carservice_unit_test/assets/os/valid_cpufreq_without_time_in_state/policy1/cpuinfo_cur_freq b/tests/carservice_unit_test/assets/os/valid_cpufreq_without_time_in_state/policy1/cpuinfo_cur_freq
new file mode 100644
index 0000000..2bc4ce9
--- /dev/null
+++ b/tests/carservice_unit_test/assets/os/valid_cpufreq_without_time_in_state/policy1/cpuinfo_cur_freq
@@ -0,0 +1 @@
+1450000
diff --git a/tests/carservice_unit_test/assets/os/valid_cpufreq_without_time_in_state/policy1/cpuinfo_max_freq b/tests/carservice_unit_test/assets/os/valid_cpufreq_without_time_in_state/policy1/cpuinfo_max_freq
new file mode 100644
index 0000000..c754f1a
--- /dev/null
+++ b/tests/carservice_unit_test/assets/os/valid_cpufreq_without_time_in_state/policy1/cpuinfo_max_freq
@@ -0,0 +1 @@
+2800000
diff --git a/tests/carservice_unit_test/assets/os/valid_cpufreq_without_time_in_state/policy1/related_cpus b/tests/carservice_unit_test/assets/os/valid_cpufreq_without_time_in_state/policy1/related_cpus
new file mode 100644
index 0000000..56a6051
--- /dev/null
+++ b/tests/carservice_unit_test/assets/os/valid_cpufreq_without_time_in_state/policy1/related_cpus
@@ -0,0 +1 @@
+1
\ No newline at end of file
diff --git a/tests/carservice_unit_test/assets/os/valid_cpufreq_without_time_in_state/policy2/affected_cpus b/tests/carservice_unit_test/assets/os/valid_cpufreq_without_time_in_state/policy2/affected_cpus
new file mode 100644
index 0000000..06717bd
--- /dev/null
+++ b/tests/carservice_unit_test/assets/os/valid_cpufreq_without_time_in_state/policy2/affected_cpus
@@ -0,0 +1 @@
+2,3
diff --git a/tests/carservice_unit_test/assets/os/valid_cpufreq_without_time_in_state/policy2/cpuinfo_cur_freq b/tests/carservice_unit_test/assets/os/valid_cpufreq_without_time_in_state/policy2/cpuinfo_cur_freq
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/carservice_unit_test/assets/os/valid_cpufreq_without_time_in_state/policy2/cpuinfo_cur_freq
diff --git a/tests/carservice_unit_test/assets/os/valid_cpufreq_without_time_in_state/policy2/cpuinfo_max_freq b/tests/carservice_unit_test/assets/os/valid_cpufreq_without_time_in_state/policy2/cpuinfo_max_freq
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/carservice_unit_test/assets/os/valid_cpufreq_without_time_in_state/policy2/cpuinfo_max_freq
diff --git a/tests/carservice_unit_test/assets/os/valid_cpufreq_without_time_in_state/policy2/related_cpus b/tests/carservice_unit_test/assets/os/valid_cpufreq_without_time_in_state/policy2/related_cpus
new file mode 100644
index 0000000..82e6fae
--- /dev/null
+++ b/tests/carservice_unit_test/assets/os/valid_cpufreq_without_time_in_state/policy2/related_cpus
@@ -0,0 +1 @@
+2-3
\ No newline at end of file
diff --git a/tests/carservice_unit_test/assets/os/valid_cpufreq_without_time_in_state/policy2/scaling_cur_freq b/tests/carservice_unit_test/assets/os/valid_cpufreq_without_time_in_state/policy2/scaling_cur_freq
new file mode 100644
index 0000000..749fce6
--- /dev/null
+++ b/tests/carservice_unit_test/assets/os/valid_cpufreq_without_time_in_state/policy2/scaling_cur_freq
@@ -0,0 +1 @@
+1000000
diff --git a/tests/carservice_unit_test/assets/os/valid_cpufreq_without_time_in_state/policy2/scaling_max_freq b/tests/carservice_unit_test/assets/os/valid_cpufreq_without_time_in_state/policy2/scaling_max_freq
new file mode 100644
index 0000000..deebb18
--- /dev/null
+++ b/tests/carservice_unit_test/assets/os/valid_cpufreq_without_time_in_state/policy2/scaling_max_freq
@@ -0,0 +1 @@
+2000000
diff --git a/tests/carservice_unit_test/assets/os/valid_cpufreq_without_time_in_state_2/policy0/affected_cpus b/tests/carservice_unit_test/assets/os/valid_cpufreq_without_time_in_state_2/policy0/affected_cpus
new file mode 100644
index 0000000..573541a
--- /dev/null
+++ b/tests/carservice_unit_test/assets/os/valid_cpufreq_without_time_in_state_2/policy0/affected_cpus
@@ -0,0 +1 @@
+0
diff --git a/tests/carservice_unit_test/assets/os/valid_cpufreq_without_time_in_state_2/policy0/cpuinfo_cur_freq b/tests/carservice_unit_test/assets/os/valid_cpufreq_without_time_in_state_2/policy0/cpuinfo_cur_freq
new file mode 100644
index 0000000..749fce6
--- /dev/null
+++ b/tests/carservice_unit_test/assets/os/valid_cpufreq_without_time_in_state_2/policy0/cpuinfo_cur_freq
@@ -0,0 +1 @@
+1000000
diff --git a/tests/carservice_unit_test/assets/os/valid_cpufreq_without_time_in_state_2/policy0/cpuinfo_max_freq b/tests/carservice_unit_test/assets/os/valid_cpufreq_without_time_in_state_2/policy0/cpuinfo_max_freq
new file mode 100644
index 0000000..a93d6f7
--- /dev/null
+++ b/tests/carservice_unit_test/assets/os/valid_cpufreq_without_time_in_state_2/policy0/cpuinfo_max_freq
@@ -0,0 +1 @@
+2500000
diff --git a/tests/carservice_unit_test/assets/os/valid_cpufreq_without_time_in_state_2/policy0/scaling_cur_freq b/tests/carservice_unit_test/assets/os/valid_cpufreq_without_time_in_state_2/policy0/scaling_cur_freq
new file mode 100644
index 0000000..573541a
--- /dev/null
+++ b/tests/carservice_unit_test/assets/os/valid_cpufreq_without_time_in_state_2/policy0/scaling_cur_freq
@@ -0,0 +1 @@
+0
diff --git a/tests/carservice_unit_test/assets/os/valid_cpufreq_without_time_in_state_2/policy0/scaling_max_freq b/tests/carservice_unit_test/assets/os/valid_cpufreq_without_time_in_state_2/policy0/scaling_max_freq
new file mode 100644
index 0000000..573541a
--- /dev/null
+++ b/tests/carservice_unit_test/assets/os/valid_cpufreq_without_time_in_state_2/policy0/scaling_max_freq
@@ -0,0 +1 @@
+0
diff --git a/tests/carservice_unit_test/assets/os/valid_cpufreq_without_time_in_state_2/policy1/affected_cpus b/tests/carservice_unit_test/assets/os/valid_cpufreq_without_time_in_state_2/policy1/affected_cpus
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/tests/carservice_unit_test/assets/os/valid_cpufreq_without_time_in_state_2/policy1/affected_cpus
@@ -0,0 +1 @@
+1
diff --git a/tests/carservice_unit_test/assets/os/valid_cpufreq_without_time_in_state_2/policy1/cpuinfo_cur_freq b/tests/carservice_unit_test/assets/os/valid_cpufreq_without_time_in_state_2/policy1/cpuinfo_cur_freq
new file mode 100644
index 0000000..c754f1a
--- /dev/null
+++ b/tests/carservice_unit_test/assets/os/valid_cpufreq_without_time_in_state_2/policy1/cpuinfo_cur_freq
@@ -0,0 +1 @@
+2800000
diff --git a/tests/carservice_unit_test/assets/os/valid_cpufreq_without_time_in_state_2/policy1/cpuinfo_max_freq b/tests/carservice_unit_test/assets/os/valid_cpufreq_without_time_in_state_2/policy1/cpuinfo_max_freq
new file mode 100644
index 0000000..c754f1a
--- /dev/null
+++ b/tests/carservice_unit_test/assets/os/valid_cpufreq_without_time_in_state_2/policy1/cpuinfo_max_freq
@@ -0,0 +1 @@
+2800000
diff --git a/tests/carservice_unit_test/assets/os/valid_cpufreq_without_time_in_state_2/policy2/affected_cpus b/tests/carservice_unit_test/assets/os/valid_cpufreq_without_time_in_state_2/policy2/affected_cpus
new file mode 100644
index 0000000..06717bd
--- /dev/null
+++ b/tests/carservice_unit_test/assets/os/valid_cpufreq_without_time_in_state_2/policy2/affected_cpus
@@ -0,0 +1 @@
+2,3
diff --git a/tests/carservice_unit_test/assets/os/valid_cpufreq_without_time_in_state_2/policy2/cpuinfo_cur_freq b/tests/carservice_unit_test/assets/os/valid_cpufreq_without_time_in_state_2/policy2/cpuinfo_cur_freq
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/carservice_unit_test/assets/os/valid_cpufreq_without_time_in_state_2/policy2/cpuinfo_cur_freq
diff --git a/tests/carservice_unit_test/assets/os/valid_cpufreq_without_time_in_state_2/policy2/cpuinfo_max_freq b/tests/carservice_unit_test/assets/os/valid_cpufreq_without_time_in_state_2/policy2/cpuinfo_max_freq
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/carservice_unit_test/assets/os/valid_cpufreq_without_time_in_state_2/policy2/cpuinfo_max_freq
diff --git a/tests/carservice_unit_test/assets/os/valid_cpufreq_without_time_in_state_2/policy2/scaling_cur_freq b/tests/carservice_unit_test/assets/os/valid_cpufreq_without_time_in_state_2/policy2/scaling_cur_freq
new file mode 100644
index 0000000..deebb18
--- /dev/null
+++ b/tests/carservice_unit_test/assets/os/valid_cpufreq_without_time_in_state_2/policy2/scaling_cur_freq
@@ -0,0 +1 @@
+2000000
diff --git a/tests/carservice_unit_test/assets/os/valid_cpufreq_without_time_in_state_2/policy2/scaling_max_freq b/tests/carservice_unit_test/assets/os/valid_cpufreq_without_time_in_state_2/policy2/scaling_max_freq
new file mode 100644
index 0000000..deebb18
--- /dev/null
+++ b/tests/carservice_unit_test/assets/os/valid_cpufreq_without_time_in_state_2/policy2/scaling_max_freq
@@ -0,0 +1 @@
+2000000
diff --git a/tests/carservice_unit_test/assets/os/valid_cpuset/background/cpus b/tests/carservice_unit_test/assets/os/valid_cpuset/background/cpus
new file mode 100644
index 0000000..4792e70
--- /dev/null
+++ b/tests/carservice_unit_test/assets/os/valid_cpuset/background/cpus
@@ -0,0 +1,2 @@
+2
+3
diff --git a/tests/carservice_unit_test/assets/os/valid_cpuset/top-app/cpus b/tests/carservice_unit_test/assets/os/valid_cpuset/top-app/cpus
new file mode 100644
index 0000000..40c7bb2
--- /dev/null
+++ b/tests/carservice_unit_test/assets/os/valid_cpuset/top-app/cpus
@@ -0,0 +1 @@
+0-3
diff --git a/tests/carservice_unit_test/assets/os/valid_proc_stat b/tests/carservice_unit_test/assets/os/valid_proc_stat
new file mode 100644
index 0000000..5168336
--- /dev/null
+++ b/tests/carservice_unit_test/assets/os/valid_proc_stat
@@ -0,0 +1,12 @@
+cpu 6119889 1575038 10623107 81174407 250978 2293369 192710 16073 0 0
+cpu0 3224961 795093 5222705 40903695 132281 814674 42897 8195 0 0
+cpu1 2894928 779945 5400402 40270712 118696 1478694 149813 7878 0 0
+cpu2 2895928 778945 5401402 40271712 116696 1479694 147813 8878 0 0
+cpu3 3234961 785093 5212705 40913695 133281 813674 43897 7195 0 0
+intr 1411620772 49 19 0 0 4 0 0 0 1 0 0 1497 3 0 0 0 1 0 0 0 0 459002 0 0 19479985 0 30742819 0 1 0 22977745 0 79 0 10 0 1578 2077 0 207913133 0 53571 0 43 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 142749 719664 0 4096981 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ctxt 3289727889
+btime 1648158254
+processes 7700412
+procs_running 1
+procs_blocked 0
+softirq 190070910 9 21017845 30017 4408 64129752 0 672853 46618585 0 57597441
diff --git a/tests/carservice_unit_test/assets/os/valid_proc_stat_2 b/tests/carservice_unit_test/assets/os/valid_proc_stat_2
new file mode 100644
index 0000000..20c3082
--- /dev/null
+++ b/tests/carservice_unit_test/assets/os/valid_proc_stat_2
@@ -0,0 +1,12 @@
+cpu 6119889 1575038 10623107 81174407 250978 2293369 192710 16073 0 0
+cpu0 4224961 895093 6222705 51903695 242281 954674 50897 10295 0 0
+cpu1 2984928 879945 6400402 40370712 127696 1498694 159813 17878 0 0
+cpu2 3895928 978945 5401402 41271712 216696 3479694 247813 18878 0 0
+cpu3 3434961 885093 5312705 40923695 143281 823674 143897 7295 0 0
+intr 1411620772 49 19 0 0 4 0 0 0 1 0 0 1497 3 0 0 0 1 0 0 0 0 459002 0 0 19479985 0 30742819 0 1 0 22977745 0 79 0 10 0 1578 2077 0 207913133 0 53571 0 43 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 142749 719664 0 4096981 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ctxt 3289727889
+btime 1648158254
+processes 7700412
+procs_running 1
+procs_blocked 0
+softirq 190070910 9 21017845 30017 4408 64129752 0 672853 46618585 0 57597441
diff --git a/tests/carservice_unit_test/res/raw/car_api_classes.txt b/tests/carservice_unit_test/res/raw/car_api_classes.txt
new file mode 100644
index 0000000..11fc354
--- /dev/null
+++ b/tests/carservice_unit_test/res/raw/car_api_classes.txt
@@ -0,0 +1,255 @@
+android.car.AoapService
+android.car.ApiVersion
+android.car.ApiVersion$ApiVersionFactory
+android.car.Car
+android.car.Car$CarServiceLifecycleListener
+android.car.CarAppFocusManager
+android.car.CarAppFocusManager$OnAppFocusChangedListener
+android.car.CarAppFocusManager$OnAppFocusOwnershipCallback
+android.car.CarBugreportManager
+android.car.CarBugreportManager$CarBugreportManagerCallback
+android.car.CarFeatures
+android.car.CarInfoManager
+android.car.CarLibLog
+android.car.CarManagerBase
+android.car.CarNotConnectedException
+android.car.CarOccupantZoneManager
+android.car.CarOccupantZoneManager$OccupantZoneInfo
+android.car.CarOccupantZoneManager$OccupantZoneConfigChangeListener
+android.car.CarProjectionManager
+android.car.CarProjectionManager$CarProjectionListener
+android.car.CarProjectionManager$ProjectionKeyEventHandler
+android.car.CarProjectionManager$ProjectionStatusListener
+android.car.CarProjectionManager$ProjectionAccessPointCallback
+android.car.CarTransactionException
+android.car.CarVersion
+android.car.CarVersion$VERSION_CODES
+android.car.EvConnectorType
+android.car.FuelType
+android.car.GsrComplianceType
+android.car.PlatformVersion
+android.car.PlatformVersion$VERSION_CODES
+android.car.PlatformVersionMismatchException
+android.car.PortLocationType
+android.car.VehicleAreaDoor
+android.car.VehicleAreaMirror
+android.car.VehicleAreaSeat
+android.car.VehicleAreaType
+android.car.VehicleAreaWheel
+android.car.VehicleAreaWindow
+android.car.VehicleGear
+android.car.VehicleHvacFanDirection
+android.car.VehicleIgnitionState
+android.car.VehicleLightState
+android.car.VehicleLightSwitch
+android.car.VehicleOilLevel
+android.car.VehiclePropertyAccess
+android.car.VehiclePropertyIds
+android.car.VehiclePropertyType
+android.car.VehicleSeatOccupancyState
+android.car.VehicleUnit
+android.car.admin.CarDevicePolicyManager
+android.car.admin.CreateUserResult
+android.car.admin.RemoveUserResult
+android.car.admin.StartUserInBackgroundResult
+android.car.admin.StopUserResult
+android.car.app.CarActivityManager
+android.car.cluster.CarInstrumentClusterManager
+android.car.cluster.CarInstrumentClusterManager$Callback
+android.car.cluster.ClusterActivityState
+android.car.cluster.ClusterHomeManager
+android.car.cluster.ClusterHomeManager$ClusterStateListener
+android.car.cluster.ClusterHomeManager$ClusterNavigationStateListener
+android.car.cluster.renderer.InstrumentClusterRenderer
+android.car.cluster.renderer.InstrumentClusterRenderingService
+android.car.cluster.renderer.NavigationRenderer
+android.car.content.pm.AppBlockingPackageInfo
+android.car.content.pm.CarAppBlockingPolicy
+android.car.content.pm.CarAppBlockingPolicyService
+android.car.content.pm.CarPackageManager
+android.car.diagnostic.CarDiagnosticEvent
+android.car.diagnostic.CarDiagnosticEvent$Builder
+android.car.diagnostic.CarDiagnosticEvent$FuelSystemStatus
+android.car.diagnostic.CarDiagnosticEvent$SecondaryAirStatus
+android.car.diagnostic.CarDiagnosticEvent$FuelType
+android.car.diagnostic.CarDiagnosticEvent$IgnitionMonitor
+android.car.diagnostic.CarDiagnosticEvent$IgnitionMonitor$Decoder
+android.car.diagnostic.CarDiagnosticEvent$CommonIgnitionMonitors
+android.car.diagnostic.CarDiagnosticEvent$SparkIgnitionMonitors
+android.car.diagnostic.CarDiagnosticEvent$CompressionIgnitionMonitors
+android.car.diagnostic.CarDiagnosticManager
+android.car.diagnostic.CarDiagnosticManager$OnDiagnosticEventListener
+android.car.diagnostic.FloatSensorIndex
+android.car.diagnostic.IntegerSensorIndex
+android.car.drivingstate.CarDrivingStateEvent
+android.car.drivingstate.CarDrivingStateManager
+android.car.drivingstate.CarDrivingStateManager$CarDrivingStateEventListener
+android.car.drivingstate.CarUxRestrictions
+android.car.drivingstate.CarUxRestrictions$Builder
+android.car.drivingstate.CarUxRestrictionsConfiguration
+android.car.drivingstate.CarUxRestrictionsConfiguration$Builder
+android.car.drivingstate.CarUxRestrictionsConfiguration$Builder$SpeedRange
+android.car.drivingstate.CarUxRestrictionsConfiguration$DrivingStateRestrictions
+android.car.drivingstate.CarUxRestrictionsManager
+android.car.drivingstate.CarUxRestrictionsManager$OnUxRestrictionsChangedListener
+android.car.evs.CarEvsBufferDescriptor
+android.car.evs.CarEvsManager
+android.car.evs.CarEvsManager$CarEvsStatusListener
+android.car.evs.CarEvsManager$CarEvsStreamCallback
+android.car.evs.CarEvsStatus
+android.car.hardware.CarHvacFanDirection
+android.car.hardware.CarPropertyConfig
+android.car.hardware.CarPropertyConfig$AreaConfig
+android.car.hardware.CarPropertyConfig$Builder
+android.car.hardware.CarPropertyValue
+android.car.hardware.CarSensorConfig
+android.car.hardware.CarSensorEvent
+android.car.hardware.CarSensorEvent$EnvironmentData
+android.car.hardware.CarSensorEvent$IgnitionStateData
+android.car.hardware.CarSensorEvent$NightData
+android.car.hardware.CarSensorEvent$GearData
+android.car.hardware.CarSensorEvent$ParkingBrakeData
+android.car.hardware.CarSensorEvent$FuelLevelData
+android.car.hardware.CarSensorEvent$OdometerData
+android.car.hardware.CarSensorEvent$RpmData
+android.car.hardware.CarSensorEvent$CarSpeedData
+android.car.hardware.CarSensorEvent$CarWheelTickDistanceData
+android.car.hardware.CarSensorEvent$CarAbsActiveData
+android.car.hardware.CarSensorEvent$CarTractionControlActiveData
+android.car.hardware.CarSensorEvent$CarFuelDoorOpenData
+android.car.hardware.CarSensorEvent$CarEvBatteryLevelData
+android.car.hardware.CarSensorEvent$CarEvChargePortOpenData
+android.car.hardware.CarSensorEvent$CarEvChargePortConnectedData
+android.car.hardware.CarSensorEvent$CarEvBatteryChargeRateData
+android.car.hardware.CarSensorEvent$CarEngineOilLevelData
+android.car.hardware.CarSensorManager
+android.car.hardware.CarSensorManager$OnSensorChangedListener
+android.car.hardware.CarVendorExtensionManager
+android.car.hardware.CarVendorExtensionManager$CarVendorExtensionCallback
+android.car.hardware.cabin.CarCabinManager
+android.car.hardware.cabin.CarCabinManager$CarCabinEventCallback
+android.car.hardware.hvac.CarHvacManager
+android.car.hardware.hvac.CarHvacManager$CarHvacEventCallback
+android.car.hardware.power.CarPowerManager
+android.car.hardware.power.CarPowerManager$CompletablePowerStateChangeFuture
+android.car.hardware.power.CarPowerManager$CarPowerStateListener
+android.car.hardware.power.CarPowerManager$CarPowerStateListenerWithCompletion
+android.car.hardware.power.CarPowerManager$CarPowerPolicyListener
+android.car.hardware.power.CarPowerPolicy
+android.car.hardware.power.CarPowerPolicyFilter
+android.car.hardware.power.CarPowerPolicyFilter$Builder
+android.car.hardware.power.PowerComponentUtil
+android.car.hardware.property.CarInternalErrorException
+android.car.hardware.property.CarPropertyEvent
+android.car.hardware.property.CarPropertyManager
+android.car.hardware.property.CarPropertyManager$CarPropertyEventCallback
+android.car.hardware.property.EvChargingConnectorType
+android.car.hardware.property.PropertyAccessDeniedSecurityException
+android.car.hardware.property.PropertyNotAvailableAndRetryException
+android.car.hardware.property.PropertyNotAvailableException
+android.car.hardware.property.VehicleElectronicTollCollectionCardStatus
+android.car.hardware.property.VehicleElectronicTollCollectionCardType
+android.car.hardware.property.VehicleHalStatusCode
+android.car.hardware.property.VehicleVendorPermission
+android.car.input.CarInputHandlingService
+android.car.input.CarInputHandlingService$InputFilter
+android.car.input.CarInputManager
+android.car.input.CarInputManager$CarInputCaptureCallback
+android.car.input.CustomInputEvent
+android.car.input.RotaryEvent
+android.car.media.CarAudioManager
+android.car.media.CarAudioManager$CarVolumeCallback
+android.car.media.CarAudioPatchHandle
+android.car.media.CarMediaIntents
+android.car.media.CarMediaManager
+android.car.media.CarMediaManager$MediaSourceChangedListener
+android.car.navigation.CarNavigationInstrumentCluster
+android.car.navigation.CarNavigationStatusManager
+android.car.occupantawareness.DriverMonitoringDetection
+android.car.occupantawareness.GazeDetection
+android.car.occupantawareness.OccupantAwarenessDetection
+android.car.occupantawareness.OccupantAwarenessManager
+android.car.occupantawareness.OccupantAwarenessManager$ChangeCallback
+android.car.occupantawareness.Point3D
+android.car.occupantawareness.SystemStatusEvent
+android.car.os.CarPerformanceManager
+android.car.os.CarPerformanceManager$SetSchedulerFailedException
+android.car.os.CarPerformanceManager$CpuAvailabilityChangeListener
+android.car.os.CpuAvailabilityInfo
+android.car.os.CpuAvailabilityInfo$Builder
+android.car.os.CpuAvailabilityMonitoringConfig
+android.car.os.CpuAvailabilityMonitoringConfig$Builder
+android.car.os.ThreadPolicyWithPriority
+android.car.projection.ProjectionOptions
+android.car.projection.ProjectionOptions$Builder
+android.car.projection.ProjectionStatus
+android.car.projection.ProjectionStatus$Builder
+android.car.projection.ProjectionStatus$MobileDevice
+android.car.projection.ProjectionStatus$MobileDevice$Builder
+android.car.settings.CarSettings
+android.car.settings.CarSettings$Global
+android.car.settings.CarSettings$Secure
+android.car.storagemonitoring.CarStorageMonitoringManager
+android.car.storagemonitoring.CarStorageMonitoringManager$IoStatsListener
+android.car.storagemonitoring.IoStats
+android.car.storagemonitoring.IoStatsEntry
+android.car.storagemonitoring.IoStatsEntry$Metrics
+android.car.storagemonitoring.LifetimeWriteInfo
+android.car.storagemonitoring.UidIoRecord
+android.car.storagemonitoring.WearEstimate
+android.car.storagemonitoring.WearEstimateChange
+android.car.telemetry.CarTelemetryManager
+android.car.telemetry.CarTelemetryManager$AddMetricsConfigCallback
+android.car.telemetry.CarTelemetryManager$MetricsReportCallback
+android.car.telemetry.CarTelemetryManager$ReportReadyListener
+android.car.test.CarLocationTestHelper
+android.car.test.CarTestManager
+android.car.user.CarUserManager
+android.car.user.CarUserManager$UserLifecycleEvent
+android.car.user.CarUserManager$UserLifecycleListener
+android.car.user.CarUserManager$UserSwitchUiCallback
+android.car.user.CommonResults
+android.car.user.ExperimentalCarUserManager
+android.car.user.OperationResult
+android.car.user.UserCreationResult
+android.car.user.UserIdentificationAssociationResponse
+android.car.user.UserLifecycleEventFilter
+android.car.user.UserLifecycleEventFilter$Builder
+android.car.user.UserRemovalResult
+android.car.user.UserStartResult
+android.car.user.UserStopResult
+android.car.user.UserSwitchResult
+android.car.util.concurrent.AndroidAsyncFuture
+android.car.util.concurrent.AndroidFuture
+android.car.util.concurrent.AsyncFuture
+android.car.vms.VmsAssociatedLayer
+android.car.vms.VmsAvailableLayers
+android.car.vms.VmsClient
+android.car.vms.VmsClientManager
+android.car.vms.VmsClientManager$VmsClientCallback
+android.car.vms.VmsLayer
+android.car.vms.VmsLayerDependency
+android.car.vms.VmsLayersOffering
+android.car.vms.VmsOperationRecorder
+android.car.vms.VmsOperationRecorder$Writer
+android.car.vms.VmsProviderInfo
+android.car.vms.VmsPublisherClientService
+android.car.vms.VmsRegistrationInfo
+android.car.vms.VmsSubscriberManager
+android.car.vms.VmsSubscriberManager$VmsSubscriberClientCallback
+android.car.vms.VmsSubscriptionHelper
+android.car.vms.VmsSubscriptionState
+android.car.watchdog.CarWatchdogManager
+android.car.watchdog.CarWatchdogManager$CarWatchdogClientCallback
+android.car.watchdog.CarWatchdogManager$ResourceOveruseListener
+android.car.watchdog.IoOveruseAlertThreshold
+android.car.watchdog.IoOveruseConfiguration
+android.car.watchdog.IoOveruseConfiguration$Builder
+android.car.watchdog.IoOveruseStats
+android.car.watchdog.IoOveruseStats$Builder
+android.car.watchdog.PackageKillableState
+android.car.watchdog.PerStateBytes
+android.car.watchdog.ResourceOveruseConfiguration
+android.car.watchdog.ResourceOveruseConfiguration$Builder
+android.car.watchdog.ResourceOveruseStats
+android.car.watchdog.ResourceOveruseStats$Builder
diff --git a/tests/carservice_unit_test/res/raw/car_built_in_api_classes.txt b/tests/carservice_unit_test/res/raw/car_built_in_api_classes.txt
new file mode 100644
index 0000000..ca159ad
--- /dev/null
+++ b/tests/carservice_unit_test/res/raw/car_built_in_api_classes.txt
@@ -0,0 +1,43 @@
+android.car.builtin.CarBuiltin
+android.car.builtin.PermissionHelper
+android.car.builtin.app.ActivityManagerHelper
+android.car.builtin.app.ActivityManagerHelper$ProcessObserverCallback
+android.car.builtin.app.KeyguardManagerHelper
+android.car.builtin.app.TaskInfoHelper
+android.car.builtin.app.VoiceInteractionHelper
+android.car.builtin.bluetooth.BluetoothHeadsetClientHelper
+android.car.builtin.bluetooth.le.AdvertisingSetCallbackHelper
+android.car.builtin.bluetooth.le.AdvertisingSetCallbackHelper$Callback
+android.car.builtin.bluetooth.le.AdvertisingSetHelper
+android.car.builtin.content.ContextHelper
+android.car.builtin.content.pm.PackageManagerHelper
+android.car.builtin.input.InputManagerHelper
+android.car.builtin.job.JobSchedulerHelper
+android.car.builtin.media.AudioManagerHelper
+android.car.builtin.media.AudioManagerHelper$AudioGainInfo
+android.car.builtin.media.AudioManagerHelper$AudioPatchInfo
+android.car.builtin.media.AudioManagerHelper$VolumeAndMuteReceiver
+android.car.builtin.os.BinderHelper
+android.car.builtin.os.BinderHelper$ShellCommandListener
+android.car.builtin.os.BuildHelper
+android.car.builtin.os.ParcelHelper
+android.car.builtin.os.ServiceManagerHelper
+android.car.builtin.os.SharedMemoryHelper
+android.car.builtin.os.SystemPropertiesHelper
+android.car.builtin.os.TraceHelper
+android.car.builtin.os.UserManagerHelper
+android.car.builtin.power.PowerManagerHelper
+android.car.builtin.provider.SettingsHelper
+android.car.builtin.util.AssistUtilsHelper
+android.car.builtin.util.AssistUtilsHelper$VoiceInteractionSessionShowCallbackHelper
+android.car.builtin.util.AssistUtilsHelper$VoiceInteractionSessionListenerHelper
+android.car.builtin.util.AtomicFileHelper
+android.car.builtin.util.EventLogHelper
+android.car.builtin.util.Slogf
+android.car.builtin.util.TimeUtils
+android.car.builtin.util.TimingsTraceLog
+android.car.builtin.util.ValidationHelper
+android.car.builtin.view.DisplayHelper
+android.car.builtin.view.KeyEventHelper
+android.car.builtin.widget.LockPatternHelper
+android.car.builtin.window.DisplayAreaOrganizerHelper
diff --git a/tests/carservice_unit_test/src/android/car/AnnotationTest.java b/tests/carservice_unit_test/src/android/car/AnnotationTest.java
index 15c6136..e76dc95 100644
--- a/tests/carservice_unit_test/src/android/car/AnnotationTest.java
+++ b/tests/carservice_unit_test/src/android/car/AnnotationTest.java
@@ -16,345 +16,39 @@
package android.car;
-import static com.google.common.truth.Truth.assertWithMessage;
+import static android.car.test.util.AnnotationHelper.checkForAnnotation;
-import android.car.annotation.AddedIn;
import android.car.annotation.AddedInOrBefore;
+import android.car.annotation.ApiRequirements;
+
+import androidx.test.core.app.ApplicationProvider;
+
+import com.android.car.R;
import org.junit.Test;
-import java.lang.reflect.Field;
-import java.lang.reflect.Method;
-import java.lang.reflect.Modifier;
-import java.util.ArrayList;
-import java.util.List;
+import java.io.IOException;
+import java.io.InputStream;
public final class AnnotationTest {
private static final String TAG = AnnotationTest.class.getSimpleName();
- /*
- * TODO(b/192692829): Add logic to populate this list automatically.
- * Currently this list is generate as follow:
- * $ m -j GenericCarApiBuilder
- * $ GenericCarApiBuilder --classes-only
- */
- //
- private static final String[] CAR_API_CLASSES = new String[] {
- "android.car.VehicleAreaDoor",
- "android.car.CarTransactionException",
- "android.car.occupantawareness.DriverMonitoringDetection",
- "android.car.occupantawareness.OccupantAwarenessDetection",
- "android.car.occupantawareness.Point3D",
- "android.car.occupantawareness.SystemStatusEvent",
- "android.car.occupantawareness.GazeDetection",
- "android.car.occupantawareness.OccupantAwarenessManager",
- "android.car.occupantawareness.OccupantAwarenessManager$ChangeCallback",
- "android.car.VehicleOilLevel",
- "android.car.VehiclePropertyType",
- "android.car.projection.ProjectionStatus",
- "android.car.projection.ProjectionStatus$Builder",
- "android.car.projection.ProjectionStatus$MobileDevice",
- "android.car.projection.ProjectionStatus$MobileDevice$Builder",
- "android.car.projection.ProjectionOptions",
- "android.car.projection.ProjectionOptions$Builder",
- "android.car.evs.CarEvsManager",
- "android.car.evs.CarEvsManager$CarEvsStatusListener",
- "android.car.evs.CarEvsManager$CarEvsStreamCallback",
- "android.car.evs.CarEvsStatus",
- "android.car.evs.CarEvsBufferDescriptor",
- "android.car.media.CarMediaManager",
- "android.car.media.CarMediaManager$MediaSourceChangedListener",
- "android.car.media.CarAudioPatchHandle",
- "android.car.media.CarAudioManager",
- "android.car.media.CarAudioManager$CarVolumeCallback",
- "android.car.media.CarMediaIntents",
- "android.car.content.pm.CarAppBlockingPolicy",
- "android.car.content.pm.CarPackageManager",
- "android.car.content.pm.AppBlockingPackageInfo",
- "android.car.content.pm.CarAppBlockingPolicyService",
- "android.car.VehicleAreaSeat",
- "android.car.CarOccupantZoneManager",
- "android.car.CarOccupantZoneManager$OccupantZoneInfo",
- "android.car.CarOccupantZoneManager$OccupantZoneConfigChangeListener",
- "android.car.VehicleSeatOccupancyState",
- "android.car.VehicleGear",
- "android.car.EvConnectorType",
- "android.car.user.CarUserManager",
- "android.car.user.CarUserManager$UserLifecycleEvent",
- "android.car.user.CarUserManager$UserLifecycleListener",
- "android.car.user.CarUserManager$UserSwitchUiCallback",
- "android.car.user.ExperimentalCarUserManager",
- "android.car.user.UserStopResult",
- "android.car.user.UserCreationResult",
- "android.car.user.UserRemovalResult",
- "android.car.user.CommonResults",
- "android.car.user.OperationResult",
- "android.car.user.UserLifecycleEventFilter",
- "android.car.user.UserLifecycleEventFilter$Builder",
- "android.car.user.UserStartResult",
- "android.car.user.UserIdentificationAssociationResponse",
- "android.car.user.UserSwitchResult",
- "android.car.VehicleLightState",
- "android.car.CarLibLog",
- "android.car.VehicleHvacFanDirection",
- "android.car.test.CarLocationTestHelper",
- "android.car.test.CarTestManager",
- "android.car.VehicleAreaType",
- "android.car.CarBugreportManager",
- "android.car.CarBugreportManager$CarBugreportManagerCallback",
- "android.car.CarInfoManager",
- "android.car.settings.CarSettings",
- "android.car.settings.CarSettings$Global",
- "android.car.settings.CarSettings$Secure",
- "android.car.AoapService",
- "android.car.VehiclePropertyAccess",
- "android.car.VehicleIgnitionState",
- "android.car.CarProjectionManager",
- "android.car.CarProjectionManager$CarProjectionListener",
- "android.car.CarProjectionManager$ProjectionKeyEventHandler",
- "android.car.CarProjectionManager$ProjectionStatusListener",
- "android.car.CarProjectionManager$ProjectionAccessPointCallback",
- "android.car.admin.StartUserInBackgroundResult",
- "android.car.admin.CarDevicePolicyManager",
- "android.car.admin.RemoveUserResult",
- "android.car.admin.StopUserResult",
- "android.car.admin.CreateUserResult",
- "android.car.CarNotConnectedException",
- "android.car.storagemonitoring.IoStatsEntry",
- "android.car.storagemonitoring.IoStatsEntry$Metrics",
- "android.car.storagemonitoring.IoStats",
- "android.car.storagemonitoring.LifetimeWriteInfo",
- "android.car.storagemonitoring.CarStorageMonitoringManager",
- "android.car.storagemonitoring.CarStorageMonitoringManager$IoStatsListener",
- "android.car.storagemonitoring.UidIoRecord",
- "android.car.storagemonitoring.WearEstimateChange",
- "android.car.storagemonitoring.WearEstimate",
- "android.car.CarManagerBase",
- "android.car.VehicleAreaWindow",
- "android.car.navigation.CarNavigationInstrumentCluster",
- "android.car.navigation.CarNavigationStatusManager",
- "android.car.VehicleAreaMirror",
- "android.car.input.CustomInputEvent",
- "android.car.input.CarInputHandlingService",
- "android.car.input.CarInputHandlingService$InputFilter",
- "android.car.input.RotaryEvent",
- "android.car.input.CarInputManager",
- "android.car.input.CarInputManager$CarInputCaptureCallback",
- "android.car.VehicleLightSwitch",
- "android.car.drivingstate.CarUxRestrictionsManager",
- "android.car.drivingstate.CarUxRestrictionsManager$OnUxRestrictionsChangedListener",
- "android.car.drivingstate.CarDrivingStateManager",
- "android.car.drivingstate.CarDrivingStateManager$CarDrivingStateEventListener",
- "android.car.drivingstate.CarUxRestrictions",
- "android.car.drivingstate.CarUxRestrictions$Builder",
- "android.car.drivingstate.CarDrivingStateEvent",
- "android.car.drivingstate.CarUxRestrictionsConfiguration",
- "android.car.drivingstate.CarUxRestrictionsConfiguration$Builder",
- "android.car.drivingstate.CarUxRestrictionsConfiguration$Builder$SpeedRange",
- "android.car.drivingstate.CarUxRestrictionsConfiguration$DrivingStateRestrictions",
- "android.car.app.CarActivityManager",
- "android.car.hardware.CarVendorExtensionManager",
- "android.car.hardware.CarVendorExtensionManager$CarVendorExtensionCallback",
- "android.car.hardware.CarPropertyConfig",
- "android.car.hardware.CarPropertyConfig$AreaConfig",
- "android.car.hardware.CarPropertyConfig$Builder",
- "android.car.hardware.CarHvacFanDirection",
- "android.car.hardware.CarPropertyValue",
- "android.car.hardware.CarSensorConfig",
- "android.car.hardware.CarSensorEvent",
- "android.car.hardware.CarSensorEvent$EnvironmentData",
- "android.car.hardware.CarSensorEvent$IgnitionStateData",
- "android.car.hardware.CarSensorEvent$NightData",
- "android.car.hardware.CarSensorEvent$GearData",
- "android.car.hardware.CarSensorEvent$ParkingBrakeData",
- "android.car.hardware.CarSensorEvent$FuelLevelData",
- "android.car.hardware.CarSensorEvent$OdometerData",
- "android.car.hardware.CarSensorEvent$RpmData",
- "android.car.hardware.CarSensorEvent$CarSpeedData",
- "android.car.hardware.CarSensorEvent$CarWheelTickDistanceData",
- "android.car.hardware.CarSensorEvent$CarAbsActiveData",
- "android.car.hardware.CarSensorEvent$CarTractionControlActiveData",
- "android.car.hardware.CarSensorEvent$CarFuelDoorOpenData",
- "android.car.hardware.CarSensorEvent$CarEvBatteryLevelData",
- "android.car.hardware.CarSensorEvent$CarEvChargePortOpenData",
- "android.car.hardware.CarSensorEvent$CarEvChargePortConnectedData",
- "android.car.hardware.CarSensorEvent$CarEvBatteryChargeRateData",
- "android.car.hardware.CarSensorEvent$CarEngineOilLevelData",
- "android.car.hardware.CarSensorManager",
- "android.car.hardware.CarSensorManager$OnSensorChangedListener",
- "android.car.hardware.hvac.CarHvacManager",
- "android.car.hardware.hvac.CarHvacManager$CarHvacEventCallback",
- "android.car.hardware.cabin.CarCabinManager",
- "android.car.hardware.cabin.CarCabinManager$CarCabinEventCallback",
- "android.car.hardware.property.PropertyAccessDeniedSecurityException",
- "android.car.hardware.property.EvChargingConnectorType",
- "android.car.hardware.property.PropertyNotAvailableException",
- "android.car.hardware.property.VehicleVendorPermission",
- "android.car.hardware.property.VehicleElectronicTollCollectionCardStatus",
- "android.car.hardware.property.VehicleHalStatusCode",
- "android.car.hardware.property.PropertyNotAvailableAndRetryException",
- "android.car.hardware.property.VehicleElectronicTollCollectionCardType",
- "android.car.hardware.property.CarInternalErrorException",
- "android.car.hardware.property.CarPropertyEvent",
- "android.car.hardware.property.CarPropertyManager",
- "android.car.hardware.property.CarPropertyManager$CarPropertyEventCallback",
- "android.car.hardware.power.CarPowerManager",
- "android.car.hardware.power.CarPowerManager$CompletablePowerStateChangeFuture",
- "android.car.hardware.power.CarPowerManager$CarPowerStateListener",
- "android.car.hardware.power.CarPowerManager$CarPowerStateListenerWithCompletion",
- "android.car.hardware.power.CarPowerManager$CarPowerPolicyListener",
- "android.car.hardware.power.PowerComponentUtil",
- "android.car.hardware.power.CarPowerPolicy",
- "android.car.hardware.power.CarPowerPolicyFilter",
- "android.car.hardware.power.CarPowerPolicyFilter$Builder",
- "android.car.CarFeatures",
- "android.car.Car",
- "android.car.Car$CarServiceLifecycleListener",
- "android.car.telemetry.CarTelemetryManager",
- "android.car.telemetry.CarTelemetryManager$AddMetricsConfigCallback",
- "android.car.telemetry.CarTelemetryManager$MetricsReportCallback",
- "android.car.telemetry.CarTelemetryManager$ReportReadyListener",
- "android.car.cluster.ClusterActivityState",
- "android.car.cluster.renderer.NavigationRenderer",
- "android.car.cluster.renderer.InstrumentClusterRenderer",
- "android.car.cluster.renderer.InstrumentClusterRenderingService",
- "android.car.cluster.CarInstrumentClusterManager",
- "android.car.cluster.CarInstrumentClusterManager$Callback",
- "android.car.cluster.ClusterHomeManager",
- "android.car.cluster.ClusterHomeManager$ClusterStateListener",
- "android.car.cluster.ClusterHomeManager$ClusterNavigationStateListener",
- "android.car.PortLocationType",
- "android.car.FuelType",
- "android.car.vms.VmsLayer",
- "android.car.vms.VmsOperationRecorder",
- "android.car.vms.VmsOperationRecorder$Writer",
- "android.car.vms.VmsAvailableLayers",
- "android.car.vms.VmsSubscriptionHelper",
- "android.car.vms.VmsClient",
- "android.car.vms.VmsLayerDependency",
- "android.car.vms.VmsRegistrationInfo",
- "android.car.vms.VmsSubscriptionState",
- "android.car.vms.VmsLayersOffering",
- "android.car.vms.VmsAssociatedLayer",
- "android.car.vms.VmsPublisherClientService",
- "android.car.vms.VmsSubscriberManager",
- "android.car.vms.VmsSubscriberManager$VmsSubscriberClientCallback",
- "android.car.vms.VmsProviderInfo",
- "android.car.vms.VmsClientManager",
- "android.car.vms.VmsClientManager$VmsClientCallback",
- "android.car.VehicleAreaWheel",
- "android.car.util.concurrent.AndroidFuture",
- "android.car.util.concurrent.AndroidAsyncFuture",
- "android.car.util.concurrent.AsyncFuture",
- "android.car.diagnostic.CarDiagnosticManager",
- "android.car.diagnostic.CarDiagnosticManager$OnDiagnosticEventListener",
- "android.car.diagnostic.FloatSensorIndex",
- "android.car.diagnostic.CarDiagnosticEvent",
- "android.car.diagnostic.CarDiagnosticEvent$Builder",
- "android.car.diagnostic.CarDiagnosticEvent$FuelSystemStatus",
- "android.car.diagnostic.CarDiagnosticEvent$SecondaryAirStatus",
- "android.car.diagnostic.CarDiagnosticEvent$FuelType",
- "android.car.diagnostic.CarDiagnosticEvent$IgnitionMonitor",
- "android.car.diagnostic.CarDiagnosticEvent$IgnitionMonitor$Decoder",
- "android.car.diagnostic.CarDiagnosticEvent$CommonIgnitionMonitors",
- "android.car.diagnostic.CarDiagnosticEvent$SparkIgnitionMonitors",
- "android.car.diagnostic.CarDiagnosticEvent$CompressionIgnitionMonitors",
- "android.car.diagnostic.IntegerSensorIndex",
- "android.car.VehiclePropertyIds",
- "android.car.VehicleUnit",
- "android.car.os.CarPerformanceManager",
- "android.car.os.CarPerformanceManager$CpuAvailabilityChangeListener",
- "android.car.os.CpuAvailabilityMonitoringConfig",
- "android.car.os.CpuAvailabilityMonitoringConfig$Builder",
- "android.car.os.CpuAvailabilityInfo",
- "android.car.os.CpuAvailabilityInfo$Builder",
- "android.car.watchdog.ResourceOveruseStats",
- "android.car.watchdog.ResourceOveruseStats$Builder",
- "android.car.watchdog.IoOveruseAlertThreshold",
- "android.car.watchdog.IoOveruseStats",
- "android.car.watchdog.IoOveruseStats$Builder",
- "android.car.watchdog.CarWatchdogManager",
- "android.car.watchdog.CarWatchdogManager$CarWatchdogClientCallback",
- "android.car.watchdog.CarWatchdogManager$ResourceOveruseListener",
- "android.car.watchdog.IoOveruseConfiguration",
- "android.car.watchdog.IoOveruseConfiguration$Builder",
- "android.car.watchdog.ResourceOveruseConfiguration",
- "android.car.watchdog.ResourceOveruseConfiguration$Builder",
- "android.car.watchdog.PerStateBytes",
- "android.car.watchdog.PackageKillableState",
- "android.car.CarAppFocusManager",
- "android.car.CarAppFocusManager$OnAppFocusChangedListener",
- "android.car.CarAppFocusManager$OnAppFocusOwnershipCallback"
- };
+ @Test
+ public void testCarAPIApiRequirementsAnnotation() throws Exception {
+ checkForAnnotation(readFile(R.raw.car_api_classes), ApiRequirements.class,
+ AddedInOrBefore.class);
+ }
@Test
- public void testClassAddedInAnnotation() throws Exception {
- List<String> errorsNoAnnotation = new ArrayList<>();
- List<String> errorsExtraAnnotation = new ArrayList<>();
-
- for (int i = 0; i < CAR_API_CLASSES.length; i++) {
- String className = CAR_API_CLASSES[i];
- Field[] fields = Class.forName(className).getDeclaredFields();
- for (int j = 0; j < fields.length; j++) {
- Field field = fields[j];
- boolean isAnnotated = containsAddedInAnnotation(field);
- boolean isPrivate = Modifier.isPrivate(field.getModifiers());
-
- if (isPrivate && isAnnotated) {
- errorsExtraAnnotation.add(className + " FIELD: " + field.getName());
- }
-
- if (!isPrivate && !isAnnotated) {
- errorsNoAnnotation.add(className + " FIELD: " + field.getName());
- }
- }
-
- Method[] methods = Class.forName(className).getDeclaredMethods();
- for (int j = 0; j < methods.length; j++) {
- Method method = methods[j];
-
- // These are some internal methods
- if (method.getName().contains("$")) continue;
-
- boolean isAnnotated = containsAddedInAnnotation(method);
- boolean isPrivate = Modifier.isPrivate(method.getModifiers());
-
- if (isPrivate && isAnnotated) {
- errorsExtraAnnotation.add(className + " METHOD: " + method.getName());
- }
-
- if (!isPrivate && !isAnnotated) {
- errorsNoAnnotation.add(className + " METHOD: " + method.getName());
- }
- }
- }
-
- StringBuilder errorFlatten = new StringBuilder();
- if (!errorsNoAnnotation.isEmpty()) {
- errorFlatten.append("Errors:\nNo AddedIn annotation found for-\n");
- for (int i = 0; i < errorsNoAnnotation.size(); i++) {
- errorFlatten.append(errorsNoAnnotation.get(i) + "\n");
- }
- }
-
- if (!errorsExtraAnnotation.isEmpty()) {
- errorFlatten.append("\nErrors:\nExtra AddedIn annotation found for-\n");
- for (int i = 0; i < errorsExtraAnnotation.size(); i++) {
- errorFlatten.append(errorsExtraAnnotation.get(i) + "\n");
- }
- }
-
- assertWithMessage(errorFlatten.toString())
- .that(errorsExtraAnnotation.size() + errorsNoAnnotation.size()).isEqualTo(0);
+ public void testCarBuiltInAPIAddedInAnnotation() throws Exception {
+ checkForAnnotation(readFile(R.raw.car_built_in_api_classes),
+ android.car.builtin.annotation.AddedIn.class);
}
- private boolean containsAddedInAnnotation(Field field) {
- return field.getAnnotation(AddedInOrBefore.class) != null
- || field.getAnnotation(AddedIn.class) != null;
- }
-
- private boolean containsAddedInAnnotation(Method method) {
- return method.getAnnotation(AddedInOrBefore.class) != null
- || method.getAnnotation(AddedIn.class) != null;
+ private String[] readFile(int resourceId) throws IOException {
+ try (InputStream configurationStream = ApplicationProvider.getApplicationContext()
+ .getResources().openRawResource(resourceId)) {
+ return new String(configurationStream.readAllBytes()).split("\n");
+ }
}
}
diff --git a/tests/carservice_unit_test/src/android/car/CarTest.java b/tests/carservice_unit_test/src/android/car/CarTest.java
index 9badc9c..3cfbfa3 100644
--- a/tests/carservice_unit_test/src/android/car/CarTest.java
+++ b/tests/carservice_unit_test/src/android/car/CarTest.java
@@ -18,7 +18,6 @@
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
import static com.google.common.truth.Truth.assertThat;
@@ -29,6 +28,8 @@
import static org.mockito.Mockito.when;
import android.annotation.Nullable;
+import android.car.test.mocks.AbstractExtendedMockitoTestCase;
+import android.car.test.util.ExceptionalFunction;
import android.content.ComponentName;
import android.content.Context;
import android.os.IBinder;
@@ -40,40 +41,39 @@
import com.android.car.CarServiceUtils;
import com.android.car.internal.ICarServiceHelper;
-import org.junit.After;
import org.junit.Before;
import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
import org.mockito.Mock;
-import org.mockito.MockitoSession;
import org.mockito.invocation.InvocationOnMock;
-import org.mockito.quality.Strictness;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.function.Consumer;
/**
* Unit test for Car API.
*/
-@RunWith(JUnit4.class)
-public class CarTest {
- private static final String TAG = CarTest.class.getSimpleName();
+public final class CarTest extends AbstractExtendedMockitoTestCase {
- private MockitoSession mMockingSession;
+ private static final String TAG = CarTest.class.getSimpleName();
+ private static final String PKG_NAME = "Bond.James.Bond";
@Mock
private Context mContext;
private int mGetServiceCallCount;
+
// It is tricky to mock this. So create placeholder version instead.
- private ICar.Stub mService = new ICar.Stub() {
+ private static final class FakeService extends ICar.Stub {
+
+ public ExceptionalFunction<String, CarVersion, RemoteException>
+ getTargetCarApiVersionMocker;
+
@Override
public void setSystemServerConnections(ICarServiceHelper helper,
- ICarResultReceiver receiver)
- throws RemoteException {
+ ICarResultReceiver receiver) throws RemoteException {
}
@Override
@@ -122,7 +122,10 @@
}
};
- private class LifecycleListener implements Car.CarServiceLifecycleListener {
+ private final FakeService mService = new FakeService();
+
+
+ private final class LifecycleListener implements Car.CarServiceLifecycleListener {
// Use thread safe one to prevent adding another lock for testing
private CopyOnWriteArrayList<Pair<Car, Boolean>> mEvents = new CopyOnWriteArrayList<>();
@@ -133,21 +136,16 @@
}
}
- private final LifecycleListener mLifecycleListener = new LifecycleListener();
+ private final LifecycleListener mLifecycleListener = new LifecycleListener();
@Before
public void setUp() {
- mMockingSession = mockitoSession()
- .initMocks(this)
- .mockStatic(ServiceManager.class)
- .strictness(Strictness.LENIENT)
- .startMocking();
- mGetServiceCallCount = 0;
+ when(mContext.getPackageName()).thenReturn(PKG_NAME);
}
- @After
- public void tearDown() {
- mMockingSession.finishMocking();
+ @Override
+ protected void onSessionBuilder(CustomMockitoSessionBuilder session) {
+ session.spyStatic(ServiceManager.class);
}
private void expectService(@Nullable IBinder service) {
@@ -295,4 +293,16 @@
// dispatch placeholder runnable and confirm that it is done.
runOnMainSyncSafe(() -> { });
}
+
+ private void onNewCar(Consumer<Car> action) throws Exception {
+ expectService(mService);
+
+ Car car = Car.createCar(mContext);
+ try {
+ assertThat(car).isNotNull();
+ action.accept(car);
+ } finally {
+ car.disconnect();
+ }
+ }
}
diff --git a/tests/carservice_unit_test/src/android/car/PlatformVersionMismatchExceptionTest.java b/tests/carservice_unit_test/src/android/car/PlatformVersionMismatchExceptionTest.java
new file mode 100644
index 0000000..5946297
--- /dev/null
+++ b/tests/carservice_unit_test/src/android/car/PlatformVersionMismatchExceptionTest.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2022 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;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.os.Parcel;
+
+import org.junit.Test;
+
+public final class PlatformVersionMismatchExceptionTest {
+
+ @Test
+ public void testExpectedVersionAndMessage() {
+ int expectedMajorVersion = 33;
+ int expectedMinorVersion = 1;
+
+ PlatformVersionMismatchException exception = new PlatformVersionMismatchException(
+ PlatformVersion.forMajorAndMinorVersions(expectedMajorVersion,
+ expectedMinorVersion));
+
+ PlatformVersion expectedApiVersion = exception.getMinimumPlatformApiVersion();
+
+ assertThat(expectedApiVersion.getMajorVersion()).isEqualTo(expectedMajorVersion);
+ assertThat(expectedApiVersion.getMinorVersion()).isEqualTo(expectedMinorVersion);
+
+ String message = exception.getMessage();
+ assertThat(message).contains("Expected version: " + expectedApiVersion);
+ assertThat(message).contains("Current version: " + Car.getPlatformVersion());
+ }
+
+ @Test
+ public void testExceptionParceable() {
+ int expectedMajorVersion = 33;
+ int expectedMinorVersion = 1;
+
+ PlatformVersionMismatchException exception = new PlatformVersionMismatchException(
+ PlatformVersion.forMajorAndMinorVersions(expectedMajorVersion,
+ expectedMinorVersion));
+
+ Parcel parcel = Parcel.obtain();
+ try {
+ exception.writeToParcel(parcel, 0);
+
+ // reset parcel position
+ parcel.setDataPosition(0);
+
+ PlatformVersionMismatchException exceptionFromParcel =
+ PlatformVersionMismatchException.CREATOR.createFromParcel(parcel);
+
+ assertThat(exceptionFromParcel.getMinimumPlatformApiVersion())
+ .isEqualTo(exception.getMinimumPlatformApiVersion());
+ } finally {
+ parcel.recycle();
+ }
+ }
+}
diff --git a/tests/carservice_unit_test/src/android/car/builtin/bluetooth/le/AdvertisingSetCallbackHelperTest.java b/tests/carservice_unit_test/src/android/car/builtin/bluetooth/le/AdvertisingSetCallbackHelperTest.java
new file mode 100644
index 0000000..aa6b376
--- /dev/null
+++ b/tests/carservice_unit_test/src/android/car/builtin/bluetooth/le/AdvertisingSetCallbackHelperTest.java
@@ -0,0 +1,253 @@
+/*
+ * Copyright (C) 2022 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.builtin.bluetooth.le;
+
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.anyInt;
+import static org.mockito.Mockito.anyString;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.timeout;
+import static org.mockito.Mockito.verify;
+
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothManager;
+import android.bluetooth.le.AdvertisingSet;
+import android.bluetooth.le.AdvertisingSetCallback;
+import android.bluetooth.le.AdvertisingSetParameters;
+import android.bluetooth.le.BluetoothLeAdvertiser;
+import android.util.Log;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.RequiresDevice;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnitRunner;
+
+import java.util.Objects;
+
+@RunWith(MockitoJUnitRunner.class)
+public final class AdvertisingSetCallbackHelperTest {
+
+ private static final String TAG = AdvertisingSetCallbackHelperTest.class.getSimpleName();
+
+ private AdvertisingSetCallbackHelper.Callback mProxy =
+ spy(new AdvertisingSetCallbackHelper.Callback() {});
+
+ @Mock
+ private AdvertisingSet mMockExpectedAdvertisingSet;
+
+ private static final int EXPECTED_TX_POWER = 123;
+ private static final int EXPECTED_STATUS = -123;
+ private static final boolean EXPECTED_ENABLE_FLAG = true;
+ private static final int EXPECTED_ADDRESS_TYPE = 314;
+ private static final String EXPECTED_ADDRESS = "1600 Amphitheatre Parkway";
+ // {@code 1 sec} should be more than enough time for a callback to be invoked.
+ private static final int CALLBACK_TIMEOUT_MS = 1000;
+
+ @Test
+ public void createRealCallbackFromProxy_delegateOnAdvertisingSetStarted() {
+ AdvertisingSetCallback realCallback =
+ AdvertisingSetCallbackHelper.createRealCallbackFromProxy(mProxy);
+
+ realCallback.onAdvertisingSetStarted(mMockExpectedAdvertisingSet, EXPECTED_TX_POWER,
+ EXPECTED_STATUS);
+
+ verify(mProxy).onAdvertisingSetStarted(mMockExpectedAdvertisingSet, EXPECTED_TX_POWER,
+ EXPECTED_STATUS);
+ }
+
+ @Test
+ public void createRealCallbackFromProxy_delegateOnAdvertisingSetStopped() {
+ AdvertisingSetCallback realCallback =
+ AdvertisingSetCallbackHelper.createRealCallbackFromProxy(mProxy);
+
+ realCallback.onAdvertisingSetStopped(mMockExpectedAdvertisingSet);
+
+ verify(mProxy).onAdvertisingSetStopped(mMockExpectedAdvertisingSet);
+ }
+
+ @Test
+ public void createRealCallbackFromProxy_delegateOnAdvertisingEnabled() {
+ AdvertisingSetCallback realCallback =
+ AdvertisingSetCallbackHelper.createRealCallbackFromProxy(mProxy);
+
+ realCallback.onAdvertisingEnabled(mMockExpectedAdvertisingSet, EXPECTED_ENABLE_FLAG,
+ EXPECTED_STATUS);
+
+ verify(mProxy).onAdvertisingEnabled(mMockExpectedAdvertisingSet, EXPECTED_ENABLE_FLAG,
+ EXPECTED_STATUS);
+ }
+
+ @Test
+ public void createRealCallbackFromProxy_delegateOnAdvertisingDataSet() {
+ AdvertisingSetCallback realCallback =
+ AdvertisingSetCallbackHelper.createRealCallbackFromProxy(mProxy);
+
+ realCallback.onAdvertisingDataSet(mMockExpectedAdvertisingSet, EXPECTED_STATUS);
+
+ verify(mProxy).onAdvertisingDataSet(mMockExpectedAdvertisingSet, EXPECTED_STATUS);
+ }
+
+ @Test
+ public void createRealCallbackFromProxy_delegateOnScanResponseDataSet() {
+ AdvertisingSetCallback realCallback =
+ AdvertisingSetCallbackHelper.createRealCallbackFromProxy(mProxy);
+
+ realCallback.onScanResponseDataSet(mMockExpectedAdvertisingSet, EXPECTED_STATUS);
+
+ verify(mProxy).onScanResponseDataSet(mMockExpectedAdvertisingSet, EXPECTED_STATUS);
+ }
+
+ @Test
+ public void createRealCallbackFromProxy_delegateOnAdvertisingParametersUpdated() {
+ AdvertisingSetCallback realCallback =
+ AdvertisingSetCallbackHelper.createRealCallbackFromProxy(mProxy);
+
+ realCallback.onAdvertisingParametersUpdated(mMockExpectedAdvertisingSet, EXPECTED_TX_POWER,
+ EXPECTED_STATUS);
+
+ verify(mProxy).onAdvertisingParametersUpdated(mMockExpectedAdvertisingSet,
+ EXPECTED_TX_POWER, EXPECTED_STATUS);
+ }
+
+ @Test
+ public void createRealCallbackFromProxy_delegateOnPeriodicAdvertisingParametersUpdated() {
+ AdvertisingSetCallback realCallback =
+ AdvertisingSetCallbackHelper.createRealCallbackFromProxy(mProxy);
+
+ realCallback.onPeriodicAdvertisingParametersUpdated(mMockExpectedAdvertisingSet,
+ EXPECTED_STATUS);
+
+ verify(mProxy).onPeriodicAdvertisingParametersUpdated(mMockExpectedAdvertisingSet,
+ EXPECTED_STATUS);
+ }
+
+ @Test
+ public void createRealCallbackFromProxy_delegateOnPeriodicAdvertisingDataSet() {
+ AdvertisingSetCallback realCallback =
+ AdvertisingSetCallbackHelper.createRealCallbackFromProxy(mProxy);
+
+ realCallback.onPeriodicAdvertisingDataSet(mMockExpectedAdvertisingSet,
+ EXPECTED_STATUS);
+
+ verify(mProxy).onPeriodicAdvertisingDataSet(mMockExpectedAdvertisingSet,
+ EXPECTED_STATUS);
+ }
+
+ @Test
+ public void createRealCallbackFromProxy_delegateOnPeriodicAdvertisingEnabled() {
+ AdvertisingSetCallback realCallback =
+ AdvertisingSetCallbackHelper.createRealCallbackFromProxy(mProxy);
+
+ realCallback.onPeriodicAdvertisingEnabled(mMockExpectedAdvertisingSet, EXPECTED_ENABLE_FLAG,
+ EXPECTED_STATUS);
+
+ verify(mProxy).onPeriodicAdvertisingEnabled(mMockExpectedAdvertisingSet,
+ EXPECTED_ENABLE_FLAG, EXPECTED_STATUS);
+ }
+
+ @Test
+ public void createRealCallbackFromProxy_delegateOnOwnAddressRead() {
+ AdvertisingSetCallback realCallback =
+ AdvertisingSetCallbackHelper.createRealCallbackFromProxy(mProxy);
+
+ realCallback.onOwnAddressRead(mMockExpectedAdvertisingSet, EXPECTED_ADDRESS_TYPE,
+ EXPECTED_ADDRESS);
+
+ verify(mProxy).onOwnAddressRead(mMockExpectedAdvertisingSet, EXPECTED_ADDRESS_TYPE,
+ EXPECTED_ADDRESS);
+ }
+
+ /**
+ * Integration test of {@link AdvertisingSetCallbackHelper#Callback}.
+ * 1. Use {@link BluetoothLeAdvertiser#startAdvertisingSet} to create a
+ * {@link AdvertisingSet} and trigger
+ * {@link AdvertisingSetCallback#onAdvertisingSetStarted}. In order to call
+ * {@link BluetoothLeAdvertiser#startAdvertisingSet}, we need to pass in
+ * {@code non-null}:
+ * a. {@link AdvertisingSetParameters} -- will get build error if {@code null}.
+ * b. {@link AdvertisingSetCallback} -- This is how we inject our proxy.
+ * 2. In the {@link AdvertisingSetCallback#onAdvertisingSetStarted} callback, invoke
+ * {@link AdvertisingSet#getOwnAddress}. This should then trigger the
+ * {@link AdvertisingSetCallback#onOwnAddressRead} callback.
+ *
+ * Test start: invoke {@link BluetoothLeAdvertiser#startAdvertisingSet}.
+ * Success criteria: {@link AdvertisingSetCallback#onOwnAddressRead} is invoked.
+ */
+ @Test
+ @RequiresDevice
+ public void integrationTest_onAdvertisingSetStarted_onOwnAddressRead() {
+ Log.d(TAG, "integrationTest_onAdvertisingSetStarted_onOwnAddressRead");
+
+ // Getting the {@link BluetoothLeAdvertiser}
+ BluetoothManager bluetoothManager = Objects.requireNonNull(
+ InstrumentationRegistry.getTargetContext()
+ .getSystemService(BluetoothManager.class));
+ BluetoothAdapter adapter = Objects.requireNonNull(bluetoothManager.getAdapter());
+ BluetoothLeAdvertiser advertiser = Objects.requireNonNull(
+ adapter.getBluetoothLeAdvertiser());
+
+ // Creating {@link AdvertisingSetCallback} for
+ // {@link BluetoothLeAdvertiser#startAdvertisingSet} (and its proxy for the test).
+ AdvertisingSetCallbackHelper.Callback proxyForOnOwnAddressRead =
+ new AdvertisingSetCallbackHelper.Callback() {
+ @Override
+ public void onAdvertisingSetStarted(AdvertisingSet advertisingSet, int txPower,
+ int status) {
+ Log.d(TAG, "onAdvertisingSetStarted invoked: advertisingSet="
+ + advertisingSet + ", txPower=" + txPower + ", status=" + status);
+
+ AdvertisingSetHelper.getOwnAddress(advertisingSet);
+ }
+
+ @Override
+ public void onOwnAddressRead(AdvertisingSet advertisingSet, int addressType,
+ String address) {
+ Log.d(TAG, "onOwnAddressRead invoked: advertisingSet="
+ + advertisingSet + ", addressType=" + addressType + ", address="
+ + address);
+ }
+ };
+
+ AdvertisingSetCallbackHelper.Callback spyCallbackProxy =
+ spy(proxyForOnOwnAddressRead);
+
+ AdvertisingSetCallback realCallback =
+ AdvertisingSetCallbackHelper.createRealCallbackFromProxy(spyCallbackProxy);
+
+ // Creating {@link AdvertisingSetParameters} for
+ // {@link BluetoothLeAdvertiser#startAdvertisingSet}
+ AdvertisingSetParameters advertisingSetParameters = new AdvertisingSetParameters.Builder()
+ .setConnectable(true)
+ .build();
+
+ // Invoking {@link BluetoothLeAdvertiser#startAdvertisingSet} will create an
+ // {@link AdvertisingSet} object, and invoke the callback
+ // {@link AdvertisingSetCallback#onAdvertisingSetStarted}, from which
+ // {@link AdvertisingSet#getOwnAddress} will be invoked, which in turn will invoke the
+ // callback {@link AdvertisingSetCallback#onOwnAddressRead}.
+ advertiser.startAdvertisingSet(advertisingSetParameters, /* advertiseData */ null,
+ /* scanResponse */ null, /* periodicParameters */ null, /* periodicData */ null,
+ realCallback);
+ Log.d(TAG, "startAdvertisingSet invoked");
+
+ verify(spyCallbackProxy, timeout(CALLBACK_TIMEOUT_MS))
+ .onOwnAddressRead(any(), anyInt(), anyString());
+ }
+}
diff --git a/tests/carservice_unit_test/src/android/car/builtin/bluetooth/le/AdvertisingSetHelperTest.java b/tests/carservice_unit_test/src/android/car/builtin/bluetooth/le/AdvertisingSetHelperTest.java
new file mode 100644
index 0000000..3312f2e
--- /dev/null
+++ b/tests/carservice_unit_test/src/android/car/builtin/bluetooth/le/AdvertisingSetHelperTest.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2022 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.builtin.bluetooth.le;
+
+import static org.mockito.Mockito.verify;
+
+import android.bluetooth.le.AdvertisingSet;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnitRunner;
+
+@RunWith(MockitoJUnitRunner.class)
+public final class AdvertisingSetHelperTest {
+
+ @Mock
+ private AdvertisingSet mMockAdvertisingSet;
+
+ @Test
+ public void getOwnAddress_delegate() {
+ AdvertisingSetHelper.getOwnAddress(mMockAdvertisingSet);
+
+ verify(mMockAdvertisingSet).getOwnAddress();
+ }
+}
diff --git a/tests/carservice_unit_test/src/android/car/os/CarPerformanceManagerUnitTest.java b/tests/carservice_unit_test/src/android/car/os/CarPerformanceManagerUnitTest.java
new file mode 100644
index 0000000..3c85a53
--- /dev/null
+++ b/tests/carservice_unit_test/src/android/car/os/CarPerformanceManagerUnitTest.java
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2022 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.os;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.junit.Assert.assertThrows;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.car.Car;
+import android.content.Context;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Looper;
+import android.os.RemoteException;
+import android.os.ServiceSpecificException;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnitRunner;
+
+@RunWith(MockitoJUnitRunner.class)
+public final class CarPerformanceManagerUnitTest {
+
+ private final Handler mMainHandler = new Handler(Looper.getMainLooper());
+
+ @Mock private Context mContext;
+ @Mock private Car mCar;
+ @Mock private IBinder mBinder;
+ @Mock private ICarPerformanceService mService;
+
+ private CarPerformanceManager mCarPerformanceManager;
+
+ @Before
+ public void setUp() {
+ when(mCar.getContext()).thenReturn(mContext);
+ when(mCar.getEventHandler()).thenReturn(mMainHandler);
+ when(mCar.handleRemoteExceptionFromCarService(any(RemoteException.class), any()))
+ .thenCallRealMethod();
+ when(mBinder.queryLocalInterface(anyString())).thenReturn(mService);
+ mCarPerformanceManager = new CarPerformanceManager(mCar, mBinder);
+ }
+
+ @Test
+ public void testSetThreadPriority() throws Exception {
+ ThreadPolicyWithPriority expected = new ThreadPolicyWithPriority(
+ ThreadPolicyWithPriority.SCHED_FIFO, /* priority= */ 1);
+
+ mCarPerformanceManager.setThreadPriority(expected);
+
+ verify(mService).setThreadPriority(anyInt(), eq(expected));
+ }
+
+ @Test
+ public void testSetThreadPriorityServiceSpecificExceptionFromService() throws Exception {
+ ThreadPolicyWithPriority p = new ThreadPolicyWithPriority(
+ ThreadPolicyWithPriority.SCHED_FIFO, /* priority= */ 1);
+ doThrow(new ServiceSpecificException(0)).when(mService).setThreadPriority(anyInt(), eq(p));
+
+ assertThrows(CarPerformanceManager.SetSchedulerFailedException.class,
+ () -> mCarPerformanceManager.setThreadPriority(p));
+ }
+
+ @Test
+ public void testSetThreadPriorityRemoteExceptionFromService() throws Exception {
+ ThreadPolicyWithPriority p = new ThreadPolicyWithPriority(
+ ThreadPolicyWithPriority.SCHED_FIFO, /* priority= */ 1);
+ doThrow(new RemoteException("")).when(mService).setThreadPriority(anyInt(), eq(p));
+
+ // Nothing should be thrown since {@link RemoteException} should be handled.
+ mCarPerformanceManager.setThreadPriority(p);
+ }
+
+ @Test
+ public void testGetThreadPriority() throws Exception {
+ ThreadPolicyWithPriority expected = new ThreadPolicyWithPriority(
+ ThreadPolicyWithPriority.SCHED_FIFO, /* priority= */ 1);
+ when(mService.getThreadPriority(anyInt())).thenReturn(expected);
+
+ ThreadPolicyWithPriority got = mCarPerformanceManager.getThreadPriority();
+
+ assertThat(got.getPolicy()).isEqualTo(expected.getPolicy());
+ assertThat(got.getPriority()).isEqualTo(expected.getPriority());
+ }
+
+ @Test
+ public void testGetThreadPriorityRemoteExceptionFromService() throws Exception {
+ when(mService.getThreadPriority(anyInt())).thenThrow(new RemoteException(""));
+
+ ThreadPolicyWithPriority got = mCarPerformanceManager.getThreadPriority();
+
+ assertThat(got.getPolicy()).isEqualTo(ThreadPolicyWithPriority.SCHED_DEFAULT);
+ assertThat(got.getPriority()).isEqualTo(0);
+ }
+}
diff --git a/tests/carservice_unit_test/src/android/car/os/ThreadPolicyWithPriorityUnitTest.java b/tests/carservice_unit_test/src/android/car/os/ThreadPolicyWithPriorityUnitTest.java
new file mode 100644
index 0000000..dcc8bc8
--- /dev/null
+++ b/tests/carservice_unit_test/src/android/car/os/ThreadPolicyWithPriorityUnitTest.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2022 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.os;
+
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
+
+import static org.testng.Assert.expectThrows;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.junit.MockitoJUnitRunner;
+
+@RunWith(MockitoJUnitRunner.class)
+public final class ThreadPolicyWithPriorityUnitTest {
+
+ @Test
+ public void testThreadPolicyWithPriorityMinPriority() {
+ int expectedPolicy = ThreadPolicyWithPriority.SCHED_FIFO;
+ int expectedPriority = ThreadPolicyWithPriority.PRIORITY_MIN;
+
+ ThreadPolicyWithPriority gotPolicyPriority = new ThreadPolicyWithPriority(
+ expectedPolicy, expectedPriority);
+
+ assertThat(gotPolicyPriority.getPolicy()).isEqualTo(expectedPolicy);
+ assertThat(gotPolicyPriority.getPriority()).isEqualTo(expectedPriority);
+ }
+
+ @Test
+ public void testThreadPolicyWithPriorityMaxPriority() {
+ int expectedPolicy = ThreadPolicyWithPriority.SCHED_FIFO;
+ int expectedPriority = ThreadPolicyWithPriority.PRIORITY_MAX;
+
+ ThreadPolicyWithPriority gotPolicyPriority = new ThreadPolicyWithPriority(
+ expectedPolicy, expectedPriority);
+
+ assertThat(gotPolicyPriority.getPolicy()).isEqualTo(expectedPolicy);
+ assertThat(gotPolicyPriority.getPriority()).isEqualTo(expectedPriority);
+ }
+
+ @Test
+ public void testThreadPolicyWithPriorityInvalidPolicy() {
+ int policy = -1;
+ int priority = ThreadPolicyWithPriority.PRIORITY_MIN;
+
+ IllegalArgumentException thrown = expectThrows(IllegalArgumentException.class,
+ () -> new ThreadPolicyWithPriority(policy, priority));
+
+ assertWithMessage("thrown exception has expected message").that(thrown).hasMessageThat()
+ .contains("invalid policy");
+ }
+
+ @Test
+ public void testThreadPolicyWithPriorityPriorityTooSmall() {
+ int policy = ThreadPolicyWithPriority.SCHED_FIFO;
+ int priority = ThreadPolicyWithPriority.PRIORITY_MIN - 1;
+
+ IllegalArgumentException thrown = expectThrows(IllegalArgumentException.class,
+ () -> new ThreadPolicyWithPriority(policy, priority));
+
+ assertWithMessage("thrown exception has expected message").that(thrown).hasMessageThat()
+ .contains("invalid priority");
+ }
+
+ @Test
+ public void testThreadPolicyWithPriorityPriorityTooLarge() {
+ int policy = ThreadPolicyWithPriority.SCHED_FIFO;
+ int priority = ThreadPolicyWithPriority.PRIORITY_MAX + 1;
+
+ IllegalArgumentException thrown = expectThrows(IllegalArgumentException.class,
+ () -> new ThreadPolicyWithPriority(policy, priority));
+
+ assertWithMessage("thrown exception has expected message").that(thrown).hasMessageThat()
+ .contains("invalid priority");
+ }
+
+ @Test
+ public void testDefaultThreadPolicy() {
+ ThreadPolicyWithPriority gotPolicyPriority = new ThreadPolicyWithPriority(
+ ThreadPolicyWithPriority.SCHED_DEFAULT, /* priority= */ 1);
+
+ assertThat(gotPolicyPriority.getPolicy()).isEqualTo(ThreadPolicyWithPriority.SCHED_DEFAULT);
+ assertThat(gotPolicyPriority.getPriority()).isEqualTo(0);
+ }
+}
diff --git a/tests/carservice_unit_test/src/android/car/test/ApiCheckerRuleTest.java b/tests/carservice_unit_test/src/android/car/test/ApiCheckerRuleTest.java
new file mode 100644
index 0000000..51d6387
--- /dev/null
+++ b/tests/carservice_unit_test/src/android/car/test/ApiCheckerRuleTest.java
@@ -0,0 +1,1097 @@
+/*
+ * Copyright (C) 2022 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.test;
+
+import static android.car.test.mocks.AndroidMockitoHelper.mockCarGetCarVersion;
+import static android.car.test.mocks.AndroidMockitoHelper.mockCarGetPlatformVersion;
+
+import static com.google.common.truth.Truth.assertWithMessage;
+
+import static org.junit.Assert.assertThrows;
+
+import android.car.Car;
+import android.car.CarVersion;
+import android.car.PlatformVersion;
+import android.car.PlatformVersionMismatchException;
+import android.car.annotation.AddedInOrBefore;
+import android.car.annotation.ApiRequirements;
+import android.car.test.ApiCheckerRule.ExpectedVersionAssumptionViolationException;
+import android.car.test.ApiCheckerRule.IgnoreInvalidApi;
+import android.car.test.ApiCheckerRule.IncompatibleApiRequirementsException;
+import android.car.test.ApiCheckerRule.PlatformVersionMismatchExceptionNotThrownException;
+import android.car.test.ApiCheckerRule.SupportedVersionTest;
+import android.car.test.ApiCheckerRule.UnsupportedVersionTest;
+import android.car.test.ApiCheckerRule.UnsupportedVersionTest.Behavior;
+import android.car.test.mocks.AbstractExtendedMockitoTestCase;
+import android.util.Log;
+
+import com.android.compatibility.common.util.ApiTest;
+import com.android.compatibility.common.util.CddTest;
+
+import org.junit.Test;
+import org.junit.runner.Description;
+import org.junit.runners.model.Statement;
+
+import java.lang.annotation.Annotation;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Objects;
+
+public final class ApiCheckerRuleTest extends AbstractExtendedMockitoTestCase {
+
+ private static final String TAG = ApiCheckerRuleTest.class.getSimpleName();
+
+ // Not a real test (i.e., it doesn't exist on this class), but it's passed to Description
+ private static final String TEST_METHOD_BEING_EXECUTED = "testAmI..OrNot";
+
+ // Similar, not a real method, but passed on annotation fields
+ private static final String METHOD_NAME_INVALID = "invalidIAm";
+
+ private static final String METHOD_NAME_REQUIRES_CAR_AND_PLATFORM_TIRAMISU_0 =
+ "requiresCarAndPlatformTiramisu0";
+ private static final String METHOD_NAME_REQUIRES_CAR_AND_PLATFORM_TIRAMISU_1 =
+ "requiresCarAndPlatformTiramisu1";
+
+ private static final String METHOD_NAME_ANNOTATED_WITH_RIGHT_SUPPORTED_VERSION_ANNOTATION =
+ "annotatedWithSupportedVersionAnnotationWithRightUnsupportedField";
+ private static final String METHOD_NAME_ANNOTATED_WITH_WRONG_SUPPORTED_VERSION_ANNOTATION =
+ "annotatedWithSupportedVersionAnnotationWithWrongUnsupportedField";
+ private static final String METHOD_NAME_ANNOTATED_WITH_RIGHT_UNSUPPORTED_VERSION_ANNOTATION =
+ "annotatedWithUnsupportedVersionAnnotationWithRightSupportedField";
+ private static final String METHOD_NAME_ANNOTATED_WITH_WRONG_UNSUPPORTED_VERSION_ANNOTATION =
+ "annotatedWithUnsupportedVersionAnnotationWithWrongSupportedField";
+
+ private static final String INVALID_API = "I.cant.believe.this.is.a.valid.API";
+ private static final String VALID_API_THAT_REQUIRES_CAR_AND_PLATFORM_TIRAMISU_0 =
+ "android.car.test.ApiCheckerRuleTest#"
+ + METHOD_NAME_REQUIRES_CAR_AND_PLATFORM_TIRAMISU_0;
+ private static final String VALID_API_THAT_REQUIRES_CAR_AND_PLATFORM_TIRAMISU_1 =
+ "android.car.test.ApiCheckerRuleTest#"
+ + METHOD_NAME_REQUIRES_CAR_AND_PLATFORM_TIRAMISU_1;
+ private static final String ANOTHER_VALID_API_THAT_REQUIRES_CAR_AND_PLATFORM_TIRAMISU_0 =
+ "android.car.test.ApiCheckerRuleTest#alsoRequiresCarAndPlatformTiramisu0";
+ private static final String VALID_API_WITHOUT_ANNOTATIONS =
+ "android.car.test.ApiCheckerRuleTest#apiYUNoAnnotated";
+ private static final String VALID_API_ADDED_IN_OR_BEFORE =
+ "android.car.test.ApiCheckerRuleTest#annotatedWithAddedInOrBefore";
+
+ private final SimpleStatement<Exception> mBaseStatement = new SimpleStatement<>();
+
+ @Override
+ protected void onSessionBuilder(CustomMockitoSessionBuilder session) {
+ session.spyStatic(Car.class);
+ }
+
+ @Test
+ public void failWhenTestMethodIsMissingAnnotations() throws Throwable {
+ Description testMethod = newTestMethod();
+ ApiCheckerRule rule = new ApiCheckerRule.Builder().build();
+
+ IllegalArgumentException e = assertThrows(IllegalArgumentException.class,
+ () -> rule.apply(new SimpleStatement<>(), testMethod).evaluate());
+ Log.d(TAG, "Exception: " + e);
+
+ assertWithMessage("exception (%s) message", e).that(e).hasMessageThat()
+ .matches(".*missing.*@ApiTest.*@CddTest.*annotation.*");
+ }
+
+ @Test
+ public void failWhenTestMethodHasApiTestAnnotationButItsNull() throws Throwable {
+ Description testMethod = newTestMethod(new ApiTestAnnotation((String[]) null));
+ ApiCheckerRule rule = new ApiCheckerRule.Builder().build();
+
+ IllegalArgumentException e = assertThrows(IllegalArgumentException.class,
+ () -> rule.apply(new SimpleStatement<>(), testMethod).evaluate());
+ Log.d(TAG, "Exception: " + e);
+
+ assertWithMessage("exception (%s) message", e).that(e).hasMessageThat()
+ .contains("empty @ApiTest annotation");
+ }
+
+ @Test
+ public void failWhenTestMethodHasApiTestAnnotationButItsEmpty() throws Throwable {
+ Description testMethod = newTestMethod(new ApiTestAnnotation(new String[0]));
+ ApiCheckerRule rule = new ApiCheckerRule.Builder().build();
+
+ IllegalArgumentException e = assertThrows(IllegalArgumentException.class,
+ () -> rule.apply(new SimpleStatement<>(), testMethod).evaluate());
+ Log.d(TAG, "Exception: " + e);
+
+ assertWithMessage("exception (%s) message", e).that(e).hasMessageThat()
+ .contains("empty @ApiTest annotation");
+ }
+
+ @Test
+ public void failWhenTestMethodHasApiTestAnnotationButItsInvalid() throws Throwable {
+ String methodName = INVALID_API;
+ Description testMethod = newTestMethod(new ApiTestAnnotation(methodName));
+ ApiCheckerRule rule = new ApiCheckerRule.Builder().build();
+
+ IllegalArgumentException e = assertThrows(IllegalArgumentException.class,
+ () -> rule.apply(new SimpleStatement<>(), testMethod).evaluate());
+ Log.d(TAG, "Exception: " + e);
+
+ assertWithMessage("exception (%s) message", e).that(e).hasMessageThat()
+ .contains(methodName);
+ }
+
+ @Test
+ public void failWhenTestMethodHasInvalidApiTestAnnotatedWithIgnoreInvalidApiButWithoutApiRequirements()
+ throws Throwable {
+ String methodName = INVALID_API;
+ Description testMethod = newTestMethod(new ApiTestAnnotation(methodName),
+ new IgnoreInvalidApiAnnotation("I validate, therefore am!"));
+ ApiCheckerRule rule = new ApiCheckerRule.Builder().build();
+
+ IllegalArgumentException e = assertThrows(IllegalArgumentException.class,
+ () -> rule.apply(new SimpleStatement<>(), testMethod).evaluate());
+ Log.d(TAG, "Exception: " + e);
+
+ assertWithMessage("exception (%s) message", e).that(e).hasMessageThat()
+ .matches(".*contains @IgnoreInvalidApi.*missing.*@ApiRequirements.*");
+ }
+
+ @Test
+ public void
+ passWhenTestMethodHasInvalidApiTestButAnnotatedWithIgnoreInvalidApiAndApiRequirements()
+ throws Throwable {
+ String methodName = INVALID_API;
+ Description testMethod = newTestMethod(new ApiTestAnnotation(methodName),
+ new IgnoreInvalidApiAnnotation("I validate, therefore am!"),
+ new ApiRequirementsAnnotation(ApiRequirements.CarVersion.TIRAMISU_1,
+ ApiRequirements.PlatformVersion.TIRAMISU_1));
+
+ ApiCheckerRule rule = new ApiCheckerRule.Builder().build();
+
+ rule.apply(mBaseStatement, testMethod).evaluate();
+
+ mBaseStatement.assertEvaluated();
+ }
+
+ @Test
+ public void failWhenTestMethodHasValidApiTestAnnotationButNoApiRequirements() throws Throwable {
+ String methodName = VALID_API_WITHOUT_ANNOTATIONS;
+ Description testMethod = newTestMethod(new ApiTestAnnotation(methodName));
+ ApiCheckerRule rule = new ApiCheckerRule.Builder().build();
+
+ IllegalArgumentException e = assertThrows(IllegalArgumentException.class,
+ () -> rule.apply(new SimpleStatement<>(), testMethod).evaluate());
+ Log.d(TAG, "Exception: " + e);
+
+ assertWithMessage("exception (%s) message", e).that(e).hasMessageThat()
+ .contains("@ApiRequirements");
+ }
+
+ @Test
+ public void passWhenTestMethodHasValidApiTestAnnotationWithAddedInOrBefore() throws Throwable {
+ String methodName = VALID_API_ADDED_IN_OR_BEFORE;
+ Description testMethod = newTestMethod(new ApiTestAnnotation(methodName));
+ ApiCheckerRule rule = new ApiCheckerRule.Builder().build();
+
+ rule.apply(mBaseStatement, testMethod).evaluate();
+
+ mBaseStatement.assertEvaluated();
+ }
+
+ @Test
+ public void failWhenTestMethodHasValidApiTestAnnotationAndApiRequirements() throws Throwable {
+ Description testMethod = newTestMethod(new ApiTestAnnotation(
+ VALID_API_THAT_REQUIRES_CAR_AND_PLATFORM_TIRAMISU_1),
+ new ApiRequirementsAnnotation(ApiRequirements.CarVersion.TIRAMISU_1,
+ ApiRequirements.PlatformVersion.TIRAMISU_1));
+ ApiCheckerRule rule = new ApiCheckerRule.Builder().build();
+
+ IllegalArgumentException e = assertThrows(IllegalArgumentException.class,
+ () -> rule.apply(new SimpleStatement<>(), testMethod).evaluate());
+ Log.d(TAG, "Exception: " + e);
+
+ assertWithMessage("exception (%s) message", e).that(e).hasMessageThat()
+ .contains("both @ApiTest and @ApiRequirements");
+ }
+
+ @Test
+ public void failWhenTestMethodHasCddTestAnnotationWithDeprecatedRequirement() throws Throwable {
+ Description testMethod = newTestMethod(CddTestAnnotation.forRequirement("Boot in 1s"));
+ ApiCheckerRule rule = new ApiCheckerRule.Builder().build();
+
+ IllegalArgumentException e = assertThrows(IllegalArgumentException.class,
+ () -> rule.apply(new SimpleStatement<>(), testMethod).evaluate());
+ Log.d(TAG, "Exception: " + e);
+
+ assertWithMessage("exception (%s) message", e).that(e).hasMessageThat().matches(
+ ".*CddTest.*deprecated.*requirement.*Boot in 1s.*requirements.*instead.*");
+ }
+
+ @Test
+ public void failWhenTestMethodHasCddTestAnnotationWithEmptyRequirements() throws Throwable {
+ Description testMethod = newTestMethod(CddTestAnnotation.forRequirements());
+ ApiCheckerRule rule = new ApiCheckerRule.Builder().build();
+
+ IllegalArgumentException e = assertThrows(IllegalArgumentException.class,
+ () -> rule.apply(new SimpleStatement<>(), testMethod).evaluate());
+ Log.d(TAG, "Exception: " + e);
+
+ assertWithMessage("exception (%s) message", e).that(e).hasMessageThat()
+ .matches(".*CddTest.*requirement.*empty.*");
+ }
+
+ @Test
+ public void failWhenTestMethodHasCddTestAnnotationWithInvalidRequirements() throws Throwable {
+ Description testMethod = newTestMethod(CddTestAnnotation.forRequirements("", " ", null));
+ ApiCheckerRule rule = new ApiCheckerRule.Builder().build();
+
+ IllegalArgumentException e = assertThrows(IllegalArgumentException.class,
+ () -> rule.apply(new SimpleStatement<>(), testMethod).evaluate());
+ Log.d(TAG, "Exception: " + e);
+
+ assertWithMessage("exception (%s) message", e).that(e).hasMessageThat()
+ .matches(".*CddTest.*empty.*requirement.*");
+ }
+
+ @Test
+ public void failWhenTestMethodHasCddTestAnnotationButNoApiRequirements() throws Throwable {
+ Description testMethod = newTestMethod(CddTestAnnotation.forRequirements("Boot in 10m"));
+ ApiCheckerRule rule = new ApiCheckerRule.Builder().build();
+
+ IllegalArgumentException e = assertThrows(IllegalArgumentException.class,
+ () -> rule.apply(new SimpleStatement<>(), testMethod).evaluate());
+ Log.d(TAG, "Exception: " + e);
+
+ assertWithMessage("exception (%s) message", e).that(e).hasMessageThat()
+ .matches(".*CddTest.*missing.*ApiRequirements.*");
+ }
+
+ @Test
+ public void passWhenTestMethodHasValidCddTestAnnotation() throws Throwable {
+ Description testMethod = newTestMethod(CddTestAnnotation.forRequirements("Boot in 10m"),
+ new ApiRequirementsAnnotation(ApiRequirements.CarVersion.TIRAMISU_1,
+ ApiRequirements.PlatformVersion.TIRAMISU_1));
+ ApiCheckerRule rule = new ApiCheckerRule.Builder().build();
+
+ rule.apply(mBaseStatement, testMethod).evaluate();
+
+ mBaseStatement.assertEvaluated();
+ }
+
+ @Test
+ public void passWhenTestMethodHasValidApiTestAnnotation() throws Throwable {
+ Description testMethod = newTestMethod(new ApiTestAnnotation(
+ VALID_API_THAT_REQUIRES_CAR_AND_PLATFORM_TIRAMISU_1));
+ ApiCheckerRule rule = new ApiCheckerRule.Builder().build();
+
+ rule.apply(mBaseStatement, testMethod).evaluate();
+
+ mBaseStatement.assertEvaluated();
+ }
+
+ @Test
+ public void passWhenTestMethodIsMissingAnnotationsButItsNotEnforced() throws Throwable {
+ Description testMethod = newTestMethod();
+ ApiCheckerRule rule = new ApiCheckerRule.Builder().disableAnnotationsCheck().build();
+
+ rule.apply(mBaseStatement, testMethod).evaluate();
+
+ mBaseStatement.assertEvaluated();
+ }
+
+ @Test
+ public void passWhenTestMethodIsMissingApiRequirementsButItsNotEnforced() throws Throwable {
+ String methodName = VALID_API_WITHOUT_ANNOTATIONS;
+ Description testMethod = newTestMethod(new ApiTestAnnotation(methodName));
+ ApiCheckerRule rule = new ApiCheckerRule.Builder().disableAnnotationsCheck().build();
+
+ rule.apply(mBaseStatement, testMethod).evaluate();
+
+ mBaseStatement.assertEvaluated();
+ }
+
+ @Test
+ public void failWhenTestMethodRunsOnUnsupportedVersionsAndDoesntThrow() throws Throwable {
+ String methodName = VALID_API_THAT_REQUIRES_CAR_AND_PLATFORM_TIRAMISU_1;
+ Description testMethod = newTestMethod(new ApiTestAnnotation(methodName));
+ ApiCheckerRule rule = new ApiCheckerRule.Builder().build();
+ mockCarGetCarVersion(CarVersion.VERSION_CODES.TIRAMISU_1);
+ mockCarGetPlatformVersion(PlatformVersion.VERSION_CODES.TIRAMISU_0);
+
+ PlatformVersionMismatchExceptionNotThrownException e = assertThrows(
+ PlatformVersionMismatchExceptionNotThrownException.class,
+ () -> rule.apply(mBaseStatement, testMethod).evaluate());
+ Log.d(TAG, "Exception: " + e);
+
+ assertWithMessage("exception.carVersion").that(e.getCarVersion())
+ .isEqualTo(CarVersion.VERSION_CODES.TIRAMISU_1);
+ assertWithMessage("exception.platformVersion").that(e.getPlatformVersion())
+ .isEqualTo(PlatformVersion.VERSION_CODES.TIRAMISU_0);
+ ApiRequirements apiRequirements = e.getApiRequirements();
+ assertWithMessage("exception.apiRequirements.minCarVersion")
+ .that(apiRequirements.minCarVersion().get())
+ .isEqualTo(CarVersion.VERSION_CODES.TIRAMISU_1);
+ assertWithMessage("exception.apiRequirements.minPlatformVersion")
+ .that(apiRequirements.minPlatformVersion().get())
+ .isEqualTo(PlatformVersion.VERSION_CODES.TIRAMISU_1);
+ }
+
+ @Test
+ public void passWhenTestMethodRunsOnUnsupportedVersionsAndDoesntThrow() throws Throwable {
+ String methodName = VALID_API_THAT_REQUIRES_CAR_AND_PLATFORM_TIRAMISU_1;
+ Description testMethod = newTestMethod(new ApiTestAnnotation(methodName));
+ ApiCheckerRule rule = new ApiCheckerRule.Builder().build();
+ CarVersion carVersion = CarVersion.VERSION_CODES.TIRAMISU_1;
+ PlatformVersion platformVersion = PlatformVersion.VERSION_CODES.TIRAMISU_0;
+ mockCarGetCarVersion(carVersion);
+ mockCarGetPlatformVersion(platformVersion);
+ mBaseStatement.failWith(
+ new PlatformVersionMismatchException(PlatformVersion.VERSION_CODES.TIRAMISU_1));
+
+ rule.apply(mBaseStatement, testMethod).evaluate();
+
+ mBaseStatement.assertEvaluated();
+ }
+
+ @Test
+ public void passWhenTestMethodContainsCompatibleApiRequirements() throws Throwable {
+ Description testMethod = newTestMethod(new ApiTestAnnotation(
+ VALID_API_THAT_REQUIRES_CAR_AND_PLATFORM_TIRAMISU_0,
+ ANOTHER_VALID_API_THAT_REQUIRES_CAR_AND_PLATFORM_TIRAMISU_0));
+ ApiCheckerRule rule = new ApiCheckerRule.Builder().build();
+
+ rule.apply(mBaseStatement, testMethod).evaluate();
+
+ mBaseStatement.assertEvaluated();
+ }
+
+ @Test
+ public void failWhenTestMethodContainsIncompatibleApiRequirements() throws Throwable {
+ Description testMethod = newTestMethod(new ApiTestAnnotation(
+ VALID_API_THAT_REQUIRES_CAR_AND_PLATFORM_TIRAMISU_0,
+ VALID_API_THAT_REQUIRES_CAR_AND_PLATFORM_TIRAMISU_1));
+ ApiCheckerRule rule = new ApiCheckerRule.Builder().build();
+
+ IncompatibleApiRequirementsException e = assertThrows(
+ IncompatibleApiRequirementsException.class,
+ () -> rule.apply(mBaseStatement, testMethod).evaluate());
+ Log.d(TAG, "Exception: " + e);
+
+ assertWithMessage("apis on exception").that(e.getApis()).containsExactly(
+ VALID_API_THAT_REQUIRES_CAR_AND_PLATFORM_TIRAMISU_0,
+ VALID_API_THAT_REQUIRES_CAR_AND_PLATFORM_TIRAMISU_1).inOrder();
+
+ List<ApiRequirements> apiRequirements = e.getApiRequirements();
+ assertWithMessage("apiRequirements on exception").that(apiRequirements).hasSize(2);
+
+ ApiRequirements apiRequirements0 = apiRequirements.get(0);
+ assertWithMessage("apiRequirements[0].minCarVersion on exception")
+ .that(apiRequirements0.minCarVersion())
+ .isEqualTo(ApiRequirements.CarVersion.TIRAMISU_0);
+ assertWithMessage("apiRequirements[0].minPlatformVersion on exception")
+ .that(apiRequirements0.minPlatformVersion())
+ .isEqualTo(ApiRequirements.PlatformVersion.TIRAMISU_0);
+
+ ApiRequirements apiRequirements1 = apiRequirements.get(1);
+ assertWithMessage("apiRequirements[0].minCarVersion on exception")
+ .that(apiRequirements1.minCarVersion())
+ .isEqualTo(ApiRequirements.CarVersion.TIRAMISU_1);
+ assertWithMessage("apiRequirements[0].minPlatformVersion on exception")
+ .that(apiRequirements1.minPlatformVersion())
+ .isEqualTo(ApiRequirements.PlatformVersion.TIRAMISU_1);
+ }
+
+ @Test
+ public void failWhenUnsupportedVersionDoesNotHaveSupportedVersionTest() throws Throwable {
+ Description testMethod = newTestMethod(new UnsupportedVersionTestAnnotation(""));
+
+ ApiCheckerRule rule = new ApiCheckerRule.Builder().build();
+
+ IllegalArgumentException e = assertThrows(IllegalArgumentException.class,
+ () -> rule.apply(mBaseStatement, testMethod).evaluate());
+ Log.d(TAG, "Exception: " + e);
+ assertWithMessage("exception.message").that(e).hasMessageThat()
+ .contains("missing supportedVersionTest");
+ }
+
+ @Test
+ public void failWhenUnsupportedVersionTestPointsToInvalidMethod() throws Throwable {
+ Description testMethod = newTestMethod(
+ new UnsupportedVersionTestAnnotation("supportedIAm"));
+
+ ApiCheckerRule rule = new ApiCheckerRule.Builder().build();
+
+ IllegalArgumentException e = assertThrows(IllegalArgumentException.class,
+ () -> rule.apply(mBaseStatement, testMethod).evaluate());
+ Log.d(TAG, "Exception: " + e);
+ assertWithMessage("exception.message").that(e).hasMessageThat()
+ .containsMatch(".*invalid supportedVersionTest.*supportedIAm.*");
+ }
+
+ @Test
+ public void failWhenUnsupportedVersionTestPointsToValidMethodWithoutSupportedVersionAnnotation()
+ throws Throwable {
+ Description testMethod = newTestMethod(new UnsupportedVersionTestAnnotation(
+ METHOD_NAME_REQUIRES_CAR_AND_PLATFORM_TIRAMISU_0));
+
+ ApiCheckerRule rule = new ApiCheckerRule.Builder().build();
+
+ IllegalArgumentException e = assertThrows(IllegalArgumentException.class,
+ () -> rule.apply(mBaseStatement, testMethod).evaluate());
+ Log.d(TAG, "Exception: " + e);
+ assertWithMessage("exception.message").that(e).hasMessageThat()
+ .containsMatch(".*invalid supportedVersionTest.*"
+ + METHOD_NAME_REQUIRES_CAR_AND_PLATFORM_TIRAMISU_0
+ + ".*annotated with @SupportedVersionTest");
+ }
+
+ @Test
+ public void
+ failWhenUnsupportedVersionTestPointsToValidMethodWithInvalidSupportedVersionAnnotation()
+ throws Throwable {
+ Description testMethod = newTestMethod(new UnsupportedVersionTestAnnotation(
+ METHOD_NAME_ANNOTATED_WITH_WRONG_SUPPORTED_VERSION_ANNOTATION));
+
+ ApiCheckerRule rule = new ApiCheckerRule.Builder().build();
+
+ IllegalArgumentException e = assertThrows(IllegalArgumentException.class,
+ () -> rule.apply(mBaseStatement, testMethod).evaluate());
+ Log.d(TAG, "Exception: " + e);
+ assertWithMessage("exception.message").that(e).hasMessageThat()
+ .containsMatch(".*invalid unsupportedVersionTest.*"
+ + METHOD_NAME_INVALID
+ + ".*method "
+ + METHOD_NAME_ANNOTATED_WITH_WRONG_SUPPORTED_VERSION_ANNOTATION
+ + ".*should be.*" + TEST_METHOD_BEING_EXECUTED);
+ }
+
+ @Test
+ public void failWhenTestHaveBothUnsupportedAndSupportedVersionTestAnnotations()
+ throws Throwable {
+ Description testMethod = newTestMethod(
+ new UnsupportedVersionTestAnnotation(
+ VALID_API_THAT_REQUIRES_CAR_AND_PLATFORM_TIRAMISU_0),
+ new SupportedVersionTestAnnotation(
+ VALID_API_THAT_REQUIRES_CAR_AND_PLATFORM_TIRAMISU_0));
+
+ ApiCheckerRule rule = new ApiCheckerRule.Builder().build();
+
+ IllegalArgumentException e = assertThrows(IllegalArgumentException.class,
+ () -> rule.apply(mBaseStatement, testMethod).evaluate());
+ Log.d(TAG, "Exception: " + e);
+ assertWithMessage("exception.message").that(e).hasMessageThat()
+ .contains("either supportedVersionTest or unsupportedVersionTest, not both");
+ }
+
+ @Test
+ public void ignoreTestWithUnsupportedVersionTest_DEFAULT_OnSupportedVersion() throws Throwable {
+ ignoreTestWithUnsupportedVersionTest_DEFAULT_or_EXPECT_THROWS_OnSupportedVersion(
+ /*behavior= */ null);
+ }
+
+ @Test
+ public void ignoreTestWithUnsupportedVersionTest_EXPECT_THROWS_OnSupportedVersion()
+ throws Throwable {
+ ignoreTestWithUnsupportedVersionTest_DEFAULT_or_EXPECT_THROWS_OnSupportedVersion(
+ Behavior.EXPECT_THROWS_VERSION_MISMATCH_EXCEPTION);
+ }
+
+ private void ignoreTestWithUnsupportedVersionTest_DEFAULT_or_EXPECT_THROWS_OnSupportedVersion(
+ Behavior behavior) throws Throwable {
+ Description testMethod = newTestMethod(
+ METHOD_NAME_ANNOTATED_WITH_RIGHT_UNSUPPORTED_VERSION_ANNOTATION,
+ new ApiTestAnnotation(
+ VALID_API_THAT_REQUIRES_CAR_AND_PLATFORM_TIRAMISU_1),
+ new UnsupportedVersionTestAnnotation(behavior,
+ METHOD_NAME_ANNOTATED_WITH_RIGHT_SUPPORTED_VERSION_ANNOTATION));
+ mockCarGetCarVersion(CarVersion.VERSION_CODES.TIRAMISU_1);
+ mockCarGetPlatformVersion(PlatformVersion.VERSION_CODES.TIRAMISU_1);
+
+ ApiCheckerRule rule = new ApiCheckerRule.Builder().build();
+
+ ExpectedVersionAssumptionViolationException e = assertThrows(
+ ExpectedVersionAssumptionViolationException.class,
+ () -> rule.apply(mBaseStatement, testMethod).evaluate());
+ Log.d(TAG, "Exception: " + e);
+
+ assertWithMessage("exception.carVersion").that(e.getCarVersion())
+ .isEqualTo(CarVersion.VERSION_CODES.TIRAMISU_1);
+ assertWithMessage("exception.platformVersion").that(e.getPlatformVersion())
+ .isEqualTo(PlatformVersion.VERSION_CODES.TIRAMISU_1);
+ ApiRequirements apiRequirements = e.getApiRequirements();
+ assertWithMessage("exception.apiRequirements.minCarVersion")
+ .that(apiRequirements.minCarVersion().get())
+ .isEqualTo(CarVersion.VERSION_CODES.TIRAMISU_1);
+ assertWithMessage("exception.apiRequirements.minPlatformVersion")
+ .that(apiRequirements.minPlatformVersion().get())
+ .isEqualTo(PlatformVersion.VERSION_CODES.TIRAMISU_1);
+
+ }
+
+ @Test
+ public void runTestWithUnsupportedVersionTest_DEFAULT_OnUnsupportedVersion()
+ throws Throwable {
+ runTestWithUnsupportedVersionTest_DEFAULT_or_EXPECT_THROWS_OnUnsupportedVersion(
+ /* behavior= */ null);
+ }
+
+ @Test
+ public void runTestWithUnsupportedVersionTest_EXPECT_THROWS_OnUnsupportedVersion()
+ throws Throwable {
+ runTestWithUnsupportedVersionTest_DEFAULT_or_EXPECT_THROWS_OnUnsupportedVersion(
+ Behavior.EXPECT_THROWS_VERSION_MISMATCH_EXCEPTION);
+ }
+
+ private void runTestWithUnsupportedVersionTest_DEFAULT_or_EXPECT_THROWS_OnUnsupportedVersion(
+ Behavior behavior) throws Throwable {
+ Description testMethod = newTestMethod(
+ METHOD_NAME_ANNOTATED_WITH_RIGHT_UNSUPPORTED_VERSION_ANNOTATION,
+ new ApiTestAnnotation(
+ VALID_API_THAT_REQUIRES_CAR_AND_PLATFORM_TIRAMISU_1),
+ new UnsupportedVersionTestAnnotation(behavior,
+ METHOD_NAME_ANNOTATED_WITH_RIGHT_SUPPORTED_VERSION_ANNOTATION));
+ mockCarGetCarVersion(CarVersion.VERSION_CODES.TIRAMISU_1);
+ mockCarGetPlatformVersion(PlatformVersion.VERSION_CODES.TIRAMISU_0);
+
+ ApiCheckerRule rule = new ApiCheckerRule.Builder().build();
+
+ PlatformVersionMismatchExceptionNotThrownException e = assertThrows(
+ PlatformVersionMismatchExceptionNotThrownException.class,
+ () -> rule.apply(mBaseStatement, testMethod).evaluate());
+ Log.d(TAG, "Exception: " + e);
+
+ assertWithMessage("exception.carVersion").that(e.getCarVersion())
+ .isEqualTo(CarVersion.VERSION_CODES.TIRAMISU_1);
+ assertWithMessage("exception.platformVersion").that(e.getPlatformVersion())
+ .isEqualTo(PlatformVersion.VERSION_CODES.TIRAMISU_0);
+ ApiRequirements apiRequirements = e.getApiRequirements();
+ assertWithMessage("exception.apiRequirements.minCarVersion")
+ .that(apiRequirements.minCarVersion().get())
+ .isEqualTo(CarVersion.VERSION_CODES.TIRAMISU_1);
+ assertWithMessage("exception.apiRequirements.minPlatformVersion")
+ .that(apiRequirements.minPlatformVersion().get())
+ .isEqualTo(PlatformVersion.VERSION_CODES.TIRAMISU_1);
+ }
+
+ @Test
+ public void runTestWithUnsupportedVersionTest_EXPECT_PASS_OnSupportedVersion()
+ throws Throwable {
+ Description testMethod = newTestMethod(
+ METHOD_NAME_ANNOTATED_WITH_RIGHT_UNSUPPORTED_VERSION_ANNOTATION,
+ new ApiTestAnnotation(
+ VALID_API_THAT_REQUIRES_CAR_AND_PLATFORM_TIRAMISU_1),
+ new UnsupportedVersionTestAnnotation(Behavior.EXPECT_PASS,
+ METHOD_NAME_ANNOTATED_WITH_RIGHT_SUPPORTED_VERSION_ANNOTATION));
+ mockCarGetCarVersion(CarVersion.VERSION_CODES.TIRAMISU_1);
+ mockCarGetPlatformVersion(PlatformVersion.VERSION_CODES.TIRAMISU_1);
+
+ ApiCheckerRule rule = new ApiCheckerRule.Builder().build();
+
+ ExpectedVersionAssumptionViolationException e = assertThrows(
+ ExpectedVersionAssumptionViolationException.class,
+ () -> rule.apply(mBaseStatement, testMethod).evaluate());
+ Log.d(TAG, "Exception: " + e);
+
+ assertWithMessage("exception.carVersion").that(e.getCarVersion())
+ .isEqualTo(CarVersion.VERSION_CODES.TIRAMISU_1);
+ assertWithMessage("exception.platformVersion").that(e.getPlatformVersion())
+ .isEqualTo(PlatformVersion.VERSION_CODES.TIRAMISU_1);
+ ApiRequirements apiRequirements = e.getApiRequirements();
+ assertWithMessage("exception.apiRequirements.minCarVersion")
+ .that(apiRequirements.minCarVersion().get())
+ .isEqualTo(CarVersion.VERSION_CODES.TIRAMISU_1);
+ assertWithMessage("exception.apiRequirements.minPlatformVersion")
+ .that(apiRequirements.minPlatformVersion().get())
+ .isEqualTo(PlatformVersion.VERSION_CODES.TIRAMISU_1);
+ }
+
+ @Test
+ public void runTestWithUnsupportedVersionTest_EXPECT_PASS_OnUnsupportedVersion()
+ throws Throwable {
+ Description testMethod = newTestMethod(
+ METHOD_NAME_ANNOTATED_WITH_RIGHT_UNSUPPORTED_VERSION_ANNOTATION,
+ new ApiTestAnnotation(
+ VALID_API_THAT_REQUIRES_CAR_AND_PLATFORM_TIRAMISU_1),
+ new UnsupportedVersionTestAnnotation(Behavior.EXPECT_PASS,
+ METHOD_NAME_ANNOTATED_WITH_RIGHT_SUPPORTED_VERSION_ANNOTATION));
+ mockCarGetCarVersion(CarVersion.VERSION_CODES.TIRAMISU_1);
+ mockCarGetPlatformVersion(PlatformVersion.VERSION_CODES.TIRAMISU_0);
+
+ ApiCheckerRule rule = new ApiCheckerRule.Builder().build();
+
+ rule.apply(mBaseStatement, testMethod).evaluate();
+
+ mBaseStatement.assertEvaluated();
+ }
+
+ @Test
+ public void failTestWithSupportedVersionMissingUnsupported() throws Throwable {
+ Description testMethod = newTestMethod(new SupportedVersionTestAnnotation(""));
+
+ ApiCheckerRule rule = new ApiCheckerRule.Builder().build();
+
+ IllegalArgumentException e = assertThrows(IllegalArgumentException.class,
+ () -> rule.apply(mBaseStatement, testMethod).evaluate());
+ Log.d(TAG, "Exception: " + e);
+ assertWithMessage("exception.message").that(e).hasMessageThat()
+ .contains("missing unsupportedVersionTest");
+ }
+
+ @Test
+ public void failTestWithSupportedVersionWithWrongUnsupported() throws Throwable {
+ String methodName = VALID_API_THAT_REQUIRES_CAR_AND_PLATFORM_TIRAMISU_1;
+ Description testMethod = newTestMethod(new ApiTestAnnotation(methodName),
+ new SupportedVersionTestAnnotation(
+ METHOD_NAME_ANNOTATED_WITH_WRONG_UNSUPPORTED_VERSION_ANNOTATION));
+ mockCarGetCarVersion(CarVersion.VERSION_CODES.TIRAMISU_1);
+ mockCarGetPlatformVersion(PlatformVersion.VERSION_CODES.TIRAMISU_1);
+
+ ApiCheckerRule rule = new ApiCheckerRule.Builder().build();
+
+ IllegalArgumentException e = assertThrows(IllegalArgumentException.class,
+ () -> rule.apply(mBaseStatement, testMethod).evaluate());
+ Log.d(TAG, "Exception: " + e);
+
+ assertWithMessage("exception.message").that(e).hasMessageThat()
+ .containsMatch(".*invalid supportedVersionTest.*"
+ + "method.*"
+ + METHOD_NAME_ANNOTATED_WITH_WRONG_UNSUPPORTED_VERSION_ANNOTATION
+ + ".*should be.*" + TEST_METHOD_BEING_EXECUTED);
+ }
+
+ @Test
+ public void runTestWithSupportedVersionTestOnSupportedVersion() throws Throwable {
+ String methodName = VALID_API_THAT_REQUIRES_CAR_AND_PLATFORM_TIRAMISU_1;
+ Description testMethod = newTestMethod(
+ METHOD_NAME_ANNOTATED_WITH_RIGHT_SUPPORTED_VERSION_ANNOTATION,
+ new ApiTestAnnotation(methodName),
+ new SupportedVersionTestAnnotation(
+ METHOD_NAME_ANNOTATED_WITH_RIGHT_UNSUPPORTED_VERSION_ANNOTATION));
+ mockCarGetCarVersion(CarVersion.VERSION_CODES.TIRAMISU_1);
+ mockCarGetPlatformVersion(PlatformVersion.VERSION_CODES.TIRAMISU_1);
+
+ ApiCheckerRule rule = new ApiCheckerRule.Builder().build();
+
+ rule.apply(mBaseStatement, testMethod).evaluate();
+
+ mBaseStatement.assertEvaluated();
+ }
+
+ @Test
+ public void ignoreTestWithSupportedVersionTestOnUnsupportedVersion() throws Throwable {
+ String methodName = VALID_API_THAT_REQUIRES_CAR_AND_PLATFORM_TIRAMISU_1;
+ Description testMethod = newTestMethod(
+ METHOD_NAME_ANNOTATED_WITH_RIGHT_SUPPORTED_VERSION_ANNOTATION,
+ new ApiTestAnnotation(methodName),
+ new SupportedVersionTestAnnotation(
+ METHOD_NAME_ANNOTATED_WITH_RIGHT_UNSUPPORTED_VERSION_ANNOTATION));
+ mockCarGetCarVersion(CarVersion.VERSION_CODES.TIRAMISU_1);
+ mockCarGetPlatformVersion(PlatformVersion.VERSION_CODES.TIRAMISU_0);
+
+ ApiCheckerRule rule = new ApiCheckerRule.Builder().build();
+
+ ExpectedVersionAssumptionViolationException e = assertThrows(
+ ExpectedVersionAssumptionViolationException.class,
+ () -> rule.apply(mBaseStatement, testMethod).evaluate());
+ Log.d(TAG, "Exception: " + e);
+
+ assertWithMessage("exception.carVersion").that(e.getCarVersion())
+ .isEqualTo(CarVersion.VERSION_CODES.TIRAMISU_1);
+ assertWithMessage("exception.platformVersion").that(e.getPlatformVersion())
+ .isEqualTo(PlatformVersion.VERSION_CODES.TIRAMISU_0);
+ ApiRequirements apiRequirements = e.getApiRequirements();
+ assertWithMessage("exception.apiRequirements.minCarVersion")
+ .that(apiRequirements.minCarVersion().get())
+ .isEqualTo(CarVersion.VERSION_CODES.TIRAMISU_1);
+ assertWithMessage("exception.apiRequirements.minPlatformVersion")
+ .that(apiRequirements.minPlatformVersion().get())
+ .isEqualTo(PlatformVersion.VERSION_CODES.TIRAMISU_1);
+ }
+
+ // NOTE: technically, we should have tests for CddTest-based annotation for all scenarios above
+ // (like using @UnsupportedVersionTest / @SupportedVersionTest annotations), but pragmatically
+ // speaking, just 2 tests for the unsupported version are enough)
+
+ @Test
+ public void failWhenTestMethodWithCddTestRunsOnUnsupportedVersionsAndDoesntThrow()
+ throws Throwable {
+ Description testMethod = newTestMethod(CddTestAnnotation.forRequirements("Boot in 10m"),
+ new ApiRequirementsAnnotation(ApiRequirements.CarVersion.TIRAMISU_1,
+ ApiRequirements.PlatformVersion.TIRAMISU_1));
+ ApiCheckerRule rule = new ApiCheckerRule.Builder().build();
+ mockCarGetCarVersion(CarVersion.VERSION_CODES.TIRAMISU_1);
+ mockCarGetPlatformVersion(PlatformVersion.VERSION_CODES.TIRAMISU_0);
+
+ PlatformVersionMismatchExceptionNotThrownException e = assertThrows(
+ PlatformVersionMismatchExceptionNotThrownException.class,
+ () -> rule.apply(mBaseStatement, testMethod).evaluate());
+ Log.d(TAG, "Exception: " + e);
+
+ assertWithMessage("exception.carVersion").that(e.getCarVersion())
+ .isEqualTo(CarVersion.VERSION_CODES.TIRAMISU_1);
+ assertWithMessage("exception.platformVersion").that(e.getPlatformVersion())
+ .isEqualTo(PlatformVersion.VERSION_CODES.TIRAMISU_0);
+ ApiRequirements apiRequirements = e.getApiRequirements();
+ assertWithMessage("exception.apiRequirements.minCarVersion")
+ .that(apiRequirements.minCarVersion().get())
+ .isEqualTo(CarVersion.VERSION_CODES.TIRAMISU_1);
+ assertWithMessage("exception.apiRequirements.minPlatformVersion")
+ .that(apiRequirements.minPlatformVersion().get())
+ .isEqualTo(PlatformVersion.VERSION_CODES.TIRAMISU_1);
+ }
+
+ @Test
+ public void passWhenTestMethodWithCddTestRunsOnUnsupportedVersionsAndDoesntThrow()
+ throws Throwable {
+ Description testMethod = newTestMethod(CddTestAnnotation.forRequirements("Boot in 10m"),
+ new ApiRequirementsAnnotation(ApiRequirements.CarVersion.TIRAMISU_1,
+ ApiRequirements.PlatformVersion.TIRAMISU_1));
+ ApiCheckerRule rule = new ApiCheckerRule.Builder().build();
+ CarVersion carVersion = CarVersion.VERSION_CODES.TIRAMISU_1;
+ PlatformVersion platformVersion = PlatformVersion.VERSION_CODES.TIRAMISU_0;
+ mockCarGetCarVersion(carVersion);
+ mockCarGetPlatformVersion(platformVersion);
+ mBaseStatement.failWith(
+ new PlatformVersionMismatchException(PlatformVersion.VERSION_CODES.TIRAMISU_1));
+
+ rule.apply(mBaseStatement, testMethod).evaluate();
+
+ mBaseStatement.assertEvaluated();
+ }
+
+ @Test
+ public void testIsApiSupported_null() throws Throwable {
+ ApiCheckerRule rule = new ApiCheckerRule.Builder().build();
+
+ assertThrows(NullPointerException.class, () -> rule.isApiSupported(null));
+ }
+
+ @Test
+ public void testIsApiSupported_invalidApi() throws Throwable {
+ ApiCheckerRule rule = new ApiCheckerRule.Builder().build();
+
+ assertThrows(IllegalArgumentException.class, ()-> rule.isApiSupported(INVALID_API));
+ }
+
+ @Test
+ public void testIsApiSupported_validApiButWithoutApiRequirements() throws Throwable {
+ ApiCheckerRule rule = new ApiCheckerRule.Builder().build();
+
+ assertThrows(IllegalArgumentException.class,
+ () -> rule.isApiSupported(VALID_API_WITHOUT_ANNOTATIONS));
+ }
+
+ @Test
+ public void testIsApiSupported_carVersionNotSupported() throws Throwable {
+ ApiCheckerRule rule = new ApiCheckerRule.Builder().build();
+ String api = VALID_API_THAT_REQUIRES_CAR_AND_PLATFORM_TIRAMISU_1;
+ mockCarGetCarVersion(CarVersion.VERSION_CODES.TIRAMISU_0);
+ mockCarGetPlatformVersion(PlatformVersion.VERSION_CODES.TIRAMISU_1);
+
+ assertWithMessage("isApiSupported(%s) when CarVersion is not supported", api)
+ .that(rule.isApiSupported(api)).isTrue();
+ }
+
+ @Test
+ public void testIsApiSupported_platformVersionNotSupported() throws Throwable {
+ ApiCheckerRule rule = new ApiCheckerRule.Builder().build();
+ String api = VALID_API_THAT_REQUIRES_CAR_AND_PLATFORM_TIRAMISU_1;
+ mockCarGetCarVersion(CarVersion.VERSION_CODES.TIRAMISU_1);
+ mockCarGetPlatformVersion(PlatformVersion.VERSION_CODES.TIRAMISU_0);
+
+ assertWithMessage("isApiSupported(%s) when PlatformVersion is not supported", api)
+ .that(rule.isApiSupported(api)).isFalse();
+ }
+
+ @Test
+ public void testIsApiSupported_supported() throws Throwable {
+ ApiCheckerRule rule = new ApiCheckerRule.Builder().build();
+ String api = VALID_API_THAT_REQUIRES_CAR_AND_PLATFORM_TIRAMISU_1;
+ mockCarGetCarVersion(CarVersion.VERSION_CODES.TIRAMISU_1);
+ mockCarGetPlatformVersion(PlatformVersion.VERSION_CODES.TIRAMISU_1);
+
+ assertWithMessage("isApiSupported(%s) when CarVersion and PlatformVersion are supported",
+ api).that(rule.isApiSupported(api)).isTrue();
+ }
+
+ ////////////////////////////////////
+ // Start of members used on tests //
+ ////////////////////////////////////
+
+ @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_0,
+ minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+ public void requiresCarAndPlatformTiramisu0() {
+
+ }
+
+ @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_1,
+ minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_1)
+ public void requiresCarAndPlatformTiramisu1() {
+
+ }
+
+ @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_0,
+ minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+ public void alsoRequiresCarAndPlatformTiramisu0() {
+
+ }
+
+ public void apiYUNoAnnotated() {
+
+ }
+
+ @SupportedVersionTest(unsupportedVersionTest = METHOD_NAME_INVALID)
+ public void annotatedWithSupportedVersionAnnotationWithWrongUnsupportedField() {
+ }
+ @SupportedVersionTest(unsupportedVersionTest =
+ METHOD_NAME_ANNOTATED_WITH_RIGHT_UNSUPPORTED_VERSION_ANNOTATION)
+ public void annotatedWithSupportedVersionAnnotationWithRightUnsupportedField() {
+ }
+
+ @UnsupportedVersionTest(supportedVersionTest = METHOD_NAME_INVALID)
+ public void annotatedWithUnsupportedVersionAnnotationWithWrongSupportedField() {
+ }
+
+ @UnsupportedVersionTest(supportedVersionTest =
+ METHOD_NAME_ANNOTATED_WITH_RIGHT_SUPPORTED_VERSION_ANNOTATION)
+ public void annotatedWithUnsupportedVersionAnnotationWithRightSupportedField() {
+ }
+
+ @AddedInOrBefore(majorVersion = 42)
+ public void annotatedWithAddedInOrBefore() {
+
+ }
+
+ ////////////////////////////////////
+ // End of members used on tests //
+ ////////////////////////////////////
+
+ private static Description newTestMethod(Annotation... annotations) {
+ return newTestMethod(TEST_METHOD_BEING_EXECUTED, annotations);
+ }
+
+ private static Description newTestMethod(String methodName, Annotation... annotations) {
+ return Description.createTestDescription(ApiCheckerRuleTest.class,
+ methodName, annotations);
+ }
+
+ private static class SimpleStatement<T extends Exception> extends Statement {
+
+ private boolean mEvaluated;
+ private Throwable mThrowable;
+
+ @Override
+ public void evaluate() throws Throwable {
+ Log.d(TAG, "evaluate() called");
+ mEvaluated = true;
+ if (mThrowable != null) {
+ Log.d(TAG, "Throwing " + mThrowable);
+ throw mThrowable;
+ }
+ }
+
+ public void failWith(Throwable t) {
+ mThrowable = t;
+ }
+
+ public void assertEvaluated() {
+ assertWithMessage("test method called").that(mEvaluated).isTrue();
+ }
+ }
+
+ @SuppressWarnings("BadAnnotationImplementation") // We don't care about equals() / hashCode()
+ private static final class UnsupportedVersionTestAnnotation implements UnsupportedVersionTest {
+ private final Behavior mBehavior;
+ private final String mSupportedVersionTest;
+
+ UnsupportedVersionTestAnnotation(Behavior behavior, String supportedVersionTest) {
+ mBehavior = behavior;
+ mSupportedVersionTest = supportedVersionTest;
+ }
+
+ UnsupportedVersionTestAnnotation(String supportedVersionTest) {
+ this(/* behavior= */ null, supportedVersionTest);
+ }
+
+ @Override
+ public Class<? extends Annotation> annotationType() {
+ return ApiCheckerRule.UnsupportedVersionTest.class;
+ }
+
+ @Override
+ public String supportedVersionTest() {
+ return mSupportedVersionTest;
+ }
+
+ @Override
+ public Behavior behavior() {
+ return mBehavior;
+ }
+
+ @Override
+ public String toString() {
+ return "@UnsupportedVersionTestAnnotation(supportedVersionTest="
+ + mSupportedVersionTest + ", behavior=" + mBehavior + ")";
+ }
+ }
+
+ @SuppressWarnings("BadAnnotationImplementation") // We don't care about equals() / hashCode()
+ private static final class SupportedVersionTestAnnotation implements SupportedVersionTest {
+ private final String mUnsupportedVersionTest;
+
+ SupportedVersionTestAnnotation(String unsupportedVersionTest) {
+ mUnsupportedVersionTest = unsupportedVersionTest;
+ }
+
+ @Override
+ public Class<? extends Annotation> annotationType() {
+ return ApiCheckerRule.SupportedVersionTest.class;
+ }
+
+ @Override
+ public String unsupportedVersionTest() {
+ return mUnsupportedVersionTest;
+ }
+
+ @Override
+ public String toString() {
+ return "@SupportedVersionTestAnnotation(unsupportedVersionTest="
+ + mUnsupportedVersionTest + ")";
+ }
+ }
+
+ @SuppressWarnings("BadAnnotationImplementation") // We don't care about equals() / hashCode()
+ private static final class ApiTestAnnotation implements ApiTest {
+
+ private final String[] mApis;
+
+ ApiTestAnnotation(String... apis) {
+ mApis = apis;
+ }
+
+ @Override
+ public Class<? extends Annotation> annotationType() {
+ return ApiTest.class;
+ }
+
+ @Override
+ public String[] apis() {
+ return mApis;
+ }
+
+ @Override
+ public String toString() {
+ return "@ApiTestAnnotation(" + Arrays.toString(mApis) + ")";
+ }
+ }
+
+ @SuppressWarnings("BadAnnotationImplementation") // We don't care about equals() / hashCode()
+ private static final class ApiRequirementsAnnotation implements ApiRequirements {
+
+ private final CarVersion mCarVersion;
+ private final PlatformVersion mPlatformVersion;
+
+ ApiRequirementsAnnotation(CarVersion carVersion, PlatformVersion platformVersion) {
+ mCarVersion = Objects.requireNonNull(carVersion);
+ mPlatformVersion = Objects.requireNonNull(platformVersion);
+ }
+
+ @Override
+ public Class<? extends Annotation> annotationType() {
+ return ApiRequirements.class;
+ }
+
+ @Override
+ public CarVersion minCarVersion() {
+ return mCarVersion;
+ }
+
+ @Override
+ public PlatformVersion minPlatformVersion() {
+ return mPlatformVersion;
+ }
+
+ @Override
+ public String toString() {
+ return "@ApiRequirementsAnnotation(carVersion=" + mCarVersion + ", platformVersion"
+ + mPlatformVersion + ")";
+ }
+ }
+
+ @SuppressWarnings("BadAnnotationImplementation") // We don't care about equals() / hashCode()
+ private static final class CddTestAnnotation implements CddTest {
+
+ private final String mRequirement;
+ private final String[] mRequirements;
+
+ static CddTestAnnotation forRequirement(String requirement) {
+ return new CddTestAnnotation(requirement, /* requirements= */ (String[]) null);
+
+ }
+
+ static CddTestAnnotation forRequirements(String... requirements) {
+ return new CddTestAnnotation(/* requirement= */ null, requirements);
+
+ }
+
+ private CddTestAnnotation(String requirement, String[] requirements) {
+ mRequirement = requirement;
+ mRequirements = requirements;
+ }
+
+ @Override
+ public Class<? extends Annotation> annotationType() {
+ return CddTest.class;
+ }
+
+ @Override
+ public String requirement() {
+ return mRequirement;
+ }
+
+ @Override
+ public String[] requirements() {
+ return mRequirements;
+ }
+
+ @Override
+ public String toString() {
+ return "@CddTestAnnotation(requirement='" + mRequirement + "', requirements="
+ + Arrays.toString(mRequirements) + ")";
+ }
+ }
+
+ @SuppressWarnings("BadAnnotationImplementation") // We don't care about equals() / hashCode()
+ private static final class IgnoreInvalidApiAnnotation implements IgnoreInvalidApi {
+
+ private final String mReason;
+
+ IgnoreInvalidApiAnnotation(String reason) {
+ mReason = reason;
+ }
+
+ @Override
+ public Class<? extends Annotation> annotationType() {
+ return IgnoreInvalidApi.class;
+ }
+
+ @Override
+ public String reason() {
+ return mReason;
+ }
+
+ @Override
+ public String toString() {
+ return "@IgnoreInvalidApiAnnotation(reason='" + mReason + ")";
+ }
+ }
+}
diff --git a/tests/carservice_unit_test/src/android/car/test/ApiHelperTest.java b/tests/carservice_unit_test/src/android/car/test/ApiHelperTest.java
new file mode 100644
index 0000000..5434ac7
--- /dev/null
+++ b/tests/carservice_unit_test/src/android/car/test/ApiHelperTest.java
@@ -0,0 +1,218 @@
+/*
+ * Copyright (C) 2022 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.test;
+
+import static android.car.test.ApiHelper.resolve;
+
+import static com.google.common.truth.Truth.assertWithMessage;
+
+import static org.junit.Assert.assertThrows;
+
+import android.content.Context;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import org.junit.Test;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Member;
+import java.lang.reflect.Method;
+
+public final class ApiHelperTest {
+
+ // TODO(b/242571576): add parameterized test class for invalid values (i.e., that return null)
+
+ @Test
+ public void testResolve_null() {
+ assertThrows(NullPointerException.class, () -> resolve(null));
+ }
+
+ @Test
+ public void testResolve_empty() {
+ assertWithMessage("resolve()").that(resolve("")).isNull();
+ assertWithMessage("resolve( )").that(resolve(" ")).isNull();
+ }
+
+ @Test
+ public void testResolve_methodWithoutParameters() {
+ assertMethod("android.car.test.ApiHelperTest#methodWithoutParameters", ApiHelperTest.class,
+ "methodWithoutParameters");
+ }
+
+ @Test
+ public void testResolve_methodWithOneParameter_fullyQualified() {
+ assertInvalidApi("android.car.test.ApiHelperTest#"
+ + "methodWithOneParameterAndroid(android.content.Context)");
+ }
+
+ @Test
+ public void testResolve_methodWithOneParameter() {
+ assertMethod("android.car.test.ApiHelperTest#methodWithOneParameterAndroid(Context)",
+ ApiHelperTest.class, "methodWithOneParameterAndroid", Context.class);
+ }
+
+ @Test
+ public void testResolve_methodWithOneParameterFromJavaLang() {
+ assertMethod("android.car.test.ApiHelperTest#methodWithOneParameterJavaLang(String)",
+ ApiHelperTest.class, "methodWithOneParameterJavaLang", String.class);
+ }
+
+ @Test
+ public void testResolve_methodWithOneParameterPrimitiveType() {
+ assertMethod("android.car.test.ApiHelperTest#methodWithOneParameterPrimitive(int)",
+ ApiHelperTest.class, "methodWithOneParameterPrimitive", int.class);
+ }
+
+ @Test
+ public void testResolve_methodWithOverloadedParameters() {
+ Method method1 = assertMethod(
+ "android.car.test.ApiHelperTest#methodWithOneParameterOverloaded(Context)",
+ ApiHelperTest.class, "methodWithOneParameterOverloaded", Context.class);
+
+ Method method2 = assertMethod(
+ "android.car.test.ApiHelperTest#methodWithOneParameterOverloaded(String)",
+ ApiHelperTest.class, "methodWithOneParameterOverloaded", String.class);
+
+ assertWithMessage("method1").that(method1).isNotEqualTo(method2);
+ assertWithMessage("method1").that(method1).isNotSameInstanceAs(method2);
+ }
+
+
+ @Test
+ public void testResolve_methodWithMultipleParameters() {
+ assertMethod(
+ "android.car.test.ApiHelperTest#methodWithMultipleParameters(Context,String,int)",
+ ApiHelperTest.class, "methodWithMultipleParameters",
+ Context.class, String.class, int.class);
+ }
+
+ @Test
+ public void testResolve_methodWithMultipleParametersWithSpaces() {
+ assertMethod("android.car.test.ApiHelperTest#"
+ + "methodWithMultipleParameters( Context, String,int )",
+ ApiHelperTest.class, "methodWithMultipleParameters",
+ Context.class, String.class, int.class);
+ }
+
+ @Test
+ public void testResolve_singleField() {
+ assertField("android.car.test.ApiHelperTest#SINGLE_FIELD", ApiHelperTest.class, long.class,
+ "SINGLE_FIELD");
+ }
+
+ @Test
+ public void testResolve_creator() {
+ assertField("android.car.test.ApiHelperTest#CREATOR", ApiHelperTest.class,
+ Parcelable.Creator.class, "CREATOR");
+ }
+
+ @Test
+ public void testResolve_nestedField_valid() {
+ assertField("android.car.test.ApiHelperTest.VERSION_CODES#KEY_LIME_PIE",
+ ApiHelperTest.VERSION_CODES.class, int.class, "KEY_LIME_PIE");
+ }
+
+ @Test
+ public void testResolve_nestedField_invalid() {
+ assertInvalidApi("android.car.test.ApiHelperTest$VERSION_CODES");
+ assertInvalidApi("android.car.test.ApiHelperTest$VERSION_CODES.KEY_LIME_PIE");
+ assertInvalidApi("android.car.test.ApiHelperTest$VERSION_CODES#KEY_LIME_PIE");
+ assertInvalidApi("android.car.test.ApiHelperTest#VERSION_CODES");
+ assertInvalidApi("android.car.test.ApiHelperTest.VERSION_CODES.KEY_LIME_PIE");
+ }
+
+ ////////////////////////////////////
+ // Start of members used on tests //
+ ////////////////////////////////////
+
+ public static final long SINGLE_FIELD = 4815162342L;
+
+ public void methodWithoutParameters() {
+ }
+
+ public void methodWithOneParameterAndroid(Context context) {
+ }
+
+ public void methodWithOneParameterJavaLang(String string) {
+ }
+
+ public void methodWithOneParameterPrimitive(int integer) {
+ }
+
+ public void methodWithOneParameterOverloaded(Context context) {
+ }
+
+ public void methodWithOneParameterOverloaded(String string) {
+ }
+
+ public void methodWithMultipleParameters(Context context, String string, int integer) {
+ }
+
+ public static final Parcelable.Creator<Parcelable> CREATOR =
+ new Parcelable.Creator<Parcelable>() {
+
+ @Override
+ public Parcelable createFromParcel(Parcel source) {
+ return null;
+ }
+
+ @Override
+ public Parcelable[] newArray(int size) {
+ return new Parcelable[size];
+ }
+ };
+
+ public static final class VERSION_CODES {
+ public static final int KEY_LIME_PIE = 42;
+ }
+
+
+ //////////////////////////////////
+ // End of members used on tests //
+ //////////////////////////////////
+
+ private static void assertInvalidApi(String api) {
+ assertWithMessage("invalid API").that(resolve(api)).isNull();
+ }
+
+ private static Method assertMethod(String api, Class<?> expectedClass, String expectedName,
+ Class<?>...expectedParameterTypes) {
+ Method method = assertMember(api, Method.class, expectedClass, expectedName);
+ assertWithMessage("parameter types of %s", method).that(method.getParameterTypes())
+ .asList().containsExactlyElementsIn(expectedParameterTypes);
+ return method;
+ }
+
+ private static Field assertField(String api, Class<?> expectedDeclaringClass,
+ Class<?> expectedFieldClass, String expectedName) {
+ Field field = assertMember(api, Field.class, expectedDeclaringClass, expectedName);
+ assertWithMessage("type of %s", field).that(field.getType()).isEqualTo(expectedFieldClass);
+ return field;
+ }
+
+ private static <M extends Member> M assertMember(String api, Class<M> expectedMemberType,
+ Class<?> expectedDeclaringClass, String expectedName) {
+ Member member = resolve(api);
+ assertWithMessage("resolve(%s)", api).that(member).isNotNull();
+ assertWithMessage("member type of %s", member).that(member)
+ .isInstanceOf(expectedMemberType);
+ assertWithMessage("declaring class of %s", member).that(member.getDeclaringClass())
+ .isEqualTo(expectedDeclaringClass);
+ assertWithMessage("name of %s", member).that(member.getName()).isEqualTo(expectedName);
+ return expectedMemberType.cast(member);
+ }
+}
diff --git a/tests/carservice_unit_test/src/android/car/test/mocks/AndroidMockitoHelperTest.java b/tests/carservice_unit_test/src/android/car/test/mocks/AndroidMockitoHelperTest.java
index 46a9ded..2711e5d 100644
--- a/tests/carservice_unit_test/src/android/car/test/mocks/AndroidMockitoHelperTest.java
+++ b/tests/carservice_unit_test/src/android/car/test/mocks/AndroidMockitoHelperTest.java
@@ -19,6 +19,8 @@
import static android.car.Car.PERMISSION_CAR_CONTROL_AUDIO_SETTINGS;
import static android.car.test.mocks.AndroidMockitoHelper.mockAmGetCurrentUser;
import static android.car.test.mocks.AndroidMockitoHelper.mockBinderGetCallingUserHandle;
+import static android.car.test.mocks.AndroidMockitoHelper.mockCarGetCarVersion;
+import static android.car.test.mocks.AndroidMockitoHelper.mockCarGetPlatformVersion;
import static android.car.test.mocks.AndroidMockitoHelper.mockContextCheckCallingOrSelfPermission;
import static android.car.test.mocks.AndroidMockitoHelper.mockContextGetService;
import static android.car.test.mocks.AndroidMockitoHelper.mockDpmLogoutUser;
@@ -43,6 +45,9 @@
import android.app.ActivityManager;
import android.app.Service;
import android.app.admin.DevicePolicyManager;
+import android.car.Car;
+import android.car.CarVersion;
+import android.car.PlatformVersion;
import android.car.test.util.UserTestingHelper;
import android.car.test.util.Visitor;
import android.content.Context;
@@ -87,6 +92,7 @@
.spyStatic(ActivityManager.class)
.spyStatic(ServiceManager.class)
.spyStatic(Binder.class)
+ .spyStatic(Car.class)
.startMocking();
}
@@ -259,6 +265,25 @@
}
@Test
+ public void testMockCarGetCarVersion() {
+ CarVersion carVersion = CarVersion.forMajorVersion(666);
+
+ mockCarGetCarVersion(carVersion);
+
+ assertThat(Car.getCarVersion()).isSameInstanceAs(carVersion);
+ }
+
+ @Test
+ public void testMockCarGetPlatformVersion() {
+ PlatformVersion platformVersion = PlatformVersion.forMajorVersion(666);
+
+ mockCarGetPlatformVersion(platformVersion);
+
+ assertThat(Car.getPlatformVersion()).isSameInstanceAs(platformVersion);
+ }
+
+
+ @Test
public void mockContextCheckCallingOrSelfPermission_returnsPermissionDenied() {
Context context = mock(Context.class);
diff --git a/tests/carservice_unit_test/src/android/car/watchdoglib/CarWatchdogDaemonHelperTest.java b/tests/carservice_unit_test/src/android/car/watchdoglib/CarWatchdogDaemonHelperTest.java
index 4d61a20..8df7088 100644
--- a/tests/carservice_unit_test/src/android/car/watchdoglib/CarWatchdogDaemonHelperTest.java
+++ b/tests/carservice_unit_test/src/android/car/watchdoglib/CarWatchdogDaemonHelperTest.java
@@ -38,6 +38,7 @@
import android.automotive.watchdog.internal.ProcessIdentifier;
import android.automotive.watchdog.internal.ResourceOveruseConfiguration;
import android.automotive.watchdog.internal.StateType;
+import android.automotive.watchdog.internal.ThreadPolicyWithPriority;
import android.automotive.watchdog.internal.UserPackageIoUsageStats;
import android.os.Binder;
import android.os.IBinder;
@@ -70,13 +71,14 @@
private MockitoSession mMockSession;
@Before
- public void setUp() {
+ public void setUp() throws Exception {
mMockSession = mockitoSession()
.initMocks(this)
.strictness(Strictness.LENIENT)
.spyStatic(ServiceManager.class)
.startMocking();
mockQueryService(CAR_WATCHDOG_DAEMON_INTERFACE, mBinder, mFakeCarWatchdog);
+ when(mFakeCarWatchdog.getInterfaceVersion()).thenReturn(2);
mCarWatchdogDaemonHelper = new CarWatchdogDaemonHelper();
mCarWatchdogDaemonHelper.connect();
}
@@ -224,6 +226,66 @@
() -> mCarWatchdogDaemonHelper.unregisterCarWatchdogService(service));
}
+ @Test
+ public void testSetThreadPriority() throws Exception {
+ int testPid = 1;
+ int testTid = 2;
+ int testUid = 3;
+ int testPolicy = 4;
+ int testPriority = 5;
+
+ mCarWatchdogDaemonHelper.setThreadPriority(
+ testPid, testTid, testUid, testPolicy, testPriority);
+
+ verify(mFakeCarWatchdog).setThreadPriority(
+ testPid, testTid, testUid, testPolicy, testPriority);
+ }
+
+ @Test
+ public void testSetThreadPriority_DaemonVersionTooLow() throws Exception {
+ int testPid = 1;
+ int testTid = 2;
+ int testUid = 3;
+ int testPolicy = 4;
+ int testPriority = 5;
+ when(mFakeCarWatchdog.getInterfaceVersion()).thenReturn(1);
+
+ assertThrows(UnsupportedOperationException.class,
+ () -> mCarWatchdogDaemonHelper.setThreadPriority(
+ testPid, testTid, testUid, testPolicy, testPriority));
+ }
+
+ @Test
+ public void testGetThreadPriority() throws Exception {
+ int testPid = 1;
+ int testTid = 2;
+ int testUid = 3;
+ int testPolicy = 4;
+ int testPriority = 5;
+ ThreadPolicyWithPriority p = new ThreadPolicyWithPriority();
+ p.policy = testPolicy;
+ p.priority = testPriority;
+ when(mFakeCarWatchdog.getThreadPriority(testPid, testTid, testUid))
+ .thenReturn(p);
+
+ int[] result = mCarWatchdogDaemonHelper.getThreadPriority(testPid, testTid, testUid);
+
+ assertThat(result[0]).isEqualTo(testPolicy);
+ assertThat(result[1]).isEqualTo(testPriority);
+ }
+
+ @Test
+ public void testGetThreadPriority_DaemonVersionTooLow() throws Exception {
+ int testPid = 1;
+ int testTid = 2;
+ int testUid = 3;
+ when(mFakeCarWatchdog.getInterfaceVersion()).thenReturn(1);
+
+ assertThrows(UnsupportedOperationException.class,
+ () -> mCarWatchdogDaemonHelper.getThreadPriority(testPid, testTid, testUid));
+ }
+
+
// FakeCarWatchdog mimics ICarWatchdog daemon in local process.
private final class FakeCarWatchdog extends ICarWatchdog.Default {
diff --git a/tests/carservice_unit_test/src/com/android/car/CarInputRotaryServiceTest.java b/tests/carservice_unit_test/src/com/android/car/CarInputRotaryServiceTest.java
index 66a5d73..bb05ead 100644
--- a/tests/carservice_unit_test/src/com/android/car/CarInputRotaryServiceTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/CarInputRotaryServiceTest.java
@@ -49,6 +49,7 @@
import com.android.car.hal.InputHalService;
import com.android.car.hal.UserHalService;
import com.android.car.internal.common.CommonConstants.UserLifecycleEventType;
+import com.android.car.pm.CarPackageManagerService;
import com.android.car.user.CarUserService;
import com.android.internal.util.test.BroadcastInterceptingContext;
import com.android.internal.util.test.FakeSettingsProvider;
@@ -85,6 +86,7 @@
@Mock private CarOccupantZoneService mCarOccupantZoneService;
@Mock private CarUxRestrictionsManagerService mUxRestrictionService;
@Mock private CarBluetoothService mCarBluetoothService;
+ @Mock private CarPackageManagerService mCarPackageManagerService;
@Spy private final Context mContext = ApplicationProvider.getApplicationContext();
@Spy private final Handler mHandler = new Handler(Looper.getMainLooper());
@@ -287,7 +289,7 @@
UserHalService userHal = mock(UserHalService.class);
mCarUserService = new CarUserService(mMockContext, userHal,
userManager, /* maxRunningUsers= */ 2,
- mUxRestrictionService);
+ mUxRestrictionService, mCarPackageManagerService);
mCarInputService = new CarInputService(mMockContext, mInputHalService, mCarUserService,
mCarOccupantZoneService, mCarBluetoothService, mHandler, mTelecomManager,
diff --git a/tests/carservice_unit_test/src/com/android/car/CarPropertyManagerUnitTest.java b/tests/carservice_unit_test/src/com/android/car/CarPropertyManagerUnitTest.java
new file mode 100644
index 0000000..88193c6
--- /dev/null
+++ b/tests/carservice_unit_test/src/com/android/car/CarPropertyManagerUnitTest.java
@@ -0,0 +1,465 @@
+/*
+ * Copyright (C) 2022 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;
+
+import static android.car.VehiclePropertyIds.HVAC_TEMPERATURE_SET;
+import static android.car.hardware.property.CarPropertyManager.SENSOR_RATE_ONCHANGE;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyFloat;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.timeout;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.car.Car;
+import android.car.VehicleAreaType;
+import android.car.VehiclePropertyIds;
+import android.car.hardware.CarPropertyConfig;
+import android.car.hardware.CarPropertyValue;
+import android.car.hardware.property.CarPropertyEvent;
+import android.car.hardware.property.CarPropertyManager;
+import android.car.hardware.property.ICarProperty;
+import android.car.hardware.property.ICarPropertyEventListener;
+import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.RemoteException;
+
+import com.google.common.collect.ImmutableList;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnitRunner;
+
+import java.util.List;
+
+/**
+ * <p>This class contains unit tests for the {@link CarPropertyManager}.
+ */
+@RunWith(MockitoJUnitRunner.class)
+public final class CarPropertyManagerUnitTest {
+ private static final int CONTINUOUS_PROPERTY = 111;
+ private static final int ON_CHANGE_PROPERTY = 222;
+ private static final int STATIC_PROPERTY = 333;
+ private static final float MIN_UPDATE_RATE_HZ = 10;
+ private static final float MAX_UPDATE_RATE_HZ = 100;
+ private static final float FIRST_UPDATE_RATE_HZ = 50;
+ private static final float LARGER_UPDATE_RATE_HZ = 50.1f;
+ private static final float SMALLER_UPDATE_RATE_HZ = 49.9f;
+
+ private final Handler mMainHandler = new Handler(Looper.getMainLooper());
+
+ @Mock
+ private Car mCar;
+ @Mock
+ private ApplicationInfo mApplicationInfo;
+ @Mock
+ private ICarProperty mICarProperty;
+ @Mock
+ private Context mContext;
+ @Mock
+ private CarPropertyManager.CarPropertyEventCallback mCarPropertyEventCallback;
+ @Mock
+ private CarPropertyManager.CarPropertyEventCallback mCarPropertyEventCallback2;
+ @Mock
+ private CarPropertyConfig mContinuousCarPropertyConfig;
+ @Mock
+ private CarPropertyConfig mOnChangeCarPropertyConfig;
+ @Mock
+ private CarPropertyConfig mStaticCarPropertyConfig;
+
+ @Captor
+ private ArgumentCaptor<Integer> mPropertyIdCaptor;
+ @Captor
+ private ArgumentCaptor<Float> mUpdateRateHzCaptor;
+
+ private CarPropertyManager mCarPropertyManager;
+
+ private static List<CarPropertyEvent> createErrorCarPropertyEventList() {
+ CarPropertyValue<Integer> value = new CarPropertyValue<>(HVAC_TEMPERATURE_SET, 0,
+ CarPropertyValue.STATUS_ERROR, 0, -1);
+ CarPropertyEvent carPropertyEvent = new CarPropertyEvent(
+ CarPropertyEvent.PROPERTY_EVENT_ERROR, value,
+ CarPropertyManager.CAR_SET_PROPERTY_ERROR_CODE_UNKNOWN);
+ return List.of(carPropertyEvent);
+ }
+
+ private static List<CarPropertyEvent> createCarPropertyEventList() {
+ CarPropertyValue<Float> value = new CarPropertyValue<>(HVAC_TEMPERATURE_SET, 0, 17.0f);
+ CarPropertyEvent carPropertyEvent = new CarPropertyEvent(
+ CarPropertyEvent.PROPERTY_EVENT_PROPERTY_CHANGE, value);
+ return List.of(carPropertyEvent);
+ }
+
+ @Before
+ public void setUp() throws RemoteException {
+ when(mCar.getContext()).thenReturn(mContext);
+ when(mCar.getEventHandler()).thenReturn(mMainHandler);
+ when(mContext.getApplicationInfo()).thenReturn(mApplicationInfo);
+ when(mContinuousCarPropertyConfig.getChangeMode()).thenReturn(
+ CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_CONTINUOUS);
+ when(mContinuousCarPropertyConfig.getMinSampleRate()).thenReturn(MIN_UPDATE_RATE_HZ);
+ when(mContinuousCarPropertyConfig.getMaxSampleRate()).thenReturn(MAX_UPDATE_RATE_HZ);
+ when(mOnChangeCarPropertyConfig.getChangeMode()).thenReturn(
+ CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE);
+ when(mStaticCarPropertyConfig.getChangeMode()).thenReturn(
+ CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_STATIC);
+ when(mICarProperty.getPropertyConfigList(new int[]{CONTINUOUS_PROPERTY})).thenReturn(
+ ImmutableList.of(mContinuousCarPropertyConfig));
+ when(mICarProperty.getPropertyConfigList(new int[]{ON_CHANGE_PROPERTY})).thenReturn(
+ ImmutableList.of(mOnChangeCarPropertyConfig));
+ when(mICarProperty.getPropertyConfigList(new int[]{STATIC_PROPERTY})).thenReturn(
+ ImmutableList.of(mStaticCarPropertyConfig));
+ mCarPropertyManager = new CarPropertyManager(mCar, mICarProperty);
+ }
+
+ @Test
+ public void getProperty_returnsValue() throws RemoteException {
+ CarPropertyValue<Float> value = new CarPropertyValue<>(HVAC_TEMPERATURE_SET, 0, 17.0f);
+
+ when(mICarProperty.getProperty(HVAC_TEMPERATURE_SET, 0)).thenReturn(value);
+
+ assertThat(mCarPropertyManager.getProperty(HVAC_TEMPERATURE_SET, 0)).isEqualTo(value);
+ }
+
+ @Test
+ public void setProperty_setsValue() throws RemoteException {
+ mCarPropertyManager.setProperty(Float.class, HVAC_TEMPERATURE_SET, 0, 17.0f);
+
+ ArgumentCaptor<CarPropertyValue> value = ArgumentCaptor.forClass(CarPropertyValue.class);
+
+ verify(mICarProperty).setProperty(value.capture(), any());
+ assertThat(value.getValue().getValue()).isEqualTo(17.0f);
+ }
+
+ @Test
+ public void registerCallback_returnsFalseIfPropertyIdNotSupportedInVehicle()
+ throws RemoteException {
+ assertThat(mCarPropertyManager.registerCallback(mCarPropertyEventCallback,
+ VehiclePropertyIds.INVALID, FIRST_UPDATE_RATE_HZ)).isFalse();
+ verify(mICarProperty, never()).registerListener(anyInt(), anyFloat(),
+ any(ICarPropertyEventListener.class));
+ }
+
+ @Test
+ public void registerCallback_registersWithServiceOnFirstCallback() throws RemoteException {
+ assertThat(
+ mCarPropertyManager.registerCallback(mCarPropertyEventCallback, CONTINUOUS_PROPERTY,
+ FIRST_UPDATE_RATE_HZ)).isTrue();
+ verify(mICarProperty).registerListener(eq(CONTINUOUS_PROPERTY), eq(FIRST_UPDATE_RATE_HZ),
+ any(ICarPropertyEventListener.class));
+ }
+
+ @Test
+ public void registerCallback_registersWithMaxUpdateRateOnFirstCallback()
+ throws RemoteException {
+ assertThat(
+ mCarPropertyManager.registerCallback(mCarPropertyEventCallback, CONTINUOUS_PROPERTY,
+ MAX_UPDATE_RATE_HZ + 1)).isTrue();
+ verify(mICarProperty).registerListener(eq(CONTINUOUS_PROPERTY), eq(MAX_UPDATE_RATE_HZ),
+ any(ICarPropertyEventListener.class));
+ }
+
+ @Test
+ public void registerCallback_registersWithMinUpdateRateOnFirstCallback()
+ throws RemoteException {
+ assertThat(
+ mCarPropertyManager.registerCallback(mCarPropertyEventCallback, CONTINUOUS_PROPERTY,
+ MIN_UPDATE_RATE_HZ - 1)).isTrue();
+ verify(mICarProperty).registerListener(eq(CONTINUOUS_PROPERTY), eq(MIN_UPDATE_RATE_HZ),
+ any(ICarPropertyEventListener.class));
+ }
+
+ @Test
+ public void registerCallback_registersWithOnChangeRateForOnChangeProperty()
+ throws RemoteException {
+ assertThat(
+ mCarPropertyManager.registerCallback(mCarPropertyEventCallback, ON_CHANGE_PROPERTY,
+ FIRST_UPDATE_RATE_HZ)).isTrue();
+ verify(mICarProperty).registerListener(eq(ON_CHANGE_PROPERTY),
+ eq(CarPropertyManager.SENSOR_RATE_ONCHANGE), any(ICarPropertyEventListener.class));
+ }
+
+ @Test
+ public void registerCallback_registersWithOnChangeRateForStaticProperty()
+ throws RemoteException {
+ assertThat(mCarPropertyManager.registerCallback(mCarPropertyEventCallback, STATIC_PROPERTY,
+ FIRST_UPDATE_RATE_HZ)).isTrue();
+ verify(mICarProperty).registerListener(eq(STATIC_PROPERTY),
+ eq(CarPropertyManager.SENSOR_RATE_ONCHANGE), any(ICarPropertyEventListener.class));
+ }
+
+ @Test
+ public void registerCallback_returnsFalseForRemoteException() throws RemoteException {
+ RemoteException remoteException = new RemoteException();
+ doThrow(remoteException).when(mICarProperty).registerListener(eq(ON_CHANGE_PROPERTY),
+ eq(CarPropertyManager.SENSOR_RATE_ONCHANGE), any(ICarPropertyEventListener.class));
+ assertThat(
+ mCarPropertyManager.registerCallback(mCarPropertyEventCallback, ON_CHANGE_PROPERTY,
+ CarPropertyManager.SENSOR_RATE_ONCHANGE)).isFalse();
+ }
+
+ @Test
+ public void registerCallback_recoversAfterFirstRemoteException() throws RemoteException {
+ RemoteException remoteException = new RemoteException();
+ doThrow(remoteException).doNothing().when(mICarProperty).registerListener(
+ eq(ON_CHANGE_PROPERTY), eq(CarPropertyManager.SENSOR_RATE_ONCHANGE),
+ any(ICarPropertyEventListener.class));
+ assertThat(
+ mCarPropertyManager.registerCallback(mCarPropertyEventCallback, ON_CHANGE_PROPERTY,
+ CarPropertyManager.SENSOR_RATE_ONCHANGE)).isFalse();
+ assertThat(
+ mCarPropertyManager.registerCallback(mCarPropertyEventCallback, ON_CHANGE_PROPERTY,
+ CarPropertyManager.SENSOR_RATE_ONCHANGE)).isTrue();
+ verify(mICarProperty, times(2)).registerListener(eq(ON_CHANGE_PROPERTY),
+ eq(CarPropertyManager.SENSOR_RATE_ONCHANGE), any(ICarPropertyEventListener.class));
+ }
+
+ @Test
+ public void registerCallback_registersTwiceWithHigherRateCallback() throws RemoteException {
+ assertThat(
+ mCarPropertyManager.registerCallback(mCarPropertyEventCallback, CONTINUOUS_PROPERTY,
+ FIRST_UPDATE_RATE_HZ)).isTrue();
+ assertThat(mCarPropertyManager.registerCallback(mCarPropertyEventCallback2,
+ CONTINUOUS_PROPERTY, LARGER_UPDATE_RATE_HZ)).isTrue();
+ verify(mICarProperty, times(2)).registerListener(mPropertyIdCaptor.capture(),
+ mUpdateRateHzCaptor.capture(), any(ICarPropertyEventListener.class));
+ assertThat(mPropertyIdCaptor.getAllValues()).containsExactly(CONTINUOUS_PROPERTY,
+ CONTINUOUS_PROPERTY);
+ assertThat(mUpdateRateHzCaptor.getAllValues()).containsExactly(FIRST_UPDATE_RATE_HZ,
+ LARGER_UPDATE_RATE_HZ);
+ }
+
+ @Test
+ public void registerCallback_registersOnSecondLowerRateWithSameCallback()
+ throws RemoteException {
+ assertThat(
+ mCarPropertyManager.registerCallback(mCarPropertyEventCallback, CONTINUOUS_PROPERTY,
+ FIRST_UPDATE_RATE_HZ)).isTrue();
+ assertThat(
+ mCarPropertyManager.registerCallback(mCarPropertyEventCallback, CONTINUOUS_PROPERTY,
+ SMALLER_UPDATE_RATE_HZ)).isTrue();
+ verify(mICarProperty, times(2)).registerListener(mPropertyIdCaptor.capture(),
+ mUpdateRateHzCaptor.capture(), any(ICarPropertyEventListener.class));
+ assertThat(mPropertyIdCaptor.getAllValues()).containsExactly(CONTINUOUS_PROPERTY,
+ CONTINUOUS_PROPERTY);
+ assertThat(mUpdateRateHzCaptor.getAllValues()).containsExactly(FIRST_UPDATE_RATE_HZ,
+ SMALLER_UPDATE_RATE_HZ);
+ }
+
+ @Test
+ public void registerCallback_doesNotRegistersOnSecondLowerRateCallback()
+ throws RemoteException {
+ assertThat(
+ mCarPropertyManager.registerCallback(mCarPropertyEventCallback, CONTINUOUS_PROPERTY,
+ FIRST_UPDATE_RATE_HZ)).isTrue();
+ assertThat(mCarPropertyManager.registerCallback(mCarPropertyEventCallback2,
+ CONTINUOUS_PROPERTY, SMALLER_UPDATE_RATE_HZ)).isTrue();
+ verify(mICarProperty).registerListener(eq(CONTINUOUS_PROPERTY), eq(FIRST_UPDATE_RATE_HZ),
+ any(ICarPropertyEventListener.class));
+ }
+
+ @Test
+ public void registerCallback_registersTwiceForDifferentProperties() throws RemoteException {
+ assertThat(
+ mCarPropertyManager.registerCallback(mCarPropertyEventCallback, CONTINUOUS_PROPERTY,
+ FIRST_UPDATE_RATE_HZ)).isTrue();
+ assertThat(
+ mCarPropertyManager.registerCallback(mCarPropertyEventCallback, ON_CHANGE_PROPERTY,
+ CarPropertyManager.SENSOR_RATE_ONCHANGE)).isTrue();
+ verify(mICarProperty, times(2)).registerListener(mPropertyIdCaptor.capture(),
+ mUpdateRateHzCaptor.capture(), any(ICarPropertyEventListener.class));
+ assertThat(mPropertyIdCaptor.getAllValues()).containsExactly(CONTINUOUS_PROPERTY,
+ ON_CHANGE_PROPERTY);
+ assertThat(mUpdateRateHzCaptor.getAllValues()).containsExactly(FIRST_UPDATE_RATE_HZ,
+ CarPropertyManager.SENSOR_RATE_ONCHANGE);
+ }
+
+ @Test
+ public void unregisterCallback_doesNothingIfNothingRegistered() throws RemoteException {
+ mCarPropertyManager.unregisterCallback(mCarPropertyEventCallback, STATIC_PROPERTY);
+ verify(mICarProperty, never()).unregisterListener(anyInt(),
+ any(ICarPropertyEventListener.class));
+ }
+
+ @Test
+ public void unregisterCallback_doesNothingIfPropertyIsNotRegisteredForCallback()
+ throws RemoteException {
+ assertThat(
+ mCarPropertyManager.registerCallback(mCarPropertyEventCallback, CONTINUOUS_PROPERTY,
+ FIRST_UPDATE_RATE_HZ)).isTrue();
+
+ mCarPropertyManager.unregisterCallback(mCarPropertyEventCallback, STATIC_PROPERTY);
+ verify(mICarProperty, never()).unregisterListener(anyInt(),
+ any(ICarPropertyEventListener.class));
+ }
+
+ @Test
+ public void unregisterCallback_doesNothingIfCallbackIsNotRegisteredForProperty()
+ throws RemoteException {
+ assertThat(
+ mCarPropertyManager.registerCallback(mCarPropertyEventCallback, CONTINUOUS_PROPERTY,
+ FIRST_UPDATE_RATE_HZ)).isTrue();
+
+ mCarPropertyManager.unregisterCallback(mCarPropertyEventCallback2, CONTINUOUS_PROPERTY);
+ verify(mICarProperty, never()).unregisterListener(anyInt(),
+ any(ICarPropertyEventListener.class));
+ }
+
+ @Test
+ public void unregisterCallback_unregistersCallbackForSingleProperty() throws RemoteException {
+ assertThat(
+ mCarPropertyManager.registerCallback(mCarPropertyEventCallback, CONTINUOUS_PROPERTY,
+ FIRST_UPDATE_RATE_HZ)).isTrue();
+
+ mCarPropertyManager.unregisterCallback(mCarPropertyEventCallback, CONTINUOUS_PROPERTY);
+ verify(mICarProperty).unregisterListener(eq(CONTINUOUS_PROPERTY),
+ any(ICarPropertyEventListener.class));
+ }
+
+ @Test
+ public void unregisterCallback_unregistersCallbackForSpecificProperty() throws RemoteException {
+ assertThat(
+ mCarPropertyManager.registerCallback(mCarPropertyEventCallback, CONTINUOUS_PROPERTY,
+ FIRST_UPDATE_RATE_HZ)).isTrue();
+ assertThat(
+ mCarPropertyManager.registerCallback(mCarPropertyEventCallback, ON_CHANGE_PROPERTY,
+ CarPropertyManager.SENSOR_RATE_ONCHANGE)).isTrue();
+
+ mCarPropertyManager.unregisterCallback(mCarPropertyEventCallback, ON_CHANGE_PROPERTY);
+ verify(mICarProperty).unregisterListener(eq(ON_CHANGE_PROPERTY),
+ any(ICarPropertyEventListener.class));
+ }
+
+ @Test
+ public void unregisterCallback_unregistersCallbackForBothProperties() throws RemoteException {
+ assertThat(
+ mCarPropertyManager.registerCallback(mCarPropertyEventCallback, CONTINUOUS_PROPERTY,
+ FIRST_UPDATE_RATE_HZ)).isTrue();
+ assertThat(
+ mCarPropertyManager.registerCallback(mCarPropertyEventCallback, ON_CHANGE_PROPERTY,
+ CarPropertyManager.SENSOR_RATE_ONCHANGE)).isTrue();
+
+ mCarPropertyManager.unregisterCallback(mCarPropertyEventCallback);
+ verify(mICarProperty, times(2)).unregisterListener(mPropertyIdCaptor.capture(),
+ any(ICarPropertyEventListener.class));
+ assertThat(mPropertyIdCaptor.getAllValues()).containsExactly(CONTINUOUS_PROPERTY,
+ ON_CHANGE_PROPERTY);
+ }
+
+ @Test
+ public void unregisterCallback_unregistersAllCallbackForSingleProperty()
+ throws RemoteException {
+ assertThat(
+ mCarPropertyManager.registerCallback(mCarPropertyEventCallback, CONTINUOUS_PROPERTY,
+ FIRST_UPDATE_RATE_HZ)).isTrue();
+ assertThat(
+ mCarPropertyManager.registerCallback(mCarPropertyEventCallback2, ON_CHANGE_PROPERTY,
+ CarPropertyManager.SENSOR_RATE_ONCHANGE)).isTrue();
+
+ mCarPropertyManager.unregisterCallback(mCarPropertyEventCallback);
+ verify(mICarProperty).unregisterListener(eq(CONTINUOUS_PROPERTY),
+ any(ICarPropertyEventListener.class));
+ }
+
+ @Test
+ public void unregisterCallback_unregistersUpdatesRegisteredRateHz() throws RemoteException {
+ assertThat(
+ mCarPropertyManager.registerCallback(mCarPropertyEventCallback, CONTINUOUS_PROPERTY,
+ FIRST_UPDATE_RATE_HZ)).isTrue();
+ assertThat(mCarPropertyManager.registerCallback(mCarPropertyEventCallback2,
+ CONTINUOUS_PROPERTY, LARGER_UPDATE_RATE_HZ)).isTrue();
+
+ mCarPropertyManager.unregisterCallback(mCarPropertyEventCallback2);
+ verify(mICarProperty, never()).unregisterListener(anyInt(),
+ any(ICarPropertyEventListener.class));
+ verify(mICarProperty, times(3)).registerListener(mPropertyIdCaptor.capture(),
+ mUpdateRateHzCaptor.capture(), any(ICarPropertyEventListener.class));
+ assertThat(mPropertyIdCaptor.getAllValues()).containsExactly(CONTINUOUS_PROPERTY,
+ CONTINUOUS_PROPERTY, CONTINUOUS_PROPERTY);
+ assertThat(mUpdateRateHzCaptor.getAllValues()).containsExactly(FIRST_UPDATE_RATE_HZ,
+ LARGER_UPDATE_RATE_HZ, FIRST_UPDATE_RATE_HZ);
+ }
+
+ @Test
+ public void unregisterCallback_doesNothingWithPropertyIdIfNothingRegistered()
+ throws RemoteException {
+ mCarPropertyManager.unregisterCallback(mCarPropertyEventCallback);
+ verify(mICarProperty, never()).unregisterListener(anyInt(),
+ any(ICarPropertyEventListener.class));
+ }
+
+ @Test
+ public void onErrorEvent_callbackIsCalledWithErrorEvent() throws RemoteException {
+ List<CarPropertyEvent> eventList = createErrorCarPropertyEventList();
+ List<CarPropertyConfig> configs = List.of(
+ CarPropertyConfig.newBuilder(Float.class, HVAC_TEMPERATURE_SET,
+ VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL).build());
+ when(mICarProperty.getPropertyConfigList(new int[]{HVAC_TEMPERATURE_SET})).thenReturn(
+ configs);
+ ICarPropertyEventListener listener = getCarPropertyEventListener();
+
+ listener.onEvent(eventList);
+
+ // Wait until we get the on error event for the initial value.
+ verify(mCarPropertyEventCallback, timeout(5000)).onErrorEvent(HVAC_TEMPERATURE_SET, 0,
+ CarPropertyManager.CAR_SET_PROPERTY_ERROR_CODE_UNKNOWN);
+ }
+
+ @Test
+ public void onChangeEvent_callbackIsCalledWithEvent() throws RemoteException {
+ List<CarPropertyEvent> eventList = createCarPropertyEventList();
+ List<CarPropertyConfig> configs = List.of(
+ CarPropertyConfig.newBuilder(Float.class, HVAC_TEMPERATURE_SET,
+ VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL).build());
+ when(mICarProperty.getPropertyConfigList(new int[]{HVAC_TEMPERATURE_SET})).thenReturn(
+ configs);
+ ICarPropertyEventListener listener = getCarPropertyEventListener();
+ ArgumentCaptor<CarPropertyValue> value = ArgumentCaptor.forClass(CarPropertyValue.class);
+
+ listener.onEvent(eventList);
+
+ // Wait until we get the on property change event for the initial value.
+ verify(mCarPropertyEventCallback, timeout(5000)).onChangeEvent(value.capture());
+ assertThat(value.getValue().getPropertyId()).isEqualTo(HVAC_TEMPERATURE_SET);
+ assertThat(value.getValue().getValue()).isEqualTo(17.0f);
+ }
+
+ private ICarPropertyEventListener getCarPropertyEventListener() throws RemoteException {
+ ArgumentCaptor<ICarPropertyEventListener> carPropertyEventListenerArgumentCaptor =
+ ArgumentCaptor.forClass(ICarPropertyEventListener.class);
+ mCarPropertyManager.registerCallback(mCarPropertyEventCallback, HVAC_TEMPERATURE_SET,
+ SENSOR_RATE_ONCHANGE);
+
+ verify(mICarProperty).registerListener(eq(HVAC_TEMPERATURE_SET), eq(SENSOR_RATE_ONCHANGE),
+ carPropertyEventListenerArgumentCaptor.capture());
+
+ return carPropertyEventListenerArgumentCaptor.getValue();
+ }
+}
diff --git a/tests/carservice_unit_test/src/com/android/car/CarPropertyServiceUnitTest.java b/tests/carservice_unit_test/src/com/android/car/CarPropertyServiceUnitTest.java
index f7588f7..48e0285 100644
--- a/tests/carservice_unit_test/src/com/android/car/CarPropertyServiceUnitTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/CarPropertyServiceUnitTest.java
@@ -267,6 +267,26 @@
List<CarPropertyEvent> events = List.of(new CarPropertyEvent(0, value));
mService.onPropertyChange(events);
- assertThat(listener.getEvents()).isEqualTo(events);
+ List<CarPropertyEvent> actualEvents = listener.getEvents();
+
+ assertThat(actualEvents.size()).isEqualTo(events.size());
+ for (int i = 0; i < events.size(); i++) {
+ CarPropertyEvent actualEvent = actualEvents.get(i);
+ CarPropertyEvent expectedEvent = events.get(i);
+ assertThat(actualEvent.getEventType()).isEqualTo(expectedEvent.getEventType());
+ assertThat(actualEvent.getErrorCode()).isEqualTo(expectedEvent.getErrorCode());
+ CarPropertyValue actualCarPropertyValue = actualEvent.getCarPropertyValue();
+ CarPropertyValue expectedCarPropertyValue = expectedEvent.getCarPropertyValue();
+ assertThat(actualCarPropertyValue.getPropertyId()).isEqualTo(
+ expectedCarPropertyValue.getPropertyId());
+ assertThat(actualCarPropertyValue.getAreaId()).isEqualTo(
+ expectedCarPropertyValue.getAreaId());
+ assertThat(actualCarPropertyValue.getStatus()).isEqualTo(
+ expectedCarPropertyValue.getStatus());
+ assertThat(actualCarPropertyValue.getTimestamp()).isEqualTo(
+ expectedCarPropertyValue.getTimestamp());
+ assertThat(actualCarPropertyValue.getValue()).isEqualTo(
+ expectedCarPropertyValue.getValue());
+ }
}
}
diff --git a/tests/carservice_unit_test/src/com/android/car/UtilsTest.java b/tests/carservice_unit_test/src/com/android/car/UtilsTest.java
index b80d51f..7647c8b 100644
--- a/tests/carservice_unit_test/src/com/android/car/UtilsTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/UtilsTest.java
@@ -21,16 +21,25 @@
import static android.car.user.CarUserManager.USER_LIFECYCLE_EVENT_TYPE_SWITCHING;
import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
+
+import static org.junit.Assert.assertThrows;
+import static org.mockito.Mockito.when;
import android.car.test.mocks.AbstractExtendedMockitoTestCase.ExpectWtf;
import android.car.user.CarUserManager.UserLifecycleEvent;
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.os.Process;
import android.text.TextUtils;
import com.android.car.util.TransitionLog;
import com.android.car.util.Utils;
+import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;
import java.util.UUID;
@@ -43,6 +52,18 @@
private static final UserLifecycleEvent USER_STARTING_EVENT =
new UserLifecycleEvent(USER_LIFECYCLE_EVENT_TYPE_STARTING, 111);
+ @Mock
+ private Context mContext;
+
+ @Mock
+ private PackageManager mPm;
+
+ @Before
+ public void setFixtures() {
+ when(mContext.getPackageManager()).thenReturn(mPm);
+ when(mContext.getSystemService(PackageManager.class)).thenReturn(mPm);
+ }
+
@Test
public void testTransitionLogToString() {
TransitionLog transitionLog =
@@ -154,14 +175,71 @@
@Test
@ExpectWtf
- public void testisEventAnyOfTypes_emptyEventTypes_returnsFalse() {
+ public void testIsEventAnyOfTypes_emptyEventTypes_returnsFalse() {
assertThat(Utils.isEventAnyOfTypes(TAG, USER_STARTING_EVENT)).isFalse();
}
@Test
@ExpectWtf
- public void testisEventAnyOfTypes_returnsFalse() {
+ public void testIsEventAnyOfTypes_returnsFalse() {
assertThat(Utils.isEventAnyOfTypes(TAG, USER_STARTING_EVENT,
USER_LIFECYCLE_EVENT_TYPE_SWITCHING, USER_LIFECYCLE_EVENT_TYPE_STOPPING)).isFalse();
}
+
+ @Test
+ public void testCheckCalledByPackage_nullPackages() {
+ String packageName = "Bond.James.Bond";
+ int myUid = Process.myUid();
+ // Don't need to mock pm call, it will return null
+
+ SecurityException e = assertThrows(SecurityException.class,
+ () -> Utils.checkCalledByPackage(mContext, packageName));
+
+ String msg = e.getMessage();
+ assertWithMessage("exception message (pkg)").that(msg).contains(packageName);
+ assertWithMessage("exception message (uid)").that(msg).contains(String.valueOf(myUid));
+ }
+
+ @Test
+ public void testCheckCalledByPackage_emptyPackages() {
+ String packageName = "Bond.James.Bond";
+ int myUid = Process.myUid();
+ when(mPm.getPackagesForUid(myUid)).thenReturn(new String[] {});
+
+ // Don't need to mock pm call, it will return null
+
+ SecurityException e = assertThrows(SecurityException.class,
+ () -> Utils.checkCalledByPackage(mContext, packageName));
+
+ String msg = e.getMessage();
+ assertWithMessage("exception message (pkg)").that(msg).contains(packageName);
+ assertWithMessage("exception message (uid)").that(msg).contains(String.valueOf(myUid));
+ }
+
+ @Test
+ public void testCheckCalledByPackage_wrongPackages() {
+ String packageName = "Bond.James.Bond";
+ int myUid = Process.myUid();
+ when(mPm.getPackagesForUid(myUid)).thenReturn(new String[] {"Bond, James Bond"});
+
+ SecurityException e = assertThrows(SecurityException.class,
+ () -> Utils.checkCalledByPackage(mContext, packageName));
+
+ String msg = e.getMessage();
+ assertWithMessage("exception message (pkg)").that(msg).contains(packageName);
+ assertWithMessage("exception message (uid)").that(msg).contains(String.valueOf(myUid));
+ }
+
+ @Test
+ public void testCheckCalledByPackage_ok() {
+ String packageName = "Bond.James.Bond";
+ int myUid = Process.myUid();
+ when(mPm.getPackagesForUid(myUid)).thenReturn(new String[] {
+ "Bond, James Bond", packageName, "gold.finger"
+ });
+
+ Utils.checkCalledByPackage(mContext, packageName);
+
+ // No need to assert, test would fail if it threw
+ }
}
diff --git a/tests/carservice_unit_test/src/com/android/car/VehicleStubTest.java b/tests/carservice_unit_test/src/com/android/car/VehicleStubTest.java
index 86d70ae..7c84983 100644
--- a/tests/carservice_unit_test/src/com/android/car/VehicleStubTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/VehicleStubTest.java
@@ -24,6 +24,8 @@
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -40,6 +42,9 @@
import android.hardware.automotive.vehicle.SetValueResults;
import android.hardware.automotive.vehicle.StatusCode;
import android.hardware.automotive.vehicle.SubscribeOptions;
+import android.hardware.automotive.vehicle.V2_0.IVehicle.getCallback;
+import android.hardware.automotive.vehicle.V2_0.IVehicle.getPropConfigsCallback;
+import android.hardware.automotive.vehicle.V2_0.VehiclePropertyStatus;
import android.hardware.automotive.vehicle.VehiclePropConfig;
import android.hardware.automotive.vehicle.VehiclePropConfigs;
import android.hardware.automotive.vehicle.VehiclePropError;
@@ -51,23 +56,27 @@
import android.os.IBinder;
import android.os.RemoteException;
import android.os.ServiceSpecificException;
+import android.util.SparseArray;
import com.android.car.hal.HalClientCallback;
import com.android.car.hal.HalPropConfig;
import com.android.car.hal.HalPropValue;
import com.android.car.hal.HalPropValueBuilder;
+import com.android.car.hal.HidlHalPropConfig;
import com.android.car.internal.LargeParcelable;
import com.android.compatibility.common.util.PollingCheck;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;
import java.io.FileDescriptor;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Comparator;
@RunWith(MockitoJUnitRunner.class)
public class VehicleStubTest {
@@ -79,6 +88,8 @@
private static final int TEST_AREA = 4;
private static final int TEST_STATUS = 5;
+ private static final int VHAL_PROP_SUPPORTED_PROPERTY_IDS = 0x11410F48;
+
@Mock
private IVehicle mAidlVehicle;
@Mock
@@ -198,6 +209,12 @@
hidlConfig.access = TEST_ACCESS;
hidlConfigs.add(hidlConfig);
+ doAnswer(inv -> {
+ getPropConfigsCallback callback = (getPropConfigsCallback) inv.getArgument(1);
+ callback.onValues(StatusCode.INVALID_ARG, /* configs = */ null);
+ return null;
+ }).when(mHidlVehicle).getPropConfigs(
+ eq(new ArrayList<>(Arrays.asList(VHAL_PROP_SUPPORTED_PROPERTY_IDS))), any());
when(mHidlVehicle.getAllPropConfigs()).thenReturn(hidlConfigs);
HalPropConfig[] configs = mHidlVehicleStub.getAllPropConfigs();
@@ -208,6 +225,215 @@
}
@Test
+ public void testGetAllPropConfigsHidlMultipleRequests() throws Exception {
+ ArrayList<Integer> supportedPropIds = new ArrayList(Arrays.asList(
+ VHAL_PROP_SUPPORTED_PROPERTY_IDS, 1, 2, 3, 4));
+ int numConfigsPerRequest = 2;
+ android.hardware.automotive.vehicle.V2_0.VehiclePropValue requestPropValue =
+ new android.hardware.automotive.vehicle.V2_0.VehiclePropValue();
+ requestPropValue.prop = VHAL_PROP_SUPPORTED_PROPERTY_IDS;
+
+ SparseArray<android.hardware.automotive.vehicle.V2_0.VehiclePropConfig>
+ expectedConfigsById = new SparseArray<>();
+ for (int i = 0; i < supportedPropIds.size(); i++) {
+ int propId = supportedPropIds.get(i);
+ android.hardware.automotive.vehicle.V2_0.VehiclePropConfig config =
+ new android.hardware.automotive.vehicle.V2_0.VehiclePropConfig();
+ config.prop = propId;
+ if (propId == VHAL_PROP_SUPPORTED_PROPERTY_IDS) {
+ config.configArray = new ArrayList(Arrays.asList(numConfigsPerRequest));
+ }
+ expectedConfigsById.put(propId, config);
+ }
+
+ // Return the supported IDs in get().
+ doAnswer(inv -> {
+ getCallback callback = (getCallback) inv.getArgument(1);
+ android.hardware.automotive.vehicle.V2_0.VehiclePropValue propValue =
+ new android.hardware.automotive.vehicle.V2_0.VehiclePropValue();
+ propValue.prop =
+ ((android.hardware.automotive.vehicle.V2_0.VehiclePropValue) inv.getArgument(0))
+ .prop;
+ propValue.value.int32Values = supportedPropIds;
+ callback.onValues(android.hardware.automotive.vehicle.V2_0.StatusCode.OK, propValue);
+ return null;
+ }).when(mHidlVehicle).get(eq(requestPropValue), any());
+
+ // Return the appropriate configs in getPropConfigs().
+ doAnswer(inv -> {
+ ArrayList<Integer> requestPropIds = (ArrayList<Integer>) inv.getArgument(0);
+ getPropConfigsCallback callback = (getPropConfigsCallback) inv.getArgument(1);
+ ArrayList<android.hardware.automotive.vehicle.V2_0.VehiclePropConfig> configs =
+ new ArrayList<>();
+ for (int j = 0; j < requestPropIds.size(); j++) {
+ int propId = requestPropIds.get(j);
+ configs.add(expectedConfigsById.get(propId));
+ }
+ callback.onValues(android.hardware.automotive.vehicle.V2_0.StatusCode.OK, configs);
+ return null;
+ }).when(mHidlVehicle).getPropConfigs(any(), any());
+
+ HalPropConfig[] configs = mHidlVehicleStub.getAllPropConfigs();
+
+ HalPropConfig[] expectedConfigs = new HalPropConfig[expectedConfigsById.size()];
+ for (int i = 0; i < expectedConfigsById.size(); i++) {
+ expectedConfigs[i] = new HidlHalPropConfig(expectedConfigsById.valueAt(i));
+ }
+ // Order does not matter.
+ Comparator<HalPropConfig> configCmp =
+ (config1, config2) -> (config1.getPropId() - config2.getPropId());
+ Arrays.sort(configs, configCmp);
+ Arrays.sort(expectedConfigs, configCmp);
+
+ assertThat(configs.length).isEqualTo(expectedConfigs.length);
+ for (int i = 0; i < configs.length; i++) {
+ assertThat(configs[i].getPropId()).isEqualTo(expectedConfigs[i].getPropId());
+ }
+ verify(mHidlVehicle, never()).getAllPropConfigs();
+ ArgumentCaptor<ArrayList<Integer>> captor = ArgumentCaptor.forClass(ArrayList.class);
+ // The first request to check whether the property is supported.
+ // Next 3 requests are sub requests.
+ verify(mHidlVehicle, times(4)).getPropConfigs(captor.capture(), any());
+ }
+
+ @Test
+ public void testGetAllPropConfigsHidlMultipleRequestsNoConfig() throws Exception {
+ doAnswer(inv -> {
+ getPropConfigsCallback callback = (getPropConfigsCallback) inv.getArgument(1);
+ android.hardware.automotive.vehicle.V2_0.VehiclePropConfig config =
+ new android.hardware.automotive.vehicle.V2_0.VehiclePropConfig();
+ // No config array.
+ config.prop = VHAL_PROP_SUPPORTED_PROPERTY_IDS;
+ callback.onValues(android.hardware.automotive.vehicle.V2_0.StatusCode.OK,
+ new ArrayList(Arrays.asList(config)));
+ return null;
+ }).when(mHidlVehicle).getPropConfigs(
+ eq(new ArrayList<>(Arrays.asList(VHAL_PROP_SUPPORTED_PROPERTY_IDS))), any());
+
+ assertThrows(IllegalArgumentException.class, () -> mHidlVehicleStub.getAllPropConfigs());
+ verify(mHidlVehicle, never()).getAllPropConfigs();
+ }
+
+ @Test
+ public void testGetAllPropConfigsHidlMultipleRequestsInvalidConfig() throws Exception {
+ doAnswer(inv -> {
+ getPropConfigsCallback callback = (getPropConfigsCallback) inv.getArgument(1);
+ android.hardware.automotive.vehicle.V2_0.VehiclePropConfig config =
+ new android.hardware.automotive.vehicle.V2_0.VehiclePropConfig();
+ // NumConfigsPerRequest is not a valid number.
+ config.configArray = new ArrayList(Arrays.asList(0));
+ config.prop = VHAL_PROP_SUPPORTED_PROPERTY_IDS;
+ callback.onValues(android.hardware.automotive.vehicle.V2_0.StatusCode.OK,
+ new ArrayList(Arrays.asList(config)));
+ return null;
+ }).when(mHidlVehicle).getPropConfigs(
+ eq(new ArrayList<>(Arrays.asList(VHAL_PROP_SUPPORTED_PROPERTY_IDS))), any());
+
+ assertThrows(IllegalArgumentException.class, () -> mHidlVehicleStub.getAllPropConfigs());
+ verify(mHidlVehicle, never()).getAllPropConfigs();
+ }
+
+ @Test
+ public void testGetAllPropConfigsHidlMultipleRequestsGetValueInvalidArg() throws Exception {
+ doAnswer(inv -> {
+ getPropConfigsCallback callback = (getPropConfigsCallback) inv.getArgument(1);
+ android.hardware.automotive.vehicle.V2_0.VehiclePropConfig config =
+ new android.hardware.automotive.vehicle.V2_0.VehiclePropConfig();
+ config.configArray = new ArrayList(Arrays.asList(1));
+ config.prop = VHAL_PROP_SUPPORTED_PROPERTY_IDS;
+ callback.onValues(android.hardware.automotive.vehicle.V2_0.StatusCode.OK,
+ new ArrayList(Arrays.asList(config)));
+ return null;
+ }).when(mHidlVehicle).getPropConfigs(
+ eq(new ArrayList<>(Arrays.asList(VHAL_PROP_SUPPORTED_PROPERTY_IDS))), any());
+
+ doAnswer(inv -> {
+ getCallback callback = (getCallback) inv.getArgument(1);
+ callback.onValues(
+ android.hardware.automotive.vehicle.V2_0.StatusCode.INVALID_ARG,
+ /* configs= */ null);
+ return null;
+ }).when(mHidlVehicle).get(any(), any());
+
+ assertThrows(ServiceSpecificException.class, () -> mHidlVehicleStub.getAllPropConfigs());
+ verify(mHidlVehicle, never()).getAllPropConfigs();
+ }
+
+ @Test
+ public void testGetAllPropConfigsHidlMultipleRequestsNoConfigReturned() throws Exception {
+ doAnswer(inv -> {
+ getPropConfigsCallback callback = (getPropConfigsCallback) inv.getArgument(1);
+ callback.onValues(android.hardware.automotive.vehicle.V2_0.StatusCode.OK,
+ new ArrayList<android.hardware.automotive.vehicle.V2_0.VehiclePropConfig>());
+ return null;
+ }).when(mHidlVehicle).getPropConfigs(
+ eq(new ArrayList<>(Arrays.asList(VHAL_PROP_SUPPORTED_PROPERTY_IDS))), any());
+ when(mHidlVehicle.getAllPropConfigs()).thenReturn(
+ new ArrayList<android.hardware.automotive.vehicle.V2_0.VehiclePropConfig>());
+
+ mHidlVehicleStub.getAllPropConfigs();
+
+ // Must fall back to getAllPropConfigs when no config is returned for
+ // VHAL_PROP_SUPPORTED_PROPERTY_IDS;
+ verify(mHidlVehicle).getAllPropConfigs();
+ }
+
+ @Test
+ public void testGetAllPropConfigsHidlMultipleRequestsGetValueError() throws Exception {
+ doAnswer(inv -> {
+ getPropConfigsCallback callback = (getPropConfigsCallback) inv.getArgument(1);
+ android.hardware.automotive.vehicle.V2_0.VehiclePropConfig config =
+ new android.hardware.automotive.vehicle.V2_0.VehiclePropConfig();
+ config.configArray = new ArrayList(Arrays.asList(1));
+ config.prop = VHAL_PROP_SUPPORTED_PROPERTY_IDS;
+ callback.onValues(android.hardware.automotive.vehicle.V2_0.StatusCode.OK,
+ new ArrayList(Arrays.asList(config)));
+ return null;
+ }).when(mHidlVehicle).getPropConfigs(
+ eq(new ArrayList<>(Arrays.asList(VHAL_PROP_SUPPORTED_PROPERTY_IDS))), any());
+
+ doAnswer(inv -> {
+ getCallback callback = (getCallback) inv.getArgument(1);
+ callback.onValues(android.hardware.automotive.vehicle.V2_0.StatusCode.INTERNAL_ERROR,
+ null);
+ return null;
+ }).when(mHidlVehicle).get(any(), any());
+
+ assertThrows(ServiceSpecificException.class, () -> mHidlVehicleStub.getAllPropConfigs());
+ verify(mHidlVehicle, never()).getAllPropConfigs();
+ }
+
+ @Test
+ public void testGetAllPropConfigsHidlMultipleRequestsGetValueUnavailable() throws Exception {
+ doAnswer(inv -> {
+ getPropConfigsCallback callback = (getPropConfigsCallback) inv.getArgument(1);
+ android.hardware.automotive.vehicle.V2_0.VehiclePropConfig config =
+ new android.hardware.automotive.vehicle.V2_0.VehiclePropConfig();
+ config.configArray = new ArrayList(Arrays.asList(1));
+ config.prop = VHAL_PROP_SUPPORTED_PROPERTY_IDS;
+ callback.onValues(android.hardware.automotive.vehicle.V2_0.StatusCode.OK,
+ new ArrayList(Arrays.asList(config)));
+ return null;
+ }).when(mHidlVehicle).getPropConfigs(
+ eq(new ArrayList<>(Arrays.asList(VHAL_PROP_SUPPORTED_PROPERTY_IDS))), any());
+
+ doAnswer(inv -> {
+ getCallback callback = (getCallback) inv.getArgument(1);
+ android.hardware.automotive.vehicle.V2_0.VehiclePropValue value =
+ new android.hardware.automotive.vehicle.V2_0.VehiclePropValue();
+ value.status = VehiclePropertyStatus.UNAVAILABLE;
+ callback.onValues(android.hardware.automotive.vehicle.V2_0.StatusCode.OK, value);
+ return null;
+ }).when(mHidlVehicle).get(any(), any());
+
+ ServiceSpecificException exception = assertThrows(ServiceSpecificException.class,
+ () -> mHidlVehicleStub.getAllPropConfigs());
+ assertThat(exception.errorCode).isEqualTo(
+ android.hardware.automotive.vehicle.V2_0.StatusCode.INTERNAL_ERROR);
+ verify(mHidlVehicle, never()).getAllPropConfigs();
+ }
+
+ @Test
public void testGetAllProdConfigsAidlSmallData() throws Exception {
VehiclePropConfigs aidlConfigs = new VehiclePropConfigs();
VehiclePropConfig aidlConfig = new VehiclePropConfig();
diff --git a/tests/carservice_unit_test/src/com/android/car/am/CarActivityServiceTaskMonitorUnitTest.java b/tests/carservice_unit_test/src/com/android/car/am/CarActivityServiceTaskMonitorUnitTest.java
index c3f8c9a..7276805 100644
--- a/tests/carservice_unit_test/src/com/android/car/am/CarActivityServiceTaskMonitorUnitTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/am/CarActivityServiceTaskMonitorUnitTest.java
@@ -102,7 +102,7 @@
private void setUpTaskOrganizer() throws Exception {
Context context = getContext();
HandlerExecutor mExecutor = new HandlerExecutor(context.getMainThreadHandler());
- mTaskOrganizer = new ShellTaskOrganizer(mExecutor, context);
+ mTaskOrganizer = new ShellTaskOrganizer(mExecutor);
TransactionPool transactionPool = new TransactionPool();
SyncTransactionQueue syncQueue = new SyncTransactionQueue(transactionPool, mExecutor);
mFullscreenTaskListener = new TestTaskListener(syncQueue);
@@ -117,7 +117,7 @@
private class TestTaskListener extends FullscreenTaskListener {
TestTaskListener(SyncTransactionQueue syncQueue) {
- super(syncQueue, /* unfoldController= */ Optional.empty());
+ super(syncQueue);
}
@Override
@@ -293,7 +293,7 @@
}
private boolean topTasksHasComponent(ComponentName component) {
- for (TaskInfo topTaskInfoContainer : mService.getTopTasks()) {
+ for (TaskInfo topTaskInfoContainer : mService.getVisibleTasks()) {
if (topTaskInfoContainer.topActivity.equals(component)) {
return true;
}
diff --git a/tests/carservice_unit_test/src/com/android/car/am/FixedActivityServiceTest.java b/tests/carservice_unit_test/src/com/android/car/am/FixedActivityServiceTest.java
index 0b35685..20618d3 100644
--- a/tests/carservice_unit_test/src/com/android/car/am/FixedActivityServiceTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/am/FixedActivityServiceTest.java
@@ -28,14 +28,17 @@
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
import static org.mockito.Mockito.when;
import android.annotation.UserIdInt;
import android.app.ActivityManager;
import android.app.ActivityOptions;
-import android.app.TaskInfo;
+import android.car.Car;
import android.car.builtin.app.ActivityManagerHelper;
+import android.car.cluster.ClusterActivityState;
import android.car.hardware.power.CarPowerManager;
import android.car.test.mocks.AbstractExtendedMockitoTestCase;
import android.car.user.CarUserManager;
@@ -47,6 +50,7 @@
import android.content.pm.ActivityInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
+import android.graphics.Rect;
import android.hardware.display.DisplayManager;
import android.net.Uri;
import android.os.Bundle;
@@ -129,7 +133,7 @@
public void testStartFixedActivityModeForDisplayAndUser_noRunningActivity()
throws Exception {
int userId = 100;
- ActivityOptions options = new ActivityOptions(new Bundle());
+ ActivityOptions options = ActivityOptions.makeBasic().setLaunchDisplayId(mValidDisplayId);
Intent intent = expectComponentAvailable("test_package", "com.test.dude", userId);
mockAmGetCurrentUser(userId);
expectNoActivityStack();
@@ -147,7 +151,7 @@
throws Exception {
int userId = 100;
int taskId = 1234;
- ActivityOptions options = new ActivityOptions(new Bundle());
+ ActivityOptions options = ActivityOptions.makeBasic().setLaunchDisplayId(mValidDisplayId);
Intent intent = expectComponentAvailable("test_package", "com.test.dude", userId);
mockAmGetCurrentUser(userId);
expectRootTaskInfo(
@@ -160,12 +164,13 @@
options, mValidDisplayId, userId);
verify(mContext).startActivityAsUser(eq(intent), any(Bundle.class),
eq(UserHandle.of(userId)));
+ clearInvocations(mContext);
assertThat(ret).isTrue();
ret = mFixedActivityService.startFixedActivityModeForDisplayAndUser(intent,
options, mValidDisplayId, userId);
- // startActivityAsUser should not called at this time. So, total called count is 1.
- verify(mContext).startActivityAsUser(eq(intent), any(Bundle.class),
+ // startActivityAsUser should not called at this time.
+ verify(mContext, never()).startActivityAsUser(any(Intent.class), any(Bundle.class),
eq(UserHandle.of(userId)));
assertThat(ret).isTrue();
}
@@ -174,7 +179,7 @@
public void testStartFixedActivityModeForDisplayAndUser_runNewActivity() throws Exception {
int userId = 100;
int taskId = 1234;
- ActivityOptions options = new ActivityOptions(new Bundle());
+ ActivityOptions options = ActivityOptions.makeBasic().setLaunchDisplayId(mValidDisplayId);
Intent intent = expectComponentAvailable("test_package", "com.test.dude", userId);
Intent anotherIntent = expectComponentAvailable("test_package_II", "com.test.dude_II",
userId);
@@ -198,18 +203,111 @@
}
@Test
+ public void testStartFixedActivityModeForDisplayAndUser_WithNewExtras() throws Exception {
+ int userId = 100;
+ int taskId = 1234;
+ ActivityOptions options = ActivityOptions.makeBasic().setLaunchDisplayId(mValidDisplayId);
+ Intent intent = expectComponentAvailable("test_package", "com.test.dude", userId);
+ mockAmGetCurrentUser(userId);
+ expectRootTaskInfo(
+ createEmptyTaskInfo(),
+ createRootTaskInfo(intent, userId, mValidDisplayId, taskId)
+ );
+
+ // No running activities
+ boolean ret = mFixedActivityService.startFixedActivityModeForDisplayAndUser(intent,
+ options, mValidDisplayId, userId);
+ assertThat(ret).isTrue();
+
+ ClusterActivityState clusterActivityState = ClusterActivityState.create(
+ /* visible= */ true, /* unobscuredBounds= */ new Rect(1, 2, 3, 4));
+ Intent intentWithExtras = new Intent(intent).putExtra(
+ Car.CAR_EXTRA_CLUSTER_ACTIVITY_STATE, clusterActivityState.toBundle());
+ ret = mFixedActivityService.startFixedActivityModeForDisplayAndUser(intentWithExtras,
+ options, mValidDisplayId, userId);
+ verify(mContext).startActivityAsUser(eq(intentWithExtras), any(Bundle.class),
+ eq(UserHandle.of(userId)));
+ assertThat(ret).isTrue();
+ }
+
+ @Test
+ public void testStartFixedActivityModeForDisplayAndUser_WithModifiedExtras() throws Exception {
+ int userId = 100;
+ int taskId = 1234;
+ ActivityOptions options = ActivityOptions.makeBasic().setLaunchDisplayId(mValidDisplayId);
+ Intent intent = expectComponentAvailable("test_package", "com.test.dude", userId);
+ ClusterActivityState clusterActivityState = ClusterActivityState.create(
+ /* visible= */ true, /* unobscuredBounds= */ new Rect(1, 2, 3, 4));
+ intent.putExtra(Car.CAR_EXTRA_CLUSTER_ACTIVITY_STATE, clusterActivityState.toBundle());
+ mockAmGetCurrentUser(userId);
+ expectRootTaskInfo(
+ createEmptyTaskInfo(),
+ createRootTaskInfo(intent, userId, mValidDisplayId, taskId)
+ );
+
+ // No running activities
+ boolean ret = mFixedActivityService.startFixedActivityModeForDisplayAndUser(intent,
+ options, mValidDisplayId, userId);
+ assertThat(ret).isTrue();
+
+ ClusterActivityState newClusterActivityState = ClusterActivityState
+ .create(/* visible= */ true, /* unobscuredBounds= */ new Rect(5, 6, 7, 8));
+ Intent intentWithModifiedExtras = new Intent(intent).putExtra(
+ Car.CAR_EXTRA_CLUSTER_ACTIVITY_STATE, newClusterActivityState.toBundle());
+ ret = mFixedActivityService.startFixedActivityModeForDisplayAndUser(
+ intentWithModifiedExtras, options, mValidDisplayId, userId);
+ verify(mContext).startActivityAsUser(eq(intentWithModifiedExtras), any(Bundle.class),
+ eq(UserHandle.of(userId)));
+ assertThat(ret).isTrue();
+ }
+
+ @Test
+ public void testStartFixedActivityModeForDisplayAndUser_WithTwoExtras() throws Exception {
+ int userId = 100;
+ int taskId = 1234;
+ // The key is selected to have the bigger hashCode() than CAR_EXTRA_CLUSTER_ACTIVITY_STATE.
+ String additionalExtraKey = "___DUMMY_KEY___";
+ ActivityOptions options = ActivityOptions.makeBasic().setLaunchDisplayId(mValidDisplayId);
+ Intent intent = expectComponentAvailable("test_package", "com.test.dude", userId);
+ ClusterActivityState clusterActivityState = ClusterActivityState.create(
+ /* visible= */ true, /* unobscuredBounds= */ new Rect(1, 2, 3, 4));
+ intent.putExtra(Car.CAR_EXTRA_CLUSTER_ACTIVITY_STATE, clusterActivityState.toBundle());
+ intent.putExtra(additionalExtraKey, 1);
+ mockAmGetCurrentUser(userId);
+ expectRootTaskInfo(
+ createEmptyTaskInfo(),
+ createRootTaskInfo(intent, userId, mValidDisplayId, taskId)
+ );
+
+ // No running activities
+ boolean ret = mFixedActivityService.startFixedActivityModeForDisplayAndUser(intent,
+ options, mValidDisplayId, userId);
+ assertThat(ret).isTrue();
+
+ Intent intentWithAdditionalExtras = new Intent(intent);
+ intent.putExtra(additionalExtraKey, 2);
+ ret = mFixedActivityService.startFixedActivityModeForDisplayAndUser(
+ intentWithAdditionalExtras, options, mValidDisplayId, userId);
+ verify(mContext).startActivityAsUser(eq(intentWithAdditionalExtras), any(Bundle.class),
+ eq(UserHandle.of(userId)));
+ assertThat(ret).isTrue();
+ }
+
+ @Test
public void testStartFixedActivityModeForDisplay_relaunchWithPackageUpdated() throws Exception {
int userId = 100;
int taskId = 1234;
String packageName = "test_package";
String className = "com.test.dude";
- ActivityOptions options = new ActivityOptions(new Bundle());
+ ActivityOptions options = ActivityOptions.makeBasic().setLaunchDisplayId(mValidDisplayId);
ArgumentCaptor<BroadcastReceiver> receiverCaptor =
ArgumentCaptor.forClass(BroadcastReceiver.class);
Intent intent = expectComponentAvailable(packageName, className, userId);
mockAmGetCurrentUser(userId);
expectRootTaskInfo(
createEmptyTaskInfo(),
+ createRootTaskInfo(intent, userId, mValidDisplayId, taskId),
+ createEmptyTaskInfo(), // Updating package will crash the app
createRootTaskInfo(intent, userId, mValidDisplayId, taskId)
);
@@ -220,6 +318,7 @@
any(IntentFilter.class), eq(null), eq(null), anyInt());
verify(mContext).startActivityAsUser(eq(intent), any(Bundle.class),
eq(UserHandle.of(userId)));
+ clearInvocations(mContext);
assertThat(ret).isTrue();
// Update package
@@ -232,12 +331,13 @@
receiver.onReceive(mContext, packageIntent);
verify(mContext).startActivityAsUser(eq(intent), any(Bundle.class),
eq(UserHandle.of(userId)));
+ clearInvocations(mContext);
SystemClock.sleep(RECHECK_INTERVAL_MARGIN_MS);
ret = mFixedActivityService.startFixedActivityModeForDisplayAndUser(intent,
options, mValidDisplayId, userId);
// Activity should not be launched.
- verify(mContext).startActivityAsUser(eq(intent), any(Bundle.class),
+ verify(mContext, never()).startActivityAsUser(any(Intent.class), any(Bundle.class),
eq(UserHandle.of(userId)));
assertThat(ret).isTrue();
}
@@ -247,7 +347,7 @@
public void testStartFixedActivityModeForDisplayAndUser_runOnDifferentDisplay()
throws Exception {
int userId = 100;
- ActivityOptions options = new ActivityOptions(new Bundle());
+ ActivityOptions options = ActivityOptions.makeBasic().setLaunchDisplayId(mValidDisplayId);
Intent intent = expectComponentAvailable("test_package", "com.test.dude", userId);
Intent anotherIntent = expectComponentAvailable("test_package_II", "com.test.dude_II",
userId);
@@ -272,7 +372,7 @@
public void testStartFixedActivityModeForDisplayAndUser_invalidDisplay() {
int userId = 100;
Intent intent = new Intent(Intent.ACTION_MAIN);
- ActivityOptions options = new ActivityOptions(new Bundle());
+ ActivityOptions options = ActivityOptions.makeBasic().setLaunchDisplayId(mValidDisplayId);
int invalidDisplayId = Display.DEFAULT_DISPLAY;
boolean ret = mFixedActivityService.startFixedActivityModeForDisplayAndUser(intent, options,
@@ -284,7 +384,7 @@
public void testStartFixedActivityModeForDisplayAndUser_unavailableDisplay() {
int userId = 100;
Intent intent = new Intent(Intent.ACTION_MAIN);
- ActivityOptions options = new ActivityOptions(new Bundle());
+ ActivityOptions options = ActivityOptions.makeBasic().setLaunchDisplayId(mValidDisplayId);
int unavailableDisplayId = mValidDisplayId + 1;
boolean started = mFixedActivityService.startFixedActivityModeForDisplayAndUser(
@@ -301,7 +401,7 @@
mValidDisplay, // for launchIf
null);
int userId = 100;
- ActivityOptions options = new ActivityOptions(new Bundle());
+ ActivityOptions options = ActivityOptions.makeBasic().setLaunchDisplayId(mValidDisplayId);
Intent intent = expectComponentAvailable("test_package", "com.test.dude", userId);
mockAmGetCurrentUser(userId);
expectNoActivityStack();
@@ -325,7 +425,7 @@
int currentUserId = 100;
int notAllowedUserId = 101;
Intent intent = new Intent(Intent.ACTION_MAIN);
- ActivityOptions options = new ActivityOptions(new Bundle());
+ ActivityOptions options = ActivityOptions.makeBasic().setLaunchDisplayId(mValidDisplayId);
int displayId = mValidDisplayId;
mockAmGetCurrentUser(currentUserId);
expectNoProfileUser(currentUserId);
@@ -338,7 +438,7 @@
@Test
public void testStartFixedActivityModeForDisplayAndUser_invalidComponent() throws Exception {
int userId = 100;
- ActivityOptions options = new ActivityOptions(new Bundle());
+ ActivityOptions options = ActivityOptions.makeBasic().setLaunchDisplayId(mValidDisplayId);
Intent invalidIntent = expectComponentUnavailable("test_package", "com.test.dude", userId);
mockAmGetCurrentUser(userId);
@@ -350,7 +450,7 @@
@Test
public void testStopFixedActivityMode() throws Exception {
int userId = 100;
- ActivityOptions options = new ActivityOptions(new Bundle());
+ ActivityOptions options = ActivityOptions.makeBasic().setLaunchDisplayId(mValidDisplayId);
Intent intent = expectComponentAvailable("test_package", "com.test.dude", userId);
mockAmGetCurrentUser(userId);
expectNoActivityStack();
@@ -421,15 +521,16 @@
mValidDisplay, // for startFixedActivityModeForDisplayAndUser
mValidDisplay, // for launchIf
null);
- ActivityOptions options = new ActivityOptions(new Bundle());
+ ActivityOptions options = ActivityOptions.makeBasic().setLaunchDisplayId(mValidDisplayId);
Intent intent = expectComponentAvailable("test_package", "com.test.dude", userId);
mockAmGetCurrentUser(userId);
- List<TaskInfo> rootTaskInfo = createRootTaskInfo(intent, userId,
+ List<ActivityManager.RunningTaskInfo> rootTaskInfo = createRootTaskInfo(intent, userId,
mValidDisplayId, taskId);
expectRootTaskInfo(rootTaskInfo);
mFixedActivityService.startFixedActivityModeForDisplayAndUser(
intent, options, mValidDisplayId, userId);
+
mockAmGetCurrentUser(notAllowedUserId);
mFixedActivityService.launchIfNecessary();
@@ -437,13 +538,22 @@
ArgumentCaptor<Bundle> activityOptionsCaptor = ArgumentCaptor.forClass(Bundle.class);
ArgumentCaptor<UserHandle> userHandleCaptor = ArgumentCaptor.forClass(UserHandle.class);
- verify(mContext).startActivityAsUser(intentCaptor.capture(),
+ verify(mContext, times(2)).startActivityAsUser(intentCaptor.capture(),
activityOptionsCaptor.capture(), userHandleCaptor.capture());
- assertThat(userHandleCaptor.getValue()).isEqualTo(
- UserHandle.of(ActivityManager.getCurrentUser()));
- assertThat(ActivityOptions.fromBundle(activityOptionsCaptor.getValue())
+
+ // Called when startFixedActivityModeForDisplayAndUser().
+ assertThat(userHandleCaptor.getAllValues().get(0)).isEqualTo(UserHandle.of(userId));
+ assertThat(ActivityOptions.fromBundle(activityOptionsCaptor.getAllValues().get(0))
.getLaunchDisplayId()).isEqualTo(mValidDisplayId);
- Intent blankActivityIntent = intentCaptor.getValue();
+ Intent capturedIntent = intentCaptor.getAllValues().get(0);
+ assertThat(capturedIntent.getComponent()).isEqualTo(intent.getComponent());
+
+ // Called when launchIfNecessary().
+ assertThat(userHandleCaptor.getAllValues().get(1))
+ .isEqualTo(UserHandle.of(notAllowedUserId));
+ assertThat(ActivityOptions.fromBundle(activityOptionsCaptor.getAllValues().get(1))
+ .getLaunchDisplayId()).isEqualTo(mValidDisplayId);
+ Intent blankActivityIntent = intentCaptor.getAllValues().get(1);
assertThat(blankActivityIntent.getComponent()).isEqualTo(
ComponentName.unflattenFromString(blankActivityComponentName));
assertThat(blankActivityIntent.getFlags() & Intent.FLAG_ACTIVITY_NEW_TASK)
@@ -454,7 +564,7 @@
private void testClearingOfRunningActivitiesOnUserSwitch(int fromUserId, int toUserId,
boolean runningFixedActivityExpected) throws Exception {
- ActivityOptions options = new ActivityOptions(new Bundle());
+ ActivityOptions options = ActivityOptions.makeBasic().setLaunchDisplayId(mValidDisplayId);
Intent intent = expectComponentAvailable("test_package", "com.test.dude", fromUserId);
mockAmGetCurrentUser(fromUserId);
expectNoActivityStack();
@@ -514,30 +624,30 @@
}
private void expectNoActivityStack() throws Exception {
- when(mActivityService.getTopTasks()).thenReturn(createEmptyTaskInfo());
+ when(mActivityService.getVisibleTasks()).thenReturn(createEmptyTaskInfo());
}
- private void expectRootTaskInfo(List<TaskInfo>... taskInfos)
+ private void expectRootTaskInfo(List<ActivityManager.RunningTaskInfo>... taskInfos)
throws Exception {
- OngoingStubbing<List<TaskInfo>> stub = when(
- mActivityService.getTopTasks());
- for (List<TaskInfo> taskInfo : taskInfos) {
+ OngoingStubbing<List<ActivityManager.RunningTaskInfo>> stub = when(
+ mActivityService.getVisibleTasks());
+ for (List<ActivityManager.RunningTaskInfo> taskInfo : taskInfos) {
stub = stub.thenReturn(taskInfo);
}
}
- private List<TaskInfo> createEmptyTaskInfo() {
+ private List<ActivityManager.RunningTaskInfo> createEmptyTaskInfo() {
return new ArrayList<>();
}
- private List<TaskInfo> createRootTaskInfo(Intent intent,
+ private List<ActivityManager.RunningTaskInfo> createRootTaskInfo(Intent intent,
@UserIdInt int userId, int displayId, int taskId) {
- TaskInfo taskInfo = new ActivityManager.RunningTaskInfo();
+ ActivityManager.RunningTaskInfo taskInfo = new ActivityManager.RunningTaskInfo();
taskInfo.topActivity = intent.getComponent().clone();
taskInfo.taskId = taskId;
taskInfo.userId = userId;
taskInfo.displayId = displayId;
- List<TaskInfo> topTasks = new ArrayList<>();
+ List<ActivityManager.RunningTaskInfo> topTasks = new ArrayList<>();
topTasks.add(taskInfo);
return topTasks;
}
diff --git a/tests/carservice_unit_test/src/com/android/car/audio/CarAudioFocusUnitTest.java b/tests/carservice_unit_test/src/com/android/car/audio/CarAudioFocusUnitTest.java
index b2f749a..0a3f3ca 100644
--- a/tests/carservice_unit_test/src/com/android/car/audio/CarAudioFocusUnitTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/audio/CarAudioFocusUnitTest.java
@@ -20,10 +20,12 @@
import static android.media.AudioAttributes.USAGE_ASSISTANT;
import static android.media.AudioAttributes.USAGE_EMERGENCY;
import static android.media.AudioAttributes.USAGE_MEDIA;
+import static android.media.AudioAttributes.USAGE_NOTIFICATION;
import static android.media.AudioAttributes.USAGE_NOTIFICATION_RINGTONE;
import static android.media.AudioAttributes.USAGE_VEHICLE_STATUS;
import static android.media.AudioAttributes.USAGE_VOICE_COMMUNICATION;
import static android.media.AudioManager.AUDIOFOCUS_GAIN;
+import static android.media.AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE;
import static android.media.AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK;
import static android.media.AudioManager.AUDIOFOCUS_LOSS;
import static android.media.AudioManager.AUDIOFOCUS_LOSS_TRANSIENT;
@@ -298,6 +300,213 @@
}
@Test
+ public void
+ requestAudioFocusWithDelayed_whileInCall_thenConcurrentNav_delayedFocusNotChanged() {
+ CarAudioFocus carAudioFocus = getCarAudioFocus();
+ AudioFocusInfo callFocusInfo = setupFocusInfoAndRequestFocusForCall(carAudioFocus);
+ AudioFocusInfo delayedFocusInfo = getDelayedExclusiveInfo(AUDIOFOCUS_GAIN);
+ carAudioFocus.onAudioFocusRequest(delayedFocusInfo, AUDIOFOCUS_REQUEST_GRANTED);
+
+ // Nav focus request: concurrent with call (and also with delayed music)
+ AudioFocusInfo secondConcurrentRequest =
+ getInfo(
+ USAGE_ASSISTANCE_NAVIGATION_GUIDANCE,
+ THIRD_CLIENT_ID,
+ AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK,
+ /* acceptsDelayedFocus= */ true);
+ carAudioFocus.onAudioFocusRequest(secondConcurrentRequest, AUDIOFOCUS_REQUEST_GRANTED);
+
+ verify(mMockAudioManager)
+ .setFocusRequestResult(
+ secondConcurrentRequest, AUDIOFOCUS_REQUEST_GRANTED, mAudioPolicy);
+ verify(mMockAudioManager, never())
+ .dispatchAudioFocusChange(callFocusInfo, AUDIOFOCUS_LOSS, mAudioPolicy);
+ verify(mMockAudioManager, never())
+ .dispatchAudioFocusChange(delayedFocusInfo, AUDIOFOCUS_LOSS, mAudioPolicy);
+ }
+
+ @Test
+ public void requestAudioFocusWithDelayed_whileInCallAndNav_thenCallStop_delayedFocusGained() {
+ CarAudioFocus carAudioFocus = getCarAudioFocus();
+ AudioFocusInfo callFocusInfo = setupFocusInfoAndRequestFocusForCall(carAudioFocus);
+ AudioFocusInfo delayedFocusInfo = getDelayedExclusiveInfo(AUDIOFOCUS_GAIN);
+ carAudioFocus.onAudioFocusRequest(delayedFocusInfo, AUDIOFOCUS_REQUEST_GRANTED);
+ // Nav focus request: concurrent with call (and also with delayed music)
+ AudioFocusInfo secondConcurrentRequest =
+ getInfo(
+ USAGE_ASSISTANCE_NAVIGATION_GUIDANCE,
+ THIRD_CLIENT_ID,
+ AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK,
+ /* acceptsDelayedFocus= */ true);
+ carAudioFocus.onAudioFocusRequest(secondConcurrentRequest, AUDIOFOCUS_REQUEST_GRANTED);
+
+ carAudioFocus.onAudioFocusAbandon(callFocusInfo);
+
+ verify(mMockAudioManager)
+ .dispatchAudioFocusChange(secondConcurrentRequest, AUDIOFOCUS_LOSS, mAudioPolicy);
+ verify(mMockAudioManager)
+ .dispatchAudioFocusChange(delayedFocusInfo, AUDIOFOCUS_GAIN, mAudioPolicy);
+ }
+
+ @Test
+ public void requestAudioFocusWithDelayed_whileInCall_thenRing_delayedFocusNotChanged() {
+ CarAudioFocus carAudioFocus = getCarAudioFocus();
+ AudioFocusInfo callFocusInfo = setupFocusInfoAndRequestFocusForCall(carAudioFocus);
+ AudioFocusInfo delayedFocusInfo = getDelayedExclusiveInfo(AUDIOFOCUS_GAIN);
+ carAudioFocus.onAudioFocusRequest(delayedFocusInfo, AUDIOFOCUS_REQUEST_GRANTED);
+
+ // Ring focus request: concurrent with call (BUT REJECT delayed music)
+ AudioFocusInfo secondConcurrentRequest =
+ getInfo(
+ USAGE_NOTIFICATION_RINGTONE,
+ THIRD_CLIENT_ID,
+ AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK,
+ true);
+ carAudioFocus.onAudioFocusRequest(secondConcurrentRequest, AUDIOFOCUS_REQUEST_GRANTED);
+
+ verify(mMockAudioManager)
+ .setFocusRequestResult(
+ secondConcurrentRequest, AUDIOFOCUS_REQUEST_GRANTED, mAudioPolicy);
+ verify(mMockAudioManager, never())
+ .dispatchAudioFocusChange(callFocusInfo, AUDIOFOCUS_LOSS, mAudioPolicy);
+ verify(mMockAudioManager, never())
+ .dispatchAudioFocusChange(delayedFocusInfo, AUDIOFOCUS_LOSS, mAudioPolicy);
+ }
+
+ @Test
+ public void
+ requestAudioFocusWithDelayed_whileInCallAndRing_thenCallStop_delayedFocusNotChanged() {
+ CarAudioFocus carAudioFocus = getCarAudioFocus();
+ AudioFocusInfo callFocusInfo = setupFocusInfoAndRequestFocusForCall(carAudioFocus);
+ AudioFocusInfo delayedFocusInfo = getDelayedExclusiveInfo(AUDIOFOCUS_GAIN);
+ carAudioFocus.onAudioFocusRequest(delayedFocusInfo, AUDIOFOCUS_REQUEST_GRANTED);
+ // Ring focus request: concurrent with call (BUT REJECT delayed music)
+ AudioFocusInfo secondConcurrentRequest =
+ getInfo(
+ USAGE_NOTIFICATION_RINGTONE,
+ THIRD_CLIENT_ID,
+ AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK,
+ true);
+ carAudioFocus.onAudioFocusRequest(secondConcurrentRequest, AUDIOFOCUS_REQUEST_GRANTED);
+
+ carAudioFocus.onAudioFocusAbandon(callFocusInfo);
+
+ verify(mMockAudioManager, never())
+ .dispatchAudioFocusChange(secondConcurrentRequest, AUDIOFOCUS_LOSS, mAudioPolicy);
+ verify(mMockAudioManager, never())
+ .dispatchAudioFocusChange(delayedFocusInfo, AUDIOFOCUS_LOSS, mAudioPolicy);
+ }
+
+ @Test
+ public void requestAudioFocusWithDelayed_whileInCallAndRing_thenBothStop_delayedFocusGained() {
+ CarAudioFocus carAudioFocus = getCarAudioFocus();
+ AudioFocusInfo callFocusInfo = setupFocusInfoAndRequestFocusForCall(carAudioFocus);
+ AudioFocusInfo delayedFocusInfo = getDelayedExclusiveInfo(AUDIOFOCUS_GAIN);
+ carAudioFocus.onAudioFocusRequest(delayedFocusInfo, AUDIOFOCUS_REQUEST_GRANTED);
+ // Yet another focus request concurrent with call (BUT REJECT delayed)
+ AudioFocusInfo secondConcurrentRequest =
+ getInfo(
+ USAGE_NOTIFICATION_RINGTONE,
+ THIRD_CLIENT_ID,
+ AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK,
+ true);
+ carAudioFocus.onAudioFocusRequest(secondConcurrentRequest, AUDIOFOCUS_REQUEST_GRANTED);
+
+ carAudioFocus.onAudioFocusAbandon(callFocusInfo);
+ carAudioFocus.onAudioFocusAbandon(secondConcurrentRequest);
+
+ verify(mMockAudioManager)
+ .dispatchAudioFocusChange(delayedFocusInfo, AUDIOFOCUS_GAIN, mAudioPolicy);
+ }
+
+ @Test
+ public void requestAudioFocusWithDelayed_whileInCall_thenNav_delayedFocusNotChanged() {
+ CarAudioFocus carAudioFocus = getCarAudioFocus();
+ AudioFocusInfo callFocusInfo = setupFocusInfoAndRequestFocusForCallRing(carAudioFocus);
+ AudioFocusInfo delayedFocusInfo =
+ getInfo(USAGE_NOTIFICATION, SECOND_CLIENT_ID, AUDIOFOCUS_GAIN,
+ /* acceptsDelayedFocus= */ true);
+ carAudioFocus.onAudioFocusRequest(delayedFocusInfo, AUDIOFOCUS_REQUEST_GRANTED);
+
+ // Nav focus request concurrent with call (BUT REJECT delayed ring)
+ AudioFocusInfo secondConcurrentRequest =
+ getInfo(
+ USAGE_ASSISTANCE_NAVIGATION_GUIDANCE,
+ THIRD_CLIENT_ID,
+ AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE,
+ true);
+ carAudioFocus.onAudioFocusRequest(secondConcurrentRequest, AUDIOFOCUS_REQUEST_GRANTED);
+
+ verify(mMockAudioManager)
+ .setFocusRequestResult(
+ secondConcurrentRequest, AUDIOFOCUS_REQUEST_GRANTED, mAudioPolicy);
+ verify(mMockAudioManager, never())
+ .dispatchAudioFocusChange(callFocusInfo, AUDIOFOCUS_LOSS, mAudioPolicy);
+ verify(mMockAudioManager, never())
+ .dispatchAudioFocusChange(delayedFocusInfo, AUDIOFOCUS_LOSS, mAudioPolicy);
+ }
+
+ @Test
+ public void requestAudioFocusWithDelayed_whileInCallAndNav_thenCallStop_delayedFocusLost() {
+ CarAudioFocus carAudioFocus = getCarAudioFocus();
+ AudioFocusInfo callFocusInfo = setupFocusInfoAndRequestFocusForCallRing(carAudioFocus);
+ AudioFocusInfo delayedFocusInfo =
+ getInfo(USAGE_NOTIFICATION, SECOND_CLIENT_ID, AUDIOFOCUS_GAIN,
+ /* acceptsDelayedFocus= */ true);
+ carAudioFocus.onAudioFocusRequest(delayedFocusInfo, AUDIOFOCUS_REQUEST_GRANTED);
+ // Nav focus request concurrent with call (BUT REJECT delayed ring)
+ AudioFocusInfo secondConcurrentRequest =
+ getInfo(
+ USAGE_ASSISTANCE_NAVIGATION_GUIDANCE,
+ THIRD_CLIENT_ID,
+ AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE,
+ /* acceptsDelayedFocus= */ true);
+ carAudioFocus.onAudioFocusRequest(secondConcurrentRequest, AUDIOFOCUS_REQUEST_GRANTED);
+
+ carAudioFocus.onAudioFocusAbandon(callFocusInfo);
+
+ verify(mMockAudioManager, never())
+ .dispatchAudioFocusChange(secondConcurrentRequest, AUDIOFOCUS_LOSS, mAudioPolicy);
+ verify(mMockAudioManager)
+ .dispatchAudioFocusChange(delayedFocusInfo, AUDIOFOCUS_LOSS, mAudioPolicy);
+ }
+
+ @Test
+ public void requestAudioFocusWithDelayed_whileInCall_thenCallFocusRequestReplaced_noChanges() {
+ CarAudioFocus carAudioFocus = getCarAudioFocus();
+ AudioFocusInfo callFocusInfo = setupFocusInfoAndRequestFocusForCall(carAudioFocus);
+ AudioFocusInfo delayedFocusInfo = getDelayedExclusiveInfo(AUDIOFOCUS_GAIN);
+ carAudioFocus.onAudioFocusRequest(delayedFocusInfo, AUDIOFOCUS_REQUEST_GRANTED);
+
+ // Same client makes the same focus request, AFI will be replaced
+ carAudioFocus.onAudioFocusRequest(callFocusInfo, AUDIOFOCUS_REQUEST_GRANTED);
+
+ verify(mMockAudioManager, times(2))
+ .setFocusRequestResult(callFocusInfo, AUDIOFOCUS_REQUEST_GRANTED, mAudioPolicy);
+ // No focus change expected for Call, even if the replaced request was removed.
+ verify(mMockAudioManager, never())
+ .dispatchAudioFocusChange(callFocusInfo, AUDIOFOCUS_LOSS, mAudioPolicy);
+ // No focus change expected for delayed as well.
+ verify(mMockAudioManager, never())
+ .dispatchAudioFocusChange(delayedFocusInfo, AUDIOFOCUS_GAIN, mAudioPolicy);
+ }
+
+ @Test
+ public void requestAudioFocus_afterReplacedFocusHolderRequestAbandon_delayedFocusGained() {
+ CarAudioFocus carAudioFocus = getCarAudioFocus();
+ AudioFocusInfo callFocusInfo = setupFocusInfoAndRequestFocusForCall(carAudioFocus);
+ AudioFocusInfo delayedFocusInfo = getDelayedExclusiveInfo(AUDIOFOCUS_GAIN);
+ carAudioFocus.onAudioFocusRequest(delayedFocusInfo, AUDIOFOCUS_REQUEST_GRANTED);
+ // Same client makes the same focus request, AFI will be replaced
+ carAudioFocus.onAudioFocusRequest(callFocusInfo, AUDIOFOCUS_REQUEST_GRANTED);
+
+ carAudioFocus.onAudioFocusAbandon(callFocusInfo);
+
+ verify(mMockAudioManager)
+ .dispatchAudioFocusChange(delayedFocusInfo, AUDIOFOCUS_GAIN, mAudioPolicy);
+ }
+
+ @Test
public void onAudioFocus_delayedRequestAbandonedBeforeGettingFocus_abandonSucceeds() {
CarAudioFocus carAudioFocus = getCarAudioFocus();
@@ -809,6 +1018,24 @@
return callFocusInfo;
}
+ private AudioFocusInfo setupFocusInfoAndRequestFocusForCallRing(CarAudioFocus carAudioFocus) {
+ return setupFocusInfoAndRequestFocusForCallRing(carAudioFocus, FIRST_CLIENT_ID);
+ }
+
+ private AudioFocusInfo setupFocusInfoAndRequestFocusForCallRing(
+ CarAudioFocus carAudioFocus, String clientId) {
+ AudioFocusInfo callFocusInfo =
+ getInfo(
+ USAGE_NOTIFICATION_RINGTONE,
+ clientId,
+ AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK,
+ /* acceptsDelayedFocus= */ false);
+ carAudioFocus.onAudioFocusRequest(callFocusInfo, AUDIOFOCUS_REQUEST_GRANTED);
+ verify(mMockAudioManager, description("Failed get focus for call"))
+ .setFocusRequestResult(callFocusInfo, AUDIOFOCUS_REQUEST_GRANTED, mAudioPolicy);
+ return callFocusInfo;
+ }
+
private AudioFocusInfo requestConcurrentFocus(CarAudioFocus carAudioFocus) {
AudioFocusInfo concurrentInfo = getConcurrentInfo(AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK);
carAudioFocus.onAudioFocusRequest(concurrentInfo, AUDIOFOCUS_REQUEST_GRANTED);
diff --git a/tests/carservice_unit_test/src/com/android/car/audio/CarAudioGainConfigInfoTest.java b/tests/carservice_unit_test/src/com/android/car/audio/CarAudioGainConfigInfoTest.java
new file mode 100644
index 0000000..2ce2769
--- /dev/null
+++ b/tests/carservice_unit_test/src/com/android/car/audio/CarAudioGainConfigInfoTest.java
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2022 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.audio;
+
+import static com.google.common.truth.Truth.assertWithMessage;
+
+import android.hardware.automotive.audiocontrol.AudioGainConfigInfo;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+public final class CarAudioGainConfigInfoTest {
+ private static final int PRIMARY_ZONE_ID = 0;
+ private static final int SECONDARY_ZONE_ID = 1;
+ private static final String PRIMARY_MUSIC_ADDRESS = "primary music";
+ private static final String PRIMARY_NAVIGATION_ADDRESS = "primary navigation";
+
+ @Test
+ public void constructor_succeeds() {
+ AudioGainConfigInfo gainInfo = new AudioGainConfigInfo();
+ gainInfo.zoneId = PRIMARY_ZONE_ID;
+ gainInfo.devicePortAddress = PRIMARY_MUSIC_ADDRESS;
+ gainInfo.volumeIndex = 666;
+ CarAudioGainConfigInfo carGainInfo = new CarAudioGainConfigInfo(gainInfo);
+
+ assertWithMessage("Audio Gain Config")
+ .that(carGainInfo.getAudioGainConfigInfo())
+ .isEqualTo(gainInfo);
+ assertWithMessage("Audio Gain Config zone id")
+ .that(carGainInfo.getZoneId())
+ .isEqualTo(PRIMARY_ZONE_ID);
+ assertWithMessage("Audio Gain Config device address")
+ .that(carGainInfo.getDeviceAddress())
+ .isEqualTo(PRIMARY_MUSIC_ADDRESS);
+ assertWithMessage("Audio Gain Config volume index")
+ .that(carGainInfo.getVolumeIndex())
+ .isEqualTo(666);
+ assertWithMessage("Audio Gain Config Literal").that(carGainInfo.toString()).isNotNull();
+ }
+
+ @Test
+ public void equals_succeeds() {
+ AudioGainConfigInfo gainInfo = new AudioGainConfigInfo();
+ gainInfo.zoneId = PRIMARY_ZONE_ID;
+ gainInfo.devicePortAddress = PRIMARY_MUSIC_ADDRESS;
+ gainInfo.volumeIndex = 666;
+ CarAudioGainConfigInfo carGainInfo1 = new CarAudioGainConfigInfo(gainInfo);
+ CarAudioGainConfigInfo carGainInfo2 = new CarAudioGainConfigInfo(gainInfo);
+
+ assertWithMessage("Audio Gain Configs").that(carGainInfo1 == carGainInfo2).isFalse();
+ assertWithMessage("Audio Gain Configs").that(carGainInfo1.equals(carGainInfo2)).isTrue();
+ assertWithMessage("Audio Gain Configs").that(carGainInfo1).isEqualTo(carGainInfo2);
+ }
+
+ @Test
+ public void equals_fails() {
+ AudioGainConfigInfo gainInfo1 = new AudioGainConfigInfo();
+ gainInfo1.zoneId = PRIMARY_ZONE_ID;
+ gainInfo1.devicePortAddress = PRIMARY_MUSIC_ADDRESS;
+ gainInfo1.volumeIndex = 666;
+ CarAudioGainConfigInfo carGainInfo1 = new CarAudioGainConfigInfo(gainInfo1);
+
+ AudioGainConfigInfo gainInfo2 = new AudioGainConfigInfo();
+ gainInfo2.zoneId = PRIMARY_ZONE_ID;
+ gainInfo2.devicePortAddress = PRIMARY_MUSIC_ADDRESS;
+ gainInfo2.volumeIndex = 999;
+ CarAudioGainConfigInfo carGainInfo2 = new CarAudioGainConfigInfo(gainInfo2);
+
+ assertWithMessage("Audio Gain Configs").that(carGainInfo1.equals(carGainInfo2)).isFalse();
+ assertWithMessage("Audio Gain Configs").that(carGainInfo1).isNotEqualTo(carGainInfo2);
+
+ AudioGainConfigInfo gainInfo3 = new AudioGainConfigInfo();
+ gainInfo3.zoneId = PRIMARY_ZONE_ID;
+ gainInfo3.devicePortAddress = PRIMARY_NAVIGATION_ADDRESS;
+ gainInfo3.volumeIndex = 666;
+ CarAudioGainConfigInfo carGainInfo3 = new CarAudioGainConfigInfo(gainInfo3);
+
+ assertWithMessage("Audio Gain Configs").that(carGainInfo1.equals(carGainInfo3)).isFalse();
+ assertWithMessage("Audio Gain Configs").that(carGainInfo1).isNotEqualTo(carGainInfo3);
+
+ AudioGainConfigInfo gainInfo4 = new AudioGainConfigInfo();
+ gainInfo4.zoneId = SECONDARY_ZONE_ID;
+ gainInfo4.devicePortAddress = PRIMARY_NAVIGATION_ADDRESS;
+ gainInfo4.volumeIndex = 666;
+ CarAudioGainConfigInfo carGainInfo4 = new CarAudioGainConfigInfo(gainInfo4);
+
+ assertWithMessage("Audio Gain Configs").that(carGainInfo1.equals(carGainInfo4)).isFalse();
+ assertWithMessage("Audio Gain Configs").that(carGainInfo1).isNotEqualTo(carGainInfo4);
+ }
+}
diff --git a/tests/carservice_unit_test/src/com/android/car/audio/CarAudioGainMonitorTest.java b/tests/carservice_unit_test/src/com/android/car/audio/CarAudioGainMonitorTest.java
new file mode 100644
index 0000000..4a98614
--- /dev/null
+++ b/tests/carservice_unit_test/src/com/android/car/audio/CarAudioGainMonitorTest.java
@@ -0,0 +1,422 @@
+/*
+ * Copyright (C) 2022 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.audio;
+
+import static com.android.car.audio.CarAudioContext.MUSIC;
+import static com.android.car.audio.CarAudioContext.NAVIGATION;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
+
+import static com.google.common.truth.Truth.assertWithMessage;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.RETURNS_DEEP_STUBS;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertThrows;
+
+import android.car.test.mocks.AbstractExtendedMockitoTestCase;
+import android.hardware.automotive.audiocontrol.AudioGainConfigInfo;
+import android.hardware.automotive.audiocontrol.IAudioControl;
+import android.hardware.automotive.audiocontrol.Reasons;
+import android.os.IBinder;
+import android.util.SparseArray;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import com.android.car.audio.hal.AudioControlWrapper.AudioControlDeathRecipient;
+import com.android.car.audio.hal.AudioControlWrapperAidl;
+import com.android.car.audio.hal.HalAudioGainCallback;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+
+import java.util.Arrays;
+import java.util.List;
+
+@RunWith(AndroidJUnit4.class)
+public final class CarAudioGainMonitorTest extends AbstractExtendedMockitoTestCase {
+ private static final int PRIMARY_ZONE_ID = 0;
+ private static final int PASSENGER_ZONE_ID = 1;
+ private static final int UNKNOWN_ZONE_ID = 50;
+ private static final int REAR_ZONE_ID = 2;
+ private static final String PRIMARY_MEDIA_ADDRESS = "primary_media";
+ private static final String PRIMARY_NAVIGATION_ADDRESS = "primary_navigation_address";
+ private static final String PRIMARY_CALL_ADDRESS = "primary_call_address";
+ private static final String REAR_MEDIA_ADDRESS = "rear_media";
+
+ private final SparseArray<CarAudioZone> mCarAudioZones = generateZoneMocks();
+
+ @Mock private IBinder mBinder;
+
+ @Mock private IAudioControl mAudioControl;
+
+ private AudioControlWrapperAidl mAudioControlWrapperAidl;
+
+ @Override
+ protected void onSessionBuilder(CustomMockitoSessionBuilder session) {
+ session.spyStatic(AudioControlWrapperAidl.class);
+ }
+
+ @Before
+ public void setUp() {
+ when(mBinder.queryLocalInterface(anyString())).thenReturn(mAudioControl);
+ doReturn(mBinder).when(AudioControlWrapperAidl::getService);
+ mAudioControlWrapperAidl = spy(new AudioControlWrapperAidl(mBinder));
+ }
+
+ @Test
+ public void constructor_fails() {
+ assertThrows(
+ NullPointerException.class,
+ () ->
+ new CarAudioGainMonitor(
+ /* AudioControlWrapper= */ null, /* SparseArray<CarAudioZone>= */
+ null));
+
+ assertThrows(
+ NullPointerException.class,
+ () ->
+ new CarAudioGainMonitor(
+ mAudioControlWrapperAidl, /* SparseArray<CarAudioZone>= */ null));
+
+ assertThrows(
+ NullPointerException.class,
+ () -> new CarAudioGainMonitor(/* AudioControlWrapper= */ null, mCarAudioZones));
+ }
+
+ @Test
+ public void constructor_succeeds() {
+ CarAudioGainMonitor carAudioGainMonitor =
+ new CarAudioGainMonitor(mAudioControlWrapperAidl, mCarAudioZones);
+
+ assertNotNull(carAudioGainMonitor);
+ }
+
+ @Test
+ public void registercallback_succeeds() {
+ CarAudioGainMonitor carAudioGainMonitor =
+ new CarAudioGainMonitor(mAudioControlWrapperAidl, mCarAudioZones);
+
+ HalAudioGainCallback callback = mock(HalAudioGainCallback.class);
+ carAudioGainMonitor.registerAudioGainListener(callback);
+ verify(mAudioControlWrapperAidl).registerAudioGainCallback(eq(callback));
+
+ carAudioGainMonitor.unregisterAudioGainListener();
+ verify(mAudioControlWrapperAidl).unregisterAudioGainCallback();
+ }
+
+ @Test
+ public void registercallback_multipleTimes() {
+ CarAudioGainMonitor carAudioGainMonitor =
+ new CarAudioGainMonitor(mAudioControlWrapperAidl, mCarAudioZones);
+ HalAudioGainCallback callback = mock(HalAudioGainCallback.class);
+ carAudioGainMonitor.registerAudioGainListener(callback);
+ verify(mAudioControlWrapperAidl).registerAudioGainCallback(eq(callback));
+
+ carAudioGainMonitor.registerAudioGainListener(callback);
+ verify(mAudioControlWrapperAidl, times(2)).registerAudioGainCallback(eq(callback));
+
+ HalAudioGainCallback callback2 = mock(HalAudioGainCallback.class);
+ carAudioGainMonitor.registerAudioGainListener(callback2);
+ verify(mAudioControlWrapperAidl).registerAudioGainCallback(eq(callback2));
+ }
+
+ @Test
+ public void handleAudioDeviceGainsChanged_validZones() {
+ CarAudioGainMonitor carAudioGainMonitor =
+ new CarAudioGainMonitor(mAudioControlWrapperAidl, mCarAudioZones);
+ List<Integer> reasons = List.of(Reasons.REMOTE_MUTE, Reasons.NAV_DUCKING);
+ AudioGainConfigInfo primaryZoneGain = new AudioGainConfigInfo();
+ primaryZoneGain.zoneId = PRIMARY_ZONE_ID;
+ primaryZoneGain.devicePortAddress = PRIMARY_MEDIA_ADDRESS;
+ CarAudioGainConfigInfo primaryZoneCarGain = new CarAudioGainConfigInfo(primaryZoneGain);
+ AudioGainConfigInfo primaryZoneGain2 = new AudioGainConfigInfo();
+ primaryZoneGain2.zoneId = PRIMARY_ZONE_ID;
+ primaryZoneGain2.devicePortAddress = PRIMARY_NAVIGATION_ADDRESS;
+ CarAudioGainConfigInfo primaryZoneCarGain2 = new CarAudioGainConfigInfo(primaryZoneGain2);
+ AudioGainConfigInfo primaryZoneGain3 = new AudioGainConfigInfo();
+ primaryZoneGain3.zoneId = PRIMARY_ZONE_ID;
+ primaryZoneGain3.devicePortAddress = PRIMARY_CALL_ADDRESS;
+ CarAudioGainConfigInfo primaryZoneCarGain3 = new CarAudioGainConfigInfo(primaryZoneGain3);
+ AudioGainConfigInfo passengerZoneGain = new AudioGainConfigInfo();
+ passengerZoneGain.zoneId = PASSENGER_ZONE_ID;
+ CarAudioGainConfigInfo passengerZoneCarGain = new CarAudioGainConfigInfo(passengerZoneGain);
+ AudioGainConfigInfo rearZoneGain = new AudioGainConfigInfo();
+ rearZoneGain.zoneId = REAR_ZONE_ID;
+ CarAudioGainConfigInfo rearZoneCarGain = new CarAudioGainConfigInfo(rearZoneGain);
+
+ SparseArray<List<CarAudioGainConfigInfo>> gainsForZones = new SparseArray<>();
+ gainsForZones.put(
+ PRIMARY_ZONE_ID,
+ Arrays.asList(primaryZoneCarGain, primaryZoneCarGain2, primaryZoneCarGain3));
+ gainsForZones.put(PASSENGER_ZONE_ID, Arrays.asList(passengerZoneCarGain));
+ gainsForZones.put(REAR_ZONE_ID, Arrays.asList(rearZoneCarGain));
+
+ List<CarAudioGainConfigInfo> gains =
+ List.of(
+ primaryZoneCarGain,
+ primaryZoneCarGain2,
+ primaryZoneCarGain3,
+ passengerZoneCarGain,
+ rearZoneCarGain);
+ carAudioGainMonitor.handleAudioDeviceGainsChanged(reasons, gains);
+
+ for (int index = 0; index < mCarAudioZones.size(); index++) {
+ CarAudioZone carAudioZone = mCarAudioZones.valueAt(index);
+ List<CarAudioGainConfigInfo> gainsForZone = gainsForZones.get(carAudioZone.getId());
+ verify(carAudioZone).onAudioGainChanged(eq(reasons), eq(gainsForZone));
+ }
+ }
+
+ @Test
+ public void handleAudioDeviceGainsChanged_validAndUnknownZones() {
+ CarAudioGainMonitor carAudioGainMonitor =
+ new CarAudioGainMonitor(mAudioControlWrapperAidl, mCarAudioZones);
+ List<Integer> reasons = List.of(Reasons.REMOTE_MUTE, Reasons.NAV_DUCKING);
+ AudioGainConfigInfo primaryZoneGain = new AudioGainConfigInfo();
+ primaryZoneGain.zoneId = PRIMARY_ZONE_ID;
+ CarAudioGainConfigInfo primaryZoneCarGain = new CarAudioGainConfigInfo(primaryZoneGain);
+ AudioGainConfigInfo rearZoneGain = new AudioGainConfigInfo();
+ rearZoneGain.zoneId = REAR_ZONE_ID;
+ CarAudioGainConfigInfo rearZoneCarGain = new CarAudioGainConfigInfo(rearZoneGain);
+ AudioGainConfigInfo unknownGain = new AudioGainConfigInfo();
+ unknownGain.zoneId = UNKNOWN_ZONE_ID;
+ CarAudioGainConfigInfo unknownCarGain = new CarAudioGainConfigInfo(unknownGain);
+
+ SparseArray<List<CarAudioGainConfigInfo>> gainsForZones = new SparseArray<>();
+ gainsForZones.put(PRIMARY_ZONE_ID, Arrays.asList(primaryZoneCarGain));
+ gainsForZones.put(REAR_ZONE_ID, Arrays.asList(rearZoneCarGain));
+ gainsForZones.put(UNKNOWN_ZONE_ID, Arrays.asList(unknownCarGain));
+
+ List<CarAudioGainConfigInfo> gains =
+ List.of(primaryZoneCarGain, unknownCarGain, rearZoneCarGain);
+ carAudioGainMonitor.handleAudioDeviceGainsChanged(reasons, gains);
+
+ for (int index = 0; index < mCarAudioZones.size(); index++) {
+ CarAudioZone carAudioZone = mCarAudioZones.valueAt(index);
+ Integer zoneId = carAudioZone.getId();
+ if (gainsForZones.contains(zoneId)) {
+ List<CarAudioGainConfigInfo> gainsForZone = gainsForZones.get(zoneId);
+ verify(carAudioZone).onAudioGainChanged(eq(reasons), eq(gainsForZone));
+ continue;
+ }
+ verify(carAudioZone, never()).onAudioGainChanged(any(), any());
+ }
+ }
+
+ @Test
+ public void handleAudioDeviceGainsChanged_unknownZones() {
+ CarAudioGainMonitor carAudioGainMonitor =
+ new CarAudioGainMonitor(mAudioControlWrapperAidl, mCarAudioZones);
+ List<Integer> reasons = List.of(Reasons.REMOTE_MUTE, Reasons.NAV_DUCKING);
+
+ AudioGainConfigInfo unknownGain = new AudioGainConfigInfo();
+ unknownGain.zoneId = UNKNOWN_ZONE_ID;
+ CarAudioGainConfigInfo unknownCarGain = new CarAudioGainConfigInfo(unknownGain);
+ AudioGainConfigInfo unknownGain2 = new AudioGainConfigInfo();
+ unknownGain2.zoneId = REAR_ZONE_ID + 1;
+ CarAudioGainConfigInfo unknownCarGain2 = new CarAudioGainConfigInfo(unknownGain2);
+
+ List<CarAudioGainConfigInfo> gains = List.of(unknownCarGain, unknownCarGain2);
+ carAudioGainMonitor.handleAudioDeviceGainsChanged(reasons, gains);
+
+ for (int index = 0; index < mCarAudioZones.size(); index++) {
+ CarAudioZone carAudioZone = mCarAudioZones.valueAt(index);
+ verify(carAudioZone, never()).onAudioGainChanged(any(), any());
+ }
+ }
+
+ @Test
+ public void shouldBlockVolumeRequest_returnsTrue() {
+ List<Integer> blockingReasons =
+ List.of(Reasons.FORCED_MASTER_MUTE, Reasons.TCU_MUTE, Reasons.REMOTE_MUTE);
+
+ // One by one
+ for (int index = 0; index < blockingReasons.size(); index++) {
+ List<Integer> reasons = Arrays.asList(blockingReasons.get(index));
+ assertWithMessage("Volume Requests Blocked")
+ .that(CarAudioGainMonitor.shouldBlockVolumeRequest(reasons))
+ .isTrue();
+ }
+ // All
+ assertWithMessage("Volume Requests Blocked")
+ .that(CarAudioGainMonitor.shouldBlockVolumeRequest(blockingReasons))
+ .isTrue();
+
+ List<Integer> mixedReasons =
+ List.of(
+ Reasons.FORCED_MASTER_MUTE,
+ Reasons.NAV_DUCKING,
+ Reasons.THERMAL_LIMITATION);
+
+ assertWithMessage("Volume Requests Blocked")
+ .that(CarAudioGainMonitor.shouldBlockVolumeRequest(mixedReasons))
+ .isTrue();
+ }
+
+ @Test
+ public void shouldBlockVolumeRequest_returnsFalse() {
+ List<Integer> nonBlockingReasons =
+ List.of(
+ Reasons.NAV_DUCKING,
+ Reasons.ADAS_DUCKING,
+ Reasons.THERMAL_LIMITATION,
+ Reasons.SUSPEND_EXIT_VOL_LIMITATION);
+
+ // One by one
+ for (int index = 0; index < nonBlockingReasons.size(); index++) {
+ List<Integer> reasons = Arrays.asList(nonBlockingReasons.get(index));
+ assertWithMessage("Volume Requests Blocked")
+ .that(CarAudioGainMonitor.shouldBlockVolumeRequest(reasons))
+ .isFalse();
+ }
+ // All
+ assertWithMessage("Volume Requests Blocked")
+ .that(CarAudioGainMonitor.shouldBlockVolumeRequest(nonBlockingReasons))
+ .isFalse();
+ }
+
+ @Test
+ public void shouldLimitVolume_returnsTrue() {
+ List<Integer> limitReasons =
+ List.of(Reasons.THERMAL_LIMITATION, Reasons.SUSPEND_EXIT_VOL_LIMITATION);
+
+ // One by one
+ for (int index = 0; index < limitReasons.size(); index++) {
+ List<Integer> reasons = Arrays.asList(limitReasons.get(index));
+ assertWithMessage("Volume Limited")
+ .that(CarAudioGainMonitor.shouldLimitVolume(reasons))
+ .isTrue();
+ }
+ // All
+ assertWithMessage("Volume Limited")
+ .that(CarAudioGainMonitor.shouldLimitVolume(limitReasons))
+ .isTrue();
+
+ List<Integer> mixedReasons =
+ List.of(
+ Reasons.FORCED_MASTER_MUTE,
+ Reasons.NAV_DUCKING,
+ Reasons.THERMAL_LIMITATION);
+
+ assertWithMessage("Volume Limited")
+ .that(CarAudioGainMonitor.shouldLimitVolume(mixedReasons))
+ .isTrue();
+ }
+
+ @Test
+ public void shouldLimitVolume_returnsFalse() {
+ List<Integer> nonLimitReasons =
+ List.of(
+ Reasons.NAV_DUCKING,
+ Reasons.ADAS_DUCKING,
+ Reasons.FORCED_MASTER_MUTE,
+ Reasons.TCU_MUTE,
+ Reasons.REMOTE_MUTE);
+
+ // One by one
+ for (int index = 0; index < nonLimitReasons.size(); index++) {
+ List<Integer> reasons = Arrays.asList(nonLimitReasons.get(index));
+ assertWithMessage("Volume Limited")
+ .that(CarAudioGainMonitor.shouldLimitVolume(reasons))
+ .isFalse();
+ }
+ // All
+ assertWithMessage("Volume Limited")
+ .that(CarAudioGainMonitor.shouldLimitVolume(nonLimitReasons))
+ .isFalse();
+ }
+
+ @Test
+ public void shouldDuckGain_returnsTrue() {
+ List<Integer> limitReasons = List.of(Reasons.ADAS_DUCKING, Reasons.NAV_DUCKING);
+
+ // One by one
+ for (int index = 0; index < limitReasons.size(); index++) {
+ List<Integer> reasons = Arrays.asList(limitReasons.get(index));
+ assertWithMessage("Volume Requests Blocked")
+ .that(CarAudioGainMonitor.shouldDuckGain(reasons))
+ .isTrue();
+ }
+ // All
+ assertWithMessage("Volume Attenuated")
+ .that(CarAudioGainMonitor.shouldDuckGain(limitReasons))
+ .isTrue();
+
+ List<Integer> mixedReasons =
+ List.of(
+ Reasons.FORCED_MASTER_MUTE,
+ Reasons.NAV_DUCKING,
+ Reasons.THERMAL_LIMITATION);
+
+ assertWithMessage("Volume Attenuated")
+ .that(CarAudioGainMonitor.shouldDuckGain(mixedReasons))
+ .isTrue();
+ }
+
+ @Test
+ public void shouldDuckGain_returnsFalse() {
+ List<Integer> nonDuckingReasons =
+ List.of(
+ Reasons.THERMAL_LIMITATION,
+ Reasons.SUSPEND_EXIT_VOL_LIMITATION,
+ Reasons.FORCED_MASTER_MUTE,
+ Reasons.TCU_MUTE,
+ Reasons.REMOTE_MUTE);
+
+ // One by one
+ for (int index = 0; index < nonDuckingReasons.size(); index++) {
+ List<Integer> reasons = Arrays.asList(nonDuckingReasons.get(index));
+ assertWithMessage("Volume Attenuated")
+ .that(CarAudioGainMonitor.shouldDuckGain(reasons))
+ .isFalse();
+ }
+ // All
+ assertWithMessage("Volume Attenuated")
+ .that(CarAudioGainMonitor.shouldDuckGain(nonDuckingReasons))
+ .isFalse();
+ }
+
+ private static SparseArray<CarAudioZone> generateZoneMocks() {
+ SparseArray<CarAudioZone> zones = new SparseArray<>();
+ CarAudioZone primaryZone = mock(CarAudioZone.class, RETURNS_DEEP_STUBS);
+ when(primaryZone.getId()).thenReturn(PRIMARY_ZONE_ID);
+ when(primaryZone.getAddressForContext(MUSIC)).thenReturn(PRIMARY_MEDIA_ADDRESS);
+ when(primaryZone.getAddressForContext(NAVIGATION)).thenReturn(PRIMARY_NAVIGATION_ADDRESS);
+ zones.append(PRIMARY_ZONE_ID, primaryZone);
+
+ CarAudioZone passengerZone = mock(CarAudioZone.class, RETURNS_DEEP_STUBS);
+ when(passengerZone.getId()).thenReturn(PASSENGER_ZONE_ID);
+ zones.append(PASSENGER_ZONE_ID, passengerZone);
+
+ CarAudioZone rearZone = mock(CarAudioZone.class, RETURNS_DEEP_STUBS);
+ when(rearZone.getId()).thenReturn(REAR_ZONE_ID);
+ when(rearZone.getAddressForContext(MUSIC)).thenReturn(REAR_MEDIA_ADDRESS);
+ zones.append(REAR_ZONE_ID, rearZone);
+
+ return zones;
+ }
+}
diff --git a/tests/carservice_unit_test/src/com/android/car/audio/CarDuckingInfoTest.java b/tests/carservice_unit_test/src/com/android/car/audio/CarDuckingInfoTest.java
index 150a48a..b1365bc 100644
--- a/tests/carservice_unit_test/src/com/android/car/audio/CarDuckingInfoTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/audio/CarDuckingInfoTest.java
@@ -21,9 +21,12 @@
import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.Mockito.RETURNS_DEEP_STUBS;
+import static org.mockito.Mockito.mock;
import static org.testng.Assert.assertThrows;
import android.audio.policy.configuration.V7_0.AudioUsage;
+import android.hardware.audio.common.PlaybackTrackMetadata;
import android.hardware.automotive.audiocontrol.DuckingInfo;
import androidx.test.ext.junit.runners.AndroidJUnit4;
@@ -36,26 +39,42 @@
@RunWith(AndroidJUnit4.class)
public class CarDuckingInfoTest {
private static final int ZONE_ID = 0;
- private static final List<String> sAddressesToDuck = List.of("address1", "address2");
- private static final List<String> sAddressesToUnduck = List.of("address3", "address4");
- private static final int[] sUsagesHoldingFocus = {USAGE_MEDIA, USAGE_NOTIFICATION};
+ private static final List<String> ADDRESSES_TO_DUCK = List.of("address1", "address2");
+ private static final List<String> ADDRESSES_TO_UNDUCK = List.of("address3", "address4");
+ private static final int[] USAGES_HOLDING_FOCUS = {USAGE_MEDIA, USAGE_NOTIFICATION};
+ private static final List<PlaybackTrackMetadata> PLAYBACKTRACK_METADATA_HOLDING_FOCUS =
+ CarHalAudioUtils.usagesToMetadatas(
+ USAGES_HOLDING_FOCUS, mock(CarAudioZone.class, RETURNS_DEEP_STUBS));
@Test
public void constructor_nullAddressesToDuck_throws() {
- assertThrows(NullPointerException.class, () -> new CarDuckingInfo(ZONE_ID, null,
- sAddressesToUnduck, sUsagesHoldingFocus));
+ assertThrows(
+ NullPointerException.class,
+ () ->
+ new CarDuckingInfo(
+ ZONE_ID,
+ null,
+ ADDRESSES_TO_UNDUCK,
+ PLAYBACKTRACK_METADATA_HOLDING_FOCUS));
}
@Test
public void constructor_nullAddressesToUnduck_throws() {
- assertThrows(NullPointerException.class, () -> new CarDuckingInfo(ZONE_ID, sAddressesToDuck,
- null, sUsagesHoldingFocus));
+ assertThrows(
+ NullPointerException.class,
+ () ->
+ new CarDuckingInfo(
+ ZONE_ID,
+ ADDRESSES_TO_DUCK,
+ null,
+ PLAYBACKTRACK_METADATA_HOLDING_FOCUS));
}
@Test
public void constructor_nullusagesHoldingFocus_throws() {
- assertThrows(NullPointerException.class, () -> new CarDuckingInfo(ZONE_ID, sAddressesToDuck,
- sAddressesToUnduck, null));
+ assertThrows(
+ NullPointerException.class,
+ () -> new CarDuckingInfo(ZONE_ID, ADDRESSES_TO_DUCK, ADDRESSES_TO_UNDUCK, null));
}
@Test
@@ -63,17 +82,24 @@
CarDuckingInfo duckingInfo = getCarDuckingInfo();
assertThat(duckingInfo.mZoneId).isEqualTo(ZONE_ID);
- assertThat(duckingInfo.mAddressesToDuck).containsExactlyElementsIn(sAddressesToDuck);
- assertThat(duckingInfo.mAddressesToUnduck).containsExactlyElementsIn(sAddressesToUnduck);
- assertThat(duckingInfo.mUsagesHoldingFocus).asList()
- .containsExactly(USAGE_MEDIA, USAGE_NOTIFICATION);
+ assertThat(duckingInfo.mAddressesToDuck).containsExactlyElementsIn(ADDRESSES_TO_DUCK);
+ assertThat(duckingInfo.mAddressesToUnduck).containsExactlyElementsIn(ADDRESSES_TO_UNDUCK);
+ assertThat(duckingInfo.mPlaybackMetaDataHoldingFocus)
+ .containsExactlyElementsIn(PLAYBACKTRACK_METADATA_HOLDING_FOCUS);
+
+ assertThat(duckingInfo.getZoneId()).isEqualTo(ZONE_ID);
+ assertThat(duckingInfo.getAddressesToDuck()).containsExactlyElementsIn(ADDRESSES_TO_DUCK);
+ assertThat(duckingInfo.getAddressesToUnduck())
+ .containsExactlyElementsIn(ADDRESSES_TO_UNDUCK);
+ assertThat(duckingInfo.getPlaybackMetaDataHoldingFocus())
+ .containsExactlyElementsIn(PLAYBACKTRACK_METADATA_HOLDING_FOCUS);
}
@Test
public void generateDuckingInfo_includesSameAddressesToDuck() {
CarDuckingInfo carDuckingInfo = getCarDuckingInfo();
- DuckingInfo duckingInfo = carDuckingInfo.generateDuckingInfo();
+ DuckingInfo duckingInfo = CarHalAudioUtils.generateDuckingInfo(carDuckingInfo);
assertThat(duckingInfo.deviceAddressesToDuck).asList()
.containsExactlyElementsIn(carDuckingInfo.mAddressesToDuck);
@@ -83,7 +109,7 @@
public void generateDuckingInfo_includesSameAddressesToUnduck() {
CarDuckingInfo carDuckingInfo = getCarDuckingInfo();
- DuckingInfo duckingInfo = carDuckingInfo.generateDuckingInfo();
+ DuckingInfo duckingInfo = CarHalAudioUtils.generateDuckingInfo(carDuckingInfo);
assertThat(duckingInfo.deviceAddressesToUnduck).asList()
.containsExactlyElementsIn(carDuckingInfo.mAddressesToUnduck);
@@ -93,15 +119,29 @@
public void generateDuckingInfo_includesSameUsagesHoldingFocus() {
CarDuckingInfo carDuckingInfo = getCarDuckingInfo();
- DuckingInfo duckingInfo = carDuckingInfo.generateDuckingInfo();
+ DuckingInfo duckingInfo = CarHalAudioUtils.generateDuckingInfo(carDuckingInfo);
assertThat(duckingInfo.usagesHoldingFocus).asList()
.containsExactly(AudioUsage.AUDIO_USAGE_MEDIA.toString(),
AudioUsage.AUDIO_USAGE_NOTIFICATION.toString());
}
+ @Test
+ public void generateDuckingInfo_includesSamePlaybackTrackMetadataHoldingFocus() {
+ CarDuckingInfo carDuckingInfo = getCarDuckingInfo();
+
+ DuckingInfo duckingInfo = CarHalAudioUtils.generateDuckingInfo(carDuckingInfo);
+
+ assertThat(duckingInfo.playbackMetaDataHoldingFocus)
+ .asList()
+ .containsExactlyElementsIn(PLAYBACKTRACK_METADATA_HOLDING_FOCUS);
+ }
+
private CarDuckingInfo getCarDuckingInfo() {
- return new CarDuckingInfo(ZONE_ID, sAddressesToDuck, sAddressesToUnduck,
- sUsagesHoldingFocus);
+ return new CarDuckingInfo(
+ ZONE_ID,
+ ADDRESSES_TO_DUCK,
+ ADDRESSES_TO_UNDUCK,
+ PLAYBACKTRACK_METADATA_HOLDING_FOCUS);
}
}
diff --git a/tests/carservice_unit_test/src/com/android/car/audio/CarDuckingTest.java b/tests/carservice_unit_test/src/com/android/car/audio/CarDuckingTest.java
index 4a0171b..0e58e4f 100644
--- a/tests/carservice_unit_test/src/com/android/car/audio/CarDuckingTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/audio/CarDuckingTest.java
@@ -87,7 +87,7 @@
int zoneId = mCarAudioZones.keyAt(i);
CarDuckingInfo duckingInfo = currentDuckingInfo.get(zoneId);
assertThat(duckingInfo).isNotNull();
- assertThat(duckingInfo.mUsagesHoldingFocus).isEmpty();
+ assertThat(duckingInfo.mPlaybackMetaDataHoldingFocus).isEmpty();
assertThat(duckingInfo.mAddressesToDuck).isEmpty();
assertThat(duckingInfo.mAddressesToUnduck).isEmpty();
}
@@ -98,8 +98,11 @@
mCarDucking.onFocusChange(ONE_ZONE_CHANGE, mMediaFocusHolders);
SparseArray<CarDuckingInfo> newDuckingInfo = mCarDucking.getCurrentDuckingInfo();
- assertThat(newDuckingInfo.get(PRIMARY_ZONE_ID).mUsagesHoldingFocus)
- .asList().containsExactly(USAGE_MEDIA);
+ assertThat(
+ CarHalAudioUtils.metadatasToUsages(
+ newDuckingInfo.get(PRIMARY_ZONE_ID).mPlaybackMetaDataHoldingFocus))
+ .asList()
+ .containsExactly(USAGE_MEDIA);
}
@Test
@@ -107,8 +110,8 @@
mCarDucking.onFocusChange(ONE_ZONE_CHANGE, mMediaFocusHolders);
SparseArray<CarDuckingInfo> newDuckingInfo = mCarDucking.getCurrentDuckingInfo();
- assertThat(newDuckingInfo.get(PASSENGER_ZONE_ID).mUsagesHoldingFocus).isEmpty();
- assertThat(newDuckingInfo.get(REAR_ZONE_ID).mUsagesHoldingFocus).isEmpty();
+ assertThat(newDuckingInfo.get(PASSENGER_ZONE_ID).mPlaybackMetaDataHoldingFocus).isEmpty();
+ assertThat(newDuckingInfo.get(REAR_ZONE_ID).mPlaybackMetaDataHoldingFocus).isEmpty();
}
@Test
@@ -136,7 +139,9 @@
mCarDucking.onFocusChange(ONE_ZONE_CHANGE, mMediaFocusHolders);
verify(mMockAudioControlWrapper).onDevicesToDuckChange(mCarDuckingInfosCaptor.capture());
- int[] usagesHoldingFocus = mCarDuckingInfosCaptor.getValue().get(0).mUsagesHoldingFocus;
+ int[] usagesHoldingFocus =
+ CarHalAudioUtils.metadatasToUsages(
+ mCarDuckingInfosCaptor.getValue().get(0).mPlaybackMetaDataHoldingFocus);
assertThat(usagesHoldingFocus).asList().containsExactly(USAGE_MEDIA);
}
diff --git a/tests/carservice_unit_test/src/com/android/car/audio/CarDuckingUtilsTest.java b/tests/carservice_unit_test/src/com/android/car/audio/CarDuckingUtilsTest.java
index ece0f00..bd8291b 100644
--- a/tests/carservice_unit_test/src/com/android/car/audio/CarDuckingUtilsTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/audio/CarDuckingUtilsTest.java
@@ -38,6 +38,7 @@
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
+import android.hardware.audio.common.PlaybackTrackMetadata;
import android.media.AudioAttributes;
import android.media.AudioFocusInfo;
@@ -60,6 +61,8 @@
private static final String CALL_ADDRESS = "call";
private static final String NAVIGATION_ADDRESS = "navigation";
+ private static final int ZONE_ID = 0;
+
@Test
public void sContextsToDuck_verifyNoCycles() {
for (int i = 0; i < CarDuckingUtils.sContextsToDuck.size(); i++) {
@@ -222,6 +225,77 @@
assertThat(result).isEmpty();
}
+ @Test
+ public void generateDuckingInfo_succeed() {
+ CarAudioZone mockZone = generateAudioZoneMock();
+
+ List<AudioFocusInfo> focusHolders =
+ List.of(
+ generateAudioFocusInfoForUsage(USAGE_MEDIA),
+ generateAudioFocusInfoForUsage(USAGE_ASSISTANCE_NAVIGATION_GUIDANCE),
+ generateAudioFocusInfoForSystemUsage(USAGE_SAFETY));
+ List<PlaybackTrackMetadata> playbackTrackMetadataHoldingFocus =
+ CarHalAudioUtils.usagesToMetadatas(
+ new int[] {USAGE_MEDIA, USAGE_ASSISTANCE_NAVIGATION_GUIDANCE, USAGE_SAFETY},
+ mockZone);
+
+ CarDuckingInfo duckingInfo =
+ CarDuckingUtils.generateDuckingInfo(
+ getEmptyCarDuckingInfo(), focusHolders, mockZone);
+
+ assertThat(duckingInfo.getZoneId()).isEqualTo(ZONE_ID);
+ assertThat(duckingInfo.getAddressesToDuck())
+ .containsExactly(MEDIA_ADDRESS, NAVIGATION_ADDRESS);
+ assertThat(duckingInfo.getAddressesToUnduck()).isEmpty();
+ assertThat(duckingInfo.getPlaybackMetaDataHoldingFocus())
+ .containsExactlyElementsIn(playbackTrackMetadataHoldingFocus);
+
+ // Then decimate safety
+ focusHolders =
+ List.of(
+ generateAudioFocusInfoForUsage(USAGE_MEDIA),
+ generateAudioFocusInfoForUsage(USAGE_ASSISTANCE_NAVIGATION_GUIDANCE));
+ playbackTrackMetadataHoldingFocus =
+ CarHalAudioUtils.usagesToMetadatas(
+ new int[] {USAGE_MEDIA, USAGE_ASSISTANCE_NAVIGATION_GUIDANCE}, mockZone);
+
+ CarDuckingInfo duckingInfo1 =
+ CarDuckingUtils.generateDuckingInfo(duckingInfo, focusHolders, mockZone);
+
+ assertThat(duckingInfo1.getZoneId()).isEqualTo(ZONE_ID);
+ assertThat(duckingInfo1.getAddressesToDuck()).containsExactly(MEDIA_ADDRESS);
+ assertThat(duckingInfo1.getAddressesToUnduck()).containsExactly(NAVIGATION_ADDRESS);
+ assertThat(duckingInfo1.getPlaybackMetaDataHoldingFocus())
+ .containsExactlyElementsIn(playbackTrackMetadataHoldingFocus);
+
+ // Then decimate nav
+ focusHolders = List.of(generateAudioFocusInfoForUsage(USAGE_MEDIA));
+ playbackTrackMetadataHoldingFocus =
+ CarHalAudioUtils.usagesToMetadatas(new int[] {USAGE_MEDIA}, mockZone);
+
+ CarDuckingInfo duckingInfo2 =
+ CarDuckingUtils.generateDuckingInfo(duckingInfo1, focusHolders, mockZone);
+
+ assertThat(duckingInfo2.getZoneId()).isEqualTo(ZONE_ID);
+ assertThat(duckingInfo2.getAddressesToDuck()).isEmpty();
+ assertThat(duckingInfo2.getAddressesToUnduck()).containsExactly(MEDIA_ADDRESS);
+ assertThat(duckingInfo2.getPlaybackMetaDataHoldingFocus())
+ .containsExactlyElementsIn(playbackTrackMetadataHoldingFocus);
+
+ // back to none holding focus
+ focusHolders = new ArrayList<AudioFocusInfo>();
+ playbackTrackMetadataHoldingFocus =
+ CarHalAudioUtils.usagesToMetadatas(new int[] {USAGE_MEDIA}, mockZone);
+
+ CarDuckingInfo duckingInfo3 =
+ CarDuckingUtils.generateDuckingInfo(duckingInfo2, focusHolders, mockZone);
+
+ assertThat(duckingInfo3.getZoneId()).isEqualTo(ZONE_ID);
+ assertThat(duckingInfo3.getAddressesToDuck()).isEmpty();
+ assertThat(duckingInfo3.getAddressesToUnduck()).isEmpty();
+ assertThat(duckingInfo3.getPlaybackMetaDataHoldingFocus()).isEmpty();
+ }
+
private static AudioFocusInfo generateAudioFocusInfoForUsage(int usage) {
AudioAttributes attributes = new AudioAttributes.Builder().setUsage(usage).build();
return new AudioFocusInfo(attributes, 0, "client_id", "package.name",
@@ -242,7 +316,16 @@
when(mockZone.getAddressForContext(CALL)).thenReturn(CALL_ADDRESS);
when(mockZone.getAddressForContext(NAVIGATION)).thenReturn(NAVIGATION_ADDRESS);
when(mockZone.getAddressForContext(INVALID)).thenThrow(new IllegalArgumentException());
+ when(mockZone.getAddressForContext(NAVIGATION)).thenReturn(NAVIGATION_ADDRESS);
return mockZone;
}
+
+ private CarDuckingInfo getEmptyCarDuckingInfo() {
+ return new CarDuckingInfo(
+ ZONE_ID,
+ new ArrayList<String>(),
+ new ArrayList<String>(),
+ new ArrayList<PlaybackTrackMetadata>());
+ }
}
diff --git a/tests/carservice_unit_test/src/com/android/car/audio/CarHalAudioUtilsTest.java b/tests/carservice_unit_test/src/com/android/car/audio/CarHalAudioUtilsTest.java
new file mode 100644
index 0000000..45c6b99
--- /dev/null
+++ b/tests/carservice_unit_test/src/com/android/car/audio/CarHalAudioUtilsTest.java
@@ -0,0 +1,245 @@
+/*
+ * Copyright (C) 2022 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.audio;
+
+import static android.media.AudioAttributes.USAGE_MEDIA;
+import static android.media.AudioAttributes.USAGE_NOTIFICATION;
+
+import static com.android.car.audio.CarAudioContext.MUSIC;
+import static com.android.car.audio.CarAudioContext.NOTIFICATION;
+
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import android.audio.policy.configuration.V7_0.AudioUsage;
+import android.hardware.audio.common.PlaybackTrackMetadata;
+import android.hardware.automotive.audiocontrol.DuckingInfo;
+import android.media.audio.common.AudioDevice;
+import android.media.audio.common.AudioDeviceAddress;
+import android.media.audio.common.AudioDeviceDescription;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+
+import java.util.ArrayList;
+import java.util.List;
+
+@RunWith(AndroidJUnit4.class)
+public class CarHalAudioUtilsTest {
+ private static final int ZONE_ID = 0;
+ private static final String MEDIA_ADDRESS = "MEDIA_ADDRESS";
+ private static final String NOTIFICATION_ADDRESS = "NOTIFICATION_ADDRESS";
+ private static final List<String> ADDRESSES_TO_DUCK = List.of("address1", "address2");
+ private static final List<String> ADDRESSES_TO_UNDUCK = List.of("address3", "address4");
+ private static final int[] USAGES_HOLDING_FOCUS = {USAGE_MEDIA, USAGE_NOTIFICATION};
+ private static final String[] USAGES_LITERAL_HOLDING_FOCUS = {
+ AudioUsage.AUDIO_USAGE_MEDIA.toString(), AudioUsage.AUDIO_USAGE_NOTIFICATION.toString()
+ };
+
+ private final List<PlaybackTrackMetadata> mPlaybackTrackMetadataHoldingFocus =
+ new ArrayList<>();
+
+ private final CarAudioZone mCarAudioZone = generateZoneMock();
+
+ @Rule public MockitoRule rule = MockitoJUnit.rule();
+
+ @Before
+ public void setUp() {
+ for (int index = 0; index < USAGES_HOLDING_FOCUS.length; index++) {
+ PlaybackTrackMetadata playbackTrackMetadata = new PlaybackTrackMetadata();
+ playbackTrackMetadata.usage = USAGES_HOLDING_FOCUS[index];
+
+ AudioDeviceDescription add = new AudioDeviceDescription();
+ add.connection = new String();
+ AudioDevice ad = new AudioDevice();
+ ad.type = add;
+ ad.address =
+ AudioDeviceAddress.id(
+ mCarAudioZone.getAddressForContext(
+ CarAudioContext.getContextForUsage(
+ USAGES_HOLDING_FOCUS[index])));
+ playbackTrackMetadata.sourceDevice = ad;
+
+ mPlaybackTrackMetadataHoldingFocus.add(playbackTrackMetadata);
+ }
+ }
+
+ @Test
+ public void generateDuckingInfo_succeeds() {
+ DuckingInfo duckingInfo = CarHalAudioUtils.generateDuckingInfo(getCarDuckingInfo());
+
+ assertWithMessage("Generated duck info zone ").that(duckingInfo.zoneId).isEqualTo(ZONE_ID);
+ assertWithMessage("Generated duck info addresses to duck")
+ .that(duckingInfo.deviceAddressesToDuck)
+ .asList()
+ .containsExactlyElementsIn(ADDRESSES_TO_DUCK);
+ assertWithMessage("Generated duck info addresses to unduck")
+ .that(duckingInfo.deviceAddressesToUnduck)
+ .asList()
+ .containsExactlyElementsIn(ADDRESSES_TO_UNDUCK);
+ assertWithMessage("Generated duck info playback metadata holding focus")
+ .that(duckingInfo.playbackMetaDataHoldingFocus)
+ .asList()
+ .containsExactlyElementsIn(mPlaybackTrackMetadataHoldingFocus);
+ }
+
+ @Test
+ public void usageToMetadata_succeeds() {
+ PlaybackTrackMetadata playbackTrackMetadata =
+ CarHalAudioUtils.usageToMetadata(USAGE_MEDIA, mCarAudioZone);
+ assertWithMessage("Playback Track Metadata usage")
+ .that(playbackTrackMetadata.usage)
+ .isEqualTo(USAGE_MEDIA);
+ assertWithMessage("Playback Track Metadata source device address")
+ .that(playbackTrackMetadata.sourceDevice.address.getId())
+ .isEqualTo(MEDIA_ADDRESS);
+ }
+
+ @Test
+ public void usageToMetadata_withNullZone_succeeds() {
+ PlaybackTrackMetadata playbackTrackMetadata =
+ CarHalAudioUtils.usageToMetadata(USAGE_MEDIA, /*CarAudioZone=*/ null);
+ assertWithMessage("Playback Track Metadata usage")
+ .that(playbackTrackMetadata.usage)
+ .isEqualTo(USAGE_MEDIA);
+ String emptyAddress = new String("");
+ assertWithMessage("Playback Track Metadata source device address")
+ .that(playbackTrackMetadata.sourceDevice.address.getId())
+ .isEqualTo(emptyAddress);
+ }
+
+ @Test
+ public void usagesToMetadatas_succeeds() {
+ List<PlaybackTrackMetadata> playbackTrackMetadataList =
+ CarHalAudioUtils.usagesToMetadatas(USAGES_HOLDING_FOCUS, mCarAudioZone);
+
+ assertWithMessage(
+ "Converted PlaybackTrackMetadata size for usages holding focus size %s",
+ USAGES_HOLDING_FOCUS.length)
+ .that(playbackTrackMetadataList.size())
+ .isEqualTo(USAGES_HOLDING_FOCUS.length);
+
+ int[] usages = new int[playbackTrackMetadataList.size()];
+ String[] addresses = new String[playbackTrackMetadataList.size()];
+ for (int index = 0; index < playbackTrackMetadataList.size(); index++) {
+ PlaybackTrackMetadata playbackTrackMetadata = playbackTrackMetadataList.get(index);
+ usages[index] = playbackTrackMetadata.usage;
+ addresses[index] = playbackTrackMetadata.sourceDevice.address.getId();
+ }
+ assertWithMessage("Converted usages to PlaybackTrackMetadata usage")
+ .that(usages)
+ .asList()
+ .containsExactly(USAGE_MEDIA, USAGE_NOTIFICATION);
+ assertWithMessage("Converted usages to PlaybackTrackMetadata addresses")
+ .that(addresses)
+ .asList()
+ .containsExactly(MEDIA_ADDRESS, NOTIFICATION_ADDRESS);
+ }
+
+ @Test
+ public void usagesToMetadatas_withNullZone_succeeds() {
+ List<PlaybackTrackMetadata> playbackTrackMetadataList =
+ CarHalAudioUtils.usagesToMetadatas(USAGES_HOLDING_FOCUS, /*CarAudioZone=*/ null);
+
+ assertWithMessage(
+ "Converted PlaybackTrackMetadata size for usages holding focus size %s",
+ USAGES_HOLDING_FOCUS.length)
+ .that(playbackTrackMetadataList.size())
+ .isEqualTo(USAGES_HOLDING_FOCUS.length);
+
+ int[] usages = new int[playbackTrackMetadataList.size()];
+ String[] addresses = new String[playbackTrackMetadataList.size()];
+ for (int index = 0; index < playbackTrackMetadataList.size(); index++) {
+ PlaybackTrackMetadata playbackTrackMetadata = playbackTrackMetadataList.get(index);
+ usages[index] = playbackTrackMetadata.usage;
+ String emptyAddress = new String("");
+ assertWithMessage("Source device address Id for Usage %s", usages[index])
+ .that(playbackTrackMetadata.sourceDevice.address.getId())
+ .isEqualTo(emptyAddress);
+ }
+ assertWithMessage("Converted usages to PlaybackTrackMetadata usages")
+ .that(usages)
+ .asList()
+ .containsExactly(USAGE_MEDIA, USAGE_NOTIFICATION);
+ }
+
+ @Test
+ public void metadataToUsage_succeeds() {
+ for (int index = 0; index < mPlaybackTrackMetadataHoldingFocus.size(); index++) {
+ PlaybackTrackMetadata playbackTrackMetadata =
+ mPlaybackTrackMetadataHoldingFocus.get(index);
+ int usage = CarHalAudioUtils.metadataToUsage(playbackTrackMetadata);
+ assertWithMessage(
+ "Buld Converted PlaybackTrackMetadata[%s] usage", playbackTrackMetadata)
+ .that(usage)
+ .isEqualTo(playbackTrackMetadata.usage);
+ }
+ }
+
+ @Test
+ public void metadatasToUsages_succeeds() {
+ int[] usages = CarHalAudioUtils.metadatasToUsages(mPlaybackTrackMetadataHoldingFocus);
+ assertThat(usages.length).isEqualTo(mPlaybackTrackMetadataHoldingFocus.size());
+ assertThat(usages).asList().containsExactly(USAGE_MEDIA, USAGE_NOTIFICATION);
+
+ for (int index = 0; index < usages.length; index++) {
+ int usage = usages[index];
+ PlaybackTrackMetadata playbackTrackMetadata =
+ mPlaybackTrackMetadataHoldingFocus.get(index);
+ assertWithMessage(
+ "Buld Converted PlaybackTrackMetadata[%s] usage", playbackTrackMetadata)
+ .that(usage)
+ .isEqualTo(playbackTrackMetadata.usage);
+ }
+ }
+
+ @Test
+ public void metadatasToUsageStrings_succeeds() {
+ String[] usageLiteralsForMetadata =
+ CarHalAudioUtils.metadatasToUsageStrings(mPlaybackTrackMetadataHoldingFocus);
+ assertThat(usageLiteralsForMetadata.length)
+ .isEqualTo(mPlaybackTrackMetadataHoldingFocus.size());
+ assertThat(usageLiteralsForMetadata)
+ .asList()
+ .containsExactlyElementsIn(USAGES_LITERAL_HOLDING_FOCUS);
+ }
+
+ private CarDuckingInfo getCarDuckingInfo() {
+ return new CarDuckingInfo(
+ ZONE_ID,
+ ADDRESSES_TO_DUCK,
+ ADDRESSES_TO_UNDUCK,
+ mPlaybackTrackMetadataHoldingFocus);
+ }
+
+ private static CarAudioZone generateZoneMock() {
+ CarAudioZone zone = mock(CarAudioZone.class);
+ when(zone.getId()).thenReturn(ZONE_ID);
+ when(zone.getAddressForContext(MUSIC)).thenReturn(MEDIA_ADDRESS);
+ when(zone.getAddressForContext(NOTIFICATION)).thenReturn(NOTIFICATION_ADDRESS);
+ return zone;
+ }
+}
diff --git a/tests/carservice_unit_test/src/com/android/car/audio/CarVolumeGroupUnitTest.java b/tests/carservice_unit_test/src/com/android/car/audio/CarVolumeGroupUnitTest.java
index d71a0d5..ffaa4cb 100644
--- a/tests/carservice_unit_test/src/com/android/car/audio/CarVolumeGroupUnitTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/audio/CarVolumeGroupUnitTest.java
@@ -23,14 +23,21 @@
import static com.android.car.audio.CarAudioContext.MUSIC;
import static com.android.car.audio.CarAudioContext.NAVIGATION;
import static com.android.car.audio.CarAudioContext.NOTIFICATION;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
+import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth.assertWithMessage;
-import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.anyInt;
+import static org.mockito.Mockito.eq;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
import static org.mockito.Mockito.when;
import static org.testng.Assert.expectThrows;
import android.annotation.UserIdInt;
+import android.hardware.automotive.audiocontrol.AudioGainConfigInfo;
+import android.hardware.automotive.audiocontrol.Reasons;
import android.os.UserHandle;
import android.util.SparseBooleanArray;
import android.util.SparseIntArray;
@@ -42,6 +49,7 @@
import org.mockito.Mockito;
import org.mockito.junit.MockitoJUnitRunner;
+import java.util.ArrayList;
import java.util.List;
@RunWith(MockitoJUnitRunner.class)
@@ -576,6 +584,531 @@
.that(carVolumeGroup.isMuted()).isEqualTo(false);
}
+ @Test
+ public void setBlocked_withGain_thenBackToUninitializedGain() {
+ CarVolumeGroup carVolumeGroup = testVolumeGroupSetup();
+
+ assertThat(carVolumeGroup.isBlocked()).isFalse();
+
+ carVolumeGroup.setBlocked(10);
+
+ assertThat(carVolumeGroup.isBlocked()).isTrue();
+
+ carVolumeGroup.resetBlocked();
+
+ assertThat(carVolumeGroup.isBlocked()).isFalse();
+ }
+
+ @Test
+ public void setLimited_withGain_thenBackToMaxGain() {
+ CarVolumeGroup carVolumeGroup = testVolumeGroupSetup();
+
+ assertThat(carVolumeGroup.isLimited()).isFalse();
+
+ carVolumeGroup.setLimit(carVolumeGroup.getMaxGainIndex() - 1);
+
+ assertThat(carVolumeGroup.isLimited()).isTrue();
+
+ carVolumeGroup.resetLimit();
+
+ assertThat(carVolumeGroup.isLimited()).isFalse();
+ }
+
+ @Test
+ public void setAttenuatedGain_withGain_thenBackToUninitializedGain() {
+ CarVolumeGroup carVolumeGroup = testVolumeGroupSetup();
+
+ assertThat(carVolumeGroup.isAttenuated()).isFalse();
+
+ carVolumeGroup.setAttenuatedGain(10);
+
+ assertThat(carVolumeGroup.isAttenuated()).isTrue();
+
+ carVolumeGroup.resetAttenuation();
+
+ assertThat(carVolumeGroup.isAttenuated()).isFalse();
+ }
+
+ @Test
+ public void getCurrentGainIndex_whileBlocked_thenUnblocked() {
+ CarVolumeGroup carVolumeGroup = getCarVolumeGroupWithMusicBound();
+ carVolumeGroup.setCurrentGainIndex(TEST_GAIN_INDEX);
+
+ assertWithMessage("Initial current gain index")
+ .that(carVolumeGroup.getCurrentGainIndex())
+ .isEqualTo(TEST_GAIN_INDEX);
+
+ int blockedIndex = 10;
+ carVolumeGroup.setBlocked(blockedIndex);
+
+ assertThat(carVolumeGroup.isBlocked()).isTrue();
+
+ assertWithMessage("Blocked current gain index")
+ .that(carVolumeGroup.getCurrentGainIndex())
+ .isEqualTo(blockedIndex);
+
+ carVolumeGroup.resetBlocked();
+
+ assertThat(carVolumeGroup.isBlocked()).isFalse();
+
+ assertWithMessage("Back to current gain index")
+ .that(carVolumeGroup.getCurrentGainIndex())
+ .isEqualTo(TEST_GAIN_INDEX);
+ }
+
+ @Test
+ public void getCurrentGainIndex_whileLimited_thenUnlimited() {
+ CarVolumeGroup carVolumeGroup = getCarVolumeGroupWithMusicBound();
+ carVolumeGroup.setCurrentGainIndex(TEST_GAIN_INDEX);
+ assertWithMessage("Initial current gain index")
+ .that(carVolumeGroup.getCurrentGainIndex())
+ .isEqualTo(TEST_GAIN_INDEX);
+ assertThat(carVolumeGroup.isLimited()).isFalse();
+
+ int limitedGainIndex = carVolumeGroup.getMaxGainIndex() - 1;
+ carVolumeGroup.setLimit(limitedGainIndex);
+
+ assertThat(carVolumeGroup.isLimited()).isTrue();
+ assertWithMessage("Limited current gain index")
+ .that(carVolumeGroup.getCurrentGainIndex())
+ .isEqualTo(limitedGainIndex);
+
+ carVolumeGroup.resetLimit();
+
+ assertThat(carVolumeGroup.isLimited()).isFalse();
+ assertWithMessage("Back to current gain index")
+ .that(carVolumeGroup.getCurrentGainIndex())
+ .isEqualTo(TEST_GAIN_INDEX);
+ }
+
+ @Test
+ public void getCurrentGainIndex_whileAttenuated_thenUnattenuated() {
+ CarVolumeGroup carVolumeGroup = getCarVolumeGroupWithMusicBound();
+ carVolumeGroup.setCurrentGainIndex(TEST_GAIN_INDEX);
+ assertWithMessage("Initial current gain index")
+ .that(carVolumeGroup.getCurrentGainIndex())
+ .isEqualTo(TEST_GAIN_INDEX);
+ assertThat(carVolumeGroup.isAttenuated()).isFalse();
+
+ int attenuatedIndex = TEST_GAIN_INDEX - 1;
+ carVolumeGroup.setAttenuatedGain(attenuatedIndex);
+
+ assertThat(carVolumeGroup.isAttenuated()).isTrue();
+ assertWithMessage("Attenuated current gain index")
+ .that(carVolumeGroup.getCurrentGainIndex())
+ .isEqualTo(attenuatedIndex);
+
+ carVolumeGroup.resetAttenuation();
+
+ assertThat(carVolumeGroup.isAttenuated()).isFalse();
+ assertWithMessage("Muted current gain index")
+ .that(carVolumeGroup.getCurrentGainIndex())
+ .isEqualTo(TEST_GAIN_INDEX);
+ }
+
+ @Test
+ public void setCurrentGainIndex_whileBlocked_thenRemainsUnblocked() {
+ CarVolumeGroup carVolumeGroup = getCarVolumeGroupWithMusicBound();
+ carVolumeGroup.setCurrentGainIndex(TEST_GAIN_INDEX);
+
+ assertWithMessage("Initial current gain index")
+ .that(carVolumeGroup.getCurrentGainIndex())
+ .isEqualTo(TEST_GAIN_INDEX);
+
+ int blockedIndex = 1;
+ carVolumeGroup.setBlocked(blockedIndex);
+
+ assertThat(carVolumeGroup.isBlocked()).isTrue();
+
+ carVolumeGroup.setCurrentGainIndex(blockedIndex + 1);
+
+ assertWithMessage("Over Blocked current gain index")
+ .that(carVolumeGroup.getCurrentGainIndex())
+ .isEqualTo(blockedIndex);
+
+ carVolumeGroup.setCurrentGainIndex(blockedIndex - 1);
+
+ assertWithMessage("Under Blocked current gain index")
+ .that(carVolumeGroup.getCurrentGainIndex())
+ .isEqualTo(blockedIndex);
+ }
+
+ @Test
+ public void setCurrentGainIndex_whileLimited_under_then_over_limit() {
+ CarVolumeGroup carVolumeGroup = getCarVolumeGroupWithMusicBound();
+ carVolumeGroup.setCurrentGainIndex(MAX_GAIN_INDEX);
+ assertWithMessage("Initial current gain index")
+ .that(carVolumeGroup.getCurrentGainIndex())
+ .isEqualTo(MAX_GAIN_INDEX);
+ assertThat(carVolumeGroup.isLimited()).isFalse();
+
+ int limitedGainIndex = MAX_GAIN_INDEX - 1;
+ carVolumeGroup.setLimit(limitedGainIndex);
+
+ assertThat(carVolumeGroup.isLimited()).isTrue();
+ assertThat(carVolumeGroup.isOverLimit()).isTrue();
+
+ // Underlimit
+ carVolumeGroup.setCurrentGainIndex(limitedGainIndex - 1);
+
+ assertWithMessage("Under limit current gain index")
+ .that(carVolumeGroup.getCurrentGainIndex())
+ .isEqualTo(limitedGainIndex - 1);
+
+ assertThat(carVolumeGroup.isLimited()).isTrue();
+ assertThat(carVolumeGroup.isOverLimit()).isFalse();
+
+ // Overlimit
+ carVolumeGroup.setCurrentGainIndex(limitedGainIndex + 1);
+
+ assertWithMessage("Over limit current gain index")
+ .that(carVolumeGroup.getCurrentGainIndex())
+ .isEqualTo(limitedGainIndex);
+
+ assertThat(carVolumeGroup.isLimited()).isTrue();
+ // Limitation prevents to set overlimited inde
+ assertThat(carVolumeGroup.isOverLimit()).isFalse();
+ }
+
+ @Test
+ public void setCurrentGainIndex_whileAttenuated_thenUnattenuated() {
+ CarVolumeGroup carVolumeGroup = getCarVolumeGroupWithMusicBound();
+ carVolumeGroup.setCurrentGainIndex(TEST_GAIN_INDEX);
+ assertWithMessage("Initial current gain index")
+ .that(carVolumeGroup.getCurrentGainIndex())
+ .isEqualTo(TEST_GAIN_INDEX);
+ assertThat(carVolumeGroup.isAttenuated()).isFalse();
+
+ int attenuatedIndex = TEST_GAIN_INDEX - 2;
+ carVolumeGroup.setAttenuatedGain(attenuatedIndex);
+
+ assertThat(carVolumeGroup.isAttenuated()).isTrue();
+ assertWithMessage("Attenuated current gain index")
+ .that(carVolumeGroup.getCurrentGainIndex())
+ .isEqualTo(attenuatedIndex);
+
+ carVolumeGroup.setCurrentGainIndex(attenuatedIndex + 1);
+
+ assertThat(carVolumeGroup.isAttenuated()).isFalse();
+ assertWithMessage("new current gain index")
+ .that(carVolumeGroup.getCurrentGainIndex())
+ .isEqualTo(attenuatedIndex + 1);
+ }
+
+ @Test
+ public void isOverLimit_expectedTrue() {
+ CarVolumeGroup carVolumeGroup = testVolumeGroupSetup();
+ carVolumeGroup.setCurrentGainIndex(MAX_GAIN_INDEX);
+
+ List<Integer> limitReasons = List.of(Reasons.THERMAL_LIMITATION);
+
+ AudioGainConfigInfo musicGain = new AudioGainConfigInfo();
+ musicGain.zoneId = ZONE_ID;
+ musicGain.devicePortAddress = MEDIA_DEVICE_ADDRESS;
+ musicGain.volumeIndex = TEST_GAIN_INDEX;
+ CarAudioGainConfigInfo musicCarGain = new CarAudioGainConfigInfo(musicGain);
+
+ carVolumeGroup.onAudioGainChanged(limitReasons, musicCarGain);
+ assertThat(carVolumeGroup.isLimited()).isTrue();
+ assertThat(carVolumeGroup.isOverLimit()).isTrue();
+ }
+
+ @Test
+ public void isOverLimit_expectedFalse() {
+ CarVolumeGroup carVolumeGroup = testVolumeGroupSetup();
+ carVolumeGroup.setCurrentGainIndex(TEST_GAIN_INDEX - 1);
+
+ List<Integer> limitReasons = List.of(Reasons.THERMAL_LIMITATION);
+
+ AudioGainConfigInfo musicGain = new AudioGainConfigInfo();
+ musicGain.zoneId = ZONE_ID;
+ musicGain.devicePortAddress = MEDIA_DEVICE_ADDRESS;
+ musicGain.volumeIndex = TEST_GAIN_INDEX;
+ CarAudioGainConfigInfo musicCarGain = new CarAudioGainConfigInfo(musicGain);
+
+ carVolumeGroup.onAudioGainChanged(limitReasons, musicCarGain);
+
+ assertThat(carVolumeGroup.isLimited()).isTrue();
+ assertThat(carVolumeGroup.isOverLimit()).isFalse();
+ }
+
+ @Test
+ public void onAudioGainChanged_withOverLimit_thenEndsAndRestoresVolume() {
+ CarVolumeGroup carVolumeGroup = testVolumeGroupSetup();
+ carVolumeGroup.setCurrentGainIndex(MAX_GAIN_INDEX);
+
+ List<Integer> limitReasons = List.of(Reasons.THERMAL_LIMITATION);
+
+ AudioGainConfigInfo musicGain = new AudioGainConfigInfo();
+ musicGain.zoneId = ZONE_ID;
+ musicGain.devicePortAddress = MEDIA_DEVICE_ADDRESS;
+ musicGain.volumeIndex = DEFAULT_GAIN_INDEX;
+ CarAudioGainConfigInfo musicCarGain = new CarAudioGainConfigInfo(musicGain);
+
+ carVolumeGroup.onAudioGainChanged(limitReasons, musicCarGain);
+
+ assertWithMessage("Overlimit gain index")
+ .that(carVolumeGroup.getCurrentGainIndex())
+ .isEqualTo(DEFAULT_GAIN_INDEX);
+
+ assertThat(carVolumeGroup.isAttenuated()).isFalse();
+ assertThat(carVolumeGroup.isLimited()).isTrue();
+ assertThat(carVolumeGroup.isOverLimit()).isTrue();
+ assertThat(carVolumeGroup.isBlocked()).isFalse();
+
+ List<Integer> noReasons = new ArrayList<>(0);
+ carVolumeGroup.onAudioGainChanged(noReasons, musicCarGain);
+
+ assertThat(carVolumeGroup.isAttenuated()).isFalse();
+ assertThat(carVolumeGroup.isLimited()).isFalse();
+ assertThat(carVolumeGroup.isOverLimit()).isFalse();
+ assertThat(carVolumeGroup.isBlocked()).isFalse();
+
+ assertWithMessage("Restored initial gain index")
+ .that(carVolumeGroup.getCurrentGainIndex())
+ .isEqualTo(MAX_GAIN_INDEX);
+ }
+
+ @Test
+ public void onAudioGainChanged_withUnderLimit_thenEndsWithVolumeUnchanged() {
+ CarVolumeGroup carVolumeGroup = testVolumeGroupSetup();
+ carVolumeGroup.setCurrentGainIndex(MIN_GAIN_INDEX);
+
+ List<Integer> limitReasons = List.of(Reasons.THERMAL_LIMITATION);
+
+ AudioGainConfigInfo musicGain = new AudioGainConfigInfo();
+ musicGain.zoneId = ZONE_ID;
+ musicGain.devicePortAddress = MEDIA_DEVICE_ADDRESS;
+ musicGain.volumeIndex = DEFAULT_GAIN_INDEX;
+ CarAudioGainConfigInfo musicCarGain = new CarAudioGainConfigInfo(musicGain);
+
+ carVolumeGroup.onAudioGainChanged(limitReasons, musicCarGain);
+
+ assertWithMessage("Underlimit gain index")
+ .that(carVolumeGroup.getCurrentGainIndex())
+ .isEqualTo(MIN_GAIN_INDEX);
+
+ assertThat(carVolumeGroup.isAttenuated()).isFalse();
+ assertThat(carVolumeGroup.isLimited()).isTrue();
+ assertThat(carVolumeGroup.isOverLimit()).isFalse();
+ assertThat(carVolumeGroup.isBlocked()).isFalse();
+
+ List<Integer> noReasons = new ArrayList<>(0);
+ carVolumeGroup.onAudioGainChanged(noReasons, musicCarGain);
+
+ assertThat(carVolumeGroup.isAttenuated()).isFalse();
+ assertThat(carVolumeGroup.isLimited()).isFalse();
+ assertThat(carVolumeGroup.isOverLimit()).isFalse();
+ assertThat(carVolumeGroup.isBlocked()).isFalse();
+
+ assertWithMessage("Unchanged gain index")
+ .that(carVolumeGroup.getCurrentGainIndex())
+ .isEqualTo(MIN_GAIN_INDEX);
+ }
+
+ @Test
+ public void onAudioGainChanged_withBlockedGain_thenEndsAndRestoresVolume() {
+ CarVolumeGroup carVolumeGroup = testVolumeGroupSetup();
+ carVolumeGroup.setCurrentGainIndex(DEFAULT_GAIN_INDEX);
+
+ List<Integer> blockReasons = List.of(Reasons.TCU_MUTE);
+
+ AudioGainConfigInfo musicGain = new AudioGainConfigInfo();
+ musicGain.zoneId = ZONE_ID;
+ musicGain.devicePortAddress = MEDIA_DEVICE_ADDRESS;
+ musicGain.volumeIndex = MIN_GAIN_INDEX;
+ CarAudioGainConfigInfo musicCarGain = new CarAudioGainConfigInfo(musicGain);
+
+ carVolumeGroup.onAudioGainChanged(blockReasons, musicCarGain);
+
+ assertThat(carVolumeGroup.isAttenuated()).isFalse();
+ assertThat(carVolumeGroup.isLimited()).isFalse();
+ assertThat(carVolumeGroup.isOverLimit()).isFalse();
+ assertThat(carVolumeGroup.isBlocked()).isTrue();
+
+ assertWithMessage("Blocked gain index")
+ .that(carVolumeGroup.getCurrentGainIndex())
+ .isEqualTo(MIN_GAIN_INDEX);
+
+ List<Integer> noReasons = new ArrayList<>(0);
+ carVolumeGroup.onAudioGainChanged(noReasons, musicCarGain);
+
+ assertThat(carVolumeGroup.isAttenuated()).isFalse();
+ assertThat(carVolumeGroup.isLimited()).isFalse();
+ assertThat(carVolumeGroup.isOverLimit()).isFalse();
+ assertThat(carVolumeGroup.isBlocked()).isFalse();
+
+ assertWithMessage("Restored initial gain index")
+ .that(carVolumeGroup.getCurrentGainIndex())
+ .isEqualTo(DEFAULT_GAIN_INDEX);
+ }
+
+ @Test
+ public void onAudioGainChanged_withAttenuatedGain_thenEndsAndRestoresVolume() {
+ CarVolumeGroup carVolumeGroup = testVolumeGroupSetup();
+ carVolumeGroup.setCurrentGainIndex(DEFAULT_GAIN_INDEX);
+ int attenuatedIndex = DEFAULT_GAIN_INDEX - 1;
+
+ List<Integer> attenuateReasons = List.of(Reasons.ADAS_DUCKING);
+
+ AudioGainConfigInfo musicGain = new AudioGainConfigInfo();
+ musicGain.zoneId = ZONE_ID;
+ musicGain.devicePortAddress = MEDIA_DEVICE_ADDRESS;
+ musicGain.volumeIndex = attenuatedIndex;
+ CarAudioGainConfigInfo musicCarGain = new CarAudioGainConfigInfo(musicGain);
+
+ carVolumeGroup.onAudioGainChanged(attenuateReasons, musicCarGain);
+
+ assertThat(carVolumeGroup.isAttenuated()).isTrue();
+ assertThat(carVolumeGroup.isLimited()).isFalse();
+ assertThat(carVolumeGroup.isOverLimit()).isFalse();
+ assertThat(carVolumeGroup.isBlocked()).isFalse();
+
+ assertWithMessage("Attenuated gain index")
+ .that(carVolumeGroup.getCurrentGainIndex())
+ .isEqualTo(attenuatedIndex);
+
+ List<Integer> noReasons = new ArrayList<>(0);
+ carVolumeGroup.onAudioGainChanged(noReasons, musicCarGain);
+
+ assertThat(carVolumeGroup.isAttenuated()).isFalse();
+ assertThat(carVolumeGroup.isLimited()).isFalse();
+ assertThat(carVolumeGroup.isOverLimit()).isFalse();
+ assertThat(carVolumeGroup.isBlocked()).isFalse();
+
+ assertWithMessage("Restored initial gain index")
+ .that(carVolumeGroup.getCurrentGainIndex())
+ .isEqualTo(DEFAULT_GAIN_INDEX);
+ }
+
+ @Test
+ public void onAudioGainChanged_withBlockingLimitAndAttenuation() {
+ CarVolumeGroup carVolumeGroup = testVolumeGroupSetup();
+
+ List<Integer> allReasons =
+ List.of(
+ -1,
+ -10,
+ 666,
+ Reasons.FORCED_MASTER_MUTE,
+ Reasons.TCU_MUTE,
+ Reasons.REMOTE_MUTE,
+ Reasons.THERMAL_LIMITATION,
+ Reasons.SUSPEND_EXIT_VOL_LIMITATION,
+ Reasons.ADAS_DUCKING,
+ Reasons.ADAS_DUCKING);
+
+ AudioGainConfigInfo musicGain = new AudioGainConfigInfo();
+ musicGain.zoneId = ZONE_ID;
+ musicGain.devicePortAddress = MEDIA_DEVICE_ADDRESS;
+ musicGain.volumeIndex = DEFAULT_GAIN_INDEX;
+ CarAudioGainConfigInfo musicCarGain = new CarAudioGainConfigInfo(musicGain);
+
+ carVolumeGroup.onAudioGainChanged(allReasons, musicCarGain);
+
+ assertThat(carVolumeGroup.isAttenuated()).isTrue();
+ assertThat(carVolumeGroup.isLimited()).isTrue();
+ assertThat(carVolumeGroup.isBlocked()).isTrue();
+ }
+
+ @Test
+ public void onAudioGainChanged_resettingBlockingLimitAndAttenuation() {
+ CarVolumeGroup carVolumeGroup = testVolumeGroupSetup();
+
+ List<Integer> noReasons = new ArrayList<>(0);
+
+ AudioGainConfigInfo musicGain = new AudioGainConfigInfo();
+ musicGain.zoneId = ZONE_ID;
+ musicGain.devicePortAddress = MEDIA_DEVICE_ADDRESS;
+ musicGain.volumeIndex = DEFAULT_GAIN_INDEX;
+ CarAudioGainConfigInfo musicCarGain = new CarAudioGainConfigInfo(musicGain);
+
+ carVolumeGroup.onAudioGainChanged(noReasons, musicCarGain);
+
+ assertThat(carVolumeGroup.isAttenuated()).isFalse();
+ assertThat(carVolumeGroup.isLimited()).isFalse();
+ assertThat(carVolumeGroup.isBlocked()).isFalse();
+ }
+
+ @Test
+ public void onAudioGainChanged_setResettingBlockingLimitAndAttenuation() {
+ CarVolumeGroup carVolumeGroup = testVolumeGroupSetup();
+
+ List<Integer> allReasons =
+ List.of(
+ Reasons.FORCED_MASTER_MUTE,
+ Reasons.TCU_MUTE,
+ Reasons.REMOTE_MUTE,
+ Reasons.THERMAL_LIMITATION,
+ Reasons.SUSPEND_EXIT_VOL_LIMITATION,
+ Reasons.ADAS_DUCKING,
+ Reasons.ADAS_DUCKING);
+ AudioGainConfigInfo musicGain = new AudioGainConfigInfo();
+ musicGain.zoneId = ZONE_ID;
+ musicGain.devicePortAddress = MEDIA_DEVICE_ADDRESS;
+ musicGain.volumeIndex = DEFAULT_GAIN_INDEX;
+ CarAudioGainConfigInfo musicCarGain = new CarAudioGainConfigInfo(musicGain);
+
+ carVolumeGroup.onAudioGainChanged(allReasons, musicCarGain);
+
+ assertThat(carVolumeGroup.isAttenuated()).isTrue();
+ assertThat(carVolumeGroup.isLimited()).isTrue();
+ assertThat(carVolumeGroup.isBlocked()).isTrue();
+
+ List<Integer> noReasons = new ArrayList<>(0);
+
+ carVolumeGroup.onAudioGainChanged(noReasons, musicCarGain);
+
+ assertThat(carVolumeGroup.isAttenuated()).isFalse();
+ assertThat(carVolumeGroup.isLimited()).isFalse();
+ assertThat(carVolumeGroup.isBlocked()).isFalse();
+ }
+
+ @Test
+ public void onAudioGainChanged_validGain() {
+ CarVolumeGroup carVolumeGroup = testVolumeGroupSetup();
+
+ List<Integer> reasons = List.of(Reasons.REMOTE_MUTE, Reasons.NAV_DUCKING);
+ AudioGainConfigInfo musicGain = new AudioGainConfigInfo();
+ musicGain.zoneId = ZONE_ID;
+ musicGain.devicePortAddress = MEDIA_DEVICE_ADDRESS;
+ musicGain.volumeIndex = DEFAULT_GAIN_INDEX;
+ CarAudioGainConfigInfo musicCarGain = new CarAudioGainConfigInfo(musicGain);
+
+ AudioGainConfigInfo navGain = new AudioGainConfigInfo();
+ navGain.zoneId = ZONE_ID;
+ navGain.devicePortAddress = NAVIGATION_DEVICE_ADDRESS;
+ navGain.volumeIndex = DEFAULT_GAIN_INDEX;
+ CarAudioGainConfigInfo navCarGain = new CarAudioGainConfigInfo(navGain);
+
+ carVolumeGroup.onAudioGainChanged(reasons, musicCarGain);
+ // Broadcasted to all CarAudioDeviceInfo
+ verify(mMediaDeviceInfo).setCurrentGain(eq(DEFAULT_GAIN));
+ verify(mNavigationDeviceInfo).setCurrentGain(eq(DEFAULT_GAIN));
+
+ carVolumeGroup.onAudioGainChanged(reasons, navCarGain);
+ // Broadcasted to all CarAudioDeviceInfo
+ verify(mMediaDeviceInfo, times(2)).setCurrentGain(eq(DEFAULT_GAIN));
+ verify(mNavigationDeviceInfo, times(2)).setCurrentGain(eq(DEFAULT_GAIN));
+ }
+
+ @Test
+ public void onAudioGainChanged_invalidGain() {
+ CarVolumeGroup carVolumeGroup = testVolumeGroupSetup();
+
+ List<Integer> reasons = List.of(Reasons.REMOTE_MUTE, Reasons.NAV_DUCKING);
+ AudioGainConfigInfo unknownGain = new AudioGainConfigInfo();
+ unknownGain.zoneId = ZONE_ID;
+ unknownGain.devicePortAddress = OTHER_ADDRESS;
+ unknownGain.volumeIndex = 666;
+ CarAudioGainConfigInfo unknownCarGain = new CarAudioGainConfigInfo(unknownGain);
+
+ carVolumeGroup.onAudioGainChanged(reasons, unknownCarGain);
+
+ verify(mMediaDeviceInfo, never()).setCurrentGain(anyInt());
+ verify(mNavigationDeviceInfo, never()).setCurrentGain(anyInt());
+ }
+
private CarVolumeGroup getCarVolumeGroupWithMusicBound() {
return getBuilder()
.setDeviceInfoForContext(MUSIC, mMediaDeviceInfo)
diff --git a/tests/carservice_unit_test/src/com/android/car/audio/OWNERS b/tests/carservice_unit_test/src/com/android/car/audio/OWNERS
deleted file mode 100644
index a1eb6f7..0000000
--- a/tests/carservice_unit_test/src/com/android/car/audio/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-# Audio owners
-oscarazu@google.com
\ No newline at end of file
diff --git a/tests/carservice_unit_test/src/com/android/car/audio/hal/AudioControlWrapperAidlTest.java b/tests/carservice_unit_test/src/com/android/car/audio/hal/AudioControlWrapperAidlTest.java
index e1dd7af..093d2d6 100644
--- a/tests/carservice_unit_test/src/com/android/car/audio/hal/AudioControlWrapperAidlTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/audio/hal/AudioControlWrapperAidlTest.java
@@ -22,6 +22,7 @@
import static com.android.car.audio.hal.AudioControlWrapper.AUDIOCONTROL_FEATURE_AUDIO_DUCKING;
import static com.android.car.audio.hal.AudioControlWrapper.AUDIOCONTROL_FEATURE_AUDIO_FOCUS;
+import static com.android.car.audio.hal.AudioControlWrapper.AUDIOCONTROL_FEATURE_AUDIO_GAIN_CALLBACK;
import static com.android.car.audio.hal.AudioControlWrapper.AUDIOCONTROL_FEATURE_AUDIO_GROUP_MUTING;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
@@ -31,6 +32,7 @@
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
@@ -40,16 +42,22 @@
import android.audio.policy.configuration.V7_0.AudioUsage;
import android.car.test.mocks.AbstractExtendedMockitoTestCase;
+import android.hardware.automotive.audiocontrol.AudioGainConfigInfo;
import android.hardware.automotive.audiocontrol.DuckingInfo;
import android.hardware.automotive.audiocontrol.IAudioControl;
+import android.hardware.automotive.audiocontrol.IAudioGainCallback;
import android.hardware.automotive.audiocontrol.IFocusListener;
import android.hardware.automotive.audiocontrol.MutingInfo;
+import android.hardware.automotive.audiocontrol.Reasons;
import android.media.AudioManager;
import android.os.IBinder;
+import android.os.RemoteException;
import androidx.test.ext.junit.runners.AndroidJUnit4;
+import com.android.car.audio.CarAudioGainConfigInfo;
import com.android.car.audio.CarDuckingInfo;
+import com.android.car.audio.CarHalAudioUtils;
import com.android.car.audio.hal.AudioControlWrapper.AudioControlDeathRecipient;
import com.android.dx.mockito.inline.extended.ExtendedMockito;
@@ -85,12 +93,16 @@
private static final String SECONDARY_CALL_ADDRESS = "secondary call";
private static final String SECONDARY_NOTIFICATION_ADDRESS = "secondary notification";
+ private static final int AIDL_AUDIO_CONTROL_VERSION_1 = 1;
+
@Mock
IBinder mBinder;
@Mock
IAudioControl mAudioControl;
+ @Mock HalAudioGainCallback mHalAudioGainCallback;
+
@Mock
AudioControlDeathRecipient mDeathRecipient;
@@ -183,8 +195,9 @@
@Test
public void onDevicesToDuckChange_callsHalWithDuckingInfo() throws Exception {
- CarDuckingInfo carDuckingInfo = new CarDuckingInfo(ZONE_ID, new ArrayList<>(),
- new ArrayList<>(), new int[0]);
+ CarDuckingInfo carDuckingInfo =
+ new CarDuckingInfo(
+ ZONE_ID, new ArrayList<>(), new ArrayList<>(), new ArrayList<>());
mAudioControlWrapperAidl.onDevicesToDuckChange(List.of(carDuckingInfo));
@@ -196,8 +209,14 @@
@Test
public void onDevicesToDuckChange_convertsUsagesToXsdStrings() throws Exception {
- CarDuckingInfo carDuckingInfo = new CarDuckingInfo(ZONE_ID, new ArrayList<>(),
- new ArrayList<>(), new int[]{USAGE_MEDIA, USAGE_NOTIFICATION});
+ CarDuckingInfo carDuckingInfo =
+ new CarDuckingInfo(
+ ZONE_ID,
+ new ArrayList<>(),
+ new ArrayList<>(),
+ CarHalAudioUtils.usagesToMetadatas(
+ new int[] {USAGE_MEDIA, USAGE_NOTIFICATION},
+ /* CarAudioZone= */ null));
mAudioControlWrapperAidl.onDevicesToDuckChange(List.of(carDuckingInfo));
@@ -213,8 +232,12 @@
public void onDevicesToDuckChange_passesAlongAddressesToDuck() throws Exception {
String mediaAddress = "media_bus";
String navigationAddress = "navigation_bus";
- CarDuckingInfo carDuckingInfo = new CarDuckingInfo(ZONE_ID,
- Arrays.asList(mediaAddress, navigationAddress), new ArrayList<>(), new int[0]);
+ CarDuckingInfo carDuckingInfo =
+ new CarDuckingInfo(
+ ZONE_ID,
+ Arrays.asList(mediaAddress, navigationAddress),
+ new ArrayList<>(),
+ new ArrayList<>());
mAudioControlWrapperAidl.onDevicesToDuckChange(List.of(carDuckingInfo));
@@ -229,8 +252,12 @@
public void onDevicesToDuckChange_passesAlongAddressesToUnduck() throws Exception {
String notificationAddress = "notification_bus";
String callAddress = "call_address";
- CarDuckingInfo carDuckingInfo = new CarDuckingInfo(ZONE_ID, new ArrayList<>(),
- Arrays.asList(notificationAddress, callAddress), new int[0]);
+ CarDuckingInfo carDuckingInfo =
+ new CarDuckingInfo(
+ ZONE_ID,
+ new ArrayList<>(),
+ Arrays.asList(notificationAddress, callAddress),
+ new ArrayList<>());
mAudioControlWrapperAidl.onDevicesToDuckChange(List.of(carDuckingInfo));
@@ -243,8 +270,9 @@
@Test
public void onDevicesToDuckChange_passesAlongZoneId() throws Exception {
- CarDuckingInfo carDuckingInfo = new CarDuckingInfo(ZONE_ID, new ArrayList<>(),
- new ArrayList<>(), new int[0]);
+ CarDuckingInfo carDuckingInfo =
+ new CarDuckingInfo(
+ ZONE_ID, new ArrayList<>(), new ArrayList<>(), new ArrayList<>());
mAudioControlWrapperAidl.onDevicesToDuckChange(List.of(carDuckingInfo));
@@ -256,10 +284,12 @@
@Test
public void onDevicesToDuckChange_multipleZones_passesADuckingInfoPerZone() throws Exception {
- CarDuckingInfo carDuckingInfo = new CarDuckingInfo(ZONE_ID, new ArrayList<>(),
- new ArrayList<>(), new int[0]);
- CarDuckingInfo secondaryCarDuckingInfo = new CarDuckingInfo(SECONDARY_ZONE_ID,
- new ArrayList<>(), new ArrayList<>(), new int[0]);
+ CarDuckingInfo carDuckingInfo =
+ new CarDuckingInfo(
+ ZONE_ID, new ArrayList<>(), new ArrayList<>(), new ArrayList<>());
+ CarDuckingInfo secondaryCarDuckingInfo =
+ new CarDuckingInfo(
+ SECONDARY_ZONE_ID, new ArrayList<>(), new ArrayList<>(), new ArrayList<>());
mAudioControlWrapperAidl.onDevicesToDuckChange(List.of(carDuckingInfo,
secondaryCarDuckingInfo));
@@ -449,6 +479,181 @@
.containsExactly(SECONDARY_CALL_ADDRESS, SECONDARY_NOTIFICATION_ADDRESS);
}
+ @Test
+ public void supportsFeature_forAudioGainCallback_returnsTrue() throws Exception {
+ when(mAudioControl.getInterfaceVersion()).thenReturn(AIDL_AUDIO_CONTROL_VERSION_1 + 1);
+ assertThat(
+ mAudioControlWrapperAidl.supportsFeature(
+ AUDIOCONTROL_FEATURE_AUDIO_GAIN_CALLBACK))
+ .isTrue();
+
+ when(mAudioControl.getInterfaceVersion()).thenReturn(AIDL_AUDIO_CONTROL_VERSION_1 + 4);
+ assertThat(
+ mAudioControlWrapperAidl.supportsFeature(
+ AUDIOCONTROL_FEATURE_AUDIO_GAIN_CALLBACK))
+ .isTrue();
+ }
+
+ @Test
+ public void supportsFeature_forAudioGainCallback_returnsFalse() throws Exception {
+ when(mAudioControl.getInterfaceVersion()).thenReturn(AIDL_AUDIO_CONTROL_VERSION_1);
+ assertThat(
+ mAudioControlWrapperAidl.supportsFeature(
+ AUDIOCONTROL_FEATURE_AUDIO_GAIN_CALLBACK))
+ .isFalse();
+
+ when(mAudioControl.getInterfaceVersion()).thenReturn(0);
+ assertThat(
+ mAudioControlWrapperAidl.supportsFeature(
+ AUDIOCONTROL_FEATURE_AUDIO_GAIN_CALLBACK))
+ .isFalse();
+ }
+
+ @Test
+ public void registerAudioGainCallback_succeeds() throws Exception {
+ mAudioControlWrapperAidl.registerAudioGainCallback(mHalAudioGainCallback);
+ verify(mAudioControl).registerGainCallback(any());
+ }
+
+ @Test
+ public void registerAudioGainCallback_Throws() throws Exception {
+ doThrow(new RemoteException("D'OH!")).when(mAudioControl).registerGainCallback(any());
+
+ IllegalStateException thrown =
+ expectThrows(
+ IllegalStateException.class,
+ () ->
+ mAudioControlWrapperAidl.registerAudioGainCallback(
+ mHalAudioGainCallback));
+
+ assertWithMessage("IllegalStateException thrown by registerAudioGainCallback")
+ .that(thrown)
+ .hasMessageThat()
+ .contains("IAudioControl#registerAudioGainCallback failed");
+ }
+
+ @Test
+ public void registerAudioGainCallback_nullcallback_Throws() {
+ NullPointerException thrown =
+ expectThrows(
+ NullPointerException.class,
+ () ->
+ mAudioControlWrapperAidl.registerAudioGainCallback(
+ /* gainCallback= */ null));
+
+ assertWithMessage("NullPointerException thrown by registerAudioGainCallback")
+ .that(thrown)
+ .hasMessageThat()
+ .contains("Audio Gain Callback can not be null");
+ }
+
+ @Test
+ public void onAudioDeviceGainsChanged_succeeds() throws Exception {
+ ArgumentCaptor<IAudioGainCallback.Stub> captor =
+ ArgumentCaptor.forClass(IAudioGainCallback.Stub.class);
+
+ mAudioControlWrapperAidl.registerAudioGainCallback(mHalAudioGainCallback);
+ verify(mAudioControl).registerGainCallback(captor.capture());
+
+ int[] halReasons = {Reasons.REMOTE_MUTE, Reasons.NAV_DUCKING};
+ List<Integer> reasons = Arrays.stream(halReasons).boxed().collect(Collectors.toList());
+
+ AudioGainConfigInfo gainInfo1 = new AudioGainConfigInfo();
+ gainInfo1.zoneId = PRIMARY_ZONE_ID;
+ gainInfo1.devicePortAddress = PRIMARY_MUSIC_ADDRESS;
+ gainInfo1.volumeIndex = 666;
+ CarAudioGainConfigInfo carGainInfo1 = new CarAudioGainConfigInfo(gainInfo1);
+ AudioGainConfigInfo gainInfo2 = new AudioGainConfigInfo();
+ gainInfo2.zoneId = SECONDARY_ZONE_ID;
+ gainInfo2.devicePortAddress = SECONDARY_NAVIGATION_ADDRESS;
+ gainInfo2.volumeIndex = 999;
+ CarAudioGainConfigInfo carGainInfo2 = new CarAudioGainConfigInfo(gainInfo2);
+
+ AudioGainConfigInfo[] gains = new AudioGainConfigInfo[] {gainInfo1, gainInfo2};
+
+ List<CarAudioGainConfigInfo> carGains = List.of(carGainInfo1, carGainInfo2);
+
+ captor.getValue().onAudioDeviceGainsChanged(halReasons, gains);
+
+ ArgumentCaptor<List<CarAudioGainConfigInfo>> captorGains =
+ ArgumentCaptor.forClass(List.class);
+ verify(mHalAudioGainCallback).onAudioDeviceGainsChanged(eq(reasons), captorGains.capture());
+
+ assertThat(captorGains.getValue()).containsExactlyElementsIn(carGains);
+ }
+
+ @Test
+ public void onAudioDeviceGainsChanged_invalidReasons() throws Exception {
+ ArgumentCaptor<IAudioGainCallback.Stub> captor =
+ ArgumentCaptor.forClass(IAudioGainCallback.Stub.class);
+
+ mAudioControlWrapperAidl.registerAudioGainCallback(mHalAudioGainCallback);
+ verify(mAudioControl).registerGainCallback(captor.capture());
+
+ int[] halReasons = {-1, 1999, 666};
+ List<Integer> emptyReasons = new ArrayList<>();
+
+ AudioGainConfigInfo gainInfo1 = new AudioGainConfigInfo();
+ gainInfo1.zoneId = PRIMARY_ZONE_ID;
+ gainInfo1.devicePortAddress = PRIMARY_MUSIC_ADDRESS;
+ gainInfo1.volumeIndex = 666;
+ CarAudioGainConfigInfo carGainInfo1 = new CarAudioGainConfigInfo(gainInfo1);
+ AudioGainConfigInfo gainInfo2 = new AudioGainConfigInfo();
+ gainInfo2.zoneId = SECONDARY_ZONE_ID;
+ gainInfo2.devicePortAddress = SECONDARY_NAVIGATION_ADDRESS;
+ gainInfo2.volumeIndex = 999;
+ CarAudioGainConfigInfo carGainInfo2 = new CarAudioGainConfigInfo(gainInfo2);
+
+ AudioGainConfigInfo[] gains = new AudioGainConfigInfo[] {gainInfo1, gainInfo2};
+
+ List<CarAudioGainConfigInfo> carGains = List.of(carGainInfo1, carGainInfo2);
+
+ captor.getValue().onAudioDeviceGainsChanged(halReasons, gains);
+
+ ArgumentCaptor<List<CarAudioGainConfigInfo>> captorGains =
+ ArgumentCaptor.forClass(List.class);
+ verify(mHalAudioGainCallback)
+ .onAudioDeviceGainsChanged(eq(emptyReasons), captorGains.capture());
+
+ assertThat(captorGains.getValue()).containsExactlyElementsIn(carGains);
+ }
+
+ @Test
+ public void onAudioDeviceGainsChanged_invalidReasonsAmongValidReasons() throws Exception {
+ ArgumentCaptor<IAudioGainCallback.Stub> captor =
+ ArgumentCaptor.forClass(IAudioGainCallback.Stub.class);
+
+ mAudioControlWrapperAidl.registerAudioGainCallback(mHalAudioGainCallback);
+ verify(mAudioControl).registerGainCallback(captor.capture());
+
+ int[] halReasons = {-1, Reasons.REMOTE_MUTE, 1999, 666, Reasons.NAV_DUCKING};
+ List<Integer> validReasons = List.of(Reasons.REMOTE_MUTE, Reasons.NAV_DUCKING);
+
+ AudioGainConfigInfo gainInfo1 = new AudioGainConfigInfo();
+ gainInfo1.zoneId = PRIMARY_ZONE_ID;
+ gainInfo1.devicePortAddress = PRIMARY_MUSIC_ADDRESS;
+ gainInfo1.volumeIndex = 666;
+ CarAudioGainConfigInfo carGainInfo1 = new CarAudioGainConfigInfo(gainInfo1);
+ AudioGainConfigInfo gainInfo2 = new AudioGainConfigInfo();
+ gainInfo2.zoneId = SECONDARY_ZONE_ID;
+ gainInfo2.devicePortAddress = SECONDARY_NAVIGATION_ADDRESS;
+ gainInfo2.volumeIndex = 999;
+ CarAudioGainConfigInfo carGainInfo2 = new CarAudioGainConfigInfo(gainInfo2);
+
+ AudioGainConfigInfo[] gains = new AudioGainConfigInfo[] {gainInfo1, gainInfo2};
+
+ List<CarAudioGainConfigInfo> carGains = List.of(carGainInfo1, carGainInfo2);
+
+ captor.getValue().onAudioDeviceGainsChanged(halReasons, gains);
+
+ ArgumentCaptor<List<CarAudioGainConfigInfo>> captorGains =
+ ArgumentCaptor.forClass(List.class);
+ verify(mHalAudioGainCallback)
+ .onAudioDeviceGainsChanged(eq(validReasons), captorGains.capture());
+
+ assertThat(captorGains.getValue()).containsExactlyElementsIn(carGains);
+ }
+
private MutingInfo verifyOnDevicesToMuteChangeCalled(int audioZoneId) throws Exception {
ArgumentCaptor<MutingInfo[]> captor = ArgumentCaptor.forClass(MutingInfo[].class);
verify(mAudioControl).onDevicesToMuteChange(captor.capture());
diff --git a/tests/carservice_unit_test/src/com/android/car/audio/hal/HalAudioGainCallbackTest.java b/tests/carservice_unit_test/src/com/android/car/audio/hal/HalAudioGainCallbackTest.java
new file mode 100644
index 0000000..3ec0f92
--- /dev/null
+++ b/tests/carservice_unit_test/src/com/android/car/audio/hal/HalAudioGainCallbackTest.java
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2022 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.audio.hal;
+
+import static com.google.common.truth.Truth.assertWithMessage;
+
+import android.hardware.automotive.audiocontrol.AudioGainConfigInfo;
+import android.hardware.automotive.audiocontrol.Reasons;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.List;
+
+@RunWith(AndroidJUnit4.class)
+public final class HalAudioGainCallbackTest {
+ private static final int PRIMARY_ZONE_ID = 0;
+ private static final String PRIMARY_ZONE_ID_LITERAL = "0";
+ private static final String PRIMARY_MUSIC_ADDRESS = "primary music";
+
+ @Test
+ public void isReasonValid_withValidReasons_succeeds() {
+ List<Integer> validReasons =
+ List.of(
+ Reasons.FORCED_MASTER_MUTE,
+ Reasons.REMOTE_MUTE,
+ Reasons.TCU_MUTE,
+ Reasons.ADAS_DUCKING,
+ Reasons.NAV_DUCKING,
+ Reasons.PROJECTION_DUCKING,
+ Reasons.THERMAL_LIMITATION,
+ Reasons.SUSPEND_EXIT_VOL_LIMITATION,
+ Reasons.EXTERNAL_AMP_VOL_FEEDBACK,
+ Reasons.OTHER);
+
+ for (int index = 0; index < validReasons.size(); index++) {
+ int validReason = validReasons.get(index);
+ assertWithMessage("Reason " + HalAudioGainCallback.reasonToString(validReason))
+ .that(HalAudioGainCallback.isReasonValid(validReason))
+ .isTrue();
+ }
+ }
+
+ @Test
+ public void isReasonValid_withInvalidReasons_fails() {
+ List<Integer> invalidReasons = List.of(-1, -10, 666);
+
+ for (int index = 0; index < invalidReasons.size(); index++) {
+ int invalidReason = invalidReasons.get(index);
+ assertWithMessage("Reason " + HalAudioGainCallback.reasonToString(invalidReason))
+ .that(HalAudioGainCallback.isReasonValid(invalidReason))
+ .isFalse();
+ }
+ }
+
+ @Test
+ public void reasonToString_validReasons_succeeds() {
+ List<Integer> reasons =
+ List.of(
+ Reasons.FORCED_MASTER_MUTE,
+ Reasons.REMOTE_MUTE,
+ Reasons.TCU_MUTE,
+ Reasons.ADAS_DUCKING,
+ Reasons.NAV_DUCKING,
+ Reasons.PROJECTION_DUCKING,
+ Reasons.THERMAL_LIMITATION,
+ Reasons.SUSPEND_EXIT_VOL_LIMITATION,
+ Reasons.EXTERNAL_AMP_VOL_FEEDBACK,
+ Reasons.OTHER);
+ for (int index = 0; index < reasons.size(); index++) {
+ int reason = reasons.get(index);
+ String literalReason = HalAudioGainCallback.reasonToString(reasons.get(index));
+ assertWithMessage("Valid Reason " + reason).that(literalReason).isNotNull();
+ assertWithMessage("Valid Reason " + reason)
+ .that(literalReason)
+ .doesNotContain("Unsupported reason");
+ }
+ }
+
+ @Test
+ public void reasonToString_invalidReasons_succeeds() {
+ List<Integer> reasons = List.of(-1, -10, 666);
+ for (int index = 0; index < reasons.size(); index++) {
+ int reason = reasons.get(index);
+ String literalReason = HalAudioGainCallback.reasonToString(reasons.get(index));
+ assertWithMessage("Invalid Reason " + reason).that(literalReason).isNotNull();
+ assertWithMessage("Invalid Reason " + reason)
+ .that(literalReason)
+ .contains("Unsupported reason");
+ }
+ }
+
+ @Test
+ public void gainToString_succeeds() {
+ AudioGainConfigInfo audioGainConfigInfo = new AudioGainConfigInfo();
+ audioGainConfigInfo.zoneId = PRIMARY_ZONE_ID;
+ audioGainConfigInfo.devicePortAddress = PRIMARY_MUSIC_ADDRESS;
+ audioGainConfigInfo.volumeIndex = 666;
+
+ String literalGain = HalAudioGainCallback.gainToString(audioGainConfigInfo);
+ assertWithMessage("Audio Gain Config Info Literal").that(literalGain).isNotNull();
+ assertWithMessage("Audio Gain Config Info Literal").that(literalGain).contains("zone:");
+ assertWithMessage("Audio Gain Config Info Literal")
+ .that(literalGain)
+ .contains(PRIMARY_ZONE_ID_LITERAL);
+ assertWithMessage("Audio Gain Config Info Literal").that(literalGain).contains("address:");
+ assertWithMessage("Audio Gain Config Info Literal")
+ .that(literalGain)
+ .contains(PRIMARY_MUSIC_ADDRESS);
+ assertWithMessage("Audio Gain Config Info Literal")
+ .that(literalGain)
+ .contains("Volume Index:");
+ assertWithMessage("Audio Gain Config Info Literal").that(literalGain).contains("666");
+ }
+}
diff --git a/tests/carservice_unit_test/src/com/android/car/bluetooth/BluetoothFastPairTest.java b/tests/carservice_unit_test/src/com/android/car/bluetooth/BluetoothFastPairTest.java
deleted file mode 100644
index c69e9dd..0000000
--- a/tests/carservice_unit_test/src/com/android/car/bluetooth/BluetoothFastPairTest.java
+++ /dev/null
@@ -1,482 +0,0 @@
-/*
- * Copyright (C) 2021 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.bluetooth;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.mockito.Mockito.after;
-import static org.mockito.Mockito.any;
-import static org.mockito.Mockito.anyInt;
-import static org.mockito.Mockito.anyString;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.timeout;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyNoMoreInteractions;
-import static org.mockito.Mockito.when;
-
-import android.bluetooth.BluetoothAdapter;
-import android.bluetooth.BluetoothDevice;
-import android.bluetooth.BluetoothManager;
-import android.bluetooth.le.AdvertiseData;
-import android.bluetooth.le.AdvertisingSetParameters;
-import android.bluetooth.le.BluetoothLeAdvertiser;
-import android.content.Context;
-import android.content.Intent;
-import android.content.SharedPreferences;
-import android.content.res.Resources;
-import android.os.ParcelUuid;
-
-import com.android.dx.mockito.inline.extended.ExtendedMockito;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.ArgumentCaptor;
-import org.mockito.Captor;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-import org.mockito.MockitoSession;
-import org.mockito.junit.MockitoJUnitRunner;
-import org.mockito.quality.Strictness;
-
-import java.math.BigInteger;
-import java.util.ArrayList;
-import java.util.Base64;
-import java.util.List;
-import java.util.Map;
-
-/**
- * Unit tests for {@link BluetoothFastPair}
- *
- * Run: atest BluetoothFastPairTest
- */
-@RunWith(MockitoJUnitRunner.class)
-public class BluetoothFastPairTest {
-
- static final byte[] TEST_ACCOUNT_KEY_1 = new byte[]{0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
- (byte) 0x88, (byte) 0x99, 0x00, (byte) 0xAA, (byte) 0xBB, (byte) 0xCC, (byte) 0xDD,
- (byte) 0xEE, (byte) 0xFF};
- static final byte[] TEST_ACCOUNT_KEY_2 = new byte[]{0x11, 0x11, 0x22, 0x22, 0x33, 0x33, 0x44,
- 0x44, 0x55, 0x55, 0x66, 0x66, 0x77, 0x77, (byte) 0x88, (byte) 0x88};
- static final byte[] TEST_ACCOUNT_KEY_3 = new byte[]{0x04, 0x11, 0x22, 0x22, 0x33, 0x33, 0x44,
- 0x44, 0x55, 0x55, 0x66, 0x66, 0x77, 0x77, (byte) 0x88, (byte) 0x88};
-
-
- static final byte[] TEST_KEY_1_EXPECTED_RESULT = new byte[]{0x0A, 0x42, (byte) 0x88, 0x10};
- static final byte[] TEST_KEY_12_EXPECTED_RESULT = new byte[]{0x2F, (byte) 0xBA, 0x06, 0x42,
- 0x00};
- static final byte TEST_SALT = (byte) 0xC7;
- static final byte[] TEST_INPUT = {(byte) 0xF3, 0x0F, 0x4E, 0x78, 0x6C, 0x59, (byte) 0xA7,
- (byte) 0xBB, (byte) 0xF3, (byte) 0x87, 0x3B, 0x5A, 0x49, (byte) 0xBA, (byte) 0x97,
- (byte) 0xEA};
- static final byte[] TEST_OUTPUT = {(byte) 0xAC, (byte) 0x9A, 0x16, (byte) 0xF0, (byte) 0x95,
- 0x3A, 0x3F, 0x22, 0x3D, (byte) 0xD1, 0x0C, (byte) 0xF5, 0x36, (byte) 0xE0, (byte) 0x9E,
- (byte) 0x9C};
- static final byte[] TEST_SHARED_SECRET = {(byte) 0xA0, (byte) 0xBA, (byte) 0xF0, (byte) 0xBB,
- (byte) 0x95, 0x1F, (byte) 0xF7, (byte) 0xB6, (byte) 0xCF, 0x5E, 0x3F, 0x45, 0x61,
- (byte) 0xC3, 0x32, 0x1D};
- static final byte[] TEST_PRIVATE_KEY_B = {0x02, (byte) 0xB4, 0x37, (byte) 0xB0, (byte) 0xED,
- (byte) 0xD6, (byte) 0xBB, (byte) 0xD4, 0x29, 0x06, 0x4A, 0x4E, 0x52, (byte) 0x9F,
- (byte) 0xCB, (byte) 0xF1, (byte) 0xC4, (byte) 0x8D, 0x0D, 0x62, 0x49, 0x24, (byte) 0xD5,
- (byte) 0x92, 0x27, 0x4B, 0x7E, (byte) 0xD8, 0x11, (byte) 0x93, (byte) 0xD7, 0x63
- };
- static final byte[] TEST_PUBLIC_KEY_A = {0x36, (byte) 0xAC, 0x68, 0x2C, 0x50, (byte) 0x82, 0x15,
- 0x66, (byte) 0x8F, (byte) 0xBE, (byte) 0xFE, 0x24, 0x7D, 0x01, (byte) 0xD5, (byte) 0xEB,
- (byte) 0x96, (byte) 0xE6, 0x31, (byte) 0x8E, (byte) 0x85, 0x5B, 0x2D, 0x64, (byte) 0xB5,
- 0x19, 0x5D, 0x38, (byte) 0xEE, 0x7E, 0x37, (byte) 0xBE, 0x18, 0x38, (byte) 0xC0,
- (byte) 0xB9, 0x48, (byte) 0xC3, (byte) 0xF7, 0x55, 0x20, (byte) 0xE0, 0x7E, 0x70,
- (byte) 0xF0, 0x72, (byte) 0x91, 0x41, (byte) 0x9A, (byte) 0xCE, 0x2D, 0x28, 0x14, 0x3C,
- 0x5A, (byte) 0xDB, 0x2D, (byte) 0xBD, (byte) 0x98, (byte) 0xEE, 0x3C, (byte) 0x8E, 0x4F,
- (byte) 0xBF};
- static final byte[] TEST_GENERATED_KEY = {(byte) 0xB0, 0x7F, 0x1F, 0x17, (byte) 0xC2, 0x36,
- (byte) 0xCB, (byte) 0xD3, 0x35, 0x23, (byte) 0xC5, 0x15, (byte) 0xF3, 0x50, (byte) 0xAE,
- 0x57};
- static final String TEST_PUBLIC_KEY_A_BASE64 = Base64.getEncoder()
- .encodeToString(TEST_PUBLIC_KEY_A);
- static final String TEST_PRIVATE_KEY_B_BASE64 = Base64.getEncoder()
- .encodeToString(TEST_PRIVATE_KEY_B);
- static final String TEST_LOCAL_ADDRESS_STRING = "00:11:22:33:44:55";
- static final byte[] TEST_LOCAL_ADDRESS = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55};
- static final byte[] TEST_REMOTE_ADDRESS = {0x66, 0x77, (byte) 0x88, (byte) 0x99, (byte) 0xAA,
- (byte) 0xBB};
- static final byte[] TEST_PAIRING_REQUEST = {0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x66, 0x77, (byte) 0x88, (byte) 0x99, (byte) 0xAA, (byte) 0xBB, 0x00, 0x00};
- static final byte[] TEST_PAIRING_KEY = {0x02, 0x01, 0x02, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
- static final int TEST_PIN_NUMBER = 66051;
- static final int TEST_MODEL_ID = 4386;
- static final byte[] TEST_MODEL_ID_BYTES = {0x00, 0x11, 0x22};
- static final int ASYNC_CALL_TIMEOUT_MILLIS = 200;
- byte[] mAdvertisementExpectedResults = new byte[]{0x00, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x11, 0x00};
- @Mock
- Context mMockContext;
-
- @Mock
- Resources mMockResources;
-
- @Mock
- SharedPreferences mMockSharedPreferences;
-
- @Mock
- SharedPreferences.Editor mMockSharedPreferencesEditor;
-
- @Mock
- BluetoothManager mMockBluetoothManager;
-
- @Mock
- FastPairGattServer.Callbacks mMockGattCallbacks;
-
- @Mock
- BluetoothAdapter mMockBluetoothAdapter;
-
- @Mock
- BluetoothDevice mMockBluetoothDevice;
-
- @Mock
- BluetoothLeAdvertiser mMockLeAdvertiser;
-
- @Captor ArgumentCaptor<AdvertisingSetParameters> mAdvertisingSetParameters;
- @Captor ArgumentCaptor<AdvertiseData> mAdvertiseData;
-
- FastPairAdvertiser mTestFastPairAdvertiser;
- FastPairProvider mTestFastPairProvider;
- FastPairGattServer mTestGattServer;
-
- MockitoSession mMockitoSession;
-
- @Before
- public void setUp() {
- MockitoAnnotations.initMocks(this);
- when(mMockContext.getSharedPreferences(anyString(), anyInt()))
- .thenReturn(mMockSharedPreferences);
- when(mMockSharedPreferences.getInt(any(), anyInt())).thenReturn(2);
- when(mMockSharedPreferences.getString(any(), any()))
- .thenReturn(new BigInteger(TEST_ACCOUNT_KEY_1).toString())
- .thenReturn(new BigInteger(TEST_ACCOUNT_KEY_2).toString());
- when(mMockSharedPreferences.edit()).thenReturn(mMockSharedPreferencesEditor);
-
- when(mMockContext.getResources()).thenReturn(mMockResources);
- when(mMockContext.getSystemService(BluetoothManager.class))
- .thenReturn(mMockBluetoothManager);
- when(mMockResources.getInteger(anyInt())).thenReturn(0x001122);
- when(mMockResources.getBoolean(anyInt())).thenReturn(true);
- when(mMockBluetoothManager.getAdapter()).thenReturn(mMockBluetoothAdapter);
- when(mMockBluetoothAdapter.getBluetoothLeAdvertiser()).thenReturn(mMockLeAdvertiser);
- when(mMockBluetoothAdapter.getName()).thenReturn("name");
- when(mMockBluetoothAdapter.getAddress()).thenReturn("00:11:22:33:FF:EE");
- when(mMockBluetoothAdapter.getRemoteDevice(any(String.class))).thenReturn(
- mMockBluetoothDevice);
- when(mMockBluetoothAdapter.getRemoteDevice(any(byte[].class))).thenReturn(
- mMockBluetoothDevice);
-
- mMockitoSession = ExtendedMockito.mockitoSession()
- .strictness(Strictness.WARN)
- .spyStatic(BluetoothAdapter.class)
- .startMocking();
-
- mTestFastPairAdvertiser = new FastPairAdvertiser(mMockContext, TEST_MODEL_ID, null);
- mTestFastPairProvider = new FastPairProvider(mMockContext);
- mTestGattServer = new FastPairGattServer(mMockContext, TEST_MODEL_ID,
- TEST_PRIVATE_KEY_B_BASE64, mMockGattCallbacks, true);
- }
-
- @After
- public void tearDown() {
- mMockitoSession.finishMocking();
- }
-
- @Test
- public void bloomFilterOneKeyTest() {
- List<FastPairUtils.AccountKey> testKeys = new ArrayList();
- testKeys.add(new FastPairUtils.AccountKey(TEST_ACCOUNT_KEY_1));
-
- byte[] bloomResults = FastPairUtils.bloom(testKeys, TEST_SALT);
- assertThat(bloomResults).isEqualTo(TEST_KEY_1_EXPECTED_RESULT);
- }
-
- @Test
- public void bloomFilterTwoKeyTest() {
- List<FastPairUtils.AccountKey> testKeys = new ArrayList();
- testKeys.add(new FastPairUtils.AccountKey(TEST_ACCOUNT_KEY_1));
- testKeys.add(new FastPairUtils.AccountKey(TEST_ACCOUNT_KEY_2));
-
- byte[] bloomResults = FastPairUtils.bloom(testKeys, TEST_SALT);
- assertThat(bloomResults).isEqualTo(TEST_KEY_12_EXPECTED_RESULT);
- }
-
- @Test
- public void readAccountKeysTest() {
- List<FastPairUtils.AccountKey> testKeys = FastPairUtils.readStoredAccountKeys(mMockContext);
- assertThat(testKeys.size()).isEqualTo(2);
- assertThat(testKeys.get(0).key).isEqualTo(TEST_ACCOUNT_KEY_1);
- assertThat(testKeys.get(1).key).isEqualTo(TEST_ACCOUNT_KEY_2);
- }
-
- @Test
- public void getAccountKeyTest() {
- byte[] advertisementResults = FastPairUtils.getAccountKeyAdvertisement(mMockContext);
- byte salt = advertisementResults[advertisementResults.length - 1];
- List<FastPairUtils.AccountKey> testKeys = new ArrayList();
- testKeys.add(new FastPairUtils.AccountKey(TEST_ACCOUNT_KEY_1));
- testKeys.add(new FastPairUtils.AccountKey(TEST_ACCOUNT_KEY_2));
-
- byte[] bloomResults = FastPairUtils.bloom(testKeys, salt);
- System.arraycopy(bloomResults, 0, mAdvertisementExpectedResults, 2,
- bloomResults.length);
- mAdvertisementExpectedResults[mAdvertisementExpectedResults.length - 1] = salt;
-
- assertThat(advertisementResults).isEqualTo(mAdvertisementExpectedResults);
- }
-
- @Test
- public void testGetBytesFromAddress() {
- byte[] conversionResults = FastPairUtils.getBytesFromAddress(TEST_LOCAL_ADDRESS_STRING);
- assertThat(conversionResults).isEqualTo(TEST_LOCAL_ADDRESS);
- }
-
- @Test
- public void testAccountKeyCreation() {
- FastPairUtils.AccountKey testKey = new FastPairUtils.AccountKey(TEST_ACCOUNT_KEY_1);
- assertThat(testKey.toBytes()).isEqualTo(TEST_ACCOUNT_KEY_1);
- }
-
- @Test
- public void testSymmetricEncryption() {
- mTestGattServer.setSharedSecretKey(TEST_SHARED_SECRET);
- byte[] testEncoded = mTestGattServer.encrypt(TEST_INPUT);
- assertThat(testEncoded).isEqualTo(TEST_OUTPUT);
-
- byte[] testDecoded = mTestGattServer.decrypt(testEncoded);
- assertThat(testDecoded).isEqualTo(TEST_INPUT);
-
- }
-
- @Test
- public void tessECDHKeyGeneration() {
- FastPairUtils.AccountKey generatedKey = mTestGattServer
- .calculateAntiSpoofing(TEST_PRIVATE_KEY_B, TEST_PUBLIC_KEY_A);
- assertThat(generatedKey.toBytes()).isEqualTo(TEST_GENERATED_KEY);
-
- }
-
- @Test
- public void testStoredKeySelection() {
- FastPairUtils.AccountKey testKey = new FastPairUtils.AccountKey(TEST_ACCOUNT_KEY_1);
- mTestGattServer.setSharedSecretKey(testKey.toBytes());
- byte[] encryptedRequest = mTestGattServer.encrypt(TEST_PAIRING_REQUEST);
- mTestGattServer.setSharedSecretKey(TEST_SHARED_SECRET);
- assertThat(mTestGattServer.validatePairingRequest(encryptedRequest,
- (new FastPairUtils.AccountKey(TEST_ACCOUNT_KEY_2)).getKeySpec())).isFalse();
-
- assertThat(mTestGattServer.processKeyBasedPairing(encryptedRequest)).isTrue();
- }
-
-
- @Test
- public void testNoValidKey() {
- FastPairUtils.AccountKey testKey = new FastPairUtils.AccountKey(TEST_SHARED_SECRET);
- mTestGattServer.setSharedSecretKey(testKey.toBytes());
- byte[] encryptedRequest = mTestGattServer.encrypt(TEST_PAIRING_REQUEST);
- assertThat(mTestGattServer.validatePairingRequest(encryptedRequest,
- (new FastPairUtils.AccountKey(TEST_ACCOUNT_KEY_1)).getKeySpec())).isFalse();
- assertThat(mTestGattServer.processKeyBasedPairing(encryptedRequest)).isFalse();
- }
-
- @Test
- public void testDisableAfter10Failures() {
- FastPairUtils.AccountKey testKey = new FastPairUtils.AccountKey(TEST_ACCOUNT_KEY_2);
- mTestGattServer.setSharedSecretKey(testKey.toBytes());
- byte[] encryptedRequest = mTestGattServer.encrypt(TEST_PAIRING_REQUEST);
- assertThat(mTestGattServer.processKeyBasedPairing(encryptedRequest)).isTrue();
-
- for (int i = 0; i < 10; i++) {
- assertThat(mTestGattServer.processKeyBasedPairing(TEST_PAIRING_REQUEST)).isFalse();
- }
-
- assertThat(mTestGattServer.processKeyBasedPairing(encryptedRequest)).isFalse();
- }
-
- @Test
- public void testIgnoreAfterTimeout() {
- FastPairUtils.AccountKey testKey = new FastPairUtils.AccountKey(TEST_SHARED_SECRET);
- mTestGattServer.setSharedSecretKey(testKey.toBytes());
- byte[] encryptedRequest = mTestGattServer.encrypt(TEST_PAIRING_REQUEST);
-
- byte[] encryptedPairingKey = mTestGattServer.encrypt(TEST_PAIRING_KEY);
-
- assertThat(mTestGattServer.validatePairingRequest(encryptedRequest,
- testKey.getKeySpec())).isTrue();
- //sendTimeout
- verify(mMockBluetoothDevice, after(11000).times(0)).setPairingConfirmation(false);
-
- assertThat(mTestGattServer.processPairingKey(encryptedPairingKey)).isFalse();
- }
-
- @Test
- public void testInvalidPairingKey() {
- FastPairUtils.AccountKey testKey = new FastPairUtils.AccountKey(TEST_SHARED_SECRET);
- mTestGattServer.setSharedSecretKey(testKey.toBytes());
- byte[] encryptedRequest = mTestGattServer.encrypt(TEST_PAIRING_REQUEST);
-
- byte[] encryptedPairingKey = mTestGattServer.encrypt(TEST_PAIRING_KEY);
-
- assertThat(mTestGattServer.validatePairingRequest(encryptedRequest,
- testKey.getKeySpec())).isTrue();
- //send Wrong Pairing Key
- sendPairingKey(-2);
- mTestGattServer.processPairingKey(encryptedPairingKey);
- verify(mMockBluetoothDevice).setPairingConfirmation(false);
- }
-
- @Test
- public void testNoPairingKey() {
- FastPairUtils.AccountKey testKey = new FastPairUtils.AccountKey(TEST_SHARED_SECRET);
- mTestGattServer.setSharedSecretKey(testKey.toBytes());
- byte[] encryptedRequest = mTestGattServer.encrypt(TEST_PAIRING_REQUEST);
-
- byte[] encryptedPairingKey = mTestGattServer.encrypt(TEST_PAIRING_KEY);
-
- assertThat(mTestGattServer.validatePairingRequest(encryptedRequest,
- testKey.getKeySpec())).isTrue();
- mTestGattServer.processPairingKey(encryptedPairingKey);
- verifyNoMoreInteractions(mMockBluetoothDevice);
- }
-
-
- @Test
- public void testValidPairingKeyAutoAccept() {
- FastPairUtils.AccountKey testKey = new FastPairUtils.AccountKey(TEST_SHARED_SECRET);
- mTestGattServer.setSharedSecretKey(testKey.toBytes());
- byte[] encryptedRequest = mTestGattServer.encrypt(TEST_PAIRING_REQUEST);
-
- byte[] encryptedPairingKey = mTestGattServer.encrypt(TEST_PAIRING_KEY);
-
- assertThat(mTestGattServer.validatePairingRequest(encryptedRequest,
- testKey.getKeySpec())).isTrue();
-
- sendPairingKey(TEST_PIN_NUMBER);
- mTestGattServer.processPairingKey(encryptedPairingKey);
-
- verify(mMockBluetoothDevice).setPairingConfirmation(true);
- }
-
- @Test
- public void testValidPairingKeyNoAutoAccept() {
- mTestGattServer = new FastPairGattServer(mMockContext, TEST_MODEL_ID,
- TEST_PRIVATE_KEY_B_BASE64, mMockGattCallbacks, false);
-
- FastPairUtils.AccountKey testKey = new FastPairUtils.AccountKey(TEST_SHARED_SECRET);
- mTestGattServer.setSharedSecretKey(testKey.toBytes());
- byte[] encryptedRequest = mTestGattServer.encrypt(TEST_PAIRING_REQUEST);
-
- byte[] encryptedPairingKey = mTestGattServer.encrypt(TEST_PAIRING_KEY);
-
- assertThat(mTestGattServer.validatePairingRequest(encryptedRequest,
- testKey.getKeySpec())).isTrue();
-
- sendPairingKey(TEST_PIN_NUMBER);
- mTestGattServer.processPairingKey(encryptedPairingKey);
-
- verify(mMockBluetoothDevice, never()).setPairingConfirmation(true);
-
- }
-
- @Test
- public void receivedAccountKey() {
- FastPairUtils.AccountKey testKey = new FastPairUtils.AccountKey(TEST_SHARED_SECRET);
- mTestGattServer.setSharedSecretKey(testKey.toBytes());
- byte[] encryptedRequest = mTestGattServer.encrypt(TEST_PAIRING_REQUEST);
-
- byte[] encryptedPairingKey = mTestGattServer.encrypt(TEST_PAIRING_KEY);
-
- byte[] encryptedAccountKey = mTestGattServer.encrypt(TEST_ACCOUNT_KEY_3);
-
- assertThat(mTestGattServer.validatePairingRequest(encryptedRequest,
- testKey.getKeySpec())).isTrue();
-
- sendPairingKey(TEST_PIN_NUMBER);
- mTestGattServer.processPairingKey(encryptedPairingKey);
-
- verify(mMockBluetoothDevice).setPairingConfirmation(true);
- mTestGattServer.processAccountKey(encryptedAccountKey);
- verify(mMockSharedPreferences).edit();
-
- }
-
- @Test
- public void testAdvertiseAccountKeys() {
- mTestFastPairAdvertiser.advertiseAccountKeys();
- verify(mMockLeAdvertiser).startAdvertisingSet(mAdvertisingSetParameters.capture(),
- mAdvertiseData.capture(), any(), any(), any(), any());
- assertThat(mAdvertisingSetParameters.getValue().getInterval())
- .isEqualTo(AdvertisingSetParameters.INTERVAL_MEDIUM);
- Map<ParcelUuid, byte[]> serviceData = mAdvertiseData.getValue().getServiceData();
- assertThat(serviceData.size()).isEqualTo(1);
- byte[] advertisementResults = serviceData.get(FastPairAdvertiser.FastPairServiceUuid);
- byte salt = advertisementResults[advertisementResults.length - 1];
- List<FastPairUtils.AccountKey> testKeys = new ArrayList();
- testKeys.add(new FastPairUtils.AccountKey(TEST_ACCOUNT_KEY_1));
- testKeys.add(new FastPairUtils.AccountKey(TEST_ACCOUNT_KEY_2));
-
- byte[] bloomResults = FastPairUtils.bloom(testKeys, salt);
- System.arraycopy(bloomResults, 0, mAdvertisementExpectedResults, 2,
- bloomResults.length);
- mAdvertisementExpectedResults[mAdvertisementExpectedResults.length - 1] = salt;
-
- assertThat(advertisementResults).isEqualTo(mAdvertisementExpectedResults);
- }
-
- @Test
- public void testAdvertiseModelId() {
- mTestFastPairAdvertiser.advertiseModelId();
- verify(mMockLeAdvertiser).startAdvertisingSet(mAdvertisingSetParameters.capture(),
- mAdvertiseData.capture(), any(), any(), any(), any());
- assertThat(mAdvertisingSetParameters.getValue().getInterval())
- .isEqualTo(AdvertisingSetParameters.INTERVAL_LOW);
- Map<ParcelUuid, byte[]> serviceData = mAdvertiseData.getValue().getServiceData();
- assertThat(serviceData.size()).isEqualTo(1);
- assertThat(serviceData.get(FastPairAdvertiser.FastPairServiceUuid))
- .isEqualTo(TEST_MODEL_ID_BYTES);
- }
-
- @Test
- public void testStopAdvertisements() {
- mTestFastPairProvider.start();
- when(mMockBluetoothAdapter.isDiscovering()).thenReturn(true);
- Intent scanMode = new Intent(BluetoothAdapter.ACTION_SCAN_MODE_CHANGED);
- scanMode.putExtra(BluetoothAdapter.EXTRA_SCAN_MODE,
- BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE);
- mTestFastPairProvider.mDiscoveryModeChanged.onReceive(mMockContext, scanMode);
-
- when(mMockBluetoothAdapter.isDiscovering()).thenReturn(false);
- scanMode.putExtra(BluetoothAdapter.EXTRA_SCAN_MODE,
- BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE);
- mTestFastPairProvider.mDiscoveryModeChanged.onReceive(mMockContext, scanMode);
- verify(mMockLeAdvertiser, timeout(ASYNC_CALL_TIMEOUT_MILLIS)).stopAdvertisingSet(any());
- }
-
- void sendPairingKey(int pairingKey) {
- Intent pairingRequest = new Intent(BluetoothDevice.ACTION_PAIRING_REQUEST);
- pairingRequest.putExtra(BluetoothDevice.EXTRA_PAIRING_KEY, pairingKey);
- pairingRequest.putExtra(BluetoothDevice.EXTRA_DEVICE, mMockBluetoothDevice);
- mTestGattServer.mPairingAttemptsReceiver.onReceive(mMockContext, pairingRequest);
-
- }
-}
diff --git a/tests/carservice_unit_test/src/com/android/car/bluetooth/BluetoothUtilsGetAdapterStateNameTest.java b/tests/carservice_unit_test/src/com/android/car/bluetooth/BluetoothUtilsGetAdapterStateNameTest.java
index 78c2048..821eaeb 100644
--- a/tests/carservice_unit_test/src/com/android/car/bluetooth/BluetoothUtilsGetAdapterStateNameTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/bluetooth/BluetoothUtilsGetAdapterStateNameTest.java
@@ -54,6 +54,7 @@
{BluetoothAdapter.STATE_OFF, "off"},
{BluetoothAdapter.STATE_TURNING_ON, "turning on"},
{BluetoothAdapter.STATE_TURNING_OFF, "turning off"},
+ {BluetoothAdapter.ERROR, "error"},
{9, "unknown"},
{14, "unknown"}
});
diff --git a/tests/carservice_unit_test/src/com/android/car/bluetooth/BluetoothUtilsGetAdvertisingCallbackStatusNameTest.java b/tests/carservice_unit_test/src/com/android/car/bluetooth/BluetoothUtilsGetAdvertisingCallbackStatusNameTest.java
new file mode 100644
index 0000000..d122e78
--- /dev/null
+++ b/tests/carservice_unit_test/src/com/android/car/bluetooth/BluetoothUtilsGetAdvertisingCallbackStatusNameTest.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2021 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.bluetooth;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.bluetooth.le.AdvertisingSetCallback;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+import java.util.Arrays;
+import java.util.Collection;
+
+@RunWith(Parameterized.class)
+public final class BluetoothUtilsGetAdvertisingCallbackStatusNameTest {
+
+ private final int mStatus;
+ private final String mName;
+
+ public BluetoothUtilsGetAdvertisingCallbackStatusNameTest(int status, String name) {
+ mStatus = status;
+ mName = name;
+ }
+
+ @Test
+ public void testGetAdvertisingCallbackStatusName() {
+ String result = BluetoothUtils.getAdvertisingCallbackStatusName(mStatus);
+
+ assertThat(result).contains(String.valueOf(mStatus));
+ assertThat(result).ignoringCase().contains(mName);
+ }
+
+ @Parameterized.Parameters
+ public static Collection provideParams() {
+ return Arrays.asList(
+ new Object[][] {
+
+ {AdvertisingSetCallback.ADVERTISE_FAILED_ALREADY_STARTED,
+ "ADVERTISE_FAILED_ALREADY_STARTED"},
+ {AdvertisingSetCallback.ADVERTISE_FAILED_DATA_TOO_LARGE,
+ "ADVERTISE_FAILED_DATA_TOO_LARGE"},
+ {AdvertisingSetCallback.ADVERTISE_FAILED_FEATURE_UNSUPPORTED,
+ "ADVERTISE_FAILED_FEATURE_UNSUPPORTED"},
+ {AdvertisingSetCallback.ADVERTISE_FAILED_INTERNAL_ERROR,
+ "ADVERTISE_FAILED_INTERNAL_ERROR"},
+ {AdvertisingSetCallback.ADVERTISE_FAILED_TOO_MANY_ADVERTISERS,
+ "ADVERTISE_FAILED_TOO_MANY_ADVERTISERS"},
+ {AdvertisingSetCallback.ADVERTISE_SUCCESS,
+ "ADVERTISE_SUCCESS"},
+ {-1, "unknown"},
+ {15, "unknown"}
+ });
+ }
+}
diff --git a/tests/carservice_unit_test/src/com/android/car/bluetooth/BluetoothUtilsGetScanModeNameTest.java b/tests/carservice_unit_test/src/com/android/car/bluetooth/BluetoothUtilsGetScanModeNameTest.java
new file mode 100644
index 0000000..f17d623
--- /dev/null
+++ b/tests/carservice_unit_test/src/com/android/car/bluetooth/BluetoothUtilsGetScanModeNameTest.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2022 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.bluetooth;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.bluetooth.BluetoothAdapter;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+import java.util.Arrays;
+import java.util.Collection;
+
+@RunWith(Parameterized.class)
+public final class BluetoothUtilsGetScanModeNameTest {
+
+ private final int mMode;
+ private final String mName;
+
+ public BluetoothUtilsGetScanModeNameTest(int mode, String name) {
+ mMode = mode;
+ mName = name;
+ }
+
+ @Test
+ public void testGetScanModeName() {
+ String result = BluetoothUtils.getScanModeName(mMode);
+ assertThat(result).contains(String.valueOf(mMode));
+ assertThat(result).ignoringCase().contains(mName);
+ }
+
+ @Parameterized.Parameters
+ public static Collection provideParams() {
+ return Arrays.asList(
+ new Object[][] {
+ {BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE, "Connectable/Discoverable"},
+ {BluetoothAdapter.SCAN_MODE_CONNECTABLE, "Connectable"},
+ {BluetoothAdapter.SCAN_MODE_NONE, "None"},
+ {BluetoothAdapter.ERROR, "Error"},
+ {9, "Unknown"},
+ {13, "Unknown"}
+ });
+ }
+}
diff --git a/tests/carservice_unit_test/src/com/android/car/bluetooth/BluetoothUtilsTest.java b/tests/carservice_unit_test/src/com/android/car/bluetooth/BluetoothUtilsTest.java
index 3be2ea2..8600b2c 100644
--- a/tests/carservice_unit_test/src/com/android/car/bluetooth/BluetoothUtilsTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/bluetooth/BluetoothUtilsTest.java
@@ -29,6 +29,8 @@
@RunWith(MockitoJUnitRunner.class)
public class BluetoothUtilsTest {
+ static final String TEST_LOCAL_ADDRESS_STRING = "00:11:22:33:44:55";
+ static final byte[] TEST_LOCAL_ADDRESS = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55};
@Mock
private BluetoothDevice mMockBluetoothDevice;
@@ -43,6 +45,12 @@
}
@Test
+ public void testGetBytesFromAddress() {
+ byte[] conversionResults = BluetoothUtils.getBytesFromAddress(TEST_LOCAL_ADDRESS_STRING);
+ assertThat(conversionResults).isEqualTo(TEST_LOCAL_ADDRESS);
+ }
+
+ @Test
public void testGetDeviceDebugInfo_nullDevice() {
assertThat(BluetoothUtils.getDeviceDebugInfo(null)).isEqualTo("(null)");
}
diff --git a/tests/carservice_unit_test/src/com/android/car/bluetooth/CarBluetoothUserServiceTest.java b/tests/carservice_unit_test/src/com/android/car/bluetooth/CarBluetoothUserServiceTest.java
index cbc3633..c059a68 100644
--- a/tests/carservice_unit_test/src/com/android/car/bluetooth/CarBluetoothUserServiceTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/bluetooth/CarBluetoothUserServiceTest.java
@@ -42,6 +42,7 @@
import android.content.Context;
import android.content.res.Resources;
import android.os.ParcelUuid;
+import android.os.UserManager;
import android.telecom.PhoneAccountHandle;
import android.telecom.TelecomManager;
@@ -75,6 +76,9 @@
public class CarBluetoothUserServiceTest extends AbstractExtendedMockitoBluetoothTestCase {
private static final String TAG = CarBluetoothUserServiceTest.class.getSimpleName();
+ static final String DEVICE_NAME = "name";
+ static final String DEVICE_ADDRESS_STRING = "11:22:33:44:55:66";
+
private static final String DEFAULT_DEVICE = "00:11:22:33:44:55";
private static final List<String> DEVICE_LIST_WITHOUT_DEFAULT = Arrays.asList(
"DE:AD:BE:EF:00:00",
@@ -101,6 +105,7 @@
@Mock private PhoneAccountHandle mMockPhoneAccountHandle;
@Captor private ArgumentCaptor<BluetoothDevice> mBvraDeviceCaptor;
@Mock private Resources mMockResources;
+ @Mock private UserManager mMockUserManager;
@Override
protected void onSessionBuilder(CustomMockitoSessionBuilder session) {
@@ -117,6 +122,8 @@
when(mMockPerUserCarServiceImpl.getApplicationContext()).thenReturn(mMockContext);
mMockContext.addMockedSystemService(BluetoothManager.class, mMockBluetoothManager);
when(mMockBluetoothManager.getAdapter()).thenReturn(mMockBluetoothAdapter);
+ when(mMockBluetoothAdapter.getName()).thenReturn(DEVICE_NAME);
+ when(mMockBluetoothAdapter.getAddress()).thenReturn(DEVICE_ADDRESS_STRING);
// for testing BVRA
mMockContext.addMockedSystemService(TelecomManager.class, mMockTelecomManager);
@@ -131,6 +138,9 @@
when(mMockPerUserCarServiceImpl.getResources()).thenReturn(mMockResources);
when(mMockPerUserCarServiceImpl.getSystemService(eq(BluetoothManager.class)))
.thenReturn(mMockBluetoothManager);
+ when(mMockPerUserCarServiceImpl.getSystemService(eq(UserManager.class)))
+ .thenReturn(mMockUserManager);
+ when(mMockUserManager.isUserUnlocked()).thenReturn(false);
mCarBluetoothUserService = new CarBluetoothUserService(mMockPerUserCarServiceImpl);
diff --git a/tests/carservice_unit_test/src/com/android/car/bluetooth/FastPairAccountKeyStorageTest.java b/tests/carservice_unit_test/src/com/android/car/bluetooth/FastPairAccountKeyStorageTest.java
new file mode 100644
index 0000000..141621e
--- /dev/null
+++ b/tests/carservice_unit_test/src/com/android/car/bluetooth/FastPairAccountKeyStorageTest.java
@@ -0,0 +1,506 @@
+/*
+ * Copyright (C) 2022 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.bluetooth;
+
+import static com.android.car.bluetooth.FastPairAccountKeyStorage.AccountKey;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.nullable;
+import static org.mockito.Mockito.anyInt;
+import static org.mockito.Mockito.anyString;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.os.UserManager;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.mockito.junit.MockitoJUnitRunner;
+
+import java.math.BigInteger;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.crypto.spec.SecretKeySpec;
+
+/**
+ * Unit tests for {@link FastPairAccountKeyStorage}
+ *
+ * Run: atest FastPairAccountKeyStorageTest
+ */
+@RunWith(MockitoJUnitRunner.class)
+public class FastPairAccountKeyStorageTest {
+ private static final String KEY_NUM_ACCOUNT_KEYS = "AccountKeysCount";
+
+ private static final int TEST_SIZE = 5;
+ private static final int TEST_SIZE_TOO_SMALL = 3;
+ private static final byte[] TEST_ACCOUNT_KEY_1 = new byte[]{0x11, 0x22, 0x33, 0x44, 0x55, 0x66,
+ 0x77, (byte) 0x88, (byte) 0x99, 0x00, (byte) 0xAA, (byte) 0xBB, (byte) 0xCC,
+ (byte) 0xDD, (byte) 0xEE, (byte) 0xFF};
+ private static final byte[] TEST_ACCOUNT_KEY_2 = new byte[]{0x11, 0x11, 0x22, 0x22, 0x33, 0x33,
+ 0x44, 0x44, 0x55, 0x55, 0x66, 0x66, 0x77, 0x77, (byte) 0x88, (byte) 0x88};
+ private static final byte[] TEST_ACCOUNT_KEY_3 = new byte[]{0x04, 0x11, 0x22, 0x22, 0x33, 0x33,
+ 0x44, 0x44, 0x55, 0x55, 0x66, 0x66, 0x77, 0x77, (byte) 0x88, (byte) 0x88};
+ private static final byte[] TEST_ACCOUNT_KEY_4 = new byte[]{0x05, 0x11, 0x22, 0x22, 0x33, 0x33,
+ 0x44, 0x44, 0x55, 0x55, 0x66, 0x66, 0x77, 0x77, (byte) 0x88, (byte) 0x88};
+ private static final byte[] TEST_ACCOUNT_KEY_5 = new byte[]{0x06, 0x11, 0x22, 0x22, 0x33, 0x33,
+ 0x44, 0x44, 0x55, 0x55, 0x66, 0x66, 0x77, 0x77, (byte) 0x88, (byte) 0x88};
+ private static final byte[] TEST_ACCOUNT_KEY_6 = new byte[]{0x07, 0x11, 0x22, 0x22, 0x33, 0x33,
+ 0x44, 0x44, 0x55, 0x55, 0x66, 0x66, 0x77, 0x77, (byte) 0x88, (byte) 0x88};
+
+ @Mock Context mMockContext;
+ @Mock UserManager mMockUserManager;
+ @Mock SharedPreferences mMockSharedPreferences;
+ @Mock SharedPreferences.Editor mMockSharedPreferencesEditor;
+
+ private int mSharedPreferencesContentCount = 0;
+ private Map<String, String> mSharedPreferencesContent;
+
+ private FastPairAccountKeyStorage mFastPairAccountKeyStorage;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ when(mMockContext.getSystemService(UserManager.class)).thenReturn(mMockUserManager);
+ when(mMockContext.getSharedPreferences(anyString(), anyInt()))
+ .thenReturn(mMockSharedPreferences);
+ when(mMockSharedPreferences.edit()).thenReturn(mMockSharedPreferencesEditor);
+
+ // Mock out Shared Preferences and route calls to our internal map and int variable
+ mSharedPreferencesContentCount = 0;
+ mSharedPreferencesContent = new HashMap<>();
+
+ // SharedPreferencesEditor.putInt
+ doAnswer(invocation -> {
+ String key = (String) invocation.getArgument(0);
+ int value = (Integer) invocation.getArgument(1);
+ if (KEY_NUM_ACCOUNT_KEYS.equals(key)) {
+ mSharedPreferencesContentCount = value;
+ }
+ return invocation.getMock();
+ }).when(mMockSharedPreferencesEditor).putInt(anyString(), anyInt());
+
+ // SharedPreferencesEditor.putString
+ doAnswer(invocation -> {
+ String key = (String) invocation.getArgument(0);
+ String value = (String) invocation.getArgument(1);
+ mSharedPreferencesContent.put(key, value);
+ return invocation.getMock();
+ }).when(mMockSharedPreferencesEditor).putString(anyString(), anyString());
+
+ // SharedPreferencesEditor.remove
+ doAnswer(invocation -> {
+ String key = (String) invocation.getArgument(0);
+ mSharedPreferencesContent.remove(key);
+ return invocation.getMock();
+ }).when(mMockSharedPreferencesEditor).remove(anyString());
+
+ // SharedPreferences.getInt
+ doAnswer(invocation -> {
+ String key = (String) invocation.getArgument(0);
+ int defaultValue = (Integer) invocation.getArgument(1);
+ if (KEY_NUM_ACCOUNT_KEYS.equals(key)) {
+ return mSharedPreferencesContentCount;
+ }
+ return defaultValue;
+ }).when(mMockSharedPreferences).getInt(anyString(), anyInt());
+
+ // SharedPreferences.getString
+ doAnswer(invocation -> {
+ String key = (String) invocation.getArgument(0);
+ String defaultValue = (String) invocation.getArgument(1);
+ return mSharedPreferencesContent.getOrDefault(key, defaultValue);
+ }).when(mMockSharedPreferences).getString(anyString(), nullable(String.class));
+ }
+
+ private void setUserUnlocked(boolean state) {
+ when(mMockUserManager.isUserUnlocked()).thenReturn(state);
+ }
+
+ private void setPersistedKeys(List<AccountKey> keys) {
+ assertThat(keys).isNotNull();
+ mSharedPreferencesContent.clear();
+
+ mSharedPreferencesContentCount = keys.size();
+ int i = 0;
+ for (AccountKey key : keys) {
+ String keyString = new BigInteger(key.toBytes()).toString();
+ String index = Integer.toString(i++);
+ mSharedPreferencesContent.put(index, keyString);
+ }
+ }
+
+ private void assertPersistedKeys(List<AccountKey> expected) {
+ assertThat(expected).isNotNull();
+ assertThat(mSharedPreferencesContentCount).isEqualTo(expected.size());
+ assertThat(mSharedPreferencesContent.size()).isEqualTo(expected.size());
+ int i = 0;
+ for (AccountKey key : expected) {
+ String keyExpected = new BigInteger(key.toBytes()).toString();
+ String keyActual = mSharedPreferencesContent.getOrDefault("" + i++, null);
+ assertThat(keyActual).isNotNull();
+ assertThat(keyActual).isEqualTo(keyExpected);
+ }
+ }
+
+ @Test
+ public void testAccountKeyCreateFromBytes_succeeds() {
+ AccountKey key = new AccountKey(TEST_ACCOUNT_KEY_1);
+ assertThat(key).isNotNull();
+ assertThat(key.toBytes()).isEqualTo(TEST_ACCOUNT_KEY_1);
+ assertThat(key.getKeySpec()).isEqualTo(new SecretKeySpec(TEST_ACCOUNT_KEY_1, "AES"));
+ assertThat(key.toString()).isNotNull();
+ }
+
+ @Test
+ public void testAccountKeyCreateFromString_succeeds() {
+ AccountKey key = new AccountKey(new BigInteger(TEST_ACCOUNT_KEY_1).toString());
+ assertThat(key).isNotNull();
+ assertThat(key.toBytes()).isEqualTo(TEST_ACCOUNT_KEY_1);
+ assertThat(key.getKeySpec()).isEqualTo(new SecretKeySpec(TEST_ACCOUNT_KEY_1, "AES"));
+ assertThat(key.toString()).isNotNull();
+ }
+
+ @Test
+ public void testAccountKeyHashCodeSameKey_hashCodeMatches() {
+ AccountKey key = new AccountKey(TEST_ACCOUNT_KEY_1);
+ AccountKey keyCopy = new AccountKey(TEST_ACCOUNT_KEY_1);
+ assertThat(key.hashCode()).isEqualTo(keyCopy.hashCode());
+ }
+
+ @Test
+ public void testAccountKeyHashCodeDifferentKey_hashCodeDoesntMatch() {
+ AccountKey key = new AccountKey(TEST_ACCOUNT_KEY_1);
+ AccountKey keyDifferent = new AccountKey(TEST_ACCOUNT_KEY_2);
+ assertThat(key.hashCode()).isNotEqualTo(keyDifferent.hashCode());
+ }
+
+ @Test
+ public void testAccountKeyEqualsSameKey_keysAreEqual() {
+ AccountKey key = new AccountKey(TEST_ACCOUNT_KEY_1);
+ AccountKey keyCopy = new AccountKey(TEST_ACCOUNT_KEY_1);
+ assertThat(key.equals(keyCopy)).isTrue();
+ }
+
+ @Test
+ public void testAccountKeyEqualsDifferentKey_keysAreNotEqual() {
+ AccountKey key = new AccountKey(TEST_ACCOUNT_KEY_1);
+ AccountKey keyDifferent = new AccountKey(TEST_ACCOUNT_KEY_2);
+ assertThat(key.equals(keyDifferent)).isFalse();
+ }
+
+ @Test
+ public void testAccountKeyEqualsDifferentObjectType_keysAreNotEqual() {
+ AccountKey key = new AccountKey(TEST_ACCOUNT_KEY_1);
+ Object otherObj = new Object();
+ assertThat(key.equals(otherObj)).isFalse();
+ }
+
+ @Test
+ public void testCreateWithValidSize_storageCreated() {
+ mFastPairAccountKeyStorage = new FastPairAccountKeyStorage(mMockContext, TEST_SIZE);
+ assertThat(mFastPairAccountKeyStorage).isNotNull();
+ assertThat(mFastPairAccountKeyStorage.capacity()).isEqualTo(TEST_SIZE);
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testCreateWithSizeTooSmall_throwsException() {
+ mFastPairAccountKeyStorage =
+ new FastPairAccountKeyStorage(mMockContext, TEST_SIZE_TOO_SMALL);
+ }
+
+ @Test
+ public void testAddKeyWhileStorageEmpty_keyAdded() {
+ mFastPairAccountKeyStorage = new FastPairAccountKeyStorage(mMockContext, TEST_SIZE);
+
+ setUserUnlocked(true);
+ mFastPairAccountKeyStorage.add(new AccountKey(TEST_ACCOUNT_KEY_1));
+
+ ArrayList<AccountKey> expectedKeys =
+ new ArrayList<AccountKey>(List.of(new AccountKey(TEST_ACCOUNT_KEY_1)));
+ List<AccountKey> returnedKeys = mFastPairAccountKeyStorage.getAllAccountKeys();
+ assertThat(returnedKeys).isEqualTo(expectedKeys);
+ assertPersistedKeys(expectedKeys);
+ }
+
+ @Test
+ public void testAddKeyWhileStorageAtMax_keyAddedAndLruDropped() {
+ mFastPairAccountKeyStorage = new FastPairAccountKeyStorage(mMockContext, TEST_SIZE);
+
+ setUserUnlocked(true);
+ mFastPairAccountKeyStorage.add(new AccountKey(TEST_ACCOUNT_KEY_1));
+ mFastPairAccountKeyStorage.add(new AccountKey(TEST_ACCOUNT_KEY_2));
+ mFastPairAccountKeyStorage.add(new AccountKey(TEST_ACCOUNT_KEY_3));
+ mFastPairAccountKeyStorage.add(new AccountKey(TEST_ACCOUNT_KEY_4));
+ mFastPairAccountKeyStorage.add(new AccountKey(TEST_ACCOUNT_KEY_5));
+ mFastPairAccountKeyStorage.add(new AccountKey(TEST_ACCOUNT_KEY_6));
+
+ ArrayList<AccountKey> expectedKeys = new ArrayList<AccountKey>(List.of(
+ new AccountKey(TEST_ACCOUNT_KEY_2),
+ new AccountKey(TEST_ACCOUNT_KEY_3),
+ new AccountKey(TEST_ACCOUNT_KEY_4),
+ new AccountKey(TEST_ACCOUNT_KEY_5),
+ new AccountKey(TEST_ACCOUNT_KEY_6)));
+ List<AccountKey> returnedKeys = mFastPairAccountKeyStorage.getAllAccountKeys();
+ assertThat(returnedKeys).isEqualTo(expectedKeys);
+ assertPersistedKeys(expectedKeys);
+ }
+
+ @Test
+ public void testAddKeyAlreadyInStorage_KeysLruPositionReset() {
+ mFastPairAccountKeyStorage = new FastPairAccountKeyStorage(mMockContext, TEST_SIZE);
+
+ setUserUnlocked(true);
+ mFastPairAccountKeyStorage.add(new AccountKey(TEST_ACCOUNT_KEY_1));
+ mFastPairAccountKeyStorage.add(new AccountKey(TEST_ACCOUNT_KEY_2));
+ mFastPairAccountKeyStorage.add(new AccountKey(TEST_ACCOUNT_KEY_3));
+ mFastPairAccountKeyStorage.add(new AccountKey(TEST_ACCOUNT_KEY_4));
+ mFastPairAccountKeyStorage.add(new AccountKey(TEST_ACCOUNT_KEY_5));
+ mFastPairAccountKeyStorage.add(new AccountKey(TEST_ACCOUNT_KEY_3));
+
+ ArrayList<AccountKey> expectedKeys = new ArrayList<AccountKey>(List.of(
+ new AccountKey(TEST_ACCOUNT_KEY_1),
+ new AccountKey(TEST_ACCOUNT_KEY_2),
+ new AccountKey(TEST_ACCOUNT_KEY_4),
+ new AccountKey(TEST_ACCOUNT_KEY_5),
+ new AccountKey(TEST_ACCOUNT_KEY_3)));
+ List<AccountKey> returnedKeys = mFastPairAccountKeyStorage.getAllAccountKeys();
+ assertThat(returnedKeys).isEqualTo(expectedKeys);
+ assertPersistedKeys(expectedKeys);
+ }
+
+ @Test
+ public void testAddNullKey_nothingHappens() {
+ mFastPairAccountKeyStorage = new FastPairAccountKeyStorage(mMockContext, TEST_SIZE);
+
+ setUserUnlocked(true);
+ mFastPairAccountKeyStorage.add(new AccountKey(TEST_ACCOUNT_KEY_1));
+ mFastPairAccountKeyStorage.add(new AccountKey(TEST_ACCOUNT_KEY_2));
+ mFastPairAccountKeyStorage.add(new AccountKey(TEST_ACCOUNT_KEY_3));
+ mFastPairAccountKeyStorage.add(new AccountKey(TEST_ACCOUNT_KEY_4));
+ mFastPairAccountKeyStorage.add(new AccountKey(TEST_ACCOUNT_KEY_5));
+ mFastPairAccountKeyStorage.add(null);
+
+ ArrayList<AccountKey> expectedKeys = new ArrayList<AccountKey>(List.of(
+ new AccountKey(TEST_ACCOUNT_KEY_1),
+ new AccountKey(TEST_ACCOUNT_KEY_2),
+ new AccountKey(TEST_ACCOUNT_KEY_3),
+ new AccountKey(TEST_ACCOUNT_KEY_4),
+ new AccountKey(TEST_ACCOUNT_KEY_5)));
+ List<AccountKey> returnedKeys = mFastPairAccountKeyStorage.getAllAccountKeys();
+ assertThat(returnedKeys).isEqualTo(expectedKeys);
+ assertPersistedKeys(expectedKeys);
+ }
+
+ @Test
+ public void testRemoveKeyInStorage_keyRemoved() {
+ mFastPairAccountKeyStorage = new FastPairAccountKeyStorage(mMockContext, TEST_SIZE);
+
+ setUserUnlocked(true);
+ mFastPairAccountKeyStorage.add(new AccountKey(TEST_ACCOUNT_KEY_1));
+ mFastPairAccountKeyStorage.add(new AccountKey(TEST_ACCOUNT_KEY_2));
+ mFastPairAccountKeyStorage.add(new AccountKey(TEST_ACCOUNT_KEY_3));
+
+ ArrayList<AccountKey> expectedKeys = new ArrayList<AccountKey>(List.of(
+ new AccountKey(TEST_ACCOUNT_KEY_1),
+ new AccountKey(TEST_ACCOUNT_KEY_2),
+ new AccountKey(TEST_ACCOUNT_KEY_3)));
+ List<AccountKey> returnedKeys = mFastPairAccountKeyStorage.getAllAccountKeys();
+ assertThat(returnedKeys).isEqualTo(expectedKeys);
+ assertPersistedKeys(expectedKeys);
+
+ mFastPairAccountKeyStorage.remove(new AccountKey(TEST_ACCOUNT_KEY_2));
+
+ ArrayList<AccountKey> expectedKeys2 = new ArrayList<AccountKey>(List.of(
+ new AccountKey(TEST_ACCOUNT_KEY_1),
+ new AccountKey(TEST_ACCOUNT_KEY_3)));
+ returnedKeys = mFastPairAccountKeyStorage.getAllAccountKeys();
+ assertThat(returnedKeys).isEqualTo(expectedKeys2);
+ assertPersistedKeys(expectedKeys2);
+ }
+
+ @Test
+ public void testRemoveKeyNotInStorage_keysUnchanged() {
+ mFastPairAccountKeyStorage = new FastPairAccountKeyStorage(mMockContext, TEST_SIZE);
+
+ setUserUnlocked(true);
+ mFastPairAccountKeyStorage.add(new AccountKey(TEST_ACCOUNT_KEY_1));
+ mFastPairAccountKeyStorage.add(new AccountKey(TEST_ACCOUNT_KEY_2));
+ mFastPairAccountKeyStorage.add(new AccountKey(TEST_ACCOUNT_KEY_3));
+
+ ArrayList<AccountKey> expectedKeys = new ArrayList<AccountKey>(List.of(
+ new AccountKey(TEST_ACCOUNT_KEY_1),
+ new AccountKey(TEST_ACCOUNT_KEY_2),
+ new AccountKey(TEST_ACCOUNT_KEY_3)));
+ List<AccountKey> returnedKeys = mFastPairAccountKeyStorage.getAllAccountKeys();
+ assertThat(returnedKeys).isEqualTo(expectedKeys);
+ assertPersistedKeys(expectedKeys);
+
+ mFastPairAccountKeyStorage.remove(new AccountKey(TEST_ACCOUNT_KEY_4));
+
+ returnedKeys = mFastPairAccountKeyStorage.getAllAccountKeys();
+ assertThat(returnedKeys).isEqualTo(expectedKeys);
+ assertPersistedKeys(expectedKeys);
+ }
+
+ @Test
+ public void testRemoveNullKey_nothingHappens() {
+ mFastPairAccountKeyStorage = new FastPairAccountKeyStorage(mMockContext, TEST_SIZE);
+
+ setUserUnlocked(true);
+ mFastPairAccountKeyStorage.add(new AccountKey(TEST_ACCOUNT_KEY_1));
+ mFastPairAccountKeyStorage.add(new AccountKey(TEST_ACCOUNT_KEY_2));
+ mFastPairAccountKeyStorage.add(new AccountKey(TEST_ACCOUNT_KEY_3));
+
+ ArrayList<AccountKey> expectedKeys = new ArrayList<AccountKey>(List.of(
+ new AccountKey(TEST_ACCOUNT_KEY_1),
+ new AccountKey(TEST_ACCOUNT_KEY_2),
+ new AccountKey(TEST_ACCOUNT_KEY_3)));
+ List<AccountKey> returnedKeys = mFastPairAccountKeyStorage.getAllAccountKeys();
+ assertThat(returnedKeys).isEqualTo(expectedKeys);
+ assertPersistedKeys(expectedKeys);
+
+ mFastPairAccountKeyStorage.remove(null);
+
+ returnedKeys = mFastPairAccountKeyStorage.getAllAccountKeys();
+ assertThat(returnedKeys).isEqualTo(expectedKeys);
+ assertPersistedKeys(expectedKeys);
+ }
+
+ @Test
+ public void testClearKeys_keysEmpty() {
+ mFastPairAccountKeyStorage = new FastPairAccountKeyStorage(mMockContext, TEST_SIZE);
+
+ setUserUnlocked(true);
+ mFastPairAccountKeyStorage.add(new AccountKey(TEST_ACCOUNT_KEY_1));
+ mFastPairAccountKeyStorage.add(new AccountKey(TEST_ACCOUNT_KEY_2));
+ mFastPairAccountKeyStorage.add(new AccountKey(TEST_ACCOUNT_KEY_3));
+
+ ArrayList<AccountKey> expectedKeys = new ArrayList<AccountKey>(List.of(
+ new AccountKey(TEST_ACCOUNT_KEY_1),
+ new AccountKey(TEST_ACCOUNT_KEY_2),
+ new AccountKey(TEST_ACCOUNT_KEY_3)));
+ List<AccountKey> returnedKeys = mFastPairAccountKeyStorage.getAllAccountKeys();
+ assertThat(returnedKeys).isEqualTo(expectedKeys);
+ assertPersistedKeys(expectedKeys);
+
+ mFastPairAccountKeyStorage.clear();
+
+ returnedKeys = mFastPairAccountKeyStorage.getAllAccountKeys();
+ assertThat(returnedKeys).isEqualTo(new ArrayList<AccountKey>());
+ assertPersistedKeys(new ArrayList<AccountKey>());
+ }
+
+ @Test
+ public void testGetAllAccountKeys_returnsOrderKeySet() {
+ mFastPairAccountKeyStorage = new FastPairAccountKeyStorage(mMockContext, TEST_SIZE);
+ ArrayList<AccountKey> keys = new ArrayList<AccountKey>(List.of(
+ new AccountKey(TEST_ACCOUNT_KEY_1),
+ new AccountKey(TEST_ACCOUNT_KEY_2),
+ new AccountKey(TEST_ACCOUNT_KEY_3),
+ new AccountKey(TEST_ACCOUNT_KEY_4),
+ new AccountKey(TEST_ACCOUNT_KEY_5)));
+
+ setUserUnlocked(true);
+ mFastPairAccountKeyStorage.add(keys.get(0));
+ mFastPairAccountKeyStorage.add(keys.get(1));
+ mFastPairAccountKeyStorage.add(keys.get(2));
+ mFastPairAccountKeyStorage.add(keys.get(3));
+ mFastPairAccountKeyStorage.add(keys.get(4));
+
+ List<AccountKey> returnedKeys = mFastPairAccountKeyStorage.getAllAccountKeys();
+ assertThat(returnedKeys).isEqualTo(keys);
+ }
+
+ @Test
+ public void testLoadWhileUserLocked_loadFails() {
+ mFastPairAccountKeyStorage = new FastPairAccountKeyStorage(mMockContext, TEST_SIZE);
+
+ List<AccountKey> persistedKeys = new ArrayList<AccountKey>(List.of(
+ new AccountKey(TEST_ACCOUNT_KEY_1),
+ new AccountKey(TEST_ACCOUNT_KEY_2),
+ new AccountKey(TEST_ACCOUNT_KEY_3)));
+ setPersistedKeys(persistedKeys);
+ setUserUnlocked(false);
+ mFastPairAccountKeyStorage.load();
+
+ assertThat(mFastPairAccountKeyStorage.getAllAccountKeys()).isNotNull();
+ assertThat(mFastPairAccountKeyStorage.getAllAccountKeys()).isEmpty();
+ assertPersistedKeys(persistedKeys);
+ }
+
+ @Test
+ public void testLoadWhileUserUnlocked_loadSucceeds() {
+ mFastPairAccountKeyStorage = new FastPairAccountKeyStorage(mMockContext, TEST_SIZE);
+
+ ArrayList<AccountKey> expectedKeys = new ArrayList<AccountKey>(List.of(
+ new AccountKey(TEST_ACCOUNT_KEY_1),
+ new AccountKey(TEST_ACCOUNT_KEY_2),
+ new AccountKey(TEST_ACCOUNT_KEY_3)));
+ setPersistedKeys(expectedKeys);
+ setUserUnlocked(true);
+ mFastPairAccountKeyStorage.load();
+
+ assertThat(mFastPairAccountKeyStorage.getAllAccountKeys()).isEqualTo(expectedKeys);
+ assertPersistedKeys(expectedKeys);
+ }
+
+ @Test
+ public void testCommitWhileUserLocked_commitFails() {
+ mFastPairAccountKeyStorage = new FastPairAccountKeyStorage(mMockContext, TEST_SIZE);
+
+ setUserUnlocked(false);
+ mFastPairAccountKeyStorage.add(new AccountKey(TEST_ACCOUNT_KEY_1));
+
+ assertPersistedKeys(new ArrayList<AccountKey>());
+ verifyNoMoreInteractions(mMockSharedPreferences);
+ verifyNoMoreInteractions(mMockSharedPreferencesEditor);
+ }
+
+ @Test
+ public void testCommitWhileUserUnlocked_commitSucceeds() {
+ mFastPairAccountKeyStorage = new FastPairAccountKeyStorage(mMockContext, TEST_SIZE);
+
+ setUserUnlocked(true);
+ mFastPairAccountKeyStorage.add(new AccountKey(TEST_ACCOUNT_KEY_1));
+ mFastPairAccountKeyStorage.add(new AccountKey(TEST_ACCOUNT_KEY_2));
+ mFastPairAccountKeyStorage.add(new AccountKey(TEST_ACCOUNT_KEY_3));
+
+ ArrayList<AccountKey> expectedKeys = new ArrayList<AccountKey>(List.of(
+ new AccountKey(TEST_ACCOUNT_KEY_1),
+ new AccountKey(TEST_ACCOUNT_KEY_2),
+ new AccountKey(TEST_ACCOUNT_KEY_3)));
+ assertThat(mFastPairAccountKeyStorage.getAllAccountKeys()).isEqualTo(expectedKeys);
+ assertPersistedKeys(expectedKeys);
+ }
+
+ @Test
+ public void testToString_isNotNull() {
+ mFastPairAccountKeyStorage = new FastPairAccountKeyStorage(mMockContext, TEST_SIZE);
+ assertThat(mFastPairAccountKeyStorage.toString()).isNotNull();
+ }
+}
diff --git a/tests/carservice_unit_test/src/com/android/car/bluetooth/FastPairAdvertiserTest.java b/tests/carservice_unit_test/src/com/android/car/bluetooth/FastPairAdvertiserTest.java
new file mode 100644
index 0000000..3732610
--- /dev/null
+++ b/tests/carservice_unit_test/src/com/android/car/bluetooth/FastPairAdvertiserTest.java
@@ -0,0 +1,604 @@
+/*
+ * Copyright (C) 2022 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.bluetooth;
+
+import static android.car.test.mocks.AndroidMockitoHelper.mockCarGetPlatformVersion;
+
+import static com.android.car.bluetooth.FastPairAccountKeyStorage.AccountKey;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.staticMockMarker;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.after;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.clearInvocations;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.timeout;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothManager;
+import android.bluetooth.le.AdvertiseData;
+import android.bluetooth.le.AdvertisingSet;
+import android.bluetooth.le.AdvertisingSetCallback;
+import android.bluetooth.le.AdvertisingSetParameters;
+import android.bluetooth.le.BluetoothLeAdvertiser;
+import android.car.Car;
+import android.car.PlatformVersion;
+import android.car.builtin.bluetooth.le.AdvertisingSetCallbackHelper;
+import android.car.builtin.bluetooth.le.AdvertisingSetHelper;
+import android.content.Context;
+import android.os.Looper;
+import android.os.ParcelUuid;
+
+import com.android.dx.mockito.inline.extended.ExtendedMockito;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.mockito.MockitoSession;
+import org.mockito.junit.MockitoJUnitRunner;
+import org.mockito.quality.Strictness;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Unit tests for {@link FastPairAdvertiser}
+ *
+ * Run: atest FastPairAdvertiserTest
+ */
+@RunWith(MockitoJUnitRunner.class)
+public class FastPairAdvertiserTest {
+ public static final ParcelUuid SERVICE_UUID = ParcelUuid
+ .fromString("0000FE2C-0000-1000-8000-00805f9b34fb");
+
+ private static final int TEST_MODEL_ID = 0x112233;
+ private static final byte[] TEST_MODEL_ID_DATA = new byte[]{0x11, 0x22, 0x33};
+ private static final int MODEL_ID_ADVERTISING_INTERVAL =
+ AdvertisingSetParameters.INTERVAL_LOW;
+
+ private static final byte[] TEST_ACCOUNT_KEY_1 = new byte[]{0x11, 0x22, 0x33, 0x44, 0x55, 0x66,
+ 0x77, (byte) 0x88, (byte) 0x99, 0x00, (byte) 0xAA, (byte) 0xBB, (byte) 0xCC,
+ (byte) 0xDD, (byte) 0xEE, (byte) 0xFF};
+ private static final byte[] TEST_ACCOUNT_KEY_2 = new byte[]{0x11, 0x11, 0x22, 0x22, 0x33, 0x33,
+ 0x44, 0x44, 0x55, 0x55, 0x66, 0x66, 0x77, 0x77, (byte) 0x88, (byte) 0x88};
+ private static final List<AccountKey> TEST_ACCOUNT_KEYS = new ArrayList<AccountKey>(List.of(
+ new AccountKey(TEST_ACCOUNT_KEY_1),
+ new AccountKey(TEST_ACCOUNT_KEY_2)
+ ));
+ private static final List<AccountKey> TEST_EMPTY_ACCOUNT_KEYS = new ArrayList<>();
+
+ static final byte TEST_SALT = (byte) 0x00;
+ private static final byte[] TEST_ACCOUNT_KEY_FILTER_DATA_NO_KEYS = new byte[]{0x00, 0x00};
+ private static final int TEST_ACCOUNT_KEY_FILTER_DATA_WITH_KEYS_LENGTH = 9;
+ private static final byte TEST_ACCOUNT_KEY_FILTER_ADVERTISEMENT_RESERVED_BYTE = 0x00;
+ private static final byte TEST_ACCOUNT_KEY_FILTER_ADVERTISEMENT_FILTER_FLAGS_BYTE = (byte) 0x50;
+ private static final byte[] TEST_ACCOUNT_KEY_FILTER_ADVERTISEMENT_WITH_KEYS_FILTER_BYTES =
+ new byte[]{(byte) 0xC3, 0x15, 0x22, 0x08, 0x3A};
+ private static final byte TEST_ACCOUNT_KEY_FILTER_ADVERTISEMENT_SALT_FLAGS_BYTE = 0x11;
+ private static final int ACCOUNT_KEY_FILTER_ADVERTISING_INTERVAL =
+ AdvertisingSetParameters.INTERVAL_MEDIUM;
+
+ private static final int ADVERTISING_EVENT_SETTLE_MS = 3000;
+ private static final int ADVERTISING_EVENT_TIMEOUT_MS = 4500;
+ private static final int ADVERTISING_STATE_CHANGE_MS = 150;
+
+ MockitoSession mMockitoSession;
+
+ @Mock Context mMockContext;
+ @Mock BluetoothAdapter mMockBluetoothAdapter;
+ @Mock BluetoothManager mMockBluetoothManager;
+ @Mock BluetoothDevice mMockBluetoothDevice;
+ @Mock BluetoothLeAdvertiser mMockBluetoothLeAdvertiser;
+ @Mock AdvertisingSet mMockAdvertisingSet;
+
+ @Captor ArgumentCaptor<AdvertisingSetCallback> mAdvertisingSetCallbackCaptor;
+ @Captor ArgumentCaptor<AdvertisingSetParameters> mAdvertisingSetParametersCaptor;
+ @Captor ArgumentCaptor<AdvertiseData> mAdvertiseDataCaptor;
+
+ private FastPairAdvertiser mFastPairAdvertiser;
+ private final FastPairAdvertiser.Callbacks mCallback = new FastPairAdvertiser.Callbacks() {
+ @Override
+ public void onRpaUpdated(BluetoothDevice device) {
+ // TODO(196233989): Add tests for this when the API becomes available and the code can
+ // be uncommented.
+ }
+ };
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+
+ when(mMockContext.getSystemService(BluetoothManager.class))
+ .thenReturn(mMockBluetoothManager);
+ when(mMockBluetoothManager.getAdapter()).thenReturn(mMockBluetoothAdapter);
+ when(mMockBluetoothAdapter.getBluetoothLeAdvertiser())
+ .thenReturn(mMockBluetoothLeAdvertiser);
+
+ when(mMockBluetoothAdapter.getRemoteDevice(any(String.class)))
+ .thenReturn(mMockBluetoothDevice);
+ when(mMockBluetoothAdapter.getRemoteDevice(any(byte[].class)))
+ .thenReturn(mMockBluetoothDevice);
+
+ mAdvertisingSetCallbackCaptor = ArgumentCaptor.forClass(AdvertisingSetCallback.class);
+ mAdvertiseDataCaptor = ArgumentCaptor.forClass(AdvertiseData.class);
+ mAdvertisingSetParametersCaptor = ArgumentCaptor.forClass(AdvertisingSetParameters.class);
+
+ mMockitoSession = ExtendedMockito.mockitoSession()
+ .strictness(Strictness.WARN)
+ .spyStatic(BluetoothAdapter.class)
+ .spyStatic(Car.class)
+ .spyStatic(AdvertisingSetCallbackHelper.class)
+ .spyStatic(AdvertisingSetHelper.class)
+ .startMocking();
+
+ Looper looper = Looper.myLooper();
+ if (looper == null) {
+ Looper.prepare();
+ }
+
+ mFastPairAdvertiser = new FastPairAdvertiser(mMockContext);
+ }
+
+ @After
+ public void tearDown() {
+ mMockitoSession.finishMocking();
+ }
+
+ private void waitForAdvertisingHandlerToSettle() {
+ // TODO (243518804): Remove the need for this by adding a way to wait on state transitions
+ try {
+ Thread.sleep(ADVERTISING_EVENT_SETTLE_MS);
+ } catch (InterruptedException e) {
+ // pass
+ }
+ }
+
+ private void waitForAdvertisingHandlerStateChange() {
+ // TODO (243518804): Remove the need for this by adding a way to wait on state transitions
+ try {
+ Thread.sleep(ADVERTISING_STATE_CHANGE_MS);
+ } catch (InterruptedException e) {
+ // pass
+ }
+ }
+
+ private void assertAdvertisingParameters(AdvertisingSetParameters params, int interval) {
+ assertThat(params.isLegacy()).isTrue();
+ assertThat(params.isScannable()).isTrue();
+ assertThat(params.isConnectable()).isTrue();
+ assertThat(params.getInterval()).isEqualTo(interval);
+ }
+
+ private void assertAdvertisingData(AdvertiseData actual, byte[] data) {
+ AdvertiseData expected = new AdvertiseData.Builder()
+ .addServiceUuid(SERVICE_UUID)
+ .addServiceData(SERVICE_UUID, data)
+ .setIncludeTxPowerLevel(true)
+ .build();
+ assertThat(actual).isEqualTo(expected);
+ }
+
+ @Test
+ public void testAdvertiseModelIdFromStopped_advertisingSucceeds() {
+ mFastPairAdvertiser.advertiseModelId(TEST_MODEL_ID, mCallback);
+
+ verify(mMockBluetoothLeAdvertiser, timeout(ADVERTISING_EVENT_SETTLE_MS))
+ .startAdvertisingSet(mAdvertisingSetParametersCaptor.capture(),
+ mAdvertiseDataCaptor.capture(), any(), any(), any(),
+ mAdvertisingSetCallbackCaptor.capture());
+
+ waitForAdvertisingHandlerStateChange();
+ assertThat(mFastPairAdvertiser.getAdvertisingState())
+ .isEqualTo(FastPairAdvertiser.STATE_STARTING);
+
+ mAdvertisingSetCallbackCaptor.getValue().onAdvertisingSetStarted(mMockAdvertisingSet,
+ mAdvertisingSetParametersCaptor.getValue().getTxPowerLevel(),
+ AdvertisingSetCallback.ADVERTISE_SUCCESS);
+ waitForAdvertisingHandlerToSettle();
+
+ assertThat(mFastPairAdvertiser.getAdvertisingState())
+ .isEqualTo(FastPairAdvertiser.STATE_STARTED);
+ assertThat(mFastPairAdvertiser.isAdvertising()).isTrue();
+ assertAdvertisingParameters(mAdvertisingSetParametersCaptor.getValue(),
+ MODEL_ID_ADVERTISING_INTERVAL);
+ assertAdvertisingData(mAdvertiseDataCaptor.getValue(), TEST_MODEL_ID_DATA);
+ }
+
+ @Test
+ public void testAdvertiseModelIdWhileStarted_doNothing() {
+ testAdvertiseModelIdFromStopped_advertisingSucceeds();
+ clearInvocations(mMockBluetoothLeAdvertiser);
+ mFastPairAdvertiser.advertiseModelId(TEST_MODEL_ID, mCallback);
+ verify(mMockBluetoothLeAdvertiser, after(ADVERTISING_EVENT_SETTLE_MS).never())
+ .startAdvertisingSet(any(), any(), any(), any(), any(), any());
+ verify(mMockBluetoothLeAdvertiser, never()).stopAdvertisingSet(any());
+ waitForAdvertisingHandlerStateChange();
+ assertThat(mFastPairAdvertiser.getAdvertisingState())
+ .isEqualTo(FastPairAdvertiser.STATE_STARTED);
+ assertThat(mFastPairAdvertiser.isAdvertising()).isTrue();
+ }
+
+ @Test
+ public void testAdvertiseAccountKeyFilterNoKeys_advertisingSucceeds() {
+ mFastPairAdvertiser.advertiseAccountKeys(TEST_EMPTY_ACCOUNT_KEYS, mCallback);
+
+ verify(mMockBluetoothLeAdvertiser, timeout(ADVERTISING_EVENT_SETTLE_MS))
+ .startAdvertisingSet(mAdvertisingSetParametersCaptor.capture(),
+ mAdvertiseDataCaptor.capture(), any(), any(), any(),
+ mAdvertisingSetCallbackCaptor.capture());
+
+ mAdvertisingSetCallbackCaptor.getValue().onAdvertisingSetStarted(mMockAdvertisingSet,
+ mAdvertisingSetParametersCaptor.getValue().getTxPowerLevel(),
+ AdvertisingSetCallback.ADVERTISE_SUCCESS);
+ waitForAdvertisingHandlerToSettle();
+
+ assertThat(mFastPairAdvertiser.getAdvertisingState())
+ .isEqualTo(FastPairAdvertiser.STATE_STARTED);
+ assertThat(mFastPairAdvertiser.isAdvertising()).isTrue();
+ assertAdvertisingParameters(mAdvertisingSetParametersCaptor.getValue(),
+ ACCOUNT_KEY_FILTER_ADVERTISING_INTERVAL);
+ assertAdvertisingData(mAdvertiseDataCaptor.getValue(),
+ TEST_ACCOUNT_KEY_FILTER_DATA_NO_KEYS);
+ }
+
+ @Test
+ public void testCreateAccountKeyFilterWithKeys_returnsBytes() {
+ byte[] filter = mFastPairAdvertiser.getAccountKeyFilter(TEST_ACCOUNT_KEYS, TEST_SALT);
+ assertThat(filter).isEqualTo(TEST_ACCOUNT_KEY_FILTER_ADVERTISEMENT_WITH_KEYS_FILTER_BYTES);
+ }
+
+ @Test
+ public void testCreateAccountKeyFilterNoKeys_returnsNull() {
+ byte[] filter = mFastPairAdvertiser.getAccountKeyFilter(TEST_EMPTY_ACCOUNT_KEYS, TEST_SALT);
+ assertThat(filter).isEqualTo(null);
+ }
+
+ @Test
+ public void testCreateAccountKeyFilterNullKeys_returnsNull() {
+ byte[] filter = mFastPairAdvertiser.getAccountKeyFilter(null, TEST_SALT);
+ assertThat(filter).isEqualTo(null);
+ }
+
+ @Test
+ public void testAdvertiseAccountKeyFilterWithKeys_advertisingSucceeds() {
+ mFastPairAdvertiser.advertiseAccountKeys(TEST_ACCOUNT_KEYS, mCallback);
+
+ verify(mMockBluetoothLeAdvertiser, timeout(ADVERTISING_EVENT_SETTLE_MS))
+ .startAdvertisingSet(mAdvertisingSetParametersCaptor.capture(),
+ mAdvertiseDataCaptor.capture(), any(), any(), any(),
+ mAdvertisingSetCallbackCaptor.capture());
+
+ waitForAdvertisingHandlerStateChange();
+ assertThat(mFastPairAdvertiser.getAdvertisingState())
+ .isEqualTo(FastPairAdvertiser.STATE_STARTING);
+
+ mAdvertisingSetCallbackCaptor.getValue().onAdvertisingSetStarted(mMockAdvertisingSet,
+ mAdvertisingSetParametersCaptor.getValue().getTxPowerLevel(),
+ AdvertisingSetCallback.ADVERTISE_SUCCESS);
+ waitForAdvertisingHandlerToSettle();
+
+ assertThat(mFastPairAdvertiser.getAdvertisingState())
+ .isEqualTo(FastPairAdvertiser.STATE_STARTED);
+ assertThat(mFastPairAdvertiser.isAdvertising()).isTrue();
+ assertAdvertisingParameters(mAdvertisingSetParametersCaptor.getValue(),
+ ACCOUNT_KEY_FILTER_ADVERTISING_INTERVAL);
+ AdvertiseData actual = mAdvertiseDataCaptor.getValue();
+
+ // The filter created relies on the salt used, which is random. We cannot mock that, so
+ // instead we'll check the other parts of the packet that matter and test the filter
+ // creation itself in other tests
+ assertThat(actual).isNotNull();
+ Map<ParcelUuid, byte[]> actualServiceData = actual.getServiceData();
+ assertThat(actualServiceData).isNotNull();
+ byte[] actualData = actualServiceData.get(SERVICE_UUID);
+
+ int actualSize = actualData.length;
+ assertThat(actualData).isNotNull();
+ assertThat(actualSize).isEqualTo(TEST_ACCOUNT_KEY_FILTER_DATA_WITH_KEYS_LENGTH);
+ assertThat(actualData[0]).isEqualTo(TEST_ACCOUNT_KEY_FILTER_ADVERTISEMENT_RESERVED_BYTE);
+ assertThat(actualData[1])
+ .isEqualTo(TEST_ACCOUNT_KEY_FILTER_ADVERTISEMENT_FILTER_FLAGS_BYTE);
+ assertThat(actualData[actualSize - 2])
+ .isEqualTo(TEST_ACCOUNT_KEY_FILTER_ADVERTISEMENT_SALT_FLAGS_BYTE);
+ byte salt = actualData[actualSize - 1];
+ byte[] filter = mFastPairAdvertiser.getAccountKeyFilter(TEST_ACCOUNT_KEYS, salt);
+ assertThat(Arrays.copyOfRange(actualData, 2, 7)).isEqualTo(filter);
+ }
+
+ @Test
+ public void testAdvertiseAccountKeyFilterWhileStarted_doNothing() {
+ testAdvertiseModelIdFromStopped_advertisingSucceeds();
+ clearInvocations(mMockBluetoothLeAdvertiser);
+ mFastPairAdvertiser.advertiseAccountKeys(TEST_ACCOUNT_KEYS, mCallback);
+ verify(mMockBluetoothLeAdvertiser, after(ADVERTISING_EVENT_SETTLE_MS).never())
+ .startAdvertisingSet(any(), any(), any(), any(), any(), any());
+ waitForAdvertisingHandlerStateChange();
+ assertThat(mFastPairAdvertiser.getAdvertisingState())
+ .isEqualTo(FastPairAdvertiser.STATE_STARTED);
+ assertThat(mFastPairAdvertiser.isAdvertising()).isTrue();
+ }
+
+ @Test
+ public void testAdvertiseNewDataWhileStarted_doNothing() {
+ testAdvertiseModelIdFromStopped_advertisingSucceeds();
+ clearInvocations(mMockBluetoothLeAdvertiser);
+ mFastPairAdvertiser.advertiseModelId(TEST_MODEL_ID, mCallback);
+ verify(mMockBluetoothLeAdvertiser, after(ADVERTISING_EVENT_SETTLE_MS).never())
+ .startAdvertisingSet(any(), any(), any(), any(), any(), any());
+ verify(mMockBluetoothLeAdvertiser, never()).stopAdvertisingSet(any());
+ waitForAdvertisingHandlerStateChange();
+ assertThat(mFastPairAdvertiser.getAdvertisingState())
+ .isEqualTo(FastPairAdvertiser.STATE_STARTED);
+ assertThat(mFastPairAdvertiser.isAdvertising()).isTrue();
+ }
+
+ @Test
+ public void testFailToGetAdvertiserOnStart_doesNotAdvertise() {
+ when(mMockBluetoothAdapter.getBluetoothLeAdvertiser()).thenReturn(null);
+ mFastPairAdvertiser.advertiseModelId(TEST_MODEL_ID, mCallback);
+ waitForAdvertisingHandlerToSettle();
+ assertThat(mFastPairAdvertiser.getAdvertisingState())
+ .isEqualTo(FastPairAdvertiser.STATE_STOPPED);
+ assertThat(mFastPairAdvertiser.isAdvertising()).isFalse();
+ }
+
+ @Test
+ public void testAdvertisingStartCallbackUnsuccessful_advertisingStops() {
+ mFastPairAdvertiser.advertiseModelId(TEST_MODEL_ID, mCallback);
+
+ verify(mMockBluetoothLeAdvertiser, timeout(ADVERTISING_EVENT_SETTLE_MS))
+ .startAdvertisingSet(mAdvertisingSetParametersCaptor.capture(),
+ mAdvertiseDataCaptor.capture(), any(), any(), any(),
+ mAdvertisingSetCallbackCaptor.capture());
+
+ waitForAdvertisingHandlerStateChange();
+ assertThat(mFastPairAdvertiser.getAdvertisingState())
+ .isEqualTo(FastPairAdvertiser.STATE_STARTING);
+
+ mAdvertisingSetCallbackCaptor.getValue().onAdvertisingSetStarted(mMockAdvertisingSet,
+ 0, AdvertisingSetCallback.ADVERTISE_FAILED_INTERNAL_ERROR);
+ waitForAdvertisingHandlerToSettle();
+
+ assertThat(mFastPairAdvertiser.getAdvertisingState())
+ .isEqualTo(FastPairAdvertiser.STATE_STOPPED);
+ assertThat(mFastPairAdvertiser.isAdvertising()).isFalse();
+ }
+
+ @Test
+ public void testAdvertisingStartCallbackNullSet_advertisingStops() {
+ mFastPairAdvertiser.advertiseModelId(TEST_MODEL_ID, mCallback);
+
+ verify(mMockBluetoothLeAdvertiser, timeout(ADVERTISING_EVENT_SETTLE_MS))
+ .startAdvertisingSet(mAdvertisingSetParametersCaptor.capture(),
+ mAdvertiseDataCaptor.capture(), any(), any(), any(),
+ mAdvertisingSetCallbackCaptor.capture());
+
+ waitForAdvertisingHandlerStateChange();
+ assertThat(mFastPairAdvertiser.getAdvertisingState())
+ .isEqualTo(FastPairAdvertiser.STATE_STARTING);
+
+ mAdvertisingSetCallbackCaptor.getValue().onAdvertisingSetStarted(null,
+ 0, AdvertisingSetCallback.ADVERTISE_SUCCESS);
+ waitForAdvertisingHandlerToSettle();
+
+ assertThat(mFastPairAdvertiser.getAdvertisingState())
+ .isEqualTo(FastPairAdvertiser.STATE_STOPPED);
+ assertThat(mFastPairAdvertiser.isAdvertising()).isFalse();
+ }
+
+ @Test
+ public void testAdvertisingStartTimeout_doesNotAdvertise() {
+ mFastPairAdvertiser.advertiseModelId(TEST_MODEL_ID, mCallback);
+ verify(mMockBluetoothLeAdvertiser, timeout(ADVERTISING_EVENT_SETTLE_MS))
+ .startAdvertisingSet(any(), any(), any(), any(), any(), any());
+ waitForAdvertisingHandlerStateChange();
+ assertThat(mFastPairAdvertiser.getAdvertisingState())
+ .isEqualTo(FastPairAdvertiser.STATE_STARTING);
+
+ verify(mMockBluetoothLeAdvertiser, timeout(ADVERTISING_EVENT_TIMEOUT_MS))
+ .stopAdvertisingSet(any());
+ waitForAdvertisingHandlerStateChange();
+ assertThat(mFastPairAdvertiser.getAdvertisingState())
+ .isEqualTo(FastPairAdvertiser.STATE_STOPPED);
+ assertThat(mFastPairAdvertiser.isAdvertising()).isFalse();
+ }
+
+ @Test
+ public void testStopAdvertising() {
+ testAdvertiseModelIdFromStopped_advertisingSucceeds();
+ clearInvocations(mMockBluetoothLeAdvertiser);
+ mFastPairAdvertiser.stopAdvertising();
+ verify(mMockBluetoothLeAdvertiser, timeout(ADVERTISING_EVENT_SETTLE_MS))
+ .stopAdvertisingSet(mAdvertisingSetCallbackCaptor.capture());
+ waitForAdvertisingHandlerStateChange();
+ assertThat(mFastPairAdvertiser.getAdvertisingState())
+ .isEqualTo(FastPairAdvertiser.STATE_STOPPING);
+ mAdvertisingSetCallbackCaptor.getValue().onAdvertisingSetStopped(mMockAdvertisingSet);
+ waitForAdvertisingHandlerToSettle();
+ assertThat(mFastPairAdvertiser.getAdvertisingState())
+ .isEqualTo(FastPairAdvertiser.STATE_STOPPED);
+ assertThat(mFastPairAdvertiser.isAdvertising()).isFalse();
+ }
+
+ @Test
+ public void testStopAdvertisingWhileStopped() {
+ testStopAdvertising();
+ clearInvocations(mMockBluetoothLeAdvertiser);
+ mFastPairAdvertiser.stopAdvertising();
+ waitForAdvertisingHandlerToSettle();
+ verify(mMockBluetoothLeAdvertiser, after(ADVERTISING_EVENT_SETTLE_MS).never())
+ .stopAdvertisingSet(any());
+ assertThat(mFastPairAdvertiser.isAdvertising()).isFalse();
+ }
+
+ @Test
+ public void testAdvertisingStartWhileStopping_startProcessed() {
+ testAdvertiseModelIdFromStopped_advertisingSucceeds();
+ clearInvocations(mMockBluetoothLeAdvertiser);
+
+ mFastPairAdvertiser.stopAdvertising();
+ mFastPairAdvertiser.advertiseModelId(TEST_MODEL_ID, mCallback);
+
+ verify(mMockBluetoothLeAdvertiser, timeout(ADVERTISING_EVENT_SETTLE_MS))
+ .stopAdvertisingSet(mAdvertisingSetCallbackCaptor.capture());
+ waitForAdvertisingHandlerStateChange();
+ assertThat(mFastPairAdvertiser.getAdvertisingState())
+ .isEqualTo(FastPairAdvertiser.STATE_STOPPING);
+
+ mAdvertisingSetCallbackCaptor.getValue().onAdvertisingSetStopped(mMockAdvertisingSet);
+
+ verify(mMockBluetoothLeAdvertiser, timeout(ADVERTISING_EVENT_SETTLE_MS))
+ .startAdvertisingSet(mAdvertisingSetParametersCaptor.capture(),
+ mAdvertiseDataCaptor.capture(), any(), any(), any(),
+ mAdvertisingSetCallbackCaptor.capture());
+ }
+
+ @Test
+ public void testAdvertisingStopWhileStarting_stopProcessed() {
+ mFastPairAdvertiser.advertiseModelId(TEST_MODEL_ID, mCallback);
+
+ verify(mMockBluetoothLeAdvertiser, timeout(ADVERTISING_EVENT_SETTLE_MS))
+ .startAdvertisingSet(mAdvertisingSetParametersCaptor.capture(),
+ mAdvertiseDataCaptor.capture(), any(), any(), any(),
+ mAdvertisingSetCallbackCaptor.capture());
+
+ waitForAdvertisingHandlerStateChange();
+ assertThat(mFastPairAdvertiser.getAdvertisingState())
+ .isEqualTo(FastPairAdvertiser.STATE_STARTING);
+
+ mFastPairAdvertiser.stopAdvertising();
+
+ mAdvertisingSetCallbackCaptor.getValue().onAdvertisingSetStarted(mMockAdvertisingSet,
+ mAdvertisingSetParametersCaptor.getValue().getTxPowerLevel(),
+ AdvertisingSetCallback.ADVERTISE_SUCCESS);
+
+ verify(mMockBluetoothLeAdvertiser, timeout(ADVERTISING_EVENT_SETTLE_MS))
+ .stopAdvertisingSet(any());
+ }
+
+ @Test
+ public void testAdvertisingStartWhileStoppingTimeout_startProcessed() {
+ testAdvertiseModelIdFromStopped_advertisingSucceeds();
+ clearInvocations(mMockBluetoothLeAdvertiser);
+
+ mFastPairAdvertiser.stopAdvertising();
+ mFastPairAdvertiser.advertiseModelId(TEST_MODEL_ID, mCallback);
+
+ verify(mMockBluetoothLeAdvertiser, timeout(ADVERTISING_EVENT_SETTLE_MS))
+ .stopAdvertisingSet(mAdvertisingSetCallbackCaptor.capture());
+ waitForAdvertisingHandlerStateChange();
+ assertThat(mFastPairAdvertiser.getAdvertisingState())
+ .isEqualTo(FastPairAdvertiser.STATE_STOPPING);
+
+ verify(mMockBluetoothLeAdvertiser, timeout(ADVERTISING_EVENT_TIMEOUT_MS))
+ .startAdvertisingSet(mAdvertisingSetParametersCaptor.capture(),
+ mAdvertiseDataCaptor.capture(), any(), any(), any(),
+ mAdvertisingSetCallbackCaptor.capture());
+ }
+
+ @Test
+ public void testAdvertisingStopWhileStartingTimeout_stopProcessed() {
+ mFastPairAdvertiser.advertiseModelId(TEST_MODEL_ID, mCallback);
+
+ verify(mMockBluetoothLeAdvertiser, timeout(ADVERTISING_EVENT_SETTLE_MS))
+ .startAdvertisingSet(mAdvertisingSetParametersCaptor.capture(),
+ mAdvertiseDataCaptor.capture(), any(), any(), any(),
+ mAdvertisingSetCallbackCaptor.capture());
+ waitForAdvertisingHandlerStateChange();
+ assertThat(mFastPairAdvertiser.getAdvertisingState())
+ .isEqualTo(FastPairAdvertiser.STATE_STARTING);
+
+ mFastPairAdvertiser.stopAdvertising();
+
+ verify(mMockBluetoothLeAdvertiser, timeout(ADVERTISING_EVENT_TIMEOUT_MS))
+ .stopAdvertisingSet(any());
+ }
+
+ @Test
+ public void testAdvertisingStopTimeoutNothingQueue_advertisingStateStopped() {
+ testAdvertiseModelIdFromStopped_advertisingSucceeds();
+ clearInvocations(mMockBluetoothLeAdvertiser);
+
+ mFastPairAdvertiser.stopAdvertising();
+ verify(mMockBluetoothLeAdvertiser, timeout(ADVERTISING_EVENT_SETTLE_MS))
+ .stopAdvertisingSet(mAdvertisingSetCallbackCaptor.capture());
+ waitForAdvertisingHandlerStateChange();
+ assertThat(mFastPairAdvertiser.getAdvertisingState())
+ .isEqualTo(FastPairAdvertiser.STATE_STOPPING);
+ clearInvocations(mMockBluetoothLeAdvertiser);
+
+ verify(mMockBluetoothLeAdvertiser, after(ADVERTISING_EVENT_TIMEOUT_MS).never())
+ .stopAdvertisingSet(any());
+ verify(mMockBluetoothLeAdvertiser, never())
+ .startAdvertisingSet(any(), any(), any(), any(), any(), any());
+ assertThat(mFastPairAdvertiser.getAdvertisingState())
+ .isEqualTo(FastPairAdvertiser.STATE_STOPPED);
+ }
+
+ /**
+ * {@link AdvertisingSetCallbackHelper} and {@link AdvertisingSetHelper} were introduced in
+ * TM-QPR-1 (maj=33, min=1) to help with {@link FastPairAdvertiser} hidden API usages. A
+ * version check was added to the constructor of {@link FastPairAdvertiser} to ensure backwards
+ * compatibility with respect to the availability of these helper classes. One way to test
+ * which branch the check took is to check whether
+ * {@link AdvertisingSetCallbackHelper#createRealCallbackFromProxy} was invoked or not.
+ */
+ @Test
+ public void testFPAdvertiserBackCompat_tiramisu1_createRealCallbackFromProxyInvoked() {
+ mockCarGetPlatformVersion(PlatformVersion.VERSION_CODES.TIRAMISU_1);
+ // reset invocation count
+ clearInvocations(staticMockMarker(AdvertisingSetCallbackHelper.class));
+
+ // version check lies in constructor
+ new FastPairAdvertiser(mMockContext);
+
+ verify(() -> AdvertisingSetCallbackHelper.createRealCallbackFromProxy(any()));
+ }
+
+ /**
+ * {@link AdvertisingSetCallbackHelper} and {@link AdvertisingSetHelper} were introduced in
+ * TM-QPR-1 (maj=33, min=1) to help with {@link FastPairAdvertiser} hidden API usages. A
+ * version check was added to the constructor of {@link FastPairAdvertiser} to ensure backwards
+ * compatibility with respect to the availability of these helper classes. One way to test
+ * which branch the check took is to check whether
+ * {@link AdvertisingSetCallbackHelper#createRealCallbackFromProxy} was invoked or not.
+ */
+ @Test
+ public void testFPAdvertiserBackCompat_tiramisu0_createRealCallbackFromProxyNotInvoked() {
+ mockCarGetPlatformVersion(PlatformVersion.VERSION_CODES.TIRAMISU_0);
+ // reset invocation count
+ clearInvocations(staticMockMarker(AdvertisingSetCallbackHelper.class));
+
+ // version check lies in constructor
+ new FastPairAdvertiser(mMockContext);
+
+ verify(() -> AdvertisingSetCallbackHelper.createRealCallbackFromProxy(any()), never());
+ }
+}
diff --git a/tests/carservice_unit_test/src/com/android/car/bluetooth/FastPairGattServerTest.java b/tests/carservice_unit_test/src/com/android/car/bluetooth/FastPairGattServerTest.java
new file mode 100644
index 0000000..5ff7549
--- /dev/null
+++ b/tests/carservice_unit_test/src/com/android/car/bluetooth/FastPairGattServerTest.java
@@ -0,0 +1,818 @@
+/*
+ * Copyright (C) 2022 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.bluetooth;
+
+import static com.android.car.bluetooth.FastPairAccountKeyStorage.AccountKey;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.anyBoolean;
+import static org.mockito.Mockito.anyInt;
+import static org.mockito.Mockito.clearInvocations;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.when;
+
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothGatt;
+import android.bluetooth.BluetoothGattCharacteristic;
+import android.bluetooth.BluetoothGattDescriptor;
+import android.bluetooth.BluetoothGattServer;
+import android.bluetooth.BluetoothGattServerCallback;
+import android.bluetooth.BluetoothGattService;
+import android.bluetooth.BluetoothManager;
+import android.bluetooth.BluetoothProfile;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Looper;
+import android.os.ParcelUuid;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.RequiresDevice;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.mockito.junit.MockitoJUnitRunner;
+
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Base64;
+import java.util.List;
+import java.util.Locale;
+
+import javax.crypto.Cipher;
+import javax.crypto.spec.SecretKeySpec;
+
+/**
+ * Unit tests for {@link FastPairGattServer}
+ *
+ * Run: atest FastPairGattServerTest
+ */
+@RequiresDevice
+@RunWith(MockitoJUnitRunner.class)
+public class FastPairGattServerTest {
+
+ static final ParcelUuid FAST_PAIR_SERVICE_UUID = ParcelUuid
+ .fromString("0000FE2C-0000-1000-8000-00805f9b34fb");
+ static final ParcelUuid FAST_PAIR_MODEL_ID_UUID = ParcelUuid
+ .fromString("FE2C1233-8366-4814-8EB0-01DE32100BEA");
+ static final ParcelUuid KEY_BASED_PAIRING_UUID = ParcelUuid
+ .fromString("FE2C1234-8366-4814-8EB0-01DE32100BEA");
+ static final ParcelUuid PASSKEY_UUID = ParcelUuid
+ .fromString("FE2C1235-8366-4814-8EB0-01DE32100BEA");
+ static final ParcelUuid ACCOUNT_KEY_UUID = ParcelUuid
+ .fromString("FE2C1236-8366-4814-8EB0-01DE32100BEA");
+ static final ParcelUuid CLIENT_CHARACTERISTIC_CONFIG = ParcelUuid
+ .fromString("00002902-0000-1000-8000-00805f9b34fb");
+ static final ParcelUuid DEVICE_NAME_CHARACTERISTIC_CONFIG = ParcelUuid
+ .fromString("00002A00-0000-1000-8000-00805f9b34fb");
+
+ // Model ID Configuration
+ static final int TEST_MODEL_ID = 4386;
+ static final byte[] TEST_MODEL_ID_BYTES = {0x22, 0x11, 0x00};
+
+ // Public/Private Key Pair Configuration and Expected Generated Keys
+ static final byte[] TEST_PUBLIC_KEY_A = {0x36, (byte) 0xAC, 0x68, 0x2C, 0x50, (byte) 0x82, 0x15,
+ 0x66, (byte) 0x8F, (byte) 0xBE, (byte) 0xFE, 0x24, 0x7D, 0x01, (byte) 0xD5, (byte) 0xEB,
+ (byte) 0x96, (byte) 0xE6, 0x31, (byte) 0x8E, (byte) 0x85, 0x5B, 0x2D, 0x64, (byte) 0xB5,
+ 0x19, 0x5D, 0x38, (byte) 0xEE, 0x7E, 0x37, (byte) 0xBE, 0x18, 0x38, (byte) 0xC0,
+ (byte) 0xB9, 0x48, (byte) 0xC3, (byte) 0xF7, 0x55, 0x20, (byte) 0xE0, 0x7E, 0x70,
+ (byte) 0xF0, 0x72, (byte) 0x91, 0x41, (byte) 0x9A, (byte) 0xCE, 0x2D, 0x28, 0x14, 0x3C,
+ 0x5A, (byte) 0xDB, 0x2D, (byte) 0xBD, (byte) 0x98, (byte) 0xEE, 0x3C, (byte) 0x8E, 0x4F,
+ (byte) 0xBF};
+ static final byte[] TEST_PRIVATE_KEY_B = {0x02, (byte) 0xB4, 0x37, (byte) 0xB0, (byte) 0xED,
+ (byte) 0xD6, (byte) 0xBB, (byte) 0xD4, 0x29, 0x06, 0x4A, 0x4E, 0x52, (byte) 0x9F,
+ (byte) 0xCB, (byte) 0xF1, (byte) 0xC4, (byte) 0x8D, 0x0D, 0x62, 0x49, 0x24, (byte) 0xD5,
+ (byte) 0x92, 0x27, 0x4B, 0x7E, (byte) 0xD8, 0x11, (byte) 0x93, (byte) 0xD7, 0x63
+ };
+ static final String TEST_PRIVATE_KEY_B_BASE64 = Base64.getEncoder()
+ .encodeToString(TEST_PRIVATE_KEY_B);
+ static final byte[] TEST_GENERATED_KEY = {(byte) 0xB0, 0x7F, 0x1F, 0x17, (byte) 0xC2, 0x36,
+ (byte) 0xCB, (byte) 0xD3, 0x35, 0x23, (byte) 0xC5, 0x15, (byte) 0xF3, 0x50, (byte) 0xAE,
+ 0x57};
+ static final byte[] TEST_WRONG_GENERATED_KEY = {(byte) 0x00, 0x7F, 0x1F, 0x17, (byte) 0x00,
+ 0x36, (byte) 0xCB, (byte) 0xD3, 0x35, 0x23, (byte) 0xC5, 0x15, (byte) 0xF3, 0x50,
+ (byte) 0xAE, 0x57};
+ static final byte[] TEST_SHARED_SECRET = {(byte) 0xA0, (byte) 0xBA, (byte) 0xF0, (byte) 0xBB,
+ (byte) 0x95, 0x1F, (byte) 0xF7, (byte) 0xB6, (byte) 0xCF, 0x5E, 0x3F, 0x45, 0x61,
+ (byte) 0xC3, 0x32, 0x1D};
+
+ static final String TEST_DEVICE_ADDRESS_STRING = "00:11:22:33:FF:EE";
+ static final byte[] TEST_DEVICE_ADDRESS_BYTES =
+ new byte[]{0x00, 0x11, 0x22, 0x33, (byte) 0xFF, (byte) 0xEE};
+ static final String TEST_RPA_STRING = "11:22:33:44:55:66";
+ static final byte[] TEST_RPA_BYTES = new byte[]{0x11, 0x22, 0x33, 0x44, 0x55, 0x66};
+ static final String TEST_DEVICE_NAME = "name";
+ static final String TEST_DEVICE_NAME_2 = "name2";
+
+ static final String TEST_REMOTE_ADDRESS_STRING = "66:77:88:99:aa:bb";
+ static final byte[] TEST_REMOTE_ADDRESS_BYTES =
+ {0x66, 0x77, (byte) 0x88, (byte) 0x99, (byte) 0xAA, (byte) 0xBB};
+
+ static final byte KEY_BASED_PAIRING_REQUEST_MSG_TYPE = (byte) 0x00;
+ static final byte ACTION_REQUEST_MSG_TYPE = (byte) 0x10;
+ static final byte KEY_BASED_PAIRING_RESPONSE_MSG_TYPE = (byte) 0x01;
+ static final byte[] TEST_SALT_8 = new byte[]{0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77};
+
+ static final byte PASSKEY_REQUEST_SEEKER = (byte) 0x02;
+ static final byte PASSKEY_REQUEST_PROVIDER = (byte) 0x03;
+ static final int TEST_PAIRING_KEY = 66051;
+ static final byte[] TEST_PAIRING_KEY_BYTES = {0x01, 0x02, 0x03};
+ static final int TEST_WRONG_PAIRING_KEY = 263430;
+ static final byte[] TEST_WRONG_PAIRING_KEY_BYTES = {0x04, 0x05, 0x06};
+ static final byte[] TEST_SALT_12 =
+ new byte[]{0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x00, 0x11, 0x22, 0x33};
+
+ static final byte[] TEST_INVALID_ACCOUNT_KEY = new byte[]{0x11, 0x22, 0x33, 0x44, 0x55, 0x66,
+ 0x77, (byte) 0x88, (byte) 0x99, 0x00, (byte) 0xAA, (byte) 0xBB, (byte) 0xCC,
+ (byte) 0xDD, (byte) 0xEE, (byte) 0xFF};
+ static final byte[] TEST_VALID_ACCOUNT_KEY = new byte[]{0x04, 0x11, 0x22, 0x22, 0x33, 0x33,
+ 0x44, 0x44, 0x55, 0x55, 0x66, 0x66, 0x77, 0x77, (byte) 0x88, (byte) 0x88};
+
+ static final byte[] TEST_REQUEST_SHORT = new byte[]{0x11, 0x22, 0x33, 0x44};
+
+ static final int ASYNC_CALL_TIMEOUT_MILLIS = 200;
+
+ // GATT Service code requires BluetoothDevice.equals() calls, which cannot be mocked. We'll use
+ // real device objects from the device under test's BluetoothAdapter where equals() would be
+ // required instead
+ Context mTargetContext;
+ BluetoothAdapter mTargetBluetoothAdapter;
+
+ @Mock Context mMockContext;
+ @Mock BluetoothManager mMockBluetoothManager;
+ @Mock BluetoothAdapter mMockBluetoothAdapter;
+ @Mock BluetoothDevice mMockBluetoothDevice;
+ @Mock BluetoothGattServer mMockBluetoothGattServer;
+ @Mock BluetoothGattDescriptor mMockGattDescriptor;
+ @Mock FastPairGattServer.Callbacks mMockFastPairCallbacks;
+ @Mock FastPairAccountKeyStorage mMockFastPairAccountKeyStorage;
+
+ @Captor ArgumentCaptor<BroadcastReceiver> mBroadcastReceiverCaptor;
+ BroadcastReceiver mReceiver;
+
+ @Captor ArgumentCaptor<BluetoothGattServerCallback> mBluetoothGattServerCallbackCaptor;
+ BluetoothGattServerCallback mBluetoothGattServerCallback;
+
+ BluetoothGattService mBluetoothGattService;
+
+ @Captor ArgumentCaptor<byte[]> mBytesCaptor;
+
+ FastPairGattServer mTestGattServer;
+
+ BluetoothGattCharacteristic mModelIdCharacteristic;
+ BluetoothGattCharacteristic mKeyBasedPairingCharacteristic;
+ BluetoothGattCharacteristic mPasskeyCharacteristic;
+ BluetoothGattCharacteristic mAccountKeyCharacteristic;
+ BluetoothGattCharacteristic mDeviceNameCharacteristic;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+
+ mTargetContext = InstrumentationRegistry.getTargetContext();
+ BluetoothManager btManager = mTargetContext.getSystemService(BluetoothManager.class);
+ mTargetBluetoothAdapter = btManager.getAdapter();
+
+ when(mMockContext.getSystemService(BluetoothManager.class))
+ .thenReturn(mMockBluetoothManager);
+
+ when(mMockBluetoothManager.getAdapter()).thenReturn(mMockBluetoothAdapter);
+ when(mMockBluetoothManager.openGattServer(any(), any()))
+ .thenReturn(mMockBluetoothGattServer);
+
+ when(mMockBluetoothAdapter.getName()).thenReturn(TEST_DEVICE_NAME);
+ when(mMockBluetoothAdapter.getAddress()).thenReturn(TEST_DEVICE_ADDRESS_STRING);
+
+ doAnswer(invocation -> {
+ String address = (String) invocation.getArguments()[0];
+ return mTargetBluetoothAdapter.getRemoteDevice(address);
+ }).when(mMockBluetoothAdapter).getRemoteDevice(any(String.class));
+
+ doAnswer(invocation -> {
+ byte[] address = (byte[]) invocation.getArguments()[0];
+ if (address == null || address.length != 6) {
+ return null;
+ }
+ String addrStr = String.format(Locale.US, "%02X:%02X:%02X:%02X:%02X:%02X", address[0],
+ address[1], address[2], address[3], address[4], address[5]);
+ return mTargetBluetoothAdapter.getRemoteDevice(addrStr);
+ }).when(mMockBluetoothAdapter).getRemoteDevice(any(byte[].class));
+
+ doAnswer(invocation -> {
+ mBluetoothGattService = (BluetoothGattService) invocation.getArguments()[0];
+ return true;
+ }).when(mMockBluetoothGattServer).addService(any());
+
+ doAnswer(invocation -> {
+ mBluetoothGattService = null;
+ return true;
+ }).when(mMockBluetoothGattServer).removeService(any());
+
+ doAnswer(invocation -> {
+ return mBluetoothGattService;
+ }).when(mMockBluetoothGattServer).getService(any());
+
+ Looper looper = Looper.myLooper();
+ if (looper == null) {
+ Looper.prepare();
+ }
+
+ mBroadcastReceiverCaptor = ArgumentCaptor.forClass(BroadcastReceiver.class);
+ mBluetoothGattServerCallbackCaptor =
+ ArgumentCaptor.forClass(BluetoothGattServerCallback.class);
+ mBytesCaptor = ArgumentCaptor.forClass(byte[].class);
+
+ mTestGattServer = new FastPairGattServer(mMockContext, TEST_MODEL_ID,
+ TEST_PRIVATE_KEY_B_BASE64, mMockFastPairCallbacks, true,
+ mMockFastPairAccountKeyStorage);
+ }
+
+ private void setAvailableAccountKeys(List<AccountKey> keys) {
+ when(mMockFastPairAccountKeyStorage.getAllAccountKeys())
+ .thenReturn(new ArrayList<>(keys));
+ }
+
+ private void setCurrentRpa(String address) {
+ mTestGattServer.updateLocalRpa(mTargetBluetoothAdapter.getRemoteDevice(address));
+ }
+
+ private void setDeviceName(String name) {
+ assertThat(mReceiver).isNotNull();
+ assertThat(name).isNotNull();
+ Intent nameChange = new Intent(BluetoothAdapter.ACTION_LOCAL_NAME_CHANGED);
+ nameChange.putExtra(BluetoothAdapter.EXTRA_LOCAL_NAME, name);
+ mReceiver.onReceive(mMockContext, nameChange);
+ }
+
+ private void startAndVerifyServer() {
+ assertThat(mTestGattServer.isStarted()).isFalse();
+ mTestGattServer.start();
+
+ verify(mMockBluetoothManager)
+ .openGattServer(any(), mBluetoothGattServerCallbackCaptor.capture());
+ mBluetoothGattServerCallback = mBluetoothGattServerCallbackCaptor.getValue();
+
+ verify(mMockContext).registerReceiver(mBroadcastReceiverCaptor.capture(), any());
+ mReceiver = mBroadcastReceiverCaptor.getValue();
+ verify(mMockBluetoothGattServer).addService(eq(mBluetoothGattService));
+
+ assertThat(mBluetoothGattService).isNotNull();
+ assertThat(mBluetoothGattService.getUuid()).isEqualTo(FAST_PAIR_SERVICE_UUID.getUuid());
+
+ mModelIdCharacteristic =
+ mBluetoothGattService.getCharacteristic(FAST_PAIR_MODEL_ID_UUID.getUuid());
+ mKeyBasedPairingCharacteristic =
+ mBluetoothGattService.getCharacteristic(KEY_BASED_PAIRING_UUID.getUuid());
+ mPasskeyCharacteristic =
+ mBluetoothGattService.getCharacteristic(PASSKEY_UUID.getUuid());
+ mAccountKeyCharacteristic =
+ mBluetoothGattService.getCharacteristic(ACCOUNT_KEY_UUID.getUuid());
+ mDeviceNameCharacteristic =
+ mBluetoothGattService.getCharacteristic(
+ DEVICE_NAME_CHARACTERISTIC_CONFIG.getUuid());
+
+ assertThat(mModelIdCharacteristic).isNotNull();
+ assertThat(mKeyBasedPairingCharacteristic).isNotNull();
+ assertThat(mPasskeyCharacteristic).isNotNull();
+ assertThat(mAccountKeyCharacteristic).isNotNull();
+ assertThat(mDeviceNameCharacteristic).isNotNull();
+
+ assertThat(mTestGattServer.isStarted()).isTrue();
+ assertThat(mTestGattServer.isConnected()).isFalse();
+ clearInvocations(mMockContext);
+ }
+
+ private void connectDevice(BluetoothDevice device) {
+ assertThat(mBluetoothGattServerCallback).isNotNull();
+ mBluetoothGattServerCallback.onConnectionStateChange(device,
+ BluetoothGatt.GATT_SUCCESS, BluetoothProfile.STATE_CONNECTED);
+ }
+
+ private void disconnectDevice(BluetoothDevice device) {
+ assertThat(mBluetoothGattServerCallback).isNotNull();
+ mBluetoothGattServerCallback.onConnectionStateChange(device,
+ BluetoothGatt.GATT_SUCCESS, BluetoothProfile.STATE_DISCONNECTED);
+ }
+
+ private byte[] sendReadModelIdRequest(BluetoothDevice device) {
+ assertThat(mBluetoothGattServerCallback).isNotNull();
+ assertThat(mModelIdCharacteristic).isNotNull();
+ mBluetoothGattServerCallback.onCharacteristicReadRequest(device, 0, 0,
+ mModelIdCharacteristic);
+ verify(mMockBluetoothGattServer).sendResponse(eq(device), eq(0), anyInt(), anyInt(),
+ mBytesCaptor.capture());
+ return mBytesCaptor.getValue();
+ }
+
+ private byte[] sendReadDeviceNameRequest(BluetoothDevice device) {
+ assertThat(mBluetoothGattServerCallback).isNotNull();
+ assertThat(mDeviceNameCharacteristic).isNotNull();
+ mBluetoothGattServerCallback.onCharacteristicReadRequest(device, 0, 0,
+ mDeviceNameCharacteristic);
+ verify(mMockBluetoothGattServer).sendResponse(eq(device), eq(0), anyInt(), anyInt(),
+ mBytesCaptor.capture());
+ return mBytesCaptor.getValue();
+ }
+
+ private byte[] sendKeyBasedPairingRequest(BluetoothDevice device, byte[] value) {
+ assertThat(mBluetoothGattServerCallback).isNotNull();
+ assertThat(mKeyBasedPairingCharacteristic).isNotNull();
+ return sendCharacteristicWriteRequest(device, mKeyBasedPairingCharacteristic, value);
+ }
+
+ private byte[] buildKeyBasedPairingRequest(byte type, byte flags, byte[] provider,
+ byte[] seeker, byte[] salt, byte[] publicKey, byte[] key) {
+
+ // Make request and encrypt it
+ byte[] request = new byte[16];
+ request[0] = type;
+ request[1] = flags;
+
+ request[2] = provider[0];
+ request[3] = provider[1];
+ request[4] = provider[2];
+ request[5] = provider[3];
+ request[6] = provider[4];
+ request[7] = provider[5];
+
+ int start = 8;
+ if (seeker != null) {
+ request[8] = seeker[0];
+ request[9] = seeker[1];
+ request[10] = seeker[2];
+ request[11] = seeker[3];
+ request[12] = seeker[4];
+ request[13] = seeker[5];
+ start = 14;
+ }
+
+ for (int i = start; i < 16; i++) {
+ request[i] = salt[i - start];
+ }
+
+ byte[] encryptedRequest = encrypt(request, key);
+
+ if (publicKey != null) {
+ byte[] requestWithKey = new byte[80];
+ for (int i = 0; i < 16; i++) {
+ requestWithKey[i] = encryptedRequest[i];
+ }
+ for (int i = 16; i < 80; i++) {
+ requestWithKey[i] = publicKey[i - 16];
+ }
+ return requestWithKey;
+ }
+
+ return encryptedRequest;
+ }
+
+ private byte[] sendPasskeyRequest(BluetoothDevice device, byte[] value) {
+ assertThat(mBluetoothGattServerCallback).isNotNull();
+ assertThat(mPasskeyCharacteristic).isNotNull();
+ return sendCharacteristicWriteRequest(device, mPasskeyCharacteristic, value);
+ }
+
+ private byte[] buildPasskeyRequest(byte type, byte[] passkey, byte[] salt, byte[] key) {
+ byte[] request = new byte[16];
+ request[0] = type;
+ request[1] = passkey[0];
+ request[2] = passkey[1];
+ request[3] = passkey[2];
+
+ for (int i = 4; i < 16; i++) {
+ request[i] = salt[i - 4];
+ }
+
+ return encrypt(request, key);
+ }
+
+ private byte[] sendAccountKeyRequest(BluetoothDevice device, byte[] value) {
+ assertThat(mBluetoothGattServerCallback).isNotNull();
+ assertThat(mAccountKeyCharacteristic).isNotNull();
+ return sendCharacteristicWriteRequest(device, mAccountKeyCharacteristic, value);
+ }
+
+ private byte[] buildAccountKeyRequest(byte[] accountKeyBytes, byte[] key) {
+ byte[] request = Arrays.copyOf(accountKeyBytes, 16);
+ return encrypt(request, key);
+ }
+
+ private byte[] sendCharacteristicWriteRequest(BluetoothDevice device,
+ BluetoothGattCharacteristic characteristic, byte[] value) {
+ mBluetoothGattServerCallback.onCharacteristicWriteRequest(device, 0, characteristic, false,
+ false, 0, value);
+ verify(mMockBluetoothGattServer).sendResponse(eq(device), eq(0), anyInt(), anyInt(),
+ mBytesCaptor.capture());
+ return mBytesCaptor.getValue();
+ }
+
+ private byte[] sendDescriptorWriteRequest(BluetoothDevice device,
+ BluetoothGattDescriptor descriptor, byte[] value) {
+ mBluetoothGattServerCallback.onDescriptorWriteRequest(device, 0, descriptor, false,
+ false, 0, value);
+ verify(mMockBluetoothGattServer).sendResponse(eq(device), eq(0), anyInt(), anyInt(),
+ mBytesCaptor.capture());
+ return mBytesCaptor.getValue();
+ }
+
+ private void sendPairingRequestBroadcast(BluetoothDevice device, int key) {
+ assertThat(mReceiver).isNotNull();
+ Intent pairingRequest = new Intent(BluetoothDevice.ACTION_PAIRING_REQUEST);
+ pairingRequest.putExtra(BluetoothDevice.EXTRA_PAIRING_KEY, key);
+ pairingRequest.putExtra(BluetoothDevice.EXTRA_DEVICE, device);
+ mReceiver.onReceive(mMockContext, pairingRequest);
+ }
+
+ private void sendBondStateChangeBroadcast(BluetoothDevice device, int newState, int oldState) {
+ assertThat(mReceiver).isNotNull();
+ Intent bondStateChange = new Intent(BluetoothDevice.ACTION_BOND_STATE_CHANGED);
+ bondStateChange.putExtra(BluetoothDevice.EXTRA_DEVICE, device);
+ bondStateChange.putExtra(BluetoothDevice.EXTRA_BOND_STATE, newState);
+ bondStateChange.putExtra(BluetoothDevice.EXTRA_PREVIOUS_BOND_STATE, oldState);
+ mReceiver.onReceive(mMockContext, bondStateChange);
+ }
+
+ private byte[] encrypt(byte[] payload, byte[] keyBytes) {
+ SecretKeySpec key = new SecretKeySpec(keyBytes, "AES");
+ try {
+ Cipher cipher = Cipher.getInstance("AES/ECB/NoPadding");
+ cipher.init(Cipher.ENCRYPT_MODE, key);
+ return cipher.doFinal(payload);
+ } catch (Exception e) {
+ return null;
+ }
+ }
+
+ private byte[] decrypt(byte[] encrypted, byte[] keyBytes) {
+ SecretKeySpec key = new SecretKeySpec(keyBytes, "AES");
+ try {
+ Cipher cipher = Cipher.getInstance("AES/ECB/NoPadding");
+ cipher.init(Cipher.DECRYPT_MODE, key);
+ return cipher.doFinal(encrypted);
+ } catch (Exception e) {
+ return null;
+ }
+ }
+
+ @Test
+ public void testStartWhileStarted_startIgnored() {
+ startAndVerifyServer();
+ mTestGattServer.start();
+ verifyNoMoreInteractions(mMockContext);
+ assertThat(mTestGattServer.isStarted()).isTrue();
+ assertThat(mTestGattServer.isConnected()).isFalse();
+ }
+
+ @Test
+ public void testStopWhileStopped_stopIgnored() {
+ mTestGattServer.stop();
+ verifyNoMoreInteractions(mMockContext);
+ assertThat(mTestGattServer.isStarted()).isFalse();
+ }
+
+ @Test
+ public void testStopWhileDeviceConnected_deviceDisconnected() {
+ startAndVerifyServer();
+ connectDevice(mMockBluetoothDevice);
+ assertThat(mTestGattServer.isConnected()).isTrue();
+ mTestGattServer.stop();
+ verify(mMockBluetoothGattServer).cancelConnection(eq(mMockBluetoothDevice));
+ assertThat(mTestGattServer.isConnected()).isFalse();
+ assertThat(mTestGattServer.isStarted()).isFalse();
+ }
+
+ @Test
+ public void testProcessKeyBasedPairingRequestWithAntiSpoofKey_responseValid() {
+ startAndVerifyServer();
+ setCurrentRpa(TEST_RPA_STRING);
+ connectDevice(mMockBluetoothDevice);
+ byte[] request = buildKeyBasedPairingRequest(KEY_BASED_PAIRING_REQUEST_MSG_TYPE,
+ /* flags= */ (byte) 0x00, TEST_RPA_BYTES, /* seeker_address= */ null, TEST_SALT_8,
+ TEST_PUBLIC_KEY_A, TEST_GENERATED_KEY);
+ byte[] encryptedResponse = sendKeyBasedPairingRequest(mMockBluetoothDevice, request);
+ assertThat(encryptedResponse).isNotNull();
+
+ byte[] response = decrypt(encryptedResponse, TEST_GENERATED_KEY);
+ assertThat(response).isNotNull();
+ assertThat(response.length).isEqualTo(16);
+
+ byte type = response[0];
+ byte[] addressBytes = Arrays.copyOfRange(response, 1, 7);
+ byte[] salt = Arrays.copyOfRange(response, 7, 15);
+
+ assertThat(type).isEqualTo(KEY_BASED_PAIRING_RESPONSE_MSG_TYPE);
+ assertThat(addressBytes).isEqualTo(TEST_DEVICE_ADDRESS_BYTES);
+ assertThat(salt).isNotNull();
+
+ verify(mMockBluetoothGattServer).notifyCharacteristicChanged(eq(mMockBluetoothDevice),
+ eq(mDeviceNameCharacteristic), eq(false));
+ verify(mMockBluetoothGattServer).notifyCharacteristicChanged(eq(mMockBluetoothDevice),
+ eq(mKeyBasedPairingCharacteristic), eq(false));
+ }
+
+ @Test
+ public void testProcessKeyBasedPairingRequestUsingAccountKey_responseValid() {
+ startAndVerifyServer();
+ setCurrentRpa(TEST_RPA_STRING);
+ setAvailableAccountKeys(List.of(new AccountKey(TEST_VALID_ACCOUNT_KEY)));
+ connectDevice(mMockBluetoothDevice);
+ byte[] request = buildKeyBasedPairingRequest(KEY_BASED_PAIRING_REQUEST_MSG_TYPE,
+ /* flags= */ (byte) 0x00, TEST_RPA_BYTES, /* seeker_address= */ null, TEST_SALT_8,
+ TEST_PUBLIC_KEY_A, TEST_VALID_ACCOUNT_KEY);
+ request = Arrays.copyOfRange(request, 0, 16);
+ byte[] encryptedResponse = sendKeyBasedPairingRequest(mMockBluetoothDevice, request);
+ assertThat(encryptedResponse).isNotNull();
+
+ byte[] response = decrypt(encryptedResponse, TEST_VALID_ACCOUNT_KEY);
+ assertThat(response).isNotNull();
+ assertThat(response.length).isEqualTo(16);
+
+ byte type = response[0];
+ byte[] addressBytes = Arrays.copyOfRange(response, 1, 7);
+ byte[] salt = Arrays.copyOfRange(response, 7, 15);
+
+ assertThat(type).isEqualTo(KEY_BASED_PAIRING_RESPONSE_MSG_TYPE);
+ assertThat(addressBytes).isEqualTo(TEST_DEVICE_ADDRESS_BYTES);
+ assertThat(salt).isNotNull();
+
+ verify(mMockBluetoothGattServer).notifyCharacteristicChanged(eq(mMockBluetoothDevice),
+ eq(mDeviceNameCharacteristic), eq(false));
+ verify(mMockBluetoothGattServer).notifyCharacteristicChanged(eq(mMockBluetoothDevice),
+ eq(mKeyBasedPairingCharacteristic), eq(false));
+ }
+
+ @Test
+ public void testProcessKeyBasedPairingRequestUsingInvalidKey_requestIgnored() {
+ startAndVerifyServer();
+ setCurrentRpa(TEST_RPA_STRING);
+ connectDevice(mMockBluetoothDevice);
+ byte[] request = buildKeyBasedPairingRequest(KEY_BASED_PAIRING_REQUEST_MSG_TYPE,
+ /* flags= */ (byte) 0x00, TEST_RPA_BYTES, /* seeker_address= */ null, TEST_SALT_8,
+ TEST_PUBLIC_KEY_A, TEST_WRONG_GENERATED_KEY);
+ byte[] encryptedResponse = sendKeyBasedPairingRequest(mMockBluetoothDevice, request);
+ assertThat(encryptedResponse).isNull();
+ assertThat(mTestGattServer.isFastPairSessionActive()).isFalse();
+ verify(mMockBluetoothGattServer, never()).notifyCharacteristicChanged(any(), any(),
+ anyBoolean());
+ }
+
+ @Test
+ public void testProcessKeyBasedPairingRequestTenFailures_allRequestsIgnored() {
+ startAndVerifyServer();
+ setCurrentRpa(TEST_RPA_STRING);
+
+ for (int i = 0; i < 10; i++) {
+ connectDevice(mMockBluetoothDevice);
+ byte[] request = buildKeyBasedPairingRequest(KEY_BASED_PAIRING_REQUEST_MSG_TYPE,
+ /* flags= */ (byte) 0x00, TEST_RPA_BYTES, /* seeker_address= */ null,
+ TEST_SALT_8, TEST_PUBLIC_KEY_A, TEST_WRONG_GENERATED_KEY);
+ byte[] encryptedResponse = sendKeyBasedPairingRequest(mMockBluetoothDevice, request);
+ assertThat(encryptedResponse).isNull();
+ clearInvocations(mMockBluetoothGattServer);
+ assertThat(mTestGattServer.isFastPairSessionActive()).isFalse();
+ }
+
+ connectDevice(mMockBluetoothDevice);
+ byte[] request = buildKeyBasedPairingRequest(KEY_BASED_PAIRING_REQUEST_MSG_TYPE,
+ /* flags= */ (byte) 0x00, TEST_RPA_BYTES, /* seeker_address= */ null, TEST_SALT_8,
+ TEST_PUBLIC_KEY_A, TEST_GENERATED_KEY);
+ byte[] encryptedResponse = sendKeyBasedPairingRequest(mMockBluetoothDevice, request);
+ assertThat(encryptedResponse).isNull();
+ assertThat(mTestGattServer.isFastPairSessionActive()).isFalse();
+ verify(mMockBluetoothGattServer, never()).notifyCharacteristicChanged(any(), any(),
+ anyBoolean());
+ }
+
+ @Test
+ public void testProcessPairingKeyRequest_pairingConfirmed() {
+ testProcessKeyBasedPairingRequestWithAntiSpoofKey_responseValid();
+ clearInvocations(mMockBluetoothGattServer);
+ sendBondStateChangeBroadcast(mMockBluetoothDevice,
+ BluetoothDevice.BOND_BONDING, BluetoothDevice.BOND_NONE);
+ sendPairingRequestBroadcast(mMockBluetoothDevice, TEST_PAIRING_KEY);
+ byte[] request = buildPasskeyRequest(PASSKEY_REQUEST_SEEKER, TEST_PAIRING_KEY_BYTES,
+ TEST_SALT_12, TEST_GENERATED_KEY);
+ byte[] encryptedResponse = sendPasskeyRequest(mMockBluetoothDevice, request);
+ verify(mMockBluetoothDevice).setPairingConfirmation(eq(true));
+ assertThat(mTestGattServer.isFastPairSessionActive()).isTrue(); // lifespan 10000
+ }
+
+ @Test
+ public void testProcessPairingKeyRequestWrongPasskey_pairingCancelled() {
+ testProcessKeyBasedPairingRequestWithAntiSpoofKey_responseValid();
+ clearInvocations(mMockBluetoothGattServer);
+ sendBondStateChangeBroadcast(mMockBluetoothDevice,
+ BluetoothDevice.BOND_BONDING, BluetoothDevice.BOND_NONE);
+ sendPairingRequestBroadcast(mMockBluetoothDevice, TEST_PAIRING_KEY);
+ byte[] request = buildPasskeyRequest(PASSKEY_REQUEST_SEEKER, TEST_WRONG_PAIRING_KEY_BYTES,
+ TEST_SALT_12, TEST_GENERATED_KEY);
+ byte[] encryptedResponse = sendPasskeyRequest(mMockBluetoothDevice, request);
+ verify(mMockBluetoothDevice).setPairingConfirmation(eq(false));
+ assertThat(mTestGattServer.isFastPairSessionActive()).isFalse();
+ }
+
+ @Test
+ public void testProcessPairingKeyRequestShortPasskey_pairingCancelled() {
+ testProcessKeyBasedPairingRequestWithAntiSpoofKey_responseValid();
+ clearInvocations(mMockBluetoothGattServer);
+ sendBondStateChangeBroadcast(mMockBluetoothDevice,
+ BluetoothDevice.BOND_BONDING, BluetoothDevice.BOND_NONE);
+ sendPairingRequestBroadcast(mMockBluetoothDevice, TEST_PAIRING_KEY);
+ byte[] encryptedResponse = sendPasskeyRequest(mMockBluetoothDevice, TEST_REQUEST_SHORT);
+ assertThat(mTestGattServer.isFastPairSessionActive()).isFalse();
+ }
+
+ @Test
+ public void testProcessPairingKeyRequestNullPasskey_pairingCancelled() {
+ testProcessKeyBasedPairingRequestWithAntiSpoofKey_responseValid();
+ clearInvocations(mMockBluetoothGattServer);
+ sendBondStateChangeBroadcast(mMockBluetoothDevice,
+ BluetoothDevice.BOND_BONDING, BluetoothDevice.BOND_NONE);
+ sendPairingRequestBroadcast(mMockBluetoothDevice, TEST_PAIRING_KEY);
+ byte[] encryptedResponse = sendPasskeyRequest(mMockBluetoothDevice, null);
+ assertThat(mTestGattServer.isFastPairSessionActive()).isFalse();
+ }
+
+ @Test
+ public void testReceivePairingCode_sendsPairingResponse() {
+ testProcessKeyBasedPairingRequestWithAntiSpoofKey_responseValid();
+ clearInvocations(mMockBluetoothGattServer);
+ sendBondStateChangeBroadcast(mMockBluetoothDevice,
+ BluetoothDevice.BOND_BONDING, BluetoothDevice.BOND_NONE);
+ sendPairingRequestBroadcast(mMockBluetoothDevice, TEST_PAIRING_KEY);
+ byte[] encryptedResponse = mPasskeyCharacteristic.getValue();
+ byte[] passkeyResponse = decrypt(encryptedResponse, TEST_GENERATED_KEY);
+
+ assertThat(passkeyResponse.length).isEqualTo(16);
+ byte type = passkeyResponse[0];
+ byte[] passkey = Arrays.copyOfRange(passkeyResponse, 1, 4);
+ byte[] salt = Arrays.copyOfRange(passkeyResponse, 4, 15);
+
+ assertThat(type).isEqualTo(PASSKEY_REQUEST_PROVIDER);
+ assertThat(passkey).isEqualTo(TEST_PAIRING_KEY_BYTES);
+ assertThat(salt).isNotNull();
+
+ verify(mMockBluetoothGattServer).notifyCharacteristicChanged(eq(mMockBluetoothDevice),
+ eq(mPasskeyCharacteristic), eq(false));
+ assertThat(mTestGattServer.isFastPairSessionActive()).isTrue(); // Lifespan 35000
+ }
+
+ @Test
+ public void testReceivePairingCodeWhileDisconnected_nothingSent() {
+ startAndVerifyServer();
+ assertThat(mTestGattServer.isConnected()).isFalse();
+ assertThat(mTestGattServer.isFastPairSessionActive()).isFalse();
+ sendBondStateChangeBroadcast(mMockBluetoothDevice,
+ BluetoothDevice.BOND_BONDING, BluetoothDevice.BOND_NONE);
+ sendPairingRequestBroadcast(mMockBluetoothDevice, TEST_PAIRING_KEY);
+ byte[] encryptedResponse = mPasskeyCharacteristic.getValue();
+ byte[] passkeyResponse = decrypt(encryptedResponse, TEST_GENERATED_KEY);
+ assertThat(passkeyResponse).isNull();
+ verify(mMockBluetoothGattServer, never()).notifyCharacteristicChanged(any(), any(),
+ anyBoolean());
+ assertThat(mTestGattServer.isFastPairSessionActive()).isFalse();
+ }
+
+ @Test
+ public void testProcessAccountKeyRequestWithValidKey_keyAdded() {
+ testProcessPairingKeyRequest_pairingConfirmed();
+ clearInvocations(mMockBluetoothGattServer);
+ sendBondStateChangeBroadcast(mMockBluetoothDevice,
+ BluetoothDevice.BOND_BONDED, BluetoothDevice.BOND_BONDING);
+ assertThat(mTestGattServer.isFastPairSessionActive()).isTrue();
+ byte[] request = buildAccountKeyRequest(TEST_VALID_ACCOUNT_KEY, TEST_GENERATED_KEY);
+ byte[] encryptedResponse = sendAccountKeyRequest(mMockBluetoothDevice, request);
+ verify(mMockFastPairAccountKeyStorage).add(eq(new AccountKey(TEST_VALID_ACCOUNT_KEY)));
+ assertThat(mTestGattServer.isFastPairSessionActive()).isFalse();
+ }
+
+ @Test
+ public void testProcessAccountKeyRequestWithInvalidKey_keyIgnored() {
+ testProcessPairingKeyRequest_pairingConfirmed();
+ clearInvocations(mMockBluetoothGattServer);
+ sendBondStateChangeBroadcast(mMockBluetoothDevice,
+ BluetoothDevice.BOND_BONDED, BluetoothDevice.BOND_BONDING);
+ assertThat(mTestGattServer.isFastPairSessionActive()).isTrue();
+ byte[] request = buildAccountKeyRequest(TEST_INVALID_ACCOUNT_KEY, TEST_GENERATED_KEY);
+ byte[] encryptedResponse = sendAccountKeyRequest(mMockBluetoothDevice, request);
+ verify(mMockFastPairAccountKeyStorage, never()).add(any());
+ assertThat(mTestGattServer.isFastPairSessionActive()).isFalse();
+ }
+
+ @Test
+ public void testProcessAccountKeyRequestWithEmptyKey_requestIgnored() {
+ testProcessPairingKeyRequest_pairingConfirmed();
+ clearInvocations(mMockBluetoothGattServer);
+ sendBondStateChangeBroadcast(mMockBluetoothDevice,
+ BluetoothDevice.BOND_BONDED, BluetoothDevice.BOND_BONDING);
+ assertThat(mTestGattServer.isFastPairSessionActive()).isTrue();
+ byte[] encryptedResponse = sendAccountKeyRequest(mMockBluetoothDevice, new byte[]{});
+ verify(mMockFastPairAccountKeyStorage, never()).add(any());
+ assertThat(mTestGattServer.isFastPairSessionActive()).isFalse();
+ }
+
+ @Test
+ public void testProcessAccountKeyRequestWithShortKey_requestIgnored() {
+ testProcessPairingKeyRequest_pairingConfirmed();
+ clearInvocations(mMockBluetoothGattServer);
+ sendBondStateChangeBroadcast(mMockBluetoothDevice,
+ BluetoothDevice.BOND_BONDED, BluetoothDevice.BOND_BONDING);
+ assertThat(mTestGattServer.isFastPairSessionActive()).isTrue();
+ byte[] encryptedResponse = sendAccountKeyRequest(mMockBluetoothDevice, TEST_REQUEST_SHORT);
+ verify(mMockFastPairAccountKeyStorage, never()).add(any());
+ assertThat(mTestGattServer.isFastPairSessionActive()).isFalse();
+ }
+
+ @Test
+ public void testProcessAccountKeyRequestWithNullKey_requestIgnored() {
+ testProcessPairingKeyRequest_pairingConfirmed();
+ clearInvocations(mMockBluetoothGattServer);
+ sendBondStateChangeBroadcast(mMockBluetoothDevice,
+ BluetoothDevice.BOND_BONDED, BluetoothDevice.BOND_BONDING);
+ assertThat(mTestGattServer.isFastPairSessionActive()).isTrue();
+ byte[] encryptedResponse = sendAccountKeyRequest(mMockBluetoothDevice, null);
+ verify(mMockFastPairAccountKeyStorage, never()).add(any());
+ assertThat(mTestGattServer.isFastPairSessionActive()).isFalse();
+ }
+
+ @Test
+ public void testDeviceDisconnectsMidSession_keysClearedAndPairingStopped() {
+ testProcessKeyBasedPairingRequestWithAntiSpoofKey_responseValid();
+ clearInvocations(mMockBluetoothGattServer);
+ disconnectDevice(mMockBluetoothDevice);
+ assertThat(mTestGattServer.isConnected()).isFalse();
+ assertThat(mTestGattServer.isFastPairSessionActive()).isFalse();
+ verify(mMockFastPairCallbacks).onPairingCompleted(eq(false));
+ }
+
+ @Test
+ public void testReadDeviceModelId() {
+ testProcessKeyBasedPairingRequestWithAntiSpoofKey_responseValid();
+ clearInvocations(mMockBluetoothGattServer);
+ byte[] response = sendReadModelIdRequest(mMockBluetoothDevice);
+ assertThat(response).isEqualTo(TEST_MODEL_ID_BYTES);
+ }
+
+ @Test
+ public void testReadDeviceName() {
+ testProcessKeyBasedPairingRequestWithAntiSpoofKey_responseValid();
+ clearInvocations(mMockBluetoothGattServer);
+ byte[] response = sendReadDeviceNameRequest(mMockBluetoothDevice);
+ String name = new String(response, StandardCharsets.UTF_8);
+ assertThat(name).isEqualTo(TEST_DEVICE_NAME);
+ }
+
+ @Test
+ public void testDeviceNameChanged() {
+ startAndVerifyServer();
+ setDeviceName(TEST_DEVICE_NAME_2);
+ assertThat(mDeviceNameCharacteristic).isNotNull();
+ assertThat(mDeviceNameCharacteristic.getValue()).isEqualTo(TEST_DEVICE_NAME_2.getBytes());
+ }
+
+ @Test
+ public void testDescriptorWriteRequest_responseValid() {
+ startAndVerifyServer();
+ sendDescriptorWriteRequest(mMockBluetoothDevice, mMockGattDescriptor, null);
+ verify(mMockBluetoothGattServer).sendResponse(eq(mMockBluetoothDevice), anyInt(),
+ eq(BluetoothGatt.GATT_SUCCESS), anyInt(), any());
+ }
+
+ @Test
+ public void testUnknownBroadcastAction_broadcastIgnored() {
+ startAndVerifyServer();
+ clearInvocations(mMockBluetoothGattServer);
+ assertThat(mReceiver).isNotNull();
+ Intent unknown = new Intent(BluetoothDevice.ACTION_UUID);
+ mReceiver.onReceive(mMockContext, unknown);
+ verifyNoMoreInteractions(mMockBluetoothGattServer);
+ }
+}
diff --git a/tests/carservice_unit_test/src/com/android/car/bluetooth/FastPairProviderTest.java b/tests/carservice_unit_test/src/com/android/car/bluetooth/FastPairProviderTest.java
new file mode 100644
index 0000000..aa2ac90
--- /dev/null
+++ b/tests/carservice_unit_test/src/com/android/car/bluetooth/FastPairProviderTest.java
@@ -0,0 +1,468 @@
+/*
+ * Copyright (C) 2022 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.bluetooth;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.ArgumentMatchers.nullable;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.anyInt;
+import static org.mockito.Mockito.anyString;
+import static org.mockito.Mockito.atLeastOnce;
+import static org.mockito.Mockito.clearInvocations;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.timeout;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.when;
+
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothGattServer;
+import android.bluetooth.BluetoothGattService;
+import android.bluetooth.BluetoothManager;
+import android.bluetooth.le.AdvertiseData;
+import android.bluetooth.le.AdvertisingSet;
+import android.bluetooth.le.AdvertisingSetCallback;
+import android.bluetooth.le.BluetoothLeAdvertiser;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.content.res.Resources;
+import android.os.Looper;
+import android.os.ParcelUuid;
+import android.os.UserManager;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.mockito.junit.MockitoJUnitRunner;
+
+import java.util.Base64;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Unit tests for {@link FastPairProvider}
+ *
+ * Run: atest FastPairProviderTest
+ */
+@RunWith(MockitoJUnitRunner.class)
+public class FastPairProviderTest {
+ private static final String KEY_NUM_ACCOUNT_KEYS = "AccountKeysCount";
+ private static final String FAST_PAIR_PREFERENCES = "com.candroid.car.bluetooth";
+
+ public static final ParcelUuid SERVICE_UUID = ParcelUuid
+ .fromString("0000FE2C-0000-1000-8000-00805f9b34fb");
+
+ static final String DEVICE_NAME = "name";
+ static final String DEVICE_ADDRESS_STRING = "11:22:33:44:55:66";
+
+ static final int TEST_TX_POWER = 50;
+ static final int ADVERTISING_EVENT_TIMEOUT_MS = 3000;
+
+ static final int TEST_MODEL_ID = 0x112233;
+ static final int TEST_EMPTY_MODEL_ID = 0x000000;
+
+ static final byte[] TEST_MODEL_ID_ADVERTISEMENT = new byte[]{0x11, 0x22, 0x33};
+ static final byte[] TEST_ACCOUNT_KEY_FILTER_ADVERTISEMENT = new byte[]{0x00, 0x00};
+
+ static final byte[] TEST_PRIVATE_KEY = {0x02, (byte) 0xB4, 0x37, (byte) 0xB0, (byte) 0xED,
+ (byte) 0xD6, (byte) 0xBB, (byte) 0xD4, 0x29, 0x06, 0x4A, 0x4E, 0x52, (byte) 0x9F,
+ (byte) 0xCB, (byte) 0xF1, (byte) 0xC4, (byte) 0x8D, 0x0D, 0x62, 0x49, 0x24, (byte) 0xD5,
+ (byte) 0x92, 0x27, 0x4B, 0x7E, (byte) 0xD8, 0x11, (byte) 0x93, (byte) 0xD7, 0x63
+ };
+ static final String TEST_PRIVATE_KEY_BASE64 = Base64.getEncoder()
+ .encodeToString(TEST_PRIVATE_KEY);
+ static final String TEST_EMPTY_PRIVATE_KEY = "";
+
+ static final byte[] TEST_PUBLIC_KEY = {0x36, (byte) 0xAC, 0x68, 0x2C, 0x50, (byte) 0x82, 0x15,
+ 0x66, (byte) 0x8F, (byte) 0xBE, (byte) 0xFE, 0x24, 0x7D, 0x01, (byte) 0xD5, (byte) 0xEB,
+ (byte) 0x96, (byte) 0xE6, 0x31, (byte) 0x8E, (byte) 0x85, 0x5B, 0x2D, 0x64, (byte) 0xB5,
+ 0x19, 0x5D, 0x38, (byte) 0xEE, 0x7E, 0x37, (byte) 0xBE, 0x18, 0x38, (byte) 0xC0,
+ (byte) 0xB9, 0x48, (byte) 0xC3, (byte) 0xF7, 0x55, 0x20, (byte) 0xE0, 0x7E, 0x70,
+ (byte) 0xF0, 0x72, (byte) 0x91, 0x41, (byte) 0x9A, (byte) 0xCE, 0x2D, 0x28, 0x14, 0x3C,
+ 0x5A, (byte) 0xDB, 0x2D, (byte) 0xBD, (byte) 0x98, (byte) 0xEE, 0x3C, (byte) 0x8E, 0x4F,
+ (byte) 0xBF};
+ static final String TEST_PUBLIC_KEY_BASE64 = Base64.getEncoder()
+ .encodeToString(TEST_PUBLIC_KEY);
+
+ @Mock Context mMockContext;
+ @Mock Resources mMockResources;
+ @Mock UserManager mMockUserManager;
+ @Mock SharedPreferences mMockSharedPreferences;
+ @Mock SharedPreferences.Editor mMockSharedPreferencesEditor;
+ @Mock BluetoothAdapter mMockBluetoothAdapter;
+ @Mock BluetoothManager mMockBluetoothManager;
+ @Mock BluetoothDevice mMockBluetoothDevice;
+ @Mock BluetoothGattServer mMockBluetoothGattServer;
+ @Mock BluetoothLeAdvertiser mMockBluetoothLeAdvertiser;
+ @Mock AdvertisingSet mMockAdvertisingSet;
+
+ @Captor ArgumentCaptor<BroadcastReceiver> mBroadcastReceiverCaptor;
+ BroadcastReceiver mReceiver;
+
+ private int mSharedPreferencesContentCount = 0;
+ private Map<String, String> mSharedPreferencesContent;
+
+ private BluetoothGattService mFastPairGattService;
+
+ private AdvertisingSetCallback mAdvertisingSetCallback;
+
+ FastPairAdvertiser.Callbacks mAdvertiserCallbacks;
+ FastPairGattServer.Callbacks mGattServerCallbacks;
+
+ private FastPairProvider mFastPairProvider;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+
+ when(mMockContext.getResources()).thenReturn(mMockResources);
+ when(mMockContext.getSystemService(UserManager.class)).thenReturn(mMockUserManager);
+ when(mMockUserManager.isUserUnlocked()).thenReturn(true);
+ when(mMockContext.getSystemService(BluetoothManager.class))
+ .thenReturn(mMockBluetoothManager);
+ when(mMockBluetoothManager.getAdapter()).thenReturn(mMockBluetoothAdapter);
+ when(mMockBluetoothAdapter.getState()).thenReturn(BluetoothAdapter.STATE_OFF);
+ when(mMockBluetoothAdapter.getBluetoothLeAdvertiser())
+ .thenReturn(mMockBluetoothLeAdvertiser);
+ when(mMockBluetoothAdapter.getName()).thenReturn(DEVICE_NAME);
+ when(mMockBluetoothAdapter.getAddress()).thenReturn(DEVICE_ADDRESS_STRING);
+ when(mMockBluetoothManager.openGattServer(any(), any()))
+ .thenReturn(mMockBluetoothGattServer);
+ when(mMockBluetoothAdapter.getRemoteDevice(any(String.class)))
+ .thenReturn(mMockBluetoothDevice);
+ when(mMockBluetoothAdapter.getRemoteDevice(any(byte[].class)))
+ .thenReturn(mMockBluetoothDevice);
+
+ doAnswer(invocation -> {
+ mAdvertisingSetCallback = (AdvertisingSetCallback) invocation.getArguments()[5];
+ return true;
+ }).when(mMockBluetoothLeAdvertiser).startAdvertisingSet(
+ any(), any(), any(), any(), any(), any());
+
+ doAnswer(invocation -> {
+ mAdvertisingSetCallback = null;
+ return true;
+ }).when(mMockBluetoothLeAdvertiser).stopAdvertisingSet(any());
+
+ setupMockKeyStorage();
+
+ mFastPairGattService = null;
+ doAnswer(invocation -> {
+ mFastPairGattService = (BluetoothGattService) invocation.getArgument(0);
+ return true;
+ }).when(mMockBluetoothGattServer).addService(any());
+ doAnswer(invocation -> {
+ mFastPairGattService = null;
+ return true;
+ }).when(mMockBluetoothGattServer).removeService(any());
+ doAnswer(invocation -> {
+ return mFastPairGattService;
+ }).when(mMockBluetoothGattServer).getService(any());
+
+ mBroadcastReceiverCaptor = ArgumentCaptor.forClass(BroadcastReceiver.class);
+
+ Looper looper = Looper.myLooper();
+ if (looper == null) {
+ Looper.prepare();
+ }
+ }
+
+ private void setupMockKeyStorage() {
+ mSharedPreferencesContentCount = 0;
+ mSharedPreferencesContent = new HashMap<>();
+
+ when(mMockContext.getSharedPreferences(anyString(), anyInt()))
+ .thenReturn(mMockSharedPreferences);
+ when(mMockSharedPreferences.edit()).thenReturn(mMockSharedPreferencesEditor);
+
+ // SharedPreferencesEditor.putInt
+ doAnswer(invocation -> {
+ String key = (String) invocation.getArgument(0);
+ int value = (Integer) invocation.getArgument(1);
+ if (KEY_NUM_ACCOUNT_KEYS.equals(key)) {
+ mSharedPreferencesContentCount = value;
+ }
+ return invocation.getMock();
+ }).when(mMockSharedPreferencesEditor).putInt(anyString(), anyInt());
+
+ // SharedPreferencesEditor.putString
+ doAnswer(invocation -> {
+ String key = (String) invocation.getArgument(0);
+ String value = (String) invocation.getArgument(1);
+ mSharedPreferencesContent.put(key, value);
+ return invocation.getMock();
+ }).when(mMockSharedPreferencesEditor).putString(anyString(), anyString());
+
+ // SharedPreferencesEditor.remove
+ doAnswer(invocation -> {
+ String key = (String) invocation.getArgument(0);
+ mSharedPreferencesContent.remove(key);
+ return invocation.getMock();
+ }).when(mMockSharedPreferencesEditor).remove(anyString());
+
+ // SharedPreferences.getInt
+ doAnswer(invocation -> {
+ String key = (String) invocation.getArgument(0);
+ int defaultValue = (Integer) invocation.getArgument(1);
+ if (KEY_NUM_ACCOUNT_KEYS.equals(key)) {
+ return mSharedPreferencesContentCount;
+ }
+ return defaultValue;
+ }).when(mMockSharedPreferences).getInt(anyString(), anyInt());
+
+ // SharedPreferences.getString
+ doAnswer(invocation -> {
+ String key = (String) invocation.getArgument(0);
+ String defaultValue = (String) invocation.getArgument(1);
+ return mSharedPreferencesContent.getOrDefault(key, defaultValue);
+ }).when(mMockSharedPreferences).getString(anyString(), nullable(String.class));
+ }
+
+ private void setModelId(int modelId) {
+ when(mMockResources.getInteger(anyInt())).thenReturn(modelId);
+ }
+
+ private void setPrivateKey(String keyBase64) {
+ when(mMockResources.getString(anyInt())).thenReturn(keyBase64);
+ }
+
+ private void setAutomaticAcceptance(boolean shouldAcceptAutomatically) {
+ when(mMockResources.getBoolean(anyInt())).thenReturn(shouldAcceptAutomatically);
+ }
+
+ private void createProviderUnderTest() {
+ mFastPairProvider = new FastPairProvider(mMockContext);
+ mAdvertiserCallbacks = mFastPairProvider.mAdvertiserCallbacks;
+ mGattServerCallbacks = mFastPairProvider.mGattServerCallbacks;
+ }
+
+ private void startFastPairProvider() {
+ setModelId(TEST_MODEL_ID);
+ setPrivateKey(TEST_PRIVATE_KEY_BASE64);
+ createProviderUnderTest();
+ assertThat(mFastPairProvider.isEnabled()).isTrue();
+ assertThat(mFastPairProvider.isStarted()).isFalse();
+ mFastPairProvider.start();
+ assertThat(mFastPairProvider.isStarted()).isTrue();
+
+ verify(mMockContext).registerReceiver(mBroadcastReceiverCaptor.capture(), any());
+ mReceiver = mBroadcastReceiverCaptor.getValue();
+ clearInvocations(mMockContext);
+ }
+
+ private void sendAdapterStateChange(int newState, int fromState) {
+ when(mMockBluetoothAdapter.getState()).thenReturn(newState);
+ assertThat(mReceiver).isNotNull();
+ Intent intent = new Intent(BluetoothAdapter.ACTION_STATE_CHANGED);
+ intent.putExtra(BluetoothAdapter.EXTRA_STATE, newState);
+ intent.putExtra(BluetoothAdapter.EXTRA_PREVIOUS_STATE, fromState);
+ mReceiver.onReceive(mMockContext, intent);
+ }
+
+ private void sendUserUnlocked() {
+ assertThat(mReceiver).isNotNull();
+ Intent intent = new Intent(Intent.ACTION_USER_UNLOCKED);
+ mReceiver.onReceive(mMockContext, intent);
+ }
+
+ private void sendScanModeChange(int mode) {
+ assertThat(mReceiver).isNotNull();
+ Intent intent = new Intent(BluetoothAdapter.ACTION_SCAN_MODE_CHANGED);
+ intent.putExtra(BluetoothAdapter.EXTRA_SCAN_MODE, mode);
+ mReceiver.onReceive(mMockContext, intent);
+ }
+
+ private void sendAdvertisingStateChange(boolean isAdvertising, int state) {
+ assertThat(mAdvertisingSetCallback).isNotNull();
+ if (isAdvertising) {
+ mAdvertisingSetCallback
+ .onAdvertisingSetStarted(mMockAdvertisingSet, TEST_TX_POWER, state);
+ } else {
+ mAdvertisingSetCallback.onAdvertisingSetStopped(mMockAdvertisingSet);
+ }
+ }
+
+ private void verifyAdvertisementData(byte[] data) {
+ verify(mMockBluetoothAdapter, timeout(ADVERTISING_EVENT_TIMEOUT_MS))
+ .getBluetoothLeAdvertiser();
+ AdvertiseData advertiseData = new AdvertiseData.Builder()
+ .addServiceUuid(SERVICE_UUID)
+ .addServiceData(SERVICE_UUID, data)
+ .setIncludeTxPowerLevel(true)
+ .build();
+ verify(mMockBluetoothLeAdvertiser, timeout(ADVERTISING_EVENT_TIMEOUT_MS))
+ .startAdvertisingSet(any(), eq(advertiseData), any(), any(), any(), any());
+ }
+
+ @Test
+ public void testStartNoModelId_fastPairNotStarted() {
+ setModelId(TEST_EMPTY_MODEL_ID);
+ setPrivateKey(TEST_PRIVATE_KEY_BASE64);
+ createProviderUnderTest();
+ assertThat(mFastPairProvider.isEnabled()).isFalse();
+ assertThat(mFastPairProvider.isStarted()).isFalse();
+ mFastPairProvider.start();
+ assertThat(mFastPairProvider.isStarted()).isFalse();
+ }
+
+ @Test
+ public void testStartNoPrivateKey_fastPairNotStarted() {
+ setModelId(TEST_MODEL_ID);
+ setPrivateKey(TEST_EMPTY_PRIVATE_KEY);
+ createProviderUnderTest();
+ assertThat(mFastPairProvider.isEnabled()).isFalse();
+ assertThat(mFastPairProvider.isStarted()).isFalse();
+ mFastPairProvider.start();
+ assertThat(mFastPairProvider.isStarted()).isFalse();
+ }
+
+ @Test
+ public void testStartNoModelIdAndNoPrivateKey_fastPairNotStarted() {
+ setModelId(TEST_EMPTY_MODEL_ID);
+ setPrivateKey(TEST_EMPTY_PRIVATE_KEY);
+ createProviderUnderTest();
+ assertThat(mFastPairProvider.isEnabled()).isFalse();
+ assertThat(mFastPairProvider.isStarted()).isFalse();
+ mFastPairProvider.start();
+ assertThat(mFastPairProvider.isStarted()).isFalse();
+ }
+
+ @Test
+ public void testStart_fastPairStarted() {
+ startFastPairProvider();
+ }
+
+ @Test
+ public void testStartWhileStarted_doNothing() {
+ startFastPairProvider();
+ mFastPairProvider.start();
+ assertThat(mFastPairProvider.isStarted()).isTrue();
+ verifyNoMoreInteractions(mMockContext);
+ }
+
+ @Test
+ public void testStopWhileEnabledAndStopped_doNothing() {
+ setModelId(TEST_MODEL_ID);
+ setPrivateKey(TEST_PRIVATE_KEY_BASE64);
+ createProviderUnderTest();
+ clearInvocations(mMockContext);
+ assertThat(mFastPairProvider.isEnabled()).isTrue();
+ assertThat(mFastPairProvider.isStarted()).isFalse();
+ mFastPairProvider.stop();
+ assertThat(mFastPairProvider.isStarted()).isFalse();
+ verifyNoMoreInteractions(mMockContext);
+ }
+
+ @Test
+ public void testStopWhileStarted_fastPairStopped() {
+ startFastPairProvider();
+ mFastPairProvider.stop();
+ assertThat(mFastPairProvider.isStarted()).isFalse();
+ assertThat(mFastPairProvider.isEnabled()).isTrue();
+ }
+
+ @Test
+ public void testReceiveUserUnlocked_storageLoaded() {
+ startFastPairProvider();
+ sendUserUnlocked();
+ // Verify *something* got the key count, which signals an attempt to load.
+ // Full loading functionality tested in FastPairAccountKeyStorageTest
+ verify(mMockSharedPreferences, atLeastOnce()).getInt(anyString(), anyInt());
+ }
+
+ @Test
+ public void testReceiveAdapterOn_startGattService() {
+ startFastPairProvider();
+ sendAdapterStateChange(BluetoothAdapter.STATE_TURNING_ON, BluetoothAdapter.STATE_OFF);
+ sendAdapterStateChange(BluetoothAdapter.STATE_ON, BluetoothAdapter.STATE_TURNING_ON);
+ verify(mMockBluetoothGattServer).addService(any());
+ }
+
+ @Test
+ public void testReceiveAdapterOff_stopGattServer() {
+ testReceiveAdapterOn_startGattService();
+ sendAdapterStateChange(BluetoothAdapter.STATE_TURNING_OFF, BluetoothAdapter.STATE_ON);
+ sendAdapterStateChange(BluetoothAdapter.STATE_OFF, BluetoothAdapter.STATE_TURNING_OFF);
+ verify(mMockBluetoothGattServer).removeService(any());
+ }
+
+ @Test
+ public void testReceiveScanModeConnectableDiscoverable_advertiseModelId() {
+ startFastPairProvider();
+ when(mMockBluetoothAdapter.isDiscovering()).thenReturn(true);
+ sendScanModeChange(BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE);
+ verifyAdvertisementData(TEST_MODEL_ID_ADVERTISEMENT);
+ }
+
+ @Test
+ public void testReceiveScanModeConnectableDiscoverableNotDiscovering_advertisingStopped() {
+ testReceiveScanModeConnectableAdapterOn_advertiseAccountKeyFilter();
+ clearInvocations(mMockBluetoothLeAdvertiser);
+ sendAdvertisingStateChange(true, AdvertisingSetCallback.ADVERTISE_SUCCESS);
+ when(mMockBluetoothAdapter.isDiscovering()).thenReturn(false);
+ sendScanModeChange(BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE);
+ verify(mMockBluetoothLeAdvertiser, timeout(ADVERTISING_EVENT_TIMEOUT_MS))
+ .stopAdvertisingSet(any());
+ verify(mMockBluetoothLeAdvertiser, never())
+ .startAdvertisingSet(any(), any(), any(), any(), any(), any());
+ }
+
+ @Test
+ public void testReceiveScanModeConnectableAdapterOn_advertiseAccountKeyFilter() {
+ startFastPairProvider();
+ sendAdapterStateChange(BluetoothAdapter.STATE_TURNING_ON, BluetoothAdapter.STATE_OFF);
+ sendAdapterStateChange(BluetoothAdapter.STATE_ON, BluetoothAdapter.STATE_TURNING_ON);
+ sendScanModeChange(BluetoothAdapter.SCAN_MODE_CONNECTABLE);
+ verifyAdvertisementData(TEST_ACCOUNT_KEY_FILTER_ADVERTISEMENT);
+ }
+
+ @Test
+ public void testReceiveScanModeConnectableAdapterOff_noAdvertisingChange() {
+ startFastPairProvider();
+ sendScanModeChange(BluetoothAdapter.SCAN_MODE_CONNECTABLE);
+ verify(mMockBluetoothLeAdvertiser, never())
+ .startAdvertisingSet(any(), any(), any(), any(), any(), any());
+ }
+
+ @Test
+ public void testReceiveScanModeNoneAdapterOff_noAdvertisingChange() {
+ startFastPairProvider();
+ sendScanModeChange(BluetoothAdapter.SCAN_MODE_NONE);
+ verify(mMockBluetoothLeAdvertiser, never())
+ .startAdvertisingSet(any(), any(), any(), any(), any(), any());
+ }
+
+ @Test
+ public void testReceiveScanModeNoneAdapterOn_advertisingAccountKeyFilter() {
+ startFastPairProvider();
+ sendAdapterStateChange(BluetoothAdapter.STATE_TURNING_ON, BluetoothAdapter.STATE_OFF);
+ sendAdapterStateChange(BluetoothAdapter.STATE_ON, BluetoothAdapter.STATE_TURNING_ON);
+ sendScanModeChange(BluetoothAdapter.SCAN_MODE_NONE);
+ verifyAdvertisementData(TEST_ACCOUNT_KEY_FILTER_ADVERTISEMENT);
+ }
+}
diff --git a/tests/carservice_unit_test/src/com/android/car/content/pm/CarPackageManagerUnitTest.java b/tests/carservice_unit_test/src/com/android/car/content/pm/CarPackageManagerUnitTest.java
new file mode 100644
index 0000000..d2ff26e
--- /dev/null
+++ b/tests/carservice_unit_test/src/com/android/car/content/pm/CarPackageManagerUnitTest.java
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 2022 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.content.pm;
+
+import static android.car.testapi.CarMockitoHelper.mockHandleRemoteExceptionFromCarServiceWithDefaultValue;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.junit.Assert.assertThrows;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import android.car.Car;
+import android.car.CarVersion;
+import android.car.content.pm.CarPackageManager;
+import android.car.content.pm.ICarPackageManager;
+import android.car.test.mocks.AbstractExtendedMockitoTestCase;
+import android.content.Context;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.os.RemoteException;
+import android.os.ServiceSpecificException;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+
+public final class CarPackageManagerUnitTest extends AbstractExtendedMockitoTestCase {
+
+ @Mock
+ private Car mCar;
+
+ @Mock
+ private ICarPackageManager mService;
+
+ private CarPackageManager mMgr;
+
+ @Before
+ public void setFixtures() {
+ mMgr = new CarPackageManager(mCar, mService);
+ }
+
+ @Test
+ public void testGetTargetCarVersion_self_ok() throws Exception {
+ mockPackageName("dr.evil");
+ CarVersion apiVersion = CarVersion.forMajorAndMinorVersions(66, 6);
+ when(mService.getSelfTargetCarVersion("dr.evil")).thenReturn(apiVersion);
+
+ assertThat(mMgr.getTargetCarVersion()).isSameInstanceAs(apiVersion);
+ }
+
+ @Test
+ public void testGetTargetCarVersion_self_remoteException() throws Exception {
+ mockPackageName("the.meaning.of.life");
+ RemoteException cause = new RemoteException("D'OH!");
+ when(mService.getSelfTargetCarVersion("the.meaning.of.life")).thenThrow(cause);
+
+ RuntimeException e = assertThrows(RuntimeException.class, () -> mMgr.getTargetCarVersion());
+
+ assertThat(e.getCause()).isSameInstanceAs(cause);
+ }
+
+ @Test
+ public void testGetTargetCarVersion_ok() throws Exception {
+ CarVersion apiVersion = CarVersion.forMajorAndMinorVersions(66, 6);
+ when(mService.getTargetCarVersion("dr.evil")).thenReturn(apiVersion);
+
+ assertThat(mMgr.getTargetCarVersion("dr.evil")).isSameInstanceAs(apiVersion);
+ }
+
+ @Test
+ public void testGetTargetCarVersion_runtimeException() throws Exception {
+ mockHandleRemoteExceptionFromCarServiceWithDefaultValue(mCar);
+ RemoteException cause = new RemoteException("D'OH!");
+ when(mService.getTargetCarVersion("the.meaning.of.life")).thenThrow(cause);
+
+ RuntimeException e = assertThrows(RuntimeException.class,
+ () -> mMgr.getTargetCarVersion("the.meaning.of.life"));
+
+ assertThat(e.getCause()).isSameInstanceAs(cause);
+ }
+
+ @Test
+ public void testGetTargetCarVersion_serviceException_unexpectedErrorCode() throws Exception {
+ mockHandleRemoteExceptionFromCarServiceWithDefaultValue(mCar);
+ ServiceSpecificException cause = new ServiceSpecificException(666, "D'OH!");
+ when(mService.getTargetCarVersion("the.meaning.of.life")).thenThrow(cause);
+
+ IllegalStateException e = assertThrows(IllegalStateException.class,
+ () -> mMgr.getTargetCarVersion("the.meaning.of.life"));
+
+ assertThat(e.getCause()).isSameInstanceAs(cause);
+ }
+
+ @Test
+ public void testGetTargetCarVersion_serviceException_notFound() throws Exception {
+ mockHandleRemoteExceptionFromCarServiceWithDefaultValue(mCar);
+ when(mService.getTargetCarVersion("the.meaning.of.life"))
+ .thenThrow(new ServiceSpecificException(CarPackageManager.ERROR_CODE_NO_PACKAGE,
+ "D'OH!"));
+
+ NameNotFoundException e = assertThrows(NameNotFoundException.class,
+ () -> mMgr.getTargetCarVersion("the.meaning.of.life"));
+
+ assertThat(e.getMessage()).contains("the.meaning.of.life");
+ assertThat(e.getMessage()).doesNotContain("D'OH!");
+ }
+
+ private void mockPackageName(String name) {
+ Context context = mock(Context.class);
+ when(context.getPackageName()).thenReturn(name);
+ when(mCar.getContext()).thenReturn(context);
+ }
+}
diff --git a/tests/carservice_unit_test/src/com/android/car/hal/TimeHalServiceTest.java b/tests/carservice_unit_test/src/com/android/car/hal/TimeHalServiceTest.java
index b0d39ed..03ea0a4 100644
--- a/tests/carservice_unit_test/src/com/android/car/hal/TimeHalServiceTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/hal/TimeHalServiceTest.java
@@ -151,6 +151,20 @@
}
@Test
+ public void testInitSubscribesToProperty() {
+ TimeHalService timeHalService = mTimeHalServiceProvider.get();
+ timeHalService.takeProperties(Collections.singletonList(CAR_TIME_PROP));
+ long testTimeNanos = 123_456_789_456_123L;
+ when(mVehicleHal.get(anyInt())).thenReturn(
+ newExternalCarTimeValue(testTimeNanos));
+
+ timeHalService.init();
+
+ assertThat(timeHalService.isExternalCarTimeSupported()).isTrue();
+ verify(mVehicleHal).subscribeProperty(timeHalService, EXTERNAL_CAR_TIME);
+ }
+
+ @Test
public void testReleaseUnregistersBroadcastReceiver() {
TimeHalService timeHalService = mTimeHalServiceProvider.get();
timeHalService.takeProperties(Collections.singletonList(ANDROID_TIME_PROP));
diff --git a/tests/carservice_unit_test/src/com/android/car/hal/VehicleHalTest.java b/tests/carservice_unit_test/src/com/android/car/hal/VehicleHalTest.java
index 4c29835..8fccacb 100644
--- a/tests/carservice_unit_test/src/com/android/car/hal/VehicleHalTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/hal/VehicleHalTest.java
@@ -77,6 +77,8 @@
private static final int SOME_INT32_VEC_PROPERTY = VehiclePropertyType.INT32_VEC | 0x05;
private static final int SOME_FLOAT_PROPERTY = VehiclePropertyType.FLOAT | 0x06;
private static final int SOME_FLOAT_VEC_PROPERTY = VehiclePropertyType.FLOAT_VEC | 0x07;
+ private static final int SOME_INT64_PROPERTY = VehiclePropertyType.INT32 | 0x10;
+ private static final int SOME_INT64_VEC_PROPERTY = VehiclePropertyType.INT64_VEC | 0x11;
private static final int UNSUPPORTED_PROPERTY = -1;
private static final float ANY_SAMPLING_RATE = 60f;
@@ -1291,6 +1293,47 @@
}
@Test
+ public void testInjectVhalEvent_longProperty_skipSetupInit() throws Exception {
+ // Arrange
+ List<HalPropValue> values = new ArrayList<HalPropValue>();
+ setupInjectEventTest(SOME_INT64_PROPERTY, values);
+ long time = SystemClock.elapsedRealtimeNanos();
+
+ // Act
+ mVehicleHal.injectVhalEvent(SOME_INT64_PROPERTY, VehicleHal.NO_AREA, "1", 0);
+ CarServiceUtils.runOnLooperSync(mHandlerThread.getLooper(), () -> {});
+
+ // Assert
+ assertThat(values.size()).isEqualTo(1);
+ HalPropValue prop = values.get(0);
+ assertThat(prop.getPropId()).isEqualTo(SOME_INT64_PROPERTY);
+ assertThat(prop.getAreaId()).isEqualTo(VehicleHal.NO_AREA);
+ assertThat(prop.getInt32Value(0)).isEqualTo(1);
+ assertThat(prop.getTimestamp()).isGreaterThan(time);
+ }
+
+ @Test
+ public void testInjectVhalEvent_longVecProperty_skipSetupInit() throws Exception {
+ // Arrange
+ List<HalPropValue> values = new ArrayList<HalPropValue>();
+ setupInjectEventTest(SOME_INT64_VEC_PROPERTY, values);
+ long time = SystemClock.elapsedRealtimeNanos();
+
+ // Act
+ mVehicleHal.injectVhalEvent(SOME_INT64_VEC_PROPERTY, VehicleHal.NO_AREA, "1,2", 0);
+ CarServiceUtils.runOnLooperSync(mHandlerThread.getLooper(), () -> {});
+
+ // Assert
+ assertThat(values.size()).isEqualTo(1);
+ HalPropValue prop = values.get(0);
+ assertThat(prop.getPropId()).isEqualTo(SOME_INT64_VEC_PROPERTY);
+ assertThat(prop.getAreaId()).isEqualTo(VehicleHal.NO_AREA);
+ assertThat(prop.getInt64Value(0)).isEqualTo(1);
+ assertThat(prop.getInt64Value(1)).isEqualTo(2);
+ assertThat(prop.getTimestamp()).isGreaterThan(time);
+ }
+
+ @Test
public void testInjectVhalEvent_bool_skipSetupInit() throws Exception {
// Arrange
List<HalPropValue> values = new ArrayList<HalPropValue>();
diff --git a/tests/carservice_unit_test/src/com/android/car/hardware/power/CarPowerManagerUnitTest.java b/tests/carservice_unit_test/src/com/android/car/hardware/power/CarPowerManagerUnitTest.java
index 90c69b2..c6f56cf 100644
--- a/tests/carservice_unit_test/src/com/android/car/hardware/power/CarPowerManagerUnitTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/hardware/power/CarPowerManagerUnitTest.java
@@ -486,6 +486,22 @@
referenceStates).inOrder();
}
+ private static boolean isCompletionAllowed(@CarPowerManager.CarPowerState int state) {
+ switch (state) {
+ case CarPowerManager.STATE_PRE_SHUTDOWN_PREPARE:
+ case CarPowerManager.STATE_SHUTDOWN_PREPARE:
+ case CarPowerManager.STATE_SHUTDOWN_ENTER:
+ case CarPowerManager.STATE_SUSPEND_ENTER:
+ case CarPowerManager.STATE_HIBERNATION_ENTER:
+ case CarPowerManager.STATE_POST_SHUTDOWN_ENTER:
+ case CarPowerManager.STATE_POST_SUSPEND_ENTER:
+ case CarPowerManager.STATE_POST_HIBERNATION_ENTER:
+ return true;
+ default:
+ return false;
+ }
+ }
+
private static final class MockDisplayInterface implements DisplayInterface {
private final Object mLock = new Object();
@GuardedBy("mLock")
@@ -580,7 +596,7 @@
(state, future) -> {
mReceivedStates.add(state);
mRemainingCount--;
- if (CarPowerManager.isCompletionAllowed(state)) {
+ if (isCompletionAllowed(state)) {
assertThat(future).isNotNull();
future.complete();
} else {
diff --git a/tests/carservice_unit_test/src/com/android/car/internal/CarPropertyEventCallbackControllerUnitTest.java b/tests/carservice_unit_test/src/com/android/car/internal/CarPropertyEventCallbackControllerUnitTest.java
new file mode 100644
index 0000000..6f01277
--- /dev/null
+++ b/tests/carservice_unit_test/src/com/android/car/internal/CarPropertyEventCallbackControllerUnitTest.java
@@ -0,0 +1,490 @@
+/*
+ * Copyright (C) 2022 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.internal;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyFloat;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.car.hardware.CarPropertyValue;
+import android.car.hardware.property.CarPropertyEvent;
+import android.car.hardware.property.CarPropertyManager;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+
+import java.time.Duration;
+
+
+public final class CarPropertyEventCallbackControllerUnitTest {
+ private static final int PROPERTY_ID = 1234;
+ private static final int AREA_ID_1 = 908;
+ private static final int AREA_ID_2 = 304;
+ private static final Float FIRST_UPDATE_RATE_HZ = 1F;
+ private static final Float SECOND_BIGGER_UPDATE_RATE_HZ = 2F;
+ private static final Float SECOND_SMALLER_UPDATE_RATE_HZ = 0.5F;
+ private static final long TIMESTAMP_NANOS = Duration.ofSeconds(1).toNanos();
+ private static final long FRESH_TIMESTAMP_NANOS = Duration.ofSeconds(2).toNanos();
+ private static final long ALMOST_FRESH_TIMESTAMP_NANOS = Duration.ofMillis(1999).toNanos();
+ private static final long STALE_TIMESTAMP_NANOS = Duration.ofMillis(500).toNanos();
+ private static final Integer INTEGER_VALUE_1 = 8438;
+ private static final Integer INTEGER_VALUE_2 = 4834;
+ private static final CarPropertyValue<Integer> GOOD_CAR_PROPERTY_VALUE = new CarPropertyValue<>(
+ PROPERTY_ID, AREA_ID_1, CarPropertyValue.STATUS_AVAILABLE, TIMESTAMP_NANOS,
+ INTEGER_VALUE_1);
+ private static final CarPropertyValue<Integer> FRESH_CAR_PROPERTY_VALUE =
+ new CarPropertyValue<>(PROPERTY_ID, AREA_ID_1, CarPropertyValue.STATUS_AVAILABLE,
+ FRESH_TIMESTAMP_NANOS, INTEGER_VALUE_2);
+ private static final CarPropertyValue<Integer> ALMOST_FRESH_CAR_PROPERTY_VALUE =
+ new CarPropertyValue<>(PROPERTY_ID, AREA_ID_1, CarPropertyValue.STATUS_AVAILABLE,
+ ALMOST_FRESH_TIMESTAMP_NANOS, INTEGER_VALUE_2);
+ private static final CarPropertyValue<Integer> STALE_CAR_PROPERTY_VALUE =
+ new CarPropertyValue<>(PROPERTY_ID, AREA_ID_1, CarPropertyValue.STATUS_AVAILABLE,
+ STALE_TIMESTAMP_NANOS, INTEGER_VALUE_2);
+ private static final CarPropertyValue<Integer> STALE_CAR_PROPERTY_VALUE_WITH_DIFFERENT_AREA_ID =
+ new CarPropertyValue<>(PROPERTY_ID, AREA_ID_2, CarPropertyValue.STATUS_AVAILABLE,
+ STALE_TIMESTAMP_NANOS, INTEGER_VALUE_1);
+ private static final CarPropertyValue<Integer> ERROR_CAR_PROPERTY_VALUE =
+ new CarPropertyValue<>(PROPERTY_ID, AREA_ID_1, CarPropertyValue.STATUS_ERROR,
+ TIMESTAMP_NANOS, null);
+ @Rule
+ public final MockitoRule mockito = MockitoJUnit.rule();
+ @Mock
+ private CarPropertyEventCallbackController.RegistrationUpdateCallback
+ mRegistrationUpdateCallback;
+ @Captor
+ private ArgumentCaptor<Integer> mPropertyIdCaptor;
+ @Captor
+ private ArgumentCaptor<Float> mUpdateRateHzCaptor;
+ @Captor
+ private ArgumentCaptor<CarPropertyValue> mCarPropertyValueCaptor;
+ @Mock
+ private CarPropertyManager.CarPropertyEventCallback mCarPropertyEventCallback;
+ @Mock
+ private CarPropertyManager.CarPropertyEventCallback mCarPropertyEventCallback2;
+ private CarPropertyEventCallbackController mCarPropertyEventCallbackController;
+
+ @Before
+ public void setUp() {
+ when(mRegistrationUpdateCallback.register(anyInt(), anyFloat())).thenReturn(true);
+ mCarPropertyEventCallbackController = new CarPropertyEventCallbackController(PROPERTY_ID,
+ new Object(), mRegistrationUpdateCallback);
+ }
+
+ @Test
+ public void add_registerCalledAfterFirstAdd() {
+ assertThat(mCarPropertyEventCallbackController.add(mCarPropertyEventCallback,
+ FIRST_UPDATE_RATE_HZ)).isTrue();
+
+ verify(mRegistrationUpdateCallback).register(PROPERTY_ID, FIRST_UPDATE_RATE_HZ);
+ verify(mRegistrationUpdateCallback, never()).unregister(anyInt());
+ }
+
+ @Test
+ public void add_registerCalledIfSecondRateIsBiggerWithSameCallback() {
+ assertThat(mCarPropertyEventCallbackController.add(mCarPropertyEventCallback,
+ FIRST_UPDATE_RATE_HZ)).isTrue();
+ assertThat(mCarPropertyEventCallbackController.add(mCarPropertyEventCallback,
+ SECOND_BIGGER_UPDATE_RATE_HZ)).isTrue();
+
+ verify(mRegistrationUpdateCallback, times(2)).register(mPropertyIdCaptor.capture(),
+ mUpdateRateHzCaptor.capture());
+ verify(mRegistrationUpdateCallback, never()).unregister(anyInt());
+ assertThat(mPropertyIdCaptor.getAllValues()).containsExactly(PROPERTY_ID, PROPERTY_ID);
+ assertThat(mUpdateRateHzCaptor.getAllValues()).containsExactly(FIRST_UPDATE_RATE_HZ,
+ SECOND_BIGGER_UPDATE_RATE_HZ);
+ }
+
+ @Test
+ public void add_registerCalledIfSecondRateIsSmallerWithSameCallback() {
+ assertThat(mCarPropertyEventCallbackController.add(mCarPropertyEventCallback,
+ FIRST_UPDATE_RATE_HZ)).isTrue();
+ assertThat(mCarPropertyEventCallbackController.add(mCarPropertyEventCallback,
+ SECOND_SMALLER_UPDATE_RATE_HZ)).isTrue();
+
+ verify(mRegistrationUpdateCallback, times(2)).register(mPropertyIdCaptor.capture(),
+ mUpdateRateHzCaptor.capture());
+ verify(mRegistrationUpdateCallback, never()).unregister(anyInt());
+ assertThat(mPropertyIdCaptor.getAllValues()).containsExactly(PROPERTY_ID, PROPERTY_ID);
+ assertThat(mUpdateRateHzCaptor.getAllValues()).containsExactly(FIRST_UPDATE_RATE_HZ,
+ SECOND_SMALLER_UPDATE_RATE_HZ);
+ }
+
+ @Test
+ public void add_registerCalledIfSecondRateIsBiggerWithDifferentCallback() {
+ assertThat(mCarPropertyEventCallbackController.add(mCarPropertyEventCallback,
+ FIRST_UPDATE_RATE_HZ)).isTrue();
+ assertThat(mCarPropertyEventCallbackController.add(mCarPropertyEventCallback2,
+ SECOND_BIGGER_UPDATE_RATE_HZ)).isTrue();
+
+ verify(mRegistrationUpdateCallback, times(2)).register(mPropertyIdCaptor.capture(),
+ mUpdateRateHzCaptor.capture());
+ verify(mRegistrationUpdateCallback, never()).unregister(anyInt());
+ assertThat(mPropertyIdCaptor.getAllValues()).containsExactly(PROPERTY_ID, PROPERTY_ID);
+ assertThat(mUpdateRateHzCaptor.getAllValues()).containsExactly(FIRST_UPDATE_RATE_HZ,
+ SECOND_BIGGER_UPDATE_RATE_HZ);
+ }
+
+ @Test
+ public void add_registerNotCalledIfSecondRateIsSmallerWithDifferentCallback() {
+ assertThat(mCarPropertyEventCallbackController.add(mCarPropertyEventCallback,
+ FIRST_UPDATE_RATE_HZ)).isTrue();
+ assertThat(mCarPropertyEventCallbackController.add(mCarPropertyEventCallback2,
+ SECOND_SMALLER_UPDATE_RATE_HZ)).isTrue();
+
+ verify(mRegistrationUpdateCallback).register(PROPERTY_ID, FIRST_UPDATE_RATE_HZ);
+ verify(mRegistrationUpdateCallback, never()).unregister(anyInt());
+ }
+
+ @Test
+ public void add_returnsFalseIfRegistrationCallbackReturnsFalse() {
+ when(mRegistrationUpdateCallback.register(PROPERTY_ID, FIRST_UPDATE_RATE_HZ)).thenReturn(
+ false);
+ assertThat(mCarPropertyEventCallbackController.add(mCarPropertyEventCallback,
+ FIRST_UPDATE_RATE_HZ)).isFalse();
+
+ verify(mRegistrationUpdateCallback).register(PROPERTY_ID, FIRST_UPDATE_RATE_HZ);
+ verify(mRegistrationUpdateCallback, never()).unregister(anyInt());
+ }
+
+ @Test
+ public void add_registersAgainIfTheFirstCallbackReturnsFalse() {
+ when(mRegistrationUpdateCallback.register(PROPERTY_ID, FIRST_UPDATE_RATE_HZ)).thenReturn(
+ false, true);
+ assertThat(mCarPropertyEventCallbackController.add(mCarPropertyEventCallback,
+ FIRST_UPDATE_RATE_HZ)).isFalse();
+ assertThat(mCarPropertyEventCallbackController.add(mCarPropertyEventCallback,
+ FIRST_UPDATE_RATE_HZ)).isTrue();
+
+ verify(mRegistrationUpdateCallback, times(2)).register(PROPERTY_ID, FIRST_UPDATE_RATE_HZ);
+ verify(mRegistrationUpdateCallback, never()).unregister(anyInt());
+ }
+
+ @Test
+ public void add_restoresOriginalRateHzIfTheSecondCallbackReturnsFalse() {
+ when(mRegistrationUpdateCallback.register(PROPERTY_ID, FIRST_UPDATE_RATE_HZ)).thenReturn(
+ true);
+ when(mRegistrationUpdateCallback.register(PROPERTY_ID,
+ SECOND_BIGGER_UPDATE_RATE_HZ)).thenReturn(false);
+
+ assertThat(mCarPropertyEventCallbackController.add(mCarPropertyEventCallback,
+ FIRST_UPDATE_RATE_HZ)).isTrue();
+ mCarPropertyEventCallbackController.forwardPropertyChanged(
+ new CarPropertyEvent(CarPropertyEvent.PROPERTY_EVENT_PROPERTY_CHANGE,
+ GOOD_CAR_PROPERTY_VALUE));
+ assertThat(mCarPropertyEventCallbackController.add(mCarPropertyEventCallback,
+ SECOND_BIGGER_UPDATE_RATE_HZ)).isFalse();
+ mCarPropertyEventCallbackController.forwardPropertyChanged(
+ new CarPropertyEvent(CarPropertyEvent.PROPERTY_EVENT_PROPERTY_CHANGE,
+ ALMOST_FRESH_CAR_PROPERTY_VALUE));
+
+ verify(mRegistrationUpdateCallback).register(PROPERTY_ID, FIRST_UPDATE_RATE_HZ);
+ verify(mRegistrationUpdateCallback).register(PROPERTY_ID, SECOND_BIGGER_UPDATE_RATE_HZ);
+ verify(mRegistrationUpdateCallback, never()).unregister(anyInt());
+ verify(mCarPropertyEventCallback).onChangeEvent(mCarPropertyValueCaptor.capture());
+ verify(mCarPropertyEventCallback, never()).onErrorEvent(anyInt(), anyInt());
+ verify(mCarPropertyEventCallback, never()).onErrorEvent(anyInt(), anyInt(), anyInt());
+ assertThat(mCarPropertyValueCaptor.getAllValues()).containsExactly(GOOD_CAR_PROPERTY_VALUE);
+ }
+
+ @Test
+ public void remove_noCallbackCalledIfNoCallbacksAdded() {
+ assertThat(mCarPropertyEventCallbackController.remove(mCarPropertyEventCallback)).isTrue();
+
+ verify(mRegistrationUpdateCallback, never()).register(anyInt(), anyFloat());
+ verify(mRegistrationUpdateCallback, never()).unregister(anyInt());
+ }
+
+ @Test
+ public void remove_unregisterCalledIfRemovingSameCallbackAdded() {
+ assertThat(mCarPropertyEventCallbackController.add(mCarPropertyEventCallback,
+ FIRST_UPDATE_RATE_HZ)).isTrue();
+ assertThat(mCarPropertyEventCallbackController.remove(mCarPropertyEventCallback)).isTrue();
+
+ verify(mRegistrationUpdateCallback).register(PROPERTY_ID, FIRST_UPDATE_RATE_HZ);
+ verify(mRegistrationUpdateCallback).unregister(PROPERTY_ID);
+ }
+
+ @Test
+ public void remove_unregisterCalledIfRemovingSameCallbackAddedTwice() {
+ assertThat(mCarPropertyEventCallbackController.add(mCarPropertyEventCallback,
+ FIRST_UPDATE_RATE_HZ)).isTrue();
+ assertThat(mCarPropertyEventCallbackController.add(mCarPropertyEventCallback,
+ SECOND_BIGGER_UPDATE_RATE_HZ)).isTrue();
+ assertThat(mCarPropertyEventCallbackController.remove(mCarPropertyEventCallback)).isTrue();
+
+ verify(mRegistrationUpdateCallback, times(2)).register(mPropertyIdCaptor.capture(),
+ mUpdateRateHzCaptor.capture());
+ verify(mRegistrationUpdateCallback).unregister(PROPERTY_ID);
+ assertThat(mPropertyIdCaptor.getAllValues()).containsExactly(PROPERTY_ID, PROPERTY_ID);
+ assertThat(mUpdateRateHzCaptor.getAllValues()).containsExactly(FIRST_UPDATE_RATE_HZ,
+ SECOND_BIGGER_UPDATE_RATE_HZ);
+ }
+
+ @Test
+ public void remove_registerCalledIfBiggerRateRemoved() {
+ assertThat(mCarPropertyEventCallbackController.add(mCarPropertyEventCallback,
+ FIRST_UPDATE_RATE_HZ)).isTrue();
+ assertThat(mCarPropertyEventCallbackController.add(mCarPropertyEventCallback2,
+ SECOND_BIGGER_UPDATE_RATE_HZ)).isTrue();
+ assertThat(
+ mCarPropertyEventCallbackController.remove(mCarPropertyEventCallback2)).isFalse();
+
+ verify(mRegistrationUpdateCallback, times(3)).register(mPropertyIdCaptor.capture(),
+ mUpdateRateHzCaptor.capture());
+ verify(mRegistrationUpdateCallback, never()).unregister(anyInt());
+ assertThat(mPropertyIdCaptor.getAllValues()).containsExactly(PROPERTY_ID, PROPERTY_ID,
+ PROPERTY_ID);
+ assertThat(mUpdateRateHzCaptor.getAllValues()).containsExactly(FIRST_UPDATE_RATE_HZ,
+ SECOND_BIGGER_UPDATE_RATE_HZ, FIRST_UPDATE_RATE_HZ);
+ }
+
+ @Test
+ public void remove_registerNotCalledIfSmallerRateRemoved() {
+ assertThat(mCarPropertyEventCallbackController.add(mCarPropertyEventCallback,
+ FIRST_UPDATE_RATE_HZ)).isTrue();
+ assertThat(mCarPropertyEventCallbackController.add(mCarPropertyEventCallback2,
+ SECOND_BIGGER_UPDATE_RATE_HZ)).isTrue();
+ assertThat(mCarPropertyEventCallbackController.remove(mCarPropertyEventCallback)).isFalse();
+
+ verify(mRegistrationUpdateCallback, times(2)).register(mPropertyIdCaptor.capture(),
+ mUpdateRateHzCaptor.capture());
+ verify(mRegistrationUpdateCallback, never()).unregister(anyInt());
+ assertThat(mPropertyIdCaptor.getAllValues()).containsExactly(PROPERTY_ID, PROPERTY_ID);
+ assertThat(mUpdateRateHzCaptor.getAllValues()).containsExactly(FIRST_UPDATE_RATE_HZ,
+ SECOND_BIGGER_UPDATE_RATE_HZ);
+ }
+
+ @Test
+ public void remove_returnsTrueIfAllCallbacksRemoved() {
+ assertThat(mCarPropertyEventCallbackController.add(mCarPropertyEventCallback,
+ FIRST_UPDATE_RATE_HZ)).isTrue();
+ assertThat(mCarPropertyEventCallbackController.add(mCarPropertyEventCallback2,
+ SECOND_BIGGER_UPDATE_RATE_HZ)).isTrue();
+ assertThat(
+ mCarPropertyEventCallbackController.remove(mCarPropertyEventCallback2)).isFalse();
+ assertThat(mCarPropertyEventCallbackController.remove(mCarPropertyEventCallback)).isTrue();
+
+ verify(mRegistrationUpdateCallback, times(3)).register(mPropertyIdCaptor.capture(),
+ mUpdateRateHzCaptor.capture());
+ verify(mRegistrationUpdateCallback).unregister(PROPERTY_ID);
+ assertThat(mPropertyIdCaptor.getAllValues()).containsExactly(PROPERTY_ID, PROPERTY_ID,
+ PROPERTY_ID);
+ assertThat(mUpdateRateHzCaptor.getAllValues()).containsExactly(FIRST_UPDATE_RATE_HZ,
+ SECOND_BIGGER_UPDATE_RATE_HZ, FIRST_UPDATE_RATE_HZ);
+ }
+
+ @Test
+ public void forwardPropertyChanged_doesNothingIfNoCallbacksAdded() {
+ CarPropertyValue<Integer> carPropertyValue = new CarPropertyValue<>(PROPERTY_ID, AREA_ID_1,
+ 567);
+ mCarPropertyEventCallbackController.forwardPropertyChanged(
+ new CarPropertyEvent(CarPropertyEvent.PROPERTY_EVENT_PROPERTY_CHANGE,
+ carPropertyValue));
+
+ verify(mCarPropertyEventCallback, never()).onChangeEvent(any());
+ verify(mCarPropertyEventCallback, never()).onErrorEvent(anyInt(), anyInt());
+ verify(mCarPropertyEventCallback, never()).onErrorEvent(anyInt(), anyInt(), anyInt());
+ verify(mCarPropertyEventCallback2, never()).onChangeEvent(any());
+ verify(mCarPropertyEventCallback2, never()).onErrorEvent(anyInt(), anyInt());
+ verify(mCarPropertyEventCallback2, never()).onErrorEvent(anyInt(), anyInt(), anyInt());
+ }
+
+ @Test
+ public void forwardPropertyChanged_forwardsToCallback() {
+ assertThat(mCarPropertyEventCallbackController.add(mCarPropertyEventCallback,
+ CarPropertyManager.SENSOR_RATE_ONCHANGE)).isTrue();
+ mCarPropertyEventCallbackController.forwardPropertyChanged(
+ new CarPropertyEvent(CarPropertyEvent.PROPERTY_EVENT_PROPERTY_CHANGE,
+ GOOD_CAR_PROPERTY_VALUE));
+
+ verify(mCarPropertyEventCallback).onChangeEvent(GOOD_CAR_PROPERTY_VALUE);
+ verify(mCarPropertyEventCallback, never()).onErrorEvent(anyInt(), anyInt());
+ verify(mCarPropertyEventCallback, never()).onErrorEvent(anyInt(), anyInt(), anyInt());
+ }
+
+ @Test
+ public void forwardPropertyChanged_forwardsToMultipleCallbacks() {
+ assertThat(mCarPropertyEventCallbackController.add(mCarPropertyEventCallback,
+ CarPropertyManager.SENSOR_RATE_ONCHANGE)).isTrue();
+ assertThat(mCarPropertyEventCallbackController.add(mCarPropertyEventCallback2,
+ CarPropertyManager.SENSOR_RATE_ONCHANGE)).isTrue();
+ mCarPropertyEventCallbackController.forwardPropertyChanged(
+ new CarPropertyEvent(CarPropertyEvent.PROPERTY_EVENT_PROPERTY_CHANGE,
+ GOOD_CAR_PROPERTY_VALUE));
+
+ verify(mCarPropertyEventCallback).onChangeEvent(GOOD_CAR_PROPERTY_VALUE);
+ verify(mCarPropertyEventCallback, never()).onErrorEvent(anyInt(), anyInt());
+ verify(mCarPropertyEventCallback, never()).onErrorEvent(anyInt(), anyInt(), anyInt());
+ verify(mCarPropertyEventCallback2).onChangeEvent(GOOD_CAR_PROPERTY_VALUE);
+ verify(mCarPropertyEventCallback2, never()).onErrorEvent(anyInt(), anyInt());
+ verify(mCarPropertyEventCallback2, never()).onErrorEvent(anyInt(), anyInt(), anyInt());
+ }
+
+ @Test
+ public void forwardPropertyChanged_skipsStaleCarPropertyValues() {
+ assertThat(mCarPropertyEventCallbackController.add(mCarPropertyEventCallback,
+ CarPropertyManager.SENSOR_RATE_ONCHANGE)).isTrue();
+ mCarPropertyEventCallbackController.forwardPropertyChanged(
+ new CarPropertyEvent(CarPropertyEvent.PROPERTY_EVENT_PROPERTY_CHANGE,
+ GOOD_CAR_PROPERTY_VALUE));
+ mCarPropertyEventCallbackController.forwardPropertyChanged(
+ new CarPropertyEvent(CarPropertyEvent.PROPERTY_EVENT_PROPERTY_CHANGE,
+ STALE_CAR_PROPERTY_VALUE));
+
+ verify(mCarPropertyEventCallback).onChangeEvent(GOOD_CAR_PROPERTY_VALUE);
+ verify(mCarPropertyEventCallback, never()).onErrorEvent(anyInt(), anyInt());
+ verify(mCarPropertyEventCallback, never()).onErrorEvent(anyInt(), anyInt(), anyInt());
+ }
+
+ @Test
+ public void forwardPropertyChanged_skipsCarPropertyValuesWithNonZeroUpdateRate() {
+ assertThat(mCarPropertyEventCallbackController.add(mCarPropertyEventCallback,
+ FIRST_UPDATE_RATE_HZ)).isTrue();
+ mCarPropertyEventCallbackController.forwardPropertyChanged(
+ new CarPropertyEvent(CarPropertyEvent.PROPERTY_EVENT_PROPERTY_CHANGE,
+ GOOD_CAR_PROPERTY_VALUE));
+ mCarPropertyEventCallbackController.forwardPropertyChanged(
+ new CarPropertyEvent(CarPropertyEvent.PROPERTY_EVENT_PROPERTY_CHANGE,
+ ALMOST_FRESH_CAR_PROPERTY_VALUE));
+
+ verify(mCarPropertyEventCallback).onChangeEvent(mCarPropertyValueCaptor.capture());
+ verify(mCarPropertyEventCallback, never()).onErrorEvent(anyInt(), anyInt());
+ verify(mCarPropertyEventCallback, never()).onErrorEvent(anyInt(), anyInt(), anyInt());
+ assertThat(mCarPropertyValueCaptor.getAllValues()).containsExactly(GOOD_CAR_PROPERTY_VALUE);
+ }
+
+ @Test
+ public void forwardPropertyChanged_forwardsFreshCarPropertyValues() {
+ assertThat(mCarPropertyEventCallbackController.add(mCarPropertyEventCallback,
+ CarPropertyManager.SENSOR_RATE_ONCHANGE)).isTrue();
+ mCarPropertyEventCallbackController.forwardPropertyChanged(
+ new CarPropertyEvent(CarPropertyEvent.PROPERTY_EVENT_PROPERTY_CHANGE,
+ GOOD_CAR_PROPERTY_VALUE));
+ mCarPropertyEventCallbackController.forwardPropertyChanged(
+ new CarPropertyEvent(CarPropertyEvent.PROPERTY_EVENT_PROPERTY_CHANGE,
+ FRESH_CAR_PROPERTY_VALUE));
+
+ verify(mCarPropertyEventCallback, times(2)).onChangeEvent(
+ mCarPropertyValueCaptor.capture());
+ verify(mCarPropertyEventCallback, never()).onErrorEvent(anyInt(), anyInt());
+ verify(mCarPropertyEventCallback, never()).onErrorEvent(anyInt(), anyInt(), anyInt());
+ assertThat(mCarPropertyValueCaptor.getAllValues()).containsExactly(GOOD_CAR_PROPERTY_VALUE,
+ FRESH_CAR_PROPERTY_VALUE);
+ }
+
+ @Test
+ public void forwardPropertyChanged_forwardsFreshCarPropertyValuesWithNonZeroUpdateRate() {
+ assertThat(mCarPropertyEventCallbackController.add(mCarPropertyEventCallback,
+ FIRST_UPDATE_RATE_HZ)).isTrue();
+ mCarPropertyEventCallbackController.forwardPropertyChanged(
+ new CarPropertyEvent(CarPropertyEvent.PROPERTY_EVENT_PROPERTY_CHANGE,
+ GOOD_CAR_PROPERTY_VALUE));
+ mCarPropertyEventCallbackController.forwardPropertyChanged(
+ new CarPropertyEvent(CarPropertyEvent.PROPERTY_EVENT_PROPERTY_CHANGE,
+ FRESH_CAR_PROPERTY_VALUE));
+
+ verify(mCarPropertyEventCallback, times(2)).onChangeEvent(
+ mCarPropertyValueCaptor.capture());
+ verify(mCarPropertyEventCallback, never()).onErrorEvent(anyInt(), anyInt());
+ verify(mCarPropertyEventCallback, never()).onErrorEvent(anyInt(), anyInt(), anyInt());
+ assertThat(mCarPropertyValueCaptor.getAllValues()).containsExactly(GOOD_CAR_PROPERTY_VALUE,
+ FRESH_CAR_PROPERTY_VALUE);
+ }
+
+ @Test
+ public void forwardPropertyChanged_forwardsStaleCarPropertyValuesWithDifferentAreaId() {
+ assertThat(mCarPropertyEventCallbackController.add(mCarPropertyEventCallback,
+ CarPropertyManager.SENSOR_RATE_ONCHANGE)).isTrue();
+ mCarPropertyEventCallbackController.forwardPropertyChanged(
+ new CarPropertyEvent(CarPropertyEvent.PROPERTY_EVENT_PROPERTY_CHANGE,
+ GOOD_CAR_PROPERTY_VALUE));
+ mCarPropertyEventCallbackController.forwardPropertyChanged(
+ new CarPropertyEvent(CarPropertyEvent.PROPERTY_EVENT_PROPERTY_CHANGE,
+ STALE_CAR_PROPERTY_VALUE_WITH_DIFFERENT_AREA_ID));
+
+ verify(mCarPropertyEventCallback, times(2)).onChangeEvent(
+ mCarPropertyValueCaptor.capture());
+ verify(mCarPropertyEventCallback, never()).onErrorEvent(anyInt(), anyInt());
+ verify(mCarPropertyEventCallback, never()).onErrorEvent(anyInt(), anyInt(), anyInt());
+ assertThat(mCarPropertyValueCaptor.getAllValues()).containsExactly(GOOD_CAR_PROPERTY_VALUE,
+ STALE_CAR_PROPERTY_VALUE_WITH_DIFFERENT_AREA_ID);
+ }
+
+ @Test
+ public void forwardErrorEvent_doesNothingIfNoCallbacksAdded() {
+ CarPropertyValue<Integer> carPropertyValue = new CarPropertyValue<>(PROPERTY_ID, AREA_ID_1,
+ 567);
+ mCarPropertyEventCallbackController.forwardErrorEvent(
+ new CarPropertyEvent(CarPropertyEvent.PROPERTY_EVENT_ERROR, carPropertyValue));
+
+ verify(mCarPropertyEventCallback, never()).onChangeEvent(any());
+ verify(mCarPropertyEventCallback, never()).onErrorEvent(anyInt(), anyInt());
+ verify(mCarPropertyEventCallback, never()).onErrorEvent(anyInt(), anyInt(), anyInt());
+ verify(mCarPropertyEventCallback2, never()).onChangeEvent(any());
+ verify(mCarPropertyEventCallback2, never()).onErrorEvent(anyInt(), anyInt());
+ verify(mCarPropertyEventCallback2, never()).onErrorEvent(anyInt(), anyInt(), anyInt());
+ }
+
+ @Test
+ public void forwardErrorEvent_forwardsToCallback() {
+ assertThat(mCarPropertyEventCallbackController.add(mCarPropertyEventCallback,
+ CarPropertyManager.SENSOR_RATE_ONCHANGE)).isTrue();
+ mCarPropertyEventCallbackController.forwardErrorEvent(
+ new CarPropertyEvent(CarPropertyEvent.PROPERTY_EVENT_PROPERTY_CHANGE,
+ ERROR_CAR_PROPERTY_VALUE,
+ CarPropertyManager.CAR_SET_PROPERTY_ERROR_CODE_INVALID_ARG));
+
+ verify(mCarPropertyEventCallback, never()).onChangeEvent(any());
+ verify(mCarPropertyEventCallback, never()).onErrorEvent(anyInt(), anyInt());
+ verify(mCarPropertyEventCallback).onErrorEvent(PROPERTY_ID, AREA_ID_1,
+ CarPropertyManager.CAR_SET_PROPERTY_ERROR_CODE_INVALID_ARG);
+ }
+
+ @Test
+ public void forwardErrorEvent_forwardsToMultipleCallbacks() {
+ assertThat(mCarPropertyEventCallbackController.add(mCarPropertyEventCallback,
+ CarPropertyManager.SENSOR_RATE_ONCHANGE)).isTrue();
+ assertThat(mCarPropertyEventCallbackController.add(mCarPropertyEventCallback2,
+ CarPropertyManager.SENSOR_RATE_ONCHANGE)).isTrue();
+ mCarPropertyEventCallbackController.forwardErrorEvent(
+ new CarPropertyEvent(CarPropertyEvent.PROPERTY_EVENT_PROPERTY_CHANGE,
+ ERROR_CAR_PROPERTY_VALUE,
+ CarPropertyManager.CAR_SET_PROPERTY_ERROR_CODE_INVALID_ARG));
+
+ verify(mCarPropertyEventCallback, never()).onChangeEvent(any());
+ verify(mCarPropertyEventCallback, never()).onErrorEvent(anyInt(), anyInt());
+ verify(mCarPropertyEventCallback).onErrorEvent(PROPERTY_ID, AREA_ID_1,
+ CarPropertyManager.CAR_SET_PROPERTY_ERROR_CODE_INVALID_ARG);
+ verify(mCarPropertyEventCallback2, never()).onChangeEvent(any());
+ verify(mCarPropertyEventCallback2, never()).onErrorEvent(anyInt(), anyInt());
+ verify(mCarPropertyEventCallback2).onErrorEvent(PROPERTY_ID, AREA_ID_1,
+ CarPropertyManager.CAR_SET_PROPERTY_ERROR_CODE_INVALID_ARG);
+ }
+}
diff --git a/tests/carservice_unit_test/src/com/android/car/internal/util/VersionUtilsTest.java b/tests/carservice_unit_test/src/com/android/car/internal/util/VersionUtilsTest.java
new file mode 100644
index 0000000..2d91aff
--- /dev/null
+++ b/tests/carservice_unit_test/src/com/android/car/internal/util/VersionUtilsTest.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2022 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.internal.util;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.junit.Assert.assertThrows;
+
+import android.car.PlatformVersion;
+import android.car.PlatformVersionMismatchException;
+
+import org.junit.Test;
+
+public class VersionUtilsTest {
+
+ @Test
+ public void testMismatchVersionException() {
+ assertThrows(PlatformVersionMismatchException.class,
+ () -> VersionUtils.assertPlatformVersionAtLeast(
+ PlatformVersion.forMajorAndMinorVersions(Integer.MAX_VALUE,
+ Integer.MAX_VALUE)));
+ }
+
+ @Test
+ public void testNoExceptionForCorrectVersion() {
+ VersionUtils.assertPlatformVersionAtLeast(
+ PlatformVersion.forMajorAndMinorVersions(33, 0));
+ }
+
+ @Test
+ public void testIsPlatformVersionAtLeastSuccess() {
+ assertThat(VersionUtils.isPlatformVersionAtLeast(
+ PlatformVersion.forMajorAndMinorVersions(33, 0))).isTrue();
+ }
+
+ @Test
+ public void testIsPlatformVersionAtLeastFailure() {
+ assertThat(VersionUtils.isPlatformVersionAtLeast(
+ PlatformVersion.forMajorAndMinorVersions(Integer.MAX_VALUE, Integer.MAX_VALUE)))
+ .isFalse();
+ }
+
+}
diff --git a/tests/carservice_unit_test/src/com/android/car/os/CarPerformanceServiceUnitTest.java b/tests/carservice_unit_test/src/com/android/car/os/CarPerformanceServiceUnitTest.java
new file mode 100644
index 0000000..8481cd9
--- /dev/null
+++ b/tests/carservice_unit_test/src/com/android/car/os/CarPerformanceServiceUnitTest.java
@@ -0,0 +1,165 @@
+/*
+ * Copyright (C) 2022 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.os;
+
+import static com.google.common.truth.Truth.assertWithMessage;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+import static org.testng.Assert.expectThrows;
+
+import android.car.os.CpuAvailabilityMonitoringConfig;
+import android.car.os.ICpuAvailabilityChangeListener;
+import android.car.test.mocks.AbstractExtendedMockitoTestCase;
+import android.content.Context;
+import android.os.IBinder;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnitRunner;
+
+/**
+ * <p>This class contains unit tests for the {@link CarPerformanceService}.
+ */
+@RunWith(MockitoJUnitRunner.class)
+public final class CarPerformanceServiceUnitTest extends AbstractExtendedMockitoTestCase {
+
+ @Mock private Context mMockContext;
+
+ private CarPerformanceService mCarPerformanceService;
+
+ public CarPerformanceServiceUnitTest() {
+ super(CarPerformanceService.TAG);
+ }
+
+ @Before
+ public void setUp() throws Exception {
+ mCarPerformanceService = new CarPerformanceService(mMockContext);
+ mCarPerformanceService.init();
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ mCarPerformanceService.release();
+ }
+
+ @Test
+ public void testAddRemoveCpuAvailabilityChangeListener() throws Exception {
+ ICpuAvailabilityChangeListener mockListener = createMockCpuAvailabilityChangeListener();
+ CpuAvailabilityMonitoringConfig config = new CpuAvailabilityMonitoringConfig.Builder(
+ /* lowerBoundPercent= */ 10, /* upperBoundPercent= */ 90,
+ /* timeoutInSeconds= */ 300).build();
+ mCarPerformanceService.addCpuAvailabilityChangeListener(config, mockListener);
+
+ IBinder mockBinder = mockListener.asBinder();
+ verify(mockBinder).linkToDeath(any(IBinder.DeathRecipient.class), anyInt());
+
+ mCarPerformanceService.removeCpuAvailabilityChangeListener(mockListener);
+
+ verify(mockBinder).unlinkToDeath(any(IBinder.DeathRecipient.class), anyInt());
+ }
+
+ @Test
+ public void testDuplicateAddCpuAvailabilityChangeListener() throws Exception {
+ ICpuAvailabilityChangeListener mockListener = createMockCpuAvailabilityChangeListener();
+ CpuAvailabilityMonitoringConfig config = new CpuAvailabilityMonitoringConfig.Builder(
+ /* lowerBoundPercent= */ 10, /* upperBoundPercent= */ 90,
+ /* timeoutInSeconds= */ 300).build();
+ mCarPerformanceService.addCpuAvailabilityChangeListener(config, mockListener);
+
+ IBinder mockBinder = mockListener.asBinder();
+ verify(mockBinder).linkToDeath(any(IBinder.DeathRecipient.class), anyInt());
+
+ mCarPerformanceService.addCpuAvailabilityChangeListener(config, mockListener);
+
+ verify(mockBinder, times(2)).linkToDeath(any(IBinder.DeathRecipient.class), anyInt());
+ verify(mockBinder).unlinkToDeath(any(IBinder.DeathRecipient.class), anyInt());
+
+ mCarPerformanceService.removeCpuAvailabilityChangeListener(mockListener);
+
+ verify(mockBinder, times(2)).unlinkToDeath(any(IBinder.DeathRecipient.class), anyInt());
+
+ mCarPerformanceService.addCpuAvailabilityChangeListener(config, mockListener);
+
+ verify(mockBinder, times(3)).linkToDeath(any(IBinder.DeathRecipient.class), anyInt());
+ }
+
+ @Test
+ public void testAddCpuAvailabilityChangeListenerThrowsExceptions() throws Exception {
+ ICpuAvailabilityChangeListener mockListener = createMockCpuAvailabilityChangeListener();
+ CpuAvailabilityMonitoringConfig goodConfig =
+ new CpuAvailabilityMonitoringConfig.Builder(/* lowerBoundPercent= */ 10,
+ /* upperBoundPercent= */ 90, /* timeoutInSeconds= */ 300).build();
+
+ NullPointerException npeThrown = expectThrows(NullPointerException.class,
+ () -> mCarPerformanceService.addCpuAvailabilityChangeListener(null, mockListener));
+ assertWithMessage("NullPointerException thrown on null config")
+ .that(npeThrown).hasMessageThat().contains("Configuration must be non-null");
+
+ npeThrown = expectThrows(NullPointerException.class,
+ () -> mCarPerformanceService.addCpuAvailabilityChangeListener(goodConfig, null));
+ assertWithMessage("NullPointerException thrown on null listener")
+ .that(npeThrown).hasMessageThat().contains("Listener must be non-null");
+
+ CpuAvailabilityMonitoringConfig ignoreBoundsConfig =
+ new CpuAvailabilityMonitoringConfig.Builder(
+ CpuAvailabilityMonitoringConfig.IGNORE_PERCENT_LOWER_BOUND,
+ CpuAvailabilityMonitoringConfig.IGNORE_PERCENT_UPPER_BOUND,
+ /* timeoutInSeconds= */ 300).build();
+ IllegalArgumentException iaeThrown = expectThrows(IllegalArgumentException.class,
+ () -> mCarPerformanceService.addCpuAvailabilityChangeListener(ignoreBoundsConfig,
+ mockListener));
+ assertWithMessage("IllegalArgumentException thrown on ignore lower/uppwer bound percents")
+ .that(iaeThrown).hasMessageThat().contains(
+ "lower bound percent(0) and upper bound percent(100)");
+
+ CpuAvailabilityMonitoringConfig mismatchBoundsConfig =
+ new CpuAvailabilityMonitoringConfig.Builder(/* lowerBoundPercent= */ 90,
+ /* upperBoundPercent= */ 10, /* timeoutInSeconds= */ 300).build();
+ iaeThrown = expectThrows(IllegalArgumentException.class,
+ () -> mCarPerformanceService.addCpuAvailabilityChangeListener(mismatchBoundsConfig,
+ mockListener));
+ assertWithMessage("IllegalArgumentException thrown on invalid lower/upper bound percents")
+ .that(iaeThrown).hasMessageThat().contains(
+ "lower bound percent(90) and upper bound percent(10)");
+ }
+
+ @Test
+ public void testRemoveUnaddedCpuAvailabilityChangeListener() throws Exception {
+ ICpuAvailabilityChangeListener mockListener = createMockCpuAvailabilityChangeListener();
+
+ IBinder mockBinder = mockListener.asBinder();
+
+ mCarPerformanceService.removeCpuAvailabilityChangeListener(mockListener);
+
+ verify(mockBinder, never()).unlinkToDeath(any(IBinder.DeathRecipient.class), anyInt());
+ }
+
+ private static ICpuAvailabilityChangeListener createMockCpuAvailabilityChangeListener() {
+ ICpuAvailabilityChangeListener listener = mock(ICpuAvailabilityChangeListener.Stub.class);
+ when(listener.asBinder()).thenCallRealMethod();
+ return listener;
+ }
+}
diff --git a/tests/carservice_unit_test/src/com/android/car/os/CpuInfoReaderUnitTest.java b/tests/carservice_unit_test/src/com/android/car/os/CpuInfoReaderUnitTest.java
new file mode 100644
index 0000000..63c356c
--- /dev/null
+++ b/tests/carservice_unit_test/src/com/android/car/os/CpuInfoReaderUnitTest.java
@@ -0,0 +1,448 @@
+/*
+ * Copyright (C) 2022 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.os;
+
+import static com.android.car.os.CpuInfoReader.FLAG_CPUSET_CATEGORY_BACKGROUND;
+import static com.android.car.os.CpuInfoReader.FLAG_CPUSET_CATEGORY_TOP_APP;
+
+import static com.google.common.truth.Truth.assertWithMessage;
+
+import android.car.test.mocks.AbstractExtendedMockitoTestCase;
+import android.content.Context;
+import android.content.res.AssetManager;
+import android.util.Slog;
+
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import libcore.io.Streams;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.junit.MockitoJUnitRunner;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * <p>This class contains unit tests for the {@link CarPerformanceService}.
+ */
+@RunWith(MockitoJUnitRunner.class)
+public final class CpuInfoReaderUnitTest extends AbstractExtendedMockitoTestCase {
+ private static final String TAG = CpuInfoReaderUnitTest.class.getSimpleName();
+ private static final String ROOT_DIR_NAME = "os";
+ private static final String VALID_CPUSET_DIR = "valid_cpuset";
+ private static final String VALID_CPUFREQ_WITH_TIME_IN_STATE_DIR =
+ "valid_cpufreq_with_time_in_state";
+ private static final String VALID_CPUFREQ_WITH_TIME_IN_STATE_2_DIR =
+ "valid_cpufreq_with_time_in_state_2";
+ private static final String VALID_CPUFREQ_WITHOUT_TIME_IN_STATE_DIR =
+ "valid_cpufreq_without_time_in_state";
+ private static final String VALID_CPUFREQ_WITHOUT_TIME_IN_STATE_2_DIR =
+ "valid_cpufreq_without_time_in_state_2";
+ private static final String VALID_PROC_STAT = "valid_proc_stat";
+ private static final String VALID_PROC_STAT_2 = "valid_proc_stat_2";
+ private static final String CORRUPTED_CPUFREQ_DIR = "corrupted_cpufreq";
+ private static final String CORRUPTED_CPUSET_DIR = "corrupted_cpuset";
+ private static final String CORRUPTED_PROC_STAT = "corrupted_proc_stat";
+ private static final String EMPTY_DIR = "empty_dir";
+ private static final String EMPTY_FILE = "empty_file";
+
+ private final Context mContext =
+ InstrumentationRegistry.getInstrumentation().getTargetContext();
+ private final File mCacheRoot = new File(mContext.getCacheDir(), ROOT_DIR_NAME);
+ private final AssetManager mAssetManager = mContext.getAssets();
+
+ private CpuInfoReader mCpuInfoReader;
+
+ public CpuInfoReaderUnitTest() {
+ super(CpuInfoReaderUnitTest.TAG);
+ }
+
+ @Before
+ public void setUp() throws Exception {
+ copyAssets(ROOT_DIR_NAME, mContext.getCacheDir());
+ assertWithMessage("Cache root dir %s", mCacheRoot.getAbsolutePath())
+ .that(mCacheRoot.exists()).isTrue();
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ if (!deleteDirectory(mCacheRoot)) {
+ Slog.e(TAG, "Failed to delete cache root directory " + mCacheRoot.getAbsolutePath());
+ }
+ }
+
+ @Test
+ public void testReadCpuInfoWithTimeInState() throws Exception {
+ mCpuInfoReader = new CpuInfoReader(getCacheFile(VALID_CPUSET_DIR),
+ getCacheFile(VALID_CPUFREQ_WITH_TIME_IN_STATE_DIR), getCacheFile(VALID_PROC_STAT));
+ mCpuInfoReader.init();
+ List<CpuInfoReader.CpuInfo> actualCpuInfos = mCpuInfoReader.readCpuInfos();
+ List<CpuInfoReader.CpuInfo> expectedCpuInfos = List.of(
+ new CpuInfoReader.CpuInfo(/* cpuCore= */ 0, FLAG_CPUSET_CATEGORY_TOP_APP,
+ /* curCpuFreqKHz= */ 488095, /* maxCpuFreqKHz= */ 2500000,
+ new CpuInfoReader.CpuUsageStats(/* userTimeMillis= */ 32249610,
+ /* niceTimeMillis= */ 7950930, /* systemTimeMillis= */ 52227050,
+ /* idleTimeMillis= */ 409036950, /* iowaitTimeMillis= */ 1322810,
+ /* irqTimeMillis= */ 8146740, /* softirqTimeMillis= */ 428970,
+ /* stealTimeMillis= */ 81950, /* guestTimeMillis= */ 0,
+ /* guestNiceTimeMillis= */ 0)),
+ new CpuInfoReader.CpuInfo(/* cpuCore= */ 1, FLAG_CPUSET_CATEGORY_TOP_APP,
+ /* curCpuFreqKHz= */ 502380, /* maxCpuFreqKHz= */ 2800000,
+ new CpuInfoReader.CpuUsageStats(/* userTimeMillis= */ 28949280,
+ /* niceTimeMillis= */ 7799450, /* systemTimeMillis= */ 54004020,
+ /* idleTimeMillis= */ 402707120, /* iowaitTimeMillis= */ 1186960,
+ /* irqTimeMillis= */ 14786940, /* softirqTimeMillis= */ 1498130,
+ /* stealTimeMillis= */ 78780, /* guestTimeMillis= */ 0,
+ /* guestNiceTimeMillis= */ 0)),
+ new CpuInfoReader.CpuInfo(/* cpuCore= */ 2,
+ FLAG_CPUSET_CATEGORY_TOP_APP | FLAG_CPUSET_CATEGORY_BACKGROUND,
+ /* curCpuFreqKHz= */ 464285, /* maxCpuFreqKHz= */ 2000000,
+ new CpuInfoReader.CpuUsageStats(/* userTimeMillis= */ 28959280,
+ /* niceTimeMillis= */ 7789450, /* systemTimeMillis= */ 54014020,
+ /* idleTimeMillis= */ 402717120, /* iowaitTimeMillis= */ 1166960,
+ /* irqTimeMillis= */ 14796940, /* softirqTimeMillis= */ 1478130,
+ /* stealTimeMillis= */ 88780, /* guestTimeMillis= */ 0,
+ /* guestNiceTimeMillis= */ 0)),
+ new CpuInfoReader.CpuInfo(/* cpuCore= */ 3,
+ FLAG_CPUSET_CATEGORY_TOP_APP | FLAG_CPUSET_CATEGORY_BACKGROUND,
+ /* curCpuFreqKHz= */ 464285, /* maxCpuFreqKHz= */ 2000000,
+ new CpuInfoReader.CpuUsageStats(/* userTimeMillis= */ 32349610,
+ /* niceTimeMillis= */ 7850930, /* systemTimeMillis= */ 52127050,
+ /* idleTimeMillis= */ 409136950, /* iowaitTimeMillis= */ 1332810,
+ /* irqTimeMillis= */ 8136740, /* softirqTimeMillis= */ 438970,
+ /* stealTimeMillis= */ 71950, /* guestTimeMillis= */ 0,
+ /* guestNiceTimeMillis= */ 0)));
+
+ assertWithMessage("Cpu infos").that(actualCpuInfos)
+ .containsExactlyElementsIn(expectedCpuInfos);
+
+ mCpuInfoReader.setCpuFreqDir(getCacheFile(VALID_CPUFREQ_WITH_TIME_IN_STATE_2_DIR));
+ mCpuInfoReader.setProcStatFile(getCacheFile(VALID_PROC_STAT_2));
+
+ actualCpuInfos = mCpuInfoReader.readCpuInfos();
+ expectedCpuInfos = List.of(
+ new CpuInfoReader.CpuInfo(/* cpuCore= */ 0, FLAG_CPUSET_CATEGORY_TOP_APP,
+ /* curCpuFreqKHz= */ 419354, /* maxCpuFreqKHz= */ 2500000,
+ new CpuInfoReader.CpuUsageStats(/* userTimeMillis= */ 10000000,
+ /* niceTimeMillis= */ 1000000, /* systemTimeMillis= */ 10000000,
+ /* idleTimeMillis= */ 110000000, /* iowaitTimeMillis= */ 1100000,
+ /* irqTimeMillis= */ 1400000, /* softirqTimeMillis= */ 80000,
+ /* stealTimeMillis= */ 21000, /* guestTimeMillis= */ 0,
+ /* guestNiceTimeMillis= */ 0)),
+ new CpuInfoReader.CpuInfo(/* cpuCore= */ 1, FLAG_CPUSET_CATEGORY_TOP_APP,
+ /* curCpuFreqKHz= */ 429032, /* maxCpuFreqKHz= */ 2800000,
+ new CpuInfoReader.CpuUsageStats(/* userTimeMillis= */ 900000,
+ /* niceTimeMillis= */ 1000000, /* systemTimeMillis= */ 10000000,
+ /* idleTimeMillis= */ 1000000, /* iowaitTimeMillis= */ 90000,
+ /* irqTimeMillis= */ 200000, /* softirqTimeMillis= */ 100000,
+ /* stealTimeMillis= */ 100000, /* guestTimeMillis= */ 0,
+ /* guestNiceTimeMillis= */ 0)),
+ new CpuInfoReader.CpuInfo(/* cpuCore= */ 2,
+ FLAG_CPUSET_CATEGORY_TOP_APP | FLAG_CPUSET_CATEGORY_BACKGROUND,
+ /* curCpuFreqKHz= */ 403225, /* maxCpuFreqKHz= */ 2000000,
+ new CpuInfoReader.CpuUsageStats(/* userTimeMillis= */ 10000000,
+ /* niceTimeMillis= */ 2000000, /* systemTimeMillis= */ 0,
+ /* idleTimeMillis= */ 10000000, /* iowaitTimeMillis= */ 1000000,
+ /* irqTimeMillis= */ 20000000, /* softirqTimeMillis= */ 1000000,
+ /* stealTimeMillis= */ 100000, /* guestTimeMillis= */ 0,
+ /* guestNiceTimeMillis= */ 0)),
+ new CpuInfoReader.CpuInfo(/* cpuCore= */ 3,
+ FLAG_CPUSET_CATEGORY_TOP_APP | FLAG_CPUSET_CATEGORY_BACKGROUND,
+ /* curCpuFreqKHz= */ 403225, /* maxCpuFreqKHz= */ 2000000,
+ new CpuInfoReader.CpuUsageStats(/* userTimeMillis= */ 2000000,
+ /* niceTimeMillis= */ 1000000, /* systemTimeMillis= */ 1000000,
+ /* idleTimeMillis= */ 100000, /* iowaitTimeMillis= */ 100000,
+ /* irqTimeMillis= */ 100000, /* softirqTimeMillis= */ 1000000,
+ /* stealTimeMillis= */ 1000, /* guestTimeMillis= */ 0,
+ /* guestNiceTimeMillis= */ 0)));
+
+ assertWithMessage("Second snapshot of cpu infos").that(actualCpuInfos)
+ .containsExactlyElementsIn(expectedCpuInfos);
+ }
+
+ @Test
+ public void testReadCpuInfoWithoutTimeInState() throws Exception {
+ mCpuInfoReader = new CpuInfoReader(getCacheFile(VALID_CPUSET_DIR),
+ getCacheFile(VALID_CPUFREQ_WITHOUT_TIME_IN_STATE_DIR),
+ getCacheFile(VALID_PROC_STAT));
+ mCpuInfoReader.init();
+ List<CpuInfoReader.CpuInfo> actualCpuInfos = mCpuInfoReader.readCpuInfos();
+ List<CpuInfoReader.CpuInfo> expectedCpuInfos = List.of(
+ new CpuInfoReader.CpuInfo(/* cpuCore= */ 0, FLAG_CPUSET_CATEGORY_TOP_APP,
+ /* curCpuFreqKHz= */ 1230000, /* maxCpuFreqKHz= */ 2500000,
+ new CpuInfoReader.CpuUsageStats(/* userTimeMillis= */ 32249610,
+ /* niceTimeMillis= */ 7950930, /* systemTimeMillis= */ 52227050,
+ /* idleTimeMillis= */ 409036950, /* iowaitTimeMillis= */ 1322810,
+ /* irqTimeMillis= */ 8146740, /* softirqTimeMillis= */ 428970,
+ /* stealTimeMillis= */ 81950, /* guestTimeMillis= */ 0,
+ /* guestNiceTimeMillis= */ 0)),
+ new CpuInfoReader.CpuInfo(/* cpuCore= */ 1, FLAG_CPUSET_CATEGORY_TOP_APP,
+ /* curCpuFreqKHz= */ 1450000, /* maxCpuFreqKHz= */ 2800000,
+ new CpuInfoReader.CpuUsageStats(/* userTimeMillis= */ 28949280,
+ /* niceTimeMillis= */ 7799450, /* systemTimeMillis= */ 54004020,
+ /* idleTimeMillis= */ 402707120, /* iowaitTimeMillis= */ 1186960,
+ /* irqTimeMillis= */ 14786940, /* softirqTimeMillis= */ 1498130,
+ /* stealTimeMillis= */ 78780, /* guestTimeMillis= */ 0,
+ /* guestNiceTimeMillis= */ 0)),
+ new CpuInfoReader.CpuInfo(/* cpuCore= */ 2,
+ FLAG_CPUSET_CATEGORY_TOP_APP | FLAG_CPUSET_CATEGORY_BACKGROUND,
+ /* curCpuFreqKHz= */ 1000000, /* maxCpuFreqKHz= */ 2000000,
+ new CpuInfoReader.CpuUsageStats(/* userTimeMillis= */ 28959280,
+ /* niceTimeMillis= */ 7789450, /* systemTimeMillis= */ 54014020,
+ /* idleTimeMillis= */ 402717120, /* iowaitTimeMillis= */ 1166960,
+ /* irqTimeMillis= */ 14796940, /* softirqTimeMillis= */ 1478130,
+ /* stealTimeMillis= */ 88780, /* guestTimeMillis= */ 0,
+ /* guestNiceTimeMillis= */ 0)),
+ new CpuInfoReader.CpuInfo(/* cpuCore= */ 3,
+ FLAG_CPUSET_CATEGORY_TOP_APP | FLAG_CPUSET_CATEGORY_BACKGROUND,
+ /* curCpuFreqKHz= */ 1000000, /* maxCpuFreqKHz= */ 2000000,
+ new CpuInfoReader.CpuUsageStats(/* userTimeMillis= */ 32349610,
+ /* niceTimeMillis= */ 7850930, /* systemTimeMillis= */ 52127050,
+ /* idleTimeMillis= */ 409136950, /* iowaitTimeMillis= */ 1332810,
+ /* irqTimeMillis= */ 8136740, /* softirqTimeMillis= */ 438970,
+ /* stealTimeMillis= */ 71950, /* guestTimeMillis= */ 0,
+ /* guestNiceTimeMillis= */ 0)));
+
+ assertWithMessage("Cpu infos").that(actualCpuInfos)
+ .containsExactlyElementsIn(expectedCpuInfos);
+
+ mCpuInfoReader.setCpuFreqDir(getCacheFile(VALID_CPUFREQ_WITHOUT_TIME_IN_STATE_2_DIR));
+ mCpuInfoReader.setProcStatFile(getCacheFile(VALID_PROC_STAT_2));
+
+ actualCpuInfos = mCpuInfoReader.readCpuInfos();
+ expectedCpuInfos = List.of(
+ new CpuInfoReader.CpuInfo(/* cpuCore= */ 0, FLAG_CPUSET_CATEGORY_TOP_APP,
+ /* curCpuFreqKHz= */ 1000000, /* maxCpuFreqKHz= */ 2500000,
+ new CpuInfoReader.CpuUsageStats(/* userTimeMillis= */ 10000000,
+ /* niceTimeMillis= */ 1000000, /* systemTimeMillis= */ 10000000,
+ /* idleTimeMillis= */ 110000000, /* iowaitTimeMillis= */ 1100000,
+ /* irqTimeMillis= */ 1400000, /* softirqTimeMillis= */ 80000,
+ /* stealTimeMillis= */ 21000, /* guestTimeMillis= */ 0,
+ /* guestNiceTimeMillis= */ 0)),
+ new CpuInfoReader.CpuInfo(/* cpuCore= */ 1, FLAG_CPUSET_CATEGORY_TOP_APP,
+ /* curCpuFreqKHz= */ 2800000, /* maxCpuFreqKHz= */ 2800000,
+ new CpuInfoReader.CpuUsageStats(/* userTimeMillis= */ 900000,
+ /* niceTimeMillis= */ 1000000, /* systemTimeMillis= */ 10000000,
+ /* idleTimeMillis= */ 1000000, /* iowaitTimeMillis= */ 90000,
+ /* irqTimeMillis= */ 200000, /* softirqTimeMillis= */ 100000,
+ /* stealTimeMillis= */ 100000, /* guestTimeMillis= */ 0,
+ /* guestNiceTimeMillis= */ 0)),
+ new CpuInfoReader.CpuInfo(/* cpuCore= */ 2,
+ FLAG_CPUSET_CATEGORY_TOP_APP | FLAG_CPUSET_CATEGORY_BACKGROUND,
+ /* curCpuFreqKHz= */ 2000000, /* maxCpuFreqKHz= */ 2000000,
+ new CpuInfoReader.CpuUsageStats(/* userTimeMillis= */ 10000000,
+ /* niceTimeMillis= */ 2000000, /* systemTimeMillis= */ 0,
+ /* idleTimeMillis= */ 10000000, /* iowaitTimeMillis= */ 1000000,
+ /* irqTimeMillis= */ 20000000, /* softirqTimeMillis= */ 1000000,
+ /* stealTimeMillis= */ 100000, /* guestTimeMillis= */ 0,
+ /* guestNiceTimeMillis= */ 0)),
+ new CpuInfoReader.CpuInfo(/* cpuCore= */ 3,
+ FLAG_CPUSET_CATEGORY_TOP_APP | FLAG_CPUSET_CATEGORY_BACKGROUND,
+ /* curCpuFreqKHz= */ 2000000, /* maxCpuFreqKHz= */ 2000000,
+ new CpuInfoReader.CpuUsageStats(/* userTimeMillis= */ 2000000,
+ /* niceTimeMillis= */ 1000000, /* systemTimeMillis= */ 1000000,
+ /* idleTimeMillis= */ 100000, /* iowaitTimeMillis= */ 100000,
+ /* irqTimeMillis= */ 100000, /* softirqTimeMillis= */ 1000000,
+ /* stealTimeMillis= */ 1000, /* guestTimeMillis= */ 0,
+ /* guestNiceTimeMillis= */ 0)));
+
+ assertWithMessage("Second snapshot of cpu infos").that(actualCpuInfos)
+ .containsExactlyElementsIn(expectedCpuInfos);
+ }
+
+ @Test
+ public void testReadCpuInfoWithCorruptedCpuset() throws Exception {
+ mCpuInfoReader = new CpuInfoReader(getCacheFile(CORRUPTED_CPUSET_DIR),
+ getCacheFile(VALID_CPUFREQ_WITH_TIME_IN_STATE_DIR),
+ getCacheFile(VALID_PROC_STAT));
+ mCpuInfoReader.init();
+ List<CpuInfoReader.CpuInfo> actualCpuInfos = mCpuInfoReader.readCpuInfos();
+ List<CpuInfoReader.CpuInfo> expectedCpuInfos = List.of(
+ new CpuInfoReader.CpuInfo(/* cpuCore= */ 0, FLAG_CPUSET_CATEGORY_TOP_APP,
+ /* curCpuFreqKHz= */ 488095, /* maxCpuFreqKHz= */ 2500000,
+ new CpuInfoReader.CpuUsageStats(/* userTimeMillis= */ 32249610,
+ /* niceTimeMillis= */ 7950930, /* systemTimeMillis= */ 52227050,
+ /* idleTimeMillis= */ 409036950, /* iowaitTimeMillis= */ 1322810,
+ /* irqTimeMillis= */ 8146740, /* softirqTimeMillis= */ 428970,
+ /* stealTimeMillis= */ 81950, /* guestTimeMillis= */ 0,
+ /* guestNiceTimeMillis= */ 0)),
+ new CpuInfoReader.CpuInfo(/* cpuCore= */ 1, FLAG_CPUSET_CATEGORY_TOP_APP,
+ /* curCpuFreqKHz= */ 502380, /* maxCpuFreqKHz= */ 2800000,
+ new CpuInfoReader.CpuUsageStats(/* userTimeMillis= */ 28949280,
+ /* niceTimeMillis= */ 7799450, /* systemTimeMillis= */ 54004020,
+ /* idleTimeMillis= */ 402707120, /* iowaitTimeMillis= */ 1186960,
+ /* irqTimeMillis= */ 14786940, /* softirqTimeMillis= */ 1498130,
+ /* stealTimeMillis= */ 78780, /* guestTimeMillis= */ 0,
+ /* guestNiceTimeMillis= */ 0)),
+ new CpuInfoReader.CpuInfo(/* cpuCore= */ 2, FLAG_CPUSET_CATEGORY_TOP_APP,
+ /* curCpuFreqKHz= */ 464285, /* maxCpuFreqKHz= */ 2000000,
+ new CpuInfoReader.CpuUsageStats(/* userTimeMillis= */ 28959280,
+ /* niceTimeMillis= */ 7789450, /* systemTimeMillis= */ 54014020,
+ /* idleTimeMillis= */ 402717120, /* iowaitTimeMillis= */ 1166960,
+ /* irqTimeMillis= */ 14796940, /* softirqTimeMillis= */ 1478130,
+ /* stealTimeMillis= */ 88780, /* guestTimeMillis= */ 0,
+ /* guestNiceTimeMillis= */ 0)));
+
+ assertWithMessage("Cpu infos").that(actualCpuInfos)
+ .containsExactlyElementsIn(expectedCpuInfos);
+ }
+
+ @Test
+ public void testReadCpuInfoWithCorruptedCpufreq() throws Exception {
+ mCpuInfoReader = new CpuInfoReader(getCacheFile(VALID_CPUSET_DIR),
+ getCacheFile(CORRUPTED_CPUFREQ_DIR), getCacheFile(VALID_PROC_STAT));
+ mCpuInfoReader.init();
+ List<CpuInfoReader.CpuInfo> actualCpuInfos = mCpuInfoReader.readCpuInfos();
+ List<CpuInfoReader.CpuInfo> expectedCpuInfos = List.of(
+ new CpuInfoReader.CpuInfo(/* cpuCore= */ 1, FLAG_CPUSET_CATEGORY_TOP_APP,
+ /* curCpuFreqKHz= */ 3000000, /* maxCpuFreqKHz= */ 1000000,
+ new CpuInfoReader.CpuUsageStats(/* userTimeMillis= */ 28949280,
+ /* niceTimeMillis= */ 7799450, /* systemTimeMillis= */ 54004020,
+ /* idleTimeMillis= */ 402707120, /* iowaitTimeMillis= */ 1186960,
+ /* irqTimeMillis= */ 14786940, /* softirqTimeMillis= */ 1498130,
+ /* stealTimeMillis= */ 78780, /* guestTimeMillis= */ 0,
+ /* guestNiceTimeMillis= */ 0)),
+ new CpuInfoReader.CpuInfo(/* cpuCore= */ 2,
+ FLAG_CPUSET_CATEGORY_TOP_APP | FLAG_CPUSET_CATEGORY_BACKGROUND,
+ /* curCpuFreqKHz= */ 9, /* maxCpuFreqKHz= */ 2,
+ new CpuInfoReader.CpuUsageStats(/* userTimeMillis= */ 28959280,
+ /* niceTimeMillis= */ 7789450, /* systemTimeMillis= */ 54014020,
+ /* idleTimeMillis= */ 402717120, /* iowaitTimeMillis= */ 1166960,
+ /* irqTimeMillis= */ 14796940, /* softirqTimeMillis= */ 1478130,
+ /* stealTimeMillis= */ 88780, /* guestTimeMillis= */ 0,
+ /* guestNiceTimeMillis= */ 0)),
+ new CpuInfoReader.CpuInfo(/* cpuCore= */ 3,
+ FLAG_CPUSET_CATEGORY_TOP_APP | FLAG_CPUSET_CATEGORY_BACKGROUND,
+ /* curCpuFreqKHz= */ 9, /* maxCpuFreqKHz= */ 2,
+ new CpuInfoReader.CpuUsageStats(/* userTimeMillis= */ 32349610,
+ /* niceTimeMillis= */ 7850930, /* systemTimeMillis= */ 52127050,
+ /* idleTimeMillis= */ 409136950, /* iowaitTimeMillis= */ 1332810,
+ /* irqTimeMillis= */ 8136740, /* softirqTimeMillis= */ 438970,
+ /* stealTimeMillis= */ 71950, /* guestTimeMillis= */ 0,
+ /* guestNiceTimeMillis= */ 0)));
+
+ assertWithMessage("Cpu infos").that(actualCpuInfos)
+ .containsExactlyElementsIn(expectedCpuInfos);
+ }
+
+ @Test
+ public void testReadCpuInfoCorruptedProcStat() throws Exception {
+ mCpuInfoReader = new CpuInfoReader(getCacheFile(VALID_CPUSET_DIR),
+ getCacheFile(VALID_CPUFREQ_WITH_TIME_IN_STATE_DIR),
+ getCacheFile(CORRUPTED_PROC_STAT));
+ mCpuInfoReader.init();
+ List<CpuInfoReader.CpuInfo> actualCpuInfos = mCpuInfoReader.readCpuInfos();
+ List<CpuInfoReader.CpuInfo> expectedCpuInfos = List.of(
+ new CpuInfoReader.CpuInfo(/* cpuCore= */ 0, FLAG_CPUSET_CATEGORY_TOP_APP,
+ /* curCpuFreqKHz= */ 488095, /* maxCpuFreqKHz= */ 2500000,
+ new CpuInfoReader.CpuUsageStats(/* userTimeMillis= */ 32249610,
+ /* niceTimeMillis= */ 7950930, /* systemTimeMillis= */ 52227050,
+ /* idleTimeMillis= */ 409036950, /* iowaitTimeMillis= */ 1322810,
+ /* irqTimeMillis= */ 8146740, /* softirqTimeMillis= */ 428970,
+ /* stealTimeMillis= */ 81950, /* guestTimeMillis= */ 0,
+ /* guestNiceTimeMillis= */ 0)),
+ new CpuInfoReader.CpuInfo(/* cpuCore= */ 1,
+ FLAG_CPUSET_CATEGORY_TOP_APP,
+ /* curCpuFreqKHz= */ 502380, /* maxCpuFreqKHz= */ 2800000,
+ new CpuInfoReader.CpuUsageStats(/* userTimeMillis= */ 28949280,
+ /* niceTimeMillis= */ 7799450, /* systemTimeMillis= */ 54004020,
+ /* idleTimeMillis= */ 402707120, /* iowaitTimeMillis= */ 1186960,
+ /* irqTimeMillis= */ 14786940, /* softirqTimeMillis= */ 1498130,
+ /* stealTimeMillis= */ 78780, /* guestTimeMillis= */ 0,
+ /* guestNiceTimeMillis= */ 0)));
+
+ assertWithMessage("Cpu infos").that(actualCpuInfos)
+ .containsExactlyElementsIn(expectedCpuInfos);
+ }
+
+ @Test
+ public void testReadCpuInfoWithEmptyCpuset() throws Exception {
+ File emptyDir = getCacheFile(EMPTY_DIR);
+ assertWithMessage("Make empty dir %s", emptyDir).that(emptyDir.mkdir()).isTrue();
+ mCpuInfoReader = new CpuInfoReader(emptyDir, getCacheFile(
+ VALID_CPUFREQ_WITH_TIME_IN_STATE_DIR),
+ getCacheFile(VALID_PROC_STAT));
+
+ assertWithMessage("Init CPU reader info").that(mCpuInfoReader.init()).isFalse();
+
+ assertWithMessage("Cpu infos").that(mCpuInfoReader.readCpuInfos()).isEmpty();
+ }
+
+ @Test
+ public void testReadCpuInfoWithEmptyCpufreq() throws Exception {
+ File emptyDir = getCacheFile(EMPTY_DIR);
+ assertWithMessage("Make empty dir %s", emptyDir).that(emptyDir.mkdir()).isTrue();
+ mCpuInfoReader = new CpuInfoReader(getCacheFile(VALID_CPUSET_DIR), emptyDir,
+ getCacheFile(VALID_PROC_STAT));
+
+ assertWithMessage("Init CPU reader info").that(mCpuInfoReader.init()).isFalse();
+
+ assertWithMessage("Cpu infos").that(mCpuInfoReader.readCpuInfos()).isEmpty();
+ }
+
+ @Test
+ public void testReadCpuInfoWithEmptyProcStat() throws Exception {
+ File emptyFile = getCacheFile(EMPTY_FILE);
+ assertWithMessage("Create empty file %s", emptyFile).that(emptyFile.createNewFile())
+ .isTrue();
+ mCpuInfoReader = new CpuInfoReader(getCacheFile(VALID_CPUSET_DIR),
+ getCacheFile(VALID_CPUFREQ_WITH_TIME_IN_STATE_DIR), getCacheFile(EMPTY_FILE));
+
+ assertWithMessage("Cpu infos").that(mCpuInfoReader.readCpuInfos()).isEmpty();
+ }
+
+ private File getCacheFile(String assetName) {
+ return new File(mCacheRoot, assetName);
+ }
+
+ private void copyAssets(String assetPath, File targetRoot) throws Exception {
+ File target = new File(targetRoot, assetPath);
+ String[] assets = mAssetManager.list(assetPath);
+ if (assets == null || assets.length == 0) {
+ try (InputStream in = mAssetManager.open(assetPath);
+ OutputStream out = new FileOutputStream(target)) {
+ Streams.copy(in, out);
+ }
+ return;
+ }
+ assertWithMessage("Make target directory %s", target).that(target.mkdir()).isTrue();
+ for (int i = 0; i < assets.length; i++) {
+ copyAssets(String.format("%s%s%s", assetPath, File.separator, assets[i]), targetRoot);
+ }
+ }
+
+ private static boolean deleteDirectory(File rootDir) {
+ if (!rootDir.exists() || !rootDir.isDirectory()) {
+ return false;
+ }
+ for (File file : Objects.requireNonNull(rootDir.listFiles())) {
+ if (file.isDirectory()) {
+ deleteDirectory(file);
+ } else if (!file.delete()) {
+ return false;
+ }
+ }
+ return rootDir.delete();
+ }
+}
diff --git a/tests/carservice_unit_test/src/com/android/car/pm/CarPackageManagerServiceUnitTest.java b/tests/carservice_unit_test/src/com/android/car/pm/CarPackageManagerServiceUnitTest.java
index 4da8f8a..165eb09 100644
--- a/tests/carservice_unit_test/src/com/android/car/pm/CarPackageManagerServiceUnitTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/pm/CarPackageManagerServiceUnitTest.java
@@ -16,21 +16,39 @@
package com.android.car.pm;
+import static android.Manifest.permission.QUERY_ALL_PACKAGES;
+import static android.car.content.pm.CarPackageManager.ERROR_CODE_NO_PACKAGE;
+import static android.car.content.pm.CarPackageManager.MANIFEST_METADATA_TARGET_CAR_VERSION;
import static android.content.pm.PackageManager.MATCH_DEFAULT_ONLY;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
+import static org.junit.Assert.assertThrows;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;
import android.app.PendingIntent;
+import android.car.CarVersion;
import android.car.builtin.app.ActivityManagerHelper;
import android.car.test.mocks.AbstractExtendedMockitoTestCase;
import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.os.Binder;
+import android.os.Bundle;
+import android.os.Process;
+import android.os.ServiceSpecificException;
+import android.os.UserHandle;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.platform.app.InstrumentationRegistry;
@@ -53,10 +71,17 @@
* Unit tests for {@link CarPackageManagerService}.
*/
@RunWith(AndroidJUnit4.class)
-public class CarPackageManagerServiceUnitTest extends AbstractExtendedMockitoTestCase{
+public class CarPackageManagerServiceUnitTest extends AbstractExtendedMockitoTestCase {
CarPackageManagerService mService;
- private Context mContext;
+ private Context mSpiedContext;
+ private PackageManager mSpiedPackageManager;
+
+ private final UserHandle mUserHandle = UserHandle.of(666);
+
+ @Mock
+ private Context mUserContext;
+
@Mock
private CarUxRestrictionsManagerService mMockUxrService;
@Mock
@@ -72,14 +97,24 @@
@Override
protected void onSessionBuilder(CustomMockitoSessionBuilder builder) {
- builder.spyStatic(ActivityManagerHelper.class);
+ builder
+ .spyStatic(ActivityManagerHelper.class)
+ .spyStatic(Binder.class)
+ // Need to mock service itself because of getTargetCarVersion() - it doesn't make
+ // sense to test all variations of the methods that call it
+ .spyStatic(CarPackageManagerService.class);
}
@Before
public void setUp() {
- mContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
+ mSpiedContext = spy(InstrumentationRegistry.getInstrumentation().getTargetContext());
- mService = new CarPackageManagerService(mContext,
+ doReturn(mUserContext).when(mSpiedContext).createContextAsUser(mUserHandle, /* flags= */ 0);
+
+ mSpiedPackageManager = spy(mSpiedContext.getPackageManager());
+ doReturn(mSpiedPackageManager).when(mSpiedContext).getPackageManager();
+
+ mService = new CarPackageManagerService(mSpiedContext,
mMockUxrService, mMockActivityService, mMockCarOccupantZoneService);
}
@@ -161,12 +196,144 @@
assertThat(mService.isPendingIntentDistractionOptimized(mMockPendingIntent)).isFalse();
}
+ @Test
+ public void testGetTargetCarVersion_ok() {
+ String pkgName = "dr.evil";
+ CarVersion Version = CarVersion.forMajorAndMinorVersions(66, 6);
+
+ doReturn(Version)
+ .when(() -> CarPackageManagerService.getTargetCarVersion(mUserContext, pkgName));
+
+ mockCallingUser();
+
+ assertWithMessage("getTargetCarVersion(%s)", pkgName)
+ .that(mService.getTargetCarVersion(pkgName)).isSameInstanceAs(Version);
+ }
+
+ @Test
+ public void testGetTargetCarVersion_byUser() {
+ String pkgName = "dr.evil";
+ CarVersion Version = CarVersion.forMajorAndMinorVersions(66, 6);
+
+ doReturn(Version)
+ .when(() -> CarPackageManagerService.getTargetCarVersion(mUserContext, pkgName));
+
+ mockCallingUser();
+
+ assertWithMessage("getTargetCarVersion(%s)", pkgName)
+ .that(mService.getTargetCarVersion(mUserHandle, pkgName))
+ .isSameInstanceAs(Version);
+ }
+
+ @Test
+ public void testGetTargetCarVersion_self_ok() {
+ String pkgName = "dr.evil";
+ int myUid = Process.myUid();
+ doReturn(new String[] { pkgName }).when(mSpiedPackageManager).getPackagesForUid(myUid);
+ CarVersion Version = CarVersion.forMajorAndMinorVersions(66, 6);
+
+ doReturn(Version)
+ .when(() -> CarPackageManagerService.getTargetCarVersion(mUserContext, pkgName));
+
+ mockCallingUser();
+
+ assertWithMessage("getTargetCarVersion(%s)", pkgName)
+ .that(mService.getSelfTargetCarVersion(pkgName)).isSameInstanceAs(Version);
+ }
+
+ @Test
+ public void testGetTargetCarVersion_self_wrongUid() {
+ int myUid = Process.myUid();
+ String pkgName = "dr.evil";
+ CarVersion Version = CarVersion.forMajorAndMinorVersions(66, 6);
+
+ doReturn(Version)
+ .when(() -> CarPackageManagerService.getTargetCarVersion(mUserContext, pkgName));
+
+ mockCallingUser();
+
+ SecurityException e = assertThrows(SecurityException.class,
+ () -> mService.getSelfTargetCarVersion(pkgName));
+
+ String msg = e.getMessage();
+ assertWithMessage("exception message (pkg)").that(msg).contains(pkgName);
+ assertWithMessage("exception message (uid)").that(msg).contains(String.valueOf(myUid));
+ }
+
+ @Test
+ public void testGetTargetCarVersion_static_null() {
+ assertThrows(NullPointerException.class,
+ () -> CarPackageManagerService.getTargetCarVersion(mUserContext, null));
+ }
+
+ @Test
+ public void testGetTargetCarVersion_static_noPermission() {
+ mockQueryPermission(/* granted= */ false);
+
+ assertThrows(SecurityException.class,
+ () -> CarPackageManagerService.getTargetCarVersion(mUserContext, "d.oh"));
+ }
+
+
+ @Test
+ public void testGetTargetCarVersion_static_noApp() throws Exception {
+ mockQueryPermission(/* granted= */ true);
+ String causeMsg = mockGetApplicationInfoThrowsNotFound(mUserContext, "meaning.of.life");
+
+ ServiceSpecificException e = assertThrows(ServiceSpecificException.class,
+ () -> CarPackageManagerService.getTargetCarVersion(mUserContext,
+ "meaning.of.life"));
+ assertWithMessage("exception code").that(e.errorCode).isEqualTo(ERROR_CODE_NO_PACKAGE);
+ assertWithMessage("exception msg").that(e.getMessage()).isEqualTo(causeMsg);
+ }
+
+ // No need to test all scenarios, as they're tested by CarVersionParserParseMethodTest
+ @Test
+ public void testGetTargetCarVersion_static_ok() throws Exception {
+ mockQueryPermission(/* granted= */ true);
+ ApplicationInfo info = mockGetApplicationInfo(mUserContext, "meaning.of.life");
+ info.targetSdkVersion = 666; // Set to make sure it's not used
+ info.metaData = new Bundle();
+ info.metaData.putString(MANIFEST_METADATA_TARGET_CAR_VERSION, "42:108");
+
+ CarVersion actualVersion = CarPackageManagerService.getTargetCarVersion(
+ mUserContext, "meaning.of.life");
+
+ assertWithMessage("static getTargetCarVersion()").that(actualVersion).isNotNull();
+ assertWithMessage("major version").that(actualVersion.getMajorVersion()).isEqualTo(42);
+ assertWithMessage("minor version").that(actualVersion.getMinorVersion()).isEqualTo(108);
+ }
+
private void mockQueryPermission(boolean granted) {
int result = android.content.pm.PackageManager.PERMISSION_DENIED;
if (granted) {
result = android.content.pm.PackageManager.PERMISSION_GRANTED;
}
- doReturn(result).when(() -> ActivityManagerHelper.checkComponentPermission(any(), anyInt(),
- anyInt(), anyBoolean()));
+ doReturn(result).when(() -> ActivityManagerHelper.checkComponentPermission(
+ eq(QUERY_ALL_PACKAGES), anyInt(), anyInt(), anyBoolean()));
+ when(mUserContext.checkCallingOrSelfPermission(QUERY_ALL_PACKAGES)).thenReturn(result);
+ }
+
+ private void mockCallingUser() {
+ doReturn(mUserHandle).when(() -> Binder.getCallingUserHandle());
+ }
+
+ private static String mockGetApplicationInfoThrowsNotFound(Context context, String packageName)
+ throws NameNotFoundException {
+ String msg = "D'OH!";
+ PackageManager pm = mock(PackageManager.class);
+ when(context.getPackageManager()).thenReturn(pm);
+ when(pm.getApplicationInfo(eq(packageName), any()))
+ .thenThrow(new NameNotFoundException(msg));
+ return msg;
+ }
+
+ private static ApplicationInfo mockGetApplicationInfo(Context context, String packageName)
+ throws NameNotFoundException {
+ ApplicationInfo info = new ApplicationInfo();
+ PackageManager pm = mock(PackageManager.class);
+ when(context.getPackageManager()).thenReturn(pm);
+ when(pm.getApplicationInfo(eq(packageName), any())).thenReturn(info);
+ return info;
}
}
diff --git a/tests/carservice_unit_test/src/com/android/car/pm/CarVersionParserParseMethodTest.java b/tests/carservice_unit_test/src/com/android/car/pm/CarVersionParserParseMethodTest.java
new file mode 100644
index 0000000..0514e93
--- /dev/null
+++ b/tests/carservice_unit_test/src/com/android/car/pm/CarVersionParserParseMethodTest.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2022 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.pm;
+
+import static com.google.common.truth.Truth.assertWithMessage;
+
+import android.car.CarVersion;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+import java.util.Arrays;
+import java.util.Collection;
+
+// Life would be so much easier if JUnit allowed parameterized per method (not whole class)...
+@RunWith(Parameterized.class)
+public final class CarVersionParserParseMethodTest {
+
+ private static final String PGK_NAME = "bond.james.bond";
+ private static final int TARGET_SDK = 108;
+
+ private final String mAttribute;
+ private final int mExceptedMajor;
+ private final int mExceptedMinor;
+
+ public CarVersionParserParseMethodTest(String attribute, int expectedMajor,
+ int expectedMinor) {
+ mAttribute = attribute;
+ mExceptedMajor = expectedMajor;
+ mExceptedMinor = expectedMinor;
+ }
+
+ @Test
+ public void testParse() {
+ CarVersion actual = CarVersionParser.parse(PGK_NAME, mAttribute, TARGET_SDK);
+
+ assertWithMessage("parse(%s)", mAttribute).that(actual).isNotNull();
+ expectWithMessage("parse(%s).major", mAttribute).that(actual.getMajorVersion())
+ .isEqualTo(mExceptedMajor);
+ expectWithMessage("parse(%s).minor", mAttribute).that(actual.getMinorVersion())
+ .isEqualTo(mExceptedMinor);
+ }
+
+ @Parameterized.Parameters
+ public static Collection<?> parameters() {
+ return Arrays.asList(
+ // format: attribute, targetSdk, expectedMajor, expectedMinor
+ new Object[][] {
+ // valid ones
+ { "42:666", 42, 666},
+ { "042:666", 42, 666},
+ { "42:0666", 42, 666},
+ { "42:0", 42, 0 },
+ { "42:00", 42, 0 },
+ { "42", 42, 0 },
+ { "042", 42, 0 },
+ // invalid ones
+ { null, TARGET_SDK, 0 },
+ { "", TARGET_SDK, 0 },
+ { " ", TARGET_SDK, 0 },
+ { "42: ", TARGET_SDK, 0 },
+ { "42:", TARGET_SDK, 0 },
+ { "42:666 ", TARGET_SDK, 0 },
+ { "42 :666", TARGET_SDK, 0 },
+ { "42 : 666", TARGET_SDK, 0 },
+ { "42: 666", TARGET_SDK, 0 },
+ { " 42:0", TARGET_SDK, 0 },
+ { "42:0 ", TARGET_SDK, 0 },
+ { " 42", TARGET_SDK, 0 },
+ { "42 ", TARGET_SDK, 0 },
+ { "42:six-six-six", TARGET_SDK, 0 },
+ { "42;666", TARGET_SDK, 0 },
+ { "42.666", TARGET_SDK, 0 },
+ { "42-666", TARGET_SDK, 0 },
+ { "42 666", TARGET_SDK, 0 },
+ { "forty-two", TARGET_SDK, 0 },
+ });
+ }
+
+ // TODO(b/228506662): extend AbstractExpectableTestCase and remove members below (on master)
+
+ @org.junit.Rule
+ public final com.google.common.truth.Expect mExpect = com.google.common.truth.Expect.create();
+
+ protected com.google.common.truth.StandardSubjectBuilder expectWithMessage(String fmt,
+ Object...args) {
+ return mExpect.withMessage(fmt, args);
+ }
+}
diff --git a/tests/carservice_unit_test/src/com/android/car/pm/CarVersionParserTest.java b/tests/carservice_unit_test/src/com/android/car/pm/CarVersionParserTest.java
new file mode 100644
index 0000000..10b29d3
--- /dev/null
+++ b/tests/carservice_unit_test/src/com/android/car/pm/CarVersionParserTest.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2022 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.pm;
+
+import static android.car.content.pm.CarPackageManager.MANIFEST_METADATA_TARGET_CAR_VERSION;
+
+import static com.google.common.truth.Truth.assertWithMessage;
+
+import android.car.CarVersion;
+import android.content.pm.ApplicationInfo;
+import android.os.Bundle;
+
+import org.junit.Test;
+
+public final class CarVersionParserTest {
+
+ @Test
+ public void testGetTargetCarApiVersion_noMetadata() {
+ ApplicationInfo info = new ApplicationInfo();
+ info.targetSdkVersion = 42;
+
+ CarVersion apiVersion = CarVersionParser.getTargetCarVersion(info);
+
+ assertWithMessage("parse(%s)", info).that(apiVersion).isNotNull();
+ expectWithMessage("parse(%s).major", info).that(apiVersion.getMajorVersion()).isEqualTo(42);
+ expectWithMessage("parse(%s).minor", info).that(apiVersion.getMinorVersion()).isEqualTo(0);
+ }
+
+ // No need to test all scenarios, as they're tested by CarApiVersionParserParseMethodTest
+ @Test
+ public void testGetTargetCarApiVersion_simpleCase() {
+ ApplicationInfo info = new ApplicationInfo();
+ info.targetSdkVersion = 666; // Set to make sure it's not used
+ info.metaData = new Bundle();
+ info.metaData.putString(MANIFEST_METADATA_TARGET_CAR_VERSION, "108:42");
+
+ CarVersion apiVersion = CarVersionParser.getTargetCarVersion(info);
+
+ assertWithMessage("getTargetCarApiVersion(%s)", info).that(apiVersion).isNotNull();
+ expectWithMessage("getTargetCarApiVersion(%s).major", info)
+ .that(apiVersion.getMajorVersion()).isEqualTo(108);
+ expectWithMessage("getTargetCarApiVersion(%s).minor", info)
+ .that(apiVersion.getMinorVersion()).isEqualTo(42);
+ }
+
+ // TODO(b/228506662): extend AbstractExpectableTestCase and remove members below (on master)
+
+ @org.junit.Rule
+ public final com.google.common.truth.Expect mExpect = com.google.common.truth.Expect.create();
+
+ protected com.google.common.truth.StandardSubjectBuilder expectWithMessage(String msg) {
+ return mExpect.withMessage(msg);
+ }
+
+ protected com.google.common.truth.StandardSubjectBuilder expectWithMessage(String fmt,
+ Object...args) {
+ return mExpect.withMessage(fmt, args);
+ }
+}
diff --git a/tests/carservice_unit_test/src/com/android/car/pm/VendorServiceControllerTest.java b/tests/carservice_unit_test/src/com/android/car/pm/VendorServiceControllerTest.java
index 2a4e095..58cb175 100644
--- a/tests/carservice_unit_test/src/com/android/car/pm/VendorServiceControllerTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/pm/VendorServiceControllerTest.java
@@ -18,6 +18,7 @@
import static android.car.test.mocks.CarArgumentMatchers.isUserHandle;
+
import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth.assertWithMessage;
@@ -29,19 +30,23 @@
import android.car.test.mocks.AbstractExtendedMockitoTestCase;
import android.car.testapi.BlockingUserLifecycleListener;
import android.car.user.CarUserManager;
+import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.ContextWrapper;
import android.content.Intent;
+import android.content.IntentFilter;
import android.content.ServiceConnection;
import android.content.pm.UserInfo;
import android.content.res.Resources;
+import android.net.Uri;
import android.os.Handler;
import android.os.Looper;
import android.os.UserHandle;
import android.os.UserManager;
import android.util.Log;
+import androidx.annotation.Nullable;
import androidx.test.core.app.ApplicationProvider;
import com.android.car.CarLocalServices;
@@ -100,6 +105,9 @@
@Mock
private CarUxRestrictionsManagerService mUxRestrictionService;
+ @Mock
+ private CarPackageManagerService mCarPackageManagerService;
+
private ServiceLauncherContext mContext;
private CarUserService mCarUserService;
private VendorServiceController mController;
@@ -118,12 +126,12 @@
mContext = new ServiceLauncherContext(ApplicationProvider.getApplicationContext());
mCarUserService = new CarUserService(mContext, mUserHal, mUserManager,
- /* maxRunningUsers= */ 2, mUxRestrictionService);
+ /* maxRunningUsers= */ 2, mUxRestrictionService, mCarPackageManagerService);
CarLocalServices.addService(CarUserService.class, mCarUserService);
mController = new VendorServiceController(mContext, Looper.getMainLooper());
- UserInfo persistentFgUser = new UserInfo(FG_USER_ID, "persistent user", 0);
+ UserInfo persistentFgUser = new UserInfo(FG_USER_ID, "persistent user", /* flags= */ 0);
when(mUserManager.getUserInfo(FG_USER_ID)).thenReturn(persistentFgUser);
when(mResources.getStringArray(com.android.car.R.array.config_earlyStartupServices))
@@ -151,7 +159,7 @@
mockGetCurrentUser(UserHandle.USER_SYSTEM);
mController.init();
- mContext.assertBoundService(SERVICE_BIND_ALL_USERS_ASAP);
+ mContext.assertRecentBoundService(SERVICE_BIND_ALL_USERS_ASAP);
mContext.verifyNoMoreServiceLaunches();
}
@@ -169,7 +177,7 @@
sendUserLifecycleEvent(CarUserManager.USER_LIFECYCLE_EVENT_TYPE_UNLOCKED,
UserHandle.USER_SYSTEM);
- mContext.assertStartedService(SERVICE_START_SYSTEM_UNLOCKED);
+ mContext.assertRecentStartedService(SERVICE_START_SYSTEM_UNLOCKED);
mContext.verifyNoMoreServiceLaunches();
}
@@ -185,28 +193,101 @@
// Switch user to foreground
mockGetCurrentUser(FG_USER_ID);
// TODO(b/155918094): Update this test,
- UserInfo nullUser = new UserInfo(UserHandle.USER_NULL, "null user", 0);
+ UserInfo nullUser = new UserInfo(UserHandle.USER_NULL, "null user", /* flags= */ 0);
when(mUserManager.getUserInfo(UserHandle.USER_NULL)).thenReturn(nullUser);
sendUserLifecycleEvent(CarUserManager.USER_LIFECYCLE_EVENT_TYPE_SWITCHING, FG_USER_ID);
// Expect only services with ASAP trigger to be started
- mContext.assertBoundService(SERVICE_BIND_ALL_USERS_ASAP);
+ mContext.assertRecentBoundService(SERVICE_BIND_ALL_USERS_ASAP);
mContext.verifyNoMoreServiceLaunches();
// Unlock foreground user
mockUserUnlock(FG_USER_ID);
sendUserLifecycleEvent(CarUserManager.USER_LIFECYCLE_EVENT_TYPE_UNLOCKED, FG_USER_ID);
- mContext.assertBoundService(SERVICE_BIND_FG_USER_UNLOCKED);
+ mContext.assertRecentBoundService(SERVICE_BIND_FG_USER_UNLOCKED);
mContext.verifyNoMoreServiceLaunches();
// Send USER_POST_UNLOCKED event.
sendUserLifecycleEvent(CarUserManager.USER_LIFECYCLE_EVENT_TYPE_POST_UNLOCKED, FG_USER_ID);
- mContext.assertBoundService(SERVICE_BIND_FG_USER_POST_UNLOCKED);
+ mContext.assertRecentBoundService(SERVICE_BIND_FG_USER_POST_UNLOCKED);
mContext.verifyNoMoreServiceLaunches();
}
+ @Test
+ public void packageChanged_attemptsRebind() throws Exception {
+ mockGetCurrentUser(UserHandle.USER_SYSTEM);
+ mController.init();
+ mContext.reset();
+
+ mContext.expectServices(SERVICE_BIND_ALL_USERS_ASAP, SERVICE_BIND_FG_USER_UNLOCKED,
+ SERVICE_BIND_FG_USER_POST_UNLOCKED);
+
+ // Switch user to foreground
+ mockGetCurrentUser(FG_USER_ID);
+ UserInfo nullUser = new UserInfo(UserHandle.USER_NULL, "null user", /* flags= */ 0);
+ when(mUserManager.getUserInfo(UserHandle.USER_NULL)).thenReturn(nullUser);
+ sendUserLifecycleEvent(CarUserManager.USER_LIFECYCLE_EVENT_TYPE_SWITCHING, FG_USER_ID);
+ mContext.assertRecentBoundService(SERVICE_BIND_ALL_USERS_ASAP);
+ mockUserUnlock(FG_USER_ID);
+
+ // assertRecentBoundService() is important after every sendUserLifecycleEvent to ensure
+ // that the event has been handled completely.
+ sendUserLifecycleEvent(CarUserManager.USER_LIFECYCLE_EVENT_TYPE_UNLOCKED, FG_USER_ID);
+ mContext.assertRecentBoundService(SERVICE_BIND_FG_USER_UNLOCKED);
+ sendUserLifecycleEvent(CarUserManager.USER_LIFECYCLE_EVENT_TYPE_POST_UNLOCKED, FG_USER_ID);
+ mContext.assertRecentBoundService(SERVICE_BIND_FG_USER_POST_UNLOCKED);
+
+ Intent packageIntent = new Intent(Intent.ACTION_PACKAGE_CHANGED);
+ int appId = 123;
+ packageIntent.setData(new Uri.Builder().path("Any package").build());
+ packageIntent.putExtra(Intent.EXTRA_UID, UserHandle.getUid(FG_USER_ID, appId));
+ mContext.mPackageChangeReceiver.onReceive(mContext, packageIntent);
+ runOnMainThreadAndWaitForIdle(() -> {});
+
+ assertThat(((VendorServiceController.VendorServiceConnection)
+ mContext.mBoundServiceToConnectionMap.get(SERVICE_BIND_FG_USER_POST_UNLOCKED))
+ .isPendingRebind()).isTrue();
+ assertThat(((VendorServiceController.VendorServiceConnection)
+ mContext.mBoundServiceToConnectionMap.get(SERVICE_BIND_FG_USER_UNLOCKED))
+ .isPendingRebind()).isTrue();
+ }
+
+ @Test
+ public void packageRemoved_unbindsTheService() throws Exception {
+ mockGetCurrentUser(UserHandle.USER_SYSTEM);
+ mController.init();
+ mContext.reset();
+ mContext.expectServices(SERVICE_BIND_ALL_USERS_ASAP, SERVICE_BIND_FG_USER_UNLOCKED,
+ SERVICE_BIND_FG_USER_POST_UNLOCKED);
+
+ // Switch user to foreground
+ mockGetCurrentUser(FG_USER_ID);
+ UserInfo nullUser = new UserInfo(UserHandle.USER_NULL, "null user", /* flags= */ 0);
+ when(mUserManager.getUserInfo(UserHandle.USER_NULL)).thenReturn(nullUser);
+ sendUserLifecycleEvent(CarUserManager.USER_LIFECYCLE_EVENT_TYPE_SWITCHING, FG_USER_ID);
+ mContext.assertRecentBoundService(SERVICE_BIND_ALL_USERS_ASAP);
+ mockUserUnlock(FG_USER_ID);
+
+ // assertRecentBoundService() is important after every sendUserLifecycleEvent to ensure
+ // that the event has been handled completely.
+ sendUserLifecycleEvent(CarUserManager.USER_LIFECYCLE_EVENT_TYPE_UNLOCKED, FG_USER_ID);
+ mContext.assertRecentBoundService(SERVICE_BIND_FG_USER_UNLOCKED);
+ sendUserLifecycleEvent(CarUserManager.USER_LIFECYCLE_EVENT_TYPE_POST_UNLOCKED, FG_USER_ID);
+ mContext.assertRecentBoundService(SERVICE_BIND_FG_USER_POST_UNLOCKED);
+
+ Intent packageIntent = new Intent(Intent.ACTION_PACKAGE_REMOVED);
+ int appId = 123;
+ packageIntent.setData(new Uri.Builder().path("com.android.car").build());
+ packageIntent.putExtra(Intent.EXTRA_UID, UserHandle.getUid(FG_USER_ID, appId));
+ mContext.mPackageChangeReceiver.onReceive(mContext, packageIntent);
+ runOnMainThreadAndWaitForIdle(() -> {});
+
+ mContext.assertServiceNotBound(SERVICE_BIND_FG_USER_POST_UNLOCKED);
+ mContext.assertServiceNotBound(SERVICE_BIND_FG_USER_UNLOCKED);
+ }
+
private static void runOnMainThreadAndWaitForIdle(Runnable r) {
Handler.getMain().runWithScissors(r, DEFAULT_TIMEOUT_MS);
// Run empty runnable to make sure that all posted handlers are done.
@@ -218,12 +299,13 @@
when(mUserManager.isUserUnlockingOrUnlocked(userId)).thenReturn(true);
}
- private static void assertHasService(List<Intent> intents, String service, String action) {
- assertWithMessage("Service %s not %s yet", service, action).that(intents)
+ private static void assertHasService(List<ComponentName> recentServices, String service,
+ String action) {
+ assertWithMessage("Number of recent %s services", action).that(recentServices)
.hasSize(1);
- assertWithMessage("Wrong component %s", action).that(intents.get(0).getComponent())
+ assertWithMessage("Recent service").that(recentServices.get(0))
.isEqualTo(ComponentName.unflattenFromString(service));
- intents.clear();
+ recentServices.clear();
}
private void sendUserLifecycleEvent(@UserLifecycleEventType int eventType,
@@ -245,12 +327,18 @@
private final Object mLock = new Object();
@GuardedBy("mLock")
- private List<Intent> mBoundIntents = new ArrayList<>();
+ private Map<ServiceConnection, ComponentName> mBoundConnectionToServiceMap =
+ new HashMap<>();
@GuardedBy("mLock")
- private List<Intent> mStartedServicesIntents = new ArrayList<>();
+ private List<ComponentName> mRecentBoundServices = new ArrayList<>();
+ @GuardedBy("mLock")
+ private List<ComponentName> mRecentStartedServices = new ArrayList<>();
private final Map<String, CountDownLatch> mBoundLatches = new HashMap<>();
private final Map<String, CountDownLatch> mStartedLatches = new HashMap<>();
+ private final Map<String, ServiceConnection> mBoundServiceToConnectionMap =
+ new HashMap<>();
+ private BroadcastReceiver mPackageChangeReceiver;
ServiceLauncherContext(Context base) {
super(base);
@@ -265,7 +353,7 @@
@Override
public ComponentName startService(Intent service) {
synchronized (mLock) {
- mStartedServicesIntents.add(service);
+ mRecentStartedServices.add(service.getComponent());
}
countdown(mStartedLatches, service, "started");
return service.getComponent();
@@ -275,7 +363,10 @@
public boolean bindService(Intent service, int flags, Executor executor,
ServiceConnection conn) {
synchronized (mLock) {
- mBoundIntents.add(service);
+ mRecentBoundServices.add(service.getComponent());
+ mBoundServiceToConnectionMap.put(service.getComponent().flattenToShortString(),
+ conn);
+ mBoundConnectionToServiceMap.put(conn, service.getComponent());
Log.v(TAG, "Added service (" + service + ") to bound intents");
}
conn.onServiceConnected(service.getComponent(), null);
@@ -284,6 +375,17 @@
}
@Override
+ public void unbindService(ServiceConnection conn) {
+ synchronized (mLock) {
+ ComponentName serviceComponent = mBoundConnectionToServiceMap.get(conn);
+ Log.v(TAG, "Remove service (" + serviceComponent + ") from bound services");
+ mRecentBoundServices.remove(serviceComponent);
+ mBoundServiceToConnectionMap.remove(serviceComponent.flattenToShortString());
+ mBoundConnectionToServiceMap.remove(conn);
+ }
+ }
+
+ @Override
public Resources getResources() {
return mResources;
}
@@ -324,31 +426,40 @@
}
}
- void assertBoundService(String service) throws InterruptedException {
+ void assertRecentBoundService(String service) throws InterruptedException {
await(mBoundLatches, service, "bind()");
synchronized (mLock) {
- assertHasService(mBoundIntents, service, "bound");
+ assertHasService(mRecentBoundServices, service, "bound");
}
}
- void assertStartedService(String service) throws InterruptedException {
+ void assertServiceNotBound(String service) throws InterruptedException {
+ synchronized (mLock) {
+ assertWithMessage("Service is binded.").that(mRecentBoundServices)
+ .doesNotContain(ComponentName.unflattenFromString(service));
+ }
+ }
+
+ void assertRecentStartedService(String service) throws InterruptedException {
await(mStartedLatches, service, "start()");
synchronized (mLock) {
- assertHasService(mStartedServicesIntents, service, "started");
+ assertHasService(mRecentStartedServices, service, "started");
}
}
void verifyNoMoreServiceLaunches() {
synchronized (mLock) {
- assertThat(mStartedServicesIntents).isEmpty();
- assertThat(mBoundIntents).isEmpty();
+ assertThat(mRecentStartedServices).isEmpty();
+ assertThat(mRecentBoundServices).isEmpty();
}
}
void reset() {
synchronized (mLock) {
- mStartedServicesIntents.clear();
- mBoundIntents.clear();
+ mRecentStartedServices.clear();
+ mRecentBoundServices.clear();
+ mBoundServiceToConnectionMap.clear();
+ mBoundConnectionToServiceMap.clear();
}
}
@@ -359,5 +470,14 @@
}
return super.getSystemService(name);
}
+
+ @Nullable
+ @Override
+ public Intent registerReceiverForAllUsers(@Nullable BroadcastReceiver receiver,
+ IntentFilter filter, @Nullable String broadcastPermission,
+ @Nullable Handler scheduler, int flags) {
+ mPackageChangeReceiver = receiver;
+ return null;
+ }
}
}
diff --git a/tests/carservice_unit_test/src/com/android/car/power/CarPowerManagementServiceUnitTest.java b/tests/carservice_unit_test/src/com/android/car/power/CarPowerManagementServiceUnitTest.java
index 82756b7..8ee9bc0 100644
--- a/tests/carservice_unit_test/src/com/android/car/power/CarPowerManagementServiceUnitTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/power/CarPowerManagementServiceUnitTest.java
@@ -90,6 +90,7 @@
import java.io.StringWriter;
import java.time.Duration;
import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
@@ -587,16 +588,21 @@
@Test
public void testApplyPowerPolicy() throws Exception {
grantPowerPolicyPermission();
- // Power policy which doesn't change any components.
- String policyId = "policy_id_no_changes";
- mService.definePowerPolicy(policyId, new String[0], new String[0]);
+ String policyId = "policy_id_audio_on";
+ mService.definePowerPolicy(policyId, new String[]{"AUDIO"}, new String[0]);
+ MockedPowerPolicyListener listenerToWait = new MockedPowerPolicyListener();
+ CarPowerPolicyFilter filterAudio = new CarPowerPolicyFilter.Builder()
+ .setComponents(PowerComponent.AUDIO).build();
+ mService.addPowerPolicyListener(filterAudio, listenerToWait);
mService.applyPowerPolicy(policyId);
CarPowerPolicy policy = mService.getCurrentPowerPolicy();
+ assertThat(policy).isNotNull();
assertThat(policy.getPolicyId()).isEqualTo(policyId);
- assertThat(mPowerPolicyDaemon.getLastNotifiedPolicyId()).isEqualTo(policyId);
assertThat(mPowerComponentHandler.getAccumulatedPolicy().getPolicyId()).isEqualTo(policyId);
+ assertThat(listenerToWait.getCurrentPowerPolicy()).isNotNull();
+ assertThat(mPowerPolicyDaemon.getLastNotifiedPolicyId()).isEqualTo(policyId);
}
@Test
@@ -688,7 +694,9 @@
mService.addPowerPolicyListener(filterWifi, listenerWifi);
mService.applyPowerPolicy(policyId);
+ assertThat(listenerAudio.getCurrentPowerPolicy()).isNotNull();
assertThat(listenerAudio.getCurrentPowerPolicy().getPolicyId()).isEqualTo(policyId);
+ assertThat(listenerWifi.getCurrentPowerPolicy()).isNotNull();
assertThat(listenerWifi.getCurrentPowerPolicy().getPolicyId()).isEqualTo(policyId);
assertThat(listenerLocation.getCurrentPowerPolicy()).isNull();
}
@@ -1135,16 +1143,24 @@
}
private final class MockedPowerPolicyListener extends ICarPowerPolicyListener.Stub {
+ private static final int NOTIFICATION_TIMEOUT_SEC = 5;
+
+ private final CountDownLatch mLatch = new CountDownLatch(1);
private CarPowerPolicy mCurrentPowerPolicy;
@Override
public void onPolicyChanged(CarPowerPolicy appliedPolicy,
CarPowerPolicy accumulatedPolicy) {
mCurrentPowerPolicy = accumulatedPolicy;
+ mLatch.countDown();
}
- public CarPowerPolicy getCurrentPowerPolicy() {
- return mCurrentPowerPolicy;
+ public CarPowerPolicy getCurrentPowerPolicy() throws Exception {
+ if (mLatch.await(NOTIFICATION_TIMEOUT_SEC, TimeUnit.SECONDS)) {
+ return mCurrentPowerPolicy;
+ }
+
+ return null;
}
}
}
diff --git a/tests/carservice_unit_test/src/com/android/car/power/PolicyReaderUnitTest.java b/tests/carservice_unit_test/src/com/android/car/power/PolicyReaderUnitTest.java
index 0a11082..1a4a9a4 100644
--- a/tests/carservice_unit_test/src/com/android/car/power/PolicyReaderUnitTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/power/PolicyReaderUnitTest.java
@@ -67,6 +67,8 @@
private static final String NO_USER_INTERACTION_POLICY_ID =
"system_power_policy_no_user_interaction";
private static final String SUSPEND_PREP_POLICY_ID = "system_power_policy_suspend_prep";
+ private static final String ALL_ON_POLICY_ID = "system_power_policy_all_on";
+ private static final String INITIAL_ON_POLICY_ID = "system_power_policy_initial_on";
private static final CarPowerPolicy POLICY_OTHER_OFF = new CarPowerPolicy(POLICY_ID_OTHER_OFF,
new int[]{WIFI},
@@ -207,6 +209,26 @@
assertInvalidXml(R.raw.invalid_system_power_policy_incorrect_id);
}
+ @Test
+ public void testDefaultPolicies() throws Exception {
+ assertDefaultPolicies();
+ }
+
+ @Test
+ public void testDefaultPoliciesWithCustomVendorPolicies() throws Exception {
+ readPowerPolicyXml(R.raw.valid_power_policy);
+
+ assertDefaultPolicies();
+ }
+
+ private void assertDefaultPolicies() {
+ assertThat(mPolicyReader.getPowerPolicy(ALL_ON_POLICY_ID)).isNotNull();
+ assertThat(mPolicyReader.getPreemptivePowerPolicy(NO_USER_INTERACTION_POLICY_ID))
+ .isNotNull();
+ assertThat(mPolicyReader.getPowerPolicy(INITIAL_ON_POLICY_ID)).isNotNull();
+ assertThat(mPolicyReader.getPreemptivePowerPolicy(SUSPEND_PREP_POLICY_ID)).isNotNull();
+ }
+
private void assertValidPolicyPart() throws Exception {
assertThat(mPolicyReader.getPowerPolicy(POLICY_ID_NOT_EXIST)).isNull();
checkPolicy(POLICY_ID_OTHER_OFF, POLICY_OTHER_OFF);
diff --git a/tests/carservice_unit_test/src/com/android/car/telemetry/CarTelemetryServiceTest.java b/tests/carservice_unit_test/src/com/android/car/telemetry/CarTelemetryServiceTest.java
index 22f9724..5a1620f 100644
--- a/tests/carservice_unit_test/src/com/android/car/telemetry/CarTelemetryServiceTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/telemetry/CarTelemetryServiceTest.java
@@ -34,8 +34,8 @@
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.isNull;
import static org.mockito.Mockito.atLeastOnce;
-import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -47,6 +47,7 @@
import android.car.telemetry.TelemetryProto;
import android.content.Context;
import android.os.Handler;
+import android.os.ParcelFileDescriptor;
import android.os.PersistableBundle;
import android.os.ResultReceiver;
@@ -62,6 +63,7 @@
import com.android.car.telemetry.publisher.PublisherFactory;
import com.android.car.telemetry.sessioncontroller.SessionController;
import com.android.car.telemetry.systemmonitor.SystemMonitor;
+import com.android.car.telemetry.util.MetricsReportProtoUtils;
// import com.android.car.telemetry.systemmonitor.SystemMonitorEvent;
import org.junit.Before;
@@ -69,8 +71,13 @@
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
+import java.io.ByteArrayInputStream;
import java.io.File;
+import java.io.InputStream;
+import java.nio.ByteBuffer;
import java.nio.file.Files;
+import java.util.ArrayList;
+import java.util.List;
@SmallTest
public class CarTelemetryServiceTest extends AbstractExtendedMockitoCarServiceTestCase {
@@ -112,16 +119,13 @@
@Override
protected void onSessionBuilder(CustomMockitoSessionBuilder session) {
- session.spyStatic(SystemMonitor.class);
+ session.spyStatic(SystemMonitor.class).spyStatic(ParcelFileDescriptor.class);
}
@Before
public void setUp() throws Exception {
CarLocalServices.removeServiceForTest(SystemInterface.class);
CarLocalServices.addService(SystemInterface.class, mMockSystemInterface);
- CarLocalServices.removeServiceForTest(CarPowerManagementService.class);
- CarLocalServices.addService(CarPowerManagementService.class,
- mMockCarPowerManagementService);
when(mMockContext.getSystemService(ActivityManager.class))
.thenReturn(mMockActivityManager);
@@ -133,11 +137,12 @@
when(mMockSystemInterface.getSystemCarDir()).thenReturn(mTempSystemCarDir);
when(mDependencies.getUidPackageMapper(any(), any())).thenReturn(mMockUidMapper);
- when(mDependencies.getPublisherFactory(any(), any(), any(), any(), any(), any(), any()))
+ when(mDependencies.getPublisherFactory(any(), any(), any(), any(), any(), any()))
.thenReturn(mPublisherFactory);
mService = new CarTelemetryService(
mMockContext,
+ mMockCarPowerManagementService,
mMockCarPropertyService,
mDependencies,
mMockDataBroker,
@@ -280,15 +285,14 @@
mService.addMetricsConfig(METRICS_CONFIG_NAME, METRICS_CONFIG_V1.toByteArray(),
mMockAddMetricsConfigCallback);
mResultStore.putInterimResult(METRICS_CONFIG_NAME, new PersistableBundle());
- mResultStore.putFinalResult(testConfigName, new PersistableBundle());
+ mResultStore.putMetricsReport(testConfigName, new PersistableBundle(), false);
mService.removeAllMetricsConfigs();
CarServiceUtils.runOnLooperSync(mTelemetryHandler.getLooper(), () -> { });
assertThat(mMetricsConfigStore.getActiveMetricsConfigs()).isEmpty();
assertThat(mResultStore.getInterimResult(METRICS_CONFIG_NAME)).isNull();
- assertThat(mResultStore.getFinalResult(testConfigName, /* deleteResult = */ false))
- .isNull();
+ assertThat(mResultStore.getMetricsReports(testConfigName, false)).isNull();
}
@Test
@@ -326,21 +330,35 @@
}
@Test
- public void testGetFinishedReport_whenFinalResult_shouldReceiveResult() throws Exception {
- PersistableBundle finalResult = new PersistableBundle();
- finalResult.putBoolean("finished", true);
- mResultStore.putFinalResult(METRICS_CONFIG_NAME, finalResult);
+ public void testGetFinishedReport_whenMultiple_shouldReceiveCorrectStatusCode()
+ throws Exception {
+ ParcelFileDescriptor[] fds = ParcelFileDescriptor.createPipe();
+ ParcelFileDescriptor readFd = fds[0].dup();
+ when(ParcelFileDescriptor.createPipe()).thenReturn(fds);
+ PersistableBundle expectedReport = new PersistableBundle();
+ expectedReport.putBoolean("finished", true);
+ // a report produced via on_metrics_report callback
+ mResultStore.putMetricsReport(METRICS_CONFIG_NAME, expectedReport.deepCopy(), false);
+ // a report produced via on_script_finished callback
+ mResultStore.putMetricsReport(METRICS_CONFIG_NAME, expectedReport.deepCopy(), true);
mService.getFinishedReport(METRICS_CONFIG_NAME, mMockReportListener);
CarServiceUtils.runOnLooperSync(mTelemetryHandler.getLooper(), () -> { });
- ArgumentCaptor<PersistableBundle> reportCaptor =
- ArgumentCaptor.forClass(PersistableBundle.class);
- verify(mMockReportListener).onResult(eq(METRICS_CONFIG_NAME), reportCaptor.capture(),
- isNull(), eq(STATUS_GET_METRICS_CONFIG_FINISHED));
- assertThat(reportCaptor.getValue().toString()).isEqualTo(finalResult.toString());
+ verify(mMockReportListener, times(1)).onResult(
+ eq(METRICS_CONFIG_NAME),
+ eq(fds[0]),
+ isNull(),
+ eq(STATUS_GET_METRICS_CONFIG_FINISHED));
+
+ // verify the reports are expected
+ List<PersistableBundle> parseReports = parseReports(readFd);
+ assertThat(parseReports.get(0).keySet())
+ .containsAtLeastElementsIn(expectedReport.keySet().toArray());
+ assertThat(parseReports.get(1).keySet())
+ .containsAtLeastElementsIn(expectedReport.keySet().toArray());
// result should have been deleted
- assertThat(mResultStore.getFinalResult(METRICS_CONFIG_NAME, false)).isNull();
+ assertThat(mResultStore.getMetricsReports(METRICS_CONFIG_NAME, false)).isNull();
}
@Test
@@ -370,6 +388,9 @@
@Test
public void testGetAllFinishedReports_shouldSendEverything() throws Exception {
+ ParcelFileDescriptor[] fds = ParcelFileDescriptor.createPipe();
+ ParcelFileDescriptor readFd = fds[0].dup();
+ when(ParcelFileDescriptor.createPipe()).thenReturn(fds);
String nameFoo = "foo";
TelemetryProto.TelemetryError error = TelemetryProto.TelemetryError.newBuilder()
.setErrorType(TelemetryProto.TelemetryError.ErrorType.LUA_RUNTIME_ERROR)
@@ -377,30 +398,37 @@
.build();
mResultStore.putErrorResult(nameFoo, error); // result 1
String nameBar = "bar";
- PersistableBundle finalResult = new PersistableBundle();
- finalResult.putBoolean("finished", true);
- mResultStore.putFinalResult(nameBar, finalResult); // result 2
+ PersistableBundle expectedReport = new PersistableBundle();
+ expectedReport.putBoolean("finished", true);
+ mResultStore.putMetricsReport(nameBar, expectedReport, false); // result 2
+ // result 3, "bar" has 2 reports
+ mResultStore.putMetricsReport(nameBar, expectedReport, true);
mService.getAllFinishedReports(mMockReportListener);
CarServiceUtils.runOnLooperSync(mTelemetryHandler.getLooper(), () -> { });
+ // expect 1 binder call for the error
verify(mMockReportListener).onResult(eq(nameFoo), isNull(), eq(error.toByteArray()),
eq(STATUS_GET_METRICS_CONFIG_RUNTIME_ERROR));
- ArgumentCaptor<PersistableBundle> reportCaptor =
- ArgumentCaptor.forClass(PersistableBundle.class);
- verify(mMockReportListener).onResult(eq(nameBar), reportCaptor.capture(), isNull(),
+ // expect only 1 binder call for multiple reports
+ verify(mMockReportListener).onResult(eq(nameBar), eq(fds[0]), isNull(),
eq(STATUS_GET_METRICS_CONFIG_FINISHED));
- assertThat(reportCaptor.getValue().toString()).isEqualTo(finalResult.toString());
+ // verify that 2 reports are parsed from the pipe for "nameBar"
+ List<PersistableBundle> parseReports = parseReports(readFd);
+ assertThat(parseReports.get(0).keySet())
+ .containsAtLeastElementsIn(expectedReport.keySet().toArray());
+ assertThat(parseReports.get(1).keySet())
+ .containsAtLeastElementsIn(expectedReport.keySet().toArray());
// results should have been deleted
assertThat(mResultStore.getErrorResult(nameFoo, false)).isNull();
- assertThat(mResultStore.getFinalResult(nameBar, false)).isNull();
+ assertThat(mResultStore.getMetricsReports(nameBar, false)).isNull();
}
@Test
public void testSetReportReadyListener() throws Exception {
String name1 = "name1";
String name2 = "name2";
- mResultStore.putFinalResult(name1, new PersistableBundle());
+ mResultStore.putMetricsReport(name1, new PersistableBundle(), false);
mResultStore.putErrorResult(
name2, TelemetryProto.TelemetryError.newBuilder().build());
@@ -442,7 +470,8 @@
CarServiceUtils.runOnLooperSync(mTelemetryHandler.getLooper(), () -> { });
assertThat(mMetricsConfigStore.getActiveMetricsConfigs()).isEmpty();
- assertThat(mResultStore.getFinalResult(METRICS_CONFIG_NAME, false)).isNotNull();
+ assertThat(mResultStore.getMetricsReports(METRICS_CONFIG_NAME, false).getReportCount())
+ .isEqualTo(1);
verify(mMockReportReadyListener).onReady(eq(METRICS_CONFIG_NAME));
verify(mMockDataBroker).scheduleNextTask();
}
@@ -467,51 +496,35 @@
mService.setReportReadyListener(mMockReportReadyListener);
mMetricsConfigStore.addMetricsConfig(METRICS_CONFIG_V1);
PersistableBundle bundle = new PersistableBundle();
+ bundle.putString("test", "test");
- mDataBrokerListener.onMetricsReport(METRICS_CONFIG_NAME, bundle, bundle);
+ mDataBrokerListener.onMetricsReport(
+ METRICS_CONFIG_NAME, bundle.deepCopy(), bundle.deepCopy());
CarServiceUtils.runOnLooperSync(mTelemetryHandler.getLooper(), () -> { });
assertThat(mMetricsConfigStore.getActiveMetricsConfigs())
.containsExactly(METRICS_CONFIG_V1);
- assertThat(mResultStore.getInterimResult(METRICS_CONFIG_NAME)).isEqualTo(bundle);
- assertThat(mResultStore.getFinalResult(METRICS_CONFIG_NAME, false)).isEqualTo(bundle);
+ assertThat(mResultStore.getInterimResult(METRICS_CONFIG_NAME).toString())
+ .isEqualTo(bundle.toString());
+ PersistableBundle report = MetricsReportProtoUtils.getBundle(
+ mResultStore.getMetricsReports(METRICS_CONFIG_NAME, false), 0);
+ assertThat(report.keySet()).containsAtLeastElementsIn(bundle.keySet().toArray());
verify(mMockReportReadyListener).onReady(eq(METRICS_CONFIG_NAME));
verify(mMockDataBroker).scheduleNextTask();
}
@Test
- public void testOnBootCompleted_shouldStartMetricsCollection() {
- mMetricsConfigStore.addMetricsConfig(METRICS_CONFIG_V1);
- ArgumentCaptor<Runnable> mRunnableCaptor = ArgumentCaptor.forClass(Runnable.class);
-
- // verify that startsMetricsCollection() is scheduled to run on boot complete
- verify(mMockSystemInterface).scheduleActionForBootCompleted(
- mRunnableCaptor.capture(), any());
- // run startMetricsCollection()
- mRunnableCaptor.getValue().run();
-
+ public void testOnInitCompleted_shouldStartMetricsCollection() {
+ // Metrics collection start is dispatched to main thread.
+ // We force it to run.
+ CarServiceUtils.runOnMainSync(() -> { });
CarServiceUtils.runOnLooperSync(mTelemetryHandler.getLooper(), () -> { });
- verify(mMockDataBroker).addMetricsConfig(eq(METRICS_CONFIG_NAME), eq(METRICS_CONFIG_V1));
+
+ // SessionController.initSession() is called after all logic in
+ // startMetricCollection executes.
verify(mMockSessionController).initSession();
}
- @Test
- public void testStartMetricsCollection_shouldReportFailure() {
- mMetricsConfigStore.addMetricsConfig(METRICS_CONFIG_V1);
- doThrow(IllegalArgumentException.class)
- .when(mMockDataBroker).addMetricsConfig(any(), any());
- ArgumentCaptor<Runnable> mRunnableCaptor = ArgumentCaptor.forClass(Runnable.class);
- // startsMetricsCollection() is scheduled to run on boot complete
- verify(mMockSystemInterface).scheduleActionForBootCompleted(
- mRunnableCaptor.capture(), any());
-
- mRunnableCaptor.getValue().run(); // run startMetricsCollection()
-
- CarServiceUtils.runOnLooperSync(mTelemetryHandler.getLooper(), () -> { });
- assertThat(mMetricsConfigStore.getActiveMetricsConfigs()).isEmpty();
- assertThat(mResultStore.getErrorResult(METRICS_CONFIG_NAME, false)).isNotNull();
- }
-
// TODO(b/233973826): Uncomment once SystemMonitor is tuned-up.
/*
@Test
@@ -568,4 +581,28 @@
verify(mMockDataBroker).setTaskExecutionPriority(eq(TASK_PRIORITY_LOW));
}*/
+
+ private List<PersistableBundle> parseReports(ParcelFileDescriptor reportFileDescriptor)
+ throws Exception {
+ List<PersistableBundle> reports = new ArrayList<>();
+ try (InputStream input = new ParcelFileDescriptor.AutoCloseInputStream(
+ reportFileDescriptor)) {
+ while (true) {
+ // read 4 byte integer that is the size of the PersistableBundle
+ byte[] intBytes = input.readNBytes(4);
+ if (intBytes.length != 4) {
+ break;
+ }
+ int size = ByteBuffer.wrap(intBytes).getInt();
+ byte[] bundleBytes = input.readNBytes(size);
+ if (bundleBytes.length != size) {
+ break;
+ }
+ PersistableBundle report = PersistableBundle.readFromStream(
+ new ByteArrayInputStream(bundleBytes));
+ reports.add(report);
+ }
+ }
+ return reports;
+ }
}
diff --git a/tests/carservice_unit_test/src/com/android/car/telemetry/ResultStoreTest.java b/tests/carservice_unit_test/src/com/android/car/telemetry/ResultStoreTest.java
index 49395f4..4686383 100644
--- a/tests/carservice_unit_test/src/com/android/car/telemetry/ResultStoreTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/telemetry/ResultStoreTest.java
@@ -16,15 +16,28 @@
package com.android.car.telemetry;
+import static com.android.car.telemetry.ResultStore.BUNDLE_KEY_ID;
+
import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth.assertWithMessage;
+import static org.mockito.Mockito.when;
+
import android.car.telemetry.TelemetryProto;
+import android.content.Context;
import android.os.PersistableBundle;
+import android.provider.Settings;
+import android.test.mock.MockContentResolver;
+
+import com.android.car.telemetry.MetricsReportProto.MetricsReportList;
+import com.android.car.telemetry.util.IoUtils;
+import com.android.car.telemetry.util.MetricsReportProtoUtils;
+import com.android.internal.util.test.FakeSettingsProvider;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;
import java.io.ByteArrayOutputStream;
@@ -32,13 +45,14 @@
import java.io.FileInputStream;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
+import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
@RunWith(MockitoJUnitRunner.class)
public class ResultStoreTest {
private static final PersistableBundle TEST_INTERIM_BUNDLE = new PersistableBundle();
- private static final PersistableBundle TEST_FINAL_BUNDLE = new PersistableBundle();
+ private static final PersistableBundle TEST_METRICS_REPORT_BUNDLE = new PersistableBundle();
private static final PersistableBundle TEST_PUBLISHER_BUNDLE = new PersistableBundle();
private static final TelemetryProto.TelemetryError TEST_TELEMETRY_ERROR =
TelemetryProto.TelemetryError.newBuilder().setMessage("test error").build();
@@ -46,30 +60,41 @@
private File mTestRootDir;
private File mTestInterimResultDir;
private File mTestErrorResultDir;
- private File mTestFinalResultDir;
+ private File mTestMetricsReportDir;
private File mTestPublisherDataDir;
private ResultStore mResultStore;
+ @Mock
+ private Context mMockContext;
+
@Before
public void setUp() throws Exception {
+ MockContentResolver mockContentResolver = new MockContentResolver();
+ mockContentResolver.addProvider(Settings.AUTHORITY, new FakeSettingsProvider());
+ when(mMockContext.getContentResolver()).thenReturn(mockContentResolver);
TEST_INTERIM_BUNDLE.putString("test key", "interim value");
- TEST_FINAL_BUNDLE.putString("test key", "final value");
+ TEST_METRICS_REPORT_BUNDLE.putDouble("pi", 3.14159);
+ TEST_METRICS_REPORT_BUNDLE.putString("test key", "metrics report");
TEST_PUBLISHER_BUNDLE.putString("test key", "publisher provided string");
mTestRootDir = Files.createTempDirectory("car_telemetry_test").toFile();
mTestInterimResultDir = new File(mTestRootDir, ResultStore.INTERIM_RESULT_DIR);
mTestErrorResultDir = new File(mTestRootDir, ResultStore.ERROR_RESULT_DIR);
- mTestFinalResultDir = new File(mTestRootDir, ResultStore.FINAL_RESULT_DIR);
+ mTestMetricsReportDir = new File(mTestRootDir, ResultStore.FINAL_RESULT_DIR);
mTestPublisherDataDir = new File(mTestRootDir, ResultStore.PUBLISHER_STORAGE_DIR);
- mResultStore = new ResultStore(mTestRootDir);
+ mResultStore = createResultStore();
+ }
+
+ private ResultStore createResultStore() {
+ return new ResultStore(mMockContext, mTestRootDir);
}
@Test
public void testConstructor_shouldCreateResultsFolder() {
// constructor is called in setUp()
assertThat(mTestInterimResultDir.exists()).isTrue();
- assertThat(mTestFinalResultDir.exists()).isTrue();
+ assertThat(mTestMetricsReportDir.exists()).isTrue();
assertThat(mTestErrorResultDir.exists()).isTrue();
assertThat(mTestPublisherDataDir.exists()).isTrue();
}
@@ -79,7 +104,7 @@
String testInterimFileName = "test_file_1";
writeBundleToFile(mTestInterimResultDir, testInterimFileName, TEST_INTERIM_BUNDLE);
- mResultStore = new ResultStore(mTestRootDir);
+ mResultStore = createResultStore();
// should compare value instead of reference
assertThat(mResultStore.getInterimResult(testInterimFileName).toString())
@@ -89,10 +114,13 @@
@Test
public void testFlushToDisk_shouldRemoveStaleData() throws Exception {
File staleTestFile1 = new File(mTestInterimResultDir, "stale_test_file_1");
- File staleTestFile2 = new File(mTestFinalResultDir, "stale_test_file_2");
+ File staleTestFile2 = new File(mTestMetricsReportDir, "stale_test_file_2");
File activeTestFile3 = new File(mTestInterimResultDir, "active_test_file_3");
writeBundleToFile(staleTestFile1, TEST_INTERIM_BUNDLE);
- writeBundleToFile(staleTestFile2, TEST_FINAL_BUNDLE);
+ IoUtils.writeProto(
+ staleTestFile2,
+ MetricsReportProtoUtils.buildMetricsReportList(
+ TEST_METRICS_REPORT_BUNDLE, TEST_METRICS_REPORT_BUNDLE));
writeBundleToFile(activeTestFile3, TEST_INTERIM_BUNDLE);
long currTimeMs = System.currentTimeMillis();
staleTestFile1.setLastModified(0L); // stale
@@ -140,7 +168,7 @@
File fileBar = new File(mTestInterimResultDir, "bar");
writeBundleToFile(fileFoo, TEST_INTERIM_BUNDLE);
writeBundleToFile(fileBar, TEST_INTERIM_BUNDLE);
- mResultStore = new ResultStore(mTestRootDir); // re-load data
+ mResultStore = createResultStore(); // re-load data
PersistableBundle newData = new PersistableBundle();
newData.putDouble("pi", 3.1415926);
@@ -154,68 +182,119 @@
}
@Test
- public void testGetFinalResult_whenNoData_shouldReceiveNull() throws Exception {
+ public void testGetInterimResult() throws Exception {
+ String metricsConfigName = "my_metrics_config";
+ writeBundleToFile(mTestInterimResultDir, metricsConfigName, TEST_INTERIM_BUNDLE);
+ mResultStore = createResultStore(); // reload data
+
+ PersistableBundle data = mResultStore.getInterimResult(metricsConfigName);
+
+ assertThat(data.toString()).isEqualTo(TEST_INTERIM_BUNDLE.toString());
+ }
+
+ @Test
+ public void testGetMetricsReports_whenNoData_shouldReceiveNull() {
String metricsConfigName = "my_metrics_config";
- PersistableBundle bundle = mResultStore.getFinalResult(metricsConfigName, true);
+ MetricsReportList reportList = mResultStore.getMetricsReports(metricsConfigName, true);
- assertThat(bundle).isNull();
+ assertThat(reportList).isNull();
}
@Test
- public void testGetFinalResult_whenDataCorrupt_shouldReceiveNull() throws Exception {
+ public void testGetMetricsReports_whenDataCorrupt_shouldReceiveNull() throws Exception {
String metricsConfigName = "my_metrics_config";
- Files.write(new File(mTestFinalResultDir, metricsConfigName).toPath(),
+ Files.write(new File(mTestMetricsReportDir, metricsConfigName).toPath(),
"not a bundle".getBytes(StandardCharsets.UTF_8));
- PersistableBundle bundle = mResultStore.getFinalResult(metricsConfigName, true);
+ MetricsReportList reportList = mResultStore.getMetricsReports(metricsConfigName, true);
- assertThat(bundle).isNull();
+ assertThat(reportList).isNull();
}
@Test
- public void testGetFinalResult_whenDeleteFlagTrue_shouldDeleteData() throws Exception {
- String testFinalFileName = "my_metrics_config";
- writeBundleToFile(mTestFinalResultDir, testFinalFileName, TEST_FINAL_BUNDLE);
+ public void testGetMetricsReports_whenMultipleReports_shouldReceiveCorrectList()
+ throws Exception {
+ String metricsConfigName = "my_metrics_config";
+ IoUtils.writeProto(
+ mTestMetricsReportDir,
+ metricsConfigName,
+ MetricsReportProtoUtils.buildMetricsReportList(
+ TEST_METRICS_REPORT_BUNDLE, TEST_METRICS_REPORT_BUNDLE));
- PersistableBundle bundle = mResultStore.getFinalResult(testFinalFileName, true);
+ MetricsReportList reportList = mResultStore.getMetricsReports(metricsConfigName, false);
+ assertThat(reportList.getReportCount()).isEqualTo(2);
// should compare value instead of reference
- assertThat(bundle.toString()).isEqualTo(TEST_FINAL_BUNDLE.toString());
- assertThat(new File(mTestFinalResultDir, testFinalFileName).exists()).isFalse();
+ assertThat(MetricsReportProtoUtils.getBundle(reportList, 0).toString())
+ .isEqualTo(TEST_METRICS_REPORT_BUNDLE.toString());
+ assertThat(MetricsReportProtoUtils.getBundle(reportList, 1).toString())
+ .isEqualTo(TEST_METRICS_REPORT_BUNDLE.toString());
}
@Test
- public void testGetFinalResult_whenDeleteFlagFalse_shouldNotDeleteData() throws Exception {
+ public void testGetMetricsReports_whenDeleteFlagTrue_shouldDeleteData() throws Exception {
String testFinalFileName = "my_metrics_config";
- writeBundleToFile(mTestFinalResultDir, testFinalFileName, TEST_FINAL_BUNDLE);
+ IoUtils.writeProto(
+ mTestMetricsReportDir,
+ testFinalFileName,
+ MetricsReportProtoUtils.buildMetricsReportList(
+ TEST_METRICS_REPORT_BUNDLE, TEST_METRICS_REPORT_BUNDLE));
- PersistableBundle bundle = mResultStore.getFinalResult(testFinalFileName, false);
+ MetricsReportList reportList = mResultStore.getMetricsReports(testFinalFileName, true);
+ assertThat(reportList.getReportCount()).isEqualTo(2);
// should compare value instead of reference
- assertThat(bundle.toString()).isEqualTo(TEST_FINAL_BUNDLE.toString());
- assertThat(new File(mTestFinalResultDir, testFinalFileName).exists()).isTrue();
+ assertThat(MetricsReportProtoUtils.getBundle(reportList, 0).toString())
+ .isEqualTo(TEST_METRICS_REPORT_BUNDLE.toString());
+ assertThat(MetricsReportProtoUtils.getBundle(reportList, 1).toString())
+ .isEqualTo(TEST_METRICS_REPORT_BUNDLE.toString());
+ assertThat(new File(mTestMetricsReportDir, testFinalFileName).exists()).isFalse();
}
@Test
- public void testGetFinalResults_whenHasData_shouldReturnMapWithBundle() throws Exception {
- writeBundleToFile(mTestFinalResultDir, "my_metrics_config", TEST_FINAL_BUNDLE);
+ public void testGetAllMetricsReports_shouldReturnMapWithBundle() throws Exception {
+ String configName = "my_config";
+ // 2 reports for my_config
+ IoUtils.writeProto(
+ mTestMetricsReportDir,
+ configName,
+ MetricsReportProtoUtils.buildMetricsReportList(
+ TEST_METRICS_REPORT_BUNDLE, TEST_METRICS_REPORT_BUNDLE));
+ // 1 report for my_second_config
+ String configName2 = "my_second_config";
+ PersistableBundle expectedReportForConfig2 = new PersistableBundle();
+ expectedReportForConfig2.putDouble("pi", 3.14);
+ mResultStore.putMetricsReport(configName2, expectedReportForConfig2, false);
- assertThat(mResultStore.getAllFinalResults().get("my_metrics_config").toString())
- .isEqualTo(TEST_FINAL_BUNDLE.toString());
+ Map<String, MetricsReportList> allReports = mResultStore.getAllMetricsReports();
+
+ assertThat(allReports.keySet()).containsExactly(configName, configName2);
+ // should get 2 reports for my_config
+ MetricsReportList reportsForConfig1 = allReports.get(configName);
+ assertThat(reportsForConfig1.getReportCount()).isEqualTo(2);
+ assertThat(MetricsReportProtoUtils.getBundle(reportsForConfig1, 0).toString())
+ .isEqualTo(TEST_METRICS_REPORT_BUNDLE.toString());
+ assertThat(MetricsReportProtoUtils.getBundle(reportsForConfig1, 1).toString())
+ .isEqualTo(TEST_METRICS_REPORT_BUNDLE.toString());
+ // should get 1 report for my_second_config
+ MetricsReportList reportsForConfig2 = allReports.get(configName2);
+ assertThat(reportsForConfig2.getReportCount()).isEqualTo(1);
+ assertThat(MetricsReportProtoUtils.getBundle(reportsForConfig2, 0).toString())
+ .isEqualTo(expectedReportForConfig2.toString());
}
@Test
- public void testGetFinalResults_whenNoData_shouldReceiveEmptyMap() throws Exception {
- assertThat(mResultStore.getAllFinalResults()).isEmpty();
+ public void testGetAllMetricsReports_whenNoData_shouldReceiveEmptyMap() throws Exception {
+ assertThat(mResultStore.getAllMetricsReports()).isEmpty();
}
@Test
- public void testGetFinalResults_whenDataCorrupt_shouldReceiveEmptyMap() throws Exception {
- Files.write(new File(mTestFinalResultDir, "my_metrics_config").toPath(),
+ public void testGetAllMetricsReports_whenDataCorrupt_shouldReceiveEmptyMap() throws Exception {
+ Files.write(new File(mTestMetricsReportDir, "my_metrics_config").toPath(),
"not a bundle".getBytes(StandardCharsets.UTF_8));
- assertThat(mResultStore.getAllFinalResults()).isEmpty();
+ assertThat(mResultStore.getAllMetricsReports()).isEmpty();
}
@Test
@@ -252,27 +331,67 @@
}
@Test
- public void testPutFinalResult_shouldNotWriteToDisk() {
+ public void testPutMetricsReport_shouldNotWriteToDisk() {
String metricsConfigName = "my_metrics_config";
- mResultStore.putFinalResult(metricsConfigName, TEST_FINAL_BUNDLE);
+ mResultStore.putMetricsReport(metricsConfigName, TEST_METRICS_REPORT_BUNDLE, false);
+ mResultStore.putMetricsReport(metricsConfigName, TEST_METRICS_REPORT_BUNDLE, false);
- assertThat(mTestFinalResultDir.list()).asList().doesNotContain(metricsConfigName);
- assertThat(mResultStore.getFinalResult(metricsConfigName, false)).isNotNull();
+ assertThat(mTestMetricsReportDir.list()).isEmpty();
+ assertThat(mResultStore.getMetricsReports(metricsConfigName, false).getReportCount())
+ .isEqualTo(2);
}
@Test
- public void testPutFinalResultAndFlushToDisk_shouldWriteResultAndRemoveInterim()
- throws Exception {
+ public void testPutMetricsReportAndFlushToDisk_shouldWriteToDisk() {
String metricsConfigName = "my_metrics_config";
- writeBundleToFile(mTestInterimResultDir, metricsConfigName, TEST_INTERIM_BUNDLE);
- mResultStore.putFinalResult(metricsConfigName, TEST_FINAL_BUNDLE);
+ mResultStore.putMetricsReport(
+ metricsConfigName, TEST_METRICS_REPORT_BUNDLE.deepCopy(), false);
+ mResultStore.putMetricsReport(
+ metricsConfigName, TEST_METRICS_REPORT_BUNDLE.deepCopy(), false);
mResultStore.flushToDisk();
- assertThat(mResultStore.getInterimResult(metricsConfigName)).isNull();
- assertThat(new File(mTestInterimResultDir, metricsConfigName).exists()).isFalse();
- assertThat(new File(mTestFinalResultDir, metricsConfigName).exists()).isTrue();
+ assertThat(new File(mTestMetricsReportDir, metricsConfigName).exists()).isTrue();
+ MetricsReportList reportList = mResultStore.getMetricsReports(metricsConfigName, false);
+ assertThat(reportList.getReportCount()).isEqualTo(2);
+ assertThat(MetricsReportProtoUtils.getBundle(reportList, 0).keySet())
+ .containsAtLeastElementsIn(TEST_METRICS_REPORT_BUNDLE.keySet().toArray());
+ assertThat(MetricsReportProtoUtils.getBundle(reportList, 1).keySet())
+ .containsAtLeastElementsIn(TEST_METRICS_REPORT_BUNDLE.keySet().toArray());
+ }
+
+ @Test
+ public void testPutMetricsReport_whenLastReport_shouldBuildCorrectReportContainer()
+ throws Exception {
+ String metricsConfigName = "my_metrics_config";
+ File reportListFile = new File(mTestMetricsReportDir, metricsConfigName);
+
+ mResultStore.putMetricsReport(metricsConfigName, TEST_METRICS_REPORT_BUNDLE, false);
+ mResultStore.putMetricsReport(metricsConfigName, TEST_METRICS_REPORT_BUNDLE, true);
+ mResultStore.flushToDisk();
+
+ MetricsReportList reportList = MetricsReportList.parseFrom(
+ Files.readAllBytes(reportListFile.toPath()));
+ assertThat(reportList.getReportCount()).isEqualTo(2);
+ assertThat(reportList.getReport(0).getIsLastReport()).isFalse();
+ assertThat(reportList.getReport(1).getIsLastReport()).isTrue();
+ }
+
+ @Test
+ public void testPutMetricsReport_shouldAnnotateReport() {
+ String metricsConfigName = "my_metrics_config";
+
+ mResultStore.putMetricsReport(
+ metricsConfigName, TEST_METRICS_REPORT_BUNDLE.deepCopy(), false);
+ mResultStore.putMetricsReport(
+ metricsConfigName, TEST_METRICS_REPORT_BUNDLE.deepCopy(), false);
+
+ MetricsReportList reportList = mResultStore.getMetricsReports(metricsConfigName, false);
+ PersistableBundle report1 = MetricsReportProtoUtils.getBundle(reportList, 0);
+ assertThat(report1.getInt(BUNDLE_KEY_ID)).isEqualTo(1);
+ PersistableBundle report2 = MetricsReportProtoUtils.getBundle(reportList, 1);
+ assertThat(report2.getInt(BUNDLE_KEY_ID)).isEqualTo(2);
}
@Test
@@ -299,10 +418,49 @@
}
@Test
- public void testRemovePublisherData_shouldDelete() throws Exception {
+ public void testRemoveInterimResult() throws Exception {
+ String metricsConfigName = "my_metrics_config";
+ writeBundleToFile(mTestInterimResultDir, metricsConfigName, TEST_INTERIM_BUNDLE);
+ String configName2 = "my_second_config";
+ mResultStore.putInterimResult(configName2, TEST_INTERIM_BUNDLE);
+
+ mResultStore.removeInterimResult(metricsConfigName);
+
+ assertThat(new File(mTestInterimResultDir, metricsConfigName).exists()).isFalse();
+ assertThat(mResultStore.getInterimResult(metricsConfigName)).isNull();
+ }
+
+ @Test
+ public void testRemoveFinalReports() throws Exception {
+ String metricsConfigName = "my_metrics_config";
+ IoUtils.writeProto(
+ mTestMetricsReportDir,
+ metricsConfigName,
+ MetricsReportProtoUtils.buildMetricsReportList(
+ TEST_METRICS_REPORT_BUNDLE, TEST_METRICS_REPORT_BUNDLE));
+
+ mResultStore.removeMetricsReports(metricsConfigName);
+
+ assertThat(new File(mTestInterimResultDir, metricsConfigName).exists()).isFalse();
+ assertThat(mResultStore.getMetricsReports(metricsConfigName, false)).isNull();
+ }
+
+ @Test
+ public void testRemoveErrorResult() throws Exception {
+ String metricsConfigName = "my_metrics_config";
+ writeErrorToFile(metricsConfigName, TEST_TELEMETRY_ERROR);
+
+ mResultStore.removeErrorResult(metricsConfigName);
+
+ assertThat(new File(mTestErrorResultDir, metricsConfigName).exists()).isFalse();
+ assertThat(mResultStore.getErrorResult(metricsConfigName, false)).isNull();
+ }
+
+ @Test
+ public void testRemovePublisherData() throws Exception {
String publisherName = "publisher 1";
writeBundleToFile(mTestPublisherDataDir, publisherName, TEST_PUBLISHER_BUNDLE);
- mResultStore = new ResultStore(mTestRootDir); // reload data
+ mResultStore = createResultStore(); // reload data
mResultStore.removePublisherData(publisherName);
@@ -310,39 +468,27 @@
}
@Test
- public void testRemoveResult_whenInterimResult_shouldDelete() throws Exception {
+ public void testRemoveResult() throws Exception {
String metricsConfigName = "my_metrics_config";
writeBundleToFile(mTestInterimResultDir, metricsConfigName, TEST_INTERIM_BUNDLE);
+ IoUtils.writeProto(
+ mTestMetricsReportDir,
+ metricsConfigName,
+ MetricsReportProtoUtils.buildMetricsReportList(
+ TEST_METRICS_REPORT_BUNDLE, TEST_METRICS_REPORT_BUNDLE));
+ writeErrorToFile(metricsConfigName, TEST_TELEMETRY_ERROR);
mResultStore.removeResult(metricsConfigName);
assertThat(new File(mTestInterimResultDir, metricsConfigName).exists()).isFalse();
- }
-
- @Test
- public void testRemoveResult_whenFinalResult_shouldDelete() throws Exception {
- String metricsConfigName = "my_metrics_config";
- writeBundleToFile(mTestFinalResultDir, metricsConfigName, TEST_FINAL_BUNDLE);
-
- mResultStore.removeResult(metricsConfigName);
-
- assertThat(new File(mTestFinalResultDir, metricsConfigName).exists()).isFalse();
- }
-
- @Test
- public void testRemoveResult_whenErrorResult_shouldDelete() throws Exception {
- String metricsConfigName = "my_metrics_config";
- writeBundleToFile(mTestErrorResultDir, metricsConfigName, TEST_FINAL_BUNDLE);
-
- mResultStore.removeResult(metricsConfigName);
-
+ assertThat(new File(mTestMetricsReportDir, metricsConfigName).exists()).isFalse();
assertThat(new File(mTestErrorResultDir, metricsConfigName).exists()).isFalse();
}
@Test
- public void testRemoveAllResults_shouldDeleteAll() throws Exception {
+ public void testRemoveAllResults() {
mResultStore.putInterimResult("config 1", TEST_INTERIM_BUNDLE);
- mResultStore.putFinalResult("config 2", TEST_FINAL_BUNDLE);
+ mResultStore.putMetricsReport("config 2", TEST_METRICS_REPORT_BUNDLE, false);
mResultStore.putErrorResult("config 3", TEST_TELEMETRY_ERROR);
mResultStore.putPublisherData("publisher 1", TEST_PUBLISHER_BUNDLE);
mResultStore.flushToDisk();
@@ -350,7 +496,7 @@
mResultStore.removeAllResults();
assertThat(mTestInterimResultDir.listFiles()).isEmpty();
- assertThat(mTestFinalResultDir.listFiles()).isEmpty();
+ assertThat(mTestMetricsReportDir.listFiles()).isEmpty();
assertThat(mTestErrorResultDir.listFiles()).isEmpty();
assertThat(mTestPublisherDataDir.listFiles()).isEmpty();
}
@@ -358,9 +504,13 @@
@Test
public void testGetFinishedMetricsConfigNames() throws Exception {
mResultStore.putInterimResult("name0", TEST_INTERIM_BUNDLE);
- mResultStore.putFinalResult("name1", TEST_FINAL_BUNDLE);
+ mResultStore.putMetricsReport("name1", TEST_METRICS_REPORT_BUNDLE, false);
mResultStore.putErrorResult("name2", TEST_TELEMETRY_ERROR);
- writeBundleToFile(mTestFinalResultDir, "name3", TEST_FINAL_BUNDLE);
+ IoUtils.writeProto(
+ mTestMetricsReportDir,
+ "name3",
+ MetricsReportProtoUtils.buildMetricsReportList(
+ TEST_METRICS_REPORT_BUNDLE, TEST_METRICS_REPORT_BUNDLE));
writeErrorToFile("name4", TEST_TELEMETRY_ERROR);
Set<String> names = mResultStore.getFinishedMetricsConfigNames();
diff --git a/tests/carservice_unit_test/src/com/android/car/telemetry/databroker/DataBrokerTest.java b/tests/carservice_unit_test/src/com/android/car/telemetry/databroker/DataBrokerTest.java
index 927efbc..69f62160 100644
--- a/tests/carservice_unit_test/src/com/android/car/telemetry/databroker/DataBrokerTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/telemetry/databroker/DataBrokerTest.java
@@ -354,6 +354,33 @@
}
@Test
+ public void testScheduleNextTask_whenScriptExecutorBypassed_shouldStoreFinalResult()
+ throws Exception {
+ mData.putBoolean("bypass successful", true);
+ mData.putDouble("value of pi", 3.14159265359);
+ TelemetryProto.Subscriber subscriberWithoutHandler =
+ TelemetryProto.Subscriber.newBuilder().setPublisher(
+ PUBLISHER_CONFIGURATION).setPriority(PRIORITY_HIGH).build();
+ TelemetryProto.MetricsConfig metricConfigForBypass =
+ TelemetryProto.MetricsConfig.newBuilder().setName("Bypass").setVersion(
+ 1).addSubscribers(subscriberWithoutHandler).build();
+ ScriptExecutionTask bypassTask = new ScriptExecutionTask(
+ new DataSubscriber(mDataBroker, metricConfigForBypass, subscriberWithoutHandler),
+ mData,
+ SystemClock.elapsedRealtime(),
+ false,
+ TelemetryProto.Publisher.PublisherCase.STATS.getNumber());
+ mDataBroker.getTaskQueue().add(bypassTask);
+
+ mDataBroker.scheduleNextTask();
+ waitForTelemetryThreadToFinish();
+
+ assertThat(mFakeScriptExecutor.getInvokeScriptCount()).isEqualTo(0);
+ verify(mMockDataBrokerListener).onMetricsReport(
+ eq(bypassTask.getMetricsConfig().getName()), eq(mData), isNull());
+ }
+
+ @Test
public void testScheduleNextTask_whenInterimDataExists_shouldPassToScriptExecutor()
throws Exception {
mData.putDouble("value of golden ratio", 1.618033);
diff --git a/tests/carservice_unit_test/src/com/android/car/telemetry/publisher/CarTelemetrydPublisherTest.java b/tests/carservice_unit_test/src/com/android/car/telemetry/publisher/CarTelemetrydPublisherTest.java
index ae600b1..503cbea 100644
--- a/tests/carservice_unit_test/src/com/android/car/telemetry/publisher/CarTelemetrydPublisherTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/telemetry/publisher/CarTelemetrydPublisherTest.java
@@ -23,21 +23,31 @@
import static org.junit.Assert.assertThrows;
import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.annotation.Nullable;
+import android.automotive.telemetry.internal.CarDataInternal;
import android.automotive.telemetry.internal.ICarDataListener;
import android.automotive.telemetry.internal.ICarTelemetryInternal;
import android.car.telemetry.TelemetryProto;
import android.car.test.mocks.AbstractExtendedMockitoTestCase;
import android.os.IBinder;
import android.os.Looper;
+import android.os.PersistableBundle;
import android.os.RemoteException;
import android.os.ServiceManager;
+import android.util.ArraySet;
import com.android.car.CarLog;
import com.android.car.telemetry.databroker.DataSubscriber;
+import com.android.car.telemetry.sessioncontroller.SessionAnnotation;
+import com.android.car.telemetry.sessioncontroller.SessionController;
import com.android.car.test.FakeHandlerWrapper;
import org.junit.Before;
@@ -49,6 +59,11 @@
import org.mockito.Mockito;
import org.mockito.junit.MockitoJUnitRunner;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Set;
+import java.util.stream.Collectors;
+
@RunWith(MockitoJUnitRunner.class)
public class CarTelemetrydPublisherTest extends AbstractExtendedMockitoTestCase {
private static final String SERVICE_NAME = ICarTelemetryInternal.DESCRIPTOR + "/default";
@@ -58,15 +73,30 @@
.setCartelemetryd(TelemetryProto.CarTelemetrydPublisher.newBuilder()
.setId(CAR_DATA_ID_1))
.build();
+ private static final SessionAnnotation SESSION_ANNOTATION_BEGIN_1 =
+ new SessionAnnotation(1, SessionController.STATE_ENTER_DRIVING_SESSION, 0, 0, "");
+ private static final String[] SESSION_ANNOTATION_KEYS =
+ {SessionAnnotation.ANNOTATION_BUNDLE_KEY_SESSION_ID,
+ SessionAnnotation.ANNOTATION_BUNDLE_KEY_BOOT_REASON,
+ SessionAnnotation.ANNOTATION_BUNDLE_KEY_SESSION_STATE,
+ SessionAnnotation.ANNOTATION_BUNDLE_KEY_CREATED_AT_MILLIS,
+ SessionAnnotation.ANNOTATION_BUNDLE_KEY_CREATED_AT_SINCE_BOOT_MILLIS};
private final FakeHandlerWrapper mFakeHandlerWrapper =
new FakeHandlerWrapper(Looper.getMainLooper(), FakeHandlerWrapper.Mode.IMMEDIATE);
private final FakePublisherListener mFakePublisherListener = new FakePublisherListener();
- @Mock private IBinder mMockBinder;
- @Mock private DataSubscriber mMockDataSubscriber;
+ @Mock
+ private IBinder mMockBinder;
+ @Mock
+ private DataSubscriber mMockDataSubscriber;
+ @Mock
+ private SessionController mMockSessionController;
- @Captor private ArgumentCaptor<IBinder.DeathRecipient> mLinkToDeathCallbackCaptor;
+ @Captor
+ private ArgumentCaptor<IBinder.DeathRecipient> mLinkToDeathCallbackCaptor;
+ @Captor
+ private ArgumentCaptor<PersistableBundle> mBundleCaptor;
private FakeCarTelemetryInternal mFakeCarTelemetryInternal;
private CarTelemetrydPublisher mPublisher;
@@ -75,13 +105,22 @@
super(CarLog.TAG_TELEMETRY);
}
+ private CarDataInternal buildCarDataInternal(int id, byte[] content) {
+ CarDataInternal data = new CarDataInternal();
+ data.id = id;
+ data.content = content;
+ return data;
+ }
+
@Before
public void setUp() throws Exception {
mPublisher = new CarTelemetrydPublisher(
- mFakePublisherListener, mFakeHandlerWrapper.getMockHandler());
+ mFakePublisherListener, mFakeHandlerWrapper.getMockHandler(),
+ mMockSessionController);
mFakeCarTelemetryInternal = new FakeCarTelemetryInternal(mMockBinder);
when(mMockDataSubscriber.getPublisherParam()).thenReturn(PUBLISHER_PARAMS_1);
when(mMockBinder.queryLocalInterface(any())).thenReturn(mFakeCarTelemetryInternal);
+ when(mMockSessionController.getSessionAnnotation()).thenReturn(SESSION_ANNOTATION_BEGIN_1);
doNothing().when(mMockBinder).linkToDeath(mLinkToDeathCallbackCaptor.capture(), anyInt());
doReturn(mMockBinder).when(() -> ServiceManager.checkService(SERVICE_NAME));
}
@@ -98,6 +137,7 @@
assertThat(mFakeCarTelemetryInternal.mListener).isNotNull();
assertThat(mPublisher.isConnectedToCarTelemetryd()).isTrue();
assertThat(mPublisher.hasDataSubscriber(mMockDataSubscriber)).isTrue();
+ assertThat(mFakeCarTelemetryInternal.mCarDataIds).containsExactly(CAR_DATA_ID_1);
}
@Test
@@ -184,11 +224,175 @@
assertThat(mFakePublisherListener.mFailedConfigs).hasSize(1);
}
+ @Test
+ public void testPushesPublishedData_whenOnCarDataReceived() throws RemoteException {
+ mPublisher.addDataSubscriber(mMockDataSubscriber);
+
+ mFakeCarTelemetryInternal.mListener.onCarDataReceived(
+ new CarDataInternal[]{buildCarDataInternal(CAR_DATA_ID_1, new byte[]{1, 2, 3})});
+
+ // Also verifies that the published data is not large.
+ verify(mMockDataSubscriber).push(mBundleCaptor.capture(), eq(false));
+ PersistableBundle result = mBundleCaptor.getValue();
+ // Verify published contents.
+ assertThat(result.getInt(
+ Constants.CAR_TELEMETRYD_BUNDLE_KEY_ID)).isEqualTo(
+ CAR_DATA_ID_1);
+ assertThat(result.getIntArray(
+ Constants.CAR_TELEMETRYD_BUNDLE_KEY_CONTENT)).asList()
+ .containsExactly(1, 2, 3).inOrder();
+ // Verify session annotations are also present.
+ assertThat(result.keySet()).containsAtLeastElementsIn(SESSION_ANNOTATION_KEYS);
+ }
+
+ @Test
+ public void testPushesPublishedData_multipleData() throws RemoteException {
+ mPublisher.addDataSubscriber(mMockDataSubscriber);
+
+ mFakeCarTelemetryInternal.mListener.onCarDataReceived(
+ new CarDataInternal[]{buildCarDataInternal(CAR_DATA_ID_1, new byte[]{1, 2, 3}),
+ buildCarDataInternal(CAR_DATA_ID_1, new byte[]{3, 2, 1})});
+
+ verify(mMockDataSubscriber, times(2)).push(mBundleCaptor.capture(),
+ anyBoolean());
+ }
+
+ @Test
+ public void testPushesPublishedData_multipleSubscribers() throws RemoteException {
+ DataSubscriber subscriber2 = Mockito.mock(DataSubscriber.class);
+ when(subscriber2.getPublisherParam()).thenReturn(PUBLISHER_PARAMS_1);
+ mPublisher.addDataSubscriber(mMockDataSubscriber);
+ mPublisher.addDataSubscriber(subscriber2);
+
+ mFakeCarTelemetryInternal.mListener.onCarDataReceived(
+ new CarDataInternal[]{buildCarDataInternal(CAR_DATA_ID_1, new byte[]{1, 2, 3}),
+ buildCarDataInternal(CAR_DATA_ID_1, new byte[]{3, 2, 1}),
+ buildCarDataInternal(CAR_DATA_ID_1, new byte[]{30, 20, 10})});
+
+ verify(mMockDataSubscriber, times(3)).push(mBundleCaptor.capture(),
+ eq(false));
+ List<PersistableBundle> telemetryDataList = mBundleCaptor.getAllValues();
+ // Verify published contents.
+ assertThat(telemetryDataList.get(0).getInt(
+ Constants.CAR_TELEMETRYD_BUNDLE_KEY_ID)).isEqualTo(
+ CAR_DATA_ID_1);
+ assertThat(telemetryDataList.get(0).getIntArray(
+ Constants.CAR_TELEMETRYD_BUNDLE_KEY_CONTENT)).asList()
+ .containsExactly(1, 2, 3).inOrder();
+ // Verify session annotations are also present.
+ assertThat(telemetryDataList.get(0).keySet()).containsAtLeastElementsIn(
+ SESSION_ANNOTATION_KEYS);
+
+
+ // Verify published contents.
+ assertThat(telemetryDataList.get(1).getInt(
+ Constants.CAR_TELEMETRYD_BUNDLE_KEY_ID)).isEqualTo(
+ CAR_DATA_ID_1);
+ assertThat(telemetryDataList.get(1).getIntArray(
+ Constants.CAR_TELEMETRYD_BUNDLE_KEY_CONTENT)).asList()
+ .containsExactly(
+ 3, 2, 1).inOrder();
+ // Verify session annotations are also present.
+ assertThat(telemetryDataList.get(1).keySet()).containsAtLeastElementsIn(
+ SESSION_ANNOTATION_KEYS);
+
+
+ // Verify published contents.
+ assertThat(telemetryDataList.get(2).getInt(
+ Constants.CAR_TELEMETRYD_BUNDLE_KEY_ID)).isEqualTo(
+ CAR_DATA_ID_1);
+ assertThat(telemetryDataList.get(2).getIntArray(
+ Constants.CAR_TELEMETRYD_BUNDLE_KEY_CONTENT)).asList()
+ .containsExactly(30, 20, 10).inOrder();
+ // Verify session annotations are also present.
+ assertThat(telemetryDataList.get(2).keySet()).containsAtLeastElementsIn(
+ SESSION_ANNOTATION_KEYS);
+
+
+ // Verify that the other subscriber received the same data.
+ verify(subscriber2, times(3)).push(mBundleCaptor.capture(), eq(false));
+ telemetryDataList = mBundleCaptor.getAllValues();
+ // Verify published contents.
+ assertThat(telemetryDataList.get(0).getInt(
+ Constants.CAR_TELEMETRYD_BUNDLE_KEY_ID)).isEqualTo(
+ CAR_DATA_ID_1);
+ assertThat(telemetryDataList.get(0).getIntArray(
+ Constants.CAR_TELEMETRYD_BUNDLE_KEY_CONTENT)).asList()
+ .containsExactly(1, 2, 3).inOrder();
+ // Verify session annotations are also present.
+ assertThat(telemetryDataList.get(0).keySet()).containsAtLeastElementsIn(
+ SESSION_ANNOTATION_KEYS);
+
+
+ // Verify published contents.
+ assertThat(telemetryDataList.get(1).getInt(
+ Constants.CAR_TELEMETRYD_BUNDLE_KEY_ID)).isEqualTo(
+ CAR_DATA_ID_1);
+ assertThat(telemetryDataList.get(1).getIntArray(
+ Constants.CAR_TELEMETRYD_BUNDLE_KEY_CONTENT)).asList()
+ .containsExactly(3, 2, 1).inOrder();
+ // Verify session annotations are also present.
+ assertThat(telemetryDataList.get(1).keySet()).containsAtLeastElementsIn(
+ SESSION_ANNOTATION_KEYS);
+
+
+ // Verify published contents.
+ assertThat(telemetryDataList.get(2).getInt(
+ Constants.CAR_TELEMETRYD_BUNDLE_KEY_ID)).isEqualTo(
+ CAR_DATA_ID_1);
+ assertThat(telemetryDataList.get(2).getIntArray(
+ Constants.CAR_TELEMETRYD_BUNDLE_KEY_CONTENT)).asList()
+ .containsExactly(30, 20, 10).inOrder();
+ // Verify session annotations are also present.
+ assertThat(telemetryDataList.get(2).keySet()).containsAtLeastElementsIn(
+ SESSION_ANNOTATION_KEYS);
+ }
+
+ @Test
+ public void testPushesPublishedData_noMatchingSubscribers() throws RemoteException {
+ mPublisher.addDataSubscriber(mMockDataSubscriber);
+
+ mFakeCarTelemetryInternal.mListener.onCarDataReceived(
+ new CarDataInternal[]{buildCarDataInternal(10, new byte[]{1, 2, 3}),
+ buildCarDataInternal(20, new byte[]{3, 2, 1}),
+ buildCarDataInternal(2000, new byte[]{30, 20, 10})});
+
+ // No subscribers are called because the generated data ids 30, 100, 2000 are not
+ // subscribed to.
+ verify(mMockDataSubscriber, never()).push(mBundleCaptor.capture(), anyBoolean());
+ }
+
+ @Test
+ public void testPushesPublishedData_detectsLargeData() throws RemoteException {
+ mPublisher.addDataSubscriber(mMockDataSubscriber);
+
+ mFakeCarTelemetryInternal.mListener.onCarDataReceived(new CarDataInternal[]{
+ buildCarDataInternal(CAR_DATA_ID_1,
+ new byte[DataSubscriber.SCRIPT_INPUT_SIZE_THRESHOLD_BYTES + 1])});
+
+ // Also verifies that the published data is large.
+ verify(mMockDataSubscriber).push(mBundleCaptor.capture(), eq(true));
+ PersistableBundle result = mBundleCaptor.getValue();
+ // Verify published contents.
+ assertThat(result.getInt(
+ Constants.CAR_TELEMETRYD_BUNDLE_KEY_ID)).isEqualTo(
+ CAR_DATA_ID_1);
+ assertThat(result.getIntArray(
+ Constants.CAR_TELEMETRYD_BUNDLE_KEY_CONTENT)).asList()
+ .hasSize(DataSubscriber.SCRIPT_INPUT_SIZE_THRESHOLD_BYTES + 1);
+ // Verify session annotations are also present.
+ assertThat(result.keySet()).containsAtLeastElementsIn(SESSION_ANNOTATION_KEYS);
+ }
+
+
private static class FakeCarTelemetryInternal implements ICarTelemetryInternal {
- @Nullable ICarDataListener mListener;
- int mSetListenerCallCount = 0;
private final IBinder mBinder;
- @Nullable private RemoteException mApiFailure = null;
+ @Nullable
+ ICarDataListener mListener;
+ int mSetListenerCallCount = 0;
+ @Nullable
+ private RemoteException mApiFailure = null;
+ private Set<Integer> mCarDataIds = new ArraySet<>();
FakeCarTelemetryInternal(IBinder binder) {
mBinder = binder;
@@ -216,6 +420,16 @@
mListener = null;
}
+ @Override
+ public void addCarDataIds(int[] ids) throws RemoteException {
+ mCarDataIds.addAll(Arrays.stream(ids).boxed().collect(Collectors.toList()));
+ }
+
+ @Override
+ public void removeCarDataIds(int[] ids) throws RemoteException {
+ mCarDataIds.removeAll(Arrays.stream(ids).boxed().collect(Collectors.toList()));
+ }
+
void setApiFailure(RemoteException e) {
mApiFailure = e;
}
diff --git a/tests/carservice_unit_test/src/com/android/car/telemetry/publisher/ConnectivityPublisherTest.java b/tests/carservice_unit_test/src/com/android/car/telemetry/publisher/ConnectivityPublisherTest.java
index 66ceb64..99e42a8 100644
--- a/tests/carservice_unit_test/src/com/android/car/telemetry/publisher/ConnectivityPublisherTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/telemetry/publisher/ConnectivityPublisherTest.java
@@ -32,6 +32,7 @@
import android.car.telemetry.TelemetryProto;
import android.car.telemetry.TelemetryProto.ConnectivityPublisher.OemType;
import android.car.telemetry.TelemetryProto.ConnectivityPublisher.Transport;
+import android.content.Context;
import android.net.ConnectivityManager;
import android.net.NetworkIdentity;
import android.net.NetworkTemplate;
@@ -143,6 +144,7 @@
private static final int UID_3 = 3;
private static final int UID_4 = 4;
+ @Mock private Context mMockContext;
@Mock private UidPackageMapper mMockUidMapper;
private final long mNow = System.currentTimeMillis(); // since epoch
@@ -173,7 +175,7 @@
@Before
public void setUp() throws Exception {
mTestRootDir = Files.createTempDirectory("car_telemetry_test").toFile();
- mResultStore = new ResultStore(mTestRootDir);
+ mResultStore = new ResultStore(mMockContext, mTestRootDir);
when(mMockUidMapper.getPackagesForUid(anyInt())).thenReturn(List.of("pkg1"));
mPublisher =
new ConnectivityPublisher(
diff --git a/tests/carservice_unit_test/src/com/android/car/telemetry/publisher/MemoryPublisherTest.java b/tests/carservice_unit_test/src/com/android/car/telemetry/publisher/MemoryPublisherTest.java
index 11112b7..9d26b58 100644
--- a/tests/carservice_unit_test/src/com/android/car/telemetry/publisher/MemoryPublisherTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/telemetry/publisher/MemoryPublisherTest.java
@@ -40,6 +40,8 @@
import com.android.car.telemetry.ResultStore;
import com.android.car.telemetry.databroker.DataSubscriber;
+import com.android.car.telemetry.sessioncontroller.SessionAnnotation;
+import com.android.car.telemetry.sessioncontroller.SessionController;
import com.android.car.test.FakeHandlerWrapper;
import com.google.common.collect.Range;
@@ -97,10 +99,14 @@
@Captor
private ArgumentCaptor<PersistableBundle> mBundleCaptor;
+ @Captor
+ private ArgumentCaptor<SessionController.SessionControllerCallback> mSessionCallbackCaptor;
@Mock
private DataSubscriber mMockDataSubscriber;
@Mock
private ResultStore mMockResultStore;
+ @Mock
+ private SessionController mMockSessionController;
@Before
public void setUp() throws Exception {
@@ -116,6 +122,7 @@
// create MemoryPublisher
mPublisher = createPublisher(mTempFile.toPath());
+ verify(mMockSessionController).registerCallback(mSessionCallbackCaptor.capture());
}
/**
@@ -127,6 +134,7 @@
mFakePublisherListener,
mFakeHandlerWrapper.getMockHandler(),
mMockResultStore,
+ mMockSessionController,
meminfoPath);
}
@@ -141,6 +149,22 @@
}
@Test
+ public void testAddDataSubscriber_annotatesWithDrivingSessionData() {
+ SessionAnnotation sessionAnnotation = new SessionAnnotation(
+ 2, SessionController.STATE_ENTER_DRIVING_SESSION, 123, 1234, "reboot");
+
+ mSessionCallbackCaptor.getValue().onSessionStateChanged(sessionAnnotation);
+ mPublisher.addDataSubscriber(mMockDataSubscriber);
+
+ verify(mMockDataSubscriber).push(mBundleCaptor.capture());
+ PersistableBundle report = mBundleCaptor.getValue();
+ assertThat(report.getString(DATA_BUNDLE_KEY_MEMINFO)).isEqualTo(FAKE_MEMINFO);
+ assertThat(report.getInt(SessionAnnotation.ANNOTATION_BUNDLE_KEY_SESSION_ID)).isEqualTo(2);
+ assertThat(report.getString(SessionAnnotation.ANNOTATION_BUNDLE_KEY_BOOT_REASON))
+ .isEqualTo("reboot");
+ }
+
+ @Test
public void testAddDataSubscriber_whenDataSubscriberAlreadyExists_throwsException() {
mPublisher.addDataSubscriber(mMockDataSubscriber);
diff --git a/tests/carservice_unit_test/src/com/android/car/telemetry/publisher/StatsPublisherTest.java b/tests/carservice_unit_test/src/com/android/car/telemetry/publisher/StatsPublisherTest.java
index e1359fd..f8f5f6d 100644
--- a/tests/carservice_unit_test/src/com/android/car/telemetry/publisher/StatsPublisherTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/telemetry/publisher/StatsPublisherTest.java
@@ -45,6 +45,7 @@
import android.app.StatsManager;
import android.car.telemetry.TelemetryProto;
+import android.content.Context;
import android.os.Looper;
import android.os.Message;
import android.os.PersistableBundle;
@@ -54,6 +55,7 @@
import com.android.car.telemetry.AtomsProto.AppStartMemoryStateCaptured;
import com.android.car.telemetry.AtomsProto.Atom;
import com.android.car.telemetry.AtomsProto.ProcessMemoryState;
+import com.android.car.telemetry.ResultStore;
import com.android.car.telemetry.StatsLogProto;
import com.android.car.telemetry.StatsLogProto.ConfigMetricsReport;
import com.android.car.telemetry.StatsLogProto.DimensionsValue;
@@ -77,8 +79,6 @@
import org.mockito.Mockito;
import org.mockito.junit.MockitoJUnitRunner;
-import java.io.File;
-import java.io.FileInputStream;
import java.nio.file.Files;
import java.util.Arrays;
@@ -259,16 +259,18 @@
new FakeHandlerWrapper(Looper.getMainLooper(), FakeHandlerWrapper.Mode.QUEUEING);
private final FakePublisherListener mFakePublisherListener = new FakePublisherListener();
- private File mRootDirectory;
+ private ResultStore mResultStore;
private StatsPublisher mPublisher; // subject
+ @Mock private Context mMockContext;
@Mock private StatsManagerProxy mStatsManager;
@Captor private ArgumentCaptor<PersistableBundle> mBundleCaptor;
@Before
public void setUp() throws Exception {
- mRootDirectory = Files.createTempDirectory("telemetry_test").toFile();
+ mResultStore = new ResultStore(
+ mMockContext, Files.createTempDirectory("telemetry_test").toFile());
mPublisher = createRestartedPublisher();
when(mStatsManager.getStatsMetadata()).thenReturn(CONFIG_STATS_REPORT.toByteArray());
}
@@ -277,11 +279,11 @@
* Emulates a restart by creating a new StatsPublisher. StatsManager and PersistableBundle
* stays the same.
*/
- private StatsPublisher createRestartedPublisher() throws Exception {
+ private StatsPublisher createRestartedPublisher() {
return new StatsPublisher(
mFakePublisherListener,
mStatsManager,
- mRootDirectory,
+ mResultStore,
mFakeHandlerWrapper.getMockHandler());
}
@@ -349,7 +351,8 @@
mPublisher.removeDataSubscriber(DATA_SUBSCRIBER_1);
verify(mStatsManager, times(1)).removeConfig(SUBSCRIBER_1_HASH);
- assertThat(getSavedStatsConfigs().keySet()).isEmpty();
+ assertThat(mResultStore.getPublisherData(StatsPublisher.class.getSimpleName(), false))
+ .isNull();
assertThat(mPublisher.hasDataSubscriber(DATA_SUBSCRIBER_1)).isFalse();
}
@@ -373,7 +376,8 @@
publisher2.removeAllDataSubscribers();
verify(mStatsManager, times(1)).removeConfig(SUBSCRIBER_1_HASH);
- assertThat(getSavedStatsConfigs().keySet()).isEmpty();
+ assertThat(mResultStore.getPublisherData(StatsPublisher.class.getSimpleName(), false))
+ .isNull();
assertThat(publisher2.hasDataSubscriber(DATA_SUBSCRIBER_1)).isFalse();
}
@@ -465,7 +469,7 @@
}
@Test
- public void testBundleWithLargeSize_isLargeData() throws Exception {
+ public void testBundleWithLargeSize_isLargeData() {
PersistableBundle bundle = new PersistableBundle();
bundle.putBooleanArray("bool", new boolean[1000]);
bundle.putLongArray("long", new long[1000]);
@@ -481,7 +485,7 @@
}
@Test
- public void testBundleWithSmallSize_isNotLargeData() throws Exception {
+ public void testBundleWithSmallSize_isNotLargeData() {
PersistableBundle bundle = new PersistableBundle();
bundle.putBooleanArray("bool", new boolean[100]);
bundle.putLongArray("long", new long[100]);
@@ -520,16 +524,6 @@
.hasMessageThat().contains("Found invalid configs");
}
- private PersistableBundle getSavedStatsConfigs() throws Exception {
- File savedConfigsFile = new File(mRootDirectory, StatsPublisher.SAVED_STATS_CONFIGS_FILE);
- if (!savedConfigsFile.exists()) {
- return new PersistableBundle();
- }
- try (FileInputStream fileInputStream = new FileInputStream(savedConfigsFile)) {
- return PersistableBundle.readFromStream(fileInputStream);
- }
- }
-
private static void assertThatMessageIsScheduledWithGivenDelay(Message msg, long delayMillis) {
long expectedTimeMillis = SystemClock.uptimeMillis() + delayMillis;
long deltaMillis = 1000; // +/- 1 seconds is good enough for testing
diff --git a/tests/carservice_unit_test/src/com/android/car/telemetry/publisher/VehiclePropertyPublisherTest.java b/tests/carservice_unit_test/src/com/android/car/telemetry/publisher/VehiclePropertyPublisherTest.java
index 792119c..2536327 100644
--- a/tests/carservice_unit_test/src/com/android/car/telemetry/publisher/VehiclePropertyPublisherTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/telemetry/publisher/VehiclePropertyPublisherTest.java
@@ -18,6 +18,16 @@
import static android.car.hardware.property.CarPropertyEvent.PROPERTY_EVENT_PROPERTY_CHANGE;
+import static com.android.car.telemetry.publisher.VehiclePropertyPublisher.BUNDLE_BOOLEAN_KEY;
+import static com.android.car.telemetry.publisher.VehiclePropertyPublisher.BUNDLE_BYTE_ARRAY_KEY;
+import static com.android.car.telemetry.publisher.VehiclePropertyPublisher.BUNDLE_FLOAT_ARRAY_KEY;
+import static com.android.car.telemetry.publisher.VehiclePropertyPublisher.BUNDLE_FLOAT_KEY;
+import static com.android.car.telemetry.publisher.VehiclePropertyPublisher.BUNDLE_INT_ARRAY_KEY;
+import static com.android.car.telemetry.publisher.VehiclePropertyPublisher.BUNDLE_INT_KEY;
+import static com.android.car.telemetry.publisher.VehiclePropertyPublisher.BUNDLE_LONG_ARRAY_KEY;
+import static com.android.car.telemetry.publisher.VehiclePropertyPublisher.BUNDLE_LONG_KEY;
+import static com.android.car.telemetry.publisher.VehiclePropertyPublisher.BUNDLE_STRING_KEY;
+
import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.assertThrows;
@@ -51,24 +61,133 @@
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collections;
import java.util.List;
@RunWith(MockitoJUnitRunner.class)
public class VehiclePropertyPublisherTest {
- private static final int PROP_ID_1 = 100;
- private static final int PROP_ID_2 = 102;
+ private static final int PROP_STRING_ID = 0x00100000;
+ private static final int PROP_BOOLEAN_ID = 0x00200000;
+ private static final int PROP_INT_ID = 0x00400000;
+ private static final int PROP_INT_ID_2 = 0x00400001;
+ private static final int PROP_INT_VEC_ID = 0x00410000;
+ private static final int PROP_LONG_ID = 0x00500000;
+ private static final int PROP_LONG_VEC_ID = 0x00510000;
+ private static final int PROP_FLOAT_ID = 0x00600000;
+ private static final int PROP_FLOAT_VEC_ID = 0x00610000;
+ private static final int PROP_BYTES_ID = 0x00700000;
+ private static final int PROP_MIXED_ID = 0x00e00000;
private static final int AREA_ID = 20;
private static final float PROP_READ_RATE = 0.0f;
- private static final CarPropertyEvent PROP_EVENT_1 =
+ private static final CarPropertyEvent PROP_STRING_EVENT =
new CarPropertyEvent(PROPERTY_EVENT_PROPERTY_CHANGE,
- new CarPropertyValue<>(PROP_ID_1, AREA_ID, /* value= */ 1));
+ new CarPropertyValue<>(PROP_STRING_ID, AREA_ID, "hi"));
+ private static final CarPropertyEvent PROP_BOOLEAN_EVENT =
+ new CarPropertyEvent(PROPERTY_EVENT_PROPERTY_CHANGE,
+ new CarPropertyValue<>(PROP_BOOLEAN_ID, AREA_ID, true));
+ private static final CarPropertyEvent PROP_INT_EVENT =
+ new CarPropertyEvent(PROPERTY_EVENT_PROPERTY_CHANGE,
+ new CarPropertyValue<>(PROP_INT_ID, AREA_ID, 1));
+ private static final CarPropertyEvent PROP_INT_VEC_EVENT =
+ new CarPropertyEvent(PROPERTY_EVENT_PROPERTY_CHANGE,
+ new CarPropertyValue<>(PROP_INT_VEC_ID, AREA_ID, new Integer[] {1, 2}));
+ private static final CarPropertyEvent PROP_LONG_EVENT =
+ new CarPropertyEvent(PROPERTY_EVENT_PROPERTY_CHANGE,
+ new CarPropertyValue<>(PROP_LONG_ID, AREA_ID, 10L));
+ private static final CarPropertyEvent PROP_LONG_VEC_EVENT =
+ new CarPropertyEvent(PROPERTY_EVENT_PROPERTY_CHANGE,
+ new CarPropertyValue<>(PROP_LONG_VEC_ID, AREA_ID, new Long[] {10L, 20L}));
+ private static final CarPropertyEvent PROP_FLOAT_EVENT =
+ new CarPropertyEvent(PROPERTY_EVENT_PROPERTY_CHANGE,
+ new CarPropertyValue<>(PROP_FLOAT_ID, AREA_ID, 1f));
+ private static final CarPropertyEvent PROP_FLOAT_VEC_EVENT =
+ new CarPropertyEvent(PROPERTY_EVENT_PROPERTY_CHANGE,
+ new CarPropertyValue<>(PROP_FLOAT_VEC_ID, AREA_ID, new Float[] {1f, 2f}));
+ private static final CarPropertyEvent PROP_BYTES_EVENT =
+ new CarPropertyEvent(PROPERTY_EVENT_PROPERTY_CHANGE,
+ new CarPropertyValue<>(PROP_BYTES_ID, AREA_ID,
+ new byte[] {(byte) 1, (byte) 2}));
+ private static final CarPropertyEvent PROP_MIXED_EVENT =
+ new CarPropertyEvent(PROPERTY_EVENT_PROPERTY_CHANGE,
+ new CarPropertyValue<>(PROP_MIXED_ID, AREA_ID, new Object[] {
+ "test",
+ (Boolean) true,
+ (Integer) 1,
+ (Integer) 2,
+ (Integer) 3,
+ (Integer) 4,
+ (Long) 2L,
+ (Long) 5L,
+ (Long) 6L,
+ (Float) 3f,
+ (Float) 7f,
+ (Float) 8f,
+ (byte) 5,
+ (byte) 6
+ }));
- private static final TelemetryProto.Publisher PUBLISHER_PARAMS_1 =
+ private static final TelemetryProto.Publisher PUBLISHER_PARAMS_STRING =
TelemetryProto.Publisher.newBuilder()
.setVehicleProperty(TelemetryProto.VehiclePropertyPublisher.newBuilder()
.setReadRate(PROP_READ_RATE)
- .setVehiclePropertyId(PROP_ID_1))
+ .setVehiclePropertyId(PROP_STRING_ID))
+ .build();
+ private static final TelemetryProto.Publisher PUBLISHER_PARAMS_BOOLEAN =
+ TelemetryProto.Publisher.newBuilder()
+ .setVehicleProperty(TelemetryProto.VehiclePropertyPublisher.newBuilder()
+ .setReadRate(PROP_READ_RATE)
+ .setVehiclePropertyId(PROP_BOOLEAN_ID))
+ .build();
+ private static final TelemetryProto.Publisher PUBLISHER_PARAMS_INT =
+ TelemetryProto.Publisher.newBuilder()
+ .setVehicleProperty(TelemetryProto.VehiclePropertyPublisher.newBuilder()
+ .setReadRate(PROP_READ_RATE)
+ .setVehiclePropertyId(PROP_INT_ID))
+ .build();
+ private static final TelemetryProto.Publisher PUBLISHER_PARAMS_INT_VEC =
+ TelemetryProto.Publisher.newBuilder()
+ .setVehicleProperty(TelemetryProto.VehiclePropertyPublisher.newBuilder()
+ .setReadRate(PROP_READ_RATE)
+ .setVehiclePropertyId(PROP_INT_VEC_ID))
+ .build();
+ private static final TelemetryProto.Publisher PUBLISHER_PARAMS_LONG =
+ TelemetryProto.Publisher.newBuilder()
+ .setVehicleProperty(TelemetryProto.VehiclePropertyPublisher.newBuilder()
+ .setReadRate(PROP_READ_RATE)
+ .setVehiclePropertyId(PROP_LONG_ID))
+ .build();
+ private static final TelemetryProto.Publisher PUBLISHER_PARAMS_LONG_VEC =
+ TelemetryProto.Publisher.newBuilder()
+ .setVehicleProperty(TelemetryProto.VehiclePropertyPublisher.newBuilder()
+ .setReadRate(PROP_READ_RATE)
+ .setVehiclePropertyId(PROP_LONG_VEC_ID))
+ .build();
+ private static final TelemetryProto.Publisher PUBLISHER_PARAMS_FLOAT =
+ TelemetryProto.Publisher.newBuilder()
+ .setVehicleProperty(TelemetryProto.VehiclePropertyPublisher.newBuilder()
+ .setReadRate(PROP_READ_RATE)
+ .setVehiclePropertyId(PROP_FLOAT_ID))
+ .build();
+ private static final TelemetryProto.Publisher PUBLISHER_PARAMS_FLOAT_VEC =
+ TelemetryProto.Publisher.newBuilder()
+ .setVehicleProperty(TelemetryProto.VehiclePropertyPublisher.newBuilder()
+ .setReadRate(PROP_READ_RATE)
+ .setVehiclePropertyId(PROP_FLOAT_VEC_ID))
+ .build();
+ private static final TelemetryProto.Publisher PUBLISHER_PARAMS_BYTES =
+ TelemetryProto.Publisher.newBuilder()
+ .setVehicleProperty(TelemetryProto.VehiclePropertyPublisher.newBuilder()
+ .setReadRate(PROP_READ_RATE)
+ .setVehiclePropertyId(PROP_BYTES_ID))
+ .build();
+ private static final TelemetryProto.Publisher PUBLISHER_PARAMS_MIXED =
+ TelemetryProto.Publisher.newBuilder()
+ .setVehicleProperty(TelemetryProto.VehiclePropertyPublisher.newBuilder()
+ .setReadRate(PROP_READ_RATE)
+ .setVehiclePropertyId(PROP_MIXED_ID))
.build();
private static final TelemetryProto.Publisher PUBLISHER_PARAMS_INVALID =
TelemetryProto.Publisher.newBuilder()
@@ -78,11 +197,40 @@
.build();
// CarPropertyConfigs for mMockCarPropertyService.
- private static final CarPropertyConfig<Integer> PROP_CONFIG_1 =
- CarPropertyConfig.newBuilder(Integer.class, PROP_ID_1, AREA_ID).setAccess(
+ private static final CarPropertyConfig<Integer> PROP_STRING_CONFIG =
+ CarPropertyConfig.newBuilder(Integer.class, PROP_STRING_ID, AREA_ID).setAccess(
CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ).build();
+ private static final CarPropertyConfig<Integer> PROP_BOOLEAN_CONFIG =
+ CarPropertyConfig.newBuilder(Integer.class, PROP_BOOLEAN_ID, AREA_ID).setAccess(
+ CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ).build();
+ private static final CarPropertyConfig<Integer> PROP_INT_CONFIG =
+ CarPropertyConfig.newBuilder(Integer.class, PROP_INT_ID, AREA_ID).setAccess(
+ CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ).build();
+ private static final CarPropertyConfig<Integer> PROP_INT_VEC_CONFIG =
+ CarPropertyConfig.newBuilder(Integer.class, PROP_INT_VEC_ID, AREA_ID).setAccess(
+ CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ).build();
+ private static final CarPropertyConfig<Integer> PROP_LONG_CONFIG =
+ CarPropertyConfig.newBuilder(Integer.class, PROP_LONG_ID, AREA_ID).setAccess(
+ CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ).build();
+ private static final CarPropertyConfig<Integer> PROP_LONG_VEC_CONFIG =
+ CarPropertyConfig.newBuilder(Integer.class, PROP_LONG_VEC_ID, AREA_ID).setAccess(
+ CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ).build();
+ private static final CarPropertyConfig<Integer> PROP_FLOAT_CONFIG =
+ CarPropertyConfig.newBuilder(Integer.class, PROP_FLOAT_ID, AREA_ID).setAccess(
+ CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ).build();
+ private static final CarPropertyConfig<Integer> PROP_FLOAT_VEC_CONFIG =
+ CarPropertyConfig.newBuilder(Integer.class, PROP_FLOAT_VEC_ID, AREA_ID).setAccess(
+ CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ).build();
+ private static final CarPropertyConfig<Integer> PROP_BYTES_CONFIG =
+ CarPropertyConfig.newBuilder(Integer.class, PROP_BYTES_ID, AREA_ID).setAccess(
+ CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ).build();
+ private static final CarPropertyConfig<Integer> PROP_MIXED_CONFIG =
+ CarPropertyConfig.newBuilder(Integer.class, PROP_MIXED_ID, AREA_ID).setAccess(
+ CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ)
+ .setConfigArray(new ArrayList<Integer>(
+ Arrays.asList(1, 1, 1, 3, 1, 2, 1, 2, 2))).build();
private static final CarPropertyConfig<Integer> PROP_CONFIG_2_WRITE_ONLY =
- CarPropertyConfig.newBuilder(Integer.class, PROP_ID_2, AREA_ID).setAccess(
+ CarPropertyConfig.newBuilder(Integer.class, PROP_INT_ID_2, AREA_ID).setAccess(
CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_WRITE).build();
private final FakeHandlerWrapper mFakeHandlerWrapper =
@@ -90,7 +238,25 @@
private final FakePublisherListener mFakePublisherListener = new FakePublisherListener();
@Mock
- private DataSubscriber mMockDataSubscriber;
+ private DataSubscriber mMockStringDataSubscriber;
+ @Mock
+ private DataSubscriber mMockBoolDataSubscriber;
+ @Mock
+ private DataSubscriber mMockIntDataSubscriber;
+ @Mock
+ private DataSubscriber mMockIntVecDataSubscriber;
+ @Mock
+ private DataSubscriber mMockLongDataSubscriber;
+ @Mock
+ private DataSubscriber mMockLongVecDataSubscriber;
+ @Mock
+ private DataSubscriber mMockFloatDataSubscriber;
+ @Mock
+ private DataSubscriber mMockFloatVecDataSubscriber;
+ @Mock
+ private DataSubscriber mMockBytesDataSubscriber;
+ @Mock
+ private DataSubscriber mMockMixedDataSubscriber;
@Mock
private CarPropertyService mMockCarPropertyService;
@@ -103,9 +269,30 @@
@Before
public void setUp() {
- when(mMockDataSubscriber.getPublisherParam()).thenReturn(PUBLISHER_PARAMS_1);
+ when(mMockStringDataSubscriber.getPublisherParam()).thenReturn(PUBLISHER_PARAMS_STRING);
+ when(mMockBoolDataSubscriber.getPublisherParam()).thenReturn(PUBLISHER_PARAMS_BOOLEAN);
+ when(mMockIntDataSubscriber.getPublisherParam()).thenReturn(PUBLISHER_PARAMS_INT);
+ when(mMockIntVecDataSubscriber.getPublisherParam()).thenReturn(PUBLISHER_PARAMS_INT_VEC);
+ when(mMockLongDataSubscriber.getPublisherParam()).thenReturn(PUBLISHER_PARAMS_LONG);
+ when(mMockLongVecDataSubscriber.getPublisherParam()).thenReturn(PUBLISHER_PARAMS_LONG_VEC);
+ when(mMockFloatDataSubscriber.getPublisherParam()).thenReturn(PUBLISHER_PARAMS_FLOAT);
+ when(mMockFloatVecDataSubscriber.getPublisherParam())
+ .thenReturn(PUBLISHER_PARAMS_FLOAT_VEC);
+ when(mMockBytesDataSubscriber.getPublisherParam()).thenReturn(PUBLISHER_PARAMS_BYTES);
+ when(mMockMixedDataSubscriber.getPublisherParam()).thenReturn(PUBLISHER_PARAMS_MIXED);
when(mMockCarPropertyService.getPropertyList())
- .thenReturn(List.of(PROP_CONFIG_1, PROP_CONFIG_2_WRITE_ONLY));
+ .thenReturn(List.of(
+ PROP_STRING_CONFIG,
+ PROP_BOOLEAN_CONFIG,
+ PROP_INT_CONFIG,
+ PROP_INT_VEC_CONFIG,
+ PROP_LONG_CONFIG,
+ PROP_LONG_VEC_CONFIG,
+ PROP_FLOAT_CONFIG,
+ PROP_FLOAT_VEC_CONFIG,
+ PROP_BYTES_CONFIG,
+ PROP_MIXED_CONFIG,
+ PROP_CONFIG_2_WRITE_ONLY));
mVehiclePropertyPublisher = new VehiclePropertyPublisher(
mMockCarPropertyService,
mFakePublisherListener,
@@ -114,23 +301,24 @@
@Test
public void testAddDataSubscriber_registersNewCallback() {
- mVehiclePropertyPublisher.addDataSubscriber(mMockDataSubscriber);
+ mVehiclePropertyPublisher.addDataSubscriber(mMockIntDataSubscriber);
- verify(mMockCarPropertyService).registerListener(eq(PROP_ID_1), eq(PROP_READ_RATE), any());
- assertThat(mVehiclePropertyPublisher.hasDataSubscriber(mMockDataSubscriber)).isTrue();
+ verify(mMockCarPropertyService).registerListener(
+ eq(PROP_INT_ID), eq(PROP_READ_RATE), any());
+ assertThat(mVehiclePropertyPublisher.hasDataSubscriber(mMockIntDataSubscriber)).isTrue();
}
@Test
public void testAddDataSubscriber_withSamePropertyId_registersSingleListener() {
DataSubscriber subscriber2 = mock(DataSubscriber.class);
- when(subscriber2.getPublisherParam()).thenReturn(PUBLISHER_PARAMS_1);
+ when(subscriber2.getPublisherParam()).thenReturn(PUBLISHER_PARAMS_INT);
- mVehiclePropertyPublisher.addDataSubscriber(mMockDataSubscriber);
+ mVehiclePropertyPublisher.addDataSubscriber(mMockIntDataSubscriber);
mVehiclePropertyPublisher.addDataSubscriber(subscriber2);
verify(mMockCarPropertyService, times(1))
- .registerListener(eq(PROP_ID_1), eq(PROP_READ_RATE), any());
- assertThat(mVehiclePropertyPublisher.hasDataSubscriber(mMockDataSubscriber)).isTrue();
+ .registerListener(eq(PROP_INT_ID), eq(PROP_READ_RATE), any());
+ assertThat(mVehiclePropertyPublisher.hasDataSubscriber(mMockIntDataSubscriber)).isTrue();
assertThat(mVehiclePropertyPublisher.hasDataSubscriber(subscriber2)).isTrue();
}
@@ -141,14 +329,14 @@
TelemetryProto.Publisher.newBuilder()
.setVehicleProperty(TelemetryProto.VehiclePropertyPublisher.newBuilder()
.setReadRate(PROP_READ_RATE)
- .setVehiclePropertyId(PROP_ID_2))
+ .setVehiclePropertyId(PROP_INT_ID_2))
.build());
Throwable error = assertThrows(IllegalArgumentException.class,
() -> mVehiclePropertyPublisher.addDataSubscriber(invalidDataSubscriber));
assertThat(error).hasMessageThat().contains("No access.");
- assertThat(mVehiclePropertyPublisher.hasDataSubscriber(mMockDataSubscriber)).isFalse();
+ assertThat(mVehiclePropertyPublisher.hasDataSubscriber(mMockIntDataSubscriber)).isFalse();
}
@Test
@@ -160,48 +348,120 @@
() -> mVehiclePropertyPublisher.addDataSubscriber(invalidDataSubscriber));
assertThat(error).hasMessageThat().contains("not found");
- assertThat(mVehiclePropertyPublisher.hasDataSubscriber(mMockDataSubscriber)).isFalse();
+ assertThat(mVehiclePropertyPublisher.hasDataSubscriber(mMockIntDataSubscriber)).isFalse();
}
@Test
public void testRemoveDataSubscriber_succeeds() {
- mVehiclePropertyPublisher.addDataSubscriber(mMockDataSubscriber);
+ mVehiclePropertyPublisher.addDataSubscriber(mMockIntDataSubscriber);
- mVehiclePropertyPublisher.removeDataSubscriber(mMockDataSubscriber);
+ mVehiclePropertyPublisher.removeDataSubscriber(mMockIntDataSubscriber);
- verify(mMockCarPropertyService, times(1)).unregisterListener(eq(PROP_ID_1), any());
- assertThat(mVehiclePropertyPublisher.hasDataSubscriber(mMockDataSubscriber)).isFalse();
+ verify(mMockCarPropertyService, times(1)).unregisterListener(eq(PROP_INT_ID), any());
+ assertThat(mVehiclePropertyPublisher.hasDataSubscriber(mMockIntDataSubscriber)).isFalse();
}
@Test
public void testRemoveDataSubscriber_ignoresIfNotFound() {
- mVehiclePropertyPublisher.removeDataSubscriber(mMockDataSubscriber);
+ mVehiclePropertyPublisher.removeDataSubscriber(mMockIntDataSubscriber);
}
@Test
public void testRemoveAllDataSubscribers_succeeds() {
DataSubscriber subscriber2 = mock(DataSubscriber.class);
- when(subscriber2.getPublisherParam()).thenReturn(PUBLISHER_PARAMS_1);
- mVehiclePropertyPublisher.addDataSubscriber(mMockDataSubscriber);
+ when(subscriber2.getPublisherParam()).thenReturn(PUBLISHER_PARAMS_INT);
+ mVehiclePropertyPublisher.addDataSubscriber(mMockIntDataSubscriber);
mVehiclePropertyPublisher.addDataSubscriber(subscriber2);
mVehiclePropertyPublisher.removeAllDataSubscribers();
- assertThat(mVehiclePropertyPublisher.hasDataSubscriber(mMockDataSubscriber)).isFalse();
+ assertThat(mVehiclePropertyPublisher.hasDataSubscriber(mMockIntDataSubscriber)).isFalse();
assertThat(mVehiclePropertyPublisher.hasDataSubscriber(subscriber2)).isFalse();
- verify(mMockCarPropertyService, times(1)).unregisterListener(eq(PROP_ID_1), any());
+ verify(mMockCarPropertyService, times(1)).unregisterListener(eq(PROP_INT_ID), any());
}
@Test
public void testOnNewCarPropertyEvent_pushesValueToDataSubscriber() throws Exception {
doNothing().when(mMockCarPropertyService).registerListener(
anyInt(), anyFloat(), mCarPropertyCallbackCaptor.capture());
- mVehiclePropertyPublisher.addDataSubscriber(mMockDataSubscriber);
+ mVehiclePropertyPublisher.addDataSubscriber(mMockIntDataSubscriber);
- mCarPropertyCallbackCaptor.getValue().onEvent(Collections.singletonList(PROP_EVENT_1));
+ mCarPropertyCallbackCaptor.getValue().onEvent(Collections.singletonList(PROP_INT_EVENT));
- verify(mMockDataSubscriber).push(mBundleCaptor.capture());
- // TODO(b/197269115): add more assertions on the contents of
- // PersistableBundle object.
+ verify(mMockIntDataSubscriber).push(mBundleCaptor.capture());
+ assertThat(mBundleCaptor.getValue().getInt(BUNDLE_INT_KEY)).isEqualTo(1);
+ }
+
+ @Test
+ public void testOnNewCarPropertyEvent_parsesValueCorrectly() throws Exception {
+ doNothing().when(mMockCarPropertyService).registerListener(
+ anyInt(), anyFloat(), mCarPropertyCallbackCaptor.capture());
+ mVehiclePropertyPublisher.addDataSubscriber(mMockStringDataSubscriber);
+ mVehiclePropertyPublisher.addDataSubscriber(mMockBoolDataSubscriber);
+ mVehiclePropertyPublisher.addDataSubscriber(mMockIntDataSubscriber);
+ mVehiclePropertyPublisher.addDataSubscriber(mMockIntVecDataSubscriber);
+ mVehiclePropertyPublisher.addDataSubscriber(mMockLongDataSubscriber);
+ mVehiclePropertyPublisher.addDataSubscriber(mMockLongVecDataSubscriber);
+ mVehiclePropertyPublisher.addDataSubscriber(mMockFloatDataSubscriber);
+ mVehiclePropertyPublisher.addDataSubscriber(mMockFloatVecDataSubscriber);
+ mVehiclePropertyPublisher.addDataSubscriber(mMockBytesDataSubscriber);
+ mVehiclePropertyPublisher.addDataSubscriber(mMockMixedDataSubscriber);
+ ICarPropertyEventListener eventListener = mCarPropertyCallbackCaptor.getValue();
+ eventListener.onEvent(Collections.singletonList(PROP_STRING_EVENT));
+ eventListener.onEvent(Collections.singletonList(PROP_BOOLEAN_EVENT));
+ eventListener.onEvent(Collections.singletonList(PROP_INT_EVENT));
+ eventListener.onEvent(Collections.singletonList(PROP_INT_VEC_EVENT));
+ eventListener.onEvent(Collections.singletonList(PROP_LONG_EVENT));
+ eventListener.onEvent(Collections.singletonList(PROP_LONG_VEC_EVENT));
+ eventListener.onEvent(Collections.singletonList(PROP_FLOAT_EVENT));
+ eventListener.onEvent(Collections.singletonList(PROP_FLOAT_VEC_EVENT));
+ eventListener.onEvent(Collections.singletonList(PROP_BYTES_EVENT));
+ eventListener.onEvent(Collections.singletonList(PROP_MIXED_EVENT));
+
+ verify(mMockStringDataSubscriber).push(mBundleCaptor.capture());
+ assertThat(mBundleCaptor.getValue().getString(BUNDLE_STRING_KEY)).isEqualTo("hi");
+
+ verify(mMockBoolDataSubscriber).push(mBundleCaptor.capture());
+ assertThat(mBundleCaptor.getValue().getBoolean(BUNDLE_BOOLEAN_KEY)).isTrue();
+
+ verify(mMockIntDataSubscriber).push(mBundleCaptor.capture());
+ assertThat(mBundleCaptor.getValue().getInt(BUNDLE_INT_KEY)).isEqualTo(1);
+
+ verify(mMockIntVecDataSubscriber).push(mBundleCaptor.capture());
+ assertThat(mBundleCaptor.getValue().getIntArray(BUNDLE_INT_ARRAY_KEY))
+ .isEqualTo(new int[] {1, 2});
+
+ verify(mMockLongDataSubscriber).push(mBundleCaptor.capture());
+ assertThat(mBundleCaptor.getValue().getLong(BUNDLE_LONG_KEY)).isEqualTo(10L);
+
+ verify(mMockLongVecDataSubscriber).push(mBundleCaptor.capture());
+ assertThat(mBundleCaptor.getValue().getLongArray(BUNDLE_LONG_ARRAY_KEY))
+ .isEqualTo(new long[] {10L, 20L});
+
+ verify(mMockFloatDataSubscriber).push(mBundleCaptor.capture());
+ assertThat(mBundleCaptor.getValue().getDouble(BUNDLE_FLOAT_KEY)).isEqualTo(1d);
+
+ verify(mMockFloatVecDataSubscriber).push(mBundleCaptor.capture());
+ assertThat(mBundleCaptor.getValue().getDoubleArray(BUNDLE_FLOAT_ARRAY_KEY))
+ .isEqualTo(new double[] {1d, 2d});
+
+ verify(mMockBytesDataSubscriber).push(mBundleCaptor.capture());
+ assertThat(mBundleCaptor.getValue().getString(BUNDLE_BYTE_ARRAY_KEY))
+ .isEqualTo(new String(new byte[] {(byte) 1, (byte) 2}, StandardCharsets.UTF_8));
+
+ verify(mMockMixedDataSubscriber).push(mBundleCaptor.capture());
+ assertThat(mBundleCaptor.getValue().getString(BUNDLE_STRING_KEY)).isEqualTo("test");
+ assertThat(mBundleCaptor.getValue().getBoolean(BUNDLE_BOOLEAN_KEY)).isTrue();
+ assertThat(mBundleCaptor.getValue().getInt(BUNDLE_INT_KEY)).isEqualTo(1);
+ assertThat(mBundleCaptor.getValue().getIntArray(BUNDLE_INT_ARRAY_KEY))
+ .isEqualTo(new int[] {2, 3, 4});
+ assertThat(mBundleCaptor.getValue().getLong(BUNDLE_LONG_KEY)).isEqualTo(2L);
+ assertThat(mBundleCaptor.getValue().getLongArray(BUNDLE_LONG_ARRAY_KEY))
+ .isEqualTo(new long[] {5L, 6L});
+ assertThat(mBundleCaptor.getValue().getDouble(BUNDLE_FLOAT_KEY)).isEqualTo(3d);
+ assertThat(mBundleCaptor.getValue().getDoubleArray(BUNDLE_FLOAT_ARRAY_KEY))
+ .isEqualTo(new double[] {7d, 8d});
+ assertThat(mBundleCaptor.getValue().getString(BUNDLE_BYTE_ARRAY_KEY))
+ .isEqualTo(new String(new byte[] {(byte) 5, (byte) 6}, StandardCharsets.UTF_8));
}
}
diff --git a/tests/carservice_unit_test/src/com/android/car/telemetry/sessioncontroller/SessionControllerUnitTest.java b/tests/carservice_unit_test/src/com/android/car/telemetry/sessioncontroller/SessionControllerUnitTest.java
index ce9f99b..ac52cad 100644
--- a/tests/carservice_unit_test/src/com/android/car/telemetry/sessioncontroller/SessionControllerUnitTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/telemetry/sessioncontroller/SessionControllerUnitTest.java
@@ -28,7 +28,6 @@
import android.car.AbstractExtendedMockitoCarServiceTestCase;
import android.car.hardware.power.CarPowerManager;
import android.car.hardware.power.ICarPowerStateListener;
-import android.content.Context;
import android.os.Handler;
import android.os.RemoteException;
@@ -54,8 +53,6 @@
private static final int CALLBACK_TIMEOUT_SEC = 10;
@Mock
- private Context mMockContext;
- @Mock
private Handler mDirectHandler; // Runs the messages on the current thread immediately
@Mock
private CarPowerManagementService mMockCarPowerManagementService;
@@ -94,15 +91,12 @@
@Before
public void setUp() {
- CarLocalServices.removeServiceForTest(CarPowerManagementService.class);
- CarLocalServices.addService(CarPowerManagementService.class,
- mMockCarPowerManagementService);
when(mDirectHandler.post(any(Runnable.class))).thenAnswer(i -> {
Runnable runnable = i.getArgument(0);
runnable.run();
return true;
});
- mSessionController = new SessionController(mMockContext, mDirectHandler);
+ mSessionController = new SessionController(mMockCarPowerManagementService, mDirectHandler);
verify(mMockCarPowerManagementService).registerInternalListener(
mPowerStateListenerCaptor.capture());
}
diff --git a/tests/carservice_unit_test/src/com/android/car/telemetry/util/MetricsReportProtoUtilsTest.java b/tests/carservice_unit_test/src/com/android/car/telemetry/util/MetricsReportProtoUtilsTest.java
new file mode 100644
index 0000000..21de91f
--- /dev/null
+++ b/tests/carservice_unit_test/src/com/android/car/telemetry/util/MetricsReportProtoUtilsTest.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2022 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.telemetry.util;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.os.PersistableBundle;
+
+import com.android.car.telemetry.MetricsReportProto.MetricsReportList;
+
+import com.google.protobuf.ByteString;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+@RunWith(JUnit4.class)
+public class MetricsReportProtoUtilsTest {
+
+ @Test
+ public void testConversion() {
+ PersistableBundle expected = new PersistableBundle();
+ expected.putLong("timestamp", System.currentTimeMillis());
+
+ byte[] bytes = MetricsReportProtoUtils.getBytes(expected);
+ PersistableBundle bundle = MetricsReportProtoUtils.getBundle(ByteString.copyFrom(bytes));
+
+ assertThat(bundle.toString()).isEqualTo(expected.toString());
+ }
+
+ @Test
+ public void testBuildMetricsReportListAndGetBundle() {
+ PersistableBundle expected = new PersistableBundle();
+ expected.putString("test", "test");
+
+ MetricsReportList reportList =
+ MetricsReportProtoUtils.buildMetricsReportList(expected, expected);
+ assertThat(reportList.getReportCount()).isEqualTo(2);
+ PersistableBundle report1 = MetricsReportProtoUtils.getBundle(reportList, 0);
+ PersistableBundle report2 = MetricsReportProtoUtils.getBundle(reportList, 1);
+
+ assertThat(report1.toString()).isEqualTo(expected.toString());
+ assertThat(report2.toString()).isEqualTo(expected.toString());
+ }
+}
diff --git a/tests/carservice_unit_test/src/com/android/car/user/BaseCarUserServiceTestCase.java b/tests/carservice_unit_test/src/com/android/car/user/BaseCarUserServiceTestCase.java
index 50dc55b..af4c0e2 100644
--- a/tests/carservice_unit_test/src/com/android/car/user/BaseCarUserServiceTestCase.java
+++ b/tests/carservice_unit_test/src/com/android/car/user/BaseCarUserServiceTestCase.java
@@ -103,6 +103,7 @@
import com.android.car.internal.common.UserHelperLite;
import com.android.car.internal.os.CarSystemProperties;
import com.android.car.internal.user.UserHelper;
+import com.android.car.pm.CarPackageManagerService;
import com.android.internal.R;
import com.android.internal.util.Preconditions;
@@ -158,6 +159,7 @@
@Mock protected ICarServiceHelper mICarServiceHelper;
@Mock protected Handler mMockedHandler;
@Mock protected UserHandleHelper mMockedUserHandleHelper;
+ @Mock protected CarPackageManagerService mCarPackageManagerService;
protected final BlockingUserLifecycleListener mUserLifecycleListener =
BlockingUserLifecycleListener.forAnyEvent().build();
@@ -472,7 +474,8 @@
mInitialUserSetter,
mUserPreCreator,
mCarUxRestrictionService,
- mHandler);
+ mHandler,
+ mCarPackageManagerService);
}
/**
diff --git a/tests/carservice_unit_test/src/com/android/car/user/CarUserServiceTest.java b/tests/carservice_unit_test/src/com/android/car/user/CarUserServiceTest.java
index fa0e508..6818a7a 100644
--- a/tests/carservice_unit_test/src/com/android/car/user/CarUserServiceTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/user/CarUserServiceTest.java
@@ -52,6 +52,7 @@
import android.annotation.Nullable;
import android.app.ActivityManager;
+import android.car.CarVersion;
import android.car.ICarResultReceiver;
import android.car.builtin.app.ActivityManagerHelper;
import android.car.builtin.os.UserManagerHelper;
@@ -394,6 +395,34 @@
}
@Test
+ public void testOnUserLifecycleEvent_notifyReceiver_targetVersionCheck() throws Exception {
+ // Arrange: add receivers.
+ mCarUserService.setLifecycleListenerForApp("package1",
+ new UserLifecycleEventFilter.Builder()
+ .addEventType(CarUserManager.USER_LIFECYCLE_EVENT_TYPE_CREATED).build(),
+ mLifecycleEventReceiver);
+ mCarUserService.setLifecycleListenerForApp("package2",
+ new UserLifecycleEventFilter.Builder()
+ .addEventType(CarUserManager.USER_LIFECYCLE_EVENT_TYPE_CREATED).build(),
+ mAnotherLifecycleEventReceiver);
+
+ when(mCarPackageManagerService.getTargetCarVersion("package1"))
+ .thenReturn(CarVersion.VERSION_CODES.TIRAMISU_0);
+ when(mCarPackageManagerService.getTargetCarVersion("package2"))
+ .thenReturn(CarVersion.VERSION_CODES.TIRAMISU_1);
+
+ // Act: User created event occurs.
+ sendUserLifecycleEvent(/* fromUser */ 0, mRegularUserId,
+ CarUserManager.USER_LIFECYCLE_EVENT_TYPE_CREATED);
+ waitForHandlerThreadToFinish();
+
+ // Verify: receivers are called or not depending on whether the target version meets
+ // requirement.
+ verify(mLifecycleEventReceiver, never()).send(anyInt(), any());
+ verify(mAnotherLifecycleEventReceiver).send(anyInt(), any());
+ }
+
+ @Test
public void testOnUserLifecycleEvent_notifyReceiver_singleReceiverWithMultipleFilters()
throws Exception {
// Arrange: add one receiver with multiple filters.
@@ -608,7 +637,8 @@
mInitialUserSetter,
mUserPreCreator,
mCarUxRestrictionService,
- mMockedHandler);
+ mMockedHandler,
+ mCarPackageManagerService);
mockStopUserWithDelayedLockingThrows(userId, new IllegalStateException());
carUserServiceLocal.stopUser(userId, userStopResult);
diff --git a/tests/carservice_unit_test/src/com/android/car/watchdog/CarWatchdogServiceUnitTest.java b/tests/carservice_unit_test/src/com/android/car/watchdog/CarWatchdogServiceUnitTest.java
index 074d788..dca7764 100644
--- a/tests/carservice_unit_test/src/com/android/car/watchdog/CarWatchdogServiceUnitTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/watchdog/CarWatchdogServiceUnitTest.java
@@ -26,6 +26,9 @@
import static android.car.test.mocks.AndroidMockitoHelper.mockUmIsUserRunning;
import static android.car.test.util.AndroidHelper.assertFilterHasActions;
import static android.car.test.util.AndroidHelper.assertFilterHasDataScheme;
+import static android.car.user.CarUserManager.USER_LIFECYCLE_EVENT_TYPE_POST_UNLOCKED;
+import static android.car.user.CarUserManager.USER_LIFECYCLE_EVENT_TYPE_SWITCHING;
+import static android.car.user.CarUserManager.USER_LIFECYCLE_EVENT_TYPE_UNLOCKING;
import static android.car.watchdog.CarWatchdogManager.TIMEOUT_CRITICAL;
import static android.content.Intent.ACTION_PACKAGE_CHANGED;
import static android.content.Intent.ACTION_USER_REMOVED;
@@ -115,6 +118,7 @@
import android.car.hardware.power.ICarPowerStateListener;
import android.car.hardware.power.PowerComponent;
import android.car.test.mocks.AbstractExtendedMockitoTestCase;
+import android.car.user.CarUserManager;
import android.car.watchdog.CarWatchdogManager;
import android.car.watchdog.ICarWatchdogServiceCallback;
import android.car.watchdog.IResourceOveruseListener;
@@ -160,6 +164,7 @@
import com.android.car.admin.NotificationHelper;
import com.android.car.power.CarPowerManagementService;
import com.android.car.systeminterface.SystemInterface;
+import com.android.car.user.CarUserService;
import com.android.car.util.Utils;
import com.google.common.truth.Correspondence;
@@ -216,6 +221,7 @@
@Mock private UserManager mMockUserManager;
@Mock private SystemInterface mMockSystemInterface;
@Mock private CarPowerManagementService mMockCarPowerManagementService;
+ @Mock private CarUserService mMockCarUserService;
@Mock private CarUxRestrictionsManagerService mMockCarUxRestrictionsManagerService;
@Mock private Resources mMockResources;
@Mock private IBinder mMockBinder;
@@ -228,6 +234,8 @@
@Captor private ArgumentCaptor<IntentFilter> mIntentFilterCaptor;
@Captor private ArgumentCaptor<ICarUxRestrictionsChangeListener>
mICarUxRestrictionsChangeListener;
+ @Captor private ArgumentCaptor<CarUserManager.UserLifecycleListener>
+ mUserLifecycleListenerCaptor;
@Captor private ArgumentCaptor<IBinder.DeathRecipient> mDeathRecipientCaptor;
@Captor private ArgumentCaptor<ICarWatchdogServiceForSystem>
mICarWatchdogServiceForSystemCaptor;
@@ -257,6 +265,7 @@
private boolean mIsDaemonCrashed;
private ICarPowerStateListener mCarPowerStateListener;
private ICarPowerPolicyListener mCarPowerPolicyListener;
+ private CarUserManager.UserLifecycleListener mUserLifecycleListener;
private ICarUxRestrictionsChangeListener mCarUxRestrictionsChangeListener;
private StatsPullAtomCallback mStatsPullAtomCallback;
private File mTempSystemCarDir;
@@ -322,6 +331,8 @@
.when(() -> CarLocalServices.getService(SystemInterface.class));
doReturn(mMockCarPowerManagementService)
.when(() -> CarLocalServices.getService(CarPowerManagementService.class));
+ doReturn(mMockCarUserService)
+ .when(() -> CarLocalServices.getService(CarUserService.class));
doReturn(mMockCarUxRestrictionsManagerService)
.when(() -> CarLocalServices.getService(CarUxRestrictionsManagerService.class));
doReturn(mSpiedPackageManager).when(() -> ActivityThread.getPackageManager());
@@ -468,6 +479,25 @@
}
@Test
+ public void testUserSwitchingLifecycleEvents() throws Exception {
+ mUserLifecycleListener.onEvent(
+ new CarUserManager.UserLifecycleEvent(
+ USER_LIFECYCLE_EVENT_TYPE_SWITCHING, 100, 101));
+ mUserLifecycleListener.onEvent(
+ new CarUserManager.UserLifecycleEvent(USER_LIFECYCLE_EVENT_TYPE_UNLOCKING, 101));
+ mUserLifecycleListener.onEvent(
+ new CarUserManager.UserLifecycleEvent(
+ USER_LIFECYCLE_EVENT_TYPE_POST_UNLOCKED, 101));
+
+ verify(mMockCarWatchdogDaemon).notifySystemStateChange(StateType.USER_STATE, 101,
+ UserState.USER_STATE_SWITCHING);
+ verify(mMockCarWatchdogDaemon).notifySystemStateChange(StateType.USER_STATE, 101,
+ UserState.USER_STATE_UNLOCKING);
+ verify(mMockCarWatchdogDaemon).notifySystemStateChange(StateType.USER_STATE, 101,
+ UserState.USER_STATE_POST_UNLOCKED);
+ }
+
+ @Test
public void testUserRemovedBroadcast() throws Exception {
mockUmGetUserHandles(mMockUserManager, /* excludeDying= */ true, 101, 102);
mBroadcastReceiver.onReceive(mMockContext,
@@ -657,9 +687,9 @@
String packageName = "system_package";
int userId = 100;
- mDisabledPackagesSettingsStringByUserid.put(100,
- "vendor_package;system_package;third_party_package");
- mDisabledPackagesSettingsStringByUserid.put(101, "system_package");
+ disableUserPackage("system_package", 100, 101);
+ disableUserPackage("vendor_package", 100);
+ disableUserPackage("third_party_package", 100);
doReturn(COMPONENT_ENABLED_STATE_ENABLED).when(mSpiedPackageManager)
.getApplicationEnabledSetting(or(eq("system_package"),
@@ -684,8 +714,8 @@
String packageName = "system_package";
int userId = 100;
- mDisabledPackagesSettingsStringByUserid.put(100, "vendor_package;system_package");
- mDisabledPackagesSettingsStringByUserid.put(101, "system_package");
+ disableUserPackage("system_package", 100, 101);
+ disableUserPackage("vendor_package", 100);
doReturn(COMPONENT_ENABLED_STATE_DISABLED).when(mSpiedPackageManager)
.getApplicationEnabledSetting("system_package", 100);
@@ -1632,6 +1662,178 @@
}
@Test
+ public void testSetKillablePackageAsUserReenablesPackage() throws Exception {
+ mockUmGetUserHandles(mMockUserManager, /* excludeDying= */ true, 101);
+ disableUserPackage("third_party_package", 101);
+
+ injectPackageInfos(Collections.singletonList(
+ constructPackageManagerPackageInfo("third_party_package", 10103456, null)));
+
+ UserHandle userHandle = UserHandle.of(101);
+ mCarWatchdogService.setKillablePackageAsUser("third_party_package", userHandle,
+ /* isKillable= */ false);
+
+ PackageKillableStateSubject.assertThat(
+ mCarWatchdogService.getPackageKillableStatesAsUser(userHandle))
+ .containsExactly(new PackageKillableState("third_party_package", 101,
+ PackageKillableState.KILLABLE_STATE_NO));
+
+ verify(mSpiedPackageManager, times(2))
+ .getApplicationEnabledSetting("third_party_package", 101);
+
+ verify(mSpiedPackageManager).setApplicationEnabledSetting(eq("third_party_package"),
+ eq(COMPONENT_ENABLED_STATE_ENABLED), anyInt(), eq(101), anyString());
+ }
+
+ @Test
+ public void testSetKillablePackageAsUserReenablesPackagesWithSharedUids() throws Exception {
+ mockUmGetUserHandles(mMockUserManager, /* excludeDying= */ true, 101);
+ disableUserPackage("third_party_package.A", 101);
+ disableUserPackage("third_party_package.B", 101);
+
+ injectPackageInfos(Arrays.asList(
+ constructPackageManagerPackageInfo(
+ "third_party_package.A", 10103456, "third_party_shared_package.A"),
+ constructPackageManagerPackageInfo(
+ "third_party_package.B", 10103456, "third_party_shared_package.A")));
+
+ UserHandle userHandle = UserHandle.of(101);
+ mCarWatchdogService.setKillablePackageAsUser("third_party_package.A", userHandle,
+ /* isKillable= */ false);
+
+ PackageKillableStateSubject.assertThat(
+ mCarWatchdogService.getPackageKillableStatesAsUser(userHandle)).containsExactly(
+ new PackageKillableState("third_party_package.A", 101,
+ PackageKillableState.KILLABLE_STATE_NO),
+ new PackageKillableState("third_party_package.B", 101,
+ PackageKillableState.KILLABLE_STATE_NO));
+
+ verify(mSpiedPackageManager, times(2))
+ .getApplicationEnabledSetting("third_party_package.A", 101);
+ verify(mSpiedPackageManager, times(2))
+ .getApplicationEnabledSetting("third_party_package.B", 101);
+
+ verify(mSpiedPackageManager).setApplicationEnabledSetting(eq("third_party_package.A"),
+ eq(COMPONENT_ENABLED_STATE_ENABLED), anyInt(), eq(101), anyString());
+ verify(mSpiedPackageManager).setApplicationEnabledSetting(eq("third_party_package.B"),
+ eq(COMPONENT_ENABLED_STATE_ENABLED), anyInt(), eq(101), anyString());
+ }
+
+ @Test
+ public void testSetKillablePackageAsUserForAllUsersReenablesPackages() throws Exception {
+ mockUmGetUserHandles(mMockUserManager, /* excludeDying= */ true, 101, 102);
+ disableUserPackage("third_party_package", 101, 102);
+
+ injectPackageInfos(Arrays.asList(
+ constructPackageManagerPackageInfo("third_party_package", 10103456, null),
+ constructPackageManagerPackageInfo("third_party_package", 10203456, null)));
+
+ List<PackageIoOveruseStats> packageIoOveruseStats = Arrays.asList(
+ constructPackageIoOveruseStats(10103456, /* shouldNotify= */ false,
+ /* forgivenWriteBytes= */ constructPerStateBytes(80, 170, 260),
+ constructInternalIoOveruseStats(/* killableOnOveruse= */ true,
+ /* remainingWriteBytes= */ constructPerStateBytes(20, 20, 20),
+ /* writtenBytes= */ constructPerStateBytes(100, 200, 300),
+ /* totalOveruses= */ 1)),
+ constructPackageIoOveruseStats(10203456, /* shouldNotify= */ false,
+ /* forgivenWriteBytes= */ constructPerStateBytes(80, 170, 260),
+ constructInternalIoOveruseStats(/* killableOnOveruse= */ true,
+ /* remainingWriteBytes= */ constructPerStateBytes(20, 20, 20),
+ /* writtenBytes= */ constructPerStateBytes(100, 200, 300),
+ /* totalOveruses= */ 1)));
+
+ // Push stats in order to create and cache the usages of the third_party_package
+ pushLatestIoOveruseStatsAndWait(packageIoOveruseStats);
+
+ mCarWatchdogService.setKillablePackageAsUser("third_party_package", UserHandle.ALL,
+ /* isKillable= */ false);
+
+ PackageKillableStateSubject.assertThat(
+ mCarWatchdogService.getPackageKillableStatesAsUser(UserHandle.ALL)).containsExactly(
+ new PackageKillableState("third_party_package", 101,
+ PackageKillableState.KILLABLE_STATE_NO),
+ new PackageKillableState("third_party_package", 102,
+ PackageKillableState.KILLABLE_STATE_NO));
+
+ verify(mSpiedPackageManager, times(2))
+ .getApplicationEnabledSetting("third_party_package", 101);
+ verify(mSpiedPackageManager, times(2))
+ .getApplicationEnabledSetting("third_party_package", 102);
+
+ verify(mSpiedPackageManager).setApplicationEnabledSetting(eq("third_party_package"),
+ eq(COMPONENT_ENABLED_STATE_ENABLED), anyInt(), eq(101), anyString());
+ verify(mSpiedPackageManager).setApplicationEnabledSetting(eq("third_party_package"),
+ eq(COMPONENT_ENABLED_STATE_ENABLED), anyInt(), eq(102), anyString());
+ }
+
+ @Test
+ public void testSetKillablePackageAsUsersForAllUsersReenablesPackagesWithSharedUids()
+ throws Exception {
+ mockUmGetUserHandles(mMockUserManager, /* excludeDying= */ true, 101, 102);
+ disableUserPackage("third_party_package.A", 101, 102);
+ disableUserPackage("third_party_package.B", 101, 102);
+
+ injectPackageInfos(Arrays.asList(
+ constructPackageManagerPackageInfo(
+ "third_party_package.A", 10103456, "third_party_shared_package"),
+ constructPackageManagerPackageInfo(
+ "third_party_package.B", 10103456, "third_party_shared_package"),
+ constructPackageManagerPackageInfo(
+ "third_party_package.A", 10203456, "third_party_shared_package"),
+ constructPackageManagerPackageInfo(
+ "third_party_package.B", 10203456, "third_party_shared_package")));
+
+ List<PackageIoOveruseStats> packageIoOveruseStats = Arrays.asList(
+ constructPackageIoOveruseStats(10103456, /* shouldNotify= */ false,
+ /* forgivenWriteBytes= */ constructPerStateBytes(80, 170, 260),
+ constructInternalIoOveruseStats(/* killableOnOveruse= */ true,
+ /* remainingWriteBytes= */ constructPerStateBytes(20, 20, 20),
+ /* writtenBytes= */ constructPerStateBytes(100, 200, 300),
+ /* totalOveruses= */ 1)),
+ constructPackageIoOveruseStats(10203456, /* shouldNotify= */ false,
+ /* forgivenWriteBytes= */ constructPerStateBytes(80, 170, 260),
+ constructInternalIoOveruseStats(/* killableOnOveruse= */ true,
+ /* remainingWriteBytes= */ constructPerStateBytes(20, 20, 20),
+ /* writtenBytes= */ constructPerStateBytes(100, 200, 300),
+ /* totalOveruses= */ 1)));
+
+ // Push stats in order to create and cache the usages of the third_party_shared_package
+ pushLatestIoOveruseStatsAndWait(packageIoOveruseStats);
+
+ mCarWatchdogService.setKillablePackageAsUser("third_party_package.A", UserHandle.ALL,
+ /* isKillable= */ false);
+
+ PackageKillableStateSubject.assertThat(
+ mCarWatchdogService.getPackageKillableStatesAsUser(UserHandle.ALL)).containsExactly(
+ new PackageKillableState("third_party_package.A", 101,
+ PackageKillableState.KILLABLE_STATE_NO),
+ new PackageKillableState("third_party_package.B", 101,
+ PackageKillableState.KILLABLE_STATE_NO),
+ new PackageKillableState("third_party_package.A", 102,
+ PackageKillableState.KILLABLE_STATE_NO),
+ new PackageKillableState("third_party_package.B", 102,
+ PackageKillableState.KILLABLE_STATE_NO));
+
+ verify(mSpiedPackageManager, times(2))
+ .getApplicationEnabledSetting("third_party_package.A", 101);
+ verify(mSpiedPackageManager, times(2))
+ .getApplicationEnabledSetting("third_party_package.B", 101);
+ verify(mSpiedPackageManager, times(2))
+ .getApplicationEnabledSetting("third_party_package.A", 102);
+ verify(mSpiedPackageManager, times(2))
+ .getApplicationEnabledSetting("third_party_package.B", 102);
+
+ verify(mSpiedPackageManager).setApplicationEnabledSetting(eq("third_party_package.A"),
+ eq(COMPONENT_ENABLED_STATE_ENABLED), anyInt(), eq(101), anyString());
+ verify(mSpiedPackageManager).setApplicationEnabledSetting(eq("third_party_package.B"),
+ eq(COMPONENT_ENABLED_STATE_ENABLED), anyInt(), eq(101), anyString());
+ verify(mSpiedPackageManager).setApplicationEnabledSetting(eq("third_party_package.A"),
+ eq(COMPONENT_ENABLED_STATE_ENABLED), anyInt(), eq(102), anyString());
+ verify(mSpiedPackageManager).setApplicationEnabledSetting(eq("third_party_package.B"),
+ eq(COMPONENT_ENABLED_STATE_ENABLED), anyInt(), eq(102), anyString());
+ }
+
+ @Test
public void testGetPackageKillableStatesAsUser() throws Exception {
mockUmGetUserHandles(mMockUserManager, /* excludeDying= */ true, 101, 102);
injectPackageInfos(Arrays.asList(
@@ -3060,8 +3262,9 @@
/* userPackagesCsv= */ "100:third_party_package");
// Package was enabled again.
- mDisabledUserPackages.clear();
- mDisabledPackagesSettingsStringByUserid.clear();
+ doReturn(COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED).when(mSpiedPackageManager)
+ .getApplicationEnabledSetting("third_party_package", 100);
+ enableUserPackage("third_party_package", 100, true);
PackageIoOveruseStats packageIoOveruseStats =
constructPackageIoOveruseStats(thirdPartyPkgUid, /* shouldNotify= */ true,
@@ -3179,20 +3382,24 @@
mGenericPackageNameByUid, /* killablePackages= */ new ArraySet<>(),
/* shouldNotifyPackages= */ new ArraySet<>());
- doReturn(COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED).when(mSpiedPackageManager)
- .getApplicationEnabledSetting(
- or(or(eq("third_party_package.A"), eq("vendor_package.critical.A")),
- eq("vendor_package.critical.B")), eq(100));
+ disableUserPackage("third_party_package.A", 100);
+ disableUserPackage("vendor_package.critical.A", 100);
+ disableUserPackage("vendor_package.critical.B", 100);
mWatchdogServiceForSystemImpl.resetResourceOveruseStats(
Arrays.asList("third_party_package.A", "shared:vendor_shared_package.A",
"shared:system_shared_package.A", "third_party_package.B"));
- verify(mSpiedPackageManager).getApplicationEnabledSetting("third_party_package.A", 100);
- verify(mSpiedPackageManager).getApplicationEnabledSetting("vendor_package.critical.A", 100);
- verify(mSpiedPackageManager).getApplicationEnabledSetting("vendor_package.critical.B", 100);
- verify(mSpiedPackageManager).getApplicationEnabledSetting("system_package.critical.A", 100);
- verify(mSpiedPackageManager).getApplicationEnabledSetting("third_party_package.B", 100);
+ verify(mSpiedPackageManager, times(2))
+ .getApplicationEnabledSetting("third_party_package.A", 100);
+ verify(mSpiedPackageManager, times(2))
+ .getApplicationEnabledSetting("vendor_package.critical.A", 100);
+ verify(mSpiedPackageManager, times(2))
+ .getApplicationEnabledSetting("vendor_package.critical.B", 100);
+ verify(mSpiedPackageManager, never())
+ .getApplicationEnabledSetting("system_package.critical.A", 100);
+ verify(mSpiedPackageManager, never())
+ .getApplicationEnabledSetting("third_party_package.B", 100);
verify(mSpiedPackageManager).setApplicationEnabledSetting(eq("third_party_package.A"),
eq(COMPONENT_ENABLED_STATE_ENABLED), anyInt(), eq(100), anyString());
@@ -3200,8 +3407,6 @@
eq(COMPONENT_ENABLED_STATE_ENABLED), anyInt(), eq(100), anyString());
verify(mSpiedPackageManager).setApplicationEnabledSetting(eq("vendor_package.critical.B"),
eq(COMPONENT_ENABLED_STATE_ENABLED), anyInt(), eq(100), anyString());
-
- verifyNoMoreInteractions(mSpiedPackageManager);
}
@Test
@@ -3828,6 +4033,7 @@
mCarWatchdogService.init();
captureCarPowerListeners(wantedInvocations);
captureBroadcastReceiver(wantedInvocations);
+ captureUserLifecycleListener(wantedInvocations);
captureCarUxRestrictionsChangeListener(wantedInvocations);
captureAndVerifyRegistrationWithDaemon(/* waitOnMain= */ true);
verifyDatabaseInit(wantedInvocations);
@@ -3883,6 +4089,13 @@
assertFilterHasDataScheme(filter, /* dataScheme= */ "package");
}
+ private void captureUserLifecycleListener(int wantedInvocations) {
+ verify(mMockCarUserService, times(wantedInvocations)).addUserLifecycleListener(any(),
+ mUserLifecycleListenerCaptor.capture());
+ mUserLifecycleListener = mUserLifecycleListenerCaptor.getValue();
+ assertWithMessage("User lifecycle listener").that(mUserLifecycleListener).isNotNull();
+ }
+
private void captureCarUxRestrictionsChangeListener(int wantedInvocations) {
verify(mMockCarUxRestrictionsManagerService, times(wantedInvocations))
.getCurrentUxRestrictions();
@@ -3993,11 +4206,17 @@
return mDisabledPackagesSettingsStringByUserid.get(userId);
});
+ // Use any() instead of anyString() to consider when string arg is null.
when(Settings.Secure.putString(any(ContentResolver.class),
- eq(KEY_PACKAGES_DISABLED_ON_RESOURCE_OVERUSE), anyString())).thenAnswer(args -> {
+ eq(KEY_PACKAGES_DISABLED_ON_RESOURCE_OVERUSE), any())).thenAnswer(args -> {
ContentResolver contentResolver = args.getArgument(0);
int userId = contentResolver.getUserId();
- mDisabledPackagesSettingsStringByUserid.put(userId, args.getArgument(2));
+ String packageSettings = args.getArgument(2);
+ if (packageSettings == null) {
+ mDisabledPackagesSettingsStringByUserid.remove(userId);
+ } else {
+ mDisabledPackagesSettingsStringByUserid.put(userId, args.getArgument(2));
+ }
return null;
});
}
@@ -4064,7 +4283,6 @@
}
return packageInfo.applicationInfo.uid;
});
-
doAnswer((args) -> {
String value = args.getArgument(3) + USER_PACKAGE_SEPARATOR
+ args.getArgument(0);
@@ -4073,6 +4291,14 @@
}).when(mSpiedPackageManager).setApplicationEnabledSetting(
anyString(), eq(COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED), anyInt(),
anyInt(), anyString());
+ doAnswer((args) -> {
+ String value = args.getArgument(3) + USER_PACKAGE_SEPARATOR
+ + args.getArgument(0);
+ mDisabledUserPackages.remove(value);
+ return null;
+ }).when(mSpiedPackageManager).setApplicationEnabledSetting(
+ anyString(), eq(COMPONENT_ENABLED_STATE_ENABLED), anyInt(),
+ anyInt(), anyString());
doReturn(COMPONENT_ENABLED_STATE_ENABLED).when(mSpiedPackageManager)
.getApplicationEnabledSetting(anyString(), anyInt());
}
@@ -4280,6 +4506,57 @@
return packageIoOveruseStats;
}
+ private void enableUserPackage(String packageName, int userId, boolean isKillable)
+ throws Exception {
+ UserHandle userHandle = UserHandle.of(userId);
+
+ // Set package killable state to not killable, which enable the user package
+ mCarWatchdogService.setKillablePackageAsUser(packageName, userHandle,
+ /* isKillable= */ false);
+
+ if (isKillable) {
+ mCarWatchdogService.setKillablePackageAsUser(packageName, userHandle,
+ /* isKillable= */ true);
+ }
+
+ verify(mSpiedPackageManager, atLeastOnce())
+ .getApplicationEnabledSetting(packageName, userId);
+
+ verify(mSpiedPackageManager).setApplicationEnabledSetting(eq(packageName),
+ eq(COMPONENT_ENABLED_STATE_ENABLED), eq(0),
+ eq(userId), anyString());
+
+ assertThat(mDisabledUserPackages).doesNotContain(userId + ":" + packageName);
+
+ doReturn(COMPONENT_ENABLED_STATE_ENABLED).when(mSpiedPackageManager)
+ .getApplicationEnabledSetting(eq(packageName), eq(userId));
+ }
+
+ private void disableUserPackage(String packageName, int... userIds) throws Exception {
+ for (int i = 0; i < userIds.length; i++) {
+ int userId = userIds[i];
+ UserHandle userHandle = UserHandle.of(userId);
+
+ mBroadcastReceiver
+ .onReceive(mMockContext, new Intent(ACTION_RESOURCE_OVERUSE_DISABLE_APP)
+ .putExtra(Intent.EXTRA_PACKAGE_NAME, packageName)
+ .putExtra(Intent.EXTRA_USER, userHandle)
+ .putExtra(INTENT_EXTRA_NOTIFICATION_ID, RESOURCE_OVERUSE_NOTIFICATION_BASE_ID));
+
+ verify(mSpiedPackageManager, atLeastOnce())
+ .getApplicationEnabledSetting(packageName, userId);
+
+ verify(mSpiedPackageManager).setApplicationEnabledSetting(eq(packageName),
+ eq(COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED), eq(0),
+ eq(userId), anyString());
+
+ assertThat(mDisabledUserPackages).contains(userId + ":" + packageName);
+
+ doReturn(COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED).when(mSpiedPackageManager)
+ .getApplicationEnabledSetting(eq(packageName), eq(userId));
+ }
+ }
+
private void verifyDisabledPackages(String userPackagesCsv) {
verifyDisabledPackages(/* message= */ "", userPackagesCsv);
}
diff --git a/tests/vehiclehal_test/OWNERS b/tests/vehiclehal_test/OWNERS
new file mode 100644
index 0000000..88671a1
--- /dev/null
+++ b/tests/vehiclehal_test/OWNERS
@@ -0,0 +1 @@
+ericjeong@google.com
diff --git a/tools/GenericCarApiBuilder/README.md b/tools/GenericCarApiBuilder/README.md
index 1395a4f..a1fd2ab 100644
--- a/tools/GenericCarApiBuilder/README.md
+++ b/tools/GenericCarApiBuilder/README.md
@@ -16,16 +16,6 @@
# Android Automotive OS API Generator Tool
-* Tool will generate a file `complete_api_list.txt`. This file contains
- all public API including the hidden API. It also contains three type
- of annotations - `@hide` (for hidden calls), `@SystemAPI` (for System
- calls), and `@AddedIn`/`@AddedInOrBefore` Annotation. This file can be a
- better guide for future API changes as it can keep track of hidden
- APIs too.
-* tool will also generate a file `un_annotated_api_list.txt`. This file
- contains the API which are not annotated with
- `@AddedIn`/`@AddedInOrBefore annotation`. This file should be empty before
- the release.
* To Build `m -j GenericCarApiBuilder`
* To Run `GenericCarApiBuilder`
diff --git a/tools/GenericCarApiBuilder/complete_api_list.txt b/tools/GenericCarApiBuilder/complete_api_list.txt
deleted file mode 100644
index 2b6f53b..0000000
--- a/tools/GenericCarApiBuilder/complete_api_list.txt
+++ /dev/null
@@ -1,2868 +0,0 @@
-class @hide @SystemApi VehicleAreaDoor package android.car
- field @AddedInOrBefore int DOOR_ROW_1_LEFT = 0x00000001;
- field @AddedInOrBefore int DOOR_ROW_1_RIGHT = 0x00000004;
- field @AddedInOrBefore int DOOR_ROW_2_LEFT = 0x00000010;
- field @AddedInOrBefore int DOOR_ROW_2_RIGHT = 0x00000040;
- field @AddedInOrBefore int DOOR_ROW_3_LEFT = 0x00000100;
- field @AddedInOrBefore int DOOR_ROW_3_RIGHT = 0x00000400;
- field @AddedInOrBefore int DOOR_HOOD = 0x10000000;
- field @AddedInOrBefore int DOOR_REAR = 0x20000000;
-class @hide CarTransactionException package android.car
-class @hide DriverMonitoringDetection package android.car.occupantawareness
- field @AddedInOrBefore int confidenceLevel;
- field @AddedInOrBefore boolean isLookingOnRoad;
- field @AddedInOrBefore long gazeDurationMillis;
- field @AddedInOrBefore Parcelable.Creator<DriverMonitoringDetection> CREATOR;
- method @AddedInOrBefore int describeContents();
- method @AddedInOrBefore String toString();
- method @AddedInOrBefore void writeToParcel(Parcel dest, int flags);
-class @hide OccupantAwarenessDetection package android.car.occupantawareness
- field @AddedInOrBefore int VEHICLE_OCCUPANT_NONE = 0;
- field @AddedInOrBefore int VEHICLE_OCCUPANT_DRIVER = 1 << 2;
- field @AddedInOrBefore int VEHICLE_OCCUPANT_FRONT_PASSENGER = 1 << 1;
- field @AddedInOrBefore int VEHICLE_OCCUPANT_ROW_2_PASSENGER_LEFT = 1 << 3;
- field @AddedInOrBefore int VEHICLE_OCCUPANT_ROW_2_PASSENGER_CENTER = 1 << 4;
- field @AddedInOrBefore int VEHICLE_OCCUPANT_ROW_2_PASSENGER_RIGHT = 1 << 5;
- field @AddedInOrBefore int VEHICLE_OCCUPANT_ROW_3_PASSENGER_LEFT = 1 << 6;
- field @AddedInOrBefore int VEHICLE_OCCUPANT_ROW_3_PASSENGER_CENTER = 1 << 7;
- field @AddedInOrBefore int VEHICLE_OCCUPANT_ROW_3_PASSENGER_RIGHT = 1 << 8;
- field @AddedInOrBefore int VEHICLE_OCCUPANT_ALL_FRONT_OCCUPANTS = VEHICLE_OCCUPANT_DRIVER | VEHICLE_OCCUPANT_FRONT_PASSENGER;
- field @AddedInOrBefore int VEHICLE_OCCUPANT_ALL_ROW_2_OCCUPANTS = VEHICLE_OCCUPANT_ROW_2_PASSENGER_LEFT | VEHICLE_OCCUPANT_ROW_2_PASSENGER_RIGHT | VEHICLE_OCCUPANT_ROW_2_PASSENGER_CENTER;
- field @AddedInOrBefore int VEHICLE_OCCUPANT_ALL_ROW_3_OCCUPANTS = VEHICLE_OCCUPANT_ROW_3_PASSENGER_LEFT | VEHICLE_OCCUPANT_ROW_3_PASSENGER_RIGHT | VEHICLE_OCCUPANT_ROW_3_PASSENGER_CENTER;
- field @AddedInOrBefore int VEHICLE_OCCUPANT_ALL_OCCUPANTS = VEHICLE_OCCUPANT_ALL_FRONT_OCCUPANTS | VEHICLE_OCCUPANT_ALL_ROW_2_OCCUPANTS | VEHICLE_OCCUPANT_ALL_ROW_3_OCCUPANTS;
- field @AddedInOrBefore int CONFIDENCE_LEVEL_NONE = 0;
- field @AddedInOrBefore int CONFIDENCE_LEVEL_LOW = 1;
- field @AddedInOrBefore int CONFIDENCE_LEVEL_HIGH = 2;
- field @AddedInOrBefore int CONFIDENCE_LEVEL_MAX = 3;
- field @AddedInOrBefore int role;
- field @AddedInOrBefore long timestampMillis;
- field @AddedInOrBefore boolean isPresent;
- field @AddedInOrBefore GazeDetection gazeDetection;
- field @AddedInOrBefore DriverMonitoringDetection driverMonitoringDetection;
- field @AddedInOrBefore Parcelable.Creator<OccupantAwarenessDetection> CREATOR;
- method @AddedInOrBefore int describeContents();
- method @AddedInOrBefore void writeToParcel(Parcel dest, int flags);
- method @AddedInOrBefore String toString();
-class @hide Point3D package android.car.occupantawareness
- field @AddedInOrBefore double x;
- field @AddedInOrBefore double y;
- field @AddedInOrBefore double z;
- field @AddedInOrBefore Parcelable.Creator<Point3D> CREATOR;
- method @AddedInOrBefore int describeContents();
- method @AddedInOrBefore void writeToParcel(Parcel dest, int flags);
- method @AddedInOrBefore String toString();
-class @hide SystemStatusEvent package android.car.occupantawareness
- field @AddedInOrBefore int SYSTEM_STATUS_READY = 0;
- field @AddedInOrBefore int SYSTEM_STATUS_NOT_SUPPORTED = 1;
- field @AddedInOrBefore int SYSTEM_STATUS_NOT_READY = 2;
- field @AddedInOrBefore int SYSTEM_STATUS_SYSTEM_FAILURE = 3;
- field @AddedInOrBefore int DETECTION_TYPE_NONE = 0;
- field @AddedInOrBefore int DETECTION_TYPE_PRESENCE = 1 << 0;
- field @AddedInOrBefore int DETECTION_TYPE_GAZE = 1 << 1;
- field @AddedInOrBefore int DETECTION_TYPE_DRIVER_MONITORING = 1 << 2;
- field @AddedInOrBefore int systemStatus;
- field @AddedInOrBefore int detectionType;
- field @AddedInOrBefore Parcelable.Creator<SystemStatusEvent> CREATOR;
- method @AddedInOrBefore int describeContents();
- method @AddedInOrBefore void writeToParcel(Parcel dest, int flags);
- method @AddedInOrBefore String toString();
-class @hide GazeDetection package android.car.occupantawareness
- field @AddedInOrBefore int VEHICLE_REGION_UNKNOWN = 0;
- field @AddedInOrBefore int VEHICLE_REGION_CENTER_INSTRUMENT_CLUSTER = 1;
- field @AddedInOrBefore int VEHICLE_REGION_REAR_VIEW_MIRROR = 2;
- field @AddedInOrBefore int VEHICLE_REGION_LEFT_SIDE_MIRROR = 3;
- field @AddedInOrBefore int VEHICLE_REGION_RIGHT_SIDE_MIRROR = 4;
- field @AddedInOrBefore int VEHICLE_REGION_FORWARD_ROADWAY = 5;
- field @AddedInOrBefore int VEHICLE_REGION_LEFT_ROADWAY = 6;
- field @AddedInOrBefore int VEHICLE_REGION_RIGHT_ROADWAY = 7;
- field @AddedInOrBefore int VEHICLE_REGION_HEAD_UNIT_DISPLAY = 8;
- field @AddedInOrBefore int confidenceLevel;
- field @AddedInOrBefore Point3D leftEyePosition;
- field @AddedInOrBefore Point3D rightEyePosition;
- field @AddedInOrBefore Point3D headAngleUnitVector;
- field @AddedInOrBefore Point3D gazeAngleUnitVector;
- field @AddedInOrBefore int gazeTarget;
- field @AddedInOrBefore long durationOnTargetMillis;
- field @AddedInOrBefore Parcelable.Creator<GazeDetection> CREATOR;
- method @AddedInOrBefore int describeContents();
- method @AddedInOrBefore void writeToParcel(Parcel dest, int flags);
- method @AddedInOrBefore String toString();
-class @hide OccupantAwarenessManager package android.car.occupantawareness
- method @hide @AddedInOrBefore void onCarDisconnected();
- method @AddedInOrBefore int getCapabilityForRole(int role);
- method @AddedInOrBefore void registerChangeCallback(ChangeCallback callback);
- method @AddedInOrBefore void unregisterChangeCallback();
-class OccupantAwarenessManager.ChangeCallback package android.car.occupantawareness
- method @AddedInOrBefore void onSystemStateChanged(SystemStatusEvent systemStatus);
- method @AddedInOrBefore void onDetectionEvent(OccupantAwarenessDetection event);
-class @hide VehicleOilLevel package android.car
- field @AddedInOrBefore int CRITICALLY_LOW = 0;
- field @AddedInOrBefore int LOW = 1;
- field @AddedInOrBefore int NORMAL = 2;
- field @AddedInOrBefore int HIGH = 3;
- field @AddedInOrBefore int ERROR = 4;
-class @hide VehiclePropertyType package android.car
- field @AddedInOrBefore int STRING = 0x00100000;
- field @AddedInOrBefore int BOOLEAN = 0x00200000;
- field @AddedInOrBefore int INT32 = 0x00400000;
- field @AddedInOrBefore int INT32_VEC = 0x00410000;
- field @AddedInOrBefore int INT64 = 0x00500000;
- field @AddedInOrBefore int INT64_VEC = 0x00510000;
- field @AddedInOrBefore int FLOAT = 0x00600000;
- field @AddedInOrBefore int FLOAT_VEC = 0x00610000;
- field @AddedInOrBefore int BYTES = 0x00700000;
- field @AddedInOrBefore int MIXED = 0x00e00000;
- field @AddedInOrBefore int MASK = 0x00ff0000;
-class @hide @SystemApi ProjectionStatus package android.car.projection
- field @AddedInOrBefore int PROJECTION_STATE_INACTIVE = 0;
- field @AddedInOrBefore int PROJECTION_STATE_READY_TO_PROJECT = 1;
- field @AddedInOrBefore int PROJECTION_STATE_ACTIVE_FOREGROUND = 2;
- field @AddedInOrBefore int PROJECTION_STATE_ACTIVE_BACKGROUND = 3;
- field @AddedInOrBefore int PROJECTION_TRANSPORT_NONE = 0;
- field @AddedInOrBefore int PROJECTION_TRANSPORT_USB = 1;
- field @AddedInOrBefore int PROJECTION_TRANSPORT_WIFI = 2;
- field @AddedInOrBefore Creator<ProjectionStatus> CREATOR;
- method @AddedInOrBefore int describeContents();
- method @AddedInOrBefore void writeToParcel(Parcel dest, int flags);
- method @AddedInOrBefore int getState();
- method @AddedInOrBefore String getPackageName();
- method @AddedInOrBefore Bundle getExtras();
- method @AddedInOrBefore boolean isActive();
- method @AddedInOrBefore int getTransport();
- method @AddedInOrBefore List<MobileDevice> getConnectedMobileDevices();
- method @AddedInOrBefore Builder builder(String packageName, int state);
- method @AddedInOrBefore String toString();
-class ProjectionStatus.Builder package android.car.projection
- method @AddedInOrBefore Builder setProjectionTransport(int transport);
- method @AddedInOrBefore Builder addMobileDevice(MobileDevice mobileDevice);
- method @AddedInOrBefore Builder setExtras(Bundle extras);
- method @AddedInOrBefore ProjectionStatus build();
-class ProjectionStatus.MobileDevice package android.car.projection
- field @AddedInOrBefore Creator<MobileDevice> CREATOR;
- method @AddedInOrBefore void writeToParcel(Parcel dest, int flags);
- method @AddedInOrBefore int getId();
- method @AddedInOrBefore String getName();
- method @AddedInOrBefore List<Integer> getAvailableTransports();
- method @AddedInOrBefore boolean isProjecting();
- method @AddedInOrBefore Bundle getExtras();
- method @AddedInOrBefore int describeContents();
- method @AddedInOrBefore Builder builder(int id, String name);
- method @AddedInOrBefore String toString();
-class ProjectionStatus.MobileDevice.Builder package android.car.projection
- method @AddedInOrBefore Builder addTransport(int transport);
- method @AddedInOrBefore Builder setProjecting(boolean projecting);
- method @AddedInOrBefore Builder setExtras(Bundle extras);
- method @AddedInOrBefore MobileDevice build();
-class @hide @SystemApi ProjectionOptions package android.car.projection
- field @AddedInOrBefore int UI_MODE_FULL_SCREEN = 0;
- field @AddedInOrBefore int UI_MODE_BLENDED = 1;
- field @AddedInOrBefore int AP_MODE_NOT_SPECIFIED = 0;
- field @AddedInOrBefore int AP_MODE_TETHERED = 1;
- field @AddedInOrBefore int AP_MODE_LOHS_DYNAMIC_CREDENTIALS = 2;
- field @AddedInOrBefore int AP_MODE_LOHS_STATIC_CREDENTIALS = 3;
- method @AddedInOrBefore int getUiMode();
- method @AddedInOrBefore int getProjectionAccessPointMode();
- method @AddedInOrBefore ActivityOptions getActivityOptions();
- method @AddedInOrBefore ComponentName getConsentActivity();
- method @AddedInOrBefore Bundle toBundle();
- method @hide @AddedInOrBefore Builder builder();
- method @hide @AddedInOrBefore String toString();
-class @hide ProjectionOptions.Builder package android.car.projection
- method @AddedInOrBefore Builder setProjectionActivityOptions(ActivityOptions activityOptions);
- method @AddedInOrBefore Builder setUiMode(int uiMode);
- method @AddedInOrBefore Builder setConsentActivity(ComponentName consentActivity);
- method @AddedInOrBefore Builder setAccessPointMode(int accessPointMode);
- method @AddedInOrBefore ProjectionOptions build();
-class @hide @SystemApi CarEvsManager package android.car.evs
- field @AddedInOrBefore String EXTRA_SESSION_TOKEN = "android.car.evs.extra.SESSION_TOKEN";
- field @AddedInOrBefore int SERVICE_TYPE_REARVIEW = 0;
- field @AddedInOrBefore int SERVICE_TYPE_SURROUNDVIEW = 1;
- field @AddedInOrBefore int SERVICE_STATE_UNAVAILABLE = 0;
- field @AddedInOrBefore int SERVICE_STATE_INACTIVE = 1;
- field @AddedInOrBefore int SERVICE_STATE_REQUESTED = 2;
- field @AddedInOrBefore int SERVICE_STATE_ACTIVE = 3;
- field @AddedInOrBefore int STREAM_EVENT_NONE = 0;
- field @AddedInOrBefore int STREAM_EVENT_STREAM_STARTED = 1;
- field @AddedInOrBefore int STREAM_EVENT_STREAM_STOPPED = 2;
- field @AddedInOrBefore int STREAM_EVENT_FRAME_DROPPED = 3;
- field @AddedInOrBefore int STREAM_EVENT_TIMEOUT = 4;
- field @AddedInOrBefore int STREAM_EVENT_PARAMETER_CHANGED = 5;
- field @AddedInOrBefore int STREAM_EVENT_PRIMARY_OWNER_CHANGED = 6;
- field @AddedInOrBefore int STREAM_EVENT_OTHER_ERRORS = 7;
- field @AddedInOrBefore int ERROR_NONE = 0;
- field @AddedInOrBefore int ERROR_UNAVAILABLE = -1;
- field @AddedInOrBefore int ERROR_BUSY = -2;
- method @hide @AddedInOrBefore void onCarDisconnected();
- method @AddedInOrBefore void setStatusListener(Executor executor, CarEvsStatusListener listener);
- method @AddedInOrBefore void clearStatusListener();
- method @AddedInOrBefore void returnFrameBuffer(CarEvsBufferDescriptor buffer);
- method @AddedInOrBefore int startActivity(int type);
- method @AddedInOrBefore void stopActivity();
- method @AddedInOrBefore int startVideoStream(int type, IBinder token, Executor executor, CarEvsStreamCallback callback);
- method @AddedInOrBefore void stopVideoStream();
- method @AddedInOrBefore CarEvsStatus getCurrentStatus();
- method @AddedInOrBefore IBinder generateSessionToken();
- method @AddedInOrBefore boolean isSupported(int type);
-interface CarEvsManager.CarEvsStatusListener package android.car.evs
- method @AddedInOrBefore void onStatusChanged(CarEvsStatus status);
-interface CarEvsManager.CarEvsStreamCallback package android.car.evs
- method @AddedInOrBefore void onStreamEvent(int event);
- method @AddedInOrBefore void onNewFrame(CarEvsBufferDescriptor buffer);
-class @hide @SystemApi CarEvsStatus package android.car.evs
- field @AddedInOrBefore Parcelable.Creator<CarEvsStatus> CREATOR;
- method @AddedInOrBefore int describeContents();
- method @AddedInOrBefore void writeToParcel(Parcel dest, int flags);
- method @AddedInOrBefore String toString();
- method @AddedInOrBefore int getState();
- method @AddedInOrBefore int getServiceType();
-class @hide @SystemApi CarEvsBufferDescriptor package android.car.evs
- field @AddedInOrBefore Parcelable.Creator<CarEvsBufferDescriptor> CREATOR;
- method @AddedInOrBefore int describeContents();
- method @AddedInOrBefore void writeToParcel(Parcel dest, int flags);
- method @AddedInOrBefore String toString();
- method @AddedInOrBefore int getId();
- method @AddedInOrBefore HardwareBuffer getHardwareBuffer();
-class @hide @SystemApi CarMediaManager package android.car.media
- field @AddedInOrBefore int MEDIA_SOURCE_MODE_PLAYBACK = 0;
- field @AddedInOrBefore int MEDIA_SOURCE_MODE_BROWSE = 1;
- method @AddedInOrBefore ComponentName getMediaSource(int mode);
- method @AddedInOrBefore void setMediaSource(ComponentName componentName, int mode);
- method @AddedInOrBefore void addMediaSourceListener(MediaSourceChangedListener callback, int mode);
- method @AddedInOrBefore void removeMediaSourceListener(MediaSourceChangedListener callback, int mode);
- method @AddedInOrBefore List<ComponentName> getLastMediaSources(int mode);
- method @hide @AddedInOrBefore void onCarDisconnected();
- method @hide @AddedInOrBefore boolean isIndependentPlaybackConfig();
- method @hide @AddedInOrBefore void setIndependentPlaybackConfig(boolean independent);
-interface CarMediaManager.MediaSourceChangedListener package android.car.media
- method @AddedInOrBefore void onMediaSourceChanged(ComponentName componentName);
-class @hide @SystemApi CarAudioPatchHandle package android.car.media
- field @AddedInOrBefore Parcelable.Creator<CarAudioPatchHandle> CREATOR;
- method @AddedInOrBefore String toString();
- method @AddedInOrBefore void writeToParcel(Parcel out, int flags);
- method @AddedInOrBefore int describeContents();
- method @hide @AddedInOrBefore String getSourceAddress();
- method @hide @AddedInOrBefore String getSinkAddress();
- method @hide @AddedInOrBefore int getHandleId();
-class CarAudioManager package android.car.media
- field @hide @SystemApi @AddedInOrBefore int PRIMARY_AUDIO_ZONE = 0x0;
- field @hide @SystemApi @AddedInOrBefore int INVALID_AUDIO_ZONE = 0xffffffff;
- field @AddedInOrBefore int AUDIO_FEATURE_DYNAMIC_ROUTING = 0x1;
- field @AddedInOrBefore int AUDIO_FEATURE_VOLUME_GROUP_MUTING = 0x2;
- field @hide @AddedInOrBefore int INVALID_VOLUME_GROUP_ID = -1;
- field @hide @SystemApi @AddedInOrBefore String AUDIOFOCUS_EXTRA_RECEIVE_DUCKING_EVENTS = "android.car.media.AUDIOFOCUS_EXTRA_RECEIVE_DUCKING_EVENTS";
- field @hide @AddedInOrBefore String AUDIOFOCUS_EXTRA_REQUEST_ZONE_ID = "android.car.media.AUDIOFOCUS_EXTRA_REQUEST_ZONE_ID";
- method @hide @AddedInOrBefore boolean isDynamicRoutingEnabled();
- method @AddedInOrBefore boolean isAudioFeatureEnabled(int audioFeature);
- method @hide @SystemApi @AddedInOrBefore void setGroupVolume(int groupId, int index, int flags);
- method @hide @SystemApi @AddedInOrBefore void setGroupVolume(int zoneId, int groupId, int index, int flags);
- method @hide @SystemApi @AddedInOrBefore int getGroupMaxVolume(int groupId);
- method @hide @SystemApi @AddedInOrBefore int getGroupMaxVolume(int zoneId, int groupId);
- method @hide @SystemApi @AddedInOrBefore int getGroupMinVolume(int groupId);
- method @hide @SystemApi @AddedInOrBefore int getGroupMinVolume(int zoneId, int groupId);
- method @hide @SystemApi @AddedInOrBefore int getGroupVolume(int groupId);
- method @hide @SystemApi @AddedInOrBefore int getGroupVolume(int zoneId, int groupId);
- method @hide @SystemApi @AddedInOrBefore void setFadeTowardFront(float value);
- method @hide @SystemApi @AddedInOrBefore void setBalanceTowardRight(float value);
- method @hide @SystemApi @AddedInOrBefore String[] getExternalSources();
- method @hide @SystemApi @AddedInOrBefore CarAudioPatchHandle createAudioPatch(String sourceAddress, int usage, int gainInMillibels);
- method @hide @SystemApi @AddedInOrBefore void releaseAudioPatch(CarAudioPatchHandle patch);
- method @hide @SystemApi @AddedInOrBefore int getVolumeGroupCount();
- method @hide @SystemApi @AddedInOrBefore int getVolumeGroupCount(int zoneId);
- method @hide @SystemApi @AddedInOrBefore int getVolumeGroupIdForUsage(int usage);
- method @hide @SystemApi @AddedInOrBefore int getVolumeGroupIdForUsage(int zoneId, int usage);
- method @hide @SystemApi @AddedInOrBefore int[] getUsagesForVolumeGroupId(int groupId);
- method @hide @SystemApi @AddedInOrBefore int[] getUsagesForVolumeGroupId(int zoneId, int groupId);
- method @hide @SystemApi @AddedInOrBefore boolean isPlaybackOnVolumeGroupActive(int zoneId, int groupId);
- method @hide @SystemApi @AddedInOrBefore List<Integer> getAudioZoneIds();
- method @hide @AddedInOrBefore int getZoneIdForUid(int uid);
- method @hide @AddedInOrBefore boolean setZoneIdForUid(int zoneId, int uid);
- method @hide @AddedInOrBefore boolean clearZoneIdForUid(int uid);
- method @hide @SystemApi @AddedInOrBefore AudioDeviceInfo getOutputDeviceForUsage(int zoneId, int usage);
- method @hide @SystemApi @AddedInOrBefore List<AudioDeviceInfo> getInputDevicesForZoneId(int zoneId);
- method @hide @AddedInOrBefore void onCarDisconnected();
- method @AddedInOrBefore void registerCarVolumeCallback(CarVolumeCallback callback);
- method @AddedInOrBefore void unregisterCarVolumeCallback(CarVolumeCallback callback);
- method @hide @SystemApi @AddedInOrBefore boolean isVolumeGroupMuted(int zoneId, int groupId);
- method @hide @SystemApi @AddedInOrBefore void setVolumeGroupMute(int zoneId, int groupId, boolean mute, int flags);
-class CarAudioManager.CarVolumeCallback package android.car.media
- method @AddedInOrBefore void onGroupVolumeChanged(int zoneId, int groupId, int flags);
- method @AddedInOrBefore void onMasterMuteChanged(int zoneId, int flags);
- method @AddedInOrBefore void onGroupMuteChanged(int zoneId, int groupId, int flags);
-class CarMediaIntents package android.car.media
- field @AddedInOrBefore String ACTION_MEDIA_TEMPLATE = "android.car.intent.action.MEDIA_TEMPLATE";
- field @AddedInOrBefore String EXTRA_MEDIA_COMPONENT = "android.car.intent.extra.MEDIA_COMPONENT";
- field @AddedInOrBefore String EXTRA_SEARCH_QUERY = "android.car.media.extra.SEARCH_QUERY";
-class @hide @SystemApi CarAppBlockingPolicy package android.car.content.pm
- field @AddedInOrBefore AppBlockingPackageInfo[] whitelists;
- field @AddedInOrBefore AppBlockingPackageInfo[] blacklists;
- field @AddedInOrBefore Parcelable.Creator<CarAppBlockingPolicy> CREATOR;
- method @AddedInOrBefore int describeContents();
- method @AddedInOrBefore void writeToParcel(Parcel dest, int flags);
- method @AddedInOrBefore int hashCode();
- method @AddedInOrBefore boolean equals(Object obj);
- method @AddedInOrBefore String toString();
-class CarPackageManager package android.car.content.pm
- field @hide @SystemApi @AddedInOrBefore int FLAG_SET_POLICY_WAIT_FOR_CHANGE = 0x1;
- field @hide @SystemApi @AddedInOrBefore int FLAG_SET_POLICY_ADD = 0x2;
- field @hide @SystemApi @AddedInOrBefore int FLAG_SET_POLICY_REMOVE = 0x4;
- field @hide @AddedInOrBefore String BLOCKING_INTENT_EXTRA_BLOCKED_ACTIVITY_NAME = "blocked_activity";
- field @hide @AddedInOrBefore String BLOCKING_INTENT_EXTRA_BLOCKED_TASK_ID = "blocked_task_id";
- field @hide @AddedInOrBefore String BLOCKING_INTENT_EXTRA_ROOT_ACTIVITY_NAME = "root_activity_name";
- field @hide @AddedInOrBefore String BLOCKING_INTENT_EXTRA_IS_ROOT_ACTIVITY_DO = "is_root_activity_do";
- field @hide @AddedInOrBefore String BLOCKING_INTENT_EXTRA_DISPLAY_ID = "display_id";
- field @hide @AddedInOrBefore String DRIVING_SAFETY_REGION_ALL = "android.car.drivingsafetyregion.all";
- field @hide @AddedInOrBefore String DRIVING_SAFETY_ACTIVITY_METADATA_REGIONS = "android.car.drivingsafetyregions";
- field @hide @AddedInOrBefore int ERROR_CODE_NO_PACKAGE = -100;
- method @hide @AddedInOrBefore void onCarDisconnected();
- method @hide @SystemApi @AddedInOrBefore void setAppBlockingPolicy(String packageName, CarAppBlockingPolicy policy, int flags);
- method @hide @AddedInOrBefore void restartTask(int taskId);
- method @hide @SystemApi @AddedInOrBefore boolean isActivityBackedBySafeActivity(ComponentName activityName);
- method @hide @AddedInOrBefore void setEnableActivityBlocking(boolean enable);
- method @AddedInOrBefore boolean isActivityDistractionOptimized(String packageName, String className);
- method @AddedInOrBefore boolean isPendingIntentDistractionOptimized(PendingIntent pendingIntent);
- method @AddedInOrBefore boolean isServiceDistractionOptimized(String packageName, String className);
- method @hide @AddedInOrBefore String getCurrentDrivingSafetyRegion();
- method @hide @AddedInOrBefore void controlTemporaryActivityBlockingBypassingAsUser(String packageName, String activityClassName, boolean bypass, int userId);
- method @hide @AddedInOrBefore List<String> getSupportedDrivingSafetyRegionsForActivityAsUser(String packageName, String activityClassName, int userId);
-class @hide @SystemApi AppBlockingPackageInfo package android.car.content.pm
- field @AddedInOrBefore String packageName;
- field @AddedInOrBefore int FLAG_SYSTEM_APP = 0x1;
- field @AddedInOrBefore int FLAG_WHOLE_ACTIVITY = 0x2;
- field @AddedInOrBefore int flags;
- field @AddedInOrBefore int minRevisionCode;
- field @AddedInOrBefore int maxRevisionCode;
- field @AddedInOrBefore Signature[] signatures;
- field @AddedInOrBefore String[] activities;
- field @AddedInOrBefore Parcelable.Creator<AppBlockingPackageInfo> CREATOR;
- method @AddedInOrBefore int describeContents();
- method @AddedInOrBefore void writeToParcel(Parcel dest, int flags);
- method @hide @AddedInOrBefore void verify();
- method @hide @AddedInOrBefore boolean isActivityCovered(String className);
- method @AddedInOrBefore int hashCode();
- method @AddedInOrBefore boolean equals(Object obj);
- method @AddedInOrBefore String toString();
-class @hide @SystemApi CarAppBlockingPolicyService package android.car.content.pm
- field @AddedInOrBefore String SERVICE_INTERFACE = "android.car.content.pm.CarAppBlockingPolicyService";
- method @AddedInOrBefore CarAppBlockingPolicy getAppBlockingPolicy();
- method @AddedInOrBefore int onStartCommand(Intent intent, int flags, int startId);
- method @AddedInOrBefore IBinder onBind(Intent intent);
- method @AddedInOrBefore boolean onUnbind(Intent intent);
-class VehicleAreaSeat package android.car
- field @AddedInOrBefore int SEAT_UNKNOWN = 0;
- field @AddedInOrBefore int SEAT_ROW_1_LEFT = 0x0001;
- field @AddedInOrBefore int SEAT_ROW_1_CENTER = 0x0002;
- field @AddedInOrBefore int SEAT_ROW_1_RIGHT = 0x0004;
- field @AddedInOrBefore int SEAT_ROW_2_LEFT = 0x0010;
- field @AddedInOrBefore int SEAT_ROW_2_CENTER = 0x0020;
- field @AddedInOrBefore int SEAT_ROW_2_RIGHT = 0x0040;
- field @AddedInOrBefore int SEAT_ROW_3_LEFT = 0x0100;
- field @AddedInOrBefore int SEAT_ROW_3_CENTER = 0x0200;
- field @AddedInOrBefore int SEAT_ROW_3_RIGHT = 0x0400;
- field @hide @AddedInOrBefore int SIDE_LEFT = -1;
- field @hide @AddedInOrBefore int SIDE_CENTER = 0;
- field @hide @AddedInOrBefore int SIDE_RIGHT = 1;
- method @hide @AddedInOrBefore int fromRowAndSide(int rowNumber, int side);
-class CarOccupantZoneManager package android.car
- field @AddedInOrBefore int DISPLAY_TYPE_UNKNOWN = 0;
- field @AddedInOrBefore int DISPLAY_TYPE_MAIN = 1;
- field @AddedInOrBefore int DISPLAY_TYPE_INSTRUMENT_CLUSTER = 2;
- field @AddedInOrBefore int DISPLAY_TYPE_HUD = 3;
- field @AddedInOrBefore int DISPLAY_TYPE_INPUT = 4;
- field @AddedInOrBefore int DISPLAY_TYPE_AUXILIARY = 5;
- field @hide @AddedInOrBefore int OCCUPANT_TYPE_INVALID = -1;
- field @AddedInOrBefore int OCCUPANT_TYPE_DRIVER = 0;
- field @AddedInOrBefore int OCCUPANT_TYPE_FRONT_PASSENGER = 1;
- field @AddedInOrBefore int OCCUPANT_TYPE_REAR_PASSENGER = 2;
- field @AddedInOrBefore int ZONE_CONFIG_CHANGE_FLAG_DISPLAY = 0x1;
- field @AddedInOrBefore int ZONE_CONFIG_CHANGE_FLAG_USER = 0x2;
- field @AddedInOrBefore int ZONE_CONFIG_CHANGE_FLAG_AUDIO = 0x4;
- method @AddedInOrBefore List<OccupantZoneInfo> getAllOccupantZones();
- method @AddedInOrBefore List<Display> getAllDisplaysForOccupant(OccupantZoneInfo occupantZone);
- method @AddedInOrBefore Display getDisplayForOccupant(OccupantZoneInfo occupantZone, int displayType);
- method @hide @SystemApi @AddedInOrBefore int getDisplayIdForDriver(int displayType);
- method @hide @SystemApi @AddedInOrBefore int getAudioZoneIdForOccupant(OccupantZoneInfo occupantZone);
- method @hide @SystemApi @AddedInOrBefore OccupantZoneInfo getOccupantForAudioZoneId(int audioZoneId);
- method @AddedInOrBefore int getDisplayType(Display display);
- method @AddedInOrBefore int getUserForOccupant(OccupantZoneInfo occupantZone);
- method @hide @AddedInOrBefore boolean assignProfileUserToOccupantZone(OccupantZoneInfo occupantZone, int userId);
- method @AddedInOrBefore void registerOccupantZoneConfigChangeListener(OccupantZoneConfigChangeListener listener);
- method @AddedInOrBefore void unregisterOccupantZoneConfigChangeListener(OccupantZoneConfigChangeListener listener);
- method @hide @AddedInOrBefore void onCarDisconnected();
-class CarOccupantZoneManager.OccupantZoneInfo package android.car
- field @hide @AddedInOrBefore int INVALID_ZONE_ID = -1;
- field @AddedInOrBefore int zoneId;
- field @AddedInOrBefore int occupantType;
- field @AddedInOrBefore int seat;
- field @AddedInOrBefore Parcelable.Creator<OccupantZoneInfo> CREATOR;
- method @AddedInOrBefore int describeContents();
- method @AddedInOrBefore void writeToParcel(Parcel dest, int flags);
- method @AddedInOrBefore boolean equals(Object other);
- method @AddedInOrBefore int hashCode();
- method @AddedInOrBefore String toString();
-interface CarOccupantZoneManager.OccupantZoneConfigChangeListener package android.car
- method @AddedInOrBefore void onOccupantZoneConfigChanged(int changeFlags);
-class @hide VehicleSeatOccupancyState package android.car
- field @AddedInOrBefore int UNKNOWN = 0;
- field @AddedInOrBefore int VACANT = 1;
- field @AddedInOrBefore int OCCUPIED = 2;
-class VehicleGear package android.car
- field @AddedInOrBefore int GEAR_UNKNOWN = 0x0000;
- field @AddedInOrBefore int GEAR_NEUTRAL = 0x0001;
- field @AddedInOrBefore int GEAR_REVERSE = 0x0002;
- field @AddedInOrBefore int GEAR_PARK = 0x0004;
- field @AddedInOrBefore int GEAR_DRIVE = 0x0008;
- field @AddedInOrBefore int GEAR_FIRST = 0x0010;
- field @AddedInOrBefore int GEAR_SECOND = 0x0020;
- field @AddedInOrBefore int GEAR_THIRD = 0x0040;
- field @AddedInOrBefore int GEAR_FOURTH = 0x0080;
- field @AddedInOrBefore int GEAR_FIFTH = 0x0100;
- field @AddedInOrBefore int GEAR_SIXTH = 0x0200;
- field @AddedInOrBefore int GEAR_SEVENTH = 0x0400;
- field @AddedInOrBefore int GEAR_EIGHTH = 0x0800;
- field @AddedInOrBefore int GEAR_NINTH = 0x1000;
- method @AddedInOrBefore String toString(int o);
-class EvConnectorType package android.car
- field @AddedInOrBefore int UNKNOWN = 0;
- field @AddedInOrBefore int J1772 = 1;
- field @AddedInOrBefore int MENNEKES = 2;
- field @AddedInOrBefore int CHADEMO = 3;
- field @AddedInOrBefore int COMBO_1 = 4;
- field @AddedInOrBefore int COMBO_2 = 5;
- field @AddedInOrBefore int TESLA_ROADSTER = 6;
- field @AddedInOrBefore int TESLA_HPWC = 7;
- field @AddedInOrBefore int TESLA_SUPERCHARGER = 8;
- field @AddedInOrBefore int GBT = 9;
- field @AddedInOrBefore int GBT_DC = 10;
- field @AddedInOrBefore int SCAME = 11;
- field @AddedInOrBefore int OTHER = 101;
-class @hide @SystemApi CarUserManager package android.car.user
- field @hide @AddedInOrBefore String TAG = CarUserManager.class.getSimpleName();
- field @hide @SystemApi @AddedInOrBefore int USER_LIFECYCLE_EVENT_TYPE_STARTING = CommonConstants.USER_LIFECYCLE_EVENT_TYPE_STARTING;
- field @hide @SystemApi @AddedInOrBefore int USER_LIFECYCLE_EVENT_TYPE_SWITCHING = CommonConstants.USER_LIFECYCLE_EVENT_TYPE_SWITCHING;
- field @hide @SystemApi @AddedInOrBefore int USER_LIFECYCLE_EVENT_TYPE_UNLOCKING = CommonConstants.USER_LIFECYCLE_EVENT_TYPE_UNLOCKING;
- field @hide @SystemApi @AddedInOrBefore int USER_LIFECYCLE_EVENT_TYPE_UNLOCKED = CommonConstants.USER_LIFECYCLE_EVENT_TYPE_UNLOCKED;
- field @hide @AddedInOrBefore int USER_LIFECYCLE_EVENT_TYPE_POST_UNLOCKED = CommonConstants.USER_LIFECYCLE_EVENT_TYPE_POST_UNLOCKED;
- field @hide @SystemApi @AddedInOrBefore int USER_LIFECYCLE_EVENT_TYPE_STOPPING = CommonConstants.USER_LIFECYCLE_EVENT_TYPE_STOPPING;
- field @hide @SystemApi @AddedInOrBefore int USER_LIFECYCLE_EVENT_TYPE_STOPPED = CommonConstants.USER_LIFECYCLE_EVENT_TYPE_STOPPED;
- field @hide @AddedInOrBefore String BUNDLE_PARAM_ACTION = "action";
- field @hide @AddedInOrBefore String BUNDLE_PARAM_PREVIOUS_USER_ID = "previous_user";
- field @hide @AddedInOrBefore int USER_IDENTIFICATION_ASSOCIATION_TYPE_KEY_FOB = 1;
- field @hide @AddedInOrBefore int USER_IDENTIFICATION_ASSOCIATION_TYPE_CUSTOM_1 = 101;
- field @hide @AddedInOrBefore int USER_IDENTIFICATION_ASSOCIATION_TYPE_CUSTOM_2 = 102;
- field @hide @AddedInOrBefore int USER_IDENTIFICATION_ASSOCIATION_TYPE_CUSTOM_3 = 103;
- field @hide @AddedInOrBefore int USER_IDENTIFICATION_ASSOCIATION_TYPE_CUSTOM_4 = 104;
- field @hide @AddedInOrBefore int USER_IDENTIFICATION_ASSOCIATION_SET_VALUE_ASSOCIATE_CURRENT_USER = 1;
- field @hide @AddedInOrBefore int USER_IDENTIFICATION_ASSOCIATION_SET_VALUE_DISASSOCIATE_CURRENT_USER = 2;
- field @hide @AddedInOrBefore int USER_IDENTIFICATION_ASSOCIATION_SET_VALUE_DISASSOCIATE_ALL_USERS = 3;
- field @hide @AddedInOrBefore int USER_IDENTIFICATION_ASSOCIATION_VALUE_UNKNOWN = 1;
- field @hide @AddedInOrBefore int USER_IDENTIFICATION_ASSOCIATION_VALUE_ASSOCIATE_CURRENT_USER = 2;
- field @hide @AddedInOrBefore int USER_IDENTIFICATION_ASSOCIATION_VALUE_ASSOCIATED_ANOTHER_USER = 3;
- field @hide @AddedInOrBefore int USER_IDENTIFICATION_ASSOCIATION_VALUE_NOT_ASSOCIATED_ANY_USER = 4;
- method @hide @AddedInOrBefore AsyncFuture<UserSwitchResult> switchUser(int targetUserId);
- method @hide @AddedInOrBefore AsyncFuture<UserSwitchResult> logoutUser();
- method @hide @AddedInOrBefore AsyncFuture<UserCreationResult> createGuest(String name);
- method @hide @AddedInOrBefore AsyncFuture<UserCreationResult> createUser(String name, int flags);
- method @hide @AddedInOrBefore void updatePreCreatedUsers();
- method @hide @AddedInOrBefore UserRemovalResult removeUser(int userId);
- method @hide @SystemApi @AddedInOrBefore void addListener(Executor executor, UserLifecycleListener listener);
- method @hide @SystemApi @AddedInOrBefore void addListener(Executor executor, UserLifecycleEventFilter filter, UserLifecycleListener listener);
- method @hide @SystemApi @AddedInOrBefore void removeListener(UserLifecycleListener listener);
- method @hide @AddedInOrBefore boolean isUserHalUserAssociationSupported();
- method @hide @AddedInOrBefore UserIdentificationAssociationResponse getUserIdentificationAssociation(int types);
- method @hide @AddedInOrBefore AsyncFuture<UserIdentificationAssociationResponse> setUserIdentificationAssociation(int[] types, int[] values);
- method @hide @AddedInOrBefore void setUserSwitchUiCallback(UserSwitchUiCallback callback);
- method @hide @AddedInOrBefore void onCarDisconnected();
- method @hide @AddedInOrBefore String lifecycleEventTypeToString(int type);
- method @hide @AddedInOrBefore boolean isValidUser(int userId);
-class @hide @SystemApi CarUserManager.UserLifecycleEvent package android.car.user
- method @AddedInOrBefore int getEventType();
- method @hide @AddedInOrBefore int getUserId();
- method @AddedInOrBefore UserHandle getUserHandle();
- method @hide @AddedInOrBefore int getPreviousUserId();
- method @AddedInOrBefore UserHandle getPreviousUserHandle();
- method @AddedInOrBefore String toString();
- method @AddedInOrBefore boolean equals(Object o);
- method @AddedInOrBefore int hashCode();
-interface @hide @SystemApi CarUserManager.UserLifecycleListener package android.car.user
- method @AddedInOrBefore void onEvent(UserLifecycleEvent event);
-interface @hide CarUserManager.UserSwitchUiCallback package android.car.user
- method @AddedInOrBefore void showUserSwitchDialog(int userId);
-class @hide ExperimentalCarUserManager package android.car.user
- field @hide @AddedInOrBefore String TAG = ExperimentalCarUserManager.class.getSimpleName();
- method @hide @AddedInOrBefore AndroidFuture<UserCreationResult> createDriver(String name, boolean admin);
- method @hide @AddedInOrBefore int createPassenger(String name, int driverId);
- method @hide @AddedInOrBefore AndroidFuture<UserSwitchResult> switchDriver(int driverId);
- method @hide @AddedInOrBefore List<Integer> getAllDrivers();
- method @hide @AddedInOrBefore List<Integer> getPassengers(int driverId);
- method @hide @AddedInOrBefore boolean startPassenger(int passengerId, int zoneId);
- method @hide @AddedInOrBefore boolean stopPassenger(int passengerId);
- method @hide @AddedInOrBefore void onCarDisconnected();
-class @hide UserStopResult package android.car.user
- field @AddedInOrBefore int STATUS_SUCCESSFUL = CommonResults.STATUS_SUCCESSFUL;
- field @AddedInOrBefore int STATUS_ANDROID_FAILURE = CommonResults.STATUS_ANDROID_FAILURE;
- field @AddedInOrBefore int STATUS_USER_DOES_NOT_EXIST = CommonResults.LAST_COMMON_STATUS + 1;
- field @AddedInOrBefore int STATUS_FAILURE_SYSTEM_USER = CommonResults.LAST_COMMON_STATUS + 2;
- field @AddedInOrBefore int STATUS_FAILURE_CURRENT_USER = CommonResults.LAST_COMMON_STATUS + 3;
- field @AddedInOrBefore Parcelable.Creator<UserStopResult> CREATOR;
- method @AddedInOrBefore boolean isSuccess(int status);
- method @AddedInOrBefore boolean isSuccess();
- method @hide @AddedInOrBefore String statusToString(int value);
- method @AddedInOrBefore int getStatus();
- method @AddedInOrBefore String toString();
- method @AddedInOrBefore void writeToParcel(android.os.Parcel dest, int flags);
- method @AddedInOrBefore int describeContents();
-class @hide UserCreationResult package android.car.user
- field @hide @AddedInOrBefore int STATUS_SUCCESSFUL = CommonResults.STATUS_SUCCESSFUL;
- field @hide @AddedInOrBefore int STATUS_ANDROID_FAILURE = CommonResults.STATUS_ANDROID_FAILURE;
- field @hide @AddedInOrBefore int STATUS_HAL_FAILURE = CommonResults.STATUS_HAL_FAILURE;
- field @hide @AddedInOrBefore int STATUS_HAL_INTERNAL_FAILURE = CommonResults.STATUS_HAL_INTERNAL_FAILURE;
- field @AddedInOrBefore int STATUS_INVALID_REQUEST = CommonResults.STATUS_INVALID_REQUEST;
- field @AddedInOrBefore Parcelable.Creator<UserCreationResult> CREATOR;
- method @AddedInOrBefore boolean isSuccess();
- method @AddedInOrBefore int describeContents();
- method @hide @AddedInOrBefore String statusToString(int value);
- method @AddedInOrBefore int getStatus();
- method @AddedInOrBefore Integer getAndroidFailureStatus();
- method @AddedInOrBefore UserHandle getUser();
- method @AddedInOrBefore String getErrorMessage();
- method @hide @AddedInOrBefore String getInternalErrorMessage();
- method @AddedInOrBefore String toString();
- method @AddedInOrBefore void writeToParcel(android.os.Parcel dest, int flags);
-class @hide UserRemovalResult package android.car.user
- field @AddedInOrBefore int STATUS_SUCCESSFUL = CommonResults.STATUS_SUCCESSFUL;
- field @AddedInOrBefore int STATUS_ANDROID_FAILURE = CommonResults.STATUS_ANDROID_FAILURE;
- field @AddedInOrBefore int STATUS_INVALID_REQUEST = CommonResults.STATUS_INVALID_REQUEST;
- field @AddedInOrBefore int STATUS_USER_DOES_NOT_EXIST = CommonResults.LAST_COMMON_STATUS + 1;
- field @AddedInOrBefore int STATUS_SUCCESSFUL_LAST_ADMIN_REMOVED = CommonResults.LAST_COMMON_STATUS + 2;
- field @AddedInOrBefore int STATUS_SUCCESSFUL_SET_EPHEMERAL = CommonResults.LAST_COMMON_STATUS + 3;
- field @AddedInOrBefore int STATUS_SUCCESSFUL_LAST_ADMIN_SET_EPHEMERAL = CommonResults.LAST_COMMON_STATUS + 4;
- field @AddedInOrBefore Parcelable.Creator<UserRemovalResult> CREATOR;
- method @AddedInOrBefore boolean isSuccess();
- method @hide @AddedInOrBefore String statusToString(int value);
- method @AddedInOrBefore int getStatus();
- method @AddedInOrBefore String toString();
- method @AddedInOrBefore void writeToParcel(android.os.Parcel dest, int flags);
- method @AddedInOrBefore int describeContents();
-class CommonResults package android.car.user
- field @AddedInOrBefore int STATUS_SUCCESSFUL = 1;
- field @AddedInOrBefore int STATUS_ANDROID_FAILURE = 2;
- field @AddedInOrBefore int STATUS_HAL_FAILURE = 3;
- field @AddedInOrBefore int STATUS_HAL_INTERNAL_FAILURE = 4;
- field @AddedInOrBefore int STATUS_INVALID_REQUEST = 5;
- field @AddedInOrBefore int STATUS_UX_RESTRICTION_FAILURE = 6;
- field @AddedInOrBefore int LAST_COMMON_STATUS = 100;
-interface @hide OperationResult package android.car.user
- method @AddedInOrBefore boolean isSuccess();
-class @hide @SystemApi UserLifecycleEventFilter package android.car.user
- field @AddedInOrBefore Parcelable.Creator<UserLifecycleEventFilter> CREATOR;
- method @hide @AddedInOrBefore int[] getEventTypes();
- method @hide @AddedInOrBefore int[] getUserIds();
- method @AddedInOrBefore boolean apply(UserLifecycleEvent event);
- method @AddedInOrBefore String toString();
- method @AddedInOrBefore boolean equals(Object o);
- method @AddedInOrBefore int hashCode();
- method @AddedInOrBefore void writeToParcel(Parcel dest, int flags);
- method @AddedInOrBefore int describeContents();
-class @hide UserLifecycleEventFilter.Builder package android.car.user
- method @AddedInOrBefore Builder addEventType(int eventType);
- method @AddedInOrBefore Builder addUser(UserHandle userHandle);
- method @AddedInOrBefore UserLifecycleEventFilter build();
-class @hide UserStartResult package android.car.user
- field @hide @AddedInOrBefore int STATUS_SUCCESSFUL = CommonResults.STATUS_SUCCESSFUL;
- field @hide @AddedInOrBefore int STATUS_ANDROID_FAILURE = CommonResults.STATUS_ANDROID_FAILURE;
- field @hide @AddedInOrBefore int STATUS_SUCCESSFUL_USER_IS_CURRENT_USER = CommonResults.LAST_COMMON_STATUS + 1;
- field @hide @AddedInOrBefore int STATUS_USER_DOES_NOT_EXIST = CommonResults.LAST_COMMON_STATUS + 2;
- field @AddedInOrBefore Parcelable.Creator<UserStartResult> CREATOR;
- method @AddedInOrBefore boolean isSuccess();
- method @hide @AddedInOrBefore String statusToString(int value);
- method @AddedInOrBefore int getStatus();
- method @AddedInOrBefore String toString();
- method @AddedInOrBefore void writeToParcel(android.os.Parcel dest, int flags);
- method @AddedInOrBefore int describeContents();
-class @hide UserIdentificationAssociationResponse package android.car.user
- field @AddedInOrBefore Parcelable.Creator<UserIdentificationAssociationResponse> CREATOR;
- method @AddedInOrBefore UserIdentificationAssociationResponse forFailure();
- method @AddedInOrBefore UserIdentificationAssociationResponse forFailure(String errorMessage);
- method @AddedInOrBefore UserIdentificationAssociationResponse forSuccess(int[] values);
- method @AddedInOrBefore UserIdentificationAssociationResponse forSuccess(int[] values, String errorMessage);
- method @AddedInOrBefore boolean isSuccess();
- method @AddedInOrBefore String getErrorMessage();
- method @AddedInOrBefore int[] getValues();
- method @AddedInOrBefore String toString();
- method @AddedInOrBefore void writeToParcel(android.os.Parcel dest, int flags);
- method @AddedInOrBefore int describeContents();
-class @hide UserSwitchResult package android.car.user
- field @AddedInOrBefore int STATUS_SUCCESSFUL = CommonResults.STATUS_SUCCESSFUL;
- field @AddedInOrBefore int STATUS_ANDROID_FAILURE = CommonResults.STATUS_ANDROID_FAILURE;
- field @AddedInOrBefore int STATUS_HAL_FAILURE = CommonResults.STATUS_HAL_FAILURE;
- field @AddedInOrBefore int STATUS_HAL_INTERNAL_FAILURE = CommonResults.STATUS_HAL_INTERNAL_FAILURE;
- field @AddedInOrBefore int STATUS_INVALID_REQUEST = CommonResults.STATUS_INVALID_REQUEST;
- field @AddedInOrBefore int STATUS_UX_RESTRICTION_FAILURE = CommonResults.STATUS_UX_RESTRICTION_FAILURE;
- field @AddedInOrBefore int STATUS_OK_USER_ALREADY_IN_FOREGROUND = CommonResults.LAST_COMMON_STATUS + 1;
- field @AddedInOrBefore int STATUS_TARGET_USER_ALREADY_BEING_SWITCHED_TO = CommonResults.LAST_COMMON_STATUS + 2;
- field @AddedInOrBefore int STATUS_TARGET_USER_ABANDONED_DUE_TO_A_NEW_REQUEST = CommonResults.LAST_COMMON_STATUS + 3;
- field @AddedInOrBefore int STATUS_NOT_SWITCHABLE = CommonResults.LAST_COMMON_STATUS + 4;
- field @AddedInOrBefore int STATUS_NOT_LOGGED_IN = CommonResults.LAST_COMMON_STATUS + 5;
- field @AddedInOrBefore Parcelable.Creator<UserSwitchResult> CREATOR;
- method @AddedInOrBefore boolean isSuccess();
- method @AddedInOrBefore int describeContents();
- method @hide @AddedInOrBefore String statusToString(int value);
- method @AddedInOrBefore int getStatus();
- method @hide @AddedInOrBefore Integer getAndroidFailureStatus();
- method @AddedInOrBefore String getErrorMessage();
- method @AddedInOrBefore String toString();
- method @AddedInOrBefore void writeToParcel(android.os.Parcel dest, int flags);
-class @hide VehicleLightState package android.car
- field @AddedInOrBefore int OFF = 0;
- field @AddedInOrBefore int ON = 1;
- field @AddedInOrBefore int DAYTIME_RUNNING = 2;
-class @hide CarLibLog package android.car
- field @AddedInOrBefore String TAG_CAR = "CAR.L";
- field @AddedInOrBefore String TAG_CLUSTER = TAG_CAR + ".CLUSTER";
- field @AddedInOrBefore String TAG_INPUT = TAG_CAR + ".INPUT";
- field @AddedInOrBefore String TAG_NAV = TAG_CAR + ".NAV";
- field @AddedInOrBefore String TAG_SENSOR = TAG_CAR + ".SENSOR";
- field @AddedInOrBefore String TAG_DIAGNOSTIC = TAG_CAR + ".DIAGNOSTIC";
-class @hide VehicleHvacFanDirection package android.car
- field @AddedInOrBefore int FACE = 0x1;
- field @AddedInOrBefore int FLOOR = 0x2;
- field @AddedInOrBefore int DEFROST = 0x4;
-class @hide CarLocationTestHelper package android.car.test
- method @hide @AddedInOrBefore boolean injectLocation(Location location, Context context);
-class @hide CarTestManager package android.car.test
- method @hide @AddedInOrBefore void onCarDisconnected();
- method @hide @AddedInOrBefore void stopCarService(IBinder token);
- method @hide @AddedInOrBefore void startCarService(IBinder token);
-class VehicleAreaType package android.car
- field @AddedInOrBefore int VEHICLE_AREA_TYPE_GLOBAL = 0;
- field @AddedInOrBefore int VEHICLE_AREA_TYPE_WINDOW = 2;
- field @AddedInOrBefore int VEHICLE_AREA_TYPE_SEAT = 3;
- field @AddedInOrBefore int VEHICLE_AREA_TYPE_DOOR = 4;
- field @AddedInOrBefore int VEHICLE_AREA_TYPE_MIRROR = 5;
- field @AddedInOrBefore int VEHICLE_AREA_TYPE_WHEEL = 6;
-class @hide CarBugreportManager package android.car
- method @AddedInOrBefore void requestBugreport(ParcelFileDescriptor output, ParcelFileDescriptor extraOutput, CarBugreportManagerCallback callback);
- method @hide @AddedInOrBefore void requestBugreportForTesting(ParcelFileDescriptor output, ParcelFileDescriptor extraOutput, CarBugreportManagerCallback callback);
- method @AddedInOrBefore void cancelBugreport();
- method @AddedInOrBefore void onCarDisconnected();
-class CarBugreportManager.CarBugreportManagerCallback package android.car
- field @AddedInOrBefore int CAR_BUGREPORT_DUMPSTATE_FAILED = 1;
- field @AddedInOrBefore int CAR_BUGREPORT_IN_PROGRESS = 2;
- field @AddedInOrBefore int CAR_BUGREPORT_DUMPSTATE_CONNECTION_FAILED = 3;
- field @AddedInOrBefore int CAR_BUGREPORT_SERVICE_NOT_AVAILABLE = 4;
- method @AddedInOrBefore void onProgress(float progress);
- method @AddedInOrBefore void onError(int errorCode);
- method @AddedInOrBefore void onFinished();
-class CarInfoManager package android.car
- field @hide @AddedInOrBefore int BASIC_INFO_KEY_MANUFACTURER = 0x11100101;
- field @hide @AddedInOrBefore int BASIC_INFO_KEY_MODEL = 0x11100102;
- field @hide @AddedInOrBefore int BASIC_INFO_KEY_MODEL_YEAR = 0x11400103;
- field @hide @AddedInOrBefore String BASIC_INFO_KEY_VEHICLE_ID = "android.car.vehicle-id";
- field @hide @AddedInOrBefore String INFO_KEY_PRODUCT_CONFIGURATION = "android.car.product-config";
- field @hide @AddedInOrBefore int BASIC_INFO_DRIVER_SEAT = 0x1540010a;
- field @hide @AddedInOrBefore int BASIC_INFO_EV_PORT_LOCATION = 0x11400109;
- field @hide @AddedInOrBefore int BASIC_INFO_FUEL_DOOR_LOCATION = 0x11400108;
- field @hide @AddedInOrBefore int BASIC_INFO_FUEL_CAPACITY = 0x11600104;
- field @hide @AddedInOrBefore int BASIC_INFO_FUEL_TYPES = 0x11410105;
- field @hide @AddedInOrBefore int BASIC_INFO_EV_BATTERY_CAPACITY = 0x11600106;
- field @hide @AddedInOrBefore int BASIC_INFO_EV_CONNECTOR_TYPES = 0x11410107;
- method @AddedInOrBefore String getManufacturer();
- method @AddedInOrBefore String getModel();
- method @AddedInOrBefore String getModelYear();
- method @AddedInOrBefore int getModelYearInInteger();
- method @AddedInOrBefore String getVehicleId();
- method @AddedInOrBefore float getFuelCapacity();
- method @AddedInOrBefore int[] getFuelTypes();
- method @AddedInOrBefore float getEvBatteryCapacity();
- method @AddedInOrBefore int[] getEvConnectorTypes();
- method @AddedInOrBefore int getDriverSeat();
- method @AddedInOrBefore int getEvPortLocation();
- method @AddedInOrBefore int getFuelDoorLocation();
- method @hide @AddedInOrBefore void onCarDisconnected();
-class @hide @SystemApi CarSettings package android.car.settings
- field @hide @AddedInOrBefore int[] DEFAULT_GARAGE_MODE_WAKE_UP_TIME = { 0, 0 };
- field @hide @AddedInOrBefore int DEFAULT_GARAGE_MODE_MAINTENANCE_WINDOW = 10 * 60 * 1000;
-class @hide CarSettings.Global package android.car.settings
- field @hide @AddedInOrBefore String DEFAULT_USER_RESTRICTIONS_SET = "android.car.DEFAULT_USER_RESTRICTIONS_SET";
- field @hide @AddedInOrBefore String DISABLE_INSTRUMENTATION_SERVICE = "android.car.DISABLE_INSTRUMENTATION_SERVICE";
- field @hide @AddedInOrBefore String ENABLE_USER_SWITCH_DEVELOPER_MESSAGE = "android.car.ENABLE_USER_SWITCH_DEVELOPER_MESSAGE";
- field @hide @AddedInOrBefore String LAST_ACTIVE_USER_ID = "android.car.LAST_ACTIVE_USER_ID";
- field @hide @AddedInOrBefore String LAST_ACTIVE_PERSISTENT_USER_ID = "android.car.LAST_ACTIVE_PERSISTENT_USER_ID";
- field @hide @AddedInOrBefore String SYSTEM_BAR_VISIBILITY_OVERRIDE = "android.car.SYSTEM_BAR_VISIBILITY_OVERRIDE";
-class @hide @SystemApi CarSettings.Secure package android.car.settings
- field @hide @SystemApi @AddedInOrBefore String KEY_AUDIO_FOCUS_NAVIGATION_REJECTED_DURING_CALL = "android.car.KEY_AUDIO_FOCUS_NAVIGATION_REJECTED_DURING_CALL";
- field @hide @SystemApi @AddedInOrBefore String KEY_AUDIO_PERSIST_VOLUME_GROUP_MUTE_STATES = "android.car.KEY_AUDIO_PERSIST_VOLUME_GROUP_MUTE_STATES";
- field @hide @AddedInOrBefore String KEY_BLUETOOTH_DEVICES = "android.car.KEY_BLUETOOTH_DEVICES";
- field @hide @AddedInOrBefore String KEY_BLUETOOTH_PROFILES_INHIBITED = "android.car.BLUETOOTH_PROFILES_INHIBITED";
- field @hide @SystemApi @AddedInOrBefore String KEY_ROTARY_KEY_EVENT_FILTER = "android.car.ROTARY_KEY_EVENT_FILTER";
- field @hide @SystemApi @AddedInOrBefore String KEY_ENABLE_INITIAL_NOTICE_SCREEN_TO_USER = "android.car.ENABLE_INITIAL_NOTICE_SCREEN_TO_USER";
- field @hide @SystemApi @AddedInOrBefore String KEY_SETUP_WIZARD_IN_PROGRESS = "android.car.SETUP_WIZARD_IN_PROGRESS";
- field @hide @SystemApi @AddedInOrBefore String KEY_PACKAGES_DISABLED_ON_RESOURCE_OVERUSE = "android.car.KEY_PACKAGES_DISABLED_ON_RESOURCE_OVERUSE";
-class @hide @SystemApi AoapService package android.car
- field @AddedInOrBefore int RESULT_OK = 0;
- field @AddedInOrBefore int RESULT_DEVICE_NOT_SUPPORTED = 1;
- field @AddedInOrBefore int RESULT_DO_NOT_SWITCH_TO_AOAP = 2;
- field @hide @AddedInOrBefore int MSG_NEW_DEVICE_ATTACHED = 1;
- field @hide @AddedInOrBefore int MSG_NEW_DEVICE_ATTACHED_RESPONSE = 2;
- field @hide @AddedInOrBefore int MSG_CAN_SWITCH_TO_AOAP = 3;
- field @hide @AddedInOrBefore int MSG_CAN_SWITCH_TO_AOAP_RESPONSE = 4;
- field @hide @AddedInOrBefore String KEY_DEVICE = "usb-device";
- field @hide @AddedInOrBefore String KEY_RESULT = "result";
- method @AddedInOrBefore int isDeviceSupported(UsbDevice device);
- method @AddedInOrBefore int canSwitchToAoap(UsbDevice device);
- method @AddedInOrBefore void onCreate();
- method @AddedInOrBefore IBinder onBind(Intent intent);
- method @AddedInOrBefore boolean onUnbind(Intent intent);
- method @AddedInOrBefore void dump(FileDescriptor fd, PrintWriter writer, String[] args);
-class @hide @SystemApi VehiclePropertyAccess package android.car
- field @AddedInOrBefore int NONE = 0x00;
- field @AddedInOrBefore int READ = 0x01;
- field @AddedInOrBefore int WRITE = 0x02;
- field @AddedInOrBefore int READ_WRITE = 0x03;
-class VehicleIgnitionState package android.car
- field @AddedInOrBefore int UNDEFINED = 0;
- field @AddedInOrBefore int LOCK = 1;
- field @AddedInOrBefore int OFF = 2;
- field @AddedInOrBefore int ACC = 3;
- field @AddedInOrBefore int ON = 4;
- field @AddedInOrBefore int START = 5;
- method @AddedInOrBefore String toString(int ignitionState);
-class @hide @SystemApi CarProjectionManager package android.car
- field @AddedInOrBefore int PROJECTION_VOICE_SEARCH = 0x1;
- field @AddedInOrBefore int PROJECTION_LONG_PRESS_VOICE_SEARCH = 0x2;
- field @AddedInOrBefore int KEY_EVENT_VOICE_SEARCH_KEY_DOWN = 0;
- field @AddedInOrBefore int KEY_EVENT_VOICE_SEARCH_SHORT_PRESS_KEY_UP = 1;
- field @AddedInOrBefore int KEY_EVENT_VOICE_SEARCH_LONG_PRESS_KEY_DOWN = 2;
- field @AddedInOrBefore int KEY_EVENT_VOICE_SEARCH_LONG_PRESS_KEY_UP = 3;
- field @AddedInOrBefore int KEY_EVENT_CALL_KEY_DOWN = 4;
- field @AddedInOrBefore int KEY_EVENT_CALL_SHORT_PRESS_KEY_UP = 5;
- field @AddedInOrBefore int KEY_EVENT_CALL_LONG_PRESS_KEY_DOWN = 6;
- field @AddedInOrBefore int KEY_EVENT_CALL_LONG_PRESS_KEY_UP = 7;
- field @hide @AddedInOrBefore int NUM_KEY_EVENTS = 8;
- field @hide @AddedInOrBefore int PROJECTION_AP_STARTED = 0;
- field @hide @AddedInOrBefore int PROJECTION_AP_STOPPED = 1;
- field @hide @AddedInOrBefore int PROJECTION_AP_FAILED = 2;
- method @hide @AddedInOrBefore void regsiterProjectionListener(CarProjectionListener listener, int voiceSearchFilter);
- method @AddedInOrBefore void registerProjectionListener(CarProjectionListener listener, int voiceSearchFilter);
- method @hide @AddedInOrBefore void unregsiterProjectionListener();
- method @AddedInOrBefore void unregisterProjectionListener();
- method @AddedInOrBefore void addKeyEventHandler(Set<Integer> events, ProjectionKeyEventHandler eventHandler);
- method @AddedInOrBefore void addKeyEventHandler(Set<Integer> events, Executor executor, ProjectionKeyEventHandler eventHandler);
- method @AddedInOrBefore void removeKeyEventHandler(ProjectionKeyEventHandler eventHandler);
- method @AddedInOrBefore void registerProjectionRunner(Intent serviceIntent);
- method @AddedInOrBefore void unregisterProjectionRunner(Intent serviceIntent);
- method @hide @AddedInOrBefore void onCarDisconnected();
- method @AddedInOrBefore void startProjectionAccessPoint(ProjectionAccessPointCallback callback);
- method @AddedInOrBefore List<Integer> getAvailableWifiChannels(int band);
- method @AddedInOrBefore void stopProjectionAccessPoint();
- method @AddedInOrBefore boolean requestBluetoothProfileInhibit(BluetoothDevice device, int profile);
- method @AddedInOrBefore boolean releaseBluetoothProfileInhibit(BluetoothDevice device, int profile);
- method @AddedInOrBefore void updateProjectionStatus(ProjectionStatus status);
- method @AddedInOrBefore void registerProjectionStatusListener(ProjectionStatusListener listener);
- method @AddedInOrBefore void unregisterProjectionStatusListener(ProjectionStatusListener listener);
- method @AddedInOrBefore Bundle getProjectionOptions();
- method @AddedInOrBefore void resetProjectionAccessPointCredentials();
-interface CarProjectionManager.CarProjectionListener package android.car
- method @AddedInOrBefore void onVoiceAssistantRequest(boolean fromLongPress);
-interface CarProjectionManager.ProjectionKeyEventHandler package android.car
- method @AddedInOrBefore void onKeyEvent(int event);
-interface CarProjectionManager.ProjectionStatusListener package android.car
- method @AddedInOrBefore void onProjectionStatusChanged(int state, String packageName, List<ProjectionStatus> details);
-class CarProjectionManager.ProjectionAccessPointCallback package android.car
- field @AddedInOrBefore int ERROR_NO_CHANNEL = 1;
- field @AddedInOrBefore int ERROR_GENERIC = 2;
- field @AddedInOrBefore int ERROR_INCOMPATIBLE_MODE = 3;
- field @AddedInOrBefore int ERROR_TETHERING_DISALLOWED = 4;
- method @AddedInOrBefore void onStarted(WifiConfiguration wifiConfiguration);
- method @AddedInOrBefore void onStarted(SoftApConfiguration softApConfiguration);
- method @AddedInOrBefore void onStopped();
- method @AddedInOrBefore void onFailed(int reason);
-class @hide StartUserInBackgroundResult package android.car.admin
- field @AddedInOrBefore int STATUS_SUCCESS = 1;
- field @AddedInOrBefore int STATUS_SUCCESS_CURRENT_USER = 2;
- field @AddedInOrBefore int STATUS_FAILURE_USER_DOES_NOT_EXIST = 3;
- field @AddedInOrBefore int STATUS_FAILURE_GENERIC = 100;
- method @AddedInOrBefore int getStatus();
- method @AddedInOrBefore boolean isSuccess();
- method @AddedInOrBefore String toString();
-class @hide @SystemApi CarDevicePolicyManager package android.car.admin
- field @hide @AddedInOrBefore String TAG = CarDevicePolicyManager.class.getSimpleName();
- field @AddedInOrBefore int USER_TYPE_REGULAR = 0;
- field @AddedInOrBefore int USER_TYPE_ADMIN = 1;
- field @AddedInOrBefore int USER_TYPE_GUEST = 2;
- field @hide @AddedInOrBefore int FIRST_USER_TYPE = USER_TYPE_REGULAR;
- field @hide @AddedInOrBefore int LAST_USER_TYPE = USER_TYPE_GUEST;
- method @hide @SystemApi @AddedInOrBefore RemoveUserResult removeUser(UserHandle user);
- method @hide @SystemApi @AddedInOrBefore CreateUserResult createUser(String name, int type);
- method @hide @AddedInOrBefore StartUserInBackgroundResult startUserInBackground(UserHandle user);
- method @hide @AddedInOrBefore StopUserResult stopUser(UserHandle user);
- method @hide @AddedInOrBefore void setUserDisclaimerShown(UserHandle user);
- method @hide @AddedInOrBefore void setUserDisclaimerAcknowledged(UserHandle user);
- method @hide @AddedInOrBefore void onCarDisconnected();
-class @hide @SystemApi RemoveUserResult package android.car.admin
- field @AddedInOrBefore int STATUS_SUCCESS = 1;
- field @AddedInOrBefore int STATUS_SUCCESS_LAST_ADMIN_REMOVED = 2;
- field @AddedInOrBefore int STATUS_SUCCESS_SET_EPHEMERAL = 3;
- field @AddedInOrBefore int STATUS_FAILURE_USER_DOES_NOT_EXIST = 4;
- field @AddedInOrBefore int STATUS_FAILURE_INVALID_ARGUMENTS = 5;
- field @AddedInOrBefore int STATUS_SUCCESS_LAST_ADMIN_SET_EPHEMERAL = 6;
- field @AddedInOrBefore int STATUS_FAILURE_GENERIC = 100;
- method @AddedInOrBefore int getStatus();
- method @AddedInOrBefore boolean isSuccess();
- method @AddedInOrBefore String toString();
- method @hide @AddedInOrBefore String statusToString(int status);
-class @hide StopUserResult package android.car.admin
- field @AddedInOrBefore int STATUS_SUCCESS = 1;
- field @AddedInOrBefore int STATUS_FAILURE_CURRENT_USER = 2;
- field @AddedInOrBefore int STATUS_FAILURE_SYSTEM_USER = 3;
- field @AddedInOrBefore int STATUS_FAILURE_USER_DOES_NOT_EXIST = 4;
- field @AddedInOrBefore int STATUS_FAILURE_GENERIC = 100;
- method @AddedInOrBefore int getStatus();
- method @AddedInOrBefore boolean isSuccess();
- method @AddedInOrBefore String toString();
-class @hide @SystemApi CreateUserResult package android.car.admin
- field @AddedInOrBefore int STATUS_SUCCESS = 1;
- field @AddedInOrBefore int STATUS_FAILURE_INVALID_ARGUMENTS = 2;
- field @AddedInOrBefore int STATUS_FAILURE_GENERIC = 100;
- method @hide @AddedInOrBefore CreateUserResult forGenericError();
- method @AddedInOrBefore int getStatus();
- method @AddedInOrBefore boolean isSuccess();
- method @AddedInOrBefore UserHandle getUserHandle();
- method @AddedInOrBefore String toString();
-class CarNotConnectedException package android.car
-class @hide @SystemApi IoStatsEntry package android.car.storagemonitoring
- field @AddedInOrBefore Parcelable.Creator<IoStatsEntry> CREATOR;
- field @AddedInOrBefore int uid;
- field @AddedInOrBefore long runtimeMillis;
- field @AddedInOrBefore IoStatsEntry.Metrics foreground;
- field @AddedInOrBefore IoStatsEntry.Metrics background;
- method @AddedInOrBefore int describeContents();
- method @AddedInOrBefore void writeToParcel(Parcel dest, int flags);
- method @hide @AddedInOrBefore void writeToJson(JsonWriter jsonWriter);
- method @hide @AddedInOrBefore IoStatsEntry delta(IoStatsEntry other);
- method @AddedInOrBefore boolean equals(Object other);
- method @AddedInOrBefore int hashCode();
- method @AddedInOrBefore String toString();
- method @hide @AddedInOrBefore boolean representsSameMetrics(UidIoRecord record);
-class IoStatsEntry.Metrics package android.car.storagemonitoring
- field @AddedInOrBefore Parcelable.Creator<IoStatsEntry.Metrics> CREATOR;
- field @AddedInOrBefore long bytesRead;
- field @AddedInOrBefore long bytesWritten;
- field @AddedInOrBefore long bytesReadFromStorage;
- field @AddedInOrBefore long bytesWrittenToStorage;
- field @AddedInOrBefore long fsyncCalls;
- method @AddedInOrBefore int describeContents();
- method @AddedInOrBefore void writeToParcel(Parcel dest, int flags);
- method @hide @AddedInOrBefore void writeToJson(JsonWriter jsonWriter);
- method @hide @AddedInOrBefore Metrics delta(Metrics other);
- method @AddedInOrBefore boolean equals(Object other);
- method @AddedInOrBefore int hashCode();
- method @AddedInOrBefore String toString();
-class @hide @SystemApi IoStats package android.car.storagemonitoring
- field @AddedInOrBefore Creator<IoStats> CREATOR;
- method @AddedInOrBefore void writeToParcel(Parcel dest, int flags);
- method @hide @AddedInOrBefore void writeToJson(JsonWriter jsonWriter);
- method @AddedInOrBefore int describeContents();
- method @AddedInOrBefore long getTimestamp();
- method @AddedInOrBefore List<IoStatsEntry> getStats();
- method @AddedInOrBefore int hashCode();
- method @AddedInOrBefore IoStatsEntry getUserIdStats(int uid);
- method @AddedInOrBefore IoStatsEntry.Metrics getForegroundTotals();
- method @AddedInOrBefore IoStatsEntry.Metrics getBackgroundTotals();
- method @AddedInOrBefore IoStatsEntry.Metrics getTotals();
- method @AddedInOrBefore boolean equals(Object other);
- method @AddedInOrBefore String toString();
-class @hide @SystemApi LifetimeWriteInfo package android.car.storagemonitoring
- field @AddedInOrBefore Creator<IoStats> CREATOR;
- field @AddedInOrBefore String partition;
- field @AddedInOrBefore String fstype;
- field @AddedInOrBefore long writtenBytes;
- method @AddedInOrBefore void writeToParcel(Parcel dest, int flags);
- method @hide @AddedInOrBefore void writeToJson(JsonWriter jsonWriter);
- method @AddedInOrBefore int describeContents();
- method @AddedInOrBefore boolean equals(Object other);
- method @AddedInOrBefore String toString();
-class @hide @SystemApi CarStorageMonitoringManager package android.car.storagemonitoring
- field @AddedInOrBefore String INTENT_EXCESSIVE_IO = "android.car.storagemonitoring.EXCESSIVE_IO";
- field @AddedInOrBefore int PRE_EOL_INFO_UNKNOWN = 0;
- field @AddedInOrBefore int PRE_EOL_INFO_NORMAL = 1;
- field @AddedInOrBefore int PRE_EOL_INFO_WARNING = 2;
- field @AddedInOrBefore int PRE_EOL_INFO_URGENT = 3;
- field @AddedInOrBefore long SHUTDOWN_COST_INFO_MISSING = -1;
- method @hide @AddedInOrBefore void onCarDisconnected();
- method @AddedInOrBefore int getPreEolIndicatorStatus();
- method @AddedInOrBefore WearEstimate getWearEstimate();
- method @AddedInOrBefore List<WearEstimateChange> getWearEstimateHistory();
- method @AddedInOrBefore List<IoStatsEntry> getBootIoStats();
- method @AddedInOrBefore long getShutdownDiskWriteAmount();
- method @AddedInOrBefore List<IoStatsEntry> getAggregateIoStats();
- method @AddedInOrBefore List<IoStats> getIoStatsDeltas();
- method @AddedInOrBefore void registerListener(IoStatsListener listener);
- method @AddedInOrBefore void unregisterListener(IoStatsListener listener);
-interface CarStorageMonitoringManager.IoStatsListener package android.car.storagemonitoring
- method @AddedInOrBefore void onSnapshot(IoStats snapshot);
-class @hide @SystemApi UidIoRecord package android.car.storagemonitoring
- field @AddedInOrBefore int uid;
- field @AddedInOrBefore long foreground_rchar;
- field @AddedInOrBefore long foreground_wchar;
- field @AddedInOrBefore long foreground_read_bytes;
- field @AddedInOrBefore long foreground_write_bytes;
- field @AddedInOrBefore long foreground_fsync;
- field @AddedInOrBefore long background_rchar;
- field @AddedInOrBefore long background_wchar;
- field @AddedInOrBefore long background_read_bytes;
- field @AddedInOrBefore long background_write_bytes;
- field @AddedInOrBefore long background_fsync;
- method @hide @AddedInOrBefore UidIoRecord delta(IoStatsEntry other);
- method @hide @AddedInOrBefore UidIoRecord delta(UidIoRecord other);
-class @hide @SystemApi WearEstimateChange package android.car.storagemonitoring
- field @AddedInOrBefore Parcelable.Creator<WearEstimateChange> CREATOR;
- field @AddedInOrBefore WearEstimate oldEstimate;
- field @AddedInOrBefore WearEstimate newEstimate;
- field @AddedInOrBefore long uptimeAtChange;
- field @AddedInOrBefore Instant dateAtChange;
- field @AddedInOrBefore boolean isAcceptableDegradation;
- method @AddedInOrBefore int describeContents();
- method @AddedInOrBefore void writeToParcel(Parcel dest, int flags);
- method @AddedInOrBefore boolean equals(Object other);
- method @AddedInOrBefore int hashCode();
- method @AddedInOrBefore String toString();
-class @hide @SystemApi WearEstimate package android.car.storagemonitoring
- field @AddedInOrBefore int UNKNOWN = -1;
- field @hide @AddedInOrBefore WearEstimate UNKNOWN_ESTIMATE = new WearEstimate(UNKNOWN, UNKNOWN);
- field @AddedInOrBefore Parcelable.Creator<WearEstimate> CREATOR;
- field @AddedInOrBefore int typeA;
- field @AddedInOrBefore int typeB;
- method @AddedInOrBefore int describeContents();
- method @AddedInOrBefore void writeToParcel(Parcel dest, int flags);
- method @hide @AddedInOrBefore void writeToJson(JsonWriter jsonWriter);
- method @AddedInOrBefore boolean equals(Object other);
- method @AddedInOrBefore int hashCode();
- method @AddedInOrBefore String toString();
-class @hide CarManagerBase package android.car
- field @AddedInOrBefore Car mCar;
- method @AddedInOrBefore Context getContext();
- method @AddedInOrBefore Handler getEventHandler();
- method @AddedInOrBefore T handleRemoteExceptionFromCarService(RemoteException e, T returnValue);
- method @AddedInOrBefore void handleRemoteExceptionFromCarService(RemoteException e);
- method @AddedInOrBefore T handleExceptionFromCarService(Exception e, T returnValue);
- method @AddedInOrBefore void onCarDisconnected();
- method @AddedInOrBefore T addDumpable(Object container, Supplier<T> dumpableSupplier);
-class @hide @SystemApi VehicleAreaWindow package android.car
- field @AddedInOrBefore int WINDOW_FRONT_WINDSHIELD = 0x0001;
- field @AddedInOrBefore int WINDOW_REAR_WINDSHIELD = 0x0002;
- field @AddedInOrBefore int WINDOW_ROW_1_LEFT = 0x0010;
- field @AddedInOrBefore int WINDOW_ROW_1_RIGHT = 0x0040;
- field @AddedInOrBefore int WINDOW_ROW_2_LEFT = 0x0100;
- field @AddedInOrBefore int WINDOW_ROW_2_RIGHT = 0x0400;
- field @AddedInOrBefore int WINDOW_ROW_3_LEFT = 0x1000;
- field @AddedInOrBefore int WINDOW_ROW_3_RIGHT = 0x4000;
- field @AddedInOrBefore int WINDOW_ROOF_TOP_1 = 0x10000;
- field @AddedInOrBefore int WINDOW_ROOF_TOP_2 = 0x20000;
-class @hide @SystemApi CarNavigationInstrumentCluster package android.car.navigation
- field @AddedInOrBefore int CLUSTER_TYPE_CUSTOM_IMAGES_SUPPORTED = 1;
- field @AddedInOrBefore int CLUSTER_TYPE_IMAGE_CODES_ONLY = 2;
- field @AddedInOrBefore Parcelable.Creator<CarNavigationInstrumentCluster> CREATOR;
- method @AddedInOrBefore CarNavigationInstrumentCluster createCluster(int minIntervalMillis);
- method @AddedInOrBefore CarNavigationInstrumentCluster createCustomImageCluster(int minIntervalMillis, int imageWidth, int imageHeight, int imageColorDepthBits);
- method @AddedInOrBefore int getMinIntervalMillis();
- method @AddedInOrBefore int getType();
- method @AddedInOrBefore int getImageWidth();
- method @AddedInOrBefore int getImageHeight();
- method @hide @AddedInOrBefore Bundle getExtra();
- method @AddedInOrBefore int getImageColorDepthBits();
- method @AddedInOrBefore boolean supportsCustomImages();
- method @AddedInOrBefore int describeContents();
- method @AddedInOrBefore void writeToParcel(Parcel dest, int flags);
- method @AddedInOrBefore String toString();
-class @hide @SystemApi CarNavigationStatusManager package android.car.navigation
- method @AddedInOrBefore void sendEvent(int eventType, Bundle bundle);
- method @AddedInOrBefore void sendNavigationStateChange(Bundle bundle);
- method @hide @AddedInOrBefore void onCarDisconnected();
- method @AddedInOrBefore CarNavigationInstrumentCluster getInstrumentClusterInfo();
-class @hide @SystemApi VehicleAreaMirror package android.car
- field @AddedInOrBefore int MIRROR_DRIVER_LEFT = 0x00000001;
- field @AddedInOrBefore int MIRROR_DRIVER_RIGHT = 0x00000002;
- field @AddedInOrBefore int MIRROR_DRIVER_CENTER = 0x00000004;
-class @hide @SystemApi CustomInputEvent package android.car.input
- field @AddedInOrBefore int INPUT_CODE_F1 = 1001;
- field @AddedInOrBefore int INPUT_CODE_F2 = 1002;
- field @AddedInOrBefore int INPUT_CODE_F3 = 1003;
- field @AddedInOrBefore int INPUT_CODE_F4 = 1004;
- field @AddedInOrBefore int INPUT_CODE_F5 = 1005;
- field @AddedInOrBefore int INPUT_CODE_F6 = 1006;
- field @AddedInOrBefore int INPUT_CODE_F7 = 1007;
- field @AddedInOrBefore int INPUT_CODE_F8 = 1008;
- field @AddedInOrBefore int INPUT_CODE_F9 = 1009;
- field @AddedInOrBefore int INPUT_CODE_F10 = 1010;
- field @AddedInOrBefore Parcelable.Creator<CustomInputEvent> CREATOR;
- method @AddedInOrBefore String inputCodeToString(int value);
- method @AddedInOrBefore int getInputCode();
- method @AddedInOrBefore int getTargetDisplayType();
- method @AddedInOrBefore int getRepeatCounter();
- method @AddedInOrBefore String toString();
- method @AddedInOrBefore boolean equals(Object o);
- method @AddedInOrBefore int hashCode();
- method @AddedInOrBefore void writeToParcel(Parcel dest, int flags);
- method @AddedInOrBefore int describeContents();
-class @hide @SystemApi CarInputHandlingService package android.car.input
- field @AddedInOrBefore String INPUT_CALLBACK_BINDER_KEY = "callback_binder";
- field @AddedInOrBefore int INPUT_CALLBACK_BINDER_CODE = IBinder.FIRST_CALL_TRANSACTION;
- method @AddedInOrBefore IBinder onBind(Intent intent);
- method @AddedInOrBefore void onKeyEvent(KeyEvent keyEvent, int targetDisplay);
- method @AddedInOrBefore void dump(FileDescriptor fd, PrintWriter writer, String[] args);
-class CarInputHandlingService.InputFilter package android.car.input
- field @AddedInOrBefore int mKeyCode;
- field @AddedInOrBefore int mTargetDisplay;
- field @AddedInOrBefore Parcelable.Creator CREATOR;
- method @AddedInOrBefore int describeContents();
- method @AddedInOrBefore void writeToParcel(Parcel dest, int flags);
-class @hide @SystemApi RotaryEvent package android.car.input
- field @AddedInOrBefore Parcelable.Creator<RotaryEvent> CREATOR;
- method @AddedInOrBefore int getNumberOfClicks();
- method @AddedInOrBefore long getUptimeMillisForClick(int clickIndex);
- method @AddedInOrBefore String toString();
- method @AddedInOrBefore int getInputType();
- method @AddedInOrBefore boolean isClockwise();
- method @AddedInOrBefore long[] getUptimeMillisForClicks();
- method @AddedInOrBefore boolean equals(Object o);
- method @AddedInOrBefore int hashCode();
- method @AddedInOrBefore void writeToParcel(Parcel dest, int flags);
- method @AddedInOrBefore int describeContents();
-class @hide @SystemApi CarInputManager package android.car.input
- field @AddedInOrBefore int CAPTURE_REQ_FLAGS_ALLOW_DELAYED_GRANT = 0x1;
- field @AddedInOrBefore int CAPTURE_REQ_FLAGS_TAKE_ALL_EVENTS_FOR_DISPLAY = 0x2;
- field @AddedInOrBefore int INPUT_TYPE_ALL_INPUTS = 1;
- field @AddedInOrBefore int INPUT_TYPE_ROTARY_NAVIGATION = 10;
- field @AddedInOrBefore int INPUT_TYPE_ROTARY_VOLUME = 11;
- field @AddedInOrBefore int INPUT_TYPE_DPAD_KEYS = 100;
- field @AddedInOrBefore int INPUT_TYPE_NAVIGATE_KEYS = 101;
- field @AddedInOrBefore int INPUT_TYPE_SYSTEM_NAVIGATE_KEYS = 102;
- field @AddedInOrBefore int INPUT_TYPE_CUSTOM_INPUT_EVENT = 200;
- field @AddedInOrBefore int INPUT_CAPTURE_RESPONSE_SUCCEEDED = 0;
- field @AddedInOrBefore int INPUT_CAPTURE_RESPONSE_FAILED = 1;
- field @AddedInOrBefore int INPUT_CAPTURE_RESPONSE_DELAYED = 2;
- method @AddedInOrBefore int requestInputEventCapture(int targetDisplayType, int[] inputTypes, int requestFlags, CarInputCaptureCallback callback);
- method @AddedInOrBefore int requestInputEventCapture(int targetDisplayType, int[] inputTypes, int requestFlags, Executor executor, CarInputCaptureCallback callback);
- method @AddedInOrBefore void releaseInputEventCapture(int targetDisplayType);
- method @AddedInOrBefore void injectKeyEvent(KeyEvent event, int targetDisplayType);
- method @hide @AddedInOrBefore void onCarDisconnected();
-interface CarInputManager.CarInputCaptureCallback package android.car.input
- method @AddedInOrBefore void onKeyEvents(int targetDisplayType, List<KeyEvent> keyEvents);
- method @AddedInOrBefore void onRotaryEvents(int targetDisplayType, List<RotaryEvent> events);
- method @AddedInOrBefore void onCaptureStateChanged(int targetDisplayType, int[] activeInputTypes);
- method @AddedInOrBefore void onCustomInputEvents(int targetDisplayType, List<CustomInputEvent> events);
-class @hide VehicleLightSwitch package android.car
- field @AddedInOrBefore int OFF = 0;
- field @AddedInOrBefore int ON = 1;
- field @AddedInOrBefore int DAYTIME_RUNNING = 2;
- field @AddedInOrBefore int AUTOMATIC = 0x100;
-class CarUxRestrictionsManager package android.car.drivingstate
- field @hide @AddedInOrBefore String UX_RESTRICTION_MODE_BASELINE = "baseline";
- method @hide @AddedInOrBefore void onCarDisconnected();
- method @AddedInOrBefore void registerListener(OnUxRestrictionsChangedListener listener);
- method @hide @AddedInOrBefore void registerListener(OnUxRestrictionsChangedListener listener, int displayId);
- method @AddedInOrBefore void unregisterListener();
- method @hide @AddedInOrBefore boolean saveUxRestrictionsConfigurationForNextBoot(List<CarUxRestrictionsConfiguration> configs);
- method @AddedInOrBefore CarUxRestrictions getCurrentCarUxRestrictions();
- method @hide @AddedInOrBefore CarUxRestrictions getCurrentCarUxRestrictions(int displayId);
- method @hide @AddedInOrBefore boolean setRestrictionMode(String mode);
- method @hide @AddedInOrBefore String getRestrictionMode();
- method @hide @AddedInOrBefore boolean saveUxRestrictionsConfigurationForNextBoot(CarUxRestrictionsConfiguration config);
- method @hide @AddedInOrBefore List<CarUxRestrictionsConfiguration> getStagedConfigs();
- method @hide @AddedInOrBefore List<CarUxRestrictionsConfiguration> getConfigs();
-interface CarUxRestrictionsManager.OnUxRestrictionsChangedListener package android.car.drivingstate
- method @AddedInOrBefore void onUxRestrictionsChanged(CarUxRestrictions restrictionInfo);
-class @hide @SystemApi CarDrivingStateManager package android.car.drivingstate
- method @hide @AddedInOrBefore void onCarDisconnected();
- method @hide @SystemApi @AddedInOrBefore void registerListener(CarDrivingStateEventListener listener);
- method @hide @SystemApi @AddedInOrBefore void unregisterListener();
- method @hide @SystemApi @AddedInOrBefore CarDrivingStateEvent getCurrentCarDrivingState();
- method @hide @AddedInOrBefore void injectDrivingState(int drivingState);
-interface @hide @SystemApi CarDrivingStateManager.CarDrivingStateEventListener package android.car.drivingstate
- method @AddedInOrBefore void onDrivingStateChanged(CarDrivingStateEvent event);
-class CarUxRestrictions package android.car.drivingstate
- field @AddedInOrBefore int UX_RESTRICTIONS_BASELINE = 0;
- field @AddedInOrBefore int UX_RESTRICTIONS_NO_DIALPAD = 1;
- field @AddedInOrBefore int UX_RESTRICTIONS_NO_FILTERING = 0x1 << 1;
- field @AddedInOrBefore int UX_RESTRICTIONS_LIMIT_STRING_LENGTH = 0x1 << 2;
- field @AddedInOrBefore int UX_RESTRICTIONS_NO_KEYBOARD = 0x1 << 3;
- field @AddedInOrBefore int UX_RESTRICTIONS_NO_VIDEO = 0x1 << 4;
- field @AddedInOrBefore int UX_RESTRICTIONS_LIMIT_CONTENT = 0x1 << 5;
- field @AddedInOrBefore int UX_RESTRICTIONS_NO_SETUP = 0x1 << 6;
- field @AddedInOrBefore int UX_RESTRICTIONS_NO_TEXT_MESSAGE = 0x1 << 7;
- field @AddedInOrBefore int UX_RESTRICTIONS_NO_VOICE_TRANSCRIPTION = 0x1 << 8;
- field @AddedInOrBefore int UX_RESTRICTIONS_FULLY_RESTRICTED = UX_RESTRICTIONS_NO_DIALPAD | UX_RESTRICTIONS_NO_FILTERING | UX_RESTRICTIONS_LIMIT_STRING_LENGTH | UX_RESTRICTIONS_NO_KEYBOARD | UX_RESTRICTIONS_NO_VIDEO | UX_RESTRICTIONS_LIMIT_CONTENT | UX_RESTRICTIONS_NO_SETUP | UX_RESTRICTIONS_NO_TEXT_MESSAGE | UX_RESTRICTIONS_NO_VOICE_TRANSCRIPTION;
- field @AddedInOrBefore Parcelable.Creator<CarUxRestrictions> CREATOR;
- method @hide @AddedInOrBefore long getTimeStamp();
- method @AddedInOrBefore boolean isRequiresDistractionOptimization();
- method @AddedInOrBefore int getActiveRestrictions();
- method @AddedInOrBefore int getMaxRestrictedStringLength();
- method @AddedInOrBefore int getMaxCumulativeContentItems();
- method @AddedInOrBefore int getMaxContentDepth();
- method @AddedInOrBefore int describeContents();
- method @AddedInOrBefore void writeToParcel(Parcel dest, int flags);
- method @AddedInOrBefore String toString();
- method @AddedInOrBefore boolean isSameRestrictions(CarUxRestrictions other);
-class CarUxRestrictions.Builder package android.car.drivingstate
- method @AddedInOrBefore Builder setMaxStringLength(int length);
- method @AddedInOrBefore Builder setMaxCumulativeContentItems(int number);
- method @AddedInOrBefore Builder setMaxContentDepth(int depth);
- method @AddedInOrBefore CarUxRestrictions build();
-class @hide @SystemApi CarDrivingStateEvent package android.car.drivingstate
- field @AddedInOrBefore int DRIVING_STATE_UNKNOWN = -1;
- field @AddedInOrBefore int DRIVING_STATE_PARKED = 0;
- field @AddedInOrBefore int DRIVING_STATE_IDLING = 1;
- field @AddedInOrBefore int DRIVING_STATE_MOVING = 2;
- field @AddedInOrBefore long timeStamp;
- field @AddedInOrBefore int eventValue;
- field @AddedInOrBefore Parcelable.Creator<CarDrivingStateEvent> CREATOR;
- method @AddedInOrBefore int describeContents();
- method @AddedInOrBefore void writeToParcel(Parcel dest, int flags);
- method @AddedInOrBefore String toString();
-class @hide CarUxRestrictionsConfiguration package android.car.drivingstate
- field @AddedInOrBefore Parcelable.Creator<CarUxRestrictionsConfiguration> CREATOR;
- method @AddedInOrBefore CarUxRestrictions getUxRestrictions(int drivingState, float currentSpeed);
- method @AddedInOrBefore CarUxRestrictions getUxRestrictions(int drivingState, float currentSpeed, String mode);
- method @AddedInOrBefore Integer getPhysicalPort();
- method @AddedInOrBefore void writeJson(JsonWriter writer);
- method @AddedInOrBefore String toString();
- method @AddedInOrBefore CarUxRestrictionsConfiguration readJson(JsonReader reader, int schemaVersion);
- method @AddedInOrBefore int hashCode();
- method @AddedInOrBefore boolean equals(Object obj);
- method @AddedInOrBefore boolean hasSameParameters(CarUxRestrictionsConfiguration other);
- method @AddedInOrBefore void dump(PrintWriter writer);
- method @AddedInOrBefore int describeContents();
- method @AddedInOrBefore void writeToParcel(Parcel dest, int flags);
-class @hide CarUxRestrictionsConfiguration.Builder package android.car.drivingstate
- field @AddedInOrBefore Map<String,RestrictionModeContainer> mRestrictionModes = new ArrayMap<>();
- method @AddedInOrBefore int validatePort(int port);
- method @AddedInOrBefore Builder setPhysicalPort(int port);
- method @AddedInOrBefore Builder setUxRestrictions(int drivingState, boolean requiresOptimization, int restrictions);
- method @AddedInOrBefore Builder setUxRestrictions(int drivingState, SpeedRange speedRange, boolean requiresOptimization, int restrictions);
- method @AddedInOrBefore Builder setUxRestrictions(int drivingState, DrivingStateRestrictions drivingStateRestrictions);
- method @AddedInOrBefore Builder setMaxStringLength(int maxStringLength);
- method @AddedInOrBefore Builder setMaxCumulativeContentItems(int maxCumulativeContentItems);
- method @AddedInOrBefore Builder setMaxContentDepth(int maxContentDepth);
- method @AddedInOrBefore CarUxRestrictionsConfiguration build();
-class CarUxRestrictionsConfiguration.Builder.SpeedRange package android.car.drivingstate
- field @AddedInOrBefore float MAX_SPEED = Float.POSITIVE_INFINITY;
- method @AddedInOrBefore boolean includes(float speed);
- method @AddedInOrBefore int compareTo(SpeedRange other);
- method @AddedInOrBefore int hashCode();
- method @AddedInOrBefore boolean equals(Object obj);
- method @AddedInOrBefore String toString();
-class @hide CarUxRestrictionsConfiguration.DrivingStateRestrictions package android.car.drivingstate
- method @AddedInOrBefore DrivingStateRestrictions setDistractionOptimizationRequired(boolean distractionOptimizationRequired);
- method @AddedInOrBefore DrivingStateRestrictions setRestrictions(int restrictions);
- method @AddedInOrBefore DrivingStateRestrictions setMode(String mode);
- method @AddedInOrBefore DrivingStateRestrictions setSpeedRange(Builder.SpeedRange speedRange);
- method @AddedInOrBefore String toString();
-class @hide @SystemApi CarActivityManager package android.car.app
- field @AddedInOrBefore int RESULT_SUCCESS = 0;
- field @AddedInOrBefore int RESULT_FAILURE = -1;
- field @AddedInOrBefore int RESULT_INVALID_USER = -2;
- field @hide @AddedInOrBefore int ERROR_CODE_ACTIVITY_NOT_FOUND = -101;
- method @AddedInOrBefore int setPersistentActivity(ComponentName activity, int displayId, int featureId);
- method @hide @AddedInOrBefore void onCarDisconnected();
- method @hide @AddedInOrBefore boolean registerTaskMonitor();
- method @hide @AddedInOrBefore void onTaskAppeared(ActivityManager.RunningTaskInfo taskInfo);
- method @hide @AddedInOrBefore void onTaskVanished(ActivityManager.RunningTaskInfo taskInfo);
- method @hide @AddedInOrBefore void onTaskInfoChanged(ActivityManager.RunningTaskInfo taskInfo);
- method @hide @AddedInOrBefore void unregisterTaskMonitor();
-class @hide @SystemApi CarVendorExtensionManager package android.car.hardware
- method @AddedInOrBefore void registerCallback(CarVendorExtensionCallback callback);
- method @AddedInOrBefore void unregisterCallback(CarVendorExtensionCallback callback);
- method @AddedInOrBefore List<CarPropertyConfig> getProperties();
- method @AddedInOrBefore boolean isPropertyAvailable(int propertyId, int area);
- method @AddedInOrBefore E getGlobalProperty(Class<E> propertyClass, int propId);
- method @AddedInOrBefore E getProperty(Class<E> propertyClass, int propId, int area);
- method @AddedInOrBefore void setGlobalProperty(Class<E> propertyClass, int propId, E value);
- method @AddedInOrBefore void setProperty(Class<E> propertyClass, int propId, int area, E value);
- method @hide @AddedInOrBefore void onCarDisconnected();
-interface CarVendorExtensionManager.CarVendorExtensionCallback package android.car.hardware
- method @AddedInOrBefore void onChangeEvent(CarPropertyValue value);
- method @AddedInOrBefore void onErrorEvent(int propertyId, int zone);
-class CarPropertyConfig package android.car.hardware
- field @AddedInOrBefore int VEHICLE_PROPERTY_ACCESS_NONE = 0;
- field @AddedInOrBefore int VEHICLE_PROPERTY_ACCESS_READ = 1;
- field @AddedInOrBefore int VEHICLE_PROPERTY_ACCESS_WRITE = 2;
- field @AddedInOrBefore int VEHICLE_PROPERTY_ACCESS_READ_WRITE = 3;
- field @AddedInOrBefore int VEHICLE_PROPERTY_CHANGE_MODE_STATIC = 0;
- field @AddedInOrBefore int VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE = 1;
- field @AddedInOrBefore int VEHICLE_PROPERTY_CHANGE_MODE_CONTINUOUS = 2;
- field @AddedInOrBefore Creator<CarPropertyConfig> CREATOR;
- method @AddedInOrBefore int getAccess();
- method @AddedInOrBefore int getAreaType();
- method @AddedInOrBefore int getChangeMode();
- method @AddedInOrBefore List<Integer> getConfigArray();
- method @hide @AddedInOrBefore String getConfigString();
- method @AddedInOrBefore float getMaxSampleRate();
- method @AddedInOrBefore float getMinSampleRate();
- method @AddedInOrBefore int getPropertyId();
- method @AddedInOrBefore Class<T> getPropertyType();
- method @AddedInOrBefore boolean isGlobalProperty();
- method @hide @AddedInOrBefore int getAreaCount();
- method @AddedInOrBefore int[] getAreaIds();
- method @hide @AddedInOrBefore int getFirstAndOnlyAreaId();
- method @hide @AddedInOrBefore boolean hasArea(int areaId);
- method @AddedInOrBefore T getMinValue(int areaId);
- method @AddedInOrBefore T getMaxValue(int areaId);
- method @AddedInOrBefore T getMinValue();
- method @AddedInOrBefore T getMaxValue();
- method @AddedInOrBefore int describeContents();
- method @AddedInOrBefore void writeToParcel(Parcel dest, int flags);
- method @hide @AddedInOrBefore String toString();
- method @hide @SystemApi @AddedInOrBefore Builder<T> newBuilder(Class<T> type, int propertyId, int areaType, int areaCapacity);
- method @hide @AddedInOrBefore Builder<T> newBuilder(Class<T> type, int propertyId, int areaType);
-class @hide CarPropertyConfig.AreaConfig package android.car.hardware
- field @AddedInOrBefore Parcelable.Creator<AreaConfig<Object>> CREATOR;
- method @AddedInOrBefore T getMinValue();
- method @AddedInOrBefore T getMaxValue();
- method @AddedInOrBefore int describeContents();
- method @AddedInOrBefore void writeToParcel(Parcel dest, int flags);
- method @AddedInOrBefore String toString();
-class @hide @SystemApi CarPropertyConfig.Builder package android.car.hardware
- method @AddedInOrBefore Builder<T> addAreas(int[] areaIds);
- method @AddedInOrBefore Builder<T> addArea(int areaId);
- method @AddedInOrBefore Builder<T> addAreaConfig(int areaId, T min, T max);
- method @AddedInOrBefore Builder<T> setAccess(int access);
- method @AddedInOrBefore Builder<T> setChangeMode(int changeMode);
- method @AddedInOrBefore Builder<T> setConfigArray(ArrayList<Integer> configArray);
- method @AddedInOrBefore Builder<T> setConfigString(String configString);
- method @AddedInOrBefore Builder<T> setMaxSampleRate(float maxSampleRate);
- method @AddedInOrBefore Builder<T> setMinSampleRate(float minSampleRate);
- method @AddedInOrBefore CarPropertyConfig<T> build();
-class @SystemApi CarHvacFanDirection package android.car.hardware
- field @AddedInOrBefore int UNKNOWN = 0x0;
- field @AddedInOrBefore int FACE = 0x01;
- field @AddedInOrBefore int FLOOR = 0x02;
- field @AddedInOrBefore int FACE_AND_FLOOR = 0x03;
- field @AddedInOrBefore int DEFROST = 0x04;
- field @AddedInOrBefore int DEFROST_AND_FLOOR = 0x06;
-class CarPropertyValue package android.car.hardware
- field @AddedInOrBefore int STATUS_AVAILABLE = 0;
- field @AddedInOrBefore int STATUS_UNAVAILABLE = 1;
- field @AddedInOrBefore int STATUS_ERROR = 2;
- field @AddedInOrBefore Creator<CarPropertyValue> CREATOR;
- method @AddedInOrBefore int describeContents();
- method @AddedInOrBefore void writeToParcel(Parcel dest, int flags);
- method @AddedInOrBefore int getPropertyId();
- method @AddedInOrBefore int getAreaId();
- method @AddedInOrBefore int getStatus();
- method @AddedInOrBefore long getTimestamp();
- method @AddedInOrBefore T getValue();
- method @hide @AddedInOrBefore String toString();
-class @hide CarSensorConfig package android.car.hardware
- field @hide @AddedInOrBefore String WHEEL_TICK_DISTANCE_SUPPORTED_WHEELS = "android.car.wheelTickDistanceSupportedWheels";
- field @hide @AddedInOrBefore String WHEEL_TICK_DISTANCE_FRONT_LEFT_UM_PER_TICK = "android.car.wheelTickDistanceFrontLeftUmPerTick";
- field @hide @AddedInOrBefore String WHEEL_TICK_DISTANCE_FRONT_RIGHT_UM_PER_TICK = "android.car.wheelTickDistanceFrontRightUmPerTick";
- field @hide @AddedInOrBefore String WHEEL_TICK_DISTANCE_REAR_RIGHT_UM_PER_TICK = "android.car.wheelTickDistanceRearRightUmPerTick";
- field @hide @AddedInOrBefore String WHEEL_TICK_DISTANCE_REAR_LEFT_UM_PER_TICK = "android.car.wheelTickDistanceRearLeftUmPerTick";
- field @hide @AddedInOrBefore Parcelable.Creator<CarSensorConfig> CREATOR;
- method @hide @AddedInOrBefore int describeContents();
- method @hide @AddedInOrBefore void writeToParcel(Parcel dest, int flags);
- method @hide @AddedInOrBefore Bundle getBundle();
- method @hide @AddedInOrBefore int getInt(String key);
- method @hide @AddedInOrBefore int getType();
- method @hide @AddedInOrBefore String toString();
-class CarSensorEvent package android.car.hardware
- field @AddedInOrBefore int GEAR_NEUTRAL = 0x0001;
- field @AddedInOrBefore int GEAR_FIRST = 0x0010;
- field @AddedInOrBefore int GEAR_SECOND = 0x0020;
- field @AddedInOrBefore int GEAR_THIRD = 0x0040;
- field @AddedInOrBefore int GEAR_FOURTH = 0x0080;
- field @AddedInOrBefore int GEAR_FIFTH = 0x0100;
- field @AddedInOrBefore int GEAR_SIXTH = 0x0200;
- field @AddedInOrBefore int GEAR_SEVENTH = 0x0400;
- field @AddedInOrBefore int GEAR_EIGHTH = 0x0800;
- field @AddedInOrBefore int GEAR_NINTH = 0x1000;
- field @AddedInOrBefore int GEAR_TENTH = 0x2000;
- field @AddedInOrBefore int GEAR_DRIVE = 0x0008;
- field @AddedInOrBefore int GEAR_PARK = 0x0004;
- field @AddedInOrBefore int GEAR_REVERSE = 0x0002;
- field @AddedInOrBefore int IGNITION_STATE_UNDEFINED = 0;
- field @AddedInOrBefore int IGNITION_STATE_LOCK = 1;
- field @AddedInOrBefore int IGNITION_STATE_OFF = 2;
- field @AddedInOrBefore int IGNITION_STATE_ACC = 3;
- field @AddedInOrBefore int IGNITION_STATE_ON = 4;
- field @AddedInOrBefore int IGNITION_STATE_START = 5;
- field @AddedInOrBefore int INDEX_ENVIRONMENT_TEMPERATURE = 0;
- field @AddedInOrBefore int INDEX_WHEEL_DISTANCE_RESET_COUNT = 0;
- field @AddedInOrBefore int INDEX_WHEEL_DISTANCE_FRONT_LEFT = 1;
- field @AddedInOrBefore int INDEX_WHEEL_DISTANCE_FRONT_RIGHT = 2;
- field @AddedInOrBefore int INDEX_WHEEL_DISTANCE_REAR_RIGHT = 3;
- field @AddedInOrBefore int INDEX_WHEEL_DISTANCE_REAR_LEFT = 4;
- field @AddedInOrBefore int sensorType;
- field @AddedInOrBefore long timestamp;
- field @AddedInOrBefore float[] floatValues;
- field @AddedInOrBefore int[] intValues;
- field @AddedInOrBefore long[] longValues;
- field @AddedInOrBefore Parcelable.Creator<CarSensorEvent> CREATOR;
- method @AddedInOrBefore int describeContents();
- method @AddedInOrBefore void writeToParcel(Parcel dest, int flags);
- method @hide @AddedInOrBefore EnvironmentData getEnvironmentData(EnvironmentData data);
- method @hide @AddedInOrBefore IgnitionStateData getIgnitionStateData(IgnitionStateData data);
- method @hide @AddedInOrBefore NightData getNightData(NightData data);
- method @hide @AddedInOrBefore GearData getGearData(GearData data);
- method @hide @AddedInOrBefore ParkingBrakeData getParkingBrakeData(ParkingBrakeData data);
- method @hide @AddedInOrBefore FuelLevelData getFuelLevelData(FuelLevelData data);
- method @hide @AddedInOrBefore OdometerData getOdometerData(OdometerData data);
- method @hide @AddedInOrBefore RpmData getRpmData(RpmData data);
- method @hide @AddedInOrBefore CarSpeedData getCarSpeedData(CarSpeedData data);
- method @hide @AddedInOrBefore CarWheelTickDistanceData getCarWheelTickDistanceData(CarWheelTickDistanceData data);
- method @hide @AddedInOrBefore CarAbsActiveData getCarAbsActiveData(CarAbsActiveData data);
- method @hide @AddedInOrBefore CarTractionControlActiveData getCarTractionControlActiveData(CarTractionControlActiveData data);
- method @hide @AddedInOrBefore CarFuelDoorOpenData getCarFuelDoorOpenData(CarFuelDoorOpenData data);
- method @hide @AddedInOrBefore CarEvBatteryLevelData getCarEvBatteryLevelData(CarEvBatteryLevelData data);
- method @hide @AddedInOrBefore CarEvChargePortOpenData getCarEvChargePortOpenData(CarEvChargePortOpenData data);
- method @hide @AddedInOrBefore CarEvChargePortConnectedData getCarEvChargePortConnectedData(CarEvChargePortConnectedData data);
- method @hide @AddedInOrBefore CarEvBatteryChargeRateData getCarEvBatteryChargeRateData(CarEvBatteryChargeRateData data);
- method @hide @AddedInOrBefore CarEngineOilLevelData getCarEngineOilLevelData(CarEngineOilLevelData data);
- method @hide @AddedInOrBefore String toString();
-class CarSensorEvent.EnvironmentData package android.car.hardware
- field @AddedInOrBefore long timestamp;
- field @AddedInOrBefore float temperature;
-class @hide CarSensorEvent.IgnitionStateData package android.car.hardware
- field @AddedInOrBefore long timestamp;
- field @AddedInOrBefore int ignitionState;
-class @hide CarSensorEvent.NightData package android.car.hardware
- field @AddedInOrBefore long timestamp;
- field @AddedInOrBefore boolean isNightMode;
-class @hide CarSensorEvent.GearData package android.car.hardware
- field @AddedInOrBefore long timestamp;
- field @AddedInOrBefore int gear;
-class @hide CarSensorEvent.ParkingBrakeData package android.car.hardware
- field @AddedInOrBefore long timestamp;
- field @AddedInOrBefore boolean isEngaged;
-class @hide CarSensorEvent.FuelLevelData package android.car.hardware
- field @AddedInOrBefore long timestamp;
- field @AddedInOrBefore float level;
-class @hide CarSensorEvent.OdometerData package android.car.hardware
- field @AddedInOrBefore long timestamp;
- field @AddedInOrBefore float kms;
-class @hide CarSensorEvent.RpmData package android.car.hardware
- field @AddedInOrBefore long timestamp;
- field @AddedInOrBefore float rpm;
-class @hide CarSensorEvent.CarSpeedData package android.car.hardware
- field @AddedInOrBefore long timestamp;
- field @AddedInOrBefore float carSpeed;
-class @hide CarSensorEvent.CarWheelTickDistanceData package android.car.hardware
- field @AddedInOrBefore long timestamp;
- field @AddedInOrBefore long sensorResetCount;
- field @AddedInOrBefore long frontLeftWheelDistanceMm;
- field @AddedInOrBefore long frontRightWheelDistanceMm;
- field @AddedInOrBefore long rearRightWheelDistanceMm;
- field @AddedInOrBefore long rearLeftWheelDistanceMm;
-class @hide CarSensorEvent.CarAbsActiveData package android.car.hardware
- field @AddedInOrBefore long timestamp;
- field @AddedInOrBefore boolean absIsActive;
-class @hide CarSensorEvent.CarTractionControlActiveData package android.car.hardware
- field @AddedInOrBefore long timestamp;
- field @AddedInOrBefore boolean tractionControlIsActive;
-class @hide CarSensorEvent.CarFuelDoorOpenData package android.car.hardware
- field @AddedInOrBefore long timestamp;
- field @AddedInOrBefore boolean fuelDoorIsOpen;
-class @hide CarSensorEvent.CarEvBatteryLevelData package android.car.hardware
- field @AddedInOrBefore long timestamp;
- field @AddedInOrBefore float evBatteryLevel;
-class @hide CarSensorEvent.CarEvChargePortOpenData package android.car.hardware
- field @AddedInOrBefore long timestamp;
- field @AddedInOrBefore boolean evChargePortIsOpen;
-class @hide CarSensorEvent.CarEvChargePortConnectedData package android.car.hardware
- field @AddedInOrBefore long timestamp;
- field @AddedInOrBefore boolean evChargePortIsConnected;
-class @hide CarSensorEvent.CarEvBatteryChargeRateData package android.car.hardware
- field @AddedInOrBefore long timestamp;
- field @AddedInOrBefore float evChargeRate;
-class @hide CarSensorEvent.CarEngineOilLevelData package android.car.hardware
- field @AddedInOrBefore long timestamp;
- field @AddedInOrBefore int engineOilLevel;
-class CarSensorManager package android.car.hardware
- field @hide @AddedInOrBefore int SENSOR_TYPE_RESERVED1 = 1;
- field @AddedInOrBefore int SENSOR_TYPE_CAR_SPEED = 0x11600207;
- field @AddedInOrBefore int SENSOR_TYPE_RPM = 0x11600305;
- field @AddedInOrBefore int SENSOR_TYPE_ODOMETER = 0x11600204;
- field @AddedInOrBefore int SENSOR_TYPE_FUEL_LEVEL = 0x11600307;
- field @AddedInOrBefore int SENSOR_TYPE_PARKING_BRAKE = 0x11200402;
- field @AddedInOrBefore int SENSOR_TYPE_GEAR = 0x11400400;
- field @hide @AddedInOrBefore int SENSOR_TYPE_RESERVED8 = 8;
- field @AddedInOrBefore int SENSOR_TYPE_NIGHT = 0x11200407;
- field @AddedInOrBefore int SENSOR_TYPE_ENV_OUTSIDE_TEMPERATURE = 0x11600703;
- field @hide @AddedInOrBefore int SENSOR_TYPE_RESERVED10 = 10;
- field @hide @AddedInOrBefore int SENSOR_TYPE_RESERVED11 = 11;
- field @hide @AddedInOrBefore int SENSOR_TYPE_RESERVED12 = 12;
- field @hide @AddedInOrBefore int SENSOR_TYPE_RESERVED13 = 13;
- field @hide @AddedInOrBefore int SENSOR_TYPE_RESERVED14 = 14;
- field @hide @AddedInOrBefore int SENSOR_TYPE_RESERVED15 = 15;
- field @hide @AddedInOrBefore int SENSOR_TYPE_RESERVED16 = 16;
- field @hide @AddedInOrBefore int SENSOR_TYPE_RESERVED17 = 17;
- field @hide @AddedInOrBefore int SENSOR_TYPE_RESERVED18 = 18;
- field @hide @AddedInOrBefore int SENSOR_TYPE_RESERVED19 = 19;
- field @hide @AddedInOrBefore int SENSOR_TYPE_RESERVED20 = 20;
- field @hide @AddedInOrBefore int SENSOR_TYPE_RESERVED21 = 21;
- field @AddedInOrBefore int SENSOR_TYPE_IGNITION_STATE = 0x11400409;
- field @AddedInOrBefore int SENSOR_TYPE_WHEEL_TICK_DISTANCE = 0x11510306;
- field @AddedInOrBefore int SENSOR_TYPE_ABS_ACTIVE = 0x1120040a;
- field @AddedInOrBefore int SENSOR_TYPE_TRACTION_CONTROL_ACTIVE = 0x1120040b;
- field @hide @AddedInOrBefore int SENSOR_TYPE_RESERVED26 = 26;
- field @AddedInOrBefore int SENSOR_TYPE_FUEL_DOOR_OPEN = 0x11200308;
- field @AddedInOrBefore int SENSOR_TYPE_EV_BATTERY_LEVEL = 0x11600309;
- field @AddedInOrBefore int SENSOR_TYPE_EV_CHARGE_PORT_OPEN = 0x1120030a;
- field @AddedInOrBefore int SENSOR_TYPE_EV_CHARGE_PORT_CONNECTED = 0x1120030b;
- field @AddedInOrBefore int SENSOR_TYPE_EV_BATTERY_CHARGE_RATE = 0x1160030c;
- field @AddedInOrBefore int SENSOR_TYPE_ENGINE_OIL_LEVEL = 0x11400303;
- field @AddedInOrBefore int SENSOR_RATE_ONCHANGE = 0;
- field @AddedInOrBefore int SENSOR_RATE_NORMAL = 1;
- field @AddedInOrBefore int SENSOR_RATE_UI = 5;
- field @AddedInOrBefore int SENSOR_RATE_FAST = 10;
- field @AddedInOrBefore int SENSOR_RATE_FASTEST = 100;
- method @hide @AddedInOrBefore void onCarDisconnected();
- method @AddedInOrBefore int[] getSupportedSensors();
- method @AddedInOrBefore List<CarPropertyConfig> getPropertyList();
- method @AddedInOrBefore boolean isSensorSupported(int sensorType);
- method @hide @AddedInOrBefore boolean isSensorSupported(int[] sensorList, int sensorType);
- method @AddedInOrBefore boolean registerListener(OnSensorChangedListener listener, int sensorType, int rate);
- method @AddedInOrBefore void unregisterListener(OnSensorChangedListener listener);
- method @AddedInOrBefore void unregisterListener(OnSensorChangedListener listener, int sensorType);
- method @AddedInOrBefore CarSensorEvent getLatestSensorEvent(int type);
- method @hide @AddedInOrBefore CarSensorConfig getSensorConfig(int type);
-interface CarSensorManager.OnSensorChangedListener package android.car.hardware
- method @AddedInOrBefore void onSensorChanged(CarSensorEvent event);
-class @hide @SystemApi CarHvacManager package android.car.hardware.hvac
- field @AddedInOrBefore int ID_MIRROR_DEFROSTER_ON = 0x1440050c;
- field @AddedInOrBefore int ID_STEERING_WHEEL_HEAT = 0x1140050d;
- field @AddedInOrBefore int ID_OUTSIDE_AIR_TEMP = 0x11600703;
- field @AddedInOrBefore int ID_TEMPERATURE_DISPLAY_UNITS = 0x1140050e;
- field @AddedInOrBefore int ID_ZONED_TEMP_SETPOINT = 0x15600503;
- field @AddedInOrBefore int ID_ZONED_TEMP_ACTUAL = 0x15600502;
- field @AddedInOrBefore int ID_ZONED_HVAC_POWER_ON = 0x15200510;
- field @AddedInOrBefore int ID_ZONED_FAN_SPEED_SETPOINT = 0x15400500;
- field @AddedInOrBefore int ID_ZONED_FAN_SPEED_RPM = 0x1540050f;
- field @AddedInOrBefore int ID_ZONED_FAN_DIRECTION_AVAILABLE = 0x15410511;
- field @AddedInOrBefore int ID_ZONED_FAN_DIRECTION = 0x15400501;
- field @AddedInOrBefore int ID_ZONED_SEAT_TEMP = 0x1540050b;
- field @AddedInOrBefore int ID_ZONED_AC_ON = 0x15200505;
- field @AddedInOrBefore int ID_ZONED_AUTOMATIC_MODE_ON = 0x1520050A;
- field @AddedInOrBefore int ID_ZONED_AIR_RECIRCULATION_ON = 0x15200508;
- field @AddedInOrBefore int ID_ZONED_MAX_AC_ON = 0x15200506;
- field @AddedInOrBefore int ID_ZONED_DUAL_ZONE_ON = 0x15200509;
- field @AddedInOrBefore int ID_ZONED_MAX_DEFROST_ON = 0x15200507;
- field @AddedInOrBefore int ID_ZONED_HVAC_AUTO_RECIRC_ON = 0x15200512;
- field @AddedInOrBefore int ID_WINDOW_DEFROSTER_ON = 0x13200504;
- field @AddedInOrBefore int FAN_DIRECTION_FACE = 0x1;
- field @AddedInOrBefore int FAN_DIRECTION_FLOOR = 0x2;
- field @AddedInOrBefore int FAN_DIRECTION_DEFROST = 0x4;
- method @AddedInOrBefore void registerCallback(CarHvacEventCallback callback);
- method @AddedInOrBefore void unregisterCallback(CarHvacEventCallback callback);
- method @AddedInOrBefore List<CarPropertyConfig> getPropertyList();
- method @AddedInOrBefore boolean isPropertyAvailable(int propertyId, int area);
- method @AddedInOrBefore boolean getBooleanProperty(int propertyId, int area);
- method @AddedInOrBefore float getFloatProperty(int propertyId, int area);
- method @AddedInOrBefore int getIntProperty(int propertyId, int area);
- method @AddedInOrBefore void setBooleanProperty(int propertyId, int area, boolean val);
- method @AddedInOrBefore void setFloatProperty(int propertyId, int area, float val);
- method @AddedInOrBefore void setIntProperty(int propertyId, int area, int val);
- method @hide @AddedInOrBefore void onCarDisconnected();
-interface CarHvacManager.CarHvacEventCallback package android.car.hardware.hvac
- method @AddedInOrBefore void onChangeEvent(CarPropertyValue value);
- method @AddedInOrBefore void onErrorEvent(int propertyId, int zone);
-class @hide @SystemApi CarCabinManager package android.car.hardware.cabin
- field @AddedInOrBefore int ID_DOOR_POS = 0x16400b00;
- field @AddedInOrBefore int ID_DOOR_MOVE = 0x16400b01;
- field @AddedInOrBefore int ID_DOOR_LOCK = 0x16200b02;
- field @AddedInOrBefore int ID_MIRROR_Z_POS = 0x14400b40;
- field @AddedInOrBefore int ID_MIRROR_Z_MOVE = 0x14400b41;
- field @AddedInOrBefore int ID_MIRROR_Y_POS = 0x14400b42;
- field @AddedInOrBefore int ID_MIRROR_Y_MOVE = 0x14400b43;
- field @AddedInOrBefore int ID_MIRROR_LOCK = 0x11200b44;
- field @AddedInOrBefore int ID_MIRROR_FOLD = 0x11200b45;
- field @AddedInOrBefore int ID_SEAT_MEMORY_SELECT = 0x15400b80;
- field @AddedInOrBefore int ID_SEAT_MEMORY_SET = 0x15400b81;
- field @AddedInOrBefore int ID_SEAT_BELT_BUCKLED = 0x15200b82;
- field @AddedInOrBefore int ID_SEAT_BELT_HEIGHT_POS = 0x15400b83;
- field @AddedInOrBefore int ID_SEAT_BELT_HEIGHT_MOVE = 0x15400b84;
- field @AddedInOrBefore int ID_SEAT_FORE_AFT_POS = 0x15400b85;
- field @AddedInOrBefore int ID_SEAT_FORE_AFT_MOVE = 0x15400b86;
- field @AddedInOrBefore int ID_SEAT_BACKREST_ANGLE_1_POS = 0x15400b87;
- field @AddedInOrBefore int ID_SEAT_BACKREST_ANGLE_1_MOVE = 0x15400b88;
- field @AddedInOrBefore int ID_SEAT_BACKREST_ANGLE_2_POS = 0x15400b89;
- field @AddedInOrBefore int ID_SEAT_BACKREST_ANGLE_2_MOVE = 0x15400b8a;
- field @AddedInOrBefore int ID_SEAT_HEIGHT_POS = 0x15400b8b;
- field @AddedInOrBefore int ID_SEAT_HEIGHT_MOVE = 0x15400b8c;
- field @AddedInOrBefore int ID_SEAT_DEPTH_POS = 0x15400b8d;
- field @AddedInOrBefore int ID_SEAT_DEPTH_MOVE = 0x15400b8e;
- field @AddedInOrBefore int ID_SEAT_TILT_POS = 0x15400b8f;
- field @AddedInOrBefore int ID_SEAT_TILT_MOVE = 0x15400b90;
- field @AddedInOrBefore int ID_SEAT_LUMBAR_FORE_AFT_POS = 0x15400b91;
- field @AddedInOrBefore int ID_SEAT_LUMBAR_FORE_AFT_MOVE = 0x15400b92;
- field @AddedInOrBefore int ID_SEAT_LUMBAR_SIDE_SUPPORT_POS = 0x15400b93;
- field @AddedInOrBefore int ID_SEAT_LUMBAR_SIDE_SUPPORT_MOVE = 0x15400b94;
- field @AddedInOrBefore int ID_SEAT_HEADREST_HEIGHT_POS = 0x15400b95;
- field @AddedInOrBefore int ID_SEAT_HEADREST_HEIGHT_MOVE = 0x15400b96;
- field @AddedInOrBefore int ID_SEAT_HEADREST_ANGLE_POS = 0x15400b97;
- field @AddedInOrBefore int ID_SEAT_HEADREST_ANGLE_MOVE = 0x15400b98;
- field @AddedInOrBefore int ID_SEAT_HEADREST_FORE_AFT_POS = 0x15400b99;
- field @AddedInOrBefore int ID_SEAT_HEADREST_FORE_AFT_MOVE = 0x15400b9a;
- field @AddedInOrBefore int ID_WINDOW_POS = 0x13400bc0;
- field @AddedInOrBefore int ID_WINDOW_MOVE = 0x13400bc1;
- field @AddedInOrBefore int ID_WINDOW_LOCK = 0x13400bc4;
- method @AddedInOrBefore boolean isZonedProperty(int propertyId);
- method @AddedInOrBefore void registerCallback(CarCabinEventCallback callback);
- method @AddedInOrBefore void unregisterCallback(CarCabinEventCallback callback);
- method @AddedInOrBefore List<CarPropertyConfig> getPropertyList();
- method @AddedInOrBefore boolean getBooleanProperty(int propertyId, int area);
- method @AddedInOrBefore float getFloatProperty(int propertyId, int area);
- method @AddedInOrBefore int getIntProperty(int propertyId, int area);
- method @AddedInOrBefore void setBooleanProperty(int propertyId, int area, boolean val);
- method @AddedInOrBefore void setFloatProperty(int propertyId, int area, float val);
- method @AddedInOrBefore void setIntProperty(int propertyId, int area, int val);
- method @hide @AddedInOrBefore void onCarDisconnected();
-interface CarCabinManager.CarCabinEventCallback package android.car.hardware.cabin
- method @AddedInOrBefore void onChangeEvent(CarPropertyValue value);
- method @AddedInOrBefore void onErrorEvent(int propertyId, int zone);
-class PropertyAccessDeniedSecurityException package android.car.hardware.property
-class EvChargingConnectorType package android.car.hardware.property
- field @AddedInOrBefore int UNKNOWN = 0;
- field @AddedInOrBefore int IEC_TYPE_1_AC = 1;
- field @AddedInOrBefore int IEC_TYPE_2_AC = 2;
- field @AddedInOrBefore int IEC_TYPE_3_AC = 3;
- field @AddedInOrBefore int IEC_TYPE_4_DC = 4;
- field @AddedInOrBefore int IEC_TYPE_1_CCS_DC = 5;
- field @AddedInOrBefore int IEC_TYPE_2_CCS_DC = 6;
- field @AddedInOrBefore int TESLA_ROADSTER = 7;
- field @AddedInOrBefore int TESLA_HPWC = 8;
- field @AddedInOrBefore int TESLA_SUPERCHARGER = 9;
- field @AddedInOrBefore int GBT_AC = 10;
- field @AddedInOrBefore int GBT_DC = 11;
- field @AddedInOrBefore int OTHER = 101;
- method @AddedInOrBefore String toString(int connectorType);
-class PropertyNotAvailableException package android.car.hardware.property
-class @hide @SystemApi VehicleVendorPermission package android.car.hardware.property
- field @AddedInOrBefore String PERMISSION_GET_CAR_VENDOR_CATEGORY_WINDOW = "android.car.permission.GET_CAR_VENDOR_CATEGORY_WINDOW";
- field @AddedInOrBefore String PERMISSION_SET_CAR_VENDOR_CATEGORY_WINDOW = "android.car.permission.SET_CAR_VENDOR_CATEGORY_WINDOW";
- field @AddedInOrBefore String PERMISSION_GET_CAR_VENDOR_CATEGORY_DOOR = "android.car.permission.GET_CAR_VENDOR_CATEGORY_DOOR";
- field @AddedInOrBefore String PERMISSION_SET_CAR_VENDOR_CATEGORY_DOOR = "android.car.permission.SET_CAR_VENDOR_CATEGORY_DOOR";
- field @AddedInOrBefore String PERMISSION_GET_CAR_VENDOR_CATEGORY_SEAT = "android.car.permission.GET_CAR_VENDOR_CATEGORY_SEAT";
- field @AddedInOrBefore String PERMISSION_SET_CAR_VENDOR_CATEGORY_SEAT = "android.car.permission.SET_CAR_VENDOR_CATEGORY_SEAT";
- field @AddedInOrBefore String PERMISSION_GET_CAR_VENDOR_CATEGORY_MIRROR = "android.car.permission.GET_CAR_VENDOR_CATEGORY_MIRROR";
- field @AddedInOrBefore String PERMISSION_SET_CAR_VENDOR_CATEGORY_MIRROR = "android.car.permission.SET_CAR_VENDOR_CATEGORY_MIRROR";
- field @AddedInOrBefore String PERMISSION_GET_CAR_VENDOR_CATEGORY_INFO = "android.car.permission.GET_CAR_VENDOR_CATEGORY_INFO";
- field @AddedInOrBefore String PERMISSION_SET_CAR_VENDOR_CATEGORY_INFO = "android.car.permission.SET_CAR_VENDOR_CATEGORY_INFO";
- field @AddedInOrBefore String PERMISSION_GET_CAR_VENDOR_CATEGORY_ENGINE = "android.car.permission.GET_CAR_VENDOR_CATEGORY_ENGINE";
- field @AddedInOrBefore String PERMISSION_SET_CAR_VENDOR_CATEGORY_ENGINE = "android.car.permission.SET_CAR_VENDOR_CATEGORY_ENGINE";
- field @AddedInOrBefore String PERMISSION_GET_CAR_VENDOR_CATEGORY_HVAC = "android.car.permission.GET_CAR_VENDOR_CATEGORY_HVAC";
- field @AddedInOrBefore String PERMISSION_SET_CAR_VENDOR_CATEGORY_HVAC = "android.car.permission.SET_CAR_VENDOR_CATEGORY_HVAC";
- field @AddedInOrBefore String PERMISSION_GET_CAR_VENDOR_CATEGORY_LIGHT = "android.car.permission.GET_CAR_VENDOR_CATEGORY_LIGHT";
- field @AddedInOrBefore String PERMISSION_SET_CAR_VENDOR_CATEGORY_LIGHT = "android.car.permission.SET_CAR_VENDOR_CATEGORY_LIGHT";
- field @AddedInOrBefore String PERMISSION_GET_CAR_VENDOR_CATEGORY_1 = "android.car.permission.GET_CAR_VENDOR_CATEGORY_1";
- field @AddedInOrBefore String PERMISSION_SET_CAR_VENDOR_CATEGORY_1 = "android.car.permission.SET_CAR_VENDOR_CATEGORY_1";
- field @AddedInOrBefore String PERMISSION_GET_CAR_VENDOR_CATEGORY_2 = "android.car.permission.GET_CAR_VENDOR_CATEGORY_2";
- field @AddedInOrBefore String PERMISSION_SET_CAR_VENDOR_CATEGORY_2 = "android.car.permission.SET_CAR_VENDOR_CATEGORY_2";
- field @AddedInOrBefore String PERMISSION_GET_CAR_VENDOR_CATEGORY_3 = "android.car.permission.GET_CAR_VENDOR_CATEGORY_3";
- field @AddedInOrBefore String PERMISSION_SET_CAR_VENDOR_CATEGORY_3 = "android.car.permission.SET_CAR_VENDOR_CATEGORY_3";
- field @AddedInOrBefore String PERMISSION_GET_CAR_VENDOR_CATEGORY_4 = "android.car.permission.GET_CAR_VENDOR_CATEGORY_4";
- field @AddedInOrBefore String PERMISSION_SET_CAR_VENDOR_CATEGORY_4 = "android.car.permission.SET_CAR_VENDOR_CATEGORY_4";
- field @AddedInOrBefore String PERMISSION_GET_CAR_VENDOR_CATEGORY_5 = "android.car.permission.GET_CAR_VENDOR_CATEGORY_5";
- field @AddedInOrBefore String PERMISSION_SET_CAR_VENDOR_CATEGORY_5 = "android.car.permission.SET_CAR_VENDOR_CATEGORY_5";
- field @AddedInOrBefore String PERMISSION_GET_CAR_VENDOR_CATEGORY_6 = "android.car.permission.GET_CAR_VENDOR_CATEGORY_6";
- field @AddedInOrBefore String PERMISSION_SET_CAR_VENDOR_CATEGORY_6 = "android.car.permission.SET_CAR_VENDOR_CATEGORY_6";
- field @AddedInOrBefore String PERMISSION_GET_CAR_VENDOR_CATEGORY_7 = "android.car.permission.GET_CAR_VENDOR_CATEGORY_7";
- field @AddedInOrBefore String PERMISSION_SET_CAR_VENDOR_CATEGORY_7 = "android.car.permission.SET_CAR_VENDOR_CATEGORY_7";
- field @AddedInOrBefore String PERMISSION_GET_CAR_VENDOR_CATEGORY_8 = "android.car.permission.GET_CAR_VENDOR_CATEGORY_8";
- field @AddedInOrBefore String PERMISSION_SET_CAR_VENDOR_CATEGORY_8 = "android.car.permission.SET_CAR_VENDOR_CATEGORY_8";
- field @AddedInOrBefore String PERMISSION_GET_CAR_VENDOR_CATEGORY_9 = "android.car.permission.GET_CAR_VENDOR_CATEGORY_9";
- field @AddedInOrBefore String PERMISSION_SET_CAR_VENDOR_CATEGORY_9 = "android.car.permission.SET_CAR_VENDOR_CATEGORY_9";
- field @AddedInOrBefore String PERMISSION_GET_CAR_VENDOR_CATEGORY_10 = "android.car.permission.GET_CAR_VENDOR_CATEGORY_10";
- field @AddedInOrBefore String PERMISSION_SET_CAR_VENDOR_CATEGORY_10 = "android.car.permission.SET_CAR_VENDOR_CATEGORY_10";
-class VehicleElectronicTollCollectionCardStatus package android.car.hardware.property
- field @AddedInOrBefore int UNKNOWN = 0;
- field @AddedInOrBefore int ELECTRONIC_TOLL_COLLECTION_CARD_VALID = 1;
- field @AddedInOrBefore int ELECTRONIC_TOLL_COLLECTION_CARD_INVALID = 2;
- field @AddedInOrBefore int ELECTRONIC_TOLL_COLLECTION_CARD_NOT_INSERTED = 3;
-class @hide VehicleHalStatusCode package android.car.hardware.property
- field @AddedInOrBefore int STATUS_OK = 0;
- field @AddedInOrBefore int STATUS_TRY_AGAIN = 1;
- field @AddedInOrBefore int STATUS_INVALID_ARG = 2;
- field @AddedInOrBefore int STATUS_NOT_AVAILABLE = 3;
- field @AddedInOrBefore int STATUS_ACCESS_DENIED = 4;
- field @AddedInOrBefore int STATUS_INTERNAL_ERROR = 5;
-class PropertyNotAvailableAndRetryException package android.car.hardware.property
-class VehicleElectronicTollCollectionCardType package android.car.hardware.property
- field @AddedInOrBefore int UNKNOWN = 0;
- field @AddedInOrBefore int JP_ELECTRONIC_TOLL_COLLECTION_CARD = 1;
- field @AddedInOrBefore int JP_ELECTRONIC_TOLL_COLLECTION_CARD_V2 = 2;
-class CarInternalErrorException package android.car.hardware.property
-class @hide CarPropertyEvent package android.car.hardware.property
- field @AddedInOrBefore int PROPERTY_EVENT_PROPERTY_CHANGE = 0;
- field @AddedInOrBefore int PROPERTY_EVENT_ERROR = 1;
- field @AddedInOrBefore Parcelable.Creator<CarPropertyEvent> CREATOR;
- method @AddedInOrBefore int getEventType();
- method @AddedInOrBefore CarPropertyValue<?> getCarPropertyValue();
- method @AddedInOrBefore int describeContents();
- method @AddedInOrBefore void writeToParcel(Parcel dest, int flags);
- method @AddedInOrBefore CarPropertyEvent createErrorEventWithErrorCode(int propertyId, int areaId, int errorCode);
- method @AddedInOrBefore int getErrorCode();
- method @AddedInOrBefore String toString();
-class CarPropertyManager package android.car.hardware.property
- field @AddedInOrBefore float SENSOR_RATE_ONCHANGE = 0f;
- field @AddedInOrBefore float SENSOR_RATE_NORMAL = 1f;
- field @AddedInOrBefore float SENSOR_RATE_UI = 5f;
- field @AddedInOrBefore float SENSOR_RATE_FAST = 10f;
- field @AddedInOrBefore float SENSOR_RATE_FASTEST = 100f;
- field @AddedInOrBefore int CAR_SET_PROPERTY_ERROR_CODE_TRY_AGAIN = 1;
- field @AddedInOrBefore int CAR_SET_PROPERTY_ERROR_CODE_INVALID_ARG = 2;
- field @AddedInOrBefore int CAR_SET_PROPERTY_ERROR_CODE_PROPERTY_NOT_AVAILABLE = 3;
- field @AddedInOrBefore int CAR_SET_PROPERTY_ERROR_CODE_ACCESS_DENIED = 4;
- field @AddedInOrBefore int CAR_SET_PROPERTY_ERROR_CODE_UNKNOWN = 5;
- method @AddedInOrBefore boolean registerCallback(CarPropertyEventCallback callback, int propertyId, float rate);
- method @AddedInOrBefore void unregisterCallback(CarPropertyEventCallback callback);
- method @AddedInOrBefore void unregisterCallback(CarPropertyEventCallback callback, int propertyId);
- method @AddedInOrBefore List<CarPropertyConfig> getPropertyList();
- method @AddedInOrBefore List<CarPropertyConfig> getPropertyList(ArraySet<Integer> propertyIds);
- method @AddedInOrBefore CarPropertyConfig<?> getCarPropertyConfig(int propId);
- method @AddedInOrBefore int getAreaId(int propId, int area);
- method @hide @AddedInOrBefore String getReadPermission(int propId);
- method @hide @AddedInOrBefore String getWritePermission(int propId);
- method @AddedInOrBefore boolean isPropertyAvailable(int propId, int area);
- method @AddedInOrBefore boolean getBooleanProperty(int prop, int area);
- method @AddedInOrBefore float getFloatProperty(int prop, int area);
- method @AddedInOrBefore int getIntProperty(int prop, int area);
- method @AddedInOrBefore int[] getIntArrayProperty(int prop, int area);
- method @AddedInOrBefore CarPropertyValue<E> getProperty(Class<E> clazz, int propId, int areaId);
- method @AddedInOrBefore CarPropertyValue<E> getProperty(int propId, int areaId);
- method @AddedInOrBefore void setProperty(Class<E> clazz, int propId, int areaId, E val);
- method @AddedInOrBefore void setBooleanProperty(int prop, int areaId, boolean val);
- method @AddedInOrBefore void setFloatProperty(int prop, int areaId, float val);
- method @AddedInOrBefore void setIntProperty(int prop, int areaId, int val);
- method @hide @AddedInOrBefore void onCarDisconnected();
-interface CarPropertyManager.CarPropertyEventCallback package android.car.hardware.property
- method @AddedInOrBefore void onChangeEvent(CarPropertyValue value);
- method @AddedInOrBefore void onErrorEvent(int propId, int zone);
- method @AddedInOrBefore void onErrorEvent(int propId, int areaId, int errorCode);
-class CarPowerManager package android.car.hardware.power
- field @hide @AddedInOrBefore String TAG = CarPowerManager.class.getSimpleName();
- field @hide @SystemApi @AddedInOrBefore int STATE_INVALID = 0;
- field @hide @SystemApi @AddedInOrBefore int STATE_WAIT_FOR_VHAL = 1;
- field @hide @SystemApi @AddedInOrBefore int STATE_SUSPEND_ENTER = 2;
- field @hide @SystemApi @AddedInOrBefore int STATE_SUSPEND_EXIT = 3;
- field @hide @SystemApi @AddedInOrBefore int STATE_SHUTDOWN_ENTER = 5;
- field @hide @SystemApi @AddedInOrBefore int STATE_ON = 6;
- field @hide @SystemApi @AddedInOrBefore int STATE_SHUTDOWN_PREPARE = 7;
- field @hide @SystemApi @AddedInOrBefore int STATE_SHUTDOWN_CANCELLED = 8;
- field @hide @SystemApi @AddedInOrBefore int STATE_HIBERNATION_ENTER = 9;
- field @hide @SystemApi @AddedInOrBefore int STATE_HIBERNATION_EXIT = 10;
- field @hide @SystemApi @AddedInOrBefore int STATE_PRE_SHUTDOWN_PREPARE = 11;
- field @hide @SystemApi @AddedInOrBefore int STATE_POST_SUSPEND_ENTER = 12;
- field @hide @SystemApi @AddedInOrBefore int STATE_POST_SHUTDOWN_ENTER = 13;
- field @hide @SystemApi @AddedInOrBefore int STATE_POST_HIBERNATION_ENTER = 14;
- method @hide @AddedInOrBefore void requestShutdownOnNextSuspend();
- method @hide @AddedInOrBefore void scheduleNextWakeupTime(int seconds);
- method @hide @SystemApi @AddedInOrBefore int getPowerState();
- method @hide @SystemApi @AddedInOrBefore void setListener(Executor executor, CarPowerStateListener listener);
- method @hide @SystemApi @AddedInOrBefore void setListenerWithCompletion(Executor executor, CarPowerStateListenerWithCompletion listener);
- method @hide @SystemApi @AddedInOrBefore void clearListener();
- method @AddedInOrBefore CarPowerPolicy getCurrentPowerPolicy();
- method @hide @SystemApi @AddedInOrBefore void applyPowerPolicy(String policyId);
- method @hide @SystemApi @AddedInOrBefore void setPowerPolicyGroup(String policyGroupId);
- method @AddedInOrBefore void addPowerPolicyListener(Executor executor, CarPowerPolicyFilter filter, CarPowerPolicyListener listener);
- method @AddedInOrBefore void removePowerPolicyListener(CarPowerPolicyListener listener);
- method @hide @AddedInOrBefore boolean isCompletionAllowed(int state);
- method @hide @AddedInOrBefore void onCarDisconnected();
-interface @hide @SystemApi CarPowerManager.CompletablePowerStateChangeFuture package android.car.hardware.power
- method @AddedInOrBefore void complete();
- method @AddedInOrBefore long getExpirationTime();
-interface @hide @SystemApi CarPowerManager.CarPowerStateListener package android.car.hardware.power
- method @AddedInOrBefore void onStateChanged(int state);
-interface @hide @SystemApi CarPowerManager.CarPowerStateListenerWithCompletion package android.car.hardware.power
- method @AddedInOrBefore void onStateChanged(int state, CompletablePowerStateChangeFuture future);
-interface CarPowerManager.CarPowerPolicyListener package android.car.hardware.power
- method @AddedInOrBefore void onPolicyChanged(CarPowerPolicy policy);
-class @hide PowerComponentUtil package android.car.hardware.power
- field @AddedInOrBefore int COMPONENT_STATE_ENABLED = 1;
- field @AddedInOrBefore int COMPONENT_STATE_DISABLED = 2;
- field @AddedInOrBefore int COMPONENT_STATE_UNTOUCHED = 3;
- field @AddedInOrBefore int INVALID_POWER_COMPONENT = -1;
- field @AddedInOrBefore int FIRST_POWER_COMPONENT = PowerComponent.AUDIO;
- field @AddedInOrBefore int LAST_POWER_COMPONENT = PowerComponent.CPU;
- method @AddedInOrBefore boolean isValidPowerComponent(int component);
- method @AddedInOrBefore boolean hasComponents(CarPowerPolicy policy, CarPowerPolicyFilter filter);
- method @AddedInOrBefore int toPowerComponent(String component, boolean prefix);
- method @AddedInOrBefore String powerComponentToString(int component);
-class CarPowerPolicy package android.car.hardware.power
- field @AddedInOrBefore Parcelable.Creator<CarPowerPolicy> CREATOR;
- method @AddedInOrBefore boolean isComponentEnabled(int component);
- method @AddedInOrBefore String getPolicyId();
- method @AddedInOrBefore int[] getEnabledComponents();
- method @AddedInOrBefore int[] getDisabledComponents();
- method @AddedInOrBefore void writeToParcel(android.os.Parcel dest, int flags);
- method @AddedInOrBefore int describeContents();
-class CarPowerPolicyFilter package android.car.hardware.power
- field @AddedInOrBefore Parcelable.Creator<CarPowerPolicyFilter> CREATOR;
- method @AddedInOrBefore int[] getComponents();
- method @AddedInOrBefore void writeToParcel(android.os.Parcel dest, int flags);
- method @AddedInOrBefore int describeContents();
-class CarPowerPolicyFilter.Builder package android.car.hardware.power
- method @AddedInOrBefore Builder setComponents(int value);
- method @AddedInOrBefore CarPowerPolicyFilter build();
-class @hide CarFeatures package android.car
- field @hide @AddedInOrBefore String FEATURE_CAR_USER_NOTICE_SERVICE = "com.android.car.user.CarUserNoticeService";
- method @hide @AddedInOrBefore boolean isFeatureEnabled(ICar service, String featureName);
- method @hide @AddedInOrBefore void resetCache();
-class Car package android.car
- field @AddedInOrBefore int API_VERSION_MAJOR_INT = 32;
- field @AddedInOrBefore int API_VERSION_MINOR_INT = 0;
- field @hide @AddedInOrBefore int PLATFORM_VERSION_MINOR_INT = CarBuiltin.PLATFORM_VERSION_MINOR_INT;
- field @hide @AddedInOrBefore String CAR_SERVICE_BINDER_SERVICE_NAME = "car_service";
- field @AddedInOrBefore String META_DATA_DISTRACTION_OPTIMIZED = "distractionOptimized";
- field @AddedInOrBefore String META_DATA_REQUIRES_CAR_FEATURE = "requires-car-feature";
- field @AddedInOrBefore String SENSOR_SERVICE = "sensor";
- field @AddedInOrBefore String INFO_SERVICE = "info";
- field @AddedInOrBefore String APP_FOCUS_SERVICE = "app_focus";
- field @AddedInOrBefore String PACKAGE_SERVICE = "package";
- field @AddedInOrBefore String AUDIO_SERVICE = "audio";
- field @AddedInOrBefore String CAR_NAVIGATION_SERVICE = "car_navigation_service";
- field @AddedInOrBefore String CAR_OCCUPANT_ZONE_SERVICE = "car_occupant_zone_service";
- field @hide @SystemApi @AddedInOrBefore String CAR_USER_SERVICE = "car_user_service";
- field @hide @AddedInOrBefore String EXPERIMENTAL_CAR_USER_SERVICE = "experimental_car_user_service";
- field @hide @SystemApi @AddedInOrBefore String CAR_DEVICE_POLICY_SERVICE = "car_device_policy_service";
- field @hide @AddedInOrBefore String CAR_INSTRUMENT_CLUSTER_SERVICE = "cluster_service";
- field @hide @SystemApi @AddedInOrBefore String CABIN_SERVICE = "cabin";
- field @hide @SystemApi @AddedInOrBefore String DIAGNOSTIC_SERVICE = "diagnostic";
- field @hide @SystemApi @AddedInOrBefore String HVAC_SERVICE = "hvac";
- field @AddedInOrBefore String POWER_SERVICE = "power";
- field @hide @SystemApi @AddedInOrBefore String PROJECTION_SERVICE = "projection";
- field @AddedInOrBefore String PROPERTY_SERVICE = "property";
- field @hide @SystemApi @AddedInOrBefore String VENDOR_EXTENSION_SERVICE = "vendor_extension";
- field @hide @SystemApi @AddedInOrBefore String VEHICLE_MAP_SERVICE = "vehicle_map_service";
- field @hide @SystemApi @AddedInOrBefore String VMS_SUBSCRIBER_SERVICE = "vehicle_map_subscriber_service";
- field @hide @SystemApi @AddedInOrBefore String CAR_DRIVING_STATE_SERVICE = "drivingstate";
- field @AddedInOrBefore String CAR_UX_RESTRICTION_SERVICE = "uxrestriction";
- field @hide @SystemApi @AddedInOrBefore String OCCUPANT_AWARENESS_SERVICE = "occupant_awareness";
- field @hide @SystemApi @AddedInOrBefore String CAR_MEDIA_SERVICE = "car_media";
- field @hide @AddedInOrBefore String CAR_BUGREPORT_SERVICE = "car_bugreport";
- field @hide @SystemApi @AddedInOrBefore String STORAGE_MONITORING_SERVICE = "storage_monitoring";
- field @AddedInOrBefore String CAR_WATCHDOG_SERVICE = "car_watchdog";
- field @hide @AddedInOrBefore String CAR_PERFORMANCE_SERVICE = "car_performance";
- field @hide @SystemApi @AddedInOrBefore String CAR_INPUT_SERVICE = "android.car.input";
- field @hide @AddedInOrBefore String CLUSTER_HOME_SERVICE = "cluster_home_service";
- field @hide @SystemApi @AddedInOrBefore String TEST_SERVICE = "car-service-test";
- field @hide @SystemApi @AddedInOrBefore String CAR_EVS_SERVICE = "car_evs_service";
- field @hide @SystemApi @AddedInOrBefore String CAR_TELEMETRY_SERVICE = "car_telemetry_service";
- field @hide @SystemApi @AddedInOrBefore String CAR_ACTIVITY_SERVICE = "car_activity_service";
- field @hide @SystemApi @AddedInOrBefore String PERMISSION_MILEAGE = "android.car.permission.CAR_MILEAGE";
- field @AddedInOrBefore String PERMISSION_ENERGY = "android.car.permission.CAR_ENERGY";
- field @AddedInOrBefore String PERMISSION_CONTROL_CAR_ENERGY = "android.car.permission.CONTROL_CAR_ENERGY";
- field @hide @SystemApi @AddedInOrBefore String PERMISSION_ADJUST_RANGE_REMAINING = "android.car.permission.ADJUST_RANGE_REMAINING";
- field @AddedInOrBefore String PERMISSION_IDENTIFICATION = "android.car.permission.CAR_IDENTIFICATION";
- field @AddedInOrBefore String PERMISSION_SPEED = "android.car.permission.CAR_SPEED";
- field @hide @SystemApi @AddedInOrBefore String PERMISSION_CAR_DYNAMICS_STATE = "android.car.permission.CAR_DYNAMICS_STATE";
- field @AddedInOrBefore String PERMISSION_ENERGY_PORTS = "android.car.permission.CAR_ENERGY_PORTS";
- field @hide @SystemApi @AddedInOrBefore String PERMISSION_CONTROL_ENERGY_PORTS = "android.car.permission.CONTROL_CAR_ENERGY_PORTS";
- field @hide @SystemApi @AddedInOrBefore String PERMISSION_EXTERIOR_LIGHTS = "android.car.permission.CAR_EXTERIOR_LIGHTS";
- field @AddedInOrBefore String PERMISSION_READ_INTERIOR_LIGHTS = "android.car.permission.READ_CAR_INTERIOR_LIGHTS";
- field @hide @SystemApi @AddedInOrBefore String PERMISSION_CONTROL_EXTERIOR_LIGHTS = "android.car.permission.CONTROL_CAR_EXTERIOR_LIGHTS";
- field @AddedInOrBefore String PERMISSION_CONTROL_INTERIOR_LIGHTS = "android.car.permission.CONTROL_CAR_INTERIOR_LIGHTS";
- field @AddedInOrBefore String PERMISSION_POWERTRAIN = "android.car.permission.CAR_POWERTRAIN";
- field @AddedInOrBefore String PERMISSION_CAR_CONTROL_AUDIO_VOLUME = "android.car.permission.CAR_CONTROL_AUDIO_VOLUME";
- field @AddedInOrBefore String PERMISSION_CAR_CONTROL_AUDIO_SETTINGS = "android.car.permission.CAR_CONTROL_AUDIO_SETTINGS";
- field @hide @SystemApi @AddedInOrBefore String PERMISSION_RECEIVE_CAR_AUDIO_DUCKING_EVENTS = "android.car.permission.RECEIVE_CAR_AUDIO_DUCKING_EVENTS";
- field @AddedInOrBefore String PERMISSION_CAR_NAVIGATION_MANAGER = "android.car.permission.CAR_NAVIGATION_MANAGER";
- field @hide @SystemApi @AddedInOrBefore String PERMISSION_CAR_INSTRUMENT_CLUSTER_CONTROL = "android.car.permission.CAR_INSTRUMENT_CLUSTER_CONTROL";
- field @hide @AddedInOrBefore String PERMISSION_CAR_MONITOR_CLUSTER_NAVIGATION_STATE = "android.car.permission.CAR_MONITOR_CLUSTER_NAVIGATION_STATE";
- field @hide @AddedInOrBefore String PERMISSION_CAR_DISPLAY_IN_CLUSTER = "android.car.permission.CAR_DISPLAY_IN_CLUSTER";
- field @AddedInOrBefore String PERMISSION_CAR_INFO = "android.car.permission.CAR_INFO";
- field @AddedInOrBefore String PERMISSION_PRIVILEGED_CAR_INFO = "android.car.permission.PRIVILEGED_CAR_INFO";
- field @hide @SystemApi @AddedInOrBefore String PERMISSION_READ_CAR_VENDOR_PERMISSION_INFO = "android.car.permission.READ_CAR_VENDOR_PERMISSION_INFO";
- field @AddedInOrBefore String PERMISSION_EXTERIOR_ENVIRONMENT = "android.car.permission.CAR_EXTERIOR_ENVIRONMENT";
- field @hide @SystemApi @AddedInOrBefore String PERMISSION_VENDOR_EXTENSION = "android.car.permission.CAR_VENDOR_EXTENSION";
- field @hide @SystemApi @AddedInOrBefore String PERMISSION_CONTROL_APP_BLOCKING = "android.car.permission.CONTROL_APP_BLOCKING";
- field @hide @SystemApi @AddedInOrBefore String PERMISSION_CAR_ENGINE_DETAILED = "android.car.permission.CAR_ENGINE_DETAILED";
- field @hide @SystemApi @AddedInOrBefore String PERMISSION_TIRES = "android.car.permission.CAR_TIRES";
- field @hide @SystemApi @AddedInOrBefore String PERMISSION_CAR_EPOCH_TIME = "android.car.permission.CAR_EPOCH_TIME";
- field @hide @SystemApi @AddedInOrBefore String PERMISSION_STORAGE_ENCRYPTION_BINDING_SEED = "android.car.permission.STORAGE_ENCRYPTION_BINDING_SEED";
- field @AddedInOrBefore String PERMISSION_READ_STEERING_STATE = "android.car.permission.READ_CAR_STEERING";
- field @AddedInOrBefore String PERMISSION_READ_DISPLAY_UNITS = "android.car.permission.READ_CAR_DISPLAY_UNITS";
- field @AddedInOrBefore String PERMISSION_CONTROL_DISPLAY_UNITS = "android.car.permission.CONTROL_CAR_DISPLAY_UNITS";
- field @hide @SystemApi @AddedInOrBefore String PERMISSION_CONTROL_CAR_DOORS = "android.car.permission.CONTROL_CAR_DOORS";
- field @hide @SystemApi @AddedInOrBefore String PERMISSION_CONTROL_CAR_WINDOWS = "android.car.permission.CONTROL_CAR_WINDOWS";
- field @hide @SystemApi @AddedInOrBefore String PERMISSION_CONTROL_CAR_SEATS = "android.car.permission.CONTROL_CAR_SEATS";
- field @hide @SystemApi @AddedInOrBefore String PERMISSION_CONTROL_CAR_MIRRORS = "android.car.permission.CONTROL_CAR_MIRRORS";
- field @hide @SystemApi @AddedInOrBefore String PERMISSION_CONTROL_CAR_CLIMATE = "android.car.permission.CONTROL_CAR_CLIMATE";
- field @hide @SystemApi @AddedInOrBefore String PERMISSION_CAR_POWER = "android.car.permission.CAR_POWER";
- field @AddedInOrBefore String PERMISSION_READ_CAR_POWER_POLICY = "android.car.permission.READ_CAR_POWER_POLICY";
- field @hide @SystemApi @AddedInOrBefore String PERMISSION_CONTROL_CAR_POWER_POLICY = "android.car.permission.CONTROL_CAR_POWER_POLICY";
- field @hide @SystemApi @AddedInOrBefore String PERMISSION_CONTROL_SHUTDOWN_PROCESS = "android.car.permission.CONTROL_SHUTDOWN_PROCESS";
- field @hide @SystemApi @AddedInOrBefore String PERMISSION_CAR_PROJECTION = "android.car.permission.CAR_PROJECTION";
- field @hide @SystemApi @AddedInOrBefore String PERMISSION_CAR_PROJECTION_STATUS = "android.car.permission.ACCESS_CAR_PROJECTION_STATUS";
- field @hide @SystemApi @AddedInOrBefore String PERMISSION_MOCK_VEHICLE_HAL = "android.car.permission.CAR_MOCK_VEHICLE_HAL";
- field @hide @SystemApi @AddedInOrBefore String PERMISSION_CAR_TEST_SERVICE = "android.car.permission.CAR_TEST_SERVICE";
- field @hide @SystemApi @AddedInOrBefore String PERMISSION_CAR_DRIVING_STATE = "android.car.permission.CAR_DRIVING_STATE";
- field @hide @AddedInOrBefore String PERMISSION_BIND_VMS_CLIENT = "android.car.permission.BIND_VMS_CLIENT";
- field @hide @SystemApi @AddedInOrBefore String PERMISSION_VMS_PUBLISHER = "android.car.permission.VMS_PUBLISHER";
- field @hide @SystemApi @AddedInOrBefore String PERMISSION_VMS_SUBSCRIBER = "android.car.permission.VMS_SUBSCRIBER";
- field @hide @SystemApi @AddedInOrBefore String PERMISSION_CAR_DIAGNOSTIC_READ_ALL = "android.car.permission.CAR_DIAGNOSTICS";
- field @hide @SystemApi @AddedInOrBefore String PERMISSION_CAR_DIAGNOSTIC_CLEAR = "android.car.permission.CLEAR_CAR_DIAGNOSTICS";
- field @hide @AddedInOrBefore String PERMISSION_CAR_UX_RESTRICTIONS_CONFIGURATION = "android.car.permission.CAR_UX_RESTRICTIONS_CONFIGURATION";
- field @hide @SystemApi @AddedInOrBefore String PERMISSION_READ_CAR_OCCUPANT_AWARENESS_STATE = "android.car.permission.READ_CAR_OCCUPANT_AWARENESS_STATE";
- field @hide @SystemApi @AddedInOrBefore String ACCESS_PRIVATE_DISPLAY_ID = "android.car.permission.ACCESS_PRIVATE_DISPLAY_ID";
- field @hide @SystemApi @AddedInOrBefore String PERMISSION_CONTROL_CAR_OCCUPANT_AWARENESS_SYSTEM = "android.car.permission.CONTROL_CAR_OCCUPANT_AWARENESS_SYSTEM";
- field @hide @SystemApi @AddedInOrBefore String PERMISSION_STORAGE_MONITORING = "android.car.permission.STORAGE_MONITORING";
- field @hide @SystemApi @AddedInOrBefore String PERMISSION_CONTROL_CAR_FEATURES = "android.car.permission.CONTROL_CAR_FEATURES";
- field @hide @SystemApi @AddedInOrBefore String PERMISSION_USE_CAR_WATCHDOG = "android.car.permission.USE_CAR_WATCHDOG";
- field @hide @SystemApi @AddedInOrBefore String PERMISSION_CAR_MONITOR_INPUT = "android.car.permission.CAR_MONITOR_INPUT";
- field @hide @SystemApi @AddedInOrBefore String PERMISSION_REQUEST_CAR_EVS_ACTIVITY = "android.car.permission.REQUEST_CAR_EVS_ACTIVITY";
- field @hide @SystemApi @AddedInOrBefore String PERMISSION_CONTROL_CAR_EVS_ACTIVITY = "android.car.permission.CONTROL_CAR_EVS_ACTIVITY";
- field @hide @SystemApi @AddedInOrBefore String PERMISSION_USE_CAR_EVS_CAMERA = "android.car.permission.USE_CAR_EVS_CAMERA";
- field @hide @SystemApi @AddedInOrBefore String PERMISSION_MONITOR_CAR_EVS_STATUS = "android.car.permission.MONITOR_CAR_EVS_STATUS";
- field @hide @SystemApi @AddedInOrBefore String PERMISSION_USE_CAR_TELEMETRY_SERVICE = "android.car.permission.USE_CAR_TELEMETRY_SERVICE";
- field @AddedInOrBefore int CONNECTION_TYPE_EMBEDDED = 5;
- field @hide @SystemApi @AddedInOrBefore String PERMISSION_TEMPLATE_RENDERER = "android.car.permission.TEMPLATE_RENDERER";
- field @hide @SystemApi @AddedInOrBefore String PERMISSION_CONTROL_CAR_WATCHDOG_CONFIG = "android.car.permission.CONTROL_CAR_WATCHDOG_CONFIG";
- field @hide @SystemApi @AddedInOrBefore String PERMISSION_COLLECT_CAR_WATCHDOG_METRICS = "android.car.permission.COLLECT_CAR_WATCHDOG_METRICS";
- field @hide @AddedInOrBefore String PERMISSION_COLLECT_CAR_CPU_INFO = "android.car.permission.COLLECT_CAR_CPU_INFO";
- field @hide @SystemApi @AddedInOrBefore String PERMISSION_CONTROL_CAR_APP_LAUNCH = "android.car.permission.CONTROL_CAR_APP_LAUNCH";
- field @hide @AddedInOrBefore String CAR_TEMPLATE_HOST_RENDERER_SERVICE = "android.car.template.host.RendererService";
- field @AddedInOrBefore String CAR_INTENT_ACTION_MEDIA_TEMPLATE = "android.car.intent.action.MEDIA_TEMPLATE";
- field @AddedInOrBefore String CAR_EXTRA_MEDIA_COMPONENT = "android.car.intent.extra.MEDIA_COMPONENT";
- field @AddedInOrBefore String CAR_EXTRA_MEDIA_PACKAGE = "android.car.intent.extra.MEDIA_PACKAGE";
- field @AddedInOrBefore String CAR_EXTRA_BROWSE_SERVICE_FOR_SESSION = "android.media.session.BROWSE_SERVICE";
- field @hide @AddedInOrBefore String CAR_SERVICE_INTERFACE_NAME = CommonConstants.CAR_SERVICE_INTERFACE;
- field @hide @AddedInOrBefore String CAR_CATEGORY_NAVIGATION = "android.car.cluster.NAVIGATION";
- field @hide @SystemApi @AddedInOrBefore String CAR_EXTRA_CLUSTER_ACTIVITY_STATE = "android.car.cluster.ClusterActivityState";
- field @AddedInOrBefore long CAR_WAIT_TIMEOUT_WAIT_FOREVER = -1;
- field @AddedInOrBefore long CAR_WAIT_TIMEOUT_DO_NOT_WAIT = 0;
- field @hide @SystemApi @AddedInOrBefore int FEATURE_REQUEST_SUCCESS = 0;
- field @hide @SystemApi @AddedInOrBefore int FEATURE_REQUEST_ALREADY_IN_THE_STATE = 1;
- field @hide @SystemApi @AddedInOrBefore int FEATURE_REQUEST_MANDATORY = 2;
- field @hide @SystemApi @AddedInOrBefore int FEATURE_REQUEST_NOT_EXISTING = 3;
- method @AddedInOrBefore boolean isApiVersionAtLeast(int requiredApiVersionMajor);
- method @AddedInOrBefore boolean isApiVersionAtLeast(int requiredApiVersionMajor, int requiredApiVersionMinor);
- method @AddedInOrBefore boolean isApiAndPlatformVersionAtLeast(int requiredApiVersionMajor, int minPlatformSdkInt);
- method @AddedInOrBefore boolean isApiAndPlatformVersionAtLeast(int requiredApiVersionMajor, int requiredApiVersionMinor, int minPlatformSdkInt);
- method @AddedInOrBefore Car createCar(Context context, ServiceConnection serviceConnectionListener, Handler handler);
- method @AddedInOrBefore Car createCar(Context context, ServiceConnection serviceConnectionListener);
- method @AddedInOrBefore Car createCar(Context context);
- method @AddedInOrBefore Car createCar(Context context, Handler handler);
- method @AddedInOrBefore Car createCar(Context context, Handler handler, long waitTimeoutMs, CarServiceLifecycleListener statusChangeListener);
- method @AddedInOrBefore void connect();
- method @AddedInOrBefore void disconnect();
- method @AddedInOrBefore boolean isConnected();
- method @AddedInOrBefore boolean isConnecting();
- method @hide @AddedInOrBefore ServiceConnection getServiceConnectionListener();
- method @AddedInOrBefore Object getCarManager(String serviceName);
- method @AddedInOrBefore int getCarConnectionType();
- method @AddedInOrBefore boolean isFeatureEnabled(String featureName);
- method @hide @SystemApi @AddedInOrBefore int enableFeature(String featureName);
- method @hide @SystemApi @AddedInOrBefore int disableFeature(String featureName);
- method @hide @SystemApi @AddedInOrBefore List<String> getAllEnabledFeatures();
- method @hide @SystemApi @AddedInOrBefore List<String> getAllPendingDisabledFeatures();
- method @hide @SystemApi @AddedInOrBefore List<String> getAllPendingEnabledFeatures();
- method @hide @AddedInOrBefore Context getContext();
- method @hide @AddedInOrBefore Handler getEventHandler();
- method @hide @AddedInOrBefore T handleRemoteExceptionFromCarService(RemoteException e, T returnValue);
- method @hide @AddedInOrBefore void handleRemoteExceptionFromCarService(RemoteException e);
- method @hide @AddedInOrBefore T handleRemoteExceptionFromCarService(Service service, RemoteException e, T returnValue);
- method @hide @AddedInOrBefore void handleRemoteExceptionFromCarService(Service service, RemoteException e);
-interface Car.CarServiceLifecycleListener package android.car
- method @AddedInOrBefore void onLifecycleChanged(Car car, boolean ready);
-class @hide @SystemApi CarTelemetryManager package android.car.telemetry
- field @AddedInOrBefore int STATUS_ADD_METRICS_CONFIG_SUCCEEDED = 0;
- field @AddedInOrBefore int STATUS_ADD_METRICS_CONFIG_ALREADY_EXISTS = 1;
- field @AddedInOrBefore int STATUS_ADD_METRICS_CONFIG_VERSION_TOO_OLD = 2;
- field @AddedInOrBefore int STATUS_ADD_METRICS_CONFIG_PARSE_FAILED = 3;
- field @AddedInOrBefore int STATUS_ADD_METRICS_CONFIG_SIGNATURE_VERIFICATION_FAILED = 4;
- field @AddedInOrBefore int STATUS_ADD_METRICS_CONFIG_UNKNOWN = 5;
- field @AddedInOrBefore int STATUS_GET_METRICS_CONFIG_FINISHED = 0;
- field @AddedInOrBefore int STATUS_GET_METRICS_CONFIG_PENDING = 1;
- field @AddedInOrBefore int STATUS_GET_METRICS_CONFIG_INTERIM_RESULTS = 2;
- field @AddedInOrBefore int STATUS_GET_METRICS_CONFIG_RUNTIME_ERROR = 3;
- field @AddedInOrBefore int STATUS_GET_METRICS_CONFIG_DOES_NOT_EXIST = 4;
- method @hide @AddedInOrBefore void onCarDisconnected();
- method @hide @SystemApi @AddedInOrBefore void addMetricsConfig(String metricsConfigName, byte[] metricsConfig, Executor executor, AddMetricsConfigCallback callback);
- method @hide @SystemApi @AddedInOrBefore void removeMetricsConfig(String metricsConfigName);
- method @hide @SystemApi @AddedInOrBefore void removeAllMetricsConfigs();
- method @hide @SystemApi @AddedInOrBefore void getFinishedReport(String metricsConfigName, Executor executor, MetricsReportCallback callback);
- method @hide @SystemApi @AddedInOrBefore void getAllFinishedReports(Executor executor, MetricsReportCallback callback);
- method @hide @SystemApi @AddedInOrBefore void setReportReadyListener(Executor executor, ReportReadyListener listener);
- method @hide @SystemApi @AddedInOrBefore void clearReportReadyListener();
-interface @hide @SystemApi CarTelemetryManager.AddMetricsConfigCallback package android.car.telemetry
- method @AddedInOrBefore void onAddMetricsConfigStatus(String metricsConfigName, int statusCode);
-interface @hide @SystemApi CarTelemetryManager.MetricsReportCallback package android.car.telemetry
- method @AddedInOrBefore void onResult(String metricsConfigName, PersistableBundle report, byte[] telemetryError, int status);
-interface @hide @SystemApi CarTelemetryManager.ReportReadyListener package android.car.telemetry
- method @AddedInOrBefore void onReady(String metricsConfigName);
-class @hide ClusterActivityState package android.car.cluster
- method @AddedInOrBefore boolean isVisible();
- method @AddedInOrBefore Rect getUnobscuredBounds();
- method @AddedInOrBefore Bundle getExtras();
- method @AddedInOrBefore ClusterActivityState setVisible(boolean visible);
- method @AddedInOrBefore ClusterActivityState setUnobscuredBounds(Rect unobscuredBounds);
- method @AddedInOrBefore ClusterActivityState setExtras(Bundle bundle);
- method @AddedInOrBefore ClusterActivityState create(boolean visible, Rect unobscuredBounds);
- method @AddedInOrBefore ClusterActivityState fromBundle(Bundle bundle);
- method @AddedInOrBefore Bundle toBundle();
- method @AddedInOrBefore String toString();
-class @hide @SystemApi NavigationRenderer package android.car.cluster.renderer
- method @AddedInOrBefore CarNavigationInstrumentCluster getNavigationProperties();
- method @AddedInOrBefore void onEvent(int eventType, Bundle bundle);
- method @AddedInOrBefore void onNavigationStateChanged(Bundle bundle);
-class @hide @SystemApi InstrumentClusterRenderer package android.car.cluster.renderer
- method @AddedInOrBefore void onCreate(Context context);
- method @AddedInOrBefore void onStart();
- method @AddedInOrBefore void onStop();
- method @AddedInOrBefore NavigationRenderer createNavigationRenderer();
- method @AddedInOrBefore NavigationRenderer getNavigationRenderer();
- method @AddedInOrBefore void initialize();
-class @hide @SystemApi InstrumentClusterRenderingService package android.car.cluster.renderer
- field @hide @AddedInOrBefore String EXTRA_BUNDLE_KEY_FOR_INSTRUMENT_CLUSTER_HELPER = "android.car.cluster.renderer.IInstrumentClusterHelper";
- method @AddedInOrBefore IBinder onBind(Intent intent);
- method @AddedInOrBefore NavigationRenderer getNavigationRenderer();
- method @AddedInOrBefore void onKeyEvent(KeyEvent keyEvent);
- method @AddedInOrBefore void onNavigationComponentLaunched();
- method @AddedInOrBefore void onNavigationComponentReleased();
- method @AddedInOrBefore boolean startFixedActivityModeForDisplayAndUser(Intent intent, ActivityOptions options, int userId);
- method @AddedInOrBefore void stopFixedActivityMode(int displayId);
- method @hide @AddedInOrBefore ComponentName getComponentFromPackage(String packageName);
- method @AddedInOrBefore boolean startNavigationActivity(ComponentName component);
- method @hide @AddedInOrBefore void setClusterActivityLaunchOptions(String category, ActivityOptions activityOptions);
- method @hide @AddedInOrBefore void setClusterActivityLaunchOptions(ActivityOptions activityOptions);
- method @hide @AddedInOrBefore void setClusterActivityState(String category, Bundle state);
- method @hide @AddedInOrBefore void setClusterActivityState(ClusterActivityState state);
- method @AddedInOrBefore void dump(FileDescriptor fd, PrintWriter writer, String[] args);
- method @AddedInOrBefore Bitmap getBitmap(Uri uri);
- method @AddedInOrBefore Bitmap getBitmap(Uri uri, int width, int height);
- method @AddedInOrBefore Bitmap getBitmap(Uri uri, int width, int height, float offLanesAlpha);
-class @hide @SystemApi CarInstrumentClusterManager package android.car.cluster
- field @hide @SystemApi @AddedInOrBefore String CATEGORY_NAVIGATION = "android.car.cluster.NAVIGATION";
- field @hide @SystemApi @AddedInOrBefore String KEY_EXTRA_ACTIVITY_STATE = "android.car.cluster.ClusterActivityState";
- method @hide @SystemApi @AddedInOrBefore void startActivity(Intent intent);
- method @hide @SystemApi @AddedInOrBefore void registerCallback(String category, Callback callback);
- method @hide @SystemApi @AddedInOrBefore void unregisterCallback(Callback callback);
- method @hide @AddedInOrBefore void onCarDisconnected();
-interface @hide @SystemApi CarInstrumentClusterManager.Callback package android.car.cluster
- method @AddedInOrBefore void onClusterActivityStateChanged(String category, Bundle clusterActivityState);
-class @hide ClusterHomeManager package android.car.cluster
- field @AddedInOrBefore int UI_TYPE_CLUSTER_NONE = -1;
- field @AddedInOrBefore int UI_TYPE_CLUSTER_HOME = 0;
- field @AddedInOrBefore int CONFIG_DISPLAY_ON_OFF = 0x01;
- field @AddedInOrBefore int CONFIG_DISPLAY_BOUNDS = 0x02;
- field @AddedInOrBefore int CONFIG_DISPLAY_INSETS = 0x04;
- field @AddedInOrBefore int CONFIG_UI_TYPE = 0x08;
- field @AddedInOrBefore int CONFIG_DISPLAY_ID = 0x10;
- method @AddedInOrBefore void registerClusterStateListener(Executor executor, ClusterStateListener callback);
- method @AddedInOrBefore void registerClusterNavigationStateListener(Executor executor, ClusterNavigationStateListener callback);
- method @AddedInOrBefore void unregisterClusterStateListener(ClusterStateListener callback);
- method @AddedInOrBefore void unregisterClusterNavigationStateListener(ClusterNavigationStateListener callback);
- method @AddedInOrBefore void reportState(int uiTypeMain, int uiTypeSub, byte[] uiAvailability);
- method @AddedInOrBefore void requestDisplay(int uiType);
- method @AddedInOrBefore ClusterState getClusterState();
- method @AddedInOrBefore boolean startFixedActivityModeAsUser(Intent intent, Bundle options, int userId);
- method @AddedInOrBefore void stopFixedActivityMode();
- method @AddedInOrBefore void onCarDisconnected();
-interface ClusterHomeManager.ClusterStateListener package android.car.cluster
- method @AddedInOrBefore void onClusterStateChanged(ClusterState state, int changes);
-interface ClusterHomeManager.ClusterNavigationStateListener package android.car.cluster
- method @AddedInOrBefore void onNavigationState(byte[] navigationState);
-class PortLocationType package android.car
- field @AddedInOrBefore int UNKNOWN = 0;
- field @AddedInOrBefore int FRONT_LEFT = 1;
- field @AddedInOrBefore int FRONT_RIGHT = 2;
- field @AddedInOrBefore int REAR_RIGHT = 3;
- field @AddedInOrBefore int REAR_LEFT = 4;
- field @AddedInOrBefore int FRONT = 5;
- field @AddedInOrBefore int REAR = 6;
-class FuelType package android.car
- field @AddedInOrBefore int UNKNOWN = 0;
- field @AddedInOrBefore int UNLEADED = 1;
- field @AddedInOrBefore int LEADED = 2;
- field @AddedInOrBefore int DIESEL_1 = 3;
- field @AddedInOrBefore int DIESEL_2 = 4;
- field @AddedInOrBefore int BIODIESEL = 5;
- field @AddedInOrBefore int E85 = 6;
- field @AddedInOrBefore int LPG = 7;
- field @AddedInOrBefore int CNG = 8;
- field @AddedInOrBefore int LNG = 9;
- field @AddedInOrBefore int ELECTRIC = 10;
- field @AddedInOrBefore int HYDROGEN = 11;
- field @AddedInOrBefore int OTHER = 12;
-class @hide @SystemApi VmsLayer package android.car.vms
- field @AddedInOrBefore Parcelable.Creator<VmsLayer> CREATOR;
- method @AddedInOrBefore int getSubtype();
- method @AddedInOrBefore int getType();
- method @AddedInOrBefore int getChannel();
- method @AddedInOrBefore int getVersion();
- method @AddedInOrBefore String toString();
- method @AddedInOrBefore boolean equals(Object o);
- method @AddedInOrBefore int hashCode();
- method @AddedInOrBefore void writeToParcel(Parcel dest, int flags);
- method @AddedInOrBefore int describeContents();
-class @hide @SystemApi VmsOperationRecorder package android.car.vms
- method @AddedInOrBefore VmsOperationRecorder get();
- method @AddedInOrBefore void subscribe(VmsLayer layer);
- method @AddedInOrBefore void unsubscribe(VmsLayer layer);
- method @AddedInOrBefore void subscribe(VmsLayer layer, int publisherId);
- method @AddedInOrBefore void unsubscribe(VmsLayer layer, int publisherId);
- method @AddedInOrBefore void startMonitoring();
- method @AddedInOrBefore void stopMonitoring();
- method @AddedInOrBefore void setLayersOffering(VmsLayersOffering layersOffering);
- method @AddedInOrBefore void getPublisherId(int publisherId);
- method @AddedInOrBefore void addSubscription(int sequenceNumber, VmsLayer layer);
- method @AddedInOrBefore void removeSubscription(int sequenceNumber, VmsLayer layer);
- method @AddedInOrBefore void addPromiscuousSubscription(int sequenceNumber);
- method @AddedInOrBefore void removePromiscuousSubscription(int sequenceNumber);
- method @AddedInOrBefore void addHalSubscription(int sequenceNumber, VmsLayer layer);
- method @AddedInOrBefore void removeHalSubscription(int sequenceNumber, VmsLayer layer);
- method @AddedInOrBefore void setPublisherLayersOffering(VmsLayersOffering layersOffering);
- method @AddedInOrBefore void setHalPublisherLayersOffering(VmsLayersOffering layersOffering);
-class @hide VmsOperationRecorder.Writer package android.car.vms
- method @AddedInOrBefore boolean isEnabled();
- method @AddedInOrBefore void write(String msg);
-class @hide @SystemApi VmsAvailableLayers package android.car.vms
- field @AddedInOrBefore Parcelable.Creator<VmsAvailableLayers> CREATOR;
- method @AddedInOrBefore int getSequence();
- method @AddedInOrBefore int getSequenceNumber();
- method @AddedInOrBefore Set<VmsAssociatedLayer> getAssociatedLayers();
- method @AddedInOrBefore String toString();
- method @AddedInOrBefore boolean equals(Object o);
- method @AddedInOrBefore int hashCode();
- method @AddedInOrBefore void writeToParcel(Parcel dest, int flags);
- method @AddedInOrBefore int describeContents();
-class @hide VmsSubscriptionHelper package android.car.vms
- method @AddedInOrBefore void subscribe(VmsLayer layer);
- method @AddedInOrBefore void subscribe(VmsLayer layer, int providerId);
- method @AddedInOrBefore void unsubscribe(VmsLayer layer);
- method @AddedInOrBefore void unsubscribe(VmsLayer layer, int providerId);
- method @AddedInOrBefore Set<VmsAssociatedLayer> getSubscriptions();
-class @hide @SystemApi VmsClient package android.car.vms
- method @AddedInOrBefore byte[] getProviderDescription(int providerId);
- method @AddedInOrBefore void setSubscriptions(Set<VmsAssociatedLayer> layers);
- method @AddedInOrBefore void setMonitoringEnabled(boolean enabled);
- method @AddedInOrBefore boolean isMonitoringEnabled();
- method @AddedInOrBefore VmsAvailableLayers getAvailableLayers();
- method @AddedInOrBefore int registerProvider(byte[] providerDescription);
- method @AddedInOrBefore void unregisterProvider(int providerId);
- method @AddedInOrBefore void setProviderOfferings(int providerId, Set<VmsLayerDependency> offerings);
- method @AddedInOrBefore void publishPacket(int providerId, VmsLayer layer, byte[] packet);
- method @AddedInOrBefore VmsSubscriptionState getSubscriptionState();
- method @hide @AddedInOrBefore void register();
- method @hide @AddedInOrBefore void unregister();
-class @hide @SystemApi VmsLayerDependency package android.car.vms
- field @AddedInOrBefore Parcelable.Creator<VmsLayerDependency> CREATOR;
- method @AddedInOrBefore VmsLayer getLayer();
- method @AddedInOrBefore Set<VmsLayer> getDependencies();
- method @AddedInOrBefore String toString();
- method @AddedInOrBefore boolean equals(Object o);
- method @AddedInOrBefore int hashCode();
- method @AddedInOrBefore void writeToParcel(Parcel dest, int flags);
- method @AddedInOrBefore int describeContents();
-class @hide VmsRegistrationInfo package android.car.vms
- field @AddedInOrBefore Parcelable.Creator<VmsRegistrationInfo> CREATOR;
- method @AddedInOrBefore VmsAvailableLayers getAvailableLayers();
- method @AddedInOrBefore VmsSubscriptionState getSubscriptionState();
- method @AddedInOrBefore boolean equals(Object o);
- method @AddedInOrBefore int hashCode();
- method @AddedInOrBefore void writeToParcel(Parcel dest, int flags);
- method @AddedInOrBefore int describeContents();
-class @hide @SystemApi VmsSubscriptionState package android.car.vms
- field @AddedInOrBefore Parcelable.Creator<VmsSubscriptionState> CREATOR;
- method @AddedInOrBefore int getSequenceNumber();
- method @AddedInOrBefore Set<VmsLayer> getLayers();
- method @AddedInOrBefore Set<VmsAssociatedLayer> getAssociatedLayers();
- method @AddedInOrBefore String toString();
- method @AddedInOrBefore boolean equals(Object o);
- method @AddedInOrBefore int hashCode();
- method @AddedInOrBefore void writeToParcel(Parcel dest, int flags);
- method @AddedInOrBefore int describeContents();
-class @hide @SystemApi VmsLayersOffering package android.car.vms
- field @AddedInOrBefore Parcelable.Creator<VmsLayersOffering> CREATOR;
- method @AddedInOrBefore Set<VmsLayerDependency> getDependencies();
- method @AddedInOrBefore int getPublisherId();
- method @AddedInOrBefore String toString();
- method @AddedInOrBefore boolean equals(Object o);
- method @AddedInOrBefore int hashCode();
- method @AddedInOrBefore void writeToParcel(Parcel dest, int flags);
- method @AddedInOrBefore int describeContents();
-class @hide @SystemApi VmsAssociatedLayer package android.car.vms
- field @AddedInOrBefore Parcelable.Creator<VmsAssociatedLayer> CREATOR;
- method @AddedInOrBefore Set<Integer> getPublisherIds();
- method @AddedInOrBefore VmsLayer getVmsLayer();
- method @AddedInOrBefore Set<Integer> getProviderIds();
- method @AddedInOrBefore String toString();
- method @AddedInOrBefore boolean equals(Object o);
- method @AddedInOrBefore int hashCode();
- method @AddedInOrBefore void writeToParcel(Parcel dest, int flags);
- method @AddedInOrBefore int describeContents();
-class @hide @SystemApi VmsPublisherClientService package android.car.vms
- method @AddedInOrBefore void onCreate();
- method @AddedInOrBefore void onDestroy();
- method @AddedInOrBefore IBinder onBind(Intent intent);
- method @hide @AddedInOrBefore void onCarLifecycleChanged(Car car, boolean ready);
- method @AddedInOrBefore void onVmsPublisherServiceReady();
- method @AddedInOrBefore void onVmsSubscriptionChange(VmsSubscriptionState subscriptionState);
- method @AddedInOrBefore void publish(VmsLayer layer, int publisherId, byte[] payload);
- method @AddedInOrBefore void setLayersOffering(VmsLayersOffering offering);
- method @AddedInOrBefore int getPublisherId(byte[] publisherInfo);
- method @AddedInOrBefore VmsSubscriptionState getSubscriptions();
-class @hide @SystemApi VmsSubscriberManager package android.car.vms
- method @hide @AddedInOrBefore VmsSubscriberManager wrap(Car car, VmsClientManager clientManager);
- method @AddedInOrBefore void setVmsSubscriberClientCallback(Executor executor, VmsSubscriberClientCallback clientCallback);
- method @AddedInOrBefore void clearVmsSubscriberClientCallback();
- method @AddedInOrBefore byte[] getPublisherInfo(int publisherId);
- method @AddedInOrBefore VmsAvailableLayers getAvailableLayers();
- method @AddedInOrBefore void subscribe(VmsLayer layer);
- method @AddedInOrBefore void subscribe(VmsLayer layer, int publisherId);
- method @AddedInOrBefore void startMonitoring();
- method @AddedInOrBefore void unsubscribe(VmsLayer layer);
- method @AddedInOrBefore void unsubscribe(VmsLayer layer, int publisherId);
- method @AddedInOrBefore void stopMonitoring();
- method @hide @AddedInOrBefore void onCarDisconnected();
-interface VmsSubscriberManager.VmsSubscriberClientCallback package android.car.vms
- method @AddedInOrBefore void onVmsMessageReceived(VmsLayer layer, byte[] payload);
- method @AddedInOrBefore void onLayersAvailabilityChanged(VmsAvailableLayers availableLayers);
-class @hide VmsProviderInfo package android.car.vms
- field @AddedInOrBefore Parcelable.Creator<VmsProviderInfo> CREATOR;
- method @AddedInOrBefore byte[] getDescription();
- method @AddedInOrBefore boolean equals(Object o);
- method @AddedInOrBefore int hashCode();
- method @AddedInOrBefore void writeToParcel(Parcel dest, int flags);
- method @AddedInOrBefore int describeContents();
-class @hide @SystemApi VmsClientManager package android.car.vms
- method @AddedInOrBefore void registerVmsClientCallback(Executor executor, VmsClientCallback callback);
- method @hide @AddedInOrBefore void registerVmsClientCallback(Executor executor, VmsClientCallback callback, boolean legacyClient);
- method @AddedInOrBefore void unregisterVmsClientCallback(VmsClientCallback callback);
- method @hide @AddedInOrBefore void onCarDisconnected();
-interface VmsClientManager.VmsClientCallback package android.car.vms
- method @AddedInOrBefore void onClientConnected(VmsClient client);
- method @AddedInOrBefore void onLayerAvailabilityChanged(VmsAvailableLayers availableLayers);
- method @AddedInOrBefore void onSubscriptionStateChanged(VmsSubscriptionState subscriptionState);
- method @AddedInOrBefore void onPacketReceived(int providerId, VmsLayer layer, byte[] packet);
-class VehicleAreaWheel package android.car
- field @AddedInOrBefore int WHEEL_UNKNOWN = 0x00;
- field @AddedInOrBefore int WHEEL_LEFT_FRONT = 0x01;
- field @AddedInOrBefore int WHEEL_RIGHT_FRONT = 0x02;
- field @AddedInOrBefore int WHEEL_LEFT_REAR = 0x04;
- field @AddedInOrBefore int WHEEL_RIGHT_REAR = 0x08;
-class @hide AndroidFuture package android.car.util.concurrent
- field @AddedInOrBefore Parcelable.Creator<AndroidFuture> CREATOR;
- method @AddedInOrBefore AndroidFuture<U> completedFuture(U value);
- method @AddedInOrBefore boolean complete(T value);
- method @AddedInOrBefore boolean completeExceptionally(Throwable ex);
- method @AddedInOrBefore boolean cancel(boolean mayInterruptIfRunning);
- method @AddedInOrBefore void onCompleted(T res, Throwable err);
- method @AddedInOrBefore AndroidFuture<T> whenComplete(BiConsumer<? super T,? super Throwable> action);
- method @AddedInOrBefore AndroidFuture<T> whenCompleteAsync(BiConsumer<? super T,? super Throwable> action, Executor executor);
- method @AddedInOrBefore void callListener(BiConsumer<? super TT,? super Throwable> listener, TT res, Throwable err);
- method @AddedInOrBefore AndroidFuture<T> orTimeout(long timeout, TimeUnit unit);
- method @AddedInOrBefore void triggerTimeout();
- method @AddedInOrBefore AndroidFuture<T> cancelTimeout();
- method @AddedInOrBefore AndroidFuture<T> setTimeoutHandler(Handler h);
- method @AddedInOrBefore AndroidFuture<U> thenCompose(Function<? super T,? extends CompletionStage<U>> fn);
- method @AddedInOrBefore AndroidFuture<U> thenComposeAsync(Function<? super T,? extends CompletionStage<U>> fn, Executor executor);
- method @AddedInOrBefore AndroidFuture<U> thenApply(Function<? super T,? extends U> fn);
- method @AddedInOrBefore AndroidFuture<U> thenApplyAsync(Function<? super T,? extends U> fn, Executor executor);
- method @AddedInOrBefore AndroidFuture<V> thenCombine(CompletionStage<? extends U> other, BiFunction<? super T,? super U,? extends V> combineResults);
- method @AddedInOrBefore AndroidFuture<T> thenCombine(CompletionStage<Void> other);
- method @AddedInOrBefore AndroidFuture<T> supply(Supplier<T> supplier);
- method @AddedInOrBefore AndroidFuture<T> supplyAsync(Supplier<T> supplier, Executor executor);
- method @AddedInOrBefore void writeToParcel(Parcel dest, int flags);
- method @AddedInOrBefore Throwable unwrapExecutionException(Throwable t);
- method @AddedInOrBefore int describeContents();
-class @hide AndroidAsyncFuture package android.car.util.concurrent
- method @AddedInOrBefore T get();
- method @AddedInOrBefore T get(long timeout, TimeUnit unit);
- method @AddedInOrBefore AsyncFuture<T> whenCompleteAsync(BiConsumer<? super T,? super Throwable> action, Executor executor);
-interface @hide AsyncFuture package android.car.util.concurrent
- method @AddedInOrBefore T get();
- method @AddedInOrBefore T get(long timeout, TimeUnit unit);
- method @AddedInOrBefore AsyncFuture<T> whenCompleteAsync(BiConsumer<? super T,? super Throwable> action, Executor executor);
-class @hide @SystemApi CarDiagnosticManager package android.car.diagnostic
- field @AddedInOrBefore int FRAME_TYPE_LIVE = 0;
- field @AddedInOrBefore int FRAME_TYPE_FREEZE = 1;
- field @hide @AddedInOrBefore int[] FRAME_TYPES = { FRAME_TYPE_LIVE, FRAME_TYPE_FREEZE };
- method @AddedInOrBefore void onCarDisconnected();
- method @AddedInOrBefore boolean registerListener(OnDiagnosticEventListener listener, int frameType, int rate);
- method @AddedInOrBefore void unregisterListener(OnDiagnosticEventListener listener);
- method @AddedInOrBefore CarDiagnosticEvent getLatestLiveFrame();
- method @AddedInOrBefore long[] getFreezeFrameTimestamps();
- method @AddedInOrBefore CarDiagnosticEvent getFreezeFrame(long timestamp);
- method @AddedInOrBefore boolean clearFreezeFrames(long timestamps);
- method @AddedInOrBefore boolean isLiveFrameSupported();
- method @AddedInOrBefore boolean isFreezeFrameNotificationSupported();
- method @AddedInOrBefore boolean isGetFreezeFrameSupported();
- method @AddedInOrBefore boolean isClearFreezeFramesSupported();
- method @AddedInOrBefore boolean isSelectiveClearFreezeFramesSupported();
-interface CarDiagnosticManager.OnDiagnosticEventListener package android.car.diagnostic
- method @AddedInOrBefore void onDiagnosticEvent(CarDiagnosticEvent carDiagnosticEvent);
-class @hide @SystemApi FloatSensorIndex package android.car.diagnostic
- field @AddedInOrBefore int CALCULATED_ENGINE_LOAD = 0;
- field @AddedInOrBefore int ENGINE_COOLANT_TEMPERATURE = 1;
- field @AddedInOrBefore int SHORT_TERM_FUEL_TRIM_BANK1 = 2;
- field @AddedInOrBefore int LONG_TERM_FUEL_TRIM_BANK1 = 3;
- field @AddedInOrBefore int SHORT_TERM_FUEL_TRIM_BANK2 = 4;
- field @AddedInOrBefore int LONG_TERM_FUEL_TRIM_BANK2 = 5;
- field @AddedInOrBefore int FUEL_PRESSURE = 6;
- field @AddedInOrBefore int INTAKE_MANIFOLD_ABSOLUTE_PRESSURE = 7;
- field @AddedInOrBefore int ENGINE_RPM = 8;
- field @AddedInOrBefore int VEHICLE_SPEED = 9;
- field @AddedInOrBefore int TIMING_ADVANCE = 10;
- field @AddedInOrBefore int MAF_AIR_FLOW_RATE = 11;
- field @AddedInOrBefore int THROTTLE_POSITION = 12;
- field @AddedInOrBefore int OXYGEN_SENSOR1_VOLTAGE = 13;
- field @AddedInOrBefore int OXYGEN_SENSOR1_SHORT_TERM_FUEL_TRIM = 14;
- field @AddedInOrBefore int OXYGEN_SENSOR1_FUEL_AIR_EQUIVALENCE_RATIO = 15;
- field @AddedInOrBefore int OXYGEN_SENSOR2_VOLTAGE = 16;
- field @AddedInOrBefore int OXYGEN_SENSOR2_SHORT_TERM_FUEL_TRIM = 17;
- field @AddedInOrBefore int OXYGEN_SENSOR2_FUEL_AIR_EQUIVALENCE_RATIO = 18;
- field @AddedInOrBefore int OXYGEN_SENSOR3_VOLTAGE = 19;
- field @AddedInOrBefore int OXYGEN_SENSOR3_SHORT_TERM_FUEL_TRIM = 20;
- field @AddedInOrBefore int OXYGEN_SENSOR3_FUEL_AIR_EQUIVALENCE_RATIO = 21;
- field @AddedInOrBefore int OXYGEN_SENSOR4_VOLTAGE = 22;
- field @AddedInOrBefore int OXYGEN_SENSOR4_SHORT_TERM_FUEL_TRIM = 23;
- field @AddedInOrBefore int OXYGEN_SENSOR4_FUEL_AIR_EQUIVALENCE_RATIO = 24;
- field @AddedInOrBefore int OXYGEN_SENSOR5_VOLTAGE = 25;
- field @AddedInOrBefore int OXYGEN_SENSOR5_SHORT_TERM_FUEL_TRIM = 26;
- field @AddedInOrBefore int OXYGEN_SENSOR5_FUEL_AIR_EQUIVALENCE_RATIO = 27;
- field @AddedInOrBefore int OXYGEN_SENSOR6_VOLTAGE = 28;
- field @AddedInOrBefore int OXYGEN_SENSOR6_SHORT_TERM_FUEL_TRIM = 29;
- field @AddedInOrBefore int OXYGEN_SENSOR6_FUEL_AIR_EQUIVALENCE_RATIO = 30;
- field @AddedInOrBefore int OXYGEN_SENSOR7_VOLTAGE = 31;
- field @AddedInOrBefore int OXYGEN_SENSOR7_SHORT_TERM_FUEL_TRIM = 32;
- field @AddedInOrBefore int OXYGEN_SENSOR7_FUEL_AIR_EQUIVALENCE_RATIO = 33;
- field @AddedInOrBefore int OXYGEN_SENSOR8_VOLTAGE = 34;
- field @AddedInOrBefore int OXYGEN_SENSOR8_SHORT_TERM_FUEL_TRIM = 35;
- field @AddedInOrBefore int OXYGEN_SENSOR8_FUEL_AIR_EQUIVALENCE_RATIO = 36;
- field @AddedInOrBefore int FUEL_RAIL_PRESSURE = 37;
- field @AddedInOrBefore int FUEL_RAIL_GAUGE_PRESSURE = 38;
- field @AddedInOrBefore int COMMANDED_EXHAUST_GAS_RECIRCULATION = 39;
- field @AddedInOrBefore int EXHAUST_GAS_RECIRCULATION_ERROR = 40;
- field @AddedInOrBefore int COMMANDED_EVAPORATIVE_PURGE = 41;
- field @AddedInOrBefore int FUEL_TANK_LEVEL_INPUT = 42;
- field @AddedInOrBefore int EVAPORATION_SYSTEM_VAPOR_PRESSURE = 43;
- field @AddedInOrBefore int CATALYST_TEMPERATURE_BANK1_SENSOR1 = 44;
- field @AddedInOrBefore int CATALYST_TEMPERATURE_BANK2_SENSOR1 = 45;
- field @AddedInOrBefore int CATALYST_TEMPERATURE_BANK1_SENSOR2 = 46;
- field @AddedInOrBefore int CATALYST_TEMPERATURE_BANK2_SENSOR2 = 47;
- field @AddedInOrBefore int ABSOLUTE_LOAD_VALUE = 48;
- field @AddedInOrBefore int FUEL_AIR_COMMANDED_EQUIVALENCE_RATIO = 49;
- field @AddedInOrBefore int RELATIVE_THROTTLE_POSITION = 50;
- field @AddedInOrBefore int ABSOLUTE_THROTTLE_POSITION_B = 51;
- field @AddedInOrBefore int ABSOLUTE_THROTTLE_POSITION_C = 52;
- field @AddedInOrBefore int ACCELERATOR_PEDAL_POSITION_D = 53;
- field @AddedInOrBefore int ACCELERATOR_PEDAL_POSITION_E = 54;
- field @AddedInOrBefore int ACCELERATOR_PEDAL_POSITION_F = 55;
- field @AddedInOrBefore int COMMANDED_THROTTLE_ACTUATOR = 56;
- field @AddedInOrBefore int ETHANOL_FUEL_PERCENTAGE = 57;
- field @AddedInOrBefore int ABSOLUTE_EVAPORATION_SYSTEM_VAPOR_PRESSURE = 58;
- field @AddedInOrBefore int SHORT_TERM_SECONDARY_OXYGEN_SENSOR_TRIM_BANK1 = 59;
- field @AddedInOrBefore int SHORT_TERM_SECONDARY_OXYGEN_SENSOR_TRIM_BANK2 = 60;
- field @AddedInOrBefore int SHORT_TERM_SECONDARY_OXYGEN_SENSOR_TRIM_BANK3 = 61;
- field @AddedInOrBefore int SHORT_TERM_SECONDARY_OXYGEN_SENSOR_TRIM_BANK4 = 62;
- field @AddedInOrBefore int LONG_TERM_SECONDARY_OXYGEN_SENSOR_TRIM_BANK1 = 63;
- field @AddedInOrBefore int LONG_TERM_SECONDARY_OXYGEN_SENSOR_TRIM_BANK2 = 64;
- field @AddedInOrBefore int LONG_TERM_SECONDARY_OXYGEN_SENSOR_TRIM_BANK3 = 65;
- field @AddedInOrBefore int LONG_TERM_SECONDARY_OXYGEN_SENSOR_TRIM_BANK4 = 66;
- field @AddedInOrBefore int RELATIVE_ACCELERATOR_PEDAL_POSITION = 67;
- field @AddedInOrBefore int HYBRID_BATTERY_PACK_REMAINING_LIFE = 68;
- field @AddedInOrBefore int FUEL_INJECTION_TIMING = 69;
- field @AddedInOrBefore int ENGINE_FUEL_RATE = 70;
- field @AddedInOrBefore int LAST_SYSTEM = ENGINE_FUEL_RATE;
- field @AddedInOrBefore int VENDOR_START = LAST_SYSTEM + 1;
-class @hide @SystemApi CarDiagnosticEvent package android.car.diagnostic
- field @AddedInOrBefore int frameType;
- field @AddedInOrBefore long timestamp;
- field @AddedInOrBefore String dtc;
- field @AddedInOrBefore Parcelable.Creator<CarDiagnosticEvent> CREATOR;
- method @AddedInOrBefore int describeContents();
- method @AddedInOrBefore void writeToParcel(Parcel dest, int flags);
- method @AddedInOrBefore void writeToJson(JsonWriter jsonWriter);
- method @hide @AddedInOrBefore CarDiagnosticEvent withVendorSensorsRemoved();
- method @AddedInOrBefore boolean isLiveFrame();
- method @AddedInOrBefore boolean isFreezeFrame();
- method @hide @AddedInOrBefore boolean isEmptyFrame();
- method @hide @AddedInOrBefore CarDiagnosticEvent checkLiveFrame();
- method @hide @AddedInOrBefore CarDiagnosticEvent checkFreezeFrame();
- method @hide @AddedInOrBefore boolean isEarlierThan(CarDiagnosticEvent otherEvent);
- method @AddedInOrBefore boolean equals(Object otherObject);
- method @AddedInOrBefore int hashCode();
- method @AddedInOrBefore String toString();
- method @AddedInOrBefore int getSystemIntegerSensor(int sensor, int defaultValue);
- method @AddedInOrBefore float getSystemFloatSensor(int sensor, float defaultValue);
- method @AddedInOrBefore int getVendorIntegerSensor(int sensor, int defaultValue);
- method @AddedInOrBefore float getVendorFloatSensor(int sensor, float defaultValue);
- method @AddedInOrBefore Integer getSystemIntegerSensor(int sensor);
- method @AddedInOrBefore Float getSystemFloatSensor(int sensor);
- method @AddedInOrBefore Integer getVendorIntegerSensor(int sensor);
- method @AddedInOrBefore Float getVendorFloatSensor(int sensor);
- method @AddedInOrBefore Integer getFuelSystemStatus();
- method @AddedInOrBefore Integer getSecondaryAirStatus();
- method @AddedInOrBefore CommonIgnitionMonitors getIgnitionMonitors();
- method @AddedInOrBefore Integer getFuelType();
-class CarDiagnosticEvent.Builder package android.car.diagnostic
- method @AddedInOrBefore Builder newLiveFrameBuilder();
- method @AddedInOrBefore Builder newFreezeFrameBuilder();
- method @AddedInOrBefore Builder atTimestamp(long timestamp);
- method @AddedInOrBefore Builder setTimeStamp(long timeStamp);
- method @AddedInOrBefore Builder withIntValue(int key, int value);
- method @AddedInOrBefore Builder setIntValue(int key, int value);
- method @AddedInOrBefore Builder withFloatValue(int key, float value);
- method @AddedInOrBefore Builder setFloatValue(int key, float value);
- method @AddedInOrBefore Builder withDtc(String dtc);
- method @AddedInOrBefore Builder setDtc(String dtc);
- method @AddedInOrBefore CarDiagnosticEvent build();
-class CarDiagnosticEvent.FuelSystemStatus package android.car.diagnostic
- field @AddedInOrBefore int OPEN_INSUFFICIENT_ENGINE_TEMPERATURE = 1;
- field @AddedInOrBefore int CLOSED_LOOP = 2;
- field @AddedInOrBefore int OPEN_ENGINE_LOAD_OR_DECELERATION = 4;
- field @AddedInOrBefore int OPEN_SYSTEM_FAILURE = 8;
- field @AddedInOrBefore int CLOSED_LOOP_BUT_FEEDBACK_FAULT = 16;
-class CarDiagnosticEvent.SecondaryAirStatus package android.car.diagnostic
- field @AddedInOrBefore int UPSTREAM = 1;
- field @AddedInOrBefore int DOWNSTREAM_OF_CATALYCIC_CONVERTER = 2;
- field @AddedInOrBefore int FROM_OUTSIDE_OR_OFF = 4;
- field @AddedInOrBefore int PUMP_ON_FOR_DIAGNOSTICS = 8;
-class CarDiagnosticEvent.FuelType package android.car.diagnostic
- field @AddedInOrBefore int NOT_AVAILABLE = 0;
- field @AddedInOrBefore int GASOLINE = 1;
- field @AddedInOrBefore int METHANOL = 2;
- field @AddedInOrBefore int ETHANOL = 3;
- field @AddedInOrBefore int DIESEL = 4;
- field @AddedInOrBefore int LPG = 5;
- field @AddedInOrBefore int CNG = 6;
- field @AddedInOrBefore int PROPANE = 7;
- field @AddedInOrBefore int ELECTRIC = 8;
- field @AddedInOrBefore int BIFUEL_RUNNING_GASOLINE = 9;
- field @AddedInOrBefore int BIFUEL_RUNNING_METHANOL = 10;
- field @AddedInOrBefore int BIFUEL_RUNNING_ETHANOL = 11;
- field @AddedInOrBefore int BIFUEL_RUNNING_LPG = 12;
- field @AddedInOrBefore int BIFUEL_RUNNING_CNG = 13;
- field @AddedInOrBefore int BIFUEL_RUNNING_PROPANE = 14;
- field @AddedInOrBefore int BIFUEL_RUNNING_ELECTRIC = 15;
- field @AddedInOrBefore int BIFUEL_RUNNING_ELECTRIC_AND_COMBUSTION = 16;
- field @AddedInOrBefore int HYBRID_GASOLINE = 17;
- field @AddedInOrBefore int HYBRID_ETHANOL = 18;
- field @AddedInOrBefore int HYBRID_DIESEL = 19;
- field @AddedInOrBefore int HYBRID_ELECTRIC = 20;
- field @AddedInOrBefore int HYBRID_RUNNING_ELECTRIC_AND_COMBUSTION = 21;
- field @AddedInOrBefore int HYBRID_REGENERATIVE = 22;
- field @AddedInOrBefore int BIFUEL_RUNNING_DIESEL = 23;
-class CarDiagnosticEvent.IgnitionMonitor package android.car.diagnostic
- field @AddedInOrBefore boolean available;
- field @AddedInOrBefore boolean incomplete;
-class @hide CarDiagnosticEvent.IgnitionMonitor.Decoder package android.car.diagnostic
- method @AddedInOrBefore IgnitionMonitor fromValue(int value);
-class CarDiagnosticEvent.CommonIgnitionMonitors package android.car.diagnostic
- field @AddedInOrBefore IgnitionMonitor components;
- field @AddedInOrBefore IgnitionMonitor fuelSystem;
- field @AddedInOrBefore IgnitionMonitor misfire;
- field @hide @AddedInOrBefore int COMPONENTS_AVAILABLE = 0x1 << 0;
- field @hide @AddedInOrBefore int COMPONENTS_INCOMPLETE = 0x1 << 1;
- field @hide @AddedInOrBefore int FUEL_SYSTEM_AVAILABLE = 0x1 << 2;
- field @hide @AddedInOrBefore int FUEL_SYSTEM_INCOMPLETE = 0x1 << 3;
- field @hide @AddedInOrBefore int MISFIRE_AVAILABLE = 0x1 << 4;
- field @hide @AddedInOrBefore int MISFIRE_INCOMPLETE = 0x1 << 5;
- field @AddedInOrBefore IgnitionMonitor.Decoder COMPONENTS_DECODER = new IgnitionMonitor.Decoder(COMPONENTS_AVAILABLE, COMPONENTS_INCOMPLETE);
- field @AddedInOrBefore IgnitionMonitor.Decoder FUEL_SYSTEM_DECODER = new IgnitionMonitor.Decoder(FUEL_SYSTEM_AVAILABLE, FUEL_SYSTEM_INCOMPLETE);
- field @AddedInOrBefore IgnitionMonitor.Decoder MISFIRE_DECODER = new IgnitionMonitor.Decoder(MISFIRE_AVAILABLE, MISFIRE_INCOMPLETE);
- method @AddedInOrBefore SparkIgnitionMonitors asSparkIgnitionMonitors();
- method @AddedInOrBefore CompressionIgnitionMonitors asCompressionIgnitionMonitors();
-class CarDiagnosticEvent.SparkIgnitionMonitors package android.car.diagnostic
- field @AddedInOrBefore IgnitionMonitor EGR;
- field @AddedInOrBefore IgnitionMonitor oxygenSensorHeater;
- field @AddedInOrBefore IgnitionMonitor oxygenSensor;
- field @AddedInOrBefore IgnitionMonitor ACRefrigerant;
- field @AddedInOrBefore IgnitionMonitor secondaryAirSystem;
- field @AddedInOrBefore IgnitionMonitor evaporativeSystem;
- field @AddedInOrBefore IgnitionMonitor heatedCatalyst;
- field @AddedInOrBefore IgnitionMonitor catalyst;
- field @hide @AddedInOrBefore int EGR_AVAILABLE = 0x1 << 6;
- field @hide @AddedInOrBefore int EGR_INCOMPLETE = 0x1 << 7;
- field @hide @AddedInOrBefore int OXYGEN_SENSOR_HEATER_AVAILABLE = 0x1 << 8;
- field @hide @AddedInOrBefore int OXYGEN_SENSOR_HEATER_INCOMPLETE = 0x1 << 9;
- field @hide @AddedInOrBefore int OXYGEN_SENSOR_AVAILABLE = 0x1 << 10;
- field @hide @AddedInOrBefore int OXYGEN_SENSOR_INCOMPLETE = 0x1 << 11;
- field @hide @AddedInOrBefore int AC_REFRIGERANT_AVAILABLE = 0x1 << 12;
- field @hide @AddedInOrBefore int AC_REFRIGERANT_INCOMPLETE = 0x1 << 13;
- field @hide @AddedInOrBefore int SECONDARY_AIR_SYSTEM_AVAILABLE = 0x1 << 14;
- field @hide @AddedInOrBefore int SECONDARY_AIR_SYSTEM_INCOMPLETE = 0x1 << 15;
- field @hide @AddedInOrBefore int EVAPORATIVE_SYSTEM_AVAILABLE = 0x1 << 16;
- field @hide @AddedInOrBefore int EVAPORATIVE_SYSTEM_INCOMPLETE = 0x1 << 17;
- field @hide @AddedInOrBefore int HEATED_CATALYST_AVAILABLE = 0x1 << 18;
- field @hide @AddedInOrBefore int HEATED_CATALYST_INCOMPLETE = 0x1 << 19;
- field @hide @AddedInOrBefore int CATALYST_AVAILABLE = 0x1 << 20;
- field @hide @AddedInOrBefore int CATALYST_INCOMPLETE = 0x1 << 21;
- field @AddedInOrBefore IgnitionMonitor.Decoder EGR_DECODER = new IgnitionMonitor.Decoder(EGR_AVAILABLE, EGR_INCOMPLETE);
- field @AddedInOrBefore IgnitionMonitor.Decoder OXYGEN_SENSOR_HEATER_DECODER = new IgnitionMonitor.Decoder(OXYGEN_SENSOR_HEATER_AVAILABLE, OXYGEN_SENSOR_HEATER_INCOMPLETE);
- field @AddedInOrBefore IgnitionMonitor.Decoder OXYGEN_SENSOR_DECODER = new IgnitionMonitor.Decoder(OXYGEN_SENSOR_AVAILABLE, OXYGEN_SENSOR_INCOMPLETE);
- field @AddedInOrBefore IgnitionMonitor.Decoder AC_REFRIGERANT_DECODER = new IgnitionMonitor.Decoder(AC_REFRIGERANT_AVAILABLE, AC_REFRIGERANT_INCOMPLETE);
- field @AddedInOrBefore IgnitionMonitor.Decoder SECONDARY_AIR_SYSTEM_DECODER = new IgnitionMonitor.Decoder(SECONDARY_AIR_SYSTEM_AVAILABLE, SECONDARY_AIR_SYSTEM_INCOMPLETE);
- field @AddedInOrBefore IgnitionMonitor.Decoder EVAPORATIVE_SYSTEM_DECODER = new IgnitionMonitor.Decoder(EVAPORATIVE_SYSTEM_AVAILABLE, EVAPORATIVE_SYSTEM_INCOMPLETE);
- field @AddedInOrBefore IgnitionMonitor.Decoder HEATED_CATALYST_DECODER = new IgnitionMonitor.Decoder(HEATED_CATALYST_AVAILABLE, HEATED_CATALYST_INCOMPLETE);
- field @AddedInOrBefore IgnitionMonitor.Decoder CATALYST_DECODER = new IgnitionMonitor.Decoder(CATALYST_AVAILABLE, CATALYST_INCOMPLETE);
-class CarDiagnosticEvent.CompressionIgnitionMonitors package android.car.diagnostic
- field @AddedInOrBefore IgnitionMonitor EGROrVVT;
- field @AddedInOrBefore IgnitionMonitor PMFilter;
- field @AddedInOrBefore IgnitionMonitor exhaustGasSensor;
- field @AddedInOrBefore IgnitionMonitor boostPressure;
- field @AddedInOrBefore IgnitionMonitor NOxSCR;
- field @AddedInOrBefore IgnitionMonitor NMHCCatalyst;
- field @hide @AddedInOrBefore int EGR_OR_VVT_AVAILABLE = 0x1 << 6;
- field @hide @AddedInOrBefore int EGR_OR_VVT_INCOMPLETE = 0x1 << 7;
- field @hide @AddedInOrBefore int PM_FILTER_AVAILABLE = 0x1 << 8;
- field @hide @AddedInOrBefore int PM_FILTER_INCOMPLETE = 0x1 << 9;
- field @hide @AddedInOrBefore int EXHAUST_GAS_SENSOR_AVAILABLE = 0x1 << 10;
- field @hide @AddedInOrBefore int EXHAUST_GAS_SENSOR_INCOMPLETE = 0x1 << 11;
- field @hide @AddedInOrBefore int BOOST_PRESSURE_AVAILABLE = 0x1 << 12;
- field @hide @AddedInOrBefore int BOOST_PRESSURE_INCOMPLETE = 0x1 << 13;
- field @hide @AddedInOrBefore int NOx_SCR_AVAILABLE = 0x1 << 14;
- field @hide @AddedInOrBefore int NOx_SCR_INCOMPLETE = 0x1 << 15;
- field @hide @AddedInOrBefore int NMHC_CATALYST_AVAILABLE = 0x1 << 16;
- field @hide @AddedInOrBefore int NMHC_CATALYST_INCOMPLETE = 0x1 << 17;
- field @AddedInOrBefore IgnitionMonitor.Decoder EGR_OR_VVT_DECODER = new IgnitionMonitor.Decoder(EGR_OR_VVT_AVAILABLE, EGR_OR_VVT_INCOMPLETE);
- field @AddedInOrBefore IgnitionMonitor.Decoder PM_FILTER_DECODER = new IgnitionMonitor.Decoder(PM_FILTER_AVAILABLE, PM_FILTER_INCOMPLETE);
- field @AddedInOrBefore IgnitionMonitor.Decoder EXHAUST_GAS_SENSOR_DECODER = new IgnitionMonitor.Decoder(EXHAUST_GAS_SENSOR_AVAILABLE, EXHAUST_GAS_SENSOR_INCOMPLETE);
- field @AddedInOrBefore IgnitionMonitor.Decoder BOOST_PRESSURE_DECODER = new IgnitionMonitor.Decoder(BOOST_PRESSURE_AVAILABLE, BOOST_PRESSURE_INCOMPLETE);
- field @AddedInOrBefore IgnitionMonitor.Decoder NOx_SCR_DECODER = new IgnitionMonitor.Decoder(NOx_SCR_AVAILABLE, NOx_SCR_INCOMPLETE);
- field @AddedInOrBefore IgnitionMonitor.Decoder NMHC_CATALYST_DECODER = new IgnitionMonitor.Decoder(NMHC_CATALYST_AVAILABLE, NMHC_CATALYST_INCOMPLETE);
-class @hide @SystemApi IntegerSensorIndex package android.car.diagnostic
- field @AddedInOrBefore int FUEL_SYSTEM_STATUS = 0;
- field @AddedInOrBefore int MALFUNCTION_INDICATOR_LIGHT_ON = 1;
- field @AddedInOrBefore int IGNITION_MONITORS_SUPPORTED = 2;
- field @AddedInOrBefore int IGNITION_SPECIFIC_MONITORS = 3;
- field @AddedInOrBefore int INTAKE_AIR_TEMPERATURE = 4;
- field @AddedInOrBefore int COMMANDED_SECONDARY_AIR_STATUS = 5;
- field @AddedInOrBefore int NUM_OXYGEN_SENSORS_PRESENT = 6;
- field @AddedInOrBefore int RUNTIME_SINCE_ENGINE_START = 7;
- field @AddedInOrBefore int DISTANCE_TRAVELED_WITH_MALFUNCTION_INDICATOR_LIGHT_ON = 8;
- field @AddedInOrBefore int WARMUPS_SINCE_CODES_CLEARED = 9;
- field @AddedInOrBefore int DISTANCE_TRAVELED_SINCE_CODES_CLEARED = 10;
- field @AddedInOrBefore int ABSOLUTE_BAROMETRIC_PRESSURE = 11;
- field @AddedInOrBefore int CONTROL_MODULE_VOLTAGE = 12;
- field @AddedInOrBefore int AMBIENT_AIR_TEMPERATURE = 13;
- field @AddedInOrBefore int TIME_WITH_MALFUNCTION_LIGHT_ON = 14;
- field @AddedInOrBefore int TIME_SINCE_TROUBLE_CODES_CLEARED = 15;
- field @AddedInOrBefore int MAX_FUEL_AIR_EQUIVALENCE_RATIO = 16;
- field @AddedInOrBefore int MAX_OXYGEN_SENSOR_VOLTAGE = 17;
- field @AddedInOrBefore int MAX_OXYGEN_SENSOR_CURRENT = 18;
- field @AddedInOrBefore int MAX_INTAKE_MANIFOLD_ABSOLUTE_PRESSURE = 19;
- field @AddedInOrBefore int MAX_AIR_FLOW_RATE_FROM_MASS_AIR_FLOW_SENSOR = 20;
- field @AddedInOrBefore int FUEL_TYPE = 21;
- field @AddedInOrBefore int FUEL_RAIL_ABSOLUTE_PRESSURE = 22;
- field @AddedInOrBefore int ENGINE_OIL_TEMPERATURE = 23;
- field @AddedInOrBefore int DRIVER_DEMAND_PERCENT_TORQUE = 24;
- field @AddedInOrBefore int ENGINE_ACTUAL_PERCENT_TORQUE = 25;
- field @AddedInOrBefore int ENGINE_REFERENCE_PERCENT_TORQUE = 26;
- field @AddedInOrBefore int ENGINE_PERCENT_TORQUE_DATA_IDLE = 27;
- field @AddedInOrBefore int ENGINE_PERCENT_TORQUE_DATA_POINT1 = 28;
- field @AddedInOrBefore int ENGINE_PERCENT_TORQUE_DATA_POINT2 = 29;
- field @AddedInOrBefore int ENGINE_PERCENT_TORQUE_DATA_POINT3 = 30;
- field @AddedInOrBefore int ENGINE_PERCENT_TORQUE_DATA_POINT4 = 31;
- field @AddedInOrBefore int LAST_SYSTEM = ENGINE_PERCENT_TORQUE_DATA_POINT4;
- field @AddedInOrBefore int VENDOR_START = LAST_SYSTEM + 1;
-class VehiclePropertyIds package android.car
- field @AddedInOrBefore int INVALID = 0;
- field @AddedInOrBefore int INFO_VIN = 286261504;
- field @AddedInOrBefore int INFO_MAKE = 286261505;
- field @AddedInOrBefore int INFO_MODEL = 286261506;
- field @AddedInOrBefore int INFO_MODEL_YEAR = 289407235;
- field @AddedInOrBefore int INFO_FUEL_CAPACITY = 291504388;
- field @AddedInOrBefore int INFO_FUEL_TYPE = 289472773;
- field @AddedInOrBefore int INFO_EV_BATTERY_CAPACITY = 291504390;
- field @AddedInOrBefore int INFO_EV_CONNECTOR_TYPE = 289472775;
- field @AddedInOrBefore int INFO_FUEL_DOOR_LOCATION = 289407240;
- field @AddedInOrBefore int INFO_EV_PORT_LOCATION = 289407241;
- field @AddedInOrBefore int INFO_MULTI_EV_PORT_LOCATIONS = 289472780;
- field @AddedInOrBefore int INFO_DRIVER_SEAT = 356516106;
- field @AddedInOrBefore int INFO_EXTERIOR_DIMENSIONS = 289472779;
- field @AddedInOrBefore int PERF_ODOMETER = 291504644;
- field @AddedInOrBefore int PERF_VEHICLE_SPEED = 291504647;
- field @AddedInOrBefore int PERF_VEHICLE_SPEED_DISPLAY = 291504648;
- field @AddedInOrBefore int PERF_STEERING_ANGLE = 291504649;
- field @AddedInOrBefore int PERF_REAR_STEERING_ANGLE = 291504656;
- field @AddedInOrBefore int ENGINE_COOLANT_TEMP = 291504897;
- field @AddedInOrBefore int ENGINE_OIL_LEVEL = 289407747;
- field @AddedInOrBefore int ENGINE_OIL_TEMP = 291504900;
- field @AddedInOrBefore int ENGINE_RPM = 291504901;
- field @AddedInOrBefore int WHEEL_TICK = 290521862;
- field @AddedInOrBefore int FUEL_LEVEL = 291504903;
- field @AddedInOrBefore int FUEL_DOOR_OPEN = 287310600;
- field @AddedInOrBefore int EV_BATTERY_LEVEL = 291504905;
- field @AddedInOrBefore int EV_CHARGE_PORT_OPEN = 287310602;
- field @AddedInOrBefore int EV_CHARGE_PORT_CONNECTED = 287310603;
- field @AddedInOrBefore int EV_BATTERY_INSTANTANEOUS_CHARGE_RATE = 291504908;
- field @AddedInOrBefore int RANGE_REMAINING = 291504904;
- field @AddedInOrBefore int TIRE_PRESSURE = 392168201;
- field @AddedInOrBefore int CRITICALLY_LOW_TIRE_PRESSURE = 392168202;
- field @AddedInOrBefore int GEAR_SELECTION = 289408000;
- field @AddedInOrBefore int CURRENT_GEAR = 289408001;
- field @AddedInOrBefore int PARKING_BRAKE_ON = 287310850;
- field @AddedInOrBefore int PARKING_BRAKE_AUTO_APPLY = 287310851;
- field @AddedInOrBefore int FUEL_LEVEL_LOW = 287310853;
- field @AddedInOrBefore int NIGHT_MODE = 287310855;
- field @AddedInOrBefore int TURN_SIGNAL_STATE = 289408008;
- field @AddedInOrBefore int IGNITION_STATE = 289408009;
- field @AddedInOrBefore int ABS_ACTIVE = 287310858;
- field @AddedInOrBefore int TRACTION_CONTROL_ACTIVE = 287310859;
- field @AddedInOrBefore int HVAC_FAN_SPEED = 356517120;
- field @AddedInOrBefore int HVAC_FAN_DIRECTION = 356517121;
- field @AddedInOrBefore int HVAC_TEMPERATURE_CURRENT = 358614274;
- field @AddedInOrBefore int HVAC_TEMPERATURE_SET = 358614275;
- field @AddedInOrBefore int HVAC_TEMPERATURE_VALUE_SUGGESTION = 291570965;
- field @AddedInOrBefore int HVAC_DEFROSTER = 320865540;
- field @AddedInOrBefore int HVAC_AC_ON = 354419973;
- field @AddedInOrBefore int HVAC_MAX_AC_ON = 354419974;
- field @AddedInOrBefore int HVAC_MAX_DEFROST_ON = 354419975;
- field @AddedInOrBefore int HVAC_RECIRC_ON = 354419976;
- field @AddedInOrBefore int HVAC_DUAL_ON = 354419977;
- field @AddedInOrBefore int HVAC_AUTO_ON = 354419978;
- field @AddedInOrBefore int HVAC_SEAT_TEMPERATURE = 356517131;
- field @AddedInOrBefore int HVAC_SIDE_MIRROR_HEAT = 339739916;
- field @AddedInOrBefore int HVAC_STEERING_WHEEL_HEAT = 289408269;
- field @AddedInOrBefore int HVAC_TEMPERATURE_DISPLAY_UNITS = 289408270;
- field @AddedInOrBefore int HVAC_ACTUAL_FAN_SPEED_RPM = 356517135;
- field @AddedInOrBefore int HVAC_POWER_ON = 354419984;
- field @AddedInOrBefore int HVAC_FAN_DIRECTION_AVAILABLE = 356582673;
- field @AddedInOrBefore int HVAC_AUTO_RECIRC_ON = 354419986;
- field @AddedInOrBefore int HVAC_SEAT_VENTILATION = 356517139;
- field @hide @AddedInOrBefore int HVAC_ELECTRIC_DEFROSTER_ON = 320865556;
- field @AddedInOrBefore int DISTANCE_DISPLAY_UNITS = 289408512;
- field @AddedInOrBefore int FUEL_VOLUME_DISPLAY_UNITS = 289408513;
- field @AddedInOrBefore int TIRE_PRESSURE_DISPLAY_UNITS = 289408514;
- field @AddedInOrBefore int EV_BATTERY_DISPLAY_UNITS = 289408515;
- field @AddedInOrBefore int VEHICLE_SPEED_DISPLAY_UNITS = 289408516;
- field @AddedInOrBefore int FUEL_CONSUMPTION_UNITS_DISTANCE_OVER_VOLUME = 287311364;
- field @AddedInOrBefore int ENV_OUTSIDE_TEMPERATURE = 291505923;
- field @AddedInOrBefore int AP_POWER_STATE_REQ = 289475072;
- field @AddedInOrBefore int AP_POWER_STATE_REPORT = 289475073;
- field @AddedInOrBefore int AP_POWER_BOOTUP_REASON = 289409538;
- field @AddedInOrBefore int DISPLAY_BRIGHTNESS = 289409539;
- field @AddedInOrBefore int HW_KEY_INPUT = 289475088;
- field @AddedInOrBefore int DOOR_POS = 373295872;
- field @AddedInOrBefore int DOOR_MOVE = 373295873;
- field @AddedInOrBefore int DOOR_LOCK = 371198722;
- field @AddedInOrBefore int MIRROR_Z_POS = 339741504;
- field @AddedInOrBefore int MIRROR_Z_MOVE = 339741505;
- field @AddedInOrBefore int MIRROR_Y_POS = 339741506;
- field @AddedInOrBefore int MIRROR_Y_MOVE = 339741507;
- field @AddedInOrBefore int MIRROR_LOCK = 287312708;
- field @AddedInOrBefore int MIRROR_FOLD = 287312709;
- field @AddedInOrBefore int SEAT_MEMORY_SELECT = 356518784;
- field @AddedInOrBefore int SEAT_MEMORY_SET = 356518785;
- field @AddedInOrBefore int SEAT_BELT_BUCKLED = 354421634;
- field @AddedInOrBefore int SEAT_BELT_HEIGHT_POS = 356518787;
- field @AddedInOrBefore int SEAT_BELT_HEIGHT_MOVE = 356518788;
- field @AddedInOrBefore int SEAT_FORE_AFT_POS = 356518789;
- field @AddedInOrBefore int SEAT_FORE_AFT_MOVE = 356518790;
- field @AddedInOrBefore int SEAT_BACKREST_ANGLE_1_POS = 356518791;
- field @AddedInOrBefore int SEAT_BACKREST_ANGLE_1_MOVE = 356518792;
- field @AddedInOrBefore int SEAT_BACKREST_ANGLE_2_POS = 356518793;
- field @AddedInOrBefore int SEAT_BACKREST_ANGLE_2_MOVE = 356518794;
- field @AddedInOrBefore int SEAT_HEIGHT_POS = 356518795;
- field @AddedInOrBefore int SEAT_HEIGHT_MOVE = 356518796;
- field @AddedInOrBefore int SEAT_DEPTH_POS = 356518797;
- field @AddedInOrBefore int SEAT_DEPTH_MOVE = 356518798;
- field @AddedInOrBefore int SEAT_TILT_POS = 356518799;
- field @AddedInOrBefore int SEAT_TILT_MOVE = 356518800;
- field @AddedInOrBefore int SEAT_LUMBAR_FORE_AFT_POS = 356518801;
- field @AddedInOrBefore int SEAT_LUMBAR_FORE_AFT_MOVE = 356518802;
- field @AddedInOrBefore int SEAT_LUMBAR_SIDE_SUPPORT_POS = 356518803;
- field @AddedInOrBefore int SEAT_LUMBAR_SIDE_SUPPORT_MOVE = 356518804;
- field @AddedInOrBefore int SEAT_HEADREST_HEIGHT_POS = 289409941;
- field @AddedInOrBefore int SEAT_HEADREST_HEIGHT_MOVE = 356518806;
- field @AddedInOrBefore int SEAT_HEADREST_ANGLE_POS = 356518807;
- field @AddedInOrBefore int SEAT_HEADREST_ANGLE_MOVE = 356518808;
- field @AddedInOrBefore int SEAT_HEADREST_FORE_AFT_POS = 356518809;
- field @AddedInOrBefore int SEAT_HEADREST_FORE_AFT_MOVE = 356518810;
- field @AddedInOrBefore int SEAT_OCCUPANCY = 356518832;
- field @AddedInOrBefore int WINDOW_POS = 322964416;
- field @AddedInOrBefore int WINDOW_MOVE = 322964417;
- field @AddedInOrBefore int WINDOW_LOCK = 320867268;
- field @AddedInOrBefore int VEHICLE_MAP_SERVICE = 299895808;
- field @AddedInOrBefore int OBD2_LIVE_FRAME = 299896064;
- field @AddedInOrBefore int OBD2_FREEZE_FRAME = 299896065;
- field @AddedInOrBefore int OBD2_FREEZE_FRAME_INFO = 299896066;
- field @AddedInOrBefore int OBD2_FREEZE_FRAME_CLEAR = 299896067;
- field @AddedInOrBefore int HEADLIGHTS_STATE = 289410560;
- field @AddedInOrBefore int HIGH_BEAM_LIGHTS_STATE = 289410561;
- field @AddedInOrBefore int FOG_LIGHTS_STATE = 289410562;
- field @AddedInOrBefore int HAZARD_LIGHTS_STATE = 289410563;
- field @AddedInOrBefore int HEADLIGHTS_SWITCH = 289410576;
- field @AddedInOrBefore int HIGH_BEAM_LIGHTS_SWITCH = 289410577;
- field @AddedInOrBefore int FOG_LIGHTS_SWITCH = 289410578;
- field @AddedInOrBefore int HAZARD_LIGHTS_SWITCH = 289410579;
- field @AddedInOrBefore int CABIN_LIGHTS_STATE = 289410817;
- field @AddedInOrBefore int CABIN_LIGHTS_SWITCH = 289410818;
- field @AddedInOrBefore int READING_LIGHTS_STATE = 356519683;
- field @AddedInOrBefore int READING_LIGHTS_SWITCH = 356519684;
- field @hide @AddedInOrBefore int INITIAL_USER_INFO = 299896583;
- field @hide @AddedInOrBefore int SWITCH_USER = 299896584;
- field @hide @AddedInOrBefore int CREATE_USER = 299896585;
- field @hide @AddedInOrBefore int REMOVE_USER = 299896586;
- field @hide @AddedInOrBefore int USER_IDENTIFICATION_ASSOCIATION = 299896587;
- field @hide @AddedInOrBefore int POWER_POLICY_REQ = 286265121;
- field @hide @AddedInOrBefore int POWER_POLICY_GROUP_REQ = 286265122;
- field @hide @AddedInOrBefore int CURRENT_POWER_POLICY = 286265123;
- field @hide @AddedInOrBefore int WATCHDOG_ALIVE = 290459441;
- field @hide @AddedInOrBefore int WATCHDOG_TERMINATED_PROCESS = 299896626;
- field @hide @AddedInOrBefore int VHAL_HEARTBEAT = 290459443;
- field @hide @AddedInOrBefore int CLUSTER_SWITCH_UI = 289410868;
- field @hide @AddedInOrBefore int CLUSTER_DISPLAY_STATE = 289476405;
- field @hide @AddedInOrBefore int CLUSTER_REPORT_STATE = 299896630;
- field @hide @AddedInOrBefore int CLUSTER_REQUEST_DISPLAY = 289410871;
- field @hide @AddedInOrBefore int CLUSTER_NAVIGATION_STATE = 292556600;
- field @AddedInOrBefore int EPOCH_TIME = 290457094;
- field @AddedInOrBefore int STORAGE_ENCRYPTION_BINDING_SEED = 292554247;
- field @AddedInOrBefore int ELECTRONIC_TOLL_COLLECTION_CARD_TYPE = 289410873;
- field @AddedInOrBefore int ELECTRONIC_TOLL_COLLECTION_CARD_STATUS = 289410874;
- field @AddedInOrBefore int FRONT_FOG_LIGHTS_STATE = 289410875;
- field @AddedInOrBefore int FRONT_FOG_LIGHTS_SWITCH = 289410876;
- field @AddedInOrBefore int REAR_FOG_LIGHTS_STATE = 289410877;
- field @AddedInOrBefore int REAR_FOG_LIGHTS_SWITCH = 289410878;
- field @AddedInOrBefore int EV_CHARGE_CURRENT_DRAW_LIMIT = 291508031;
- field @AddedInOrBefore int EV_CHARGE_PERCENT_LIMIT = 291508032;
- field @AddedInOrBefore int EV_CHARGE_STATE = 289410881;
- field @AddedInOrBefore int EV_CHARGE_SWITCH = 287313730;
- field @AddedInOrBefore int EV_CHARGE_TIME_REMAINING = 289410883;
- field @AddedInOrBefore int EV_REGENERATIVE_BRAKING_STATE = 289410884;
- field @AddedInOrBefore int VEHICLE_CURB_WEIGHT = 289410886;
- field @AddedInOrBefore int TRAILER_PRESENT = 289410885;
- method @AddedInOrBefore String toString(int property);
-class VehicleUnit package android.car
- field @hide @SystemApi @AddedInOrBefore int SHOULD_NOT_USE = 0x000;
- field @hide @SystemApi @AddedInOrBefore int RPM = 0x02;
- field @hide @SystemApi @AddedInOrBefore int HERTZ = 0x03;
- field @hide @SystemApi @AddedInOrBefore int PERCENTILE = 0x10;
- field @hide @SystemApi @AddedInOrBefore int NANO_SECS = 0x50;
- field @hide @SystemApi @AddedInOrBefore int SECS = 0x53;
- field @hide @SystemApi @AddedInOrBefore int YEAR = 0x59;
- field @hide @SystemApi @AddedInOrBefore int MILLIAMPERE = 0x61;
- field @hide @SystemApi @AddedInOrBefore int MILLIVOLT = 0x62;
- field @hide @SystemApi @AddedInOrBefore int MILLIWATTS = 0x63;
- field @hide @SystemApi @AddedInOrBefore int DEGREES = 0x80;
- field @AddedInOrBefore int MILLIMETER = 0x20;
- field @AddedInOrBefore int METER = 0x21;
- field @AddedInOrBefore int KILOMETER = 0x23;
- field @AddedInOrBefore int MILE = 0x24;
- field @AddedInOrBefore int CELSIUS = 0x30;
- field @AddedInOrBefore int FAHRENHEIT = 0x31;
- field @AddedInOrBefore int KELVIN = 0x32;
- field @AddedInOrBefore int MILLILITER = 0x40;
- field @AddedInOrBefore int LITER = 0x41;
- field @AddedInOrBefore int US_GALLON = 0x42;
- field @AddedInOrBefore int IMPERIAL_GALLON = 0x43;
- field @AddedInOrBefore int WATT_HOUR = 0x60;
- field @AddedInOrBefore int AMPERE_HOURS = 0x64;
- field @AddedInOrBefore int KILOWATT_HOUR = 0x65;
- field @AddedInOrBefore int KILOPASCAL = 0x70;
- field @AddedInOrBefore int PSI = 0x71;
- field @AddedInOrBefore int BAR = 0x72;
- field @AddedInOrBefore int METER_PER_SEC = 0x01;
- field @AddedInOrBefore int MILES_PER_HOUR = 0x90;
- field @AddedInOrBefore int KILOMETERS_PER_HOUR = 0x91;
-class @hide CarPerformanceManager package android.car.os
- method @hide @AddedInOrBefore void onCarDisconnected();
- method @AddedInOrBefore void addCpuAvailabilityChangeListener(Executor executor, CpuAvailabilityMonitoringConfig config, CpuAvailabilityChangeListener listener);
- method @AddedInOrBefore void removeCpuAvailabilityChangeListener(Executor executor, CpuAvailabilityChangeListener listener);
-interface CarPerformanceManager.CpuAvailabilityChangeListener package android.car.os
- method @AddedInOrBefore void onCpuAvailabilityChange(CpuAvailabilityInfo info);
-class @hide CpuAvailabilityMonitoringConfig package android.car.os
- field @AddedInOrBefore int CPUSET_ALL = 1;
- field @AddedInOrBefore int CPUSET_BACKGROUND = 2;
- field @AddedInOrBefore int IGNORE_PERCENT_LOWER_BOUND = 0;
- field @AddedInOrBefore int IGNORE_PERCENT_UPPER_BOUND = 100;
- field @AddedInOrBefore int MONITORING_TIMEOUT_NEVER = -1;
- field @AddedInOrBefore int TIMEOUT_ACTION_NOTIFICATION = 1;
- field @AddedInOrBefore int TIMEOUT_ACTION_REMOVE = 2;
- field @AddedInOrBefore Parcelable.Creator<CpuAvailabilityMonitoringConfig> CREATOR;
- method @hide @AddedInOrBefore String cpusetToString(int value);
- method @hide @AddedInOrBefore String ignorePercentToString(int value);
- method @hide @AddedInOrBefore String timeoutActionToString(int value);
- method @AddedInOrBefore int getCpuset();
- method @AddedInOrBefore int getLowerBoundPercent();
- method @AddedInOrBefore int getUpperBoundPercent();
- method @AddedInOrBefore long getTimeoutInSeconds();
- method @AddedInOrBefore int getTimeoutAction();
- method @AddedInOrBefore String toString();
- method @AddedInOrBefore void writeToParcel(android.os.Parcel dest, int flags);
- method @AddedInOrBefore int describeContents();
-class CpuAvailabilityMonitoringConfig.Builder package android.car.os
- method @AddedInOrBefore Builder setCpuset(int value);
- method @AddedInOrBefore Builder setLowerBoundPercent(int value);
- method @AddedInOrBefore Builder setUpperBoundPercent(int value);
- method @AddedInOrBefore Builder setTimeoutInSeconds(long value);
- method @AddedInOrBefore Builder setTimeoutAction(int value);
- method @AddedInOrBefore CpuAvailabilityMonitoringConfig build();
-class @hide CpuAvailabilityInfo package android.car.os
- field @AddedInOrBefore Parcelable.Creator<CpuAvailabilityInfo> CREATOR;
- method @AddedInOrBefore int getCpuset();
- method @AddedInOrBefore int getAverageAvailabilityPercent();
- method @AddedInOrBefore boolean isTimeout();
- method @AddedInOrBefore String toString();
- method @AddedInOrBefore void writeToParcel(android.os.Parcel dest, int flags);
- method @AddedInOrBefore int describeContents();
-class @hide CpuAvailabilityInfo.Builder package android.car.os
- method @AddedInOrBefore Builder setCpuset(int value);
- method @AddedInOrBefore Builder setAverageAvailabilityPercent(int value);
- method @AddedInOrBefore Builder setTimeout(boolean value);
- method @AddedInOrBefore CpuAvailabilityInfo build();
-class ResourceOveruseStats package android.car.watchdog
- field @AddedInOrBefore Parcelable.Creator<ResourceOveruseStats> CREATOR;
- method @AddedInOrBefore String getPackageName();
- method @AddedInOrBefore UserHandle getUserHandle();
- method @AddedInOrBefore IoOveruseStats getIoOveruseStats();
- method @AddedInOrBefore String toString();
- method @AddedInOrBefore void writeToParcel(android.os.Parcel dest, int flags);
- method @AddedInOrBefore int describeContents();
-class @hide ResourceOveruseStats.Builder package android.car.watchdog
- method @AddedInOrBefore Builder setPackageName(String value);
- method @AddedInOrBefore Builder setUserHandle(UserHandle value);
- method @AddedInOrBefore Builder setIoOveruseStats(IoOveruseStats value);
- method @AddedInOrBefore ResourceOveruseStats build();
-class @hide @SystemApi IoOveruseAlertThreshold package android.car.watchdog
- field @AddedInOrBefore Parcelable.Creator<IoOveruseAlertThreshold> CREATOR;
- method @AddedInOrBefore long getDurationInSeconds();
- method @AddedInOrBefore long getWrittenBytesPerSecond();
- method @AddedInOrBefore String toString();
- method @AddedInOrBefore void writeToParcel(android.os.Parcel dest, int flags);
- method @AddedInOrBefore int describeContents();
-class IoOveruseStats package android.car.watchdog
- field @AddedInOrBefore Parcelable.Creator<IoOveruseStats> CREATOR;
- method @AddedInOrBefore long getStartTime();
- method @AddedInOrBefore long getDurationInSeconds();
- method @AddedInOrBefore long getTotalOveruses();
- method @AddedInOrBefore long getTotalTimesKilled();
- method @AddedInOrBefore long getTotalBytesWritten();
- method @AddedInOrBefore boolean isKillableOnOveruse();
- method @AddedInOrBefore PerStateBytes getRemainingWriteBytes();
- method @AddedInOrBefore String toString();
- method @AddedInOrBefore void writeToParcel(android.os.Parcel dest, int flags);
- method @AddedInOrBefore int describeContents();
-class @hide IoOveruseStats.Builder package android.car.watchdog
- method @AddedInOrBefore Builder setStartTime(long value);
- method @AddedInOrBefore Builder setDurationInSeconds(long value);
- method @AddedInOrBefore Builder setTotalOveruses(long value);
- method @AddedInOrBefore Builder setTotalTimesKilled(long value);
- method @AddedInOrBefore Builder setTotalBytesWritten(long value);
- method @AddedInOrBefore Builder setKillableOnOveruse(boolean value);
- method @AddedInOrBefore Builder setRemainingWriteBytes(PerStateBytes value);
- method @AddedInOrBefore IoOveruseStats build();
-class CarWatchdogManager package android.car.watchdog
- field @hide @SystemApi @AddedInOrBefore int TIMEOUT_CRITICAL = 0;
- field @hide @SystemApi @AddedInOrBefore int TIMEOUT_MODERATE = 1;
- field @hide @SystemApi @AddedInOrBefore int TIMEOUT_NORMAL = 2;
- field @AddedInOrBefore int STATS_PERIOD_CURRENT_DAY = 1;
- field @AddedInOrBefore int STATS_PERIOD_PAST_3_DAYS = 2;
- field @AddedInOrBefore int STATS_PERIOD_PAST_7_DAYS = 3;
- field @AddedInOrBefore int STATS_PERIOD_PAST_15_DAYS = 4;
- field @AddedInOrBefore int STATS_PERIOD_PAST_30_DAYS = 5;
- field @AddedInOrBefore int FLAG_RESOURCE_OVERUSE_IO = 1 << 0;
- field @hide @SystemApi @AddedInOrBefore int FLAG_MINIMUM_STATS_IO_1_MB = 1 << 0;
- field @hide @SystemApi @AddedInOrBefore int FLAG_MINIMUM_STATS_IO_100_MB = 1 << 1;
- field @hide @SystemApi @AddedInOrBefore int FLAG_MINIMUM_STATS_IO_1_GB = 1 << 2;
- field @hide @SystemApi @AddedInOrBefore int RETURN_CODE_SUCCESS = 0;
- field @hide @SystemApi @AddedInOrBefore int RETURN_CODE_ERROR = -1;
- method @hide @SystemApi @AddedInOrBefore void registerClient(Executor executor, CarWatchdogClientCallback client, int timeout);
- method @hide @SystemApi @AddedInOrBefore void unregisterClient(CarWatchdogClientCallback client);
- method @hide @SystemApi @AddedInOrBefore void tellClientAlive(CarWatchdogClientCallback client, int sessionId);
- method @AddedInOrBefore ResourceOveruseStats getResourceOveruseStats(int resourceOveruseFlag, int maxStatsPeriod);
- method @hide @SystemApi @AddedInOrBefore List<ResourceOveruseStats> getAllResourceOveruseStats(int resourceOveruseFlag, int minimumStatsFlag, int maxStatsPeriod);
- method @hide @SystemApi @AddedInOrBefore ResourceOveruseStats getResourceOveruseStatsForUserPackage(String packageName, UserHandle userHandle, int resourceOveruseFlag, int maxStatsPeriod);
- method @AddedInOrBefore void addResourceOveruseListener(Executor executor, int resourceOveruseFlag, ResourceOveruseListener listener);
- method @AddedInOrBefore void removeResourceOveruseListener(ResourceOveruseListener listener);
- method @hide @SystemApi @AddedInOrBefore void addResourceOveruseListenerForSystem(Executor executor, int resourceOveruseFlag, ResourceOveruseListener listener);
- method @hide @SystemApi @AddedInOrBefore void removeResourceOveruseListenerForSystem(ResourceOveruseListener listener);
- method @hide @SystemApi @AddedInOrBefore void setKillablePackageAsUser(String packageName, UserHandle userHandle, boolean isKillable);
- method @hide @SystemApi @AddedInOrBefore List<PackageKillableState> getPackageKillableStatesAsUser(UserHandle userHandle);
- method @hide @SystemApi @AddedInOrBefore int setResourceOveruseConfigurations(List<ResourceOveruseConfiguration> configurations, int resourceOveruseFlag);
- method @hide @SystemApi @AddedInOrBefore List<ResourceOveruseConfiguration> getResourceOveruseConfigurations(int resourceOveruseFlag);
- method @hide @AddedInOrBefore void onCarDisconnected();
-class @hide @SystemApi CarWatchdogManager.CarWatchdogClientCallback package android.car.watchdog
- method @AddedInOrBefore boolean onCheckHealthStatus(int sessionId, int timeout);
- method @AddedInOrBefore void onPrepareProcessTermination();
-interface CarWatchdogManager.ResourceOveruseListener package android.car.watchdog
- method @AddedInOrBefore void onOveruse(ResourceOveruseStats resourceOveruseStats);
-class @hide @SystemApi IoOveruseConfiguration package android.car.watchdog
- field @AddedInOrBefore Parcelable.Creator<IoOveruseConfiguration> CREATOR;
- method @AddedInOrBefore PerStateBytes getComponentLevelThresholds();
- method @AddedInOrBefore Map<String,PerStateBytes> getPackageSpecificThresholds();
- method @AddedInOrBefore Map<String,PerStateBytes> getAppCategorySpecificThresholds();
- method @AddedInOrBefore List<IoOveruseAlertThreshold> getSystemWideThresholds();
- method @AddedInOrBefore String toString();
- method @AddedInOrBefore void writeToParcel(android.os.Parcel dest, int flags);
- method @AddedInOrBefore int describeContents();
-class IoOveruseConfiguration.Builder package android.car.watchdog
- method @AddedInOrBefore Builder setComponentLevelThresholds(PerStateBytes value);
- method @AddedInOrBefore Builder setPackageSpecificThresholds(Map<String,PerStateBytes> value);
- method @AddedInOrBefore Builder addPackageSpecificThresholds(String key, PerStateBytes value);
- method @AddedInOrBefore Builder setAppCategorySpecificThresholds(Map<String,PerStateBytes> value);
- method @AddedInOrBefore Builder addAppCategorySpecificThresholds(String key, PerStateBytes value);
- method @AddedInOrBefore Builder setSystemWideThresholds(List<IoOveruseAlertThreshold> value);
- method @AddedInOrBefore Builder addSystemWideThresholds(IoOveruseAlertThreshold value);
- method @AddedInOrBefore IoOveruseConfiguration build();
-class @hide @SystemApi ResourceOveruseConfiguration package android.car.watchdog
- field @AddedInOrBefore int COMPONENT_TYPE_SYSTEM = 1;
- field @AddedInOrBefore int COMPONENT_TYPE_VENDOR = 2;
- field @AddedInOrBefore int COMPONENT_TYPE_THIRD_PARTY = 3;
- field @AddedInOrBefore String APPLICATION_CATEGORY_TYPE_MAPS = "android.car.watchdog.app.category.MAPS";
- field @AddedInOrBefore String APPLICATION_CATEGORY_TYPE_MEDIA = "android.car.watchdog.app.category.MEDIA";
- field @AddedInOrBefore Parcelable.Creator<ResourceOveruseConfiguration> CREATOR;
- method @hide @AddedInOrBefore String componentTypeToString(int value);
- method @AddedInOrBefore int getComponentType();
- method @AddedInOrBefore List<String> getSafeToKillPackages();
- method @AddedInOrBefore List<String> getVendorPackagePrefixes();
- method @AddedInOrBefore Map<String,String> getPackagesToAppCategoryTypes();
- method @AddedInOrBefore IoOveruseConfiguration getIoOveruseConfiguration();
- method @AddedInOrBefore String toString();
- method @AddedInOrBefore void writeToParcel(android.os.Parcel dest, int flags);
- method @AddedInOrBefore int describeContents();
-class ResourceOveruseConfiguration.Builder package android.car.watchdog
- method @AddedInOrBefore Builder setComponentType(int value);
- method @AddedInOrBefore Builder setSafeToKillPackages(List<String> value);
- method @AddedInOrBefore Builder addSafeToKillPackages(String value);
- method @AddedInOrBefore Builder setVendorPackagePrefixes(List<String> value);
- method @AddedInOrBefore Builder addVendorPackagePrefixes(String value);
- method @AddedInOrBefore Builder setPackagesToAppCategoryTypes(Map<String,String> value);
- method @AddedInOrBefore Builder addPackagesToAppCategoryTypes(String key, String value);
- method @AddedInOrBefore Builder setIoOveruseConfiguration(IoOveruseConfiguration value);
- method @AddedInOrBefore ResourceOveruseConfiguration build();
-class PerStateBytes package android.car.watchdog
- field @AddedInOrBefore Parcelable.Creator<PerStateBytes> CREATOR;
- method @AddedInOrBefore long getForegroundModeBytes();
- method @AddedInOrBefore long getBackgroundModeBytes();
- method @AddedInOrBefore long getGarageModeBytes();
- method @AddedInOrBefore String toString();
- method @AddedInOrBefore void writeToParcel(android.os.Parcel dest, int flags);
- method @AddedInOrBefore int describeContents();
-class @hide @SystemApi PackageKillableState package android.car.watchdog
- field @AddedInOrBefore int KILLABLE_STATE_YES = 1;
- field @AddedInOrBefore int KILLABLE_STATE_NO = 2;
- field @AddedInOrBefore int KILLABLE_STATE_NEVER = 3;
- field @AddedInOrBefore Parcelable.Creator<PackageKillableState> CREATOR;
- method @hide @AddedInOrBefore String killableStateToString(int value);
- method @AddedInOrBefore String getPackageName();
- method @AddedInOrBefore int getUserId();
- method @AddedInOrBefore int getKillableState();
- method @AddedInOrBefore String toString();
- method @AddedInOrBefore void writeToParcel(android.os.Parcel dest, int flags);
- method @AddedInOrBefore int describeContents();
-class CarAppFocusManager package android.car
- field @AddedInOrBefore int APP_FOCUS_TYPE_NAVIGATION = 1;
- field @AddedInOrBefore int APP_FOCUS_TYPE_VOICE_COMMAND = 2;
- field @hide @AddedInOrBefore int APP_FOCUS_MAX = 2;
- field @AddedInOrBefore int APP_FOCUS_REQUEST_FAILED = 0;
- field @AddedInOrBefore int APP_FOCUS_REQUEST_SUCCEEDED = 1;
- method @AddedInOrBefore void addFocusListener(OnAppFocusChangedListener listener, int appType);
- method @AddedInOrBefore void removeFocusListener(OnAppFocusChangedListener listener, int appType);
- method @AddedInOrBefore void removeFocusListener(OnAppFocusChangedListener listener);
- method @hide @AddedInOrBefore int[] getActiveAppTypes();
- method @hide @AddedInOrBefore List<String> getAppTypeOwner(int appType);
- method @AddedInOrBefore boolean isOwningFocus(OnAppFocusOwnershipCallback callback, int appType);
- method @AddedInOrBefore int requestAppFocus(int appType, OnAppFocusOwnershipCallback ownershipCallback);
- method @AddedInOrBefore void abandonAppFocus(OnAppFocusOwnershipCallback ownershipCallback, int appType);
- method @AddedInOrBefore void abandonAppFocus(OnAppFocusOwnershipCallback ownershipCallback);
- method @hide @AddedInOrBefore void onCarDisconnected();
-interface CarAppFocusManager.OnAppFocusChangedListener package android.car
- method @AddedInOrBefore void onAppFocusChanged(int appType, boolean active);
-interface CarAppFocusManager.OnAppFocusOwnershipCallback package android.car
- method @AddedInOrBefore void onAppFocusOwnershipLost(int appType);
- method @AddedInOrBefore void onAppFocusOwnershipGranted(int appType);
diff --git a/tools/GenericCarApiBuilder/complete_car_api_list.txt b/tools/GenericCarApiBuilder/complete_car_api_list.txt
new file mode 100644
index 0000000..33eefe4
--- /dev/null
+++ b/tools/GenericCarApiBuilder/complete_car_api_list.txt
@@ -0,0 +1,2930 @@
+class @hide @SystemApi VehicleAreaDoor package android.car
+ field TIRAMISU_0 int DOOR_ROW_1_LEFT = 0x00000001;
+ field TIRAMISU_0 int DOOR_ROW_1_RIGHT = 0x00000004;
+ field TIRAMISU_0 int DOOR_ROW_2_LEFT = 0x00000010;
+ field TIRAMISU_0 int DOOR_ROW_2_RIGHT = 0x00000040;
+ field TIRAMISU_0 int DOOR_ROW_3_LEFT = 0x00000100;
+ field TIRAMISU_0 int DOOR_ROW_3_RIGHT = 0x00000400;
+ field TIRAMISU_0 int DOOR_HOOD = 0x10000000;
+ field TIRAMISU_0 int DOOR_REAR = 0x20000000;
+class @hiddenOnly @hide CarTransactionException package android.car
+class @hiddenOnly @hide DriverMonitoringDetection package android.car.occupantawareness
+ field TIRAMISU_0 int confidenceLevel;
+ field TIRAMISU_0 boolean isLookingOnRoad;
+ field TIRAMISU_0 long gazeDurationMillis;
+ field TIRAMISU_0 Parcelable.Creator<DriverMonitoringDetection> CREATOR;
+ method TIRAMISU_0 int describeContents();
+ method TIRAMISU_0 String toString();
+ method TIRAMISU_0 void writeToParcel(Parcel dest, int flags);
+class @hiddenOnly @hide OccupantAwarenessDetection package android.car.occupantawareness
+ field TIRAMISU_0 int VEHICLE_OCCUPANT_NONE = 0;
+ field TIRAMISU_0 int VEHICLE_OCCUPANT_DRIVER = 1 << 2;
+ field TIRAMISU_0 int VEHICLE_OCCUPANT_FRONT_PASSENGER = 1 << 1;
+ field TIRAMISU_0 int VEHICLE_OCCUPANT_ROW_2_PASSENGER_LEFT = 1 << 3;
+ field TIRAMISU_0 int VEHICLE_OCCUPANT_ROW_2_PASSENGER_CENTER = 1 << 4;
+ field TIRAMISU_0 int VEHICLE_OCCUPANT_ROW_2_PASSENGER_RIGHT = 1 << 5;
+ field TIRAMISU_0 int VEHICLE_OCCUPANT_ROW_3_PASSENGER_LEFT = 1 << 6;
+ field TIRAMISU_0 int VEHICLE_OCCUPANT_ROW_3_PASSENGER_CENTER = 1 << 7;
+ field TIRAMISU_0 int VEHICLE_OCCUPANT_ROW_3_PASSENGER_RIGHT = 1 << 8;
+ field TIRAMISU_0 int VEHICLE_OCCUPANT_ALL_FRONT_OCCUPANTS = VEHICLE_OCCUPANT_DRIVER | VEHICLE_OCCUPANT_FRONT_PASSENGER;
+ field TIRAMISU_0 int VEHICLE_OCCUPANT_ALL_ROW_2_OCCUPANTS = VEHICLE_OCCUPANT_ROW_2_PASSENGER_LEFT | VEHICLE_OCCUPANT_ROW_2_PASSENGER_RIGHT | VEHICLE_OCCUPANT_ROW_2_PASSENGER_CENTER;
+ field TIRAMISU_0 int VEHICLE_OCCUPANT_ALL_ROW_3_OCCUPANTS = VEHICLE_OCCUPANT_ROW_3_PASSENGER_LEFT | VEHICLE_OCCUPANT_ROW_3_PASSENGER_RIGHT | VEHICLE_OCCUPANT_ROW_3_PASSENGER_CENTER;
+ field TIRAMISU_0 int VEHICLE_OCCUPANT_ALL_OCCUPANTS = VEHICLE_OCCUPANT_ALL_FRONT_OCCUPANTS | VEHICLE_OCCUPANT_ALL_ROW_2_OCCUPANTS | VEHICLE_OCCUPANT_ALL_ROW_3_OCCUPANTS;
+ field TIRAMISU_0 int CONFIDENCE_LEVEL_NONE = 0;
+ field TIRAMISU_0 int CONFIDENCE_LEVEL_LOW = 1;
+ field TIRAMISU_0 int CONFIDENCE_LEVEL_HIGH = 2;
+ field TIRAMISU_0 int CONFIDENCE_LEVEL_MAX = 3;
+ field TIRAMISU_0 int role;
+ field TIRAMISU_0 long timestampMillis;
+ field TIRAMISU_0 boolean isPresent;
+ field TIRAMISU_0 GazeDetection gazeDetection;
+ field TIRAMISU_0 DriverMonitoringDetection driverMonitoringDetection;
+ field TIRAMISU_0 Parcelable.Creator<OccupantAwarenessDetection> CREATOR;
+ method TIRAMISU_0 int describeContents();
+ method TIRAMISU_0 void writeToParcel(Parcel dest, int flags);
+ method TIRAMISU_0 String toString();
+class @hiddenOnly @hide Point3D package android.car.occupantawareness
+ field TIRAMISU_0 double x;
+ field TIRAMISU_0 double y;
+ field TIRAMISU_0 double z;
+ field TIRAMISU_0 Parcelable.Creator<Point3D> CREATOR;
+ method TIRAMISU_0 int describeContents();
+ method TIRAMISU_0 void writeToParcel(Parcel dest, int flags);
+ method TIRAMISU_0 String toString();
+class @hiddenOnly @hide SystemStatusEvent package android.car.occupantawareness
+ field TIRAMISU_0 int SYSTEM_STATUS_READY = 0;
+ field TIRAMISU_0 int SYSTEM_STATUS_NOT_SUPPORTED = 1;
+ field TIRAMISU_0 int SYSTEM_STATUS_NOT_READY = 2;
+ field TIRAMISU_0 int SYSTEM_STATUS_SYSTEM_FAILURE = 3;
+ field TIRAMISU_0 int DETECTION_TYPE_NONE = 0;
+ field TIRAMISU_0 int DETECTION_TYPE_PRESENCE = 1 << 0;
+ field TIRAMISU_0 int DETECTION_TYPE_GAZE = 1 << 1;
+ field TIRAMISU_0 int DETECTION_TYPE_DRIVER_MONITORING = 1 << 2;
+ field TIRAMISU_0 int systemStatus;
+ field TIRAMISU_0 int detectionType;
+ field TIRAMISU_0 Parcelable.Creator<SystemStatusEvent> CREATOR;
+ method TIRAMISU_0 int describeContents();
+ method TIRAMISU_0 void writeToParcel(Parcel dest, int flags);
+ method TIRAMISU_0 String toString();
+class @hiddenOnly @hide GazeDetection package android.car.occupantawareness
+ field TIRAMISU_0 int VEHICLE_REGION_UNKNOWN = 0;
+ field TIRAMISU_0 int VEHICLE_REGION_CENTER_INSTRUMENT_CLUSTER = 1;
+ field TIRAMISU_0 int VEHICLE_REGION_REAR_VIEW_MIRROR = 2;
+ field TIRAMISU_0 int VEHICLE_REGION_LEFT_SIDE_MIRROR = 3;
+ field TIRAMISU_0 int VEHICLE_REGION_RIGHT_SIDE_MIRROR = 4;
+ field TIRAMISU_0 int VEHICLE_REGION_FORWARD_ROADWAY = 5;
+ field TIRAMISU_0 int VEHICLE_REGION_LEFT_ROADWAY = 6;
+ field TIRAMISU_0 int VEHICLE_REGION_RIGHT_ROADWAY = 7;
+ field TIRAMISU_0 int VEHICLE_REGION_HEAD_UNIT_DISPLAY = 8;
+ field TIRAMISU_0 int confidenceLevel;
+ field TIRAMISU_0 Point3D leftEyePosition;
+ field TIRAMISU_0 Point3D rightEyePosition;
+ field TIRAMISU_0 Point3D headAngleUnitVector;
+ field TIRAMISU_0 Point3D gazeAngleUnitVector;
+ field TIRAMISU_0 int gazeTarget;
+ field TIRAMISU_0 long durationOnTargetMillis;
+ field TIRAMISU_0 Parcelable.Creator<GazeDetection> CREATOR;
+ method TIRAMISU_0 int describeContents();
+ method TIRAMISU_0 void writeToParcel(Parcel dest, int flags);
+ method TIRAMISU_0 String toString();
+class @hiddenOnly @hide OccupantAwarenessManager package android.car.occupantawareness
+ method TIRAMISU_0 @hiddenOnly void onCarDisconnected();
+ method TIRAMISU_0 int getCapabilityForRole(int role);
+ method TIRAMISU_0 void registerChangeCallback(ChangeCallback callback);
+ method TIRAMISU_0 void unregisterChangeCallback();
+class OccupantAwarenessManager.ChangeCallback package android.car.occupantawareness
+ method TIRAMISU_0 void onSystemStateChanged(SystemStatusEvent systemStatus);
+ method TIRAMISU_0 void onDetectionEvent(OccupantAwarenessDetection event);
+class @hiddenOnly @hide VehicleOilLevel package android.car
+ field TIRAMISU_0 int CRITICALLY_LOW = 0;
+ field TIRAMISU_0 int LOW = 1;
+ field TIRAMISU_0 int NORMAL = 2;
+ field TIRAMISU_0 int HIGH = 3;
+ field TIRAMISU_0 int ERROR = 4;
+class @hiddenOnly @hide VehiclePropertyType package android.car
+ field TIRAMISU_0 int STRING = 0x00100000;
+ field TIRAMISU_0 int BOOLEAN = 0x00200000;
+ field TIRAMISU_0 int INT32 = 0x00400000;
+ field TIRAMISU_0 int INT32_VEC = 0x00410000;
+ field TIRAMISU_0 int INT64 = 0x00500000;
+ field TIRAMISU_0 int INT64_VEC = 0x00510000;
+ field TIRAMISU_0 int FLOAT = 0x00600000;
+ field TIRAMISU_0 int FLOAT_VEC = 0x00610000;
+ field TIRAMISU_0 int BYTES = 0x00700000;
+ field TIRAMISU_0 int MIXED = 0x00e00000;
+ field TIRAMISU_0 int MASK = 0x00ff0000;
+class @hide @SystemApi ProjectionStatus package android.car.projection
+ field TIRAMISU_0 int PROJECTION_STATE_INACTIVE = 0;
+ field TIRAMISU_0 int PROJECTION_STATE_READY_TO_PROJECT = 1;
+ field TIRAMISU_0 int PROJECTION_STATE_ACTIVE_FOREGROUND = 2;
+ field TIRAMISU_0 int PROJECTION_STATE_ACTIVE_BACKGROUND = 3;
+ field TIRAMISU_0 int PROJECTION_TRANSPORT_NONE = 0;
+ field TIRAMISU_0 int PROJECTION_TRANSPORT_USB = 1;
+ field TIRAMISU_0 int PROJECTION_TRANSPORT_WIFI = 2;
+ field TIRAMISU_0 Creator<ProjectionStatus> CREATOR;
+ method TIRAMISU_0 int describeContents();
+ method TIRAMISU_0 void writeToParcel(Parcel dest, int flags);
+ method TIRAMISU_0 int getState();
+ method TIRAMISU_0 String getPackageName();
+ method TIRAMISU_0 Bundle getExtras();
+ method TIRAMISU_0 boolean isActive();
+ method TIRAMISU_0 int getTransport();
+ method TIRAMISU_0 List<MobileDevice> getConnectedMobileDevices();
+ method TIRAMISU_0 Builder builder(String packageName, int state);
+ method TIRAMISU_0 String toString();
+class ProjectionStatus.Builder package android.car.projection
+ method TIRAMISU_0 Builder setProjectionTransport(int transport);
+ method TIRAMISU_0 Builder addMobileDevice(MobileDevice mobileDevice);
+ method TIRAMISU_0 Builder setExtras(Bundle extras);
+ method TIRAMISU_0 ProjectionStatus build();
+class ProjectionStatus.MobileDevice package android.car.projection
+ field TIRAMISU_0 Creator<MobileDevice> CREATOR;
+ method TIRAMISU_0 void writeToParcel(Parcel dest, int flags);
+ method TIRAMISU_0 int getId();
+ method TIRAMISU_0 String getName();
+ method TIRAMISU_0 List<Integer> getAvailableTransports();
+ method TIRAMISU_0 boolean isProjecting();
+ method TIRAMISU_0 Bundle getExtras();
+ method TIRAMISU_0 int describeContents();
+ method TIRAMISU_0 Builder builder(int id, String name);
+ method TIRAMISU_0 String toString();
+class ProjectionStatus.MobileDevice.Builder package android.car.projection
+ method TIRAMISU_0 Builder addTransport(int transport);
+ method TIRAMISU_0 Builder setProjecting(boolean projecting);
+ method TIRAMISU_0 Builder setExtras(Bundle extras);
+ method TIRAMISU_0 MobileDevice build();
+class @hide @SystemApi ProjectionOptions package android.car.projection
+ field TIRAMISU_0 int UI_MODE_FULL_SCREEN = 0;
+ field TIRAMISU_0 int UI_MODE_BLENDED = 1;
+ field TIRAMISU_0 int AP_MODE_NOT_SPECIFIED = 0;
+ field TIRAMISU_0 int AP_MODE_TETHERED = 1;
+ field TIRAMISU_0 int AP_MODE_LOHS_DYNAMIC_CREDENTIALS = 2;
+ field TIRAMISU_0 int AP_MODE_LOHS_STATIC_CREDENTIALS = 3;
+ method TIRAMISU_0 int getUiMode();
+ method TIRAMISU_0 int getProjectionAccessPointMode();
+ method TIRAMISU_0 ActivityOptions getActivityOptions();
+ method TIRAMISU_0 ComponentName getConsentActivity();
+ method TIRAMISU_0 Bundle toBundle();
+ method TIRAMISU_0 @hiddenOnly Builder builder();
+ method TIRAMISU_0 @hiddenOnly String toString();
+class @hiddenOnly @hide ProjectionOptions.Builder package android.car.projection
+ method TIRAMISU_0 Builder setProjectionActivityOptions(ActivityOptions activityOptions);
+ method TIRAMISU_0 Builder setUiMode(int uiMode);
+ method TIRAMISU_0 Builder setConsentActivity(ComponentName consentActivity);
+ method TIRAMISU_0 Builder setAccessPointMode(int accessPointMode);
+ method TIRAMISU_0 ProjectionOptions build();
+class @hide @SystemApi CarEvsManager package android.car.evs
+ field TIRAMISU_0 String EXTRA_SESSION_TOKEN = "android.car.evs.extra.SESSION_TOKEN";
+ field TIRAMISU_0 int SERVICE_TYPE_REARVIEW = 0;
+ field TIRAMISU_0 int SERVICE_TYPE_SURROUNDVIEW = 1;
+ field TIRAMISU_0 int SERVICE_STATE_UNAVAILABLE = 0;
+ field TIRAMISU_0 int SERVICE_STATE_INACTIVE = 1;
+ field TIRAMISU_0 int SERVICE_STATE_REQUESTED = 2;
+ field TIRAMISU_0 int SERVICE_STATE_ACTIVE = 3;
+ field TIRAMISU_0 int STREAM_EVENT_NONE = 0;
+ field TIRAMISU_0 int STREAM_EVENT_STREAM_STARTED = 1;
+ field TIRAMISU_0 int STREAM_EVENT_STREAM_STOPPED = 2;
+ field TIRAMISU_0 int STREAM_EVENT_FRAME_DROPPED = 3;
+ field TIRAMISU_0 int STREAM_EVENT_TIMEOUT = 4;
+ field TIRAMISU_0 int STREAM_EVENT_PARAMETER_CHANGED = 5;
+ field TIRAMISU_0 int STREAM_EVENT_PRIMARY_OWNER_CHANGED = 6;
+ field TIRAMISU_0 int STREAM_EVENT_OTHER_ERRORS = 7;
+ field TIRAMISU_0 int ERROR_NONE = 0;
+ field TIRAMISU_0 int ERROR_UNAVAILABLE = -1;
+ field TIRAMISU_0 int ERROR_BUSY = -2;
+ method TIRAMISU_0 @hiddenOnly void onCarDisconnected();
+ method TIRAMISU_0 void setStatusListener(Executor executor, CarEvsStatusListener listener);
+ method TIRAMISU_0 void clearStatusListener();
+ method TIRAMISU_0 void returnFrameBuffer(CarEvsBufferDescriptor buffer);
+ method TIRAMISU_0 int startActivity(int type);
+ method TIRAMISU_0 void stopActivity();
+ method TIRAMISU_0 int startVideoStream(int type, IBinder token, Executor executor, CarEvsStreamCallback callback);
+ method TIRAMISU_0 void stopVideoStream();
+ method TIRAMISU_0 CarEvsStatus getCurrentStatus();
+ method TIRAMISU_0 IBinder generateSessionToken();
+ method TIRAMISU_0 boolean isSupported(int type);
+interface CarEvsManager.CarEvsStatusListener package android.car.evs
+ method TIRAMISU_0 void onStatusChanged(CarEvsStatus status);
+interface CarEvsManager.CarEvsStreamCallback package android.car.evs
+ method TIRAMISU_0 void onStreamEvent(int event);
+ method TIRAMISU_0 void onNewFrame(CarEvsBufferDescriptor buffer);
+class @hide @SystemApi CarEvsStatus package android.car.evs
+ field TIRAMISU_0 Parcelable.Creator<CarEvsStatus> CREATOR;
+ method TIRAMISU_0 int describeContents();
+ method TIRAMISU_0 void writeToParcel(Parcel dest, int flags);
+ method TIRAMISU_0 String toString();
+ method TIRAMISU_0 int getState();
+ method TIRAMISU_0 int getServiceType();
+class @hide @SystemApi CarEvsBufferDescriptor package android.car.evs
+ field TIRAMISU_0 Parcelable.Creator<CarEvsBufferDescriptor> CREATOR;
+ method TIRAMISU_0 int describeContents();
+ method TIRAMISU_0 void writeToParcel(Parcel dest, int flags);
+ method TIRAMISU_0 String toString();
+ method TIRAMISU_0 int getId();
+ method TIRAMISU_0 HardwareBuffer getHardwareBuffer();
+class @hide @SystemApi CarMediaManager package android.car.media
+ field TIRAMISU_0 int MEDIA_SOURCE_MODE_PLAYBACK = 0;
+ field TIRAMISU_0 int MEDIA_SOURCE_MODE_BROWSE = 1;
+ method TIRAMISU_0 ComponentName getMediaSource(int mode);
+ method TIRAMISU_0 void setMediaSource(ComponentName componentName, int mode);
+ method TIRAMISU_0 void addMediaSourceListener(MediaSourceChangedListener callback, int mode);
+ method TIRAMISU_0 void removeMediaSourceListener(MediaSourceChangedListener callback, int mode);
+ method TIRAMISU_0 List<ComponentName> getLastMediaSources(int mode);
+ method TIRAMISU_0 @hiddenOnly void onCarDisconnected();
+ method TIRAMISU_0 @hiddenOnly boolean isIndependentPlaybackConfig();
+ method TIRAMISU_0 @hiddenOnly void setIndependentPlaybackConfig(boolean independent);
+interface CarMediaManager.MediaSourceChangedListener package android.car.media
+ method TIRAMISU_0 void onMediaSourceChanged(ComponentName componentName);
+class @hide @SystemApi CarAudioPatchHandle package android.car.media
+ field TIRAMISU_0 Parcelable.Creator<CarAudioPatchHandle> CREATOR;
+ method TIRAMISU_0 String toString();
+ method TIRAMISU_0 void writeToParcel(Parcel out, int flags);
+ method TIRAMISU_0 int describeContents();
+ method TIRAMISU_0 @hiddenOnly String getSourceAddress();
+ method TIRAMISU_0 @hiddenOnly String getSinkAddress();
+ method TIRAMISU_0 @hiddenOnly int getHandleId();
+class CarAudioManager package android.car.media
+ field TIRAMISU_0 int PRIMARY_AUDIO_ZONE = 0x0;
+ field TIRAMISU_0 int INVALID_AUDIO_ZONE = 0xffffffff;
+ field TIRAMISU_0 int AUDIO_FEATURE_DYNAMIC_ROUTING = 0x1;
+ field TIRAMISU_0 int AUDIO_FEATURE_VOLUME_GROUP_MUTING = 0x2;
+ field TIRAMISU_0 @hiddenOnly int INVALID_VOLUME_GROUP_ID = -1;
+ field TIRAMISU_0 String AUDIOFOCUS_EXTRA_RECEIVE_DUCKING_EVENTS = "android.car.media.AUDIOFOCUS_EXTRA_RECEIVE_DUCKING_EVENTS";
+ field TIRAMISU_0 @hiddenOnly String AUDIOFOCUS_EXTRA_REQUEST_ZONE_ID = "android.car.media.AUDIOFOCUS_EXTRA_REQUEST_ZONE_ID";
+ method TIRAMISU_0 @hiddenOnly boolean isDynamicRoutingEnabled();
+ method TIRAMISU_0 boolean isAudioFeatureEnabled(int audioFeature);
+ method TIRAMISU_0 void setGroupVolume(int groupId, int index, int flags);
+ method TIRAMISU_0 void setGroupVolume(int zoneId, int groupId, int index, int flags);
+ method TIRAMISU_0 int getGroupMaxVolume(int groupId);
+ method TIRAMISU_0 int getGroupMaxVolume(int zoneId, int groupId);
+ method TIRAMISU_0 int getGroupMinVolume(int groupId);
+ method TIRAMISU_0 int getGroupMinVolume(int zoneId, int groupId);
+ method TIRAMISU_0 int getGroupVolume(int groupId);
+ method TIRAMISU_0 int getGroupVolume(int zoneId, int groupId);
+ method TIRAMISU_0 void setFadeTowardFront(float value);
+ method TIRAMISU_0 void setBalanceTowardRight(float value);
+ method TIRAMISU_0 String[] getExternalSources();
+ method TIRAMISU_0 CarAudioPatchHandle createAudioPatch(String sourceAddress, int usage, int gainInMillibels);
+ method TIRAMISU_0 void releaseAudioPatch(CarAudioPatchHandle patch);
+ method TIRAMISU_0 int getVolumeGroupCount();
+ method TIRAMISU_0 int getVolumeGroupCount(int zoneId);
+ method TIRAMISU_0 int getVolumeGroupIdForUsage(int usage);
+ method TIRAMISU_0 int getVolumeGroupIdForUsage(int zoneId, int usage);
+ method TIRAMISU_0 int[] getUsagesForVolumeGroupId(int groupId);
+ method TIRAMISU_0 int[] getUsagesForVolumeGroupId(int zoneId, int groupId);
+ method TIRAMISU_0 boolean isPlaybackOnVolumeGroupActive(int zoneId, int groupId);
+ method TIRAMISU_0 List<Integer> getAudioZoneIds();
+ method TIRAMISU_0 @hiddenOnly int getZoneIdForUid(int uid);
+ method TIRAMISU_0 @hiddenOnly boolean setZoneIdForUid(int zoneId, int uid);
+ method TIRAMISU_0 @hiddenOnly boolean clearZoneIdForUid(int uid);
+ method TIRAMISU_0 AudioDeviceInfo getOutputDeviceForUsage(int zoneId, int usage);
+ method TIRAMISU_0 List<AudioDeviceInfo> getInputDevicesForZoneId(int zoneId);
+ method TIRAMISU_0 @hiddenOnly void onCarDisconnected();
+ method TIRAMISU_0 void registerCarVolumeCallback(CarVolumeCallback callback);
+ method TIRAMISU_0 void unregisterCarVolumeCallback(CarVolumeCallback callback);
+ method TIRAMISU_0 boolean isVolumeGroupMuted(int zoneId, int groupId);
+ method TIRAMISU_0 void setVolumeGroupMute(int zoneId, int groupId, boolean mute, int flags);
+class CarAudioManager.CarVolumeCallback package android.car.media
+ method TIRAMISU_0 void onGroupVolumeChanged(int zoneId, int groupId, int flags);
+ method TIRAMISU_0 void onMasterMuteChanged(int zoneId, int flags);
+ method TIRAMISU_0 void onGroupMuteChanged(int zoneId, int groupId, int flags);
+class CarMediaIntents package android.car.media
+ field TIRAMISU_0 String ACTION_MEDIA_TEMPLATE = "android.car.intent.action.MEDIA_TEMPLATE";
+ field TIRAMISU_0 String EXTRA_MEDIA_COMPONENT = "android.car.intent.extra.MEDIA_COMPONENT";
+ field TIRAMISU_0 String EXTRA_SEARCH_QUERY = "android.car.media.extra.SEARCH_QUERY";
+class @hide @SystemApi CarAppBlockingPolicy package android.car.content.pm
+ field TIRAMISU_0 AppBlockingPackageInfo[] whitelists;
+ field TIRAMISU_0 AppBlockingPackageInfo[] blacklists;
+ field TIRAMISU_0 Parcelable.Creator<CarAppBlockingPolicy> CREATOR;
+ method TIRAMISU_0 int describeContents();
+ method TIRAMISU_0 void writeToParcel(Parcel dest, int flags);
+ method TIRAMISU_0 int hashCode();
+ method TIRAMISU_0 boolean equals(Object obj);
+ method TIRAMISU_0 String toString();
+class CarPackageManager package android.car.content.pm
+ field TIRAMISU_0 int FLAG_SET_POLICY_WAIT_FOR_CHANGE = 0x1;
+ field TIRAMISU_0 int FLAG_SET_POLICY_ADD = 0x2;
+ field TIRAMISU_0 int FLAG_SET_POLICY_REMOVE = 0x4;
+ field TIRAMISU_0 @hiddenOnly String BLOCKING_INTENT_EXTRA_BLOCKED_ACTIVITY_NAME = "blocked_activity";
+ field TIRAMISU_0 @hiddenOnly String BLOCKING_INTENT_EXTRA_BLOCKED_TASK_ID = "blocked_task_id";
+ field TIRAMISU_0 @hiddenOnly String BLOCKING_INTENT_EXTRA_ROOT_ACTIVITY_NAME = "root_activity_name";
+ field TIRAMISU_0 @hiddenOnly String BLOCKING_INTENT_EXTRA_IS_ROOT_ACTIVITY_DO = "is_root_activity_do";
+ field TIRAMISU_0 @hiddenOnly String BLOCKING_INTENT_EXTRA_DISPLAY_ID = "display_id";
+ field TIRAMISU_0 @hiddenOnly String DRIVING_SAFETY_REGION_ALL = "android.car.drivingsafetyregion.all";
+ field TIRAMISU_0 @hiddenOnly String DRIVING_SAFETY_ACTIVITY_METADATA_REGIONS = "android.car.drivingsafetyregions";
+ field TIRAMISU_0 @hiddenOnly int ERROR_CODE_NO_PACKAGE = -100;
+ field TIRAMISU_1 String MANIFEST_METADATA_TARGET_CAR_VERSION = "android.car.targetCarVersion";
+ method TIRAMISU_0 @hiddenOnly void onCarDisconnected();
+ method TIRAMISU_0 void setAppBlockingPolicy(String packageName, CarAppBlockingPolicy policy, int flags);
+ method TIRAMISU_0 @hiddenOnly void restartTask(int taskId);
+ method TIRAMISU_0 boolean isActivityBackedBySafeActivity(ComponentName activityName);
+ method TIRAMISU_0 @hiddenOnly void setEnableActivityBlocking(boolean enable);
+ method TIRAMISU_0 boolean isActivityDistractionOptimized(String packageName, String className);
+ method TIRAMISU_0 boolean isPendingIntentDistractionOptimized(PendingIntent pendingIntent);
+ method TIRAMISU_0 boolean isServiceDistractionOptimized(String packageName, String className);
+ method TIRAMISU_0 @hiddenOnly String getCurrentDrivingSafetyRegion();
+ method TIRAMISU_0 @hiddenOnly void controlTemporaryActivityBlockingBypassingAsUser(String packageName, String activityClassName, boolean bypass, int userId);
+ method TIRAMISU_0 @hiddenOnly List<String> getSupportedDrivingSafetyRegionsForActivityAsUser(String packageName, String activityClassName, int userId);
+ method TIRAMISU_1 CarVersion getTargetCarVersion(String packageName);
+ method TIRAMISU_1 CarVersion getTargetCarVersion();
+class @hide @SystemApi AppBlockingPackageInfo package android.car.content.pm
+ field TIRAMISU_0 String packageName;
+ field TIRAMISU_0 int FLAG_SYSTEM_APP = 0x1;
+ field TIRAMISU_0 int FLAG_WHOLE_ACTIVITY = 0x2;
+ field TIRAMISU_0 int flags;
+ field TIRAMISU_0 int minRevisionCode;
+ field TIRAMISU_0 int maxRevisionCode;
+ field TIRAMISU_0 Signature[] signatures;
+ field TIRAMISU_0 String[] activities;
+ field TIRAMISU_0 Parcelable.Creator<AppBlockingPackageInfo> CREATOR;
+ method TIRAMISU_0 int describeContents();
+ method TIRAMISU_0 void writeToParcel(Parcel dest, int flags);
+ method TIRAMISU_0 @hiddenOnly void verify();
+ method TIRAMISU_0 @hiddenOnly boolean isActivityCovered(String className);
+ method TIRAMISU_0 int hashCode();
+ method TIRAMISU_0 boolean equals(Object obj);
+ method TIRAMISU_0 String toString();
+class @hide @SystemApi CarAppBlockingPolicyService package android.car.content.pm
+ field TIRAMISU_0 String SERVICE_INTERFACE = "android.car.content.pm.CarAppBlockingPolicyService";
+ method TIRAMISU_0 CarAppBlockingPolicy getAppBlockingPolicy();
+ method TIRAMISU_0 int onStartCommand(Intent intent, int flags, int startId);
+ method TIRAMISU_0 IBinder onBind(Intent intent);
+ method TIRAMISU_0 boolean onUnbind(Intent intent);
+class VehicleAreaSeat package android.car
+ field TIRAMISU_0 int SEAT_UNKNOWN = 0;
+ field TIRAMISU_0 int SEAT_ROW_1_LEFT = 0x0001;
+ field TIRAMISU_0 int SEAT_ROW_1_CENTER = 0x0002;
+ field TIRAMISU_0 int SEAT_ROW_1_RIGHT = 0x0004;
+ field TIRAMISU_0 int SEAT_ROW_2_LEFT = 0x0010;
+ field TIRAMISU_0 int SEAT_ROW_2_CENTER = 0x0020;
+ field TIRAMISU_0 int SEAT_ROW_2_RIGHT = 0x0040;
+ field TIRAMISU_0 int SEAT_ROW_3_LEFT = 0x0100;
+ field TIRAMISU_0 int SEAT_ROW_3_CENTER = 0x0200;
+ field TIRAMISU_0 int SEAT_ROW_3_RIGHT = 0x0400;
+ field TIRAMISU_0 @hiddenOnly int SIDE_LEFT = -1;
+ field TIRAMISU_0 @hiddenOnly int SIDE_CENTER = 0;
+ field TIRAMISU_0 @hiddenOnly int SIDE_RIGHT = 1;
+ method TIRAMISU_0 @hiddenOnly int fromRowAndSide(int rowNumber, int side);
+class CarOccupantZoneManager package android.car
+ field TIRAMISU_0 int DISPLAY_TYPE_UNKNOWN = 0;
+ field TIRAMISU_0 int DISPLAY_TYPE_MAIN = 1;
+ field TIRAMISU_0 int DISPLAY_TYPE_INSTRUMENT_CLUSTER = 2;
+ field TIRAMISU_0 int DISPLAY_TYPE_HUD = 3;
+ field TIRAMISU_0 int DISPLAY_TYPE_INPUT = 4;
+ field TIRAMISU_0 int DISPLAY_TYPE_AUXILIARY = 5;
+ field TIRAMISU_0 @hiddenOnly int OCCUPANT_TYPE_INVALID = -1;
+ field TIRAMISU_0 int OCCUPANT_TYPE_DRIVER = 0;
+ field TIRAMISU_0 int OCCUPANT_TYPE_FRONT_PASSENGER = 1;
+ field TIRAMISU_0 int OCCUPANT_TYPE_REAR_PASSENGER = 2;
+ field TIRAMISU_0 int ZONE_CONFIG_CHANGE_FLAG_DISPLAY = 0x1;
+ field TIRAMISU_0 int ZONE_CONFIG_CHANGE_FLAG_USER = 0x2;
+ field TIRAMISU_0 int ZONE_CONFIG_CHANGE_FLAG_AUDIO = 0x4;
+ method TIRAMISU_0 List<OccupantZoneInfo> getAllOccupantZones();
+ method TIRAMISU_0 List<Display> getAllDisplaysForOccupant(OccupantZoneInfo occupantZone);
+ method TIRAMISU_0 Display getDisplayForOccupant(OccupantZoneInfo occupantZone, int displayType);
+ method TIRAMISU_0 int getDisplayIdForDriver(int displayType);
+ method TIRAMISU_0 int getAudioZoneIdForOccupant(OccupantZoneInfo occupantZone);
+ method TIRAMISU_0 OccupantZoneInfo getOccupantForAudioZoneId(int audioZoneId);
+ method TIRAMISU_0 int getDisplayType(Display display);
+ method TIRAMISU_0 int getUserForOccupant(OccupantZoneInfo occupantZone);
+ method TIRAMISU_0 @hiddenOnly boolean assignProfileUserToOccupantZone(OccupantZoneInfo occupantZone, int userId);
+ method TIRAMISU_0 void registerOccupantZoneConfigChangeListener(OccupantZoneConfigChangeListener listener);
+ method TIRAMISU_0 void unregisterOccupantZoneConfigChangeListener(OccupantZoneConfigChangeListener listener);
+ method TIRAMISU_0 @hiddenOnly void onCarDisconnected();
+class CarOccupantZoneManager.OccupantZoneInfo package android.car
+ field TIRAMISU_0 @hiddenOnly int INVALID_ZONE_ID = -1;
+ field TIRAMISU_0 int zoneId;
+ field TIRAMISU_0 int occupantType;
+ field TIRAMISU_0 int seat;
+ field TIRAMISU_0 Parcelable.Creator<OccupantZoneInfo> CREATOR;
+ method TIRAMISU_0 int describeContents();
+ method TIRAMISU_0 void writeToParcel(Parcel dest, int flags);
+ method TIRAMISU_0 boolean equals(Object other);
+ method TIRAMISU_0 int hashCode();
+ method TIRAMISU_0 String toString();
+interface CarOccupantZoneManager.OccupantZoneConfigChangeListener package android.car
+ method TIRAMISU_0 void onOccupantZoneConfigChanged(int changeFlags);
+class @hiddenOnly @hide VehicleSeatOccupancyState package android.car
+ field TIRAMISU_0 int UNKNOWN = 0;
+ field TIRAMISU_0 int VACANT = 1;
+ field TIRAMISU_0 int OCCUPIED = 2;
+class VehicleGear package android.car
+ field TIRAMISU_0 int GEAR_UNKNOWN = 0x0000;
+ field TIRAMISU_0 int GEAR_NEUTRAL = 0x0001;
+ field TIRAMISU_0 int GEAR_REVERSE = 0x0002;
+ field TIRAMISU_0 int GEAR_PARK = 0x0004;
+ field TIRAMISU_0 int GEAR_DRIVE = 0x0008;
+ field TIRAMISU_0 int GEAR_FIRST = 0x0010;
+ field TIRAMISU_0 int GEAR_SECOND = 0x0020;
+ field TIRAMISU_0 int GEAR_THIRD = 0x0040;
+ field TIRAMISU_0 int GEAR_FOURTH = 0x0080;
+ field TIRAMISU_0 int GEAR_FIFTH = 0x0100;
+ field TIRAMISU_0 int GEAR_SIXTH = 0x0200;
+ field TIRAMISU_0 int GEAR_SEVENTH = 0x0400;
+ field TIRAMISU_0 int GEAR_EIGHTH = 0x0800;
+ field TIRAMISU_0 int GEAR_NINTH = 0x1000;
+ method TIRAMISU_0 String toString(int o);
+class EvConnectorType package android.car
+ field TIRAMISU_0 int UNKNOWN = 0;
+ field TIRAMISU_0 int J1772 = 1;
+ field TIRAMISU_0 int MENNEKES = 2;
+ field TIRAMISU_0 int CHADEMO = 3;
+ field TIRAMISU_0 int COMBO_1 = 4;
+ field TIRAMISU_0 int COMBO_2 = 5;
+ field TIRAMISU_0 int TESLA_ROADSTER = 6;
+ field TIRAMISU_0 int TESLA_HPWC = 7;
+ field TIRAMISU_0 int TESLA_SUPERCHARGER = 8;
+ field TIRAMISU_0 int GBT = 9;
+ field TIRAMISU_0 int GBT_DC = 10;
+ field TIRAMISU_0 int SCAME = 11;
+ field TIRAMISU_0 int OTHER = 101;
+class @hide @SystemApi CarUserManager package android.car.user
+ field TIRAMISU_0 @hiddenOnly String TAG = CarUserManager.class.getSimpleName();
+ field TIRAMISU_0 int USER_LIFECYCLE_EVENT_TYPE_STARTING = CommonConstants.USER_LIFECYCLE_EVENT_TYPE_STARTING;
+ field TIRAMISU_0 int USER_LIFECYCLE_EVENT_TYPE_SWITCHING = CommonConstants.USER_LIFECYCLE_EVENT_TYPE_SWITCHING;
+ field TIRAMISU_0 int USER_LIFECYCLE_EVENT_TYPE_UNLOCKING = CommonConstants.USER_LIFECYCLE_EVENT_TYPE_UNLOCKING;
+ field TIRAMISU_0 int USER_LIFECYCLE_EVENT_TYPE_UNLOCKED = CommonConstants.USER_LIFECYCLE_EVENT_TYPE_UNLOCKED;
+ field TIRAMISU_0 @hiddenOnly int USER_LIFECYCLE_EVENT_TYPE_POST_UNLOCKED = CommonConstants.USER_LIFECYCLE_EVENT_TYPE_POST_UNLOCKED;
+ field TIRAMISU_0 int USER_LIFECYCLE_EVENT_TYPE_STOPPING = CommonConstants.USER_LIFECYCLE_EVENT_TYPE_STOPPING;
+ field TIRAMISU_0 int USER_LIFECYCLE_EVENT_TYPE_STOPPED = CommonConstants.USER_LIFECYCLE_EVENT_TYPE_STOPPED;
+ field TIRAMISU_1 int USER_LIFECYCLE_EVENT_TYPE_CREATED = CommonConstants.USER_LIFECYCLE_EVENT_TYPE_CREATED;
+ field TIRAMISU_0 @hiddenOnly String BUNDLE_PARAM_ACTION = "action";
+ field TIRAMISU_0 @hiddenOnly String BUNDLE_PARAM_PREVIOUS_USER_ID = "previous_user";
+ field TIRAMISU_0 @hiddenOnly int USER_IDENTIFICATION_ASSOCIATION_TYPE_KEY_FOB = 1;
+ field TIRAMISU_0 @hiddenOnly int USER_IDENTIFICATION_ASSOCIATION_TYPE_CUSTOM_1 = 101;
+ field TIRAMISU_0 @hiddenOnly int USER_IDENTIFICATION_ASSOCIATION_TYPE_CUSTOM_2 = 102;
+ field TIRAMISU_0 @hiddenOnly int USER_IDENTIFICATION_ASSOCIATION_TYPE_CUSTOM_3 = 103;
+ field TIRAMISU_0 @hiddenOnly int USER_IDENTIFICATION_ASSOCIATION_TYPE_CUSTOM_4 = 104;
+ field TIRAMISU_0 @hiddenOnly int USER_IDENTIFICATION_ASSOCIATION_SET_VALUE_ASSOCIATE_CURRENT_USER = 1;
+ field TIRAMISU_0 @hiddenOnly int USER_IDENTIFICATION_ASSOCIATION_SET_VALUE_DISASSOCIATE_CURRENT_USER = 2;
+ field TIRAMISU_0 @hiddenOnly int USER_IDENTIFICATION_ASSOCIATION_SET_VALUE_DISASSOCIATE_ALL_USERS = 3;
+ field TIRAMISU_0 @hiddenOnly int USER_IDENTIFICATION_ASSOCIATION_VALUE_UNKNOWN = 1;
+ field TIRAMISU_0 @hiddenOnly int USER_IDENTIFICATION_ASSOCIATION_VALUE_ASSOCIATE_CURRENT_USER = 2;
+ field TIRAMISU_0 @hiddenOnly int USER_IDENTIFICATION_ASSOCIATION_VALUE_ASSOCIATED_ANOTHER_USER = 3;
+ field TIRAMISU_0 @hiddenOnly int USER_IDENTIFICATION_ASSOCIATION_VALUE_NOT_ASSOCIATED_ANY_USER = 4;
+ method TIRAMISU_0 @hiddenOnly AsyncFuture<UserSwitchResult> switchUser(int targetUserId);
+ method TIRAMISU_0 @hiddenOnly AsyncFuture<UserSwitchResult> logoutUser();
+ method TIRAMISU_0 @hiddenOnly AsyncFuture<UserCreationResult> createGuest(String name);
+ method TIRAMISU_0 @hiddenOnly AsyncFuture<UserCreationResult> createUser(String name, int flags);
+ method TIRAMISU_0 @hiddenOnly void updatePreCreatedUsers();
+ method TIRAMISU_0 @hiddenOnly UserRemovalResult removeUser(int userId);
+ method TIRAMISU_0 void addListener(Executor executor, UserLifecycleListener listener);
+ method TIRAMISU_0 void addListener(Executor executor, UserLifecycleEventFilter filter, UserLifecycleListener listener);
+ method TIRAMISU_0 void removeListener(UserLifecycleListener listener);
+ method TIRAMISU_0 @hiddenOnly boolean isUserHalUserAssociationSupported();
+ method TIRAMISU_0 @hiddenOnly UserIdentificationAssociationResponse getUserIdentificationAssociation(int types);
+ method TIRAMISU_0 @hiddenOnly AsyncFuture<UserIdentificationAssociationResponse> setUserIdentificationAssociation(int[] types, int[] values);
+ method TIRAMISU_0 @hiddenOnly void setUserSwitchUiCallback(UserSwitchUiCallback callback);
+ method TIRAMISU_0 @hiddenOnly void onCarDisconnected();
+ method TIRAMISU_0 @hiddenOnly String lifecycleEventTypeToString(int type);
+ method TIRAMISU_0 @hiddenOnly boolean isValidUser(int userId);
+class @hide @SystemApi CarUserManager.UserLifecycleEvent package android.car.user
+ method TIRAMISU_0 int getEventType();
+ method TIRAMISU_0 @hiddenOnly int getUserId();
+ method TIRAMISU_0 UserHandle getUserHandle();
+ method TIRAMISU_0 @hiddenOnly int getPreviousUserId();
+ method TIRAMISU_0 UserHandle getPreviousUserHandle();
+ method TIRAMISU_0 String toString();
+ method TIRAMISU_0 boolean equals(Object o);
+ method TIRAMISU_0 int hashCode();
+interface @hide @SystemApi CarUserManager.UserLifecycleListener package android.car.user
+ method TIRAMISU_0 void onEvent(UserLifecycleEvent event);
+interface @hiddenOnly @hide CarUserManager.UserSwitchUiCallback package android.car.user
+ method TIRAMISU_0 void showUserSwitchDialog(int userId);
+class @hiddenOnly @hide ExperimentalCarUserManager package android.car.user
+ field TIRAMISU_0 @hiddenOnly String TAG = ExperimentalCarUserManager.class.getSimpleName();
+ method TIRAMISU_0 @hiddenOnly AndroidFuture<UserCreationResult> createDriver(String name, boolean admin);
+ method TIRAMISU_0 @hiddenOnly int createPassenger(String name, int driverId);
+ method TIRAMISU_0 @hiddenOnly AndroidFuture<UserSwitchResult> switchDriver(int driverId);
+ method TIRAMISU_0 @hiddenOnly List<Integer> getAllDrivers();
+ method TIRAMISU_0 @hiddenOnly List<Integer> getPassengers(int driverId);
+ method TIRAMISU_0 @hiddenOnly boolean startPassenger(int passengerId, int zoneId);
+ method TIRAMISU_0 @hiddenOnly boolean stopPassenger(int passengerId);
+ method TIRAMISU_0 @hiddenOnly void onCarDisconnected();
+class @hiddenOnly @hide UserStopResult package android.car.user
+ field TIRAMISU_0 int STATUS_SUCCESSFUL = CommonResults.STATUS_SUCCESSFUL;
+ field TIRAMISU_0 int STATUS_ANDROID_FAILURE = CommonResults.STATUS_ANDROID_FAILURE;
+ field TIRAMISU_0 int STATUS_USER_DOES_NOT_EXIST = CommonResults.LAST_COMMON_STATUS + 1;
+ field TIRAMISU_0 int STATUS_FAILURE_SYSTEM_USER = CommonResults.LAST_COMMON_STATUS + 2;
+ field TIRAMISU_0 int STATUS_FAILURE_CURRENT_USER = CommonResults.LAST_COMMON_STATUS + 3;
+ field TIRAMISU_0 Parcelable.Creator<UserStopResult> CREATOR;
+ method TIRAMISU_0 boolean isSuccess(int status);
+ method TIRAMISU_0 boolean isSuccess();
+ method TIRAMISU_0 @hiddenOnly String statusToString(int value);
+ method TIRAMISU_0 int getStatus();
+ method TIRAMISU_0 String toString();
+ method TIRAMISU_0 void writeToParcel(android.os.Parcel dest, int flags);
+ method TIRAMISU_0 int describeContents();
+class @hiddenOnly @hide UserCreationResult package android.car.user
+ field TIRAMISU_0 @hiddenOnly int STATUS_SUCCESSFUL = CommonResults.STATUS_SUCCESSFUL;
+ field TIRAMISU_0 @hiddenOnly int STATUS_ANDROID_FAILURE = CommonResults.STATUS_ANDROID_FAILURE;
+ field TIRAMISU_0 @hiddenOnly int STATUS_HAL_FAILURE = CommonResults.STATUS_HAL_FAILURE;
+ field TIRAMISU_0 @hiddenOnly int STATUS_HAL_INTERNAL_FAILURE = CommonResults.STATUS_HAL_INTERNAL_FAILURE;
+ field TIRAMISU_0 int STATUS_INVALID_REQUEST = CommonResults.STATUS_INVALID_REQUEST;
+ field TIRAMISU_0 Parcelable.Creator<UserCreationResult> CREATOR;
+ method TIRAMISU_0 boolean isSuccess();
+ method TIRAMISU_0 int describeContents();
+ method TIRAMISU_0 @hiddenOnly String statusToString(int value);
+ method TIRAMISU_0 int getStatus();
+ method TIRAMISU_0 Integer getAndroidFailureStatus();
+ method TIRAMISU_0 UserHandle getUser();
+ method TIRAMISU_0 String getErrorMessage();
+ method TIRAMISU_0 @hiddenOnly String getInternalErrorMessage();
+ method TIRAMISU_0 String toString();
+ method TIRAMISU_0 void writeToParcel(android.os.Parcel dest, int flags);
+class @hiddenOnly @hide UserRemovalResult package android.car.user
+ field TIRAMISU_0 int STATUS_SUCCESSFUL = CommonResults.STATUS_SUCCESSFUL;
+ field TIRAMISU_0 int STATUS_ANDROID_FAILURE = CommonResults.STATUS_ANDROID_FAILURE;
+ field TIRAMISU_0 int STATUS_INVALID_REQUEST = CommonResults.STATUS_INVALID_REQUEST;
+ field TIRAMISU_0 int STATUS_USER_DOES_NOT_EXIST = CommonResults.LAST_COMMON_STATUS + 1;
+ field TIRAMISU_0 int STATUS_SUCCESSFUL_LAST_ADMIN_REMOVED = CommonResults.LAST_COMMON_STATUS + 2;
+ field TIRAMISU_0 int STATUS_SUCCESSFUL_SET_EPHEMERAL = CommonResults.LAST_COMMON_STATUS + 3;
+ field TIRAMISU_0 int STATUS_SUCCESSFUL_LAST_ADMIN_SET_EPHEMERAL = CommonResults.LAST_COMMON_STATUS + 4;
+ field TIRAMISU_0 Parcelable.Creator<UserRemovalResult> CREATOR;
+ method TIRAMISU_0 boolean isSuccess();
+ method TIRAMISU_0 @hiddenOnly String statusToString(int value);
+ method TIRAMISU_0 int getStatus();
+ method TIRAMISU_0 String toString();
+ method TIRAMISU_0 void writeToParcel(android.os.Parcel dest, int flags);
+ method TIRAMISU_0 int describeContents();
+class CommonResults package android.car.user
+ field TIRAMISU_0 int STATUS_SUCCESSFUL = 1;
+ field TIRAMISU_0 int STATUS_ANDROID_FAILURE = 2;
+ field TIRAMISU_0 int STATUS_HAL_FAILURE = 3;
+ field TIRAMISU_0 int STATUS_HAL_INTERNAL_FAILURE = 4;
+ field TIRAMISU_0 int STATUS_INVALID_REQUEST = 5;
+ field TIRAMISU_0 int STATUS_UX_RESTRICTION_FAILURE = 6;
+ field TIRAMISU_0 int LAST_COMMON_STATUS = 100;
+interface @hiddenOnly @hide OperationResult package android.car.user
+ method TIRAMISU_0 boolean isSuccess();
+class @hide @SystemApi UserLifecycleEventFilter package android.car.user
+ field TIRAMISU_0 Parcelable.Creator<UserLifecycleEventFilter> CREATOR;
+ method TIRAMISU_0 @hiddenOnly int[] getEventTypes();
+ method TIRAMISU_0 @hiddenOnly int[] getUserIds();
+ method TIRAMISU_0 boolean apply(UserLifecycleEvent event);
+ method TIRAMISU_0 String toString();
+ method TIRAMISU_0 boolean equals(Object o);
+ method TIRAMISU_0 int hashCode();
+ method TIRAMISU_0 void writeToParcel(Parcel dest, int flags);
+ method TIRAMISU_0 int describeContents();
+class @hiddenOnly @hide UserLifecycleEventFilter.Builder package android.car.user
+ method TIRAMISU_0 Builder addEventType(int eventType);
+ method TIRAMISU_0 Builder addUser(UserHandle userHandle);
+ method TIRAMISU_0 UserLifecycleEventFilter build();
+class @hiddenOnly @hide UserStartResult package android.car.user
+ field TIRAMISU_0 @hiddenOnly int STATUS_SUCCESSFUL = CommonResults.STATUS_SUCCESSFUL;
+ field TIRAMISU_0 @hiddenOnly int STATUS_ANDROID_FAILURE = CommonResults.STATUS_ANDROID_FAILURE;
+ field TIRAMISU_0 @hiddenOnly int STATUS_SUCCESSFUL_USER_IS_CURRENT_USER = CommonResults.LAST_COMMON_STATUS + 1;
+ field TIRAMISU_0 @hiddenOnly int STATUS_USER_DOES_NOT_EXIST = CommonResults.LAST_COMMON_STATUS + 2;
+ field TIRAMISU_0 Parcelable.Creator<UserStartResult> CREATOR;
+ method TIRAMISU_0 boolean isSuccess();
+ method TIRAMISU_0 @hiddenOnly String statusToString(int value);
+ method TIRAMISU_0 int getStatus();
+ method TIRAMISU_0 String toString();
+ method TIRAMISU_0 void writeToParcel(android.os.Parcel dest, int flags);
+ method TIRAMISU_0 int describeContents();
+class @hiddenOnly @hide UserIdentificationAssociationResponse package android.car.user
+ field TIRAMISU_0 Parcelable.Creator<UserIdentificationAssociationResponse> CREATOR;
+ method TIRAMISU_0 UserIdentificationAssociationResponse forFailure();
+ method TIRAMISU_0 UserIdentificationAssociationResponse forFailure(String errorMessage);
+ method TIRAMISU_0 UserIdentificationAssociationResponse forSuccess(int[] values);
+ method TIRAMISU_0 UserIdentificationAssociationResponse forSuccess(int[] values, String errorMessage);
+ method TIRAMISU_0 boolean isSuccess();
+ method TIRAMISU_0 String getErrorMessage();
+ method TIRAMISU_0 int[] getValues();
+ method TIRAMISU_0 String toString();
+ method TIRAMISU_0 void writeToParcel(android.os.Parcel dest, int flags);
+ method TIRAMISU_0 int describeContents();
+class @hiddenOnly @hide UserSwitchResult package android.car.user
+ field TIRAMISU_0 int STATUS_SUCCESSFUL = CommonResults.STATUS_SUCCESSFUL;
+ field TIRAMISU_0 int STATUS_ANDROID_FAILURE = CommonResults.STATUS_ANDROID_FAILURE;
+ field TIRAMISU_0 int STATUS_HAL_FAILURE = CommonResults.STATUS_HAL_FAILURE;
+ field TIRAMISU_0 int STATUS_HAL_INTERNAL_FAILURE = CommonResults.STATUS_HAL_INTERNAL_FAILURE;
+ field TIRAMISU_0 int STATUS_INVALID_REQUEST = CommonResults.STATUS_INVALID_REQUEST;
+ field TIRAMISU_0 int STATUS_UX_RESTRICTION_FAILURE = CommonResults.STATUS_UX_RESTRICTION_FAILURE;
+ field TIRAMISU_0 int STATUS_OK_USER_ALREADY_IN_FOREGROUND = CommonResults.LAST_COMMON_STATUS + 1;
+ field TIRAMISU_0 int STATUS_TARGET_USER_ALREADY_BEING_SWITCHED_TO = CommonResults.LAST_COMMON_STATUS + 2;
+ field TIRAMISU_0 int STATUS_TARGET_USER_ABANDONED_DUE_TO_A_NEW_REQUEST = CommonResults.LAST_COMMON_STATUS + 3;
+ field TIRAMISU_0 int STATUS_NOT_SWITCHABLE = CommonResults.LAST_COMMON_STATUS + 4;
+ field TIRAMISU_0 int STATUS_NOT_LOGGED_IN = CommonResults.LAST_COMMON_STATUS + 5;
+ field TIRAMISU_0 Parcelable.Creator<UserSwitchResult> CREATOR;
+ method TIRAMISU_0 boolean isSuccess();
+ method TIRAMISU_0 int describeContents();
+ method TIRAMISU_0 @hiddenOnly String statusToString(int value);
+ method TIRAMISU_0 int getStatus();
+ method TIRAMISU_0 @hiddenOnly Integer getAndroidFailureStatus();
+ method TIRAMISU_0 String getErrorMessage();
+ method TIRAMISU_0 String toString();
+ method TIRAMISU_0 void writeToParcel(android.os.Parcel dest, int flags);
+class @hiddenOnly @hide VehicleLightState package android.car
+ field TIRAMISU_0 int OFF = 0;
+ field TIRAMISU_0 int ON = 1;
+ field TIRAMISU_0 int DAYTIME_RUNNING = 2;
+class @hiddenOnly @hide CarLibLog package android.car
+ field TIRAMISU_0 String TAG_CAR = "CAR.L";
+ field TIRAMISU_0 String TAG_CLUSTER = TAG_CAR + ".CLUSTER";
+ field TIRAMISU_0 String TAG_INPUT = TAG_CAR + ".INPUT";
+ field TIRAMISU_0 String TAG_NAV = TAG_CAR + ".NAV";
+ field TIRAMISU_0 String TAG_SENSOR = TAG_CAR + ".SENSOR";
+ field TIRAMISU_0 String TAG_DIAGNOSTIC = TAG_CAR + ".DIAGNOSTIC";
+class @hiddenOnly @hide VehicleHvacFanDirection package android.car
+ field TIRAMISU_0 int FACE = 0x1;
+ field TIRAMISU_0 int FLOOR = 0x2;
+ field TIRAMISU_0 int DEFROST = 0x4;
+class @hiddenOnly @hide CarLocationTestHelper package android.car.test
+ method TIRAMISU_0 @hiddenOnly boolean injectLocation(Location location, Context context);
+class @hiddenOnly @hide CarTestManager package android.car.test
+ method TIRAMISU_0 @hiddenOnly void onCarDisconnected();
+ method TIRAMISU_0 @hiddenOnly void stopCarService(IBinder token);
+ method TIRAMISU_0 @hiddenOnly void startCarService(IBinder token);
+class VehicleAreaType package android.car
+ field TIRAMISU_0 int VEHICLE_AREA_TYPE_GLOBAL = 0;
+ field TIRAMISU_0 int VEHICLE_AREA_TYPE_WINDOW = 2;
+ field TIRAMISU_0 int VEHICLE_AREA_TYPE_SEAT = 3;
+ field TIRAMISU_0 int VEHICLE_AREA_TYPE_DOOR = 4;
+ field TIRAMISU_0 int VEHICLE_AREA_TYPE_MIRROR = 5;
+ field TIRAMISU_0 int VEHICLE_AREA_TYPE_WHEEL = 6;
+class ApiVersion package android.car
+ method TIRAMISU_1 boolean isAtLeast(T requiredVersion);
+ method TIRAMISU_1 int getMajorVersion();
+ method TIRAMISU_1 int getMinorVersion();
+ method TIRAMISU_1 @hiddenOnly boolean equals(Object obj);
+ method TIRAMISU_1 @hiddenOnly int hashCode();
+ method TIRAMISU_1 @hiddenOnly String toString();
+ method TIRAMISU_1 @hiddenOnly void writeToParcel(Parcel dest);
+ method TIRAMISU_1 @hiddenOnly T readFromParcel(Parcel source, ApiVersionFactory<T> factory);
+interface @hiddenOnly @hide ApiVersion.ApiVersionFactory package android.car
+ method T forMajorAndMinor(int major, int minor);
+class PlatformVersion package android.car
+ field TIRAMISU_1 Parcelable.Creator<PlatformVersion> CREATOR;
+ method TIRAMISU_1 PlatformVersion forMajorAndMinorVersions(int majorVersion, int minorVersion);
+ method TIRAMISU_1 PlatformVersion forMajorVersion(int majorVersion);
+ method TIRAMISU_1 int describeContents();
+ method TIRAMISU_1 void writeToParcel(Parcel dest, int flags);
+class PlatformVersion.VERSION_CODES package android.car
+ field TIRAMISU_1 PlatformVersion TIRAMISU_0 = forMajorAndMinorVersions(Build.VERSION_CODES.TIRAMISU, 0);
+ field TIRAMISU_1 PlatformVersion TIRAMISU_1 = forMajorAndMinorVersions(Build.VERSION_CODES.TIRAMISU, 1);
+class @hide @SystemApi CarBugreportManager package android.car
+ method TIRAMISU_0 void requestBugreport(ParcelFileDescriptor output, ParcelFileDescriptor extraOutput, CarBugreportManagerCallback callback);
+ method TIRAMISU_0 @hiddenOnly void requestBugreportForTesting(ParcelFileDescriptor output, ParcelFileDescriptor extraOutput, CarBugreportManagerCallback callback);
+ method TIRAMISU_0 void cancelBugreport();
+ method TIRAMISU_0 @hiddenOnly void onCarDisconnected();
+class CarBugreportManager.CarBugreportManagerCallback package android.car
+ field TIRAMISU_0 int CAR_BUGREPORT_DUMPSTATE_FAILED = 1;
+ field TIRAMISU_0 int CAR_BUGREPORT_IN_PROGRESS = 2;
+ field TIRAMISU_0 int CAR_BUGREPORT_DUMPSTATE_CONNECTION_FAILED = 3;
+ field TIRAMISU_0 int CAR_BUGREPORT_SERVICE_NOT_AVAILABLE = 4;
+ method TIRAMISU_0 void onProgress(float progress);
+ method TIRAMISU_0 void onError(int errorCode);
+ method TIRAMISU_0 void onFinished();
+class CarInfoManager package android.car
+ field TIRAMISU_0 @hiddenOnly int BASIC_INFO_KEY_MANUFACTURER = 0x11100101;
+ field TIRAMISU_0 @hiddenOnly int BASIC_INFO_KEY_MODEL = 0x11100102;
+ field TIRAMISU_0 @hiddenOnly int BASIC_INFO_KEY_MODEL_YEAR = 0x11400103;
+ field TIRAMISU_0 @hiddenOnly String BASIC_INFO_KEY_VEHICLE_ID = "android.car.vehicle-id";
+ field TIRAMISU_0 @hiddenOnly String INFO_KEY_PRODUCT_CONFIGURATION = "android.car.product-config";
+ field TIRAMISU_0 @hiddenOnly int BASIC_INFO_DRIVER_SEAT = 0x1540010a;
+ field TIRAMISU_0 @hiddenOnly int BASIC_INFO_EV_PORT_LOCATION = 0x11400109;
+ field TIRAMISU_0 @hiddenOnly int BASIC_INFO_FUEL_DOOR_LOCATION = 0x11400108;
+ field TIRAMISU_0 @hiddenOnly int BASIC_INFO_FUEL_CAPACITY = 0x11600104;
+ field TIRAMISU_0 @hiddenOnly int BASIC_INFO_FUEL_TYPES = 0x11410105;
+ field TIRAMISU_0 @hiddenOnly int BASIC_INFO_EV_BATTERY_CAPACITY = 0x11600106;
+ field TIRAMISU_0 @hiddenOnly int BASIC_INFO_EV_CONNECTOR_TYPES = 0x11410107;
+ method TIRAMISU_0 String getManufacturer();
+ method TIRAMISU_0 String getModel();
+ method TIRAMISU_0 String getModelYear();
+ method TIRAMISU_0 int getModelYearInInteger();
+ method TIRAMISU_0 String getVehicleId();
+ method TIRAMISU_0 float getFuelCapacity();
+ method TIRAMISU_0 int[] getFuelTypes();
+ method TIRAMISU_0 float getEvBatteryCapacity();
+ method TIRAMISU_0 int[] getEvConnectorTypes();
+ method TIRAMISU_0 int getDriverSeat();
+ method TIRAMISU_0 int getEvPortLocation();
+ method TIRAMISU_0 int getFuelDoorLocation();
+ method TIRAMISU_0 @hiddenOnly void onCarDisconnected();
+class @hide @SystemApi CarSettings package android.car.settings
+ field TIRAMISU_0 @hiddenOnly int[] DEFAULT_GARAGE_MODE_WAKE_UP_TIME = { 0, 0 };
+ field TIRAMISU_0 @hiddenOnly int DEFAULT_GARAGE_MODE_MAINTENANCE_WINDOW = 10 * 60 * 1000;
+class @hiddenOnly @hide CarSettings.Global package android.car.settings
+ field TIRAMISU_0 @hiddenOnly String DEFAULT_USER_RESTRICTIONS_SET = "android.car.DEFAULT_USER_RESTRICTIONS_SET";
+ field TIRAMISU_0 @hiddenOnly String DISABLE_INSTRUMENTATION_SERVICE = "android.car.DISABLE_INSTRUMENTATION_SERVICE";
+ field TIRAMISU_0 @hiddenOnly String ENABLE_USER_SWITCH_DEVELOPER_MESSAGE = "android.car.ENABLE_USER_SWITCH_DEVELOPER_MESSAGE";
+ field TIRAMISU_0 @hiddenOnly String LAST_ACTIVE_USER_ID = "android.car.LAST_ACTIVE_USER_ID";
+ field TIRAMISU_0 @hiddenOnly String LAST_ACTIVE_PERSISTENT_USER_ID = "android.car.LAST_ACTIVE_PERSISTENT_USER_ID";
+ field TIRAMISU_0 @hiddenOnly String SYSTEM_BAR_VISIBILITY_OVERRIDE = "android.car.SYSTEM_BAR_VISIBILITY_OVERRIDE";
+class @hide @SystemApi CarSettings.Secure package android.car.settings
+ field TIRAMISU_0 String KEY_AUDIO_FOCUS_NAVIGATION_REJECTED_DURING_CALL = "android.car.KEY_AUDIO_FOCUS_NAVIGATION_REJECTED_DURING_CALL";
+ field TIRAMISU_0 String KEY_AUDIO_PERSIST_VOLUME_GROUP_MUTE_STATES = "android.car.KEY_AUDIO_PERSIST_VOLUME_GROUP_MUTE_STATES";
+ field TIRAMISU_0 @hiddenOnly String KEY_BLUETOOTH_DEVICES = "android.car.KEY_BLUETOOTH_DEVICES";
+ field TIRAMISU_0 @hiddenOnly String KEY_BLUETOOTH_PROFILES_INHIBITED = "android.car.BLUETOOTH_PROFILES_INHIBITED";
+ field TIRAMISU_0 String KEY_ROTARY_KEY_EVENT_FILTER = "android.car.ROTARY_KEY_EVENT_FILTER";
+ field TIRAMISU_0 String KEY_ENABLE_INITIAL_NOTICE_SCREEN_TO_USER = "android.car.ENABLE_INITIAL_NOTICE_SCREEN_TO_USER";
+ field TIRAMISU_0 String KEY_SETUP_WIZARD_IN_PROGRESS = "android.car.SETUP_WIZARD_IN_PROGRESS";
+ field TIRAMISU_0 String KEY_PACKAGES_DISABLED_ON_RESOURCE_OVERUSE = "android.car.KEY_PACKAGES_DISABLED_ON_RESOURCE_OVERUSE";
+class @hide @SystemApi AoapService package android.car
+ field TIRAMISU_0 int RESULT_OK = 0;
+ field TIRAMISU_0 int RESULT_DEVICE_NOT_SUPPORTED = 1;
+ field TIRAMISU_0 int RESULT_DO_NOT_SWITCH_TO_AOAP = 2;
+ field TIRAMISU_0 @hiddenOnly int MSG_NEW_DEVICE_ATTACHED = 1;
+ field TIRAMISU_0 @hiddenOnly int MSG_NEW_DEVICE_ATTACHED_RESPONSE = 2;
+ field TIRAMISU_0 @hiddenOnly int MSG_CAN_SWITCH_TO_AOAP = 3;
+ field TIRAMISU_0 @hiddenOnly int MSG_CAN_SWITCH_TO_AOAP_RESPONSE = 4;
+ field TIRAMISU_0 @hiddenOnly String KEY_DEVICE = "usb-device";
+ field TIRAMISU_0 @hiddenOnly String KEY_RESULT = "result";
+ method TIRAMISU_0 int isDeviceSupported(UsbDevice device);
+ method TIRAMISU_0 int canSwitchToAoap(UsbDevice device);
+ method TIRAMISU_0 void onCreate();
+ method TIRAMISU_0 IBinder onBind(Intent intent);
+ method TIRAMISU_0 boolean onUnbind(Intent intent);
+ method TIRAMISU_0 void dump(FileDescriptor fd, PrintWriter writer, String[] args);
+class PlatformVersionMismatchException package android.car
+ field TIRAMISU_1 Parcelable.Creator<PlatformVersionMismatchException> CREATOR;
+ method TIRAMISU_1 String getMessage();
+ method TIRAMISU_1 PlatformVersion getExpectedPlatformApiVersion();
+ method TIRAMISU_1 void writeToParcel(Parcel dest, int flags);
+ method TIRAMISU_1 int describeContents();
+class @hide @SystemApi VehiclePropertyAccess package android.car
+ field TIRAMISU_0 int NONE = 0x00;
+ field TIRAMISU_0 int READ = 0x01;
+ field TIRAMISU_0 int WRITE = 0x02;
+ field TIRAMISU_0 int READ_WRITE = 0x03;
+class VehicleIgnitionState package android.car
+ field TIRAMISU_0 int UNDEFINED = 0;
+ field TIRAMISU_0 int LOCK = 1;
+ field TIRAMISU_0 int OFF = 2;
+ field TIRAMISU_0 int ACC = 3;
+ field TIRAMISU_0 int ON = 4;
+ field TIRAMISU_0 int START = 5;
+ method TIRAMISU_0 String toString(int ignitionState);
+class @hide @SystemApi CarProjectionManager package android.car
+ field TIRAMISU_0 int PROJECTION_VOICE_SEARCH = 0x1;
+ field TIRAMISU_0 int PROJECTION_LONG_PRESS_VOICE_SEARCH = 0x2;
+ field TIRAMISU_0 int KEY_EVENT_VOICE_SEARCH_KEY_DOWN = 0;
+ field TIRAMISU_0 int KEY_EVENT_VOICE_SEARCH_SHORT_PRESS_KEY_UP = 1;
+ field TIRAMISU_0 int KEY_EVENT_VOICE_SEARCH_LONG_PRESS_KEY_DOWN = 2;
+ field TIRAMISU_0 int KEY_EVENT_VOICE_SEARCH_LONG_PRESS_KEY_UP = 3;
+ field TIRAMISU_0 int KEY_EVENT_CALL_KEY_DOWN = 4;
+ field TIRAMISU_0 int KEY_EVENT_CALL_SHORT_PRESS_KEY_UP = 5;
+ field TIRAMISU_0 int KEY_EVENT_CALL_LONG_PRESS_KEY_DOWN = 6;
+ field TIRAMISU_0 int KEY_EVENT_CALL_LONG_PRESS_KEY_UP = 7;
+ field TIRAMISU_0 @hiddenOnly int NUM_KEY_EVENTS = 8;
+ field TIRAMISU_0 @hiddenOnly int PROJECTION_AP_STARTED = 0;
+ field TIRAMISU_0 @hiddenOnly int PROJECTION_AP_STOPPED = 1;
+ field TIRAMISU_0 @hiddenOnly int PROJECTION_AP_FAILED = 2;
+ method TIRAMISU_0 @hiddenOnly void regsiterProjectionListener(CarProjectionListener listener, int voiceSearchFilter);
+ method TIRAMISU_0 void registerProjectionListener(CarProjectionListener listener, int voiceSearchFilter);
+ method TIRAMISU_0 @hiddenOnly void unregsiterProjectionListener();
+ method TIRAMISU_0 void unregisterProjectionListener();
+ method TIRAMISU_0 void addKeyEventHandler(Set<Integer> events, ProjectionKeyEventHandler eventHandler);
+ method TIRAMISU_0 void addKeyEventHandler(Set<Integer> events, Executor executor, ProjectionKeyEventHandler eventHandler);
+ method TIRAMISU_0 void removeKeyEventHandler(ProjectionKeyEventHandler eventHandler);
+ method TIRAMISU_0 void registerProjectionRunner(Intent serviceIntent);
+ method TIRAMISU_0 void unregisterProjectionRunner(Intent serviceIntent);
+ method TIRAMISU_0 @hiddenOnly void onCarDisconnected();
+ method TIRAMISU_0 void startProjectionAccessPoint(ProjectionAccessPointCallback callback);
+ method TIRAMISU_0 List<Integer> getAvailableWifiChannels(int band);
+ method TIRAMISU_0 void stopProjectionAccessPoint();
+ method TIRAMISU_0 boolean requestBluetoothProfileInhibit(BluetoothDevice device, int profile);
+ method TIRAMISU_0 boolean releaseBluetoothProfileInhibit(BluetoothDevice device, int profile);
+ method TIRAMISU_0 void updateProjectionStatus(ProjectionStatus status);
+ method TIRAMISU_0 void registerProjectionStatusListener(ProjectionStatusListener listener);
+ method TIRAMISU_0 void unregisterProjectionStatusListener(ProjectionStatusListener listener);
+ method TIRAMISU_0 Bundle getProjectionOptions();
+ method TIRAMISU_0 void resetProjectionAccessPointCredentials();
+interface CarProjectionManager.CarProjectionListener package android.car
+ method TIRAMISU_0 void onVoiceAssistantRequest(boolean fromLongPress);
+interface CarProjectionManager.ProjectionKeyEventHandler package android.car
+ method TIRAMISU_0 void onKeyEvent(int event);
+interface CarProjectionManager.ProjectionStatusListener package android.car
+ method TIRAMISU_0 void onProjectionStatusChanged(int state, String packageName, List<ProjectionStatus> details);
+class CarProjectionManager.ProjectionAccessPointCallback package android.car
+ field TIRAMISU_0 int ERROR_NO_CHANNEL = 1;
+ field TIRAMISU_0 int ERROR_GENERIC = 2;
+ field TIRAMISU_0 int ERROR_INCOMPATIBLE_MODE = 3;
+ field TIRAMISU_0 int ERROR_TETHERING_DISALLOWED = 4;
+ method TIRAMISU_0 void onStarted(WifiConfiguration wifiConfiguration);
+ method TIRAMISU_0 void onStarted(SoftApConfiguration softApConfiguration);
+ method TIRAMISU_0 void onStopped();
+ method TIRAMISU_0 void onFailed(int reason);
+class @hiddenOnly @hide StartUserInBackgroundResult package android.car.admin
+ field TIRAMISU_0 int STATUS_SUCCESS = 1;
+ field TIRAMISU_0 int STATUS_SUCCESS_CURRENT_USER = 2;
+ field TIRAMISU_0 int STATUS_FAILURE_USER_DOES_NOT_EXIST = 3;
+ field TIRAMISU_0 int STATUS_FAILURE_GENERIC = 100;
+ method TIRAMISU_0 int getStatus();
+ method TIRAMISU_0 boolean isSuccess();
+ method TIRAMISU_0 String toString();
+class @hide @SystemApi CarDevicePolicyManager package android.car.admin
+ field TIRAMISU_0 @hiddenOnly String TAG = CarDevicePolicyManager.class.getSimpleName();
+ field TIRAMISU_0 int USER_TYPE_REGULAR = 0;
+ field TIRAMISU_0 int USER_TYPE_ADMIN = 1;
+ field TIRAMISU_0 int USER_TYPE_GUEST = 2;
+ field TIRAMISU_0 @hiddenOnly int FIRST_USER_TYPE = USER_TYPE_REGULAR;
+ field TIRAMISU_0 @hiddenOnly int LAST_USER_TYPE = USER_TYPE_GUEST;
+ method TIRAMISU_0 RemoveUserResult removeUser(UserHandle user);
+ method TIRAMISU_0 CreateUserResult createUser(String name, int type);
+ method TIRAMISU_0 @hiddenOnly StartUserInBackgroundResult startUserInBackground(UserHandle user);
+ method TIRAMISU_0 @hiddenOnly StopUserResult stopUser(UserHandle user);
+ method TIRAMISU_0 @hiddenOnly void setUserDisclaimerShown(UserHandle user);
+ method TIRAMISU_0 @hiddenOnly void setUserDisclaimerAcknowledged(UserHandle user);
+ method TIRAMISU_0 @hiddenOnly void onCarDisconnected();
+class @hide @SystemApi RemoveUserResult package android.car.admin
+ field TIRAMISU_0 int STATUS_SUCCESS = 1;
+ field TIRAMISU_0 int STATUS_SUCCESS_LAST_ADMIN_REMOVED = 2;
+ field TIRAMISU_0 int STATUS_SUCCESS_SET_EPHEMERAL = 3;
+ field TIRAMISU_0 int STATUS_FAILURE_USER_DOES_NOT_EXIST = 4;
+ field TIRAMISU_0 int STATUS_FAILURE_INVALID_ARGUMENTS = 5;
+ field TIRAMISU_0 int STATUS_SUCCESS_LAST_ADMIN_SET_EPHEMERAL = 6;
+ field TIRAMISU_0 int STATUS_FAILURE_GENERIC = 100;
+ method TIRAMISU_0 int getStatus();
+ method TIRAMISU_0 boolean isSuccess();
+ method TIRAMISU_0 String toString();
+ method TIRAMISU_0 @hiddenOnly String statusToString(int status);
+class @hiddenOnly @hide StopUserResult package android.car.admin
+ field TIRAMISU_0 int STATUS_SUCCESS = 1;
+ field TIRAMISU_0 int STATUS_FAILURE_CURRENT_USER = 2;
+ field TIRAMISU_0 int STATUS_FAILURE_SYSTEM_USER = 3;
+ field TIRAMISU_0 int STATUS_FAILURE_USER_DOES_NOT_EXIST = 4;
+ field TIRAMISU_0 int STATUS_FAILURE_GENERIC = 100;
+ method TIRAMISU_0 int getStatus();
+ method TIRAMISU_0 boolean isSuccess();
+ method TIRAMISU_0 String toString();
+class @hide @SystemApi CreateUserResult package android.car.admin
+ field TIRAMISU_0 int STATUS_SUCCESS = 1;
+ field TIRAMISU_0 int STATUS_FAILURE_INVALID_ARGUMENTS = 2;
+ field TIRAMISU_0 int STATUS_FAILURE_GENERIC = 100;
+ method TIRAMISU_0 @hiddenOnly CreateUserResult forGenericError();
+ method TIRAMISU_0 int getStatus();
+ method TIRAMISU_0 boolean isSuccess();
+ method TIRAMISU_0 UserHandle getUserHandle();
+ method TIRAMISU_0 String toString();
+class CarNotConnectedException package android.car
+class @hide @SystemApi IoStatsEntry package android.car.storagemonitoring
+ field TIRAMISU_0 Parcelable.Creator<IoStatsEntry> CREATOR;
+ field TIRAMISU_0 int uid;
+ field TIRAMISU_0 long runtimeMillis;
+ field TIRAMISU_0 IoStatsEntry.Metrics foreground;
+ field TIRAMISU_0 IoStatsEntry.Metrics background;
+ method TIRAMISU_0 int describeContents();
+ method TIRAMISU_0 void writeToParcel(Parcel dest, int flags);
+ method TIRAMISU_0 @hiddenOnly void writeToJson(JsonWriter jsonWriter);
+ method TIRAMISU_0 @hiddenOnly IoStatsEntry delta(IoStatsEntry other);
+ method TIRAMISU_0 boolean equals(Object other);
+ method TIRAMISU_0 int hashCode();
+ method TIRAMISU_0 String toString();
+ method TIRAMISU_0 @hiddenOnly boolean representsSameMetrics(UidIoRecord record);
+class IoStatsEntry.Metrics package android.car.storagemonitoring
+ field TIRAMISU_0 Parcelable.Creator<IoStatsEntry.Metrics> CREATOR;
+ field TIRAMISU_0 long bytesRead;
+ field TIRAMISU_0 long bytesWritten;
+ field TIRAMISU_0 long bytesReadFromStorage;
+ field TIRAMISU_0 long bytesWrittenToStorage;
+ field TIRAMISU_0 long fsyncCalls;
+ method TIRAMISU_0 int describeContents();
+ method TIRAMISU_0 void writeToParcel(Parcel dest, int flags);
+ method TIRAMISU_0 @hiddenOnly void writeToJson(JsonWriter jsonWriter);
+ method TIRAMISU_0 @hiddenOnly Metrics delta(Metrics other);
+ method TIRAMISU_0 boolean equals(Object other);
+ method TIRAMISU_0 int hashCode();
+ method TIRAMISU_0 String toString();
+class @hide @SystemApi IoStats package android.car.storagemonitoring
+ field TIRAMISU_0 Creator<IoStats> CREATOR;
+ method TIRAMISU_0 void writeToParcel(Parcel dest, int flags);
+ method TIRAMISU_0 @hiddenOnly void writeToJson(JsonWriter jsonWriter);
+ method TIRAMISU_0 int describeContents();
+ method TIRAMISU_0 long getTimestamp();
+ method TIRAMISU_0 List<IoStatsEntry> getStats();
+ method TIRAMISU_0 int hashCode();
+ method TIRAMISU_0 IoStatsEntry getUserIdStats(int uid);
+ method TIRAMISU_0 IoStatsEntry.Metrics getForegroundTotals();
+ method TIRAMISU_0 IoStatsEntry.Metrics getBackgroundTotals();
+ method TIRAMISU_0 IoStatsEntry.Metrics getTotals();
+ method TIRAMISU_0 boolean equals(Object other);
+ method TIRAMISU_0 String toString();
+class @hide @SystemApi LifetimeWriteInfo package android.car.storagemonitoring
+ field TIRAMISU_0 Creator<IoStats> CREATOR;
+ field TIRAMISU_0 String partition;
+ field TIRAMISU_0 String fstype;
+ field TIRAMISU_0 long writtenBytes;
+ method TIRAMISU_0 void writeToParcel(Parcel dest, int flags);
+ method TIRAMISU_0 @hiddenOnly void writeToJson(JsonWriter jsonWriter);
+ method TIRAMISU_0 int describeContents();
+ method TIRAMISU_0 boolean equals(Object other);
+ method TIRAMISU_0 String toString();
+class @hide @SystemApi CarStorageMonitoringManager package android.car.storagemonitoring
+ field TIRAMISU_0 String INTENT_EXCESSIVE_IO = "android.car.storagemonitoring.EXCESSIVE_IO";
+ field TIRAMISU_0 int PRE_EOL_INFO_UNKNOWN = 0;
+ field TIRAMISU_0 int PRE_EOL_INFO_NORMAL = 1;
+ field TIRAMISU_0 int PRE_EOL_INFO_WARNING = 2;
+ field TIRAMISU_0 int PRE_EOL_INFO_URGENT = 3;
+ field TIRAMISU_0 long SHUTDOWN_COST_INFO_MISSING = -1;
+ method TIRAMISU_0 @hiddenOnly void onCarDisconnected();
+ method TIRAMISU_0 int getPreEolIndicatorStatus();
+ method TIRAMISU_0 WearEstimate getWearEstimate();
+ method TIRAMISU_0 List<WearEstimateChange> getWearEstimateHistory();
+ method TIRAMISU_0 List<IoStatsEntry> getBootIoStats();
+ method TIRAMISU_0 long getShutdownDiskWriteAmount();
+ method TIRAMISU_0 List<IoStatsEntry> getAggregateIoStats();
+ method TIRAMISU_0 List<IoStats> getIoStatsDeltas();
+ method TIRAMISU_0 void registerListener(IoStatsListener listener);
+ method TIRAMISU_0 void unregisterListener(IoStatsListener listener);
+interface CarStorageMonitoringManager.IoStatsListener package android.car.storagemonitoring
+ method TIRAMISU_0 void onSnapshot(IoStats snapshot);
+class @hide @SystemApi UidIoRecord package android.car.storagemonitoring
+ field TIRAMISU_0 int uid;
+ field TIRAMISU_0 long foreground_rchar;
+ field TIRAMISU_0 long foreground_wchar;
+ field TIRAMISU_0 long foreground_read_bytes;
+ field TIRAMISU_0 long foreground_write_bytes;
+ field TIRAMISU_0 long foreground_fsync;
+ field TIRAMISU_0 long background_rchar;
+ field TIRAMISU_0 long background_wchar;
+ field TIRAMISU_0 long background_read_bytes;
+ field TIRAMISU_0 long background_write_bytes;
+ field TIRAMISU_0 long background_fsync;
+ method TIRAMISU_0 @hiddenOnly UidIoRecord delta(IoStatsEntry other);
+ method TIRAMISU_0 @hiddenOnly UidIoRecord delta(UidIoRecord other);
+class @hide @SystemApi WearEstimateChange package android.car.storagemonitoring
+ field TIRAMISU_0 Parcelable.Creator<WearEstimateChange> CREATOR;
+ field TIRAMISU_0 WearEstimate oldEstimate;
+ field TIRAMISU_0 WearEstimate newEstimate;
+ field TIRAMISU_0 long uptimeAtChange;
+ field TIRAMISU_0 Instant dateAtChange;
+ field TIRAMISU_0 boolean isAcceptableDegradation;
+ method TIRAMISU_0 int describeContents();
+ method TIRAMISU_0 void writeToParcel(Parcel dest, int flags);
+ method TIRAMISU_0 boolean equals(Object other);
+ method TIRAMISU_0 int hashCode();
+ method TIRAMISU_0 String toString();
+class @hide @SystemApi WearEstimate package android.car.storagemonitoring
+ field TIRAMISU_0 int UNKNOWN = -1;
+ field TIRAMISU_0 @hiddenOnly WearEstimate UNKNOWN_ESTIMATE = new WearEstimate(UNKNOWN, UNKNOWN);
+ field TIRAMISU_0 Parcelable.Creator<WearEstimate> CREATOR;
+ field TIRAMISU_0 int typeA;
+ field TIRAMISU_0 int typeB;
+ method TIRAMISU_0 int describeContents();
+ method TIRAMISU_0 void writeToParcel(Parcel dest, int flags);
+ method TIRAMISU_0 @hiddenOnly void writeToJson(JsonWriter jsonWriter);
+ method TIRAMISU_0 boolean equals(Object other);
+ method TIRAMISU_0 int hashCode();
+ method TIRAMISU_0 String toString();
+class @hiddenOnly @hide CarManagerBase package android.car
+ field TIRAMISU_0 Car mCar;
+ method TIRAMISU_0 Context getContext();
+ method TIRAMISU_0 Handler getEventHandler();
+ method TIRAMISU_0 T handleRemoteExceptionFromCarService(RemoteException e, T returnValue);
+ method TIRAMISU_0 void handleRemoteExceptionFromCarService(RemoteException e);
+ method TIRAMISU_0 T handleExceptionFromCarService(Exception e, T returnValue);
+ method TIRAMISU_0 void onCarDisconnected();
+ method TIRAMISU_0 T addDumpable(Object container, Supplier<T> dumpableSupplier);
+class @hide @SystemApi VehicleAreaWindow package android.car
+ field TIRAMISU_0 int WINDOW_FRONT_WINDSHIELD = 0x0001;
+ field TIRAMISU_0 int WINDOW_REAR_WINDSHIELD = 0x0002;
+ field TIRAMISU_0 int WINDOW_ROW_1_LEFT = 0x0010;
+ field TIRAMISU_0 int WINDOW_ROW_1_RIGHT = 0x0040;
+ field TIRAMISU_0 int WINDOW_ROW_2_LEFT = 0x0100;
+ field TIRAMISU_0 int WINDOW_ROW_2_RIGHT = 0x0400;
+ field TIRAMISU_0 int WINDOW_ROW_3_LEFT = 0x1000;
+ field TIRAMISU_0 int WINDOW_ROW_3_RIGHT = 0x4000;
+ field TIRAMISU_0 int WINDOW_ROOF_TOP_1 = 0x10000;
+ field TIRAMISU_0 int WINDOW_ROOF_TOP_2 = 0x20000;
+class @hide @SystemApi CarNavigationInstrumentCluster package android.car.navigation
+ field TIRAMISU_0 int CLUSTER_TYPE_CUSTOM_IMAGES_SUPPORTED = 1;
+ field TIRAMISU_0 int CLUSTER_TYPE_IMAGE_CODES_ONLY = 2;
+ field TIRAMISU_0 Parcelable.Creator<CarNavigationInstrumentCluster> CREATOR;
+ method TIRAMISU_0 CarNavigationInstrumentCluster createCluster(int minIntervalMillis);
+ method TIRAMISU_0 CarNavigationInstrumentCluster createCustomImageCluster(int minIntervalMillis, int imageWidth, int imageHeight, int imageColorDepthBits);
+ method TIRAMISU_0 int getMinIntervalMillis();
+ method TIRAMISU_0 int getType();
+ method TIRAMISU_0 int getImageWidth();
+ method TIRAMISU_0 int getImageHeight();
+ method TIRAMISU_0 @hiddenOnly Bundle getExtra();
+ method TIRAMISU_0 int getImageColorDepthBits();
+ method TIRAMISU_0 boolean supportsCustomImages();
+ method TIRAMISU_0 int describeContents();
+ method TIRAMISU_0 void writeToParcel(Parcel dest, int flags);
+ method TIRAMISU_0 String toString();
+class @hide @SystemApi CarNavigationStatusManager package android.car.navigation
+ method TIRAMISU_0 void sendEvent(int eventType, Bundle bundle);
+ method TIRAMISU_0 void sendNavigationStateChange(Bundle bundle);
+ method TIRAMISU_0 @hiddenOnly void onCarDisconnected();
+ method TIRAMISU_0 CarNavigationInstrumentCluster getInstrumentClusterInfo();
+class @hide @SystemApi VehicleAreaMirror package android.car
+ field TIRAMISU_0 int MIRROR_DRIVER_LEFT = 0x00000001;
+ field TIRAMISU_0 int MIRROR_DRIVER_RIGHT = 0x00000002;
+ field TIRAMISU_0 int MIRROR_DRIVER_CENTER = 0x00000004;
+class @hide @SystemApi CustomInputEvent package android.car.input
+ field TIRAMISU_0 int INPUT_CODE_F1 = 1001;
+ field TIRAMISU_0 int INPUT_CODE_F2 = 1002;
+ field TIRAMISU_0 int INPUT_CODE_F3 = 1003;
+ field TIRAMISU_0 int INPUT_CODE_F4 = 1004;
+ field TIRAMISU_0 int INPUT_CODE_F5 = 1005;
+ field TIRAMISU_0 int INPUT_CODE_F6 = 1006;
+ field TIRAMISU_0 int INPUT_CODE_F7 = 1007;
+ field TIRAMISU_0 int INPUT_CODE_F8 = 1008;
+ field TIRAMISU_0 int INPUT_CODE_F9 = 1009;
+ field TIRAMISU_0 int INPUT_CODE_F10 = 1010;
+ field TIRAMISU_0 Parcelable.Creator<CustomInputEvent> CREATOR;
+ method TIRAMISU_0 String inputCodeToString(int value);
+ method TIRAMISU_0 int getInputCode();
+ method TIRAMISU_0 int getTargetDisplayType();
+ method TIRAMISU_0 int getRepeatCounter();
+ method TIRAMISU_0 String toString();
+ method TIRAMISU_0 boolean equals(Object o);
+ method TIRAMISU_0 int hashCode();
+ method TIRAMISU_0 void writeToParcel(Parcel dest, int flags);
+ method TIRAMISU_0 int describeContents();
+class @hide @SystemApi CarInputHandlingService package android.car.input
+ field TIRAMISU_0 String INPUT_CALLBACK_BINDER_KEY = "callback_binder";
+ field TIRAMISU_0 int INPUT_CALLBACK_BINDER_CODE = IBinder.FIRST_CALL_TRANSACTION;
+ method TIRAMISU_0 IBinder onBind(Intent intent);
+ method TIRAMISU_0 void onKeyEvent(KeyEvent keyEvent, int targetDisplay);
+ method TIRAMISU_0 void dump(FileDescriptor fd, PrintWriter writer, String[] args);
+class CarInputHandlingService.InputFilter package android.car.input
+ field TIRAMISU_0 int mKeyCode;
+ field TIRAMISU_0 int mTargetDisplay;
+ field TIRAMISU_0 Parcelable.Creator CREATOR;
+ method TIRAMISU_0 int describeContents();
+ method TIRAMISU_0 void writeToParcel(Parcel dest, int flags);
+class @hide @SystemApi RotaryEvent package android.car.input
+ field TIRAMISU_0 Parcelable.Creator<RotaryEvent> CREATOR;
+ method TIRAMISU_0 int getNumberOfClicks();
+ method TIRAMISU_0 long getUptimeMillisForClick(int clickIndex);
+ method TIRAMISU_0 String toString();
+ method TIRAMISU_0 int getInputType();
+ method TIRAMISU_0 boolean isClockwise();
+ method TIRAMISU_0 long[] getUptimeMillisForClicks();
+ method TIRAMISU_0 boolean equals(Object o);
+ method TIRAMISU_0 int hashCode();
+ method TIRAMISU_0 void writeToParcel(Parcel dest, int flags);
+ method TIRAMISU_0 int describeContents();
+class @hide @SystemApi CarInputManager package android.car.input
+ field TIRAMISU_0 int CAPTURE_REQ_FLAGS_ALLOW_DELAYED_GRANT = 0x1;
+ field TIRAMISU_0 int CAPTURE_REQ_FLAGS_TAKE_ALL_EVENTS_FOR_DISPLAY = 0x2;
+ field TIRAMISU_0 int INPUT_TYPE_ALL_INPUTS = 1;
+ field TIRAMISU_0 int INPUT_TYPE_ROTARY_NAVIGATION = 10;
+ field TIRAMISU_0 int INPUT_TYPE_ROTARY_VOLUME = 11;
+ field TIRAMISU_0 int INPUT_TYPE_DPAD_KEYS = 100;
+ field TIRAMISU_0 int INPUT_TYPE_NAVIGATE_KEYS = 101;
+ field TIRAMISU_0 int INPUT_TYPE_SYSTEM_NAVIGATE_KEYS = 102;
+ field TIRAMISU_0 int INPUT_TYPE_CUSTOM_INPUT_EVENT = 200;
+ field TIRAMISU_0 int INPUT_CAPTURE_RESPONSE_SUCCEEDED = 0;
+ field TIRAMISU_0 int INPUT_CAPTURE_RESPONSE_FAILED = 1;
+ field TIRAMISU_0 int INPUT_CAPTURE_RESPONSE_DELAYED = 2;
+ method TIRAMISU_0 int requestInputEventCapture(int targetDisplayType, int[] inputTypes, int requestFlags, CarInputCaptureCallback callback);
+ method TIRAMISU_0 int requestInputEventCapture(int targetDisplayType, int[] inputTypes, int requestFlags, Executor executor, CarInputCaptureCallback callback);
+ method TIRAMISU_0 void releaseInputEventCapture(int targetDisplayType);
+ method TIRAMISU_0 void injectKeyEvent(KeyEvent event, int targetDisplayType);
+ method TIRAMISU_0 @hiddenOnly void onCarDisconnected();
+interface CarInputManager.CarInputCaptureCallback package android.car.input
+ method TIRAMISU_0 void onKeyEvents(int targetDisplayType, List<KeyEvent> keyEvents);
+ method TIRAMISU_0 void onRotaryEvents(int targetDisplayType, List<RotaryEvent> events);
+ method TIRAMISU_0 void onCaptureStateChanged(int targetDisplayType, int[] activeInputTypes);
+ method TIRAMISU_0 void onCustomInputEvents(int targetDisplayType, List<CustomInputEvent> events);
+class @hiddenOnly @hide VehicleLightSwitch package android.car
+ field TIRAMISU_0 int OFF = 0;
+ field TIRAMISU_0 int ON = 1;
+ field TIRAMISU_0 int DAYTIME_RUNNING = 2;
+ field TIRAMISU_0 int AUTOMATIC = 0x100;
+class CarUxRestrictionsManager package android.car.drivingstate
+ field TIRAMISU_0 @hiddenOnly String UX_RESTRICTION_MODE_BASELINE = "baseline";
+ method TIRAMISU_0 @hiddenOnly void onCarDisconnected();
+ method TIRAMISU_0 void registerListener(OnUxRestrictionsChangedListener listener);
+ method TIRAMISU_0 @hiddenOnly void registerListener(OnUxRestrictionsChangedListener listener, int displayId);
+ method TIRAMISU_0 void unregisterListener();
+ method TIRAMISU_0 @hiddenOnly boolean saveUxRestrictionsConfigurationForNextBoot(List<CarUxRestrictionsConfiguration> configs);
+ method TIRAMISU_0 CarUxRestrictions getCurrentCarUxRestrictions();
+ method TIRAMISU_0 @hiddenOnly CarUxRestrictions getCurrentCarUxRestrictions(int displayId);
+ method TIRAMISU_0 @hiddenOnly boolean setRestrictionMode(String mode);
+ method TIRAMISU_0 @hiddenOnly String getRestrictionMode();
+ method TIRAMISU_0 @hiddenOnly boolean saveUxRestrictionsConfigurationForNextBoot(CarUxRestrictionsConfiguration config);
+ method TIRAMISU_0 @hiddenOnly List<CarUxRestrictionsConfiguration> getStagedConfigs();
+ method TIRAMISU_0 @hiddenOnly List<CarUxRestrictionsConfiguration> getConfigs();
+interface CarUxRestrictionsManager.OnUxRestrictionsChangedListener package android.car.drivingstate
+ method TIRAMISU_0 void onUxRestrictionsChanged(CarUxRestrictions restrictionInfo);
+class @hide @SystemApi CarDrivingStateManager package android.car.drivingstate
+ method TIRAMISU_0 @hiddenOnly void onCarDisconnected();
+ method TIRAMISU_0 void registerListener(CarDrivingStateEventListener listener);
+ method TIRAMISU_0 void unregisterListener();
+ method TIRAMISU_0 CarDrivingStateEvent getCurrentCarDrivingState();
+ method TIRAMISU_0 @hiddenOnly void injectDrivingState(int drivingState);
+interface @hide @SystemApi CarDrivingStateManager.CarDrivingStateEventListener package android.car.drivingstate
+ method TIRAMISU_0 void onDrivingStateChanged(CarDrivingStateEvent event);
+class CarUxRestrictions package android.car.drivingstate
+ field TIRAMISU_0 int UX_RESTRICTIONS_BASELINE = 0;
+ field TIRAMISU_0 int UX_RESTRICTIONS_NO_DIALPAD = 1;
+ field TIRAMISU_0 int UX_RESTRICTIONS_NO_FILTERING = 0x1 << 1;
+ field TIRAMISU_0 int UX_RESTRICTIONS_LIMIT_STRING_LENGTH = 0x1 << 2;
+ field TIRAMISU_0 int UX_RESTRICTIONS_NO_KEYBOARD = 0x1 << 3;
+ field TIRAMISU_0 int UX_RESTRICTIONS_NO_VIDEO = 0x1 << 4;
+ field TIRAMISU_0 int UX_RESTRICTIONS_LIMIT_CONTENT = 0x1 << 5;
+ field TIRAMISU_0 int UX_RESTRICTIONS_NO_SETUP = 0x1 << 6;
+ field TIRAMISU_0 int UX_RESTRICTIONS_NO_TEXT_MESSAGE = 0x1 << 7;
+ field TIRAMISU_0 int UX_RESTRICTIONS_NO_VOICE_TRANSCRIPTION = 0x1 << 8;
+ field TIRAMISU_0 int UX_RESTRICTIONS_FULLY_RESTRICTED = UX_RESTRICTIONS_NO_DIALPAD | UX_RESTRICTIONS_NO_FILTERING | UX_RESTRICTIONS_LIMIT_STRING_LENGTH | UX_RESTRICTIONS_NO_KEYBOARD | UX_RESTRICTIONS_NO_VIDEO | UX_RESTRICTIONS_LIMIT_CONTENT | UX_RESTRICTIONS_NO_SETUP | UX_RESTRICTIONS_NO_TEXT_MESSAGE | UX_RESTRICTIONS_NO_VOICE_TRANSCRIPTION;
+ field TIRAMISU_0 Parcelable.Creator<CarUxRestrictions> CREATOR;
+ method TIRAMISU_0 @hiddenOnly long getTimeStamp();
+ method TIRAMISU_0 boolean isRequiresDistractionOptimization();
+ method TIRAMISU_0 int getActiveRestrictions();
+ method TIRAMISU_0 int getMaxRestrictedStringLength();
+ method TIRAMISU_0 int getMaxCumulativeContentItems();
+ method TIRAMISU_0 int getMaxContentDepth();
+ method TIRAMISU_0 int describeContents();
+ method TIRAMISU_0 void writeToParcel(Parcel dest, int flags);
+ method TIRAMISU_0 String toString();
+ method TIRAMISU_0 boolean isSameRestrictions(CarUxRestrictions other);
+class CarUxRestrictions.Builder package android.car.drivingstate
+ method TIRAMISU_0 Builder setMaxStringLength(int length);
+ method TIRAMISU_0 Builder setMaxCumulativeContentItems(int number);
+ method TIRAMISU_0 Builder setMaxContentDepth(int depth);
+ method TIRAMISU_0 CarUxRestrictions build();
+class @hide @SystemApi CarDrivingStateEvent package android.car.drivingstate
+ field TIRAMISU_0 int DRIVING_STATE_UNKNOWN = -1;
+ field TIRAMISU_0 int DRIVING_STATE_PARKED = 0;
+ field TIRAMISU_0 int DRIVING_STATE_IDLING = 1;
+ field TIRAMISU_0 int DRIVING_STATE_MOVING = 2;
+ field TIRAMISU_0 long timeStamp;
+ field TIRAMISU_0 int eventValue;
+ field TIRAMISU_0 Parcelable.Creator<CarDrivingStateEvent> CREATOR;
+ method TIRAMISU_0 int describeContents();
+ method TIRAMISU_0 void writeToParcel(Parcel dest, int flags);
+ method TIRAMISU_0 String toString();
+class @hiddenOnly @hide CarUxRestrictionsConfiguration package android.car.drivingstate
+ field TIRAMISU_0 Parcelable.Creator<CarUxRestrictionsConfiguration> CREATOR;
+ method TIRAMISU_0 CarUxRestrictions getUxRestrictions(int drivingState, float currentSpeed);
+ method TIRAMISU_0 CarUxRestrictions getUxRestrictions(int drivingState, float currentSpeed, String mode);
+ method TIRAMISU_0 Integer getPhysicalPort();
+ method TIRAMISU_0 void writeJson(JsonWriter writer);
+ method TIRAMISU_0 String toString();
+ method TIRAMISU_0 CarUxRestrictionsConfiguration readJson(JsonReader reader, int schemaVersion);
+ method TIRAMISU_0 int hashCode();
+ method TIRAMISU_0 boolean equals(Object obj);
+ method TIRAMISU_0 boolean hasSameParameters(CarUxRestrictionsConfiguration other);
+ method TIRAMISU_0 void dump(PrintWriter writer);
+ method TIRAMISU_0 int describeContents();
+ method TIRAMISU_0 void writeToParcel(Parcel dest, int flags);
+class @hiddenOnly @hide CarUxRestrictionsConfiguration.Builder package android.car.drivingstate
+ field TIRAMISU_0 Map<String,RestrictionModeContainer> mRestrictionModes = new ArrayMap<>();
+ method TIRAMISU_0 int validatePort(int port);
+ method TIRAMISU_0 Builder setPhysicalPort(int port);
+ method TIRAMISU_0 Builder setUxRestrictions(int drivingState, boolean requiresOptimization, int restrictions);
+ method TIRAMISU_0 Builder setUxRestrictions(int drivingState, SpeedRange speedRange, boolean requiresOptimization, int restrictions);
+ method TIRAMISU_0 Builder setUxRestrictions(int drivingState, DrivingStateRestrictions drivingStateRestrictions);
+ method TIRAMISU_0 Builder setMaxStringLength(int maxStringLength);
+ method TIRAMISU_0 Builder setMaxCumulativeContentItems(int maxCumulativeContentItems);
+ method TIRAMISU_0 Builder setMaxContentDepth(int maxContentDepth);
+ method TIRAMISU_0 CarUxRestrictionsConfiguration build();
+class CarUxRestrictionsConfiguration.Builder.SpeedRange package android.car.drivingstate
+ field TIRAMISU_0 float MAX_SPEED = Float.POSITIVE_INFINITY;
+ method TIRAMISU_0 boolean includes(float speed);
+ method TIRAMISU_0 int compareTo(SpeedRange other);
+ method TIRAMISU_0 int hashCode();
+ method TIRAMISU_0 boolean equals(Object obj);
+ method TIRAMISU_0 String toString();
+class @hiddenOnly @hide CarUxRestrictionsConfiguration.DrivingStateRestrictions package android.car.drivingstate
+ method TIRAMISU_0 DrivingStateRestrictions setDistractionOptimizationRequired(boolean distractionOptimizationRequired);
+ method TIRAMISU_0 DrivingStateRestrictions setRestrictions(int restrictions);
+ method TIRAMISU_0 DrivingStateRestrictions setMode(String mode);
+ method TIRAMISU_0 DrivingStateRestrictions setSpeedRange(Builder.SpeedRange speedRange);
+ method TIRAMISU_0 String toString();
+class @hide @SystemApi CarActivityManager package android.car.app
+ field TIRAMISU_0 int RESULT_SUCCESS = 0;
+ field TIRAMISU_0 int RESULT_FAILURE = -1;
+ field TIRAMISU_0 int RESULT_INVALID_USER = -2;
+ field TIRAMISU_0 @hiddenOnly int ERROR_CODE_ACTIVITY_NOT_FOUND = -101;
+ method TIRAMISU_0 int setPersistentActivity(ComponentName activity, int displayId, int featureId);
+ method TIRAMISU_0 @hiddenOnly void onCarDisconnected();
+ method TIRAMISU_0 @hiddenOnly boolean registerTaskMonitor();
+ method TIRAMISU_0 @hiddenOnly void onTaskAppeared(ActivityManager.RunningTaskInfo taskInfo);
+ method TIRAMISU_0 @hiddenOnly void onTaskVanished(ActivityManager.RunningTaskInfo taskInfo);
+ method TIRAMISU_0 @hiddenOnly void onTaskInfoChanged(ActivityManager.RunningTaskInfo taskInfo);
+ method TIRAMISU_0 @hiddenOnly void unregisterTaskMonitor();
+ method TIRAMISU_1 @hiddenOnly List<ActivityManager.RunningTaskInfo> getVisibleTasks();
+class @hide @SystemApi CarVendorExtensionManager package android.car.hardware
+ method TIRAMISU_0 void registerCallback(CarVendorExtensionCallback callback);
+ method TIRAMISU_0 void unregisterCallback(CarVendorExtensionCallback callback);
+ method TIRAMISU_0 List<CarPropertyConfig> getProperties();
+ method TIRAMISU_0 boolean isPropertyAvailable(int propertyId, int area);
+ method TIRAMISU_0 E getGlobalProperty(Class<E> propertyClass, int propId);
+ method TIRAMISU_0 E getProperty(Class<E> propertyClass, int propId, int area);
+ method TIRAMISU_0 void setGlobalProperty(Class<E> propertyClass, int propId, E value);
+ method TIRAMISU_0 void setProperty(Class<E> propertyClass, int propId, int area, E value);
+ method TIRAMISU_0 @hiddenOnly void onCarDisconnected();
+interface CarVendorExtensionManager.CarVendorExtensionCallback package android.car.hardware
+ method TIRAMISU_0 void onChangeEvent(CarPropertyValue value);
+ method TIRAMISU_0 void onErrorEvent(int propertyId, int zone);
+class CarPropertyConfig package android.car.hardware
+ field TIRAMISU_0 int VEHICLE_PROPERTY_ACCESS_NONE = 0;
+ field TIRAMISU_0 int VEHICLE_PROPERTY_ACCESS_READ = 1;
+ field TIRAMISU_0 int VEHICLE_PROPERTY_ACCESS_WRITE = 2;
+ field TIRAMISU_0 int VEHICLE_PROPERTY_ACCESS_READ_WRITE = 3;
+ field TIRAMISU_0 int VEHICLE_PROPERTY_CHANGE_MODE_STATIC = 0;
+ field TIRAMISU_0 int VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE = 1;
+ field TIRAMISU_0 int VEHICLE_PROPERTY_CHANGE_MODE_CONTINUOUS = 2;
+ field TIRAMISU_0 Creator<CarPropertyConfig> CREATOR;
+ method TIRAMISU_0 int getAccess();
+ method TIRAMISU_0 int getAreaType();
+ method TIRAMISU_0 int getChangeMode();
+ method TIRAMISU_0 List<Integer> getConfigArray();
+ method TIRAMISU_0 @hiddenOnly String getConfigString();
+ method TIRAMISU_0 float getMaxSampleRate();
+ method TIRAMISU_0 float getMinSampleRate();
+ method TIRAMISU_0 int getPropertyId();
+ method TIRAMISU_0 Class<T> getPropertyType();
+ method TIRAMISU_0 boolean isGlobalProperty();
+ method TIRAMISU_0 @hiddenOnly int getAreaCount();
+ method TIRAMISU_0 int[] getAreaIds();
+ method TIRAMISU_0 @hiddenOnly int getFirstAndOnlyAreaId();
+ method TIRAMISU_0 @hiddenOnly boolean hasArea(int areaId);
+ method TIRAMISU_0 T getMinValue(int areaId);
+ method TIRAMISU_0 T getMaxValue(int areaId);
+ method TIRAMISU_0 T getMinValue();
+ method TIRAMISU_0 T getMaxValue();
+ method TIRAMISU_0 int describeContents();
+ method TIRAMISU_0 void writeToParcel(Parcel dest, int flags);
+ method TIRAMISU_0 @hiddenOnly String toString();
+ method TIRAMISU_0 Builder<T> newBuilder(Class<T> type, int propertyId, int areaType, int areaCapacity);
+ method TIRAMISU_0 @hiddenOnly Builder<T> newBuilder(Class<T> type, int propertyId, int areaType);
+class @hiddenOnly @hide CarPropertyConfig.AreaConfig package android.car.hardware
+ field TIRAMISU_0 Parcelable.Creator<AreaConfig<Object>> CREATOR;
+ method TIRAMISU_0 T getMinValue();
+ method TIRAMISU_0 T getMaxValue();
+ method TIRAMISU_0 int describeContents();
+ method TIRAMISU_0 void writeToParcel(Parcel dest, int flags);
+ method TIRAMISU_0 String toString();
+class @hide @SystemApi CarPropertyConfig.Builder package android.car.hardware
+ method TIRAMISU_0 Builder<T> addAreas(int[] areaIds);
+ method TIRAMISU_0 Builder<T> addArea(int areaId);
+ method TIRAMISU_0 Builder<T> addAreaConfig(int areaId, T min, T max);
+ method TIRAMISU_0 Builder<T> setAccess(int access);
+ method TIRAMISU_0 Builder<T> setChangeMode(int changeMode);
+ method TIRAMISU_0 Builder<T> setConfigArray(ArrayList<Integer> configArray);
+ method TIRAMISU_0 Builder<T> setConfigString(String configString);
+ method TIRAMISU_0 Builder<T> setMaxSampleRate(float maxSampleRate);
+ method TIRAMISU_0 Builder<T> setMinSampleRate(float minSampleRate);
+ method TIRAMISU_0 CarPropertyConfig<T> build();
+class @SystemApi CarHvacFanDirection package android.car.hardware
+ field TIRAMISU_0 int UNKNOWN = 0x0;
+ field TIRAMISU_0 int FACE = 0x01;
+ field TIRAMISU_0 int FLOOR = 0x02;
+ field TIRAMISU_0 int FACE_AND_FLOOR = 0x03;
+ field TIRAMISU_0 int DEFROST = 0x04;
+ field TIRAMISU_0 int DEFROST_AND_FLOOR = 0x06;
+class CarPropertyValue package android.car.hardware
+ field TIRAMISU_0 int STATUS_AVAILABLE = 0;
+ field TIRAMISU_0 int STATUS_UNAVAILABLE = 1;
+ field TIRAMISU_0 int STATUS_ERROR = 2;
+ field TIRAMISU_0 Creator<CarPropertyValue> CREATOR;
+ method TIRAMISU_0 int describeContents();
+ method TIRAMISU_0 void writeToParcel(Parcel dest, int flags);
+ method TIRAMISU_0 int getPropertyId();
+ method TIRAMISU_0 int getAreaId();
+ method TIRAMISU_0 int getStatus();
+ method TIRAMISU_0 long getTimestamp();
+ method TIRAMISU_0 T getValue();
+ method TIRAMISU_0 @hiddenOnly String toString();
+class @hiddenOnly @hide CarSensorConfig package android.car.hardware
+ field TIRAMISU_0 @hiddenOnly String WHEEL_TICK_DISTANCE_SUPPORTED_WHEELS = "android.car.wheelTickDistanceSupportedWheels";
+ field TIRAMISU_0 @hiddenOnly String WHEEL_TICK_DISTANCE_FRONT_LEFT_UM_PER_TICK = "android.car.wheelTickDistanceFrontLeftUmPerTick";
+ field TIRAMISU_0 @hiddenOnly String WHEEL_TICK_DISTANCE_FRONT_RIGHT_UM_PER_TICK = "android.car.wheelTickDistanceFrontRightUmPerTick";
+ field TIRAMISU_0 @hiddenOnly String WHEEL_TICK_DISTANCE_REAR_RIGHT_UM_PER_TICK = "android.car.wheelTickDistanceRearRightUmPerTick";
+ field TIRAMISU_0 @hiddenOnly String WHEEL_TICK_DISTANCE_REAR_LEFT_UM_PER_TICK = "android.car.wheelTickDistanceRearLeftUmPerTick";
+ field TIRAMISU_0 @hiddenOnly Parcelable.Creator<CarSensorConfig> CREATOR;
+ method TIRAMISU_0 @hiddenOnly int describeContents();
+ method TIRAMISU_0 @hiddenOnly void writeToParcel(Parcel dest, int flags);
+ method TIRAMISU_0 @hiddenOnly Bundle getBundle();
+ method TIRAMISU_0 @hiddenOnly int getInt(String key);
+ method TIRAMISU_0 @hiddenOnly int getType();
+ method TIRAMISU_0 @hiddenOnly String toString();
+class CarSensorEvent package android.car.hardware
+ field TIRAMISU_0 int GEAR_NEUTRAL = 0x0001;
+ field TIRAMISU_0 int GEAR_FIRST = 0x0010;
+ field TIRAMISU_0 int GEAR_SECOND = 0x0020;
+ field TIRAMISU_0 int GEAR_THIRD = 0x0040;
+ field TIRAMISU_0 int GEAR_FOURTH = 0x0080;
+ field TIRAMISU_0 int GEAR_FIFTH = 0x0100;
+ field TIRAMISU_0 int GEAR_SIXTH = 0x0200;
+ field TIRAMISU_0 int GEAR_SEVENTH = 0x0400;
+ field TIRAMISU_0 int GEAR_EIGHTH = 0x0800;
+ field TIRAMISU_0 int GEAR_NINTH = 0x1000;
+ field TIRAMISU_0 int GEAR_TENTH = 0x2000;
+ field TIRAMISU_0 int GEAR_DRIVE = 0x0008;
+ field TIRAMISU_0 int GEAR_PARK = 0x0004;
+ field TIRAMISU_0 int GEAR_REVERSE = 0x0002;
+ field TIRAMISU_0 int IGNITION_STATE_UNDEFINED = 0;
+ field TIRAMISU_0 int IGNITION_STATE_LOCK = 1;
+ field TIRAMISU_0 int IGNITION_STATE_OFF = 2;
+ field TIRAMISU_0 int IGNITION_STATE_ACC = 3;
+ field TIRAMISU_0 int IGNITION_STATE_ON = 4;
+ field TIRAMISU_0 int IGNITION_STATE_START = 5;
+ field TIRAMISU_0 int INDEX_ENVIRONMENT_TEMPERATURE = 0;
+ field TIRAMISU_0 int INDEX_WHEEL_DISTANCE_RESET_COUNT = 0;
+ field TIRAMISU_0 int INDEX_WHEEL_DISTANCE_FRONT_LEFT = 1;
+ field TIRAMISU_0 int INDEX_WHEEL_DISTANCE_FRONT_RIGHT = 2;
+ field TIRAMISU_0 int INDEX_WHEEL_DISTANCE_REAR_RIGHT = 3;
+ field TIRAMISU_0 int INDEX_WHEEL_DISTANCE_REAR_LEFT = 4;
+ field TIRAMISU_0 int sensorType;
+ field TIRAMISU_0 long timestamp;
+ field TIRAMISU_0 float[] floatValues;
+ field TIRAMISU_0 int[] intValues;
+ field TIRAMISU_0 long[] longValues;
+ field TIRAMISU_0 Parcelable.Creator<CarSensorEvent> CREATOR;
+ method TIRAMISU_0 int describeContents();
+ method TIRAMISU_0 void writeToParcel(Parcel dest, int flags);
+ method TIRAMISU_0 @hiddenOnly EnvironmentData getEnvironmentData(EnvironmentData data);
+ method TIRAMISU_0 @hiddenOnly IgnitionStateData getIgnitionStateData(IgnitionStateData data);
+ method TIRAMISU_0 @hiddenOnly NightData getNightData(NightData data);
+ method TIRAMISU_0 @hiddenOnly GearData getGearData(GearData data);
+ method TIRAMISU_0 @hiddenOnly ParkingBrakeData getParkingBrakeData(ParkingBrakeData data);
+ method TIRAMISU_0 @hiddenOnly FuelLevelData getFuelLevelData(FuelLevelData data);
+ method TIRAMISU_0 @hiddenOnly OdometerData getOdometerData(OdometerData data);
+ method TIRAMISU_0 @hiddenOnly RpmData getRpmData(RpmData data);
+ method TIRAMISU_0 @hiddenOnly CarSpeedData getCarSpeedData(CarSpeedData data);
+ method TIRAMISU_0 @hiddenOnly CarWheelTickDistanceData getCarWheelTickDistanceData(CarWheelTickDistanceData data);
+ method TIRAMISU_0 @hiddenOnly CarAbsActiveData getCarAbsActiveData(CarAbsActiveData data);
+ method TIRAMISU_0 @hiddenOnly CarTractionControlActiveData getCarTractionControlActiveData(CarTractionControlActiveData data);
+ method TIRAMISU_0 @hiddenOnly CarFuelDoorOpenData getCarFuelDoorOpenData(CarFuelDoorOpenData data);
+ method TIRAMISU_0 @hiddenOnly CarEvBatteryLevelData getCarEvBatteryLevelData(CarEvBatteryLevelData data);
+ method TIRAMISU_0 @hiddenOnly CarEvChargePortOpenData getCarEvChargePortOpenData(CarEvChargePortOpenData data);
+ method TIRAMISU_0 @hiddenOnly CarEvChargePortConnectedData getCarEvChargePortConnectedData(CarEvChargePortConnectedData data);
+ method TIRAMISU_0 @hiddenOnly CarEvBatteryChargeRateData getCarEvBatteryChargeRateData(CarEvBatteryChargeRateData data);
+ method TIRAMISU_0 @hiddenOnly CarEngineOilLevelData getCarEngineOilLevelData(CarEngineOilLevelData data);
+ method TIRAMISU_0 @hiddenOnly String toString();
+class CarSensorEvent.EnvironmentData package android.car.hardware
+ field TIRAMISU_0 long timestamp;
+ field TIRAMISU_0 float temperature;
+class @hiddenOnly @hide CarSensorEvent.IgnitionStateData package android.car.hardware
+ field TIRAMISU_0 long timestamp;
+ field TIRAMISU_0 int ignitionState;
+class @hiddenOnly @hide CarSensorEvent.NightData package android.car.hardware
+ field TIRAMISU_0 long timestamp;
+ field TIRAMISU_0 boolean isNightMode;
+class @hiddenOnly @hide CarSensorEvent.GearData package android.car.hardware
+ field TIRAMISU_0 long timestamp;
+ field TIRAMISU_0 int gear;
+class @hiddenOnly @hide CarSensorEvent.ParkingBrakeData package android.car.hardware
+ field TIRAMISU_0 long timestamp;
+ field TIRAMISU_0 boolean isEngaged;
+class @hiddenOnly @hide CarSensorEvent.FuelLevelData package android.car.hardware
+ field TIRAMISU_0 long timestamp;
+ field TIRAMISU_0 float level;
+class @hiddenOnly @hide CarSensorEvent.OdometerData package android.car.hardware
+ field TIRAMISU_0 long timestamp;
+ field TIRAMISU_0 float kms;
+class @hiddenOnly @hide CarSensorEvent.RpmData package android.car.hardware
+ field TIRAMISU_0 long timestamp;
+ field TIRAMISU_0 float rpm;
+class @hiddenOnly @hide CarSensorEvent.CarSpeedData package android.car.hardware
+ field TIRAMISU_0 long timestamp;
+ field TIRAMISU_0 float carSpeed;
+class @hiddenOnly @hide CarSensorEvent.CarWheelTickDistanceData package android.car.hardware
+ field TIRAMISU_0 long timestamp;
+ field TIRAMISU_0 long sensorResetCount;
+ field TIRAMISU_0 long frontLeftWheelDistanceMm;
+ field TIRAMISU_0 long frontRightWheelDistanceMm;
+ field TIRAMISU_0 long rearRightWheelDistanceMm;
+ field TIRAMISU_0 long rearLeftWheelDistanceMm;
+class @hiddenOnly @hide CarSensorEvent.CarAbsActiveData package android.car.hardware
+ field TIRAMISU_0 long timestamp;
+ field TIRAMISU_0 boolean absIsActive;
+class @hiddenOnly @hide CarSensorEvent.CarTractionControlActiveData package android.car.hardware
+ field TIRAMISU_0 long timestamp;
+ field TIRAMISU_0 boolean tractionControlIsActive;
+class @hiddenOnly @hide CarSensorEvent.CarFuelDoorOpenData package android.car.hardware
+ field TIRAMISU_0 long timestamp;
+ field TIRAMISU_0 boolean fuelDoorIsOpen;
+class @hiddenOnly @hide CarSensorEvent.CarEvBatteryLevelData package android.car.hardware
+ field TIRAMISU_0 long timestamp;
+ field TIRAMISU_0 float evBatteryLevel;
+class @hiddenOnly @hide CarSensorEvent.CarEvChargePortOpenData package android.car.hardware
+ field TIRAMISU_0 long timestamp;
+ field TIRAMISU_0 boolean evChargePortIsOpen;
+class @hiddenOnly @hide CarSensorEvent.CarEvChargePortConnectedData package android.car.hardware
+ field TIRAMISU_0 long timestamp;
+ field TIRAMISU_0 boolean evChargePortIsConnected;
+class @hiddenOnly @hide CarSensorEvent.CarEvBatteryChargeRateData package android.car.hardware
+ field TIRAMISU_0 long timestamp;
+ field TIRAMISU_0 float evChargeRate;
+class @hiddenOnly @hide CarSensorEvent.CarEngineOilLevelData package android.car.hardware
+ field TIRAMISU_0 long timestamp;
+ field TIRAMISU_0 int engineOilLevel;
+class CarSensorManager package android.car.hardware
+ field TIRAMISU_0 @hiddenOnly int SENSOR_TYPE_RESERVED1 = 1;
+ field TIRAMISU_0 int SENSOR_TYPE_CAR_SPEED = 0x11600207;
+ field TIRAMISU_0 int SENSOR_TYPE_RPM = 0x11600305;
+ field TIRAMISU_0 int SENSOR_TYPE_ODOMETER = 0x11600204;
+ field TIRAMISU_0 int SENSOR_TYPE_FUEL_LEVEL = 0x11600307;
+ field TIRAMISU_0 int SENSOR_TYPE_PARKING_BRAKE = 0x11200402;
+ field TIRAMISU_0 int SENSOR_TYPE_GEAR = 0x11400400;
+ field TIRAMISU_0 @hiddenOnly int SENSOR_TYPE_RESERVED8 = 8;
+ field TIRAMISU_0 int SENSOR_TYPE_NIGHT = 0x11200407;
+ field TIRAMISU_0 int SENSOR_TYPE_ENV_OUTSIDE_TEMPERATURE = 0x11600703;
+ field TIRAMISU_0 @hiddenOnly int SENSOR_TYPE_RESERVED10 = 10;
+ field TIRAMISU_0 @hiddenOnly int SENSOR_TYPE_RESERVED11 = 11;
+ field TIRAMISU_0 @hiddenOnly int SENSOR_TYPE_RESERVED12 = 12;
+ field TIRAMISU_0 @hiddenOnly int SENSOR_TYPE_RESERVED13 = 13;
+ field TIRAMISU_0 @hiddenOnly int SENSOR_TYPE_RESERVED14 = 14;
+ field TIRAMISU_0 @hiddenOnly int SENSOR_TYPE_RESERVED15 = 15;
+ field TIRAMISU_0 @hiddenOnly int SENSOR_TYPE_RESERVED16 = 16;
+ field TIRAMISU_0 @hiddenOnly int SENSOR_TYPE_RESERVED17 = 17;
+ field TIRAMISU_0 @hiddenOnly int SENSOR_TYPE_RESERVED18 = 18;
+ field TIRAMISU_0 @hiddenOnly int SENSOR_TYPE_RESERVED19 = 19;
+ field TIRAMISU_0 @hiddenOnly int SENSOR_TYPE_RESERVED20 = 20;
+ field TIRAMISU_0 @hiddenOnly int SENSOR_TYPE_RESERVED21 = 21;
+ field TIRAMISU_0 int SENSOR_TYPE_IGNITION_STATE = 0x11400409;
+ field TIRAMISU_0 int SENSOR_TYPE_WHEEL_TICK_DISTANCE = 0x11510306;
+ field TIRAMISU_0 int SENSOR_TYPE_ABS_ACTIVE = 0x1120040a;
+ field TIRAMISU_0 int SENSOR_TYPE_TRACTION_CONTROL_ACTIVE = 0x1120040b;
+ field TIRAMISU_0 @hiddenOnly int SENSOR_TYPE_RESERVED26 = 26;
+ field TIRAMISU_0 int SENSOR_TYPE_FUEL_DOOR_OPEN = 0x11200308;
+ field TIRAMISU_0 int SENSOR_TYPE_EV_BATTERY_LEVEL = 0x11600309;
+ field TIRAMISU_0 int SENSOR_TYPE_EV_CHARGE_PORT_OPEN = 0x1120030a;
+ field TIRAMISU_0 int SENSOR_TYPE_EV_CHARGE_PORT_CONNECTED = 0x1120030b;
+ field TIRAMISU_0 int SENSOR_TYPE_EV_BATTERY_CHARGE_RATE = 0x1160030c;
+ field TIRAMISU_0 int SENSOR_TYPE_ENGINE_OIL_LEVEL = 0x11400303;
+ field TIRAMISU_0 int SENSOR_RATE_ONCHANGE = 0;
+ field TIRAMISU_0 int SENSOR_RATE_NORMAL = 1;
+ field TIRAMISU_0 int SENSOR_RATE_UI = 5;
+ field TIRAMISU_0 int SENSOR_RATE_FAST = 10;
+ field TIRAMISU_0 int SENSOR_RATE_FASTEST = 100;
+ method TIRAMISU_0 @hiddenOnly void onCarDisconnected();
+ method TIRAMISU_0 int[] getSupportedSensors();
+ method TIRAMISU_0 List<CarPropertyConfig> getPropertyList();
+ method TIRAMISU_0 boolean isSensorSupported(int sensorType);
+ method TIRAMISU_0 @hiddenOnly boolean isSensorSupported(int[] sensorList, int sensorType);
+ method TIRAMISU_0 boolean registerListener(OnSensorChangedListener listener, int sensorType, int rate);
+ method TIRAMISU_0 void unregisterListener(OnSensorChangedListener listener);
+ method TIRAMISU_0 void unregisterListener(OnSensorChangedListener listener, int sensorType);
+ method TIRAMISU_0 CarSensorEvent getLatestSensorEvent(int type);
+ method TIRAMISU_0 @hiddenOnly CarSensorConfig getSensorConfig(int type);
+interface CarSensorManager.OnSensorChangedListener package android.car.hardware
+ method TIRAMISU_0 void onSensorChanged(CarSensorEvent event);
+class @hide @SystemApi CarHvacManager package android.car.hardware.hvac
+ field TIRAMISU_0 int ID_MIRROR_DEFROSTER_ON = 0x1440050c;
+ field TIRAMISU_0 int ID_STEERING_WHEEL_HEAT = 0x1140050d;
+ field TIRAMISU_0 int ID_OUTSIDE_AIR_TEMP = 0x11600703;
+ field TIRAMISU_0 int ID_TEMPERATURE_DISPLAY_UNITS = 0x1140050e;
+ field TIRAMISU_0 int ID_ZONED_TEMP_SETPOINT = 0x15600503;
+ field TIRAMISU_0 int ID_ZONED_TEMP_ACTUAL = 0x15600502;
+ field TIRAMISU_0 int ID_ZONED_HVAC_POWER_ON = 0x15200510;
+ field TIRAMISU_0 int ID_ZONED_FAN_SPEED_SETPOINT = 0x15400500;
+ field TIRAMISU_0 int ID_ZONED_FAN_SPEED_RPM = 0x1540050f;
+ field TIRAMISU_0 int ID_ZONED_FAN_DIRECTION_AVAILABLE = 0x15410511;
+ field TIRAMISU_0 int ID_ZONED_FAN_DIRECTION = 0x15400501;
+ field TIRAMISU_0 int ID_ZONED_SEAT_TEMP = 0x1540050b;
+ field TIRAMISU_0 int ID_ZONED_AC_ON = 0x15200505;
+ field TIRAMISU_0 int ID_ZONED_AUTOMATIC_MODE_ON = 0x1520050A;
+ field TIRAMISU_0 int ID_ZONED_AIR_RECIRCULATION_ON = 0x15200508;
+ field TIRAMISU_0 int ID_ZONED_MAX_AC_ON = 0x15200506;
+ field TIRAMISU_0 int ID_ZONED_DUAL_ZONE_ON = 0x15200509;
+ field TIRAMISU_0 int ID_ZONED_MAX_DEFROST_ON = 0x15200507;
+ field TIRAMISU_0 int ID_ZONED_HVAC_AUTO_RECIRC_ON = 0x15200512;
+ field TIRAMISU_0 int ID_WINDOW_DEFROSTER_ON = 0x13200504;
+ field TIRAMISU_0 int FAN_DIRECTION_FACE = 0x1;
+ field TIRAMISU_0 int FAN_DIRECTION_FLOOR = 0x2;
+ field TIRAMISU_0 int FAN_DIRECTION_DEFROST = 0x4;
+ method TIRAMISU_0 void registerCallback(CarHvacEventCallback callback);
+ method TIRAMISU_0 void unregisterCallback(CarHvacEventCallback callback);
+ method TIRAMISU_0 List<CarPropertyConfig> getPropertyList();
+ method TIRAMISU_0 boolean isPropertyAvailable(int propertyId, int area);
+ method TIRAMISU_0 boolean getBooleanProperty(int propertyId, int area);
+ method TIRAMISU_0 float getFloatProperty(int propertyId, int area);
+ method TIRAMISU_0 int getIntProperty(int propertyId, int area);
+ method TIRAMISU_0 void setBooleanProperty(int propertyId, int area, boolean val);
+ method TIRAMISU_0 void setFloatProperty(int propertyId, int area, float val);
+ method TIRAMISU_0 void setIntProperty(int propertyId, int area, int val);
+ method TIRAMISU_0 @hiddenOnly void onCarDisconnected();
+interface CarHvacManager.CarHvacEventCallback package android.car.hardware.hvac
+ method TIRAMISU_0 void onChangeEvent(CarPropertyValue value);
+ method TIRAMISU_0 void onErrorEvent(int propertyId, int zone);
+class @hide @SystemApi CarCabinManager package android.car.hardware.cabin
+ field TIRAMISU_0 int ID_DOOR_POS = 0x16400b00;
+ field TIRAMISU_0 int ID_DOOR_MOVE = 0x16400b01;
+ field TIRAMISU_0 int ID_DOOR_LOCK = 0x16200b02;
+ field TIRAMISU_0 int ID_MIRROR_Z_POS = 0x14400b40;
+ field TIRAMISU_0 int ID_MIRROR_Z_MOVE = 0x14400b41;
+ field TIRAMISU_0 int ID_MIRROR_Y_POS = 0x14400b42;
+ field TIRAMISU_0 int ID_MIRROR_Y_MOVE = 0x14400b43;
+ field TIRAMISU_0 int ID_MIRROR_LOCK = 0x11200b44;
+ field TIRAMISU_0 int ID_MIRROR_FOLD = 0x11200b45;
+ field TIRAMISU_0 int ID_SEAT_MEMORY_SELECT = 0x15400b80;
+ field TIRAMISU_0 int ID_SEAT_MEMORY_SET = 0x15400b81;
+ field TIRAMISU_0 int ID_SEAT_BELT_BUCKLED = 0x15200b82;
+ field TIRAMISU_0 int ID_SEAT_BELT_HEIGHT_POS = 0x15400b83;
+ field TIRAMISU_0 int ID_SEAT_BELT_HEIGHT_MOVE = 0x15400b84;
+ field TIRAMISU_0 int ID_SEAT_FORE_AFT_POS = 0x15400b85;
+ field TIRAMISU_0 int ID_SEAT_FORE_AFT_MOVE = 0x15400b86;
+ field TIRAMISU_0 int ID_SEAT_BACKREST_ANGLE_1_POS = 0x15400b87;
+ field TIRAMISU_0 int ID_SEAT_BACKREST_ANGLE_1_MOVE = 0x15400b88;
+ field TIRAMISU_0 int ID_SEAT_BACKREST_ANGLE_2_POS = 0x15400b89;
+ field TIRAMISU_0 int ID_SEAT_BACKREST_ANGLE_2_MOVE = 0x15400b8a;
+ field TIRAMISU_0 int ID_SEAT_HEIGHT_POS = 0x15400b8b;
+ field TIRAMISU_0 int ID_SEAT_HEIGHT_MOVE = 0x15400b8c;
+ field TIRAMISU_0 int ID_SEAT_DEPTH_POS = 0x15400b8d;
+ field TIRAMISU_0 int ID_SEAT_DEPTH_MOVE = 0x15400b8e;
+ field TIRAMISU_0 int ID_SEAT_TILT_POS = 0x15400b8f;
+ field TIRAMISU_0 int ID_SEAT_TILT_MOVE = 0x15400b90;
+ field TIRAMISU_0 int ID_SEAT_LUMBAR_FORE_AFT_POS = 0x15400b91;
+ field TIRAMISU_0 int ID_SEAT_LUMBAR_FORE_AFT_MOVE = 0x15400b92;
+ field TIRAMISU_0 int ID_SEAT_LUMBAR_SIDE_SUPPORT_POS = 0x15400b93;
+ field TIRAMISU_0 int ID_SEAT_LUMBAR_SIDE_SUPPORT_MOVE = 0x15400b94;
+ field TIRAMISU_0 int ID_SEAT_HEADREST_HEIGHT_POS = 0x15400b95;
+ field TIRAMISU_0 int ID_SEAT_HEADREST_HEIGHT_MOVE = 0x15400b96;
+ field TIRAMISU_0 int ID_SEAT_HEADREST_ANGLE_POS = 0x15400b97;
+ field TIRAMISU_0 int ID_SEAT_HEADREST_ANGLE_MOVE = 0x15400b98;
+ field TIRAMISU_0 int ID_SEAT_HEADREST_FORE_AFT_POS = 0x15400b99;
+ field TIRAMISU_0 int ID_SEAT_HEADREST_FORE_AFT_MOVE = 0x15400b9a;
+ field TIRAMISU_0 int ID_WINDOW_POS = 0x13400bc0;
+ field TIRAMISU_0 int ID_WINDOW_MOVE = 0x13400bc1;
+ field TIRAMISU_0 int ID_WINDOW_LOCK = 0x13400bc4;
+ method TIRAMISU_0 boolean isZonedProperty(int propertyId);
+ method TIRAMISU_0 void registerCallback(CarCabinEventCallback callback);
+ method TIRAMISU_0 void unregisterCallback(CarCabinEventCallback callback);
+ method TIRAMISU_0 List<CarPropertyConfig> getPropertyList();
+ method TIRAMISU_0 boolean getBooleanProperty(int propertyId, int area);
+ method TIRAMISU_0 float getFloatProperty(int propertyId, int area);
+ method TIRAMISU_0 int getIntProperty(int propertyId, int area);
+ method TIRAMISU_0 void setBooleanProperty(int propertyId, int area, boolean val);
+ method TIRAMISU_0 void setFloatProperty(int propertyId, int area, float val);
+ method TIRAMISU_0 void setIntProperty(int propertyId, int area, int val);
+ method TIRAMISU_0 @hiddenOnly void onCarDisconnected();
+interface CarCabinManager.CarCabinEventCallback package android.car.hardware.cabin
+ method TIRAMISU_0 void onChangeEvent(CarPropertyValue value);
+ method TIRAMISU_0 void onErrorEvent(int propertyId, int zone);
+class PropertyAccessDeniedSecurityException package android.car.hardware.property
+class EvChargingConnectorType package android.car.hardware.property
+ field TIRAMISU_0 int UNKNOWN = 0;
+ field TIRAMISU_0 int IEC_TYPE_1_AC = 1;
+ field TIRAMISU_0 int IEC_TYPE_2_AC = 2;
+ field TIRAMISU_0 int IEC_TYPE_3_AC = 3;
+ field TIRAMISU_0 int IEC_TYPE_4_DC = 4;
+ field TIRAMISU_0 int IEC_TYPE_1_CCS_DC = 5;
+ field TIRAMISU_0 int IEC_TYPE_2_CCS_DC = 6;
+ field TIRAMISU_0 int TESLA_ROADSTER = 7;
+ field TIRAMISU_0 int TESLA_HPWC = 8;
+ field TIRAMISU_0 int TESLA_SUPERCHARGER = 9;
+ field TIRAMISU_0 int GBT_AC = 10;
+ field TIRAMISU_0 int GBT_DC = 11;
+ field TIRAMISU_0 int OTHER = 101;
+ method TIRAMISU_0 String toString(int connectorType);
+class PropertyNotAvailableException package android.car.hardware.property
+class @hide @SystemApi VehicleVendorPermission package android.car.hardware.property
+ field TIRAMISU_0 String PERMISSION_GET_CAR_VENDOR_CATEGORY_WINDOW = "android.car.permission.GET_CAR_VENDOR_CATEGORY_WINDOW";
+ field TIRAMISU_0 String PERMISSION_SET_CAR_VENDOR_CATEGORY_WINDOW = "android.car.permission.SET_CAR_VENDOR_CATEGORY_WINDOW";
+ field TIRAMISU_0 String PERMISSION_GET_CAR_VENDOR_CATEGORY_DOOR = "android.car.permission.GET_CAR_VENDOR_CATEGORY_DOOR";
+ field TIRAMISU_0 String PERMISSION_SET_CAR_VENDOR_CATEGORY_DOOR = "android.car.permission.SET_CAR_VENDOR_CATEGORY_DOOR";
+ field TIRAMISU_0 String PERMISSION_GET_CAR_VENDOR_CATEGORY_SEAT = "android.car.permission.GET_CAR_VENDOR_CATEGORY_SEAT";
+ field TIRAMISU_0 String PERMISSION_SET_CAR_VENDOR_CATEGORY_SEAT = "android.car.permission.SET_CAR_VENDOR_CATEGORY_SEAT";
+ field TIRAMISU_0 String PERMISSION_GET_CAR_VENDOR_CATEGORY_MIRROR = "android.car.permission.GET_CAR_VENDOR_CATEGORY_MIRROR";
+ field TIRAMISU_0 String PERMISSION_SET_CAR_VENDOR_CATEGORY_MIRROR = "android.car.permission.SET_CAR_VENDOR_CATEGORY_MIRROR";
+ field TIRAMISU_0 String PERMISSION_GET_CAR_VENDOR_CATEGORY_INFO = "android.car.permission.GET_CAR_VENDOR_CATEGORY_INFO";
+ field TIRAMISU_0 String PERMISSION_SET_CAR_VENDOR_CATEGORY_INFO = "android.car.permission.SET_CAR_VENDOR_CATEGORY_INFO";
+ field TIRAMISU_0 String PERMISSION_GET_CAR_VENDOR_CATEGORY_ENGINE = "android.car.permission.GET_CAR_VENDOR_CATEGORY_ENGINE";
+ field TIRAMISU_0 String PERMISSION_SET_CAR_VENDOR_CATEGORY_ENGINE = "android.car.permission.SET_CAR_VENDOR_CATEGORY_ENGINE";
+ field TIRAMISU_0 String PERMISSION_GET_CAR_VENDOR_CATEGORY_HVAC = "android.car.permission.GET_CAR_VENDOR_CATEGORY_HVAC";
+ field TIRAMISU_0 String PERMISSION_SET_CAR_VENDOR_CATEGORY_HVAC = "android.car.permission.SET_CAR_VENDOR_CATEGORY_HVAC";
+ field TIRAMISU_0 String PERMISSION_GET_CAR_VENDOR_CATEGORY_LIGHT = "android.car.permission.GET_CAR_VENDOR_CATEGORY_LIGHT";
+ field TIRAMISU_0 String PERMISSION_SET_CAR_VENDOR_CATEGORY_LIGHT = "android.car.permission.SET_CAR_VENDOR_CATEGORY_LIGHT";
+ field TIRAMISU_0 String PERMISSION_GET_CAR_VENDOR_CATEGORY_1 = "android.car.permission.GET_CAR_VENDOR_CATEGORY_1";
+ field TIRAMISU_0 String PERMISSION_SET_CAR_VENDOR_CATEGORY_1 = "android.car.permission.SET_CAR_VENDOR_CATEGORY_1";
+ field TIRAMISU_0 String PERMISSION_GET_CAR_VENDOR_CATEGORY_2 = "android.car.permission.GET_CAR_VENDOR_CATEGORY_2";
+ field TIRAMISU_0 String PERMISSION_SET_CAR_VENDOR_CATEGORY_2 = "android.car.permission.SET_CAR_VENDOR_CATEGORY_2";
+ field TIRAMISU_0 String PERMISSION_GET_CAR_VENDOR_CATEGORY_3 = "android.car.permission.GET_CAR_VENDOR_CATEGORY_3";
+ field TIRAMISU_0 String PERMISSION_SET_CAR_VENDOR_CATEGORY_3 = "android.car.permission.SET_CAR_VENDOR_CATEGORY_3";
+ field TIRAMISU_0 String PERMISSION_GET_CAR_VENDOR_CATEGORY_4 = "android.car.permission.GET_CAR_VENDOR_CATEGORY_4";
+ field TIRAMISU_0 String PERMISSION_SET_CAR_VENDOR_CATEGORY_4 = "android.car.permission.SET_CAR_VENDOR_CATEGORY_4";
+ field TIRAMISU_0 String PERMISSION_GET_CAR_VENDOR_CATEGORY_5 = "android.car.permission.GET_CAR_VENDOR_CATEGORY_5";
+ field TIRAMISU_0 String PERMISSION_SET_CAR_VENDOR_CATEGORY_5 = "android.car.permission.SET_CAR_VENDOR_CATEGORY_5";
+ field TIRAMISU_0 String PERMISSION_GET_CAR_VENDOR_CATEGORY_6 = "android.car.permission.GET_CAR_VENDOR_CATEGORY_6";
+ field TIRAMISU_0 String PERMISSION_SET_CAR_VENDOR_CATEGORY_6 = "android.car.permission.SET_CAR_VENDOR_CATEGORY_6";
+ field TIRAMISU_0 String PERMISSION_GET_CAR_VENDOR_CATEGORY_7 = "android.car.permission.GET_CAR_VENDOR_CATEGORY_7";
+ field TIRAMISU_0 String PERMISSION_SET_CAR_VENDOR_CATEGORY_7 = "android.car.permission.SET_CAR_VENDOR_CATEGORY_7";
+ field TIRAMISU_0 String PERMISSION_GET_CAR_VENDOR_CATEGORY_8 = "android.car.permission.GET_CAR_VENDOR_CATEGORY_8";
+ field TIRAMISU_0 String PERMISSION_SET_CAR_VENDOR_CATEGORY_8 = "android.car.permission.SET_CAR_VENDOR_CATEGORY_8";
+ field TIRAMISU_0 String PERMISSION_GET_CAR_VENDOR_CATEGORY_9 = "android.car.permission.GET_CAR_VENDOR_CATEGORY_9";
+ field TIRAMISU_0 String PERMISSION_SET_CAR_VENDOR_CATEGORY_9 = "android.car.permission.SET_CAR_VENDOR_CATEGORY_9";
+ field TIRAMISU_0 String PERMISSION_GET_CAR_VENDOR_CATEGORY_10 = "android.car.permission.GET_CAR_VENDOR_CATEGORY_10";
+ field TIRAMISU_0 String PERMISSION_SET_CAR_VENDOR_CATEGORY_10 = "android.car.permission.SET_CAR_VENDOR_CATEGORY_10";
+class VehicleElectronicTollCollectionCardStatus package android.car.hardware.property
+ field TIRAMISU_0 int UNKNOWN = 0;
+ field TIRAMISU_0 int ELECTRONIC_TOLL_COLLECTION_CARD_VALID = 1;
+ field TIRAMISU_0 int ELECTRONIC_TOLL_COLLECTION_CARD_INVALID = 2;
+ field TIRAMISU_0 int ELECTRONIC_TOLL_COLLECTION_CARD_NOT_INSERTED = 3;
+class @hiddenOnly @hide VehicleHalStatusCode package android.car.hardware.property
+ field TIRAMISU_0 int STATUS_OK = 0;
+ field TIRAMISU_0 int STATUS_TRY_AGAIN = 1;
+ field TIRAMISU_0 int STATUS_INVALID_ARG = 2;
+ field TIRAMISU_0 int STATUS_NOT_AVAILABLE = 3;
+ field TIRAMISU_0 int STATUS_ACCESS_DENIED = 4;
+ field TIRAMISU_0 int STATUS_INTERNAL_ERROR = 5;
+class PropertyNotAvailableAndRetryException package android.car.hardware.property
+class VehicleElectronicTollCollectionCardType package android.car.hardware.property
+ field TIRAMISU_0 int UNKNOWN = 0;
+ field TIRAMISU_0 int JP_ELECTRONIC_TOLL_COLLECTION_CARD = 1;
+ field TIRAMISU_0 int JP_ELECTRONIC_TOLL_COLLECTION_CARD_V2 = 2;
+class CarInternalErrorException package android.car.hardware.property
+class @hiddenOnly @hide CarPropertyEvent package android.car.hardware.property
+ field TIRAMISU_0 int PROPERTY_EVENT_PROPERTY_CHANGE = 0;
+ field TIRAMISU_0 int PROPERTY_EVENT_ERROR = 1;
+ field TIRAMISU_0 Parcelable.Creator<CarPropertyEvent> CREATOR;
+ method TIRAMISU_0 int getEventType();
+ method TIRAMISU_0 CarPropertyValue<?> getCarPropertyValue();
+ method TIRAMISU_0 int describeContents();
+ method TIRAMISU_0 void writeToParcel(Parcel dest, int flags);
+ method TIRAMISU_0 CarPropertyEvent createErrorEventWithErrorCode(int propertyId, int areaId, int errorCode);
+ method TIRAMISU_0 int getErrorCode();
+ method TIRAMISU_0 String toString();
+class CarPropertyManager package android.car.hardware.property
+ field TIRAMISU_0 float SENSOR_RATE_ONCHANGE = 0f;
+ field TIRAMISU_0 float SENSOR_RATE_NORMAL = 1f;
+ field TIRAMISU_0 float SENSOR_RATE_UI = 5f;
+ field TIRAMISU_0 float SENSOR_RATE_FAST = 10f;
+ field TIRAMISU_0 float SENSOR_RATE_FASTEST = 100f;
+ field TIRAMISU_0 int CAR_SET_PROPERTY_ERROR_CODE_TRY_AGAIN = 1;
+ field TIRAMISU_0 int CAR_SET_PROPERTY_ERROR_CODE_INVALID_ARG = 2;
+ field TIRAMISU_0 int CAR_SET_PROPERTY_ERROR_CODE_PROPERTY_NOT_AVAILABLE = 3;
+ field TIRAMISU_0 int CAR_SET_PROPERTY_ERROR_CODE_ACCESS_DENIED = 4;
+ field TIRAMISU_0 int CAR_SET_PROPERTY_ERROR_CODE_UNKNOWN = 5;
+ method TIRAMISU_0 boolean registerCallback(CarPropertyEventCallback carPropertyEventCallback, int propertyId, float updateRateHz);
+ method TIRAMISU_0 void unregisterCallback(CarPropertyEventCallback carPropertyEventCallback);
+ method TIRAMISU_0 void unregisterCallback(CarPropertyEventCallback carPropertyEventCallback, int propertyId);
+ method TIRAMISU_0 List<CarPropertyConfig> getPropertyList();
+ method TIRAMISU_0 List<CarPropertyConfig> getPropertyList(ArraySet<Integer> propertyIds);
+ method TIRAMISU_0 CarPropertyConfig<?> getCarPropertyConfig(int propId);
+ method TIRAMISU_0 int getAreaId(int propId, int area);
+ method TIRAMISU_0 @hiddenOnly String getReadPermission(int propId);
+ method TIRAMISU_0 @hiddenOnly String getWritePermission(int propId);
+ method TIRAMISU_0 boolean isPropertyAvailable(int propId, int area);
+ method TIRAMISU_0 boolean getBooleanProperty(int prop, int area);
+ method TIRAMISU_0 float getFloatProperty(int prop, int area);
+ method TIRAMISU_0 int getIntProperty(int prop, int area);
+ method TIRAMISU_0 int[] getIntArrayProperty(int prop, int area);
+ method TIRAMISU_0 CarPropertyValue<E> getProperty(Class<E> clazz, int propId, int areaId);
+ method TIRAMISU_0 CarPropertyValue<E> getProperty(int propId, int areaId);
+ method TIRAMISU_0 void setProperty(Class<E> clazz, int propId, int areaId, E val);
+ method TIRAMISU_0 void setBooleanProperty(int prop, int areaId, boolean val);
+ method TIRAMISU_0 void setFloatProperty(int prop, int areaId, float val);
+ method TIRAMISU_0 void setIntProperty(int prop, int areaId, int val);
+ method TIRAMISU_0 @hiddenOnly void onCarDisconnected();
+interface CarPropertyManager.CarPropertyEventCallback package android.car.hardware.property
+ method TIRAMISU_0 void onChangeEvent(CarPropertyValue value);
+ method TIRAMISU_0 void onErrorEvent(int propId, int zone);
+ method TIRAMISU_0 void onErrorEvent(int propId, int areaId, int errorCode);
+class CarPowerManager package android.car.hardware.power
+ field TIRAMISU_0 @hiddenOnly String TAG = CarPowerManager.class.getSimpleName();
+ field TIRAMISU_0 int STATE_INVALID = 0;
+ field TIRAMISU_0 int STATE_WAIT_FOR_VHAL = 1;
+ field TIRAMISU_0 int STATE_SUSPEND_ENTER = 2;
+ field TIRAMISU_0 int STATE_SUSPEND_EXIT = 3;
+ field TIRAMISU_0 int STATE_SHUTDOWN_ENTER = 5;
+ field TIRAMISU_0 int STATE_ON = 6;
+ field TIRAMISU_0 int STATE_SHUTDOWN_PREPARE = 7;
+ field TIRAMISU_0 int STATE_SHUTDOWN_CANCELLED = 8;
+ field TIRAMISU_0 int STATE_HIBERNATION_ENTER = 9;
+ field TIRAMISU_0 int STATE_HIBERNATION_EXIT = 10;
+ field TIRAMISU_0 int STATE_PRE_SHUTDOWN_PREPARE = 11;
+ field TIRAMISU_0 int STATE_POST_SUSPEND_ENTER = 12;
+ field TIRAMISU_0 int STATE_POST_SHUTDOWN_ENTER = 13;
+ field TIRAMISU_0 int STATE_POST_HIBERNATION_ENTER = 14;
+ method TIRAMISU_0 @hiddenOnly void requestShutdownOnNextSuspend();
+ method TIRAMISU_0 @hiddenOnly void scheduleNextWakeupTime(int seconds);
+ method TIRAMISU_0 int getPowerState();
+ method TIRAMISU_0 void setListener(Executor executor, CarPowerStateListener listener);
+ method TIRAMISU_0 void setListenerWithCompletion(Executor executor, CarPowerStateListenerWithCompletion listener);
+ method TIRAMISU_0 void clearListener();
+ method TIRAMISU_0 CarPowerPolicy getCurrentPowerPolicy();
+ method TIRAMISU_0 void applyPowerPolicy(String policyId);
+ method TIRAMISU_0 void setPowerPolicyGroup(String policyGroupId);
+ method TIRAMISU_0 void addPowerPolicyListener(Executor executor, CarPowerPolicyFilter filter, CarPowerPolicyListener listener);
+ method TIRAMISU_0 void removePowerPolicyListener(CarPowerPolicyListener listener);
+ method TIRAMISU_0 @hiddenOnly boolean isCompletionAllowed(int state);
+ method TIRAMISU_0 @hiddenOnly void onCarDisconnected();
+interface @hide @SystemApi CarPowerManager.CompletablePowerStateChangeFuture package android.car.hardware.power
+ method TIRAMISU_0 void complete();
+ method TIRAMISU_0 long getExpirationTime();
+interface @hide @SystemApi CarPowerManager.CarPowerStateListener package android.car.hardware.power
+ method TIRAMISU_0 void onStateChanged(int state);
+interface @hide @SystemApi CarPowerManager.CarPowerStateListenerWithCompletion package android.car.hardware.power
+ method TIRAMISU_0 void onStateChanged(int state, CompletablePowerStateChangeFuture future);
+interface CarPowerManager.CarPowerPolicyListener package android.car.hardware.power
+ method TIRAMISU_0 void onPolicyChanged(CarPowerPolicy policy);
+class @hiddenOnly @hide PowerComponentUtil package android.car.hardware.power
+ field TIRAMISU_0 int COMPONENT_STATE_ENABLED = 1;
+ field TIRAMISU_0 int COMPONENT_STATE_DISABLED = 2;
+ field TIRAMISU_0 int COMPONENT_STATE_UNTOUCHED = 3;
+ field TIRAMISU_0 int INVALID_POWER_COMPONENT = -1;
+ field TIRAMISU_0 int FIRST_POWER_COMPONENT = PowerComponent.AUDIO;
+ field TIRAMISU_0 int LAST_POWER_COMPONENT = PowerComponent.CPU;
+ method TIRAMISU_0 boolean isValidPowerComponent(int component);
+ method TIRAMISU_0 boolean hasComponents(CarPowerPolicy policy, CarPowerPolicyFilter filter);
+ method TIRAMISU_0 int toPowerComponent(String component, boolean prefix);
+ method TIRAMISU_0 String powerComponentToString(int component);
+class CarPowerPolicy package android.car.hardware.power
+ field TIRAMISU_0 Parcelable.Creator<CarPowerPolicy> CREATOR;
+ method TIRAMISU_0 boolean isComponentEnabled(int component);
+ method TIRAMISU_0 String getPolicyId();
+ method TIRAMISU_0 int[] getEnabledComponents();
+ method TIRAMISU_0 int[] getDisabledComponents();
+ method TIRAMISU_0 void writeToParcel(android.os.Parcel dest, int flags);
+ method TIRAMISU_0 int describeContents();
+class CarPowerPolicyFilter package android.car.hardware.power
+ field TIRAMISU_0 Parcelable.Creator<CarPowerPolicyFilter> CREATOR;
+ method TIRAMISU_0 int[] getComponents();
+ method TIRAMISU_0 void writeToParcel(android.os.Parcel dest, int flags);
+ method TIRAMISU_0 int describeContents();
+class CarPowerPolicyFilter.Builder package android.car.hardware.power
+ method TIRAMISU_0 Builder setComponents(int value);
+ method TIRAMISU_0 CarPowerPolicyFilter build();
+class @hiddenOnly @hide CarFeatures package android.car
+ field TIRAMISU_0 @hiddenOnly String FEATURE_CAR_USER_NOTICE_SERVICE = "com.android.car.user.CarUserNoticeService";
+ method TIRAMISU_0 @hiddenOnly boolean isFeatureEnabled(ICar service, String featureName);
+ method TIRAMISU_0 @hiddenOnly void resetCache();
+class Car package android.car
+ field TIRAMISU_0 int API_VERSION_MAJOR_INT = 33;
+ field TIRAMISU_0 int API_VERSION_MINOR_INT = 1;
+ field TIRAMISU_0 int PLATFORM_VERSION_MINOR_INT = SystemProperties.getInt(PROPERTY_PLATFORM_MINOR_VERSION, /* def= */
+0);
+ field @hiddenOnly String PROPERTY_EMULATED_PLATFORM_VERSION_MAJOR = "com.android.car.internal.debug.platform_major_version";
+ field @hiddenOnly String PROPERTY_EMULATED_PLATFORM_VERSION_MINOR = "com.android.car.internal.debug.platform_minor_version";
+ field TIRAMISU_0 @hiddenOnly String CAR_SERVICE_BINDER_SERVICE_NAME = "car_service";
+ field TIRAMISU_0 String META_DATA_DISTRACTION_OPTIMIZED = "distractionOptimized";
+ field TIRAMISU_0 String META_DATA_REQUIRES_CAR_FEATURE = "requires-car-feature";
+ field TIRAMISU_0 String SENSOR_SERVICE = "sensor";
+ field TIRAMISU_0 String INFO_SERVICE = "info";
+ field TIRAMISU_0 String APP_FOCUS_SERVICE = "app_focus";
+ field TIRAMISU_0 String PACKAGE_SERVICE = "package";
+ field TIRAMISU_0 String AUDIO_SERVICE = "audio";
+ field TIRAMISU_0 String CAR_NAVIGATION_SERVICE = "car_navigation_service";
+ field TIRAMISU_0 String CAR_OCCUPANT_ZONE_SERVICE = "car_occupant_zone_service";
+ field TIRAMISU_0 String CAR_USER_SERVICE = "car_user_service";
+ field TIRAMISU_0 @hiddenOnly String EXPERIMENTAL_CAR_USER_SERVICE = "experimental_car_user_service";
+ field TIRAMISU_0 String CAR_DEVICE_POLICY_SERVICE = "car_device_policy_service";
+ field TIRAMISU_0 @hiddenOnly String CAR_INSTRUMENT_CLUSTER_SERVICE = "cluster_service";
+ field TIRAMISU_0 String CABIN_SERVICE = "cabin";
+ field TIRAMISU_0 String DIAGNOSTIC_SERVICE = "diagnostic";
+ field TIRAMISU_0 String HVAC_SERVICE = "hvac";
+ field TIRAMISU_0 String POWER_SERVICE = "power";
+ field TIRAMISU_0 String PROJECTION_SERVICE = "projection";
+ field TIRAMISU_0 String PROPERTY_SERVICE = "property";
+ field TIRAMISU_0 String VENDOR_EXTENSION_SERVICE = "vendor_extension";
+ field TIRAMISU_0 String VEHICLE_MAP_SERVICE = "vehicle_map_service";
+ field TIRAMISU_0 String VMS_SUBSCRIBER_SERVICE = "vehicle_map_subscriber_service";
+ field TIRAMISU_0 String CAR_DRIVING_STATE_SERVICE = "drivingstate";
+ field TIRAMISU_0 String CAR_UX_RESTRICTION_SERVICE = "uxrestriction";
+ field TIRAMISU_0 String OCCUPANT_AWARENESS_SERVICE = "occupant_awareness";
+ field TIRAMISU_0 String CAR_MEDIA_SERVICE = "car_media";
+ field TIRAMISU_0 String CAR_BUGREPORT_SERVICE = "car_bugreport";
+ field TIRAMISU_0 String STORAGE_MONITORING_SERVICE = "storage_monitoring";
+ field TIRAMISU_0 String CAR_WATCHDOG_SERVICE = "car_watchdog";
+ field TIRAMISU_0 String CAR_PERFORMANCE_SERVICE = "car_performance";
+ field TIRAMISU_0 String CAR_INPUT_SERVICE = "android.car.input";
+ field TIRAMISU_0 @hiddenOnly String CLUSTER_HOME_SERVICE = "cluster_home_service";
+ field TIRAMISU_0 String TEST_SERVICE = "car-service-test";
+ field TIRAMISU_0 String CAR_EVS_SERVICE = "car_evs_service";
+ field TIRAMISU_0 String CAR_TELEMETRY_SERVICE = "car_telemetry_service";
+ field TIRAMISU_0 String CAR_ACTIVITY_SERVICE = "car_activity_service";
+ field TIRAMISU_0 String PERMISSION_MILEAGE = "android.car.permission.CAR_MILEAGE";
+ field TIRAMISU_0 String PERMISSION_ENERGY = "android.car.permission.CAR_ENERGY";
+ field TIRAMISU_0 String PERMISSION_CONTROL_CAR_ENERGY = "android.car.permission.CONTROL_CAR_ENERGY";
+ field TIRAMISU_0 String PERMISSION_ADJUST_RANGE_REMAINING = "android.car.permission.ADJUST_RANGE_REMAINING";
+ field TIRAMISU_0 String PERMISSION_IDENTIFICATION = "android.car.permission.CAR_IDENTIFICATION";
+ field TIRAMISU_0 String PERMISSION_SPEED = "android.car.permission.CAR_SPEED";
+ field TIRAMISU_0 String PERMISSION_CAR_DYNAMICS_STATE = "android.car.permission.CAR_DYNAMICS_STATE";
+ field TIRAMISU_0 String PERMISSION_ENERGY_PORTS = "android.car.permission.CAR_ENERGY_PORTS";
+ field TIRAMISU_0 String PERMISSION_CONTROL_ENERGY_PORTS = "android.car.permission.CONTROL_CAR_ENERGY_PORTS";
+ field TIRAMISU_0 String PERMISSION_EXTERIOR_LIGHTS = "android.car.permission.CAR_EXTERIOR_LIGHTS";
+ field TIRAMISU_0 String PERMISSION_READ_INTERIOR_LIGHTS = "android.car.permission.READ_CAR_INTERIOR_LIGHTS";
+ field TIRAMISU_0 String PERMISSION_CONTROL_EXTERIOR_LIGHTS = "android.car.permission.CONTROL_CAR_EXTERIOR_LIGHTS";
+ field TIRAMISU_0 String PERMISSION_CONTROL_INTERIOR_LIGHTS = "android.car.permission.CONTROL_CAR_INTERIOR_LIGHTS";
+ field TIRAMISU_0 String PERMISSION_POWERTRAIN = "android.car.permission.CAR_POWERTRAIN";
+ field TIRAMISU_0 String PERMISSION_CAR_CONTROL_AUDIO_VOLUME = "android.car.permission.CAR_CONTROL_AUDIO_VOLUME";
+ field TIRAMISU_0 String PERMISSION_CAR_CONTROL_AUDIO_SETTINGS = "android.car.permission.CAR_CONTROL_AUDIO_SETTINGS";
+ field TIRAMISU_0 String PERMISSION_RECEIVE_CAR_AUDIO_DUCKING_EVENTS = "android.car.permission.RECEIVE_CAR_AUDIO_DUCKING_EVENTS";
+ field TIRAMISU_0 String PERMISSION_CAR_NAVIGATION_MANAGER = "android.car.permission.CAR_NAVIGATION_MANAGER";
+ field TIRAMISU_0 String PERMISSION_CAR_INSTRUMENT_CLUSTER_CONTROL = "android.car.permission.CAR_INSTRUMENT_CLUSTER_CONTROL";
+ field TIRAMISU_0 @hiddenOnly String PERMISSION_CAR_MONITOR_CLUSTER_NAVIGATION_STATE = "android.car.permission.CAR_MONITOR_CLUSTER_NAVIGATION_STATE";
+ field TIRAMISU_0 @hiddenOnly String PERMISSION_CAR_DISPLAY_IN_CLUSTER = "android.car.permission.CAR_DISPLAY_IN_CLUSTER";
+ field TIRAMISU_0 String PERMISSION_CAR_INFO = "android.car.permission.CAR_INFO";
+ field TIRAMISU_0 String PERMISSION_PRIVILEGED_CAR_INFO = "android.car.permission.PRIVILEGED_CAR_INFO";
+ field TIRAMISU_0 String PERMISSION_READ_CAR_VENDOR_PERMISSION_INFO = "android.car.permission.READ_CAR_VENDOR_PERMISSION_INFO";
+ field TIRAMISU_0 String PERMISSION_EXTERIOR_ENVIRONMENT = "android.car.permission.CAR_EXTERIOR_ENVIRONMENT";
+ field TIRAMISU_0 String PERMISSION_VENDOR_EXTENSION = "android.car.permission.CAR_VENDOR_EXTENSION";
+ field TIRAMISU_0 String PERMISSION_CONTROL_APP_BLOCKING = "android.car.permission.CONTROL_APP_BLOCKING";
+ field TIRAMISU_0 String PERMISSION_CAR_ENGINE_DETAILED = "android.car.permission.CAR_ENGINE_DETAILED";
+ field TIRAMISU_0 String PERMISSION_TIRES = "android.car.permission.CAR_TIRES";
+ field TIRAMISU_0 String PERMISSION_CAR_EPOCH_TIME = "android.car.permission.CAR_EPOCH_TIME";
+ field TIRAMISU_0 String PERMISSION_STORAGE_ENCRYPTION_BINDING_SEED = "android.car.permission.STORAGE_ENCRYPTION_BINDING_SEED";
+ field TIRAMISU_0 String PERMISSION_READ_STEERING_STATE = "android.car.permission.READ_CAR_STEERING";
+ field TIRAMISU_0 String PERMISSION_READ_DISPLAY_UNITS = "android.car.permission.READ_CAR_DISPLAY_UNITS";
+ field TIRAMISU_0 String PERMISSION_CONTROL_DISPLAY_UNITS = "android.car.permission.CONTROL_CAR_DISPLAY_UNITS";
+ field TIRAMISU_0 String PERMISSION_CONTROL_CAR_DOORS = "android.car.permission.CONTROL_CAR_DOORS";
+ field TIRAMISU_0 String PERMISSION_CONTROL_CAR_WINDOWS = "android.car.permission.CONTROL_CAR_WINDOWS";
+ field TIRAMISU_0 String PERMISSION_CONTROL_CAR_SEATS = "android.car.permission.CONTROL_CAR_SEATS";
+ field TIRAMISU_0 String PERMISSION_CONTROL_CAR_MIRRORS = "android.car.permission.CONTROL_CAR_MIRRORS";
+ field TIRAMISU_0 String PERMISSION_CONTROL_CAR_CLIMATE = "android.car.permission.CONTROL_CAR_CLIMATE";
+ field TIRAMISU_0 String PERMISSION_CAR_POWER = "android.car.permission.CAR_POWER";
+ field TIRAMISU_0 String PERMISSION_READ_CAR_POWER_POLICY = "android.car.permission.READ_CAR_POWER_POLICY";
+ field TIRAMISU_0 String PERMISSION_CONTROL_CAR_POWER_POLICY = "android.car.permission.CONTROL_CAR_POWER_POLICY";
+ field TIRAMISU_0 String PERMISSION_CONTROL_SHUTDOWN_PROCESS = "android.car.permission.CONTROL_SHUTDOWN_PROCESS";
+ field TIRAMISU_0 String PERMISSION_CAR_PROJECTION = "android.car.permission.CAR_PROJECTION";
+ field TIRAMISU_0 String PERMISSION_CAR_PROJECTION_STATUS = "android.car.permission.ACCESS_CAR_PROJECTION_STATUS";
+ field TIRAMISU_0 String PERMISSION_MOCK_VEHICLE_HAL = "android.car.permission.CAR_MOCK_VEHICLE_HAL";
+ field TIRAMISU_0 String PERMISSION_CAR_TEST_SERVICE = "android.car.permission.CAR_TEST_SERVICE";
+ field TIRAMISU_0 String PERMISSION_CAR_DRIVING_STATE = "android.car.permission.CAR_DRIVING_STATE";
+ field TIRAMISU_0 @hiddenOnly String PERMISSION_BIND_VMS_CLIENT = "android.car.permission.BIND_VMS_CLIENT";
+ field TIRAMISU_0 String PERMISSION_VMS_PUBLISHER = "android.car.permission.VMS_PUBLISHER";
+ field TIRAMISU_0 String PERMISSION_VMS_SUBSCRIBER = "android.car.permission.VMS_SUBSCRIBER";
+ field TIRAMISU_0 String PERMISSION_CAR_DIAGNOSTIC_READ_ALL = "android.car.permission.CAR_DIAGNOSTICS";
+ field TIRAMISU_0 String PERMISSION_CAR_DIAGNOSTIC_CLEAR = "android.car.permission.CLEAR_CAR_DIAGNOSTICS";
+ field TIRAMISU_0 @hiddenOnly String PERMISSION_CAR_UX_RESTRICTIONS_CONFIGURATION = "android.car.permission.CAR_UX_RESTRICTIONS_CONFIGURATION";
+ field TIRAMISU_0 String PERMISSION_READ_CAR_OCCUPANT_AWARENESS_STATE = "android.car.permission.READ_CAR_OCCUPANT_AWARENESS_STATE";
+ field TIRAMISU_0 String ACCESS_PRIVATE_DISPLAY_ID = "android.car.permission.ACCESS_PRIVATE_DISPLAY_ID";
+ field TIRAMISU_0 String PERMISSION_CONTROL_CAR_OCCUPANT_AWARENESS_SYSTEM = "android.car.permission.CONTROL_CAR_OCCUPANT_AWARENESS_SYSTEM";
+ field TIRAMISU_0 String PERMISSION_STORAGE_MONITORING = "android.car.permission.STORAGE_MONITORING";
+ field TIRAMISU_0 String PERMISSION_CONTROL_CAR_FEATURES = "android.car.permission.CONTROL_CAR_FEATURES";
+ field TIRAMISU_0 String PERMISSION_USE_CAR_WATCHDOG = "android.car.permission.USE_CAR_WATCHDOG";
+ field TIRAMISU_0 String PERMISSION_CAR_MONITOR_INPUT = "android.car.permission.CAR_MONITOR_INPUT";
+ field TIRAMISU_0 String PERMISSION_REQUEST_CAR_EVS_ACTIVITY = "android.car.permission.REQUEST_CAR_EVS_ACTIVITY";
+ field TIRAMISU_0 String PERMISSION_CONTROL_CAR_EVS_ACTIVITY = "android.car.permission.CONTROL_CAR_EVS_ACTIVITY";
+ field TIRAMISU_0 String PERMISSION_USE_CAR_EVS_CAMERA = "android.car.permission.USE_CAR_EVS_CAMERA";
+ field TIRAMISU_0 String PERMISSION_MONITOR_CAR_EVS_STATUS = "android.car.permission.MONITOR_CAR_EVS_STATUS";
+ field TIRAMISU_0 String PERMISSION_USE_CAR_TELEMETRY_SERVICE = "android.car.permission.USE_CAR_TELEMETRY_SERVICE";
+ field TIRAMISU_0 int CONNECTION_TYPE_EMBEDDED = 5;
+ field TIRAMISU_0 String PERMISSION_TEMPLATE_RENDERER = "android.car.permission.TEMPLATE_RENDERER";
+ field TIRAMISU_0 String PERMISSION_CONTROL_CAR_WATCHDOG_CONFIG = "android.car.permission.CONTROL_CAR_WATCHDOG_CONFIG";
+ field TIRAMISU_0 String PERMISSION_COLLECT_CAR_WATCHDOG_METRICS = "android.car.permission.COLLECT_CAR_WATCHDOG_METRICS";
+ field TIRAMISU_0 @hiddenOnly String PERMISSION_COLLECT_CAR_CPU_INFO = "android.car.permission.COLLECT_CAR_CPU_INFO";
+ field TIRAMISU_0 String PERMISSION_CONTROL_CAR_APP_LAUNCH = "android.car.permission.CONTROL_CAR_APP_LAUNCH";
+ field TIRAMISU_1 String PERMISSION_MANAGE_THREAD_PRIORITY = "android.car.permission.MANAGE_THREAD_PRIORITY";
+ field TIRAMISU_0 @hiddenOnly String CAR_TEMPLATE_HOST_RENDERER_SERVICE = "android.car.template.host.RendererService";
+ field TIRAMISU_0 String CAR_INTENT_ACTION_MEDIA_TEMPLATE = "android.car.intent.action.MEDIA_TEMPLATE";
+ field TIRAMISU_0 String CAR_EXTRA_MEDIA_COMPONENT = "android.car.intent.extra.MEDIA_COMPONENT";
+ field TIRAMISU_0 String CAR_EXTRA_MEDIA_PACKAGE = "android.car.intent.extra.MEDIA_PACKAGE";
+ field TIRAMISU_0 String CAR_EXTRA_BROWSE_SERVICE_FOR_SESSION = "android.media.session.BROWSE_SERVICE";
+ field TIRAMISU_0 @hiddenOnly String CAR_SERVICE_INTERFACE_NAME = CommonConstants.CAR_SERVICE_INTERFACE;
+ field TIRAMISU_0 @hiddenOnly String CAR_CATEGORY_NAVIGATION = "android.car.cluster.NAVIGATION";
+ field TIRAMISU_0 String CAR_EXTRA_CLUSTER_ACTIVITY_STATE = "android.car.cluster.ClusterActivityState";
+ field TIRAMISU_0 long CAR_WAIT_TIMEOUT_WAIT_FOREVER = -1;
+ field TIRAMISU_0 long CAR_WAIT_TIMEOUT_DO_NOT_WAIT = 0;
+ field TIRAMISU_0 int FEATURE_REQUEST_SUCCESS = 0;
+ field TIRAMISU_0 int FEATURE_REQUEST_ALREADY_IN_THE_STATE = 1;
+ field TIRAMISU_0 int FEATURE_REQUEST_MANDATORY = 2;
+ field TIRAMISU_0 int FEATURE_REQUEST_NOT_EXISTING = 3;
+ method TIRAMISU_1 android.car.CarVersion getCarVersion();
+ method TIRAMISU_1 android.car.PlatformVersion getPlatformVersion();
+ method TIRAMISU_0 boolean isApiVersionAtLeast(int requiredApiVersionMajor);
+ method TIRAMISU_0 boolean isApiVersionAtLeast(int requiredApiVersionMajor, int requiredApiVersionMinor);
+ method TIRAMISU_0 boolean isApiAndPlatformVersionAtLeast(int requiredApiVersionMajor, int minPlatformSdkInt);
+ method TIRAMISU_0 boolean isApiAndPlatformVersionAtLeast(int requiredApiVersionMajor, int requiredApiVersionMinor, int minPlatformSdkInt);
+ method TIRAMISU_0 Car createCar(Context context, ServiceConnection serviceConnectionListener, Handler handler);
+ method TIRAMISU_0 Car createCar(Context context, ServiceConnection serviceConnectionListener);
+ method TIRAMISU_0 Car createCar(Context context);
+ method TIRAMISU_0 Car createCar(Context context, Handler handler);
+ method TIRAMISU_0 Car createCar(Context context, Handler handler, long waitTimeoutMs, CarServiceLifecycleListener statusChangeListener);
+ method TIRAMISU_0 void connect();
+ method TIRAMISU_0 void disconnect();
+ method TIRAMISU_0 boolean isConnected();
+ method TIRAMISU_0 boolean isConnecting();
+ method TIRAMISU_0 @hiddenOnly ServiceConnection getServiceConnectionListener();
+ method TIRAMISU_0 Object getCarManager(String serviceName);
+ method TIRAMISU_0 int getCarConnectionType();
+ method TIRAMISU_0 boolean isFeatureEnabled(String featureName);
+ method TIRAMISU_0 int enableFeature(String featureName);
+ method TIRAMISU_0 int disableFeature(String featureName);
+ method TIRAMISU_0 List<String> getAllEnabledFeatures();
+ method TIRAMISU_0 List<String> getAllPendingDisabledFeatures();
+ method TIRAMISU_0 List<String> getAllPendingEnabledFeatures();
+ method TIRAMISU_0 @hiddenOnly Context getContext();
+ method TIRAMISU_0 @hiddenOnly Handler getEventHandler();
+ method TIRAMISU_0 @hiddenOnly T handleRemoteExceptionFromCarService(RemoteException e, T returnValue);
+ method TIRAMISU_0 @hiddenOnly void handleRemoteExceptionFromCarService(RemoteException e);
+ method TIRAMISU_0 @hiddenOnly T handleRemoteExceptionFromCarService(Service service, RemoteException e, T returnValue);
+ method TIRAMISU_0 @hiddenOnly void handleRemoteExceptionFromCarService(Service service, RemoteException e);
+interface Car.CarServiceLifecycleListener package android.car
+ method TIRAMISU_0 void onLifecycleChanged(Car car, boolean ready);
+class @hide @SystemApi CarTelemetryManager package android.car.telemetry
+ field TIRAMISU_0 int STATUS_ADD_METRICS_CONFIG_SUCCEEDED = 0;
+ field TIRAMISU_0 int STATUS_ADD_METRICS_CONFIG_ALREADY_EXISTS = 1;
+ field TIRAMISU_0 int STATUS_ADD_METRICS_CONFIG_VERSION_TOO_OLD = 2;
+ field TIRAMISU_0 int STATUS_ADD_METRICS_CONFIG_PARSE_FAILED = 3;
+ field TIRAMISU_0 int STATUS_ADD_METRICS_CONFIG_SIGNATURE_VERIFICATION_FAILED = 4;
+ field TIRAMISU_0 int STATUS_ADD_METRICS_CONFIG_UNKNOWN = 5;
+ field TIRAMISU_0 int STATUS_GET_METRICS_CONFIG_FINISHED = 0;
+ field TIRAMISU_0 int STATUS_GET_METRICS_CONFIG_PENDING = 1;
+ field TIRAMISU_0 int STATUS_GET_METRICS_CONFIG_INTERIM_RESULTS = 2;
+ field TIRAMISU_0 int STATUS_GET_METRICS_CONFIG_RUNTIME_ERROR = 3;
+ field TIRAMISU_0 int STATUS_GET_METRICS_CONFIG_DOES_NOT_EXIST = 4;
+ method TIRAMISU_0 @hiddenOnly void onCarDisconnected();
+ method TIRAMISU_0 void addMetricsConfig(String metricsConfigName, byte[] metricsConfig, Executor executor, AddMetricsConfigCallback callback);
+ method TIRAMISU_0 void removeMetricsConfig(String metricsConfigName);
+ method TIRAMISU_0 void removeAllMetricsConfigs();
+ method TIRAMISU_0 void getFinishedReport(String metricsConfigName, Executor executor, MetricsReportCallback callback);
+ method TIRAMISU_0 void getAllFinishedReports(Executor executor, MetricsReportCallback callback);
+ method TIRAMISU_0 void setReportReadyListener(Executor executor, ReportReadyListener listener);
+ method TIRAMISU_0 void clearReportReadyListener();
+interface @hide @SystemApi CarTelemetryManager.AddMetricsConfigCallback package android.car.telemetry
+ method TIRAMISU_0 void onAddMetricsConfigStatus(String metricsConfigName, int statusCode);
+interface @hide @SystemApi CarTelemetryManager.MetricsReportCallback package android.car.telemetry
+ method TIRAMISU_0 void onResult(String metricsConfigName, PersistableBundle report, byte[] telemetryError, int status);
+interface @hide @SystemApi CarTelemetryManager.ReportReadyListener package android.car.telemetry
+ method TIRAMISU_0 void onReady(String metricsConfigName);
+class @hide @SystemApi ClusterActivityState package android.car.cluster
+ method TIRAMISU_0 boolean isVisible();
+ method TIRAMISU_0 Rect getUnobscuredBounds();
+ method TIRAMISU_0 Bundle getExtras();
+ method TIRAMISU_0 ClusterActivityState setVisible(boolean visible);
+ method TIRAMISU_0 ClusterActivityState setUnobscuredBounds(Rect unobscuredBounds);
+ method TIRAMISU_0 ClusterActivityState setExtras(Bundle bundle);
+ method TIRAMISU_0 ClusterActivityState create(boolean visible, Rect unobscuredBounds);
+ method TIRAMISU_0 ClusterActivityState fromBundle(Bundle bundle);
+ method TIRAMISU_0 Bundle toBundle();
+ method TIRAMISU_0 String toString();
+class @hide @SystemApi NavigationRenderer package android.car.cluster.renderer
+ method TIRAMISU_0 CarNavigationInstrumentCluster getNavigationProperties();
+ method TIRAMISU_0 void onEvent(int eventType, Bundle bundle);
+ method TIRAMISU_0 void onNavigationStateChanged(Bundle bundle);
+class @hide @SystemApi InstrumentClusterRenderer package android.car.cluster.renderer
+ method TIRAMISU_0 void onCreate(Context context);
+ method TIRAMISU_0 void onStart();
+ method TIRAMISU_0 void onStop();
+ method TIRAMISU_0 NavigationRenderer createNavigationRenderer();
+ method TIRAMISU_0 NavigationRenderer getNavigationRenderer();
+ method TIRAMISU_0 void initialize();
+class @hide @SystemApi InstrumentClusterRenderingService package android.car.cluster.renderer
+ field TIRAMISU_0 @hiddenOnly String EXTRA_BUNDLE_KEY_FOR_INSTRUMENT_CLUSTER_HELPER = "android.car.cluster.renderer.IInstrumentClusterHelper";
+ method TIRAMISU_0 IBinder onBind(Intent intent);
+ method TIRAMISU_0 NavigationRenderer getNavigationRenderer();
+ method TIRAMISU_0 void onKeyEvent(KeyEvent keyEvent);
+ method TIRAMISU_0 void onNavigationComponentLaunched();
+ method TIRAMISU_0 void onNavigationComponentReleased();
+ method TIRAMISU_0 boolean startFixedActivityModeForDisplayAndUser(Intent intent, ActivityOptions options, int userId);
+ method TIRAMISU_0 void stopFixedActivityMode(int displayId);
+ method TIRAMISU_0 @hiddenOnly ComponentName getComponentFromPackage(String packageName);
+ method TIRAMISU_0 boolean startNavigationActivity(ComponentName component);
+ method TIRAMISU_0 @hiddenOnly void setClusterActivityLaunchOptions(String category, ActivityOptions activityOptions);
+ method TIRAMISU_0 void setClusterActivityLaunchOptions(ActivityOptions activityOptions);
+ method TIRAMISU_0 @hiddenOnly void setClusterActivityState(String category, Bundle state);
+ method TIRAMISU_0 void setClusterActivityState(ClusterActivityState state);
+ method TIRAMISU_0 void dump(FileDescriptor fd, PrintWriter writer, String[] args);
+ method TIRAMISU_0 Bitmap getBitmap(Uri uri);
+ method TIRAMISU_0 Bitmap getBitmap(Uri uri, int width, int height);
+ method TIRAMISU_0 Bitmap getBitmap(Uri uri, int width, int height, float offLanesAlpha);
+class @hide @SystemApi CarInstrumentClusterManager package android.car.cluster
+ field TIRAMISU_0 String CATEGORY_NAVIGATION = "android.car.cluster.NAVIGATION";
+ field TIRAMISU_0 String KEY_EXTRA_ACTIVITY_STATE = "android.car.cluster.ClusterActivityState";
+ method TIRAMISU_0 void startActivity(Intent intent);
+ method TIRAMISU_0 void registerCallback(String category, Callback callback);
+ method TIRAMISU_0 void unregisterCallback(Callback callback);
+ method TIRAMISU_0 @hiddenOnly void onCarDisconnected();
+interface @hide @SystemApi CarInstrumentClusterManager.Callback package android.car.cluster
+ method TIRAMISU_0 void onClusterActivityStateChanged(String category, Bundle clusterActivityState);
+class @hiddenOnly @hide ClusterHomeManager package android.car.cluster
+ field TIRAMISU_0 int UI_TYPE_CLUSTER_NONE = -1;
+ field TIRAMISU_0 int UI_TYPE_CLUSTER_HOME = 0;
+ field TIRAMISU_0 int CONFIG_DISPLAY_ON_OFF = 0x01;
+ field TIRAMISU_0 int CONFIG_DISPLAY_BOUNDS = 0x02;
+ field TIRAMISU_0 int CONFIG_DISPLAY_INSETS = 0x04;
+ field TIRAMISU_0 int CONFIG_UI_TYPE = 0x08;
+ field TIRAMISU_0 int CONFIG_DISPLAY_ID = 0x10;
+ method TIRAMISU_0 void registerClusterStateListener(Executor executor, ClusterStateListener callback);
+ method TIRAMISU_0 void registerClusterNavigationStateListener(Executor executor, ClusterNavigationStateListener callback);
+ method TIRAMISU_0 void unregisterClusterStateListener(ClusterStateListener callback);
+ method TIRAMISU_0 void unregisterClusterNavigationStateListener(ClusterNavigationStateListener callback);
+ method TIRAMISU_0 void reportState(int uiTypeMain, int uiTypeSub, byte[] uiAvailability);
+ method TIRAMISU_0 void requestDisplay(int uiType);
+ method TIRAMISU_0 ClusterState getClusterState();
+ method TIRAMISU_0 boolean startFixedActivityModeAsUser(Intent intent, Bundle options, int userId);
+ method TIRAMISU_0 void stopFixedActivityMode();
+ method TIRAMISU_0 void onCarDisconnected();
+interface ClusterHomeManager.ClusterStateListener package android.car.cluster
+ method TIRAMISU_0 void onClusterStateChanged(ClusterState state, int changes);
+interface ClusterHomeManager.ClusterNavigationStateListener package android.car.cluster
+ method TIRAMISU_0 void onNavigationState(byte[] navigationState);
+class PortLocationType package android.car
+ field TIRAMISU_0 int UNKNOWN = 0;
+ field TIRAMISU_0 int FRONT_LEFT = 1;
+ field TIRAMISU_0 int FRONT_RIGHT = 2;
+ field TIRAMISU_0 int REAR_RIGHT = 3;
+ field TIRAMISU_0 int REAR_LEFT = 4;
+ field TIRAMISU_0 int FRONT = 5;
+ field TIRAMISU_0 int REAR = 6;
+class FuelType package android.car
+ field TIRAMISU_0 int UNKNOWN = 0;
+ field TIRAMISU_0 int UNLEADED = 1;
+ field TIRAMISU_0 int LEADED = 2;
+ field TIRAMISU_0 int DIESEL_1 = 3;
+ field TIRAMISU_0 int DIESEL_2 = 4;
+ field TIRAMISU_0 int BIODIESEL = 5;
+ field TIRAMISU_0 int E85 = 6;
+ field TIRAMISU_0 int LPG = 7;
+ field TIRAMISU_0 int CNG = 8;
+ field TIRAMISU_0 int LNG = 9;
+ field TIRAMISU_0 int ELECTRIC = 10;
+ field TIRAMISU_0 int HYDROGEN = 11;
+ field TIRAMISU_0 int OTHER = 12;
+class @hide @SystemApi VmsLayer package android.car.vms
+ field TIRAMISU_0 Parcelable.Creator<VmsLayer> CREATOR;
+ method TIRAMISU_0 int getSubtype();
+ method TIRAMISU_0 int getType();
+ method TIRAMISU_0 int getChannel();
+ method TIRAMISU_0 int getVersion();
+ method TIRAMISU_0 String toString();
+ method TIRAMISU_0 boolean equals(Object o);
+ method TIRAMISU_0 int hashCode();
+ method TIRAMISU_0 void writeToParcel(Parcel dest, int flags);
+ method TIRAMISU_0 int describeContents();
+class @hide @SystemApi VmsOperationRecorder package android.car.vms
+ method TIRAMISU_0 VmsOperationRecorder get();
+ method TIRAMISU_0 void subscribe(VmsLayer layer);
+ method TIRAMISU_0 void unsubscribe(VmsLayer layer);
+ method TIRAMISU_0 void subscribe(VmsLayer layer, int publisherId);
+ method TIRAMISU_0 void unsubscribe(VmsLayer layer, int publisherId);
+ method TIRAMISU_0 void startMonitoring();
+ method TIRAMISU_0 void stopMonitoring();
+ method TIRAMISU_0 void setLayersOffering(VmsLayersOffering layersOffering);
+ method TIRAMISU_0 void getPublisherId(int publisherId);
+ method TIRAMISU_0 void addSubscription(int sequenceNumber, VmsLayer layer);
+ method TIRAMISU_0 void removeSubscription(int sequenceNumber, VmsLayer layer);
+ method TIRAMISU_0 void addPromiscuousSubscription(int sequenceNumber);
+ method TIRAMISU_0 void removePromiscuousSubscription(int sequenceNumber);
+ method TIRAMISU_0 void addHalSubscription(int sequenceNumber, VmsLayer layer);
+ method TIRAMISU_0 void removeHalSubscription(int sequenceNumber, VmsLayer layer);
+ method TIRAMISU_0 void setPublisherLayersOffering(VmsLayersOffering layersOffering);
+ method TIRAMISU_0 void setHalPublisherLayersOffering(VmsLayersOffering layersOffering);
+class @hiddenOnly @hide VmsOperationRecorder.Writer package android.car.vms
+ method TIRAMISU_0 boolean isEnabled();
+ method TIRAMISU_0 void write(String msg);
+class @hide @SystemApi VmsAvailableLayers package android.car.vms
+ field TIRAMISU_0 Parcelable.Creator<VmsAvailableLayers> CREATOR;
+ method TIRAMISU_0 int getSequence();
+ method TIRAMISU_0 int getSequenceNumber();
+ method TIRAMISU_0 Set<VmsAssociatedLayer> getAssociatedLayers();
+ method TIRAMISU_0 String toString();
+ method TIRAMISU_0 boolean equals(Object o);
+ method TIRAMISU_0 int hashCode();
+ method TIRAMISU_0 void writeToParcel(Parcel dest, int flags);
+ method TIRAMISU_0 int describeContents();
+class @hiddenOnly @hide VmsSubscriptionHelper package android.car.vms
+ method TIRAMISU_0 void subscribe(VmsLayer layer);
+ method TIRAMISU_0 void subscribe(VmsLayer layer, int providerId);
+ method TIRAMISU_0 void unsubscribe(VmsLayer layer);
+ method TIRAMISU_0 void unsubscribe(VmsLayer layer, int providerId);
+ method TIRAMISU_0 Set<VmsAssociatedLayer> getSubscriptions();
+class @hide @SystemApi VmsClient package android.car.vms
+ method TIRAMISU_0 byte[] getProviderDescription(int providerId);
+ method TIRAMISU_0 void setSubscriptions(Set<VmsAssociatedLayer> layers);
+ method TIRAMISU_0 void setMonitoringEnabled(boolean enabled);
+ method TIRAMISU_0 boolean isMonitoringEnabled();
+ method TIRAMISU_0 VmsAvailableLayers getAvailableLayers();
+ method TIRAMISU_0 int registerProvider(byte[] providerDescription);
+ method TIRAMISU_0 void unregisterProvider(int providerId);
+ method TIRAMISU_0 void setProviderOfferings(int providerId, Set<VmsLayerDependency> offerings);
+ method TIRAMISU_0 void publishPacket(int providerId, VmsLayer layer, byte[] packet);
+ method TIRAMISU_0 VmsSubscriptionState getSubscriptionState();
+ method TIRAMISU_0 @hiddenOnly void register();
+ method TIRAMISU_0 @hiddenOnly void unregister();
+class @hide @SystemApi VmsLayerDependency package android.car.vms
+ field TIRAMISU_0 Parcelable.Creator<VmsLayerDependency> CREATOR;
+ method TIRAMISU_0 VmsLayer getLayer();
+ method TIRAMISU_0 Set<VmsLayer> getDependencies();
+ method TIRAMISU_0 String toString();
+ method TIRAMISU_0 boolean equals(Object o);
+ method TIRAMISU_0 int hashCode();
+ method TIRAMISU_0 void writeToParcel(Parcel dest, int flags);
+ method TIRAMISU_0 int describeContents();
+class @hiddenOnly @hide VmsRegistrationInfo package android.car.vms
+ field TIRAMISU_0 Parcelable.Creator<VmsRegistrationInfo> CREATOR;
+ method TIRAMISU_0 VmsAvailableLayers getAvailableLayers();
+ method TIRAMISU_0 VmsSubscriptionState getSubscriptionState();
+ method TIRAMISU_0 boolean equals(Object o);
+ method TIRAMISU_0 int hashCode();
+ method TIRAMISU_0 void writeToParcel(Parcel dest, int flags);
+ method TIRAMISU_0 int describeContents();
+class @hide @SystemApi VmsSubscriptionState package android.car.vms
+ field TIRAMISU_0 Parcelable.Creator<VmsSubscriptionState> CREATOR;
+ method TIRAMISU_0 int getSequenceNumber();
+ method TIRAMISU_0 Set<VmsLayer> getLayers();
+ method TIRAMISU_0 Set<VmsAssociatedLayer> getAssociatedLayers();
+ method TIRAMISU_0 String toString();
+ method TIRAMISU_0 boolean equals(Object o);
+ method TIRAMISU_0 int hashCode();
+ method TIRAMISU_0 void writeToParcel(Parcel dest, int flags);
+ method TIRAMISU_0 int describeContents();
+class @hide @SystemApi VmsLayersOffering package android.car.vms
+ field TIRAMISU_0 Parcelable.Creator<VmsLayersOffering> CREATOR;
+ method TIRAMISU_0 Set<VmsLayerDependency> getDependencies();
+ method TIRAMISU_0 int getPublisherId();
+ method TIRAMISU_0 String toString();
+ method TIRAMISU_0 boolean equals(Object o);
+ method TIRAMISU_0 int hashCode();
+ method TIRAMISU_0 void writeToParcel(Parcel dest, int flags);
+ method TIRAMISU_0 int describeContents();
+class @hide @SystemApi VmsAssociatedLayer package android.car.vms
+ field TIRAMISU_0 Parcelable.Creator<VmsAssociatedLayer> CREATOR;
+ method TIRAMISU_0 Set<Integer> getPublisherIds();
+ method TIRAMISU_0 VmsLayer getVmsLayer();
+ method TIRAMISU_0 Set<Integer> getProviderIds();
+ method TIRAMISU_0 String toString();
+ method TIRAMISU_0 boolean equals(Object o);
+ method TIRAMISU_0 int hashCode();
+ method TIRAMISU_0 void writeToParcel(Parcel dest, int flags);
+ method TIRAMISU_0 int describeContents();
+class @hide @SystemApi VmsPublisherClientService package android.car.vms
+ method TIRAMISU_0 void onCreate();
+ method TIRAMISU_0 void onDestroy();
+ method TIRAMISU_0 IBinder onBind(Intent intent);
+ method TIRAMISU_0 @hiddenOnly void onCarLifecycleChanged(Car car, boolean ready);
+ method TIRAMISU_0 void onVmsPublisherServiceReady();
+ method TIRAMISU_0 void onVmsSubscriptionChange(VmsSubscriptionState subscriptionState);
+ method TIRAMISU_0 void publish(VmsLayer layer, int publisherId, byte[] payload);
+ method TIRAMISU_0 void setLayersOffering(VmsLayersOffering offering);
+ method TIRAMISU_0 int getPublisherId(byte[] publisherInfo);
+ method TIRAMISU_0 VmsSubscriptionState getSubscriptions();
+class @hide @SystemApi VmsSubscriberManager package android.car.vms
+ method TIRAMISU_0 @hiddenOnly VmsSubscriberManager wrap(Car car, VmsClientManager clientManager);
+ method TIRAMISU_0 void setVmsSubscriberClientCallback(Executor executor, VmsSubscriberClientCallback clientCallback);
+ method TIRAMISU_0 void clearVmsSubscriberClientCallback();
+ method TIRAMISU_0 byte[] getPublisherInfo(int publisherId);
+ method TIRAMISU_0 VmsAvailableLayers getAvailableLayers();
+ method TIRAMISU_0 void subscribe(VmsLayer layer);
+ method TIRAMISU_0 void subscribe(VmsLayer layer, int publisherId);
+ method TIRAMISU_0 void startMonitoring();
+ method TIRAMISU_0 void unsubscribe(VmsLayer layer);
+ method TIRAMISU_0 void unsubscribe(VmsLayer layer, int publisherId);
+ method TIRAMISU_0 void stopMonitoring();
+ method TIRAMISU_0 @hiddenOnly void onCarDisconnected();
+interface VmsSubscriberManager.VmsSubscriberClientCallback package android.car.vms
+ method TIRAMISU_0 void onVmsMessageReceived(VmsLayer layer, byte[] payload);
+ method TIRAMISU_0 void onLayersAvailabilityChanged(VmsAvailableLayers availableLayers);
+class @hiddenOnly @hide VmsProviderInfo package android.car.vms
+ field TIRAMISU_0 Parcelable.Creator<VmsProviderInfo> CREATOR;
+ method TIRAMISU_0 byte[] getDescription();
+ method TIRAMISU_0 boolean equals(Object o);
+ method TIRAMISU_0 int hashCode();
+ method TIRAMISU_0 void writeToParcel(Parcel dest, int flags);
+ method TIRAMISU_0 int describeContents();
+class @hide @SystemApi VmsClientManager package android.car.vms
+ method TIRAMISU_0 void registerVmsClientCallback(Executor executor, VmsClientCallback callback);
+ method TIRAMISU_0 @hiddenOnly void registerVmsClientCallback(Executor executor, VmsClientCallback callback, boolean legacyClient);
+ method TIRAMISU_0 void unregisterVmsClientCallback(VmsClientCallback callback);
+ method TIRAMISU_0 @hiddenOnly void onCarDisconnected();
+interface VmsClientManager.VmsClientCallback package android.car.vms
+ method TIRAMISU_0 void onClientConnected(VmsClient client);
+ method TIRAMISU_0 void onLayerAvailabilityChanged(VmsAvailableLayers availableLayers);
+ method TIRAMISU_0 void onSubscriptionStateChanged(VmsSubscriptionState subscriptionState);
+ method TIRAMISU_0 void onPacketReceived(int providerId, VmsLayer layer, byte[] packet);
+class VehicleAreaWheel package android.car
+ field TIRAMISU_0 int WHEEL_UNKNOWN = 0x00;
+ field TIRAMISU_0 int WHEEL_LEFT_FRONT = 0x01;
+ field TIRAMISU_0 int WHEEL_RIGHT_FRONT = 0x02;
+ field TIRAMISU_0 int WHEEL_LEFT_REAR = 0x04;
+ field TIRAMISU_0 int WHEEL_RIGHT_REAR = 0x08;
+class @hiddenOnly @hide AndroidFuture package android.car.util.concurrent
+ field TIRAMISU_0 Parcelable.Creator<AndroidFuture> CREATOR;
+ method TIRAMISU_0 AndroidFuture<U> completedFuture(U value);
+ method TIRAMISU_0 boolean complete(T value);
+ method TIRAMISU_0 boolean completeExceptionally(Throwable ex);
+ method TIRAMISU_0 boolean cancel(boolean mayInterruptIfRunning);
+ method TIRAMISU_0 void onCompleted(T res, Throwable err);
+ method TIRAMISU_0 AndroidFuture<T> whenComplete(BiConsumer<? super T,? super Throwable> action);
+ method TIRAMISU_0 AndroidFuture<T> whenCompleteAsync(BiConsumer<? super T,? super Throwable> action, Executor executor);
+ method TIRAMISU_0 void callListener(BiConsumer<? super TT,? super Throwable> listener, TT res, Throwable err);
+ method TIRAMISU_0 AndroidFuture<T> orTimeout(long timeout, TimeUnit unit);
+ method TIRAMISU_0 void triggerTimeout();
+ method TIRAMISU_0 AndroidFuture<T> cancelTimeout();
+ method TIRAMISU_0 AndroidFuture<T> setTimeoutHandler(Handler h);
+ method TIRAMISU_0 AndroidFuture<U> thenCompose(Function<? super T,? extends CompletionStage<U>> fn);
+ method TIRAMISU_0 AndroidFuture<U> thenComposeAsync(Function<? super T,? extends CompletionStage<U>> fn, Executor executor);
+ method TIRAMISU_0 AndroidFuture<U> thenApply(Function<? super T,? extends U> fn);
+ method TIRAMISU_0 AndroidFuture<U> thenApplyAsync(Function<? super T,? extends U> fn, Executor executor);
+ method TIRAMISU_0 AndroidFuture<V> thenCombine(CompletionStage<? extends U> other, BiFunction<? super T,? super U,? extends V> combineResults);
+ method TIRAMISU_0 AndroidFuture<T> thenCombine(CompletionStage<Void> other);
+ method TIRAMISU_0 AndroidFuture<T> supply(Supplier<T> supplier);
+ method TIRAMISU_0 AndroidFuture<T> supplyAsync(Supplier<T> supplier, Executor executor);
+ method TIRAMISU_0 void writeToParcel(Parcel dest, int flags);
+ method TIRAMISU_0 Throwable unwrapExecutionException(Throwable t);
+ method TIRAMISU_0 int describeContents();
+class @hiddenOnly @hide AndroidAsyncFuture package android.car.util.concurrent
+ method TIRAMISU_0 T get();
+ method TIRAMISU_0 T get(long timeout, TimeUnit unit);
+ method TIRAMISU_0 AsyncFuture<T> whenCompleteAsync(BiConsumer<? super T,? super Throwable> action, Executor executor);
+interface @hiddenOnly @hide AsyncFuture package android.car.util.concurrent
+ method TIRAMISU_0 T get();
+ method TIRAMISU_0 T get(long timeout, TimeUnit unit);
+ method TIRAMISU_0 AsyncFuture<T> whenCompleteAsync(BiConsumer<? super T,? super Throwable> action, Executor executor);
+class @hide @SystemApi CarDiagnosticManager package android.car.diagnostic
+ field TIRAMISU_0 int FRAME_TYPE_LIVE = 0;
+ field TIRAMISU_0 int FRAME_TYPE_FREEZE = 1;
+ field TIRAMISU_0 @hiddenOnly int[] FRAME_TYPES = { FRAME_TYPE_LIVE, FRAME_TYPE_FREEZE };
+ method TIRAMISU_0 void onCarDisconnected();
+ method TIRAMISU_0 boolean registerListener(OnDiagnosticEventListener listener, int frameType, int rate);
+ method TIRAMISU_0 void unregisterListener(OnDiagnosticEventListener listener);
+ method TIRAMISU_0 CarDiagnosticEvent getLatestLiveFrame();
+ method TIRAMISU_0 long[] getFreezeFrameTimestamps();
+ method TIRAMISU_0 CarDiagnosticEvent getFreezeFrame(long timestamp);
+ method TIRAMISU_0 boolean clearFreezeFrames(long timestamps);
+ method TIRAMISU_0 boolean isLiveFrameSupported();
+ method TIRAMISU_0 boolean isFreezeFrameNotificationSupported();
+ method TIRAMISU_0 boolean isGetFreezeFrameSupported();
+ method TIRAMISU_0 boolean isClearFreezeFramesSupported();
+ method TIRAMISU_0 boolean isSelectiveClearFreezeFramesSupported();
+interface CarDiagnosticManager.OnDiagnosticEventListener package android.car.diagnostic
+ method TIRAMISU_0 void onDiagnosticEvent(CarDiagnosticEvent carDiagnosticEvent);
+class @hide @SystemApi FloatSensorIndex package android.car.diagnostic
+ field TIRAMISU_0 int CALCULATED_ENGINE_LOAD = 0;
+ field TIRAMISU_0 int ENGINE_COOLANT_TEMPERATURE = 1;
+ field TIRAMISU_0 int SHORT_TERM_FUEL_TRIM_BANK1 = 2;
+ field TIRAMISU_0 int LONG_TERM_FUEL_TRIM_BANK1 = 3;
+ field TIRAMISU_0 int SHORT_TERM_FUEL_TRIM_BANK2 = 4;
+ field TIRAMISU_0 int LONG_TERM_FUEL_TRIM_BANK2 = 5;
+ field TIRAMISU_0 int FUEL_PRESSURE = 6;
+ field TIRAMISU_0 int INTAKE_MANIFOLD_ABSOLUTE_PRESSURE = 7;
+ field TIRAMISU_0 int ENGINE_RPM = 8;
+ field TIRAMISU_0 int VEHICLE_SPEED = 9;
+ field TIRAMISU_0 int TIMING_ADVANCE = 10;
+ field TIRAMISU_0 int MAF_AIR_FLOW_RATE = 11;
+ field TIRAMISU_0 int THROTTLE_POSITION = 12;
+ field TIRAMISU_0 int OXYGEN_SENSOR1_VOLTAGE = 13;
+ field TIRAMISU_0 int OXYGEN_SENSOR1_SHORT_TERM_FUEL_TRIM = 14;
+ field TIRAMISU_0 int OXYGEN_SENSOR1_FUEL_AIR_EQUIVALENCE_RATIO = 15;
+ field TIRAMISU_0 int OXYGEN_SENSOR2_VOLTAGE = 16;
+ field TIRAMISU_0 int OXYGEN_SENSOR2_SHORT_TERM_FUEL_TRIM = 17;
+ field TIRAMISU_0 int OXYGEN_SENSOR2_FUEL_AIR_EQUIVALENCE_RATIO = 18;
+ field TIRAMISU_0 int OXYGEN_SENSOR3_VOLTAGE = 19;
+ field TIRAMISU_0 int OXYGEN_SENSOR3_SHORT_TERM_FUEL_TRIM = 20;
+ field TIRAMISU_0 int OXYGEN_SENSOR3_FUEL_AIR_EQUIVALENCE_RATIO = 21;
+ field TIRAMISU_0 int OXYGEN_SENSOR4_VOLTAGE = 22;
+ field TIRAMISU_0 int OXYGEN_SENSOR4_SHORT_TERM_FUEL_TRIM = 23;
+ field TIRAMISU_0 int OXYGEN_SENSOR4_FUEL_AIR_EQUIVALENCE_RATIO = 24;
+ field TIRAMISU_0 int OXYGEN_SENSOR5_VOLTAGE = 25;
+ field TIRAMISU_0 int OXYGEN_SENSOR5_SHORT_TERM_FUEL_TRIM = 26;
+ field TIRAMISU_0 int OXYGEN_SENSOR5_FUEL_AIR_EQUIVALENCE_RATIO = 27;
+ field TIRAMISU_0 int OXYGEN_SENSOR6_VOLTAGE = 28;
+ field TIRAMISU_0 int OXYGEN_SENSOR6_SHORT_TERM_FUEL_TRIM = 29;
+ field TIRAMISU_0 int OXYGEN_SENSOR6_FUEL_AIR_EQUIVALENCE_RATIO = 30;
+ field TIRAMISU_0 int OXYGEN_SENSOR7_VOLTAGE = 31;
+ field TIRAMISU_0 int OXYGEN_SENSOR7_SHORT_TERM_FUEL_TRIM = 32;
+ field TIRAMISU_0 int OXYGEN_SENSOR7_FUEL_AIR_EQUIVALENCE_RATIO = 33;
+ field TIRAMISU_0 int OXYGEN_SENSOR8_VOLTAGE = 34;
+ field TIRAMISU_0 int OXYGEN_SENSOR8_SHORT_TERM_FUEL_TRIM = 35;
+ field TIRAMISU_0 int OXYGEN_SENSOR8_FUEL_AIR_EQUIVALENCE_RATIO = 36;
+ field TIRAMISU_0 int FUEL_RAIL_PRESSURE = 37;
+ field TIRAMISU_0 int FUEL_RAIL_GAUGE_PRESSURE = 38;
+ field TIRAMISU_0 int COMMANDED_EXHAUST_GAS_RECIRCULATION = 39;
+ field TIRAMISU_0 int EXHAUST_GAS_RECIRCULATION_ERROR = 40;
+ field TIRAMISU_0 int COMMANDED_EVAPORATIVE_PURGE = 41;
+ field TIRAMISU_0 int FUEL_TANK_LEVEL_INPUT = 42;
+ field TIRAMISU_0 int EVAPORATION_SYSTEM_VAPOR_PRESSURE = 43;
+ field TIRAMISU_0 int CATALYST_TEMPERATURE_BANK1_SENSOR1 = 44;
+ field TIRAMISU_0 int CATALYST_TEMPERATURE_BANK2_SENSOR1 = 45;
+ field TIRAMISU_0 int CATALYST_TEMPERATURE_BANK1_SENSOR2 = 46;
+ field TIRAMISU_0 int CATALYST_TEMPERATURE_BANK2_SENSOR2 = 47;
+ field TIRAMISU_0 int ABSOLUTE_LOAD_VALUE = 48;
+ field TIRAMISU_0 int FUEL_AIR_COMMANDED_EQUIVALENCE_RATIO = 49;
+ field TIRAMISU_0 int RELATIVE_THROTTLE_POSITION = 50;
+ field TIRAMISU_0 int ABSOLUTE_THROTTLE_POSITION_B = 51;
+ field TIRAMISU_0 int ABSOLUTE_THROTTLE_POSITION_C = 52;
+ field TIRAMISU_0 int ACCELERATOR_PEDAL_POSITION_D = 53;
+ field TIRAMISU_0 int ACCELERATOR_PEDAL_POSITION_E = 54;
+ field TIRAMISU_0 int ACCELERATOR_PEDAL_POSITION_F = 55;
+ field TIRAMISU_0 int COMMANDED_THROTTLE_ACTUATOR = 56;
+ field TIRAMISU_0 int ETHANOL_FUEL_PERCENTAGE = 57;
+ field TIRAMISU_0 int ABSOLUTE_EVAPORATION_SYSTEM_VAPOR_PRESSURE = 58;
+ field TIRAMISU_0 int SHORT_TERM_SECONDARY_OXYGEN_SENSOR_TRIM_BANK1 = 59;
+ field TIRAMISU_0 int SHORT_TERM_SECONDARY_OXYGEN_SENSOR_TRIM_BANK2 = 60;
+ field TIRAMISU_0 int SHORT_TERM_SECONDARY_OXYGEN_SENSOR_TRIM_BANK3 = 61;
+ field TIRAMISU_0 int SHORT_TERM_SECONDARY_OXYGEN_SENSOR_TRIM_BANK4 = 62;
+ field TIRAMISU_0 int LONG_TERM_SECONDARY_OXYGEN_SENSOR_TRIM_BANK1 = 63;
+ field TIRAMISU_0 int LONG_TERM_SECONDARY_OXYGEN_SENSOR_TRIM_BANK2 = 64;
+ field TIRAMISU_0 int LONG_TERM_SECONDARY_OXYGEN_SENSOR_TRIM_BANK3 = 65;
+ field TIRAMISU_0 int LONG_TERM_SECONDARY_OXYGEN_SENSOR_TRIM_BANK4 = 66;
+ field TIRAMISU_0 int RELATIVE_ACCELERATOR_PEDAL_POSITION = 67;
+ field TIRAMISU_0 int HYBRID_BATTERY_PACK_REMAINING_LIFE = 68;
+ field TIRAMISU_0 int FUEL_INJECTION_TIMING = 69;
+ field TIRAMISU_0 int ENGINE_FUEL_RATE = 70;
+ field TIRAMISU_0 int LAST_SYSTEM = ENGINE_FUEL_RATE;
+ field TIRAMISU_0 int VENDOR_START = LAST_SYSTEM + 1;
+class @hide @SystemApi CarDiagnosticEvent package android.car.diagnostic
+ field TIRAMISU_0 int frameType;
+ field TIRAMISU_0 long timestamp;
+ field TIRAMISU_0 String dtc;
+ field TIRAMISU_0 Parcelable.Creator<CarDiagnosticEvent> CREATOR;
+ method TIRAMISU_0 int describeContents();
+ method TIRAMISU_0 void writeToParcel(Parcel dest, int flags);
+ method TIRAMISU_0 void writeToJson(JsonWriter jsonWriter);
+ method TIRAMISU_0 @hiddenOnly CarDiagnosticEvent withVendorSensorsRemoved();
+ method TIRAMISU_0 boolean isLiveFrame();
+ method TIRAMISU_0 boolean isFreezeFrame();
+ method TIRAMISU_0 @hiddenOnly boolean isEmptyFrame();
+ method TIRAMISU_0 @hiddenOnly CarDiagnosticEvent checkLiveFrame();
+ method TIRAMISU_0 @hiddenOnly CarDiagnosticEvent checkFreezeFrame();
+ method TIRAMISU_0 @hiddenOnly boolean isEarlierThan(CarDiagnosticEvent otherEvent);
+ method TIRAMISU_0 boolean equals(Object otherObject);
+ method TIRAMISU_0 int hashCode();
+ method TIRAMISU_0 String toString();
+ method TIRAMISU_0 int getSystemIntegerSensor(int sensor, int defaultValue);
+ method TIRAMISU_0 float getSystemFloatSensor(int sensor, float defaultValue);
+ method TIRAMISU_0 int getVendorIntegerSensor(int sensor, int defaultValue);
+ method TIRAMISU_0 float getVendorFloatSensor(int sensor, float defaultValue);
+ method TIRAMISU_0 Integer getSystemIntegerSensor(int sensor);
+ method TIRAMISU_0 Float getSystemFloatSensor(int sensor);
+ method TIRAMISU_0 Integer getVendorIntegerSensor(int sensor);
+ method TIRAMISU_0 Float getVendorFloatSensor(int sensor);
+ method TIRAMISU_0 Integer getFuelSystemStatus();
+ method TIRAMISU_0 Integer getSecondaryAirStatus();
+ method TIRAMISU_0 CommonIgnitionMonitors getIgnitionMonitors();
+ method TIRAMISU_0 Integer getFuelType();
+class CarDiagnosticEvent.Builder package android.car.diagnostic
+ method TIRAMISU_0 Builder newLiveFrameBuilder();
+ method TIRAMISU_0 Builder newFreezeFrameBuilder();
+ method TIRAMISU_0 Builder atTimestamp(long timestamp);
+ method TIRAMISU_0 Builder setTimeStamp(long timeStamp);
+ method TIRAMISU_0 Builder withIntValue(int key, int value);
+ method TIRAMISU_0 Builder setIntValue(int key, int value);
+ method TIRAMISU_0 Builder withFloatValue(int key, float value);
+ method TIRAMISU_0 Builder setFloatValue(int key, float value);
+ method TIRAMISU_0 Builder withDtc(String dtc);
+ method TIRAMISU_0 Builder setDtc(String dtc);
+ method TIRAMISU_0 CarDiagnosticEvent build();
+class CarDiagnosticEvent.FuelSystemStatus package android.car.diagnostic
+ field TIRAMISU_0 int OPEN_INSUFFICIENT_ENGINE_TEMPERATURE = 1;
+ field TIRAMISU_0 int CLOSED_LOOP = 2;
+ field TIRAMISU_0 int OPEN_ENGINE_LOAD_OR_DECELERATION = 4;
+ field TIRAMISU_0 int OPEN_SYSTEM_FAILURE = 8;
+ field TIRAMISU_0 int CLOSED_LOOP_BUT_FEEDBACK_FAULT = 16;
+class CarDiagnosticEvent.SecondaryAirStatus package android.car.diagnostic
+ field TIRAMISU_0 int UPSTREAM = 1;
+ field TIRAMISU_0 int DOWNSTREAM_OF_CATALYCIC_CONVERTER = 2;
+ field TIRAMISU_0 int FROM_OUTSIDE_OR_OFF = 4;
+ field TIRAMISU_0 int PUMP_ON_FOR_DIAGNOSTICS = 8;
+class CarDiagnosticEvent.FuelType package android.car.diagnostic
+ field TIRAMISU_0 int NOT_AVAILABLE = 0;
+ field TIRAMISU_0 int GASOLINE = 1;
+ field TIRAMISU_0 int METHANOL = 2;
+ field TIRAMISU_0 int ETHANOL = 3;
+ field TIRAMISU_0 int DIESEL = 4;
+ field TIRAMISU_0 int LPG = 5;
+ field TIRAMISU_0 int CNG = 6;
+ field TIRAMISU_0 int PROPANE = 7;
+ field TIRAMISU_0 int ELECTRIC = 8;
+ field TIRAMISU_0 int BIFUEL_RUNNING_GASOLINE = 9;
+ field TIRAMISU_0 int BIFUEL_RUNNING_METHANOL = 10;
+ field TIRAMISU_0 int BIFUEL_RUNNING_ETHANOL = 11;
+ field TIRAMISU_0 int BIFUEL_RUNNING_LPG = 12;
+ field TIRAMISU_0 int BIFUEL_RUNNING_CNG = 13;
+ field TIRAMISU_0 int BIFUEL_RUNNING_PROPANE = 14;
+ field TIRAMISU_0 int BIFUEL_RUNNING_ELECTRIC = 15;
+ field TIRAMISU_0 int BIFUEL_RUNNING_ELECTRIC_AND_COMBUSTION = 16;
+ field TIRAMISU_0 int HYBRID_GASOLINE = 17;
+ field TIRAMISU_0 int HYBRID_ETHANOL = 18;
+ field TIRAMISU_0 int HYBRID_DIESEL = 19;
+ field TIRAMISU_0 int HYBRID_ELECTRIC = 20;
+ field TIRAMISU_0 int HYBRID_RUNNING_ELECTRIC_AND_COMBUSTION = 21;
+ field TIRAMISU_0 int HYBRID_REGENERATIVE = 22;
+ field TIRAMISU_0 int BIFUEL_RUNNING_DIESEL = 23;
+class CarDiagnosticEvent.IgnitionMonitor package android.car.diagnostic
+ field TIRAMISU_0 boolean available;
+ field TIRAMISU_0 boolean incomplete;
+class @hiddenOnly @hide CarDiagnosticEvent.IgnitionMonitor.Decoder package android.car.diagnostic
+ method TIRAMISU_0 IgnitionMonitor fromValue(int value);
+class CarDiagnosticEvent.CommonIgnitionMonitors package android.car.diagnostic
+ field TIRAMISU_0 IgnitionMonitor components;
+ field TIRAMISU_0 IgnitionMonitor fuelSystem;
+ field TIRAMISU_0 IgnitionMonitor misfire;
+ field TIRAMISU_0 @hiddenOnly int COMPONENTS_AVAILABLE = 0x1 << 0;
+ field TIRAMISU_0 @hiddenOnly int COMPONENTS_INCOMPLETE = 0x1 << 1;
+ field TIRAMISU_0 @hiddenOnly int FUEL_SYSTEM_AVAILABLE = 0x1 << 2;
+ field TIRAMISU_0 @hiddenOnly int FUEL_SYSTEM_INCOMPLETE = 0x1 << 3;
+ field TIRAMISU_0 @hiddenOnly int MISFIRE_AVAILABLE = 0x1 << 4;
+ field TIRAMISU_0 @hiddenOnly int MISFIRE_INCOMPLETE = 0x1 << 5;
+ field TIRAMISU_0 IgnitionMonitor.Decoder COMPONENTS_DECODER = new IgnitionMonitor.Decoder(COMPONENTS_AVAILABLE, COMPONENTS_INCOMPLETE);
+ field TIRAMISU_0 IgnitionMonitor.Decoder FUEL_SYSTEM_DECODER = new IgnitionMonitor.Decoder(FUEL_SYSTEM_AVAILABLE, FUEL_SYSTEM_INCOMPLETE);
+ field TIRAMISU_0 IgnitionMonitor.Decoder MISFIRE_DECODER = new IgnitionMonitor.Decoder(MISFIRE_AVAILABLE, MISFIRE_INCOMPLETE);
+ method TIRAMISU_0 SparkIgnitionMonitors asSparkIgnitionMonitors();
+ method TIRAMISU_0 CompressionIgnitionMonitors asCompressionIgnitionMonitors();
+class CarDiagnosticEvent.SparkIgnitionMonitors package android.car.diagnostic
+ field TIRAMISU_0 IgnitionMonitor EGR;
+ field TIRAMISU_0 IgnitionMonitor oxygenSensorHeater;
+ field TIRAMISU_0 IgnitionMonitor oxygenSensor;
+ field TIRAMISU_0 IgnitionMonitor ACRefrigerant;
+ field TIRAMISU_0 IgnitionMonitor secondaryAirSystem;
+ field TIRAMISU_0 IgnitionMonitor evaporativeSystem;
+ field TIRAMISU_0 IgnitionMonitor heatedCatalyst;
+ field TIRAMISU_0 IgnitionMonitor catalyst;
+ field TIRAMISU_0 @hiddenOnly int EGR_AVAILABLE = 0x1 << 6;
+ field TIRAMISU_0 @hiddenOnly int EGR_INCOMPLETE = 0x1 << 7;
+ field TIRAMISU_0 @hiddenOnly int OXYGEN_SENSOR_HEATER_AVAILABLE = 0x1 << 8;
+ field TIRAMISU_0 @hiddenOnly int OXYGEN_SENSOR_HEATER_INCOMPLETE = 0x1 << 9;
+ field TIRAMISU_0 @hiddenOnly int OXYGEN_SENSOR_AVAILABLE = 0x1 << 10;
+ field TIRAMISU_0 @hiddenOnly int OXYGEN_SENSOR_INCOMPLETE = 0x1 << 11;
+ field TIRAMISU_0 @hiddenOnly int AC_REFRIGERANT_AVAILABLE = 0x1 << 12;
+ field TIRAMISU_0 @hiddenOnly int AC_REFRIGERANT_INCOMPLETE = 0x1 << 13;
+ field TIRAMISU_0 @hiddenOnly int SECONDARY_AIR_SYSTEM_AVAILABLE = 0x1 << 14;
+ field TIRAMISU_0 @hiddenOnly int SECONDARY_AIR_SYSTEM_INCOMPLETE = 0x1 << 15;
+ field TIRAMISU_0 @hiddenOnly int EVAPORATIVE_SYSTEM_AVAILABLE = 0x1 << 16;
+ field TIRAMISU_0 @hiddenOnly int EVAPORATIVE_SYSTEM_INCOMPLETE = 0x1 << 17;
+ field TIRAMISU_0 @hiddenOnly int HEATED_CATALYST_AVAILABLE = 0x1 << 18;
+ field TIRAMISU_0 @hiddenOnly int HEATED_CATALYST_INCOMPLETE = 0x1 << 19;
+ field TIRAMISU_0 @hiddenOnly int CATALYST_AVAILABLE = 0x1 << 20;
+ field TIRAMISU_0 @hiddenOnly int CATALYST_INCOMPLETE = 0x1 << 21;
+ field TIRAMISU_0 IgnitionMonitor.Decoder EGR_DECODER = new IgnitionMonitor.Decoder(EGR_AVAILABLE, EGR_INCOMPLETE);
+ field TIRAMISU_0 IgnitionMonitor.Decoder OXYGEN_SENSOR_HEATER_DECODER = new IgnitionMonitor.Decoder(OXYGEN_SENSOR_HEATER_AVAILABLE, OXYGEN_SENSOR_HEATER_INCOMPLETE);
+ field TIRAMISU_0 IgnitionMonitor.Decoder OXYGEN_SENSOR_DECODER = new IgnitionMonitor.Decoder(OXYGEN_SENSOR_AVAILABLE, OXYGEN_SENSOR_INCOMPLETE);
+ field TIRAMISU_0 IgnitionMonitor.Decoder AC_REFRIGERANT_DECODER = new IgnitionMonitor.Decoder(AC_REFRIGERANT_AVAILABLE, AC_REFRIGERANT_INCOMPLETE);
+ field TIRAMISU_0 IgnitionMonitor.Decoder SECONDARY_AIR_SYSTEM_DECODER = new IgnitionMonitor.Decoder(SECONDARY_AIR_SYSTEM_AVAILABLE, SECONDARY_AIR_SYSTEM_INCOMPLETE);
+ field TIRAMISU_0 IgnitionMonitor.Decoder EVAPORATIVE_SYSTEM_DECODER = new IgnitionMonitor.Decoder(EVAPORATIVE_SYSTEM_AVAILABLE, EVAPORATIVE_SYSTEM_INCOMPLETE);
+ field TIRAMISU_0 IgnitionMonitor.Decoder HEATED_CATALYST_DECODER = new IgnitionMonitor.Decoder(HEATED_CATALYST_AVAILABLE, HEATED_CATALYST_INCOMPLETE);
+ field TIRAMISU_0 IgnitionMonitor.Decoder CATALYST_DECODER = new IgnitionMonitor.Decoder(CATALYST_AVAILABLE, CATALYST_INCOMPLETE);
+class CarDiagnosticEvent.CompressionIgnitionMonitors package android.car.diagnostic
+ field TIRAMISU_0 IgnitionMonitor EGROrVVT;
+ field TIRAMISU_0 IgnitionMonitor PMFilter;
+ field TIRAMISU_0 IgnitionMonitor exhaustGasSensor;
+ field TIRAMISU_0 IgnitionMonitor boostPressure;
+ field TIRAMISU_0 IgnitionMonitor NOxSCR;
+ field TIRAMISU_0 IgnitionMonitor NMHCCatalyst;
+ field TIRAMISU_0 @hiddenOnly int EGR_OR_VVT_AVAILABLE = 0x1 << 6;
+ field TIRAMISU_0 @hiddenOnly int EGR_OR_VVT_INCOMPLETE = 0x1 << 7;
+ field TIRAMISU_0 @hiddenOnly int PM_FILTER_AVAILABLE = 0x1 << 8;
+ field TIRAMISU_0 @hiddenOnly int PM_FILTER_INCOMPLETE = 0x1 << 9;
+ field TIRAMISU_0 @hiddenOnly int EXHAUST_GAS_SENSOR_AVAILABLE = 0x1 << 10;
+ field TIRAMISU_0 @hiddenOnly int EXHAUST_GAS_SENSOR_INCOMPLETE = 0x1 << 11;
+ field TIRAMISU_0 @hiddenOnly int BOOST_PRESSURE_AVAILABLE = 0x1 << 12;
+ field TIRAMISU_0 @hiddenOnly int BOOST_PRESSURE_INCOMPLETE = 0x1 << 13;
+ field TIRAMISU_0 @hiddenOnly int NOx_SCR_AVAILABLE = 0x1 << 14;
+ field TIRAMISU_0 @hiddenOnly int NOx_SCR_INCOMPLETE = 0x1 << 15;
+ field TIRAMISU_0 @hiddenOnly int NMHC_CATALYST_AVAILABLE = 0x1 << 16;
+ field TIRAMISU_0 @hiddenOnly int NMHC_CATALYST_INCOMPLETE = 0x1 << 17;
+ field TIRAMISU_0 IgnitionMonitor.Decoder EGR_OR_VVT_DECODER = new IgnitionMonitor.Decoder(EGR_OR_VVT_AVAILABLE, EGR_OR_VVT_INCOMPLETE);
+ field TIRAMISU_0 IgnitionMonitor.Decoder PM_FILTER_DECODER = new IgnitionMonitor.Decoder(PM_FILTER_AVAILABLE, PM_FILTER_INCOMPLETE);
+ field TIRAMISU_0 IgnitionMonitor.Decoder EXHAUST_GAS_SENSOR_DECODER = new IgnitionMonitor.Decoder(EXHAUST_GAS_SENSOR_AVAILABLE, EXHAUST_GAS_SENSOR_INCOMPLETE);
+ field TIRAMISU_0 IgnitionMonitor.Decoder BOOST_PRESSURE_DECODER = new IgnitionMonitor.Decoder(BOOST_PRESSURE_AVAILABLE, BOOST_PRESSURE_INCOMPLETE);
+ field TIRAMISU_0 IgnitionMonitor.Decoder NOx_SCR_DECODER = new IgnitionMonitor.Decoder(NOx_SCR_AVAILABLE, NOx_SCR_INCOMPLETE);
+ field TIRAMISU_0 IgnitionMonitor.Decoder NMHC_CATALYST_DECODER = new IgnitionMonitor.Decoder(NMHC_CATALYST_AVAILABLE, NMHC_CATALYST_INCOMPLETE);
+class @hide @SystemApi IntegerSensorIndex package android.car.diagnostic
+ field TIRAMISU_0 int FUEL_SYSTEM_STATUS = 0;
+ field TIRAMISU_0 int MALFUNCTION_INDICATOR_LIGHT_ON = 1;
+ field TIRAMISU_0 int IGNITION_MONITORS_SUPPORTED = 2;
+ field TIRAMISU_0 int IGNITION_SPECIFIC_MONITORS = 3;
+ field TIRAMISU_0 int INTAKE_AIR_TEMPERATURE = 4;
+ field TIRAMISU_0 int COMMANDED_SECONDARY_AIR_STATUS = 5;
+ field TIRAMISU_0 int NUM_OXYGEN_SENSORS_PRESENT = 6;
+ field TIRAMISU_0 int RUNTIME_SINCE_ENGINE_START = 7;
+ field TIRAMISU_0 int DISTANCE_TRAVELED_WITH_MALFUNCTION_INDICATOR_LIGHT_ON = 8;
+ field TIRAMISU_0 int WARMUPS_SINCE_CODES_CLEARED = 9;
+ field TIRAMISU_0 int DISTANCE_TRAVELED_SINCE_CODES_CLEARED = 10;
+ field TIRAMISU_0 int ABSOLUTE_BAROMETRIC_PRESSURE = 11;
+ field TIRAMISU_0 int CONTROL_MODULE_VOLTAGE = 12;
+ field TIRAMISU_0 int AMBIENT_AIR_TEMPERATURE = 13;
+ field TIRAMISU_0 int TIME_WITH_MALFUNCTION_LIGHT_ON = 14;
+ field TIRAMISU_0 int TIME_SINCE_TROUBLE_CODES_CLEARED = 15;
+ field TIRAMISU_0 int MAX_FUEL_AIR_EQUIVALENCE_RATIO = 16;
+ field TIRAMISU_0 int MAX_OXYGEN_SENSOR_VOLTAGE = 17;
+ field TIRAMISU_0 int MAX_OXYGEN_SENSOR_CURRENT = 18;
+ field TIRAMISU_0 int MAX_INTAKE_MANIFOLD_ABSOLUTE_PRESSURE = 19;
+ field TIRAMISU_0 int MAX_AIR_FLOW_RATE_FROM_MASS_AIR_FLOW_SENSOR = 20;
+ field TIRAMISU_0 int FUEL_TYPE = 21;
+ field TIRAMISU_0 int FUEL_RAIL_ABSOLUTE_PRESSURE = 22;
+ field TIRAMISU_0 int ENGINE_OIL_TEMPERATURE = 23;
+ field TIRAMISU_0 int DRIVER_DEMAND_PERCENT_TORQUE = 24;
+ field TIRAMISU_0 int ENGINE_ACTUAL_PERCENT_TORQUE = 25;
+ field TIRAMISU_0 int ENGINE_REFERENCE_PERCENT_TORQUE = 26;
+ field TIRAMISU_0 int ENGINE_PERCENT_TORQUE_DATA_IDLE = 27;
+ field TIRAMISU_0 int ENGINE_PERCENT_TORQUE_DATA_POINT1 = 28;
+ field TIRAMISU_0 int ENGINE_PERCENT_TORQUE_DATA_POINT2 = 29;
+ field TIRAMISU_0 int ENGINE_PERCENT_TORQUE_DATA_POINT3 = 30;
+ field TIRAMISU_0 int ENGINE_PERCENT_TORQUE_DATA_POINT4 = 31;
+ field TIRAMISU_0 int LAST_SYSTEM = ENGINE_PERCENT_TORQUE_DATA_POINT4;
+ field TIRAMISU_0 int VENDOR_START = LAST_SYSTEM + 1;
+class VehiclePropertyIds package android.car
+ field TIRAMISU_0 int INVALID = 0;
+ field TIRAMISU_0 int INFO_VIN = 286261504;
+ field TIRAMISU_0 int INFO_MAKE = 286261505;
+ field TIRAMISU_0 int INFO_MODEL = 286261506;
+ field TIRAMISU_0 int INFO_MODEL_YEAR = 289407235;
+ field TIRAMISU_0 int INFO_FUEL_CAPACITY = 291504388;
+ field TIRAMISU_0 int INFO_FUEL_TYPE = 289472773;
+ field TIRAMISU_0 int INFO_EV_BATTERY_CAPACITY = 291504390;
+ field TIRAMISU_0 int INFO_EV_CONNECTOR_TYPE = 289472775;
+ field TIRAMISU_0 int INFO_FUEL_DOOR_LOCATION = 289407240;
+ field TIRAMISU_0 int INFO_EV_PORT_LOCATION = 289407241;
+ field TIRAMISU_0 int INFO_MULTI_EV_PORT_LOCATIONS = 289472780;
+ field TIRAMISU_0 int INFO_DRIVER_SEAT = 356516106;
+ field TIRAMISU_0 int INFO_EXTERIOR_DIMENSIONS = 289472779;
+ field TIRAMISU_0 int PERF_ODOMETER = 291504644;
+ field TIRAMISU_0 int PERF_VEHICLE_SPEED = 291504647;
+ field TIRAMISU_0 int PERF_VEHICLE_SPEED_DISPLAY = 291504648;
+ field TIRAMISU_0 int PERF_STEERING_ANGLE = 291504649;
+ field TIRAMISU_0 int PERF_REAR_STEERING_ANGLE = 291504656;
+ field TIRAMISU_0 int ENGINE_COOLANT_TEMP = 291504897;
+ field TIRAMISU_0 int ENGINE_OIL_LEVEL = 289407747;
+ field TIRAMISU_0 int ENGINE_OIL_TEMP = 291504900;
+ field TIRAMISU_0 int ENGINE_RPM = 291504901;
+ field TIRAMISU_0 int WHEEL_TICK = 290521862;
+ field TIRAMISU_0 int FUEL_LEVEL = 291504903;
+ field TIRAMISU_0 int FUEL_DOOR_OPEN = 287310600;
+ field TIRAMISU_0 int EV_BATTERY_LEVEL = 291504905;
+ field TIRAMISU_0 int EV_CHARGE_PORT_OPEN = 287310602;
+ field TIRAMISU_0 int EV_CHARGE_PORT_CONNECTED = 287310603;
+ field TIRAMISU_0 int EV_BATTERY_INSTANTANEOUS_CHARGE_RATE = 291504908;
+ field TIRAMISU_0 int RANGE_REMAINING = 291504904;
+ field TIRAMISU_0 int TIRE_PRESSURE = 392168201;
+ field TIRAMISU_0 int CRITICALLY_LOW_TIRE_PRESSURE = 392168202;
+ field TIRAMISU_0 int GEAR_SELECTION = 289408000;
+ field TIRAMISU_0 int CURRENT_GEAR = 289408001;
+ field TIRAMISU_0 int PARKING_BRAKE_ON = 287310850;
+ field TIRAMISU_0 int PARKING_BRAKE_AUTO_APPLY = 287310851;
+ field TIRAMISU_0 int FUEL_LEVEL_LOW = 287310853;
+ field TIRAMISU_0 int NIGHT_MODE = 287310855;
+ field TIRAMISU_0 int TURN_SIGNAL_STATE = 289408008;
+ field TIRAMISU_0 int IGNITION_STATE = 289408009;
+ field TIRAMISU_0 int ABS_ACTIVE = 287310858;
+ field TIRAMISU_0 int TRACTION_CONTROL_ACTIVE = 287310859;
+ field TIRAMISU_0 int HVAC_FAN_SPEED = 356517120;
+ field TIRAMISU_0 int HVAC_FAN_DIRECTION = 356517121;
+ field TIRAMISU_0 int HVAC_TEMPERATURE_CURRENT = 358614274;
+ field TIRAMISU_0 int HVAC_TEMPERATURE_SET = 358614275;
+ field TIRAMISU_0 int HVAC_TEMPERATURE_VALUE_SUGGESTION = 291570965;
+ field TIRAMISU_0 int HVAC_DEFROSTER = 320865540;
+ field TIRAMISU_0 int HVAC_AC_ON = 354419973;
+ field TIRAMISU_0 int HVAC_MAX_AC_ON = 354419974;
+ field TIRAMISU_0 int HVAC_MAX_DEFROST_ON = 354419975;
+ field TIRAMISU_0 int HVAC_RECIRC_ON = 354419976;
+ field TIRAMISU_0 int HVAC_DUAL_ON = 354419977;
+ field TIRAMISU_0 int HVAC_AUTO_ON = 354419978;
+ field TIRAMISU_0 int HVAC_SEAT_TEMPERATURE = 356517131;
+ field TIRAMISU_0 int HVAC_SIDE_MIRROR_HEAT = 339739916;
+ field TIRAMISU_0 int HVAC_STEERING_WHEEL_HEAT = 289408269;
+ field TIRAMISU_0 int HVAC_TEMPERATURE_DISPLAY_UNITS = 289408270;
+ field TIRAMISU_0 int HVAC_ACTUAL_FAN_SPEED_RPM = 356517135;
+ field TIRAMISU_0 int HVAC_POWER_ON = 354419984;
+ field TIRAMISU_0 int HVAC_FAN_DIRECTION_AVAILABLE = 356582673;
+ field TIRAMISU_0 int HVAC_AUTO_RECIRC_ON = 354419986;
+ field TIRAMISU_0 int HVAC_SEAT_VENTILATION = 356517139;
+ field TIRAMISU_0 int HVAC_ELECTRIC_DEFROSTER_ON = 320865556;
+ field TIRAMISU_0 int DISTANCE_DISPLAY_UNITS = 289408512;
+ field TIRAMISU_0 int FUEL_VOLUME_DISPLAY_UNITS = 289408513;
+ field TIRAMISU_0 int TIRE_PRESSURE_DISPLAY_UNITS = 289408514;
+ field TIRAMISU_0 int EV_BATTERY_DISPLAY_UNITS = 289408515;
+ field TIRAMISU_0 int VEHICLE_SPEED_DISPLAY_UNITS = 289408516;
+ field TIRAMISU_0 int FUEL_CONSUMPTION_UNITS_DISTANCE_OVER_VOLUME = 287311364;
+ field TIRAMISU_0 int ENV_OUTSIDE_TEMPERATURE = 291505923;
+ field TIRAMISU_0 int AP_POWER_STATE_REQ = 289475072;
+ field TIRAMISU_0 int AP_POWER_STATE_REPORT = 289475073;
+ field TIRAMISU_0 int AP_POWER_BOOTUP_REASON = 289409538;
+ field TIRAMISU_0 int DISPLAY_BRIGHTNESS = 289409539;
+ field TIRAMISU_0 int HW_KEY_INPUT = 289475088;
+ field TIRAMISU_0 int DOOR_POS = 373295872;
+ field TIRAMISU_0 int DOOR_MOVE = 373295873;
+ field TIRAMISU_0 int DOOR_LOCK = 371198722;
+ field TIRAMISU_0 int MIRROR_Z_POS = 339741504;
+ field TIRAMISU_0 int MIRROR_Z_MOVE = 339741505;
+ field TIRAMISU_0 int MIRROR_Y_POS = 339741506;
+ field TIRAMISU_0 int MIRROR_Y_MOVE = 339741507;
+ field TIRAMISU_0 int MIRROR_LOCK = 287312708;
+ field TIRAMISU_0 int MIRROR_FOLD = 287312709;
+ field TIRAMISU_0 int SEAT_MEMORY_SELECT = 356518784;
+ field TIRAMISU_0 int SEAT_MEMORY_SET = 356518785;
+ field TIRAMISU_0 int SEAT_BELT_BUCKLED = 354421634;
+ field TIRAMISU_0 int SEAT_BELT_HEIGHT_POS = 356518787;
+ field TIRAMISU_0 int SEAT_BELT_HEIGHT_MOVE = 356518788;
+ field TIRAMISU_0 int SEAT_FORE_AFT_POS = 356518789;
+ field TIRAMISU_0 int SEAT_FORE_AFT_MOVE = 356518790;
+ field TIRAMISU_0 int SEAT_BACKREST_ANGLE_1_POS = 356518791;
+ field TIRAMISU_0 int SEAT_BACKREST_ANGLE_1_MOVE = 356518792;
+ field TIRAMISU_0 int SEAT_BACKREST_ANGLE_2_POS = 356518793;
+ field TIRAMISU_0 int SEAT_BACKREST_ANGLE_2_MOVE = 356518794;
+ field TIRAMISU_0 int SEAT_HEIGHT_POS = 356518795;
+ field TIRAMISU_0 int SEAT_HEIGHT_MOVE = 356518796;
+ field TIRAMISU_0 int SEAT_DEPTH_POS = 356518797;
+ field TIRAMISU_0 int SEAT_DEPTH_MOVE = 356518798;
+ field TIRAMISU_0 int SEAT_TILT_POS = 356518799;
+ field TIRAMISU_0 int SEAT_TILT_MOVE = 356518800;
+ field TIRAMISU_0 int SEAT_LUMBAR_FORE_AFT_POS = 356518801;
+ field TIRAMISU_0 int SEAT_LUMBAR_FORE_AFT_MOVE = 356518802;
+ field TIRAMISU_0 int SEAT_LUMBAR_SIDE_SUPPORT_POS = 356518803;
+ field TIRAMISU_0 int SEAT_LUMBAR_SIDE_SUPPORT_MOVE = 356518804;
+ field TIRAMISU_0 int SEAT_HEADREST_HEIGHT_POS = 289409941;
+ field TIRAMISU_0 int SEAT_HEADREST_HEIGHT_MOVE = 356518806;
+ field TIRAMISU_0 int SEAT_HEADREST_ANGLE_POS = 356518807;
+ field TIRAMISU_0 int SEAT_HEADREST_ANGLE_MOVE = 356518808;
+ field TIRAMISU_0 int SEAT_HEADREST_FORE_AFT_POS = 356518809;
+ field TIRAMISU_0 int SEAT_HEADREST_FORE_AFT_MOVE = 356518810;
+ field TIRAMISU_0 int SEAT_OCCUPANCY = 356518832;
+ field TIRAMISU_0 int WINDOW_POS = 322964416;
+ field TIRAMISU_0 int WINDOW_MOVE = 322964417;
+ field TIRAMISU_0 int WINDOW_LOCK = 320867268;
+ field TIRAMISU_0 int VEHICLE_MAP_SERVICE = 299895808;
+ field TIRAMISU_0 int OBD2_LIVE_FRAME = 299896064;
+ field TIRAMISU_0 int OBD2_FREEZE_FRAME = 299896065;
+ field TIRAMISU_0 int OBD2_FREEZE_FRAME_INFO = 299896066;
+ field TIRAMISU_0 int OBD2_FREEZE_FRAME_CLEAR = 299896067;
+ field TIRAMISU_0 int HEADLIGHTS_STATE = 289410560;
+ field TIRAMISU_0 int HIGH_BEAM_LIGHTS_STATE = 289410561;
+ field TIRAMISU_0 int FOG_LIGHTS_STATE = 289410562;
+ field TIRAMISU_0 int HAZARD_LIGHTS_STATE = 289410563;
+ field TIRAMISU_0 int HEADLIGHTS_SWITCH = 289410576;
+ field TIRAMISU_0 int HIGH_BEAM_LIGHTS_SWITCH = 289410577;
+ field TIRAMISU_0 int FOG_LIGHTS_SWITCH = 289410578;
+ field TIRAMISU_0 int HAZARD_LIGHTS_SWITCH = 289410579;
+ field TIRAMISU_0 int CABIN_LIGHTS_STATE = 289410817;
+ field TIRAMISU_0 int CABIN_LIGHTS_SWITCH = 289410818;
+ field TIRAMISU_0 int READING_LIGHTS_STATE = 356519683;
+ field TIRAMISU_0 int READING_LIGHTS_SWITCH = 356519684;
+ field TIRAMISU_0 @hiddenOnly int INITIAL_USER_INFO = 299896583;
+ field TIRAMISU_0 @hiddenOnly int SWITCH_USER = 299896584;
+ field TIRAMISU_0 @hiddenOnly int CREATE_USER = 299896585;
+ field TIRAMISU_0 @hiddenOnly int REMOVE_USER = 299896586;
+ field TIRAMISU_0 @hiddenOnly int USER_IDENTIFICATION_ASSOCIATION = 299896587;
+ field TIRAMISU_0 @hiddenOnly int POWER_POLICY_REQ = 286265121;
+ field TIRAMISU_0 @hiddenOnly int POWER_POLICY_GROUP_REQ = 286265122;
+ field TIRAMISU_0 @hiddenOnly int CURRENT_POWER_POLICY = 286265123;
+ field TIRAMISU_0 @hiddenOnly int WATCHDOG_ALIVE = 290459441;
+ field TIRAMISU_0 @hiddenOnly int WATCHDOG_TERMINATED_PROCESS = 299896626;
+ field TIRAMISU_0 @hiddenOnly int VHAL_HEARTBEAT = 290459443;
+ field TIRAMISU_0 @hiddenOnly int CLUSTER_SWITCH_UI = 289410868;
+ field TIRAMISU_0 @hiddenOnly int CLUSTER_DISPLAY_STATE = 289476405;
+ field TIRAMISU_0 @hiddenOnly int CLUSTER_REPORT_STATE = 299896630;
+ field TIRAMISU_0 @hiddenOnly int CLUSTER_REQUEST_DISPLAY = 289410871;
+ field TIRAMISU_0 @hiddenOnly int CLUSTER_NAVIGATION_STATE = 292556600;
+ field TIRAMISU_0 int EPOCH_TIME = 290457094;
+ field TIRAMISU_0 int STORAGE_ENCRYPTION_BINDING_SEED = 292554247;
+ field TIRAMISU_0 int ELECTRONIC_TOLL_COLLECTION_CARD_TYPE = 289410873;
+ field TIRAMISU_0 int ELECTRONIC_TOLL_COLLECTION_CARD_STATUS = 289410874;
+ field TIRAMISU_0 int FRONT_FOG_LIGHTS_STATE = 289410875;
+ field TIRAMISU_0 int FRONT_FOG_LIGHTS_SWITCH = 289410876;
+ field TIRAMISU_0 int REAR_FOG_LIGHTS_STATE = 289410877;
+ field TIRAMISU_0 int REAR_FOG_LIGHTS_SWITCH = 289410878;
+ field TIRAMISU_0 int EV_CHARGE_CURRENT_DRAW_LIMIT = 291508031;
+ field TIRAMISU_0 int EV_CHARGE_PERCENT_LIMIT = 291508032;
+ field TIRAMISU_0 int EV_CHARGE_STATE = 289410881;
+ field TIRAMISU_0 int EV_CHARGE_SWITCH = 287313730;
+ field TIRAMISU_0 int EV_CHARGE_TIME_REMAINING = 289410883;
+ field TIRAMISU_0 int EV_REGENERATIVE_BRAKING_STATE = 289410884;
+ field TIRAMISU_0 int VEHICLE_CURB_WEIGHT = 289410886;
+ field TIRAMISU_0 int TRAILER_PRESENT = 289410885;
+ method TIRAMISU_0 String toString(int property);
+class VehicleUnit package android.car
+ field TIRAMISU_0 int SHOULD_NOT_USE = 0x000;
+ field TIRAMISU_0 int RPM = 0x02;
+ field TIRAMISU_0 int HERTZ = 0x03;
+ field TIRAMISU_0 int PERCENTILE = 0x10;
+ field TIRAMISU_0 int NANO_SECS = 0x50;
+ field TIRAMISU_0 int SECS = 0x53;
+ field TIRAMISU_0 int YEAR = 0x59;
+ field TIRAMISU_0 int MILLIAMPERE = 0x61;
+ field TIRAMISU_0 int MILLIVOLT = 0x62;
+ field TIRAMISU_0 int MILLIWATTS = 0x63;
+ field TIRAMISU_0 int DEGREES = 0x80;
+ field TIRAMISU_0 int MILLIMETER = 0x20;
+ field TIRAMISU_0 int METER = 0x21;
+ field TIRAMISU_0 int KILOMETER = 0x23;
+ field TIRAMISU_0 int MILE = 0x24;
+ field TIRAMISU_0 int CELSIUS = 0x30;
+ field TIRAMISU_0 int FAHRENHEIT = 0x31;
+ field TIRAMISU_0 int KELVIN = 0x32;
+ field TIRAMISU_0 int MILLILITER = 0x40;
+ field TIRAMISU_0 int LITER = 0x41;
+ field TIRAMISU_0 int US_GALLON = 0x42;
+ field TIRAMISU_0 int IMPERIAL_GALLON = 0x43;
+ field TIRAMISU_0 int WATT_HOUR = 0x60;
+ field TIRAMISU_0 int AMPERE_HOURS = 0x64;
+ field TIRAMISU_0 int KILOWATT_HOUR = 0x65;
+ field TIRAMISU_0 int KILOPASCAL = 0x70;
+ field TIRAMISU_0 int PSI = 0x71;
+ field TIRAMISU_0 int BAR = 0x72;
+ field TIRAMISU_0 int METER_PER_SEC = 0x01;
+ field TIRAMISU_0 int MILES_PER_HOUR = 0x90;
+ field TIRAMISU_0 int KILOMETERS_PER_HOUR = 0x91;
+class @hide @SystemApi CarPerformanceManager package android.car.os
+ method TIRAMISU_0 @hiddenOnly void onCarDisconnected();
+ method TIRAMISU_0 @hiddenOnly void addCpuAvailabilityChangeListener(Executor executor, CpuAvailabilityMonitoringConfig config, CpuAvailabilityChangeListener listener);
+ method TIRAMISU_0 @hiddenOnly void removeCpuAvailabilityChangeListener(Executor executor, CpuAvailabilityChangeListener listener);
+ method TIRAMISU_1 void setThreadPriority(ThreadPolicyWithPriority policyWithPriority);
+ method TIRAMISU_1 ThreadPolicyWithPriority getThreadPriority();
+class @hide @SystemApi CarPerformanceManager.SetSchedulerFailedException package android.car.os
+interface @hiddenOnly @hide CarPerformanceManager.CpuAvailabilityChangeListener package android.car.os
+ method TIRAMISU_0 void onCpuAvailabilityChange(CpuAvailabilityInfo info);
+class @hiddenOnly @hide CpuAvailabilityMonitoringConfig package android.car.os
+ field TIRAMISU_0 int CPUSET_ALL = 1;
+ field TIRAMISU_0 int CPUSET_BACKGROUND = 2;
+ field TIRAMISU_0 int IGNORE_PERCENT_LOWER_BOUND = 0;
+ field TIRAMISU_0 int IGNORE_PERCENT_UPPER_BOUND = 100;
+ field TIRAMISU_0 int MONITORING_TIMEOUT_NEVER = -1;
+ field TIRAMISU_0 int TIMEOUT_ACTION_NOTIFICATION = 1;
+ field TIRAMISU_0 int TIMEOUT_ACTION_REMOVE = 2;
+ field TIRAMISU_0 Parcelable.Creator<CpuAvailabilityMonitoringConfig> CREATOR;
+ method TIRAMISU_0 @hiddenOnly String cpusetToString(int value);
+ method TIRAMISU_0 @hiddenOnly String ignorePercentToString(int value);
+ method TIRAMISU_0 @hiddenOnly String timeoutActionToString(int value);
+ method TIRAMISU_0 int getCpuset();
+ method TIRAMISU_0 int getLowerBoundPercent();
+ method TIRAMISU_0 int getUpperBoundPercent();
+ method TIRAMISU_0 long getTimeoutInSeconds();
+ method TIRAMISU_0 int getTimeoutAction();
+ method TIRAMISU_0 String toString();
+ method TIRAMISU_0 void writeToParcel(android.os.Parcel dest, int flags);
+ method TIRAMISU_0 int describeContents();
+class CpuAvailabilityMonitoringConfig.Builder package android.car.os
+ method TIRAMISU_0 Builder setCpuset(int value);
+ method TIRAMISU_0 Builder setLowerBoundPercent(int value);
+ method TIRAMISU_0 Builder setUpperBoundPercent(int value);
+ method TIRAMISU_0 Builder setTimeoutInSeconds(long value);
+ method TIRAMISU_0 Builder setTimeoutAction(int value);
+ method TIRAMISU_0 CpuAvailabilityMonitoringConfig build();
+class @hide @SystemApi ThreadPolicyWithPriority package android.car.os
+ field TIRAMISU_1 int PRIORITY_MIN = 1;
+ field TIRAMISU_1 int PRIORITY_MAX = 99;
+ field TIRAMISU_1 int SCHED_DEFAULT = 0;
+ field TIRAMISU_1 int SCHED_FIFO = 1;
+ field TIRAMISU_1 int SCHED_RR = 2;
+ field TIRAMISU_1 Parcelable.Creator<ThreadPolicyWithPriority> CREATOR;
+ method @hiddenOnly String priorityToString(int value);
+ method TIRAMISU_1 @hiddenOnly String schedToString(int value);
+ method TIRAMISU_1 int getPolicy();
+ method TIRAMISU_1 int getPriority();
+ method TIRAMISU_1 void writeToParcel(android.os.Parcel dest, int flags);
+ method TIRAMISU_1 int describeContents();
+class @hiddenOnly @hide CpuAvailabilityInfo package android.car.os
+ field TIRAMISU_0 Parcelable.Creator<CpuAvailabilityInfo> CREATOR;
+ method TIRAMISU_0 int getCpuset();
+ method TIRAMISU_0 int getAverageAvailabilityPercent();
+ method TIRAMISU_0 boolean isTimeout();
+ method TIRAMISU_0 String toString();
+ method TIRAMISU_0 void writeToParcel(android.os.Parcel dest, int flags);
+ method TIRAMISU_0 int describeContents();
+class @hiddenOnly @hide CpuAvailabilityInfo.Builder package android.car.os
+ method TIRAMISU_0 Builder setCpuset(int value);
+ method TIRAMISU_0 Builder setAverageAvailabilityPercent(int value);
+ method TIRAMISU_0 Builder setTimeout(boolean value);
+ method TIRAMISU_0 CpuAvailabilityInfo build();
+class ResourceOveruseStats package android.car.watchdog
+ field TIRAMISU_0 Parcelable.Creator<ResourceOveruseStats> CREATOR;
+ method TIRAMISU_0 String getPackageName();
+ method TIRAMISU_0 UserHandle getUserHandle();
+ method TIRAMISU_0 IoOveruseStats getIoOveruseStats();
+ method TIRAMISU_0 String toString();
+ method TIRAMISU_0 void writeToParcel(android.os.Parcel dest, int flags);
+ method TIRAMISU_0 int describeContents();
+class @hiddenOnly @hide ResourceOveruseStats.Builder package android.car.watchdog
+ method TIRAMISU_0 Builder setPackageName(String value);
+ method TIRAMISU_0 Builder setUserHandle(UserHandle value);
+ method TIRAMISU_0 Builder setIoOveruseStats(IoOveruseStats value);
+ method TIRAMISU_0 ResourceOveruseStats build();
+class @hide @SystemApi IoOveruseAlertThreshold package android.car.watchdog
+ field TIRAMISU_0 Parcelable.Creator<IoOveruseAlertThreshold> CREATOR;
+ method TIRAMISU_0 long getDurationInSeconds();
+ method TIRAMISU_0 long getWrittenBytesPerSecond();
+ method TIRAMISU_0 String toString();
+ method TIRAMISU_0 void writeToParcel(android.os.Parcel dest, int flags);
+ method TIRAMISU_0 int describeContents();
+class IoOveruseStats package android.car.watchdog
+ field TIRAMISU_0 Parcelable.Creator<IoOveruseStats> CREATOR;
+ method TIRAMISU_0 long getStartTime();
+ method TIRAMISU_0 long getDurationInSeconds();
+ method TIRAMISU_0 long getTotalOveruses();
+ method TIRAMISU_0 long getTotalTimesKilled();
+ method TIRAMISU_0 long getTotalBytesWritten();
+ method TIRAMISU_0 boolean isKillableOnOveruse();
+ method TIRAMISU_0 PerStateBytes getRemainingWriteBytes();
+ method TIRAMISU_0 String toString();
+ method TIRAMISU_0 void writeToParcel(android.os.Parcel dest, int flags);
+ method TIRAMISU_0 int describeContents();
+class @hiddenOnly @hide IoOveruseStats.Builder package android.car.watchdog
+ method TIRAMISU_0 Builder setStartTime(long value);
+ method TIRAMISU_0 Builder setDurationInSeconds(long value);
+ method TIRAMISU_0 Builder setTotalOveruses(long value);
+ method TIRAMISU_0 Builder setTotalTimesKilled(long value);
+ method TIRAMISU_0 Builder setTotalBytesWritten(long value);
+ method TIRAMISU_0 Builder setKillableOnOveruse(boolean value);
+ method TIRAMISU_0 Builder setRemainingWriteBytes(PerStateBytes value);
+ method TIRAMISU_0 IoOveruseStats build();
+class CarWatchdogManager package android.car.watchdog
+ field TIRAMISU_0 int TIMEOUT_CRITICAL = 0;
+ field TIRAMISU_0 int TIMEOUT_MODERATE = 1;
+ field TIRAMISU_0 int TIMEOUT_NORMAL = 2;
+ field TIRAMISU_0 int STATS_PERIOD_CURRENT_DAY = 1;
+ field TIRAMISU_0 int STATS_PERIOD_PAST_3_DAYS = 2;
+ field TIRAMISU_0 int STATS_PERIOD_PAST_7_DAYS = 3;
+ field TIRAMISU_0 int STATS_PERIOD_PAST_15_DAYS = 4;
+ field TIRAMISU_0 int STATS_PERIOD_PAST_30_DAYS = 5;
+ field TIRAMISU_0 int FLAG_RESOURCE_OVERUSE_IO = 1 << 0;
+ field TIRAMISU_0 int FLAG_MINIMUM_STATS_IO_1_MB = 1 << 0;
+ field TIRAMISU_0 int FLAG_MINIMUM_STATS_IO_100_MB = 1 << 1;
+ field TIRAMISU_0 int FLAG_MINIMUM_STATS_IO_1_GB = 1 << 2;
+ field TIRAMISU_0 int RETURN_CODE_SUCCESS = 0;
+ field TIRAMISU_0 int RETURN_CODE_ERROR = -1;
+ method TIRAMISU_0 void registerClient(Executor executor, CarWatchdogClientCallback client, int timeout);
+ method TIRAMISU_0 void unregisterClient(CarWatchdogClientCallback client);
+ method TIRAMISU_0 void tellClientAlive(CarWatchdogClientCallback client, int sessionId);
+ method TIRAMISU_0 ResourceOveruseStats getResourceOveruseStats(int resourceOveruseFlag, int maxStatsPeriod);
+ method TIRAMISU_0 List<ResourceOveruseStats> getAllResourceOveruseStats(int resourceOveruseFlag, int minimumStatsFlag, int maxStatsPeriod);
+ method TIRAMISU_0 ResourceOveruseStats getResourceOveruseStatsForUserPackage(String packageName, UserHandle userHandle, int resourceOveruseFlag, int maxStatsPeriod);
+ method TIRAMISU_0 void addResourceOveruseListener(Executor executor, int resourceOveruseFlag, ResourceOveruseListener listener);
+ method TIRAMISU_0 void removeResourceOveruseListener(ResourceOveruseListener listener);
+ method TIRAMISU_0 void addResourceOveruseListenerForSystem(Executor executor, int resourceOveruseFlag, ResourceOveruseListener listener);
+ method TIRAMISU_0 void removeResourceOveruseListenerForSystem(ResourceOveruseListener listener);
+ method TIRAMISU_0 void setKillablePackageAsUser(String packageName, UserHandle userHandle, boolean isKillable);
+ method TIRAMISU_0 List<PackageKillableState> getPackageKillableStatesAsUser(UserHandle userHandle);
+ method TIRAMISU_0 int setResourceOveruseConfigurations(List<ResourceOveruseConfiguration> configurations, int resourceOveruseFlag);
+ method TIRAMISU_0 List<ResourceOveruseConfiguration> getResourceOveruseConfigurations(int resourceOveruseFlag);
+ method TIRAMISU_0 @hiddenOnly void onCarDisconnected();
+class @hide @SystemApi CarWatchdogManager.CarWatchdogClientCallback package android.car.watchdog
+ method TIRAMISU_0 boolean onCheckHealthStatus(int sessionId, int timeout);
+ method TIRAMISU_0 void onPrepareProcessTermination();
+interface CarWatchdogManager.ResourceOveruseListener package android.car.watchdog
+ method TIRAMISU_0 void onOveruse(ResourceOveruseStats resourceOveruseStats);
+class @hide @SystemApi IoOveruseConfiguration package android.car.watchdog
+ field TIRAMISU_0 Parcelable.Creator<IoOveruseConfiguration> CREATOR;
+ method TIRAMISU_0 PerStateBytes getComponentLevelThresholds();
+ method TIRAMISU_0 Map<String,PerStateBytes> getPackageSpecificThresholds();
+ method TIRAMISU_0 Map<String,PerStateBytes> getAppCategorySpecificThresholds();
+ method TIRAMISU_0 List<IoOveruseAlertThreshold> getSystemWideThresholds();
+ method TIRAMISU_0 String toString();
+ method TIRAMISU_0 void writeToParcel(android.os.Parcel dest, int flags);
+ method TIRAMISU_0 int describeContents();
+class IoOveruseConfiguration.Builder package android.car.watchdog
+ method TIRAMISU_0 Builder setComponentLevelThresholds(PerStateBytes value);
+ method TIRAMISU_0 Builder setPackageSpecificThresholds(Map<String,PerStateBytes> value);
+ method TIRAMISU_0 Builder addPackageSpecificThresholds(String key, PerStateBytes value);
+ method TIRAMISU_0 Builder setAppCategorySpecificThresholds(Map<String,PerStateBytes> value);
+ method TIRAMISU_0 Builder addAppCategorySpecificThresholds(String key, PerStateBytes value);
+ method TIRAMISU_0 Builder setSystemWideThresholds(List<IoOveruseAlertThreshold> value);
+ method TIRAMISU_0 Builder addSystemWideThresholds(IoOveruseAlertThreshold value);
+ method TIRAMISU_0 IoOveruseConfiguration build();
+class @hide @SystemApi ResourceOveruseConfiguration package android.car.watchdog
+ field TIRAMISU_0 int COMPONENT_TYPE_SYSTEM = 1;
+ field TIRAMISU_0 int COMPONENT_TYPE_VENDOR = 2;
+ field TIRAMISU_0 int COMPONENT_TYPE_THIRD_PARTY = 3;
+ field TIRAMISU_0 String APPLICATION_CATEGORY_TYPE_MAPS = "android.car.watchdog.app.category.MAPS";
+ field TIRAMISU_0 String APPLICATION_CATEGORY_TYPE_MEDIA = "android.car.watchdog.app.category.MEDIA";
+ field TIRAMISU_0 Parcelable.Creator<ResourceOveruseConfiguration> CREATOR;
+ method TIRAMISU_0 @hiddenOnly String componentTypeToString(int value);
+ method TIRAMISU_0 int getComponentType();
+ method TIRAMISU_0 List<String> getSafeToKillPackages();
+ method TIRAMISU_0 List<String> getVendorPackagePrefixes();
+ method TIRAMISU_0 Map<String,String> getPackagesToAppCategoryTypes();
+ method TIRAMISU_0 IoOveruseConfiguration getIoOveruseConfiguration();
+ method TIRAMISU_0 String toString();
+ method TIRAMISU_0 void writeToParcel(android.os.Parcel dest, int flags);
+ method TIRAMISU_0 int describeContents();
+class ResourceOveruseConfiguration.Builder package android.car.watchdog
+ method TIRAMISU_0 Builder setComponentType(int value);
+ method TIRAMISU_0 Builder setSafeToKillPackages(List<String> value);
+ method TIRAMISU_0 Builder addSafeToKillPackages(String value);
+ method TIRAMISU_0 Builder setVendorPackagePrefixes(List<String> value);
+ method TIRAMISU_0 Builder addVendorPackagePrefixes(String value);
+ method TIRAMISU_0 Builder setPackagesToAppCategoryTypes(Map<String,String> value);
+ method TIRAMISU_0 Builder addPackagesToAppCategoryTypes(String key, String value);
+ method TIRAMISU_0 Builder setIoOveruseConfiguration(IoOveruseConfiguration value);
+ method TIRAMISU_0 ResourceOveruseConfiguration build();
+class PerStateBytes package android.car.watchdog
+ field TIRAMISU_0 Parcelable.Creator<PerStateBytes> CREATOR;
+ method TIRAMISU_0 long getForegroundModeBytes();
+ method TIRAMISU_0 long getBackgroundModeBytes();
+ method TIRAMISU_0 long getGarageModeBytes();
+ method TIRAMISU_0 String toString();
+ method TIRAMISU_0 void writeToParcel(android.os.Parcel dest, int flags);
+ method TIRAMISU_0 int describeContents();
+class @hide @SystemApi PackageKillableState package android.car.watchdog
+ field TIRAMISU_0 int KILLABLE_STATE_YES = 1;
+ field TIRAMISU_0 int KILLABLE_STATE_NO = 2;
+ field TIRAMISU_0 int KILLABLE_STATE_NEVER = 3;
+ field TIRAMISU_0 Parcelable.Creator<PackageKillableState> CREATOR;
+ method TIRAMISU_0 @hiddenOnly String killableStateToString(int value);
+ method TIRAMISU_0 String getPackageName();
+ method TIRAMISU_0 int getUserId();
+ method TIRAMISU_0 int getKillableState();
+ method TIRAMISU_0 String toString();
+ method TIRAMISU_0 void writeToParcel(android.os.Parcel dest, int flags);
+ method TIRAMISU_0 int describeContents();
+class CarAppFocusManager package android.car
+ field TIRAMISU_0 int APP_FOCUS_TYPE_NAVIGATION = 1;
+ field TIRAMISU_0 int APP_FOCUS_TYPE_VOICE_COMMAND = 2;
+ field TIRAMISU_0 @hiddenOnly int APP_FOCUS_MAX = 2;
+ field TIRAMISU_0 int APP_FOCUS_REQUEST_FAILED = 0;
+ field TIRAMISU_0 int APP_FOCUS_REQUEST_SUCCEEDED = 1;
+ method TIRAMISU_0 void addFocusListener(OnAppFocusChangedListener listener, int appType);
+ method TIRAMISU_0 void removeFocusListener(OnAppFocusChangedListener listener, int appType);
+ method TIRAMISU_0 void removeFocusListener(OnAppFocusChangedListener listener);
+ method TIRAMISU_0 @hiddenOnly int[] getActiveAppTypes();
+ method TIRAMISU_0 @hiddenOnly List<String> getAppTypeOwner(int appType);
+ method TIRAMISU_0 boolean isOwningFocus(OnAppFocusOwnershipCallback callback, int appType);
+ method TIRAMISU_0 int requestAppFocus(int appType, OnAppFocusOwnershipCallback ownershipCallback);
+ method TIRAMISU_0 void abandonAppFocus(OnAppFocusOwnershipCallback ownershipCallback, int appType);
+ method TIRAMISU_0 void abandonAppFocus(OnAppFocusOwnershipCallback ownershipCallback);
+ method TIRAMISU_0 @hiddenOnly void onCarDisconnected();
+interface CarAppFocusManager.OnAppFocusChangedListener package android.car
+ method TIRAMISU_0 void onAppFocusChanged(int appType, boolean active);
+interface CarAppFocusManager.OnAppFocusOwnershipCallback package android.car
+ method TIRAMISU_0 void onAppFocusOwnershipLost(int appType);
+ method TIRAMISU_0 void onAppFocusOwnershipGranted(int appType);
+class CarVersion package android.car
+ field TIRAMISU_1 Parcelable.Creator<CarVersion> CREATOR;
+ method TIRAMISU_1 CarVersion forMajorAndMinorVersions(int majorVersion, int minorVersion);
+ method TIRAMISU_1 CarVersion forMajorVersion(int majorVersion);
+ method TIRAMISU_1 int describeContents();
+ method TIRAMISU_1 void writeToParcel(Parcel dest, int flags);
+class CarVersion.VERSION_CODES package android.car
+ field TIRAMISU_1 CarVersion TIRAMISU_0 = forMajorAndMinorVersions(Build.VERSION_CODES.TIRAMISU, 0);
+ field TIRAMISU_1 CarVersion TIRAMISU_1 = forMajorAndMinorVersions(Build.VERSION_CODES.TIRAMISU, 1);
diff --git a/tools/GenericCarApiBuilder/complete_car_built_in_api_list.txt b/tools/GenericCarApiBuilder/complete_car_built_in_api_list.txt
new file mode 100644
index 0000000..387164c
--- /dev/null
+++ b/tools/GenericCarApiBuilder/complete_car_built_in_api_list.txt
@@ -0,0 +1,339 @@
+class @hide @SystemApi AudioManagerHelper package android.car.builtin.media
+ field TIRAMISU_0 int UNDEFINED_STREAM_TYPE = -1;
+ method TIRAMISU_0 boolean setAudioDeviceGain(AudioManager audioManager, String address, int gainInMillibels, boolean isOutput);
+ method TIRAMISU_0 AudioGainInfo getAudioGainInfo(AudioDeviceInfo deviceInfo);
+ method TIRAMISU_0 AudioPatchInfo createAudioPatch(AudioDeviceInfo sourceDevice, AudioDeviceInfo sinkDevice, int gainInMillibels);
+ method TIRAMISU_0 boolean releaseAudioPatch(AudioManager audioManager, AudioPatchInfo info);
+ method TIRAMISU_0 String usageToString(int usage);
+ method TIRAMISU_0 String usageToXsdString(int usage);
+ method TIRAMISU_0 int xsdStringToUsage(String usage);
+ method TIRAMISU_0 int getUsageVirtualSource();
+ method TIRAMISU_0 String adjustToString(int adjustment);
+ method TIRAMISU_0 void setMasterMute(AudioManager audioManager, boolean mute, int flags);
+ method TIRAMISU_0 boolean isMasterMute(AudioManager audioManager);
+ method TIRAMISU_0 void registerVolumeAndMuteReceiver(Context context, VolumeAndMuteReceiver audioAndMuteHelper);
+ method TIRAMISU_0 void unregisterVolumeAndMuteReceiver(Context context, VolumeAndMuteReceiver audioAndMuteHelper);
+ method TIRAMISU_0 boolean isCallFocusRequestClientId(String clientId);
+class AudioManagerHelper.AudioGainInfo package android.car.builtin.media
+ method TIRAMISU_0 int getMinGain();
+ method TIRAMISU_0 int getMaxGain();
+ method TIRAMISU_0 int getDefaultGain();
+ method TIRAMISU_0 int getStepValue();
+class AudioManagerHelper.AudioPatchInfo package android.car.builtin.media
+ method TIRAMISU_0 int getHandleId();
+ method TIRAMISU_0 String getSourceAddress();
+ method TIRAMISU_0 String getSinkAddress();
+ method TIRAMISU_0 String toString();
+class AudioManagerHelper.VolumeAndMuteReceiver package android.car.builtin.media
+ method TIRAMISU_0 void onVolumeChanged(int streamType);
+ method TIRAMISU_0 void onMuteChanged();
+class @hide @SystemApi PackageManagerHelper package android.car.builtin.content.pm
+ field TIRAMISU_0 String PROPERTY_CAR_SERVICE_PACKAGE_NAME = "ro.android.car.carservice.package";
+ field TIRAMISU_0 String PROPERTY_CAR_SERVICE_OVERLAY_PACKAGES = "ro.android.car.carservice.overlay.packages";
+ method TIRAMISU_0 String getSystemUiPackageName(Context context);
+ method TIRAMISU_0 PackageInfo getPackageInfoAsUser(PackageManager pm, String packageName, int packageInfoFlags, int userId);
+ method TIRAMISU_0 int getPackageUidAsUser(PackageManager pm, String packageName, int userId);
+ method TIRAMISU_0 String[] getNamesForUids(PackageManager pm, int[] uids);
+ method TIRAMISU_0 int getApplicationEnabledSettingForUser(String packageName, int userId);
+ method TIRAMISU_0 void setApplicationEnabledSettingForUser(String packageName, int newState, int flags, int userId, String callingPackage);
+ method TIRAMISU_0 boolean isOemApp(ApplicationInfo appInfo);
+ method TIRAMISU_0 boolean isOdmApp(ApplicationInfo appInfo);
+ method TIRAMISU_0 boolean isVendorApp(ApplicationInfo appInfo);
+ method TIRAMISU_0 boolean isSystemApp(ApplicationInfo appInfo);
+ method TIRAMISU_0 boolean isUpdatedSystemApp(ApplicationInfo appInfo);
+ method TIRAMISU_0 boolean isProductApp(ApplicationInfo appInfo);
+ method TIRAMISU_0 boolean isSystemExtApp(ApplicationInfo appInfo);
+ method TIRAMISU_0 ComponentName getComponentName(ComponentInfo info);
+class @hide @SystemApi ContextHelper package android.car.builtin.content
+ method TIRAMISU_0 int getDisplayId(Context context);
+ method TIRAMISU_0 void startActivityAsUser(Context context, Intent intent, Bundle options, UserHandle user);
+class @hide @SystemApi JobSchedulerHelper package android.car.builtin.job
+ method TIRAMISU_0 int getNumberOfRunningJobsAtIdle(Context context);
+ method TIRAMISU_0 int getNumberOfPendingJobs(Context context);
+class @hide @SystemApi DisplayHelper package android.car.builtin.view
+ field TIRAMISU_0 int INVALID_PORT = -1;
+ field TIRAMISU_0 int TYPE_INTERNAL = Display.TYPE_INTERNAL;
+ field TIRAMISU_0 int TYPE_EXTERNAL = Display.TYPE_EXTERNAL;
+ field TIRAMISU_0 int TYPE_VIRTUAL = Display.TYPE_VIRTUAL;
+ method TIRAMISU_0 int getPhysicalPort(Display display);
+ method TIRAMISU_0 String getUniqueId(Display display);
+ method TIRAMISU_0 int getType(Display display);
+class @hide @SystemApi KeyEventHelper package android.car.builtin.view
+ method TIRAMISU_0 void setDisplayId(KeyEvent keyEvent, int newDisplayId);
+class @hide @SystemApi DisplayAreaOrganizerHelper package android.car.builtin.window
+ field TIRAMISU_0 int FEATURE_UNDEFINED = DisplayAreaOrganizer.FEATURE_UNDEFINED;
+class @hide @SystemApi LockPatternHelper package android.car.builtin.widget
+ method TIRAMISU_0 boolean isSecure(Context context, int userId);
+class @hide @SystemApi AdvertisingSetHelper package android.car.builtin.bluetooth.le
+ method TIRAMISU_1 void getOwnAddress(AdvertisingSet advertisingSet);
+class @hide @SystemApi AdvertisingSetCallbackHelper package android.car.builtin.bluetooth.le
+ method TIRAMISU_1 AdvertisingSetCallback createRealCallbackFromProxy(Callback proxy);
+class AdvertisingSetCallbackHelper.Callback package android.car.builtin.bluetooth.le
+ method TIRAMISU_1 void onAdvertisingSetStarted(AdvertisingSet advertisingSet, int txPower, int status);
+ method TIRAMISU_1 void onAdvertisingSetStopped(AdvertisingSet advertisingSet);
+ method TIRAMISU_1 void onAdvertisingEnabled(AdvertisingSet advertisingSet, boolean enable, int status);
+ method TIRAMISU_1 void onAdvertisingDataSet(AdvertisingSet advertisingSet, int status);
+ method TIRAMISU_1 void onScanResponseDataSet(AdvertisingSet advertisingSet, int status);
+ method TIRAMISU_1 void onAdvertisingParametersUpdated(AdvertisingSet advertisingSet, int txPower, int status);
+ method TIRAMISU_1 void onPeriodicAdvertisingParametersUpdated(AdvertisingSet advertisingSet, int status);
+ method TIRAMISU_1 void onPeriodicAdvertisingDataSet(AdvertisingSet advertisingSet, int status);
+ method TIRAMISU_1 void onPeriodicAdvertisingEnabled(AdvertisingSet advertisingSet, boolean enable, int status);
+ method TIRAMISU_1 void onOwnAddressRead(AdvertisingSet advertisingSet, int addressType, String address);
+class @hide @SystemApi BluetoothHeadsetClientHelper package android.car.builtin.bluetooth
+ method TIRAMISU_0 List<BluetoothDevice> getConnectedBvraDevices(BluetoothHeadsetClient headsetClient);
+ method TIRAMISU_0 boolean startVoiceRecognition(BluetoothHeadsetClient headsetClient, BluetoothDevice device);
+ method TIRAMISU_0 boolean stopVoiceRecognition(BluetoothHeadsetClient headsetClient, BluetoothDevice device);
+class @hide @SystemApi InputManagerHelper package android.car.builtin.input
+ method TIRAMISU_0 boolean injectInputEvent(InputManager inputManager, android.view.InputEvent event);
+class @hide @SystemApi VoiceInteractionHelper package android.car.builtin.app
+ method TIRAMISU_0 boolean isAvailable();
+ method TIRAMISU_0 void setEnabled(boolean enabled);
+class @hide @SystemApi TaskInfoHelper package android.car.builtin.app
+ method TIRAMISU_0 int getDisplayId(TaskInfo task);
+ method TIRAMISU_0 int getUserId(TaskInfo task);
+ method TIRAMISU_0 boolean isVisible(TaskInfo task);
+ method TIRAMISU_0 String toString(TaskInfo task);
+class @hide @SystemApi ActivityManagerHelper package android.car.builtin.app
+ field TIRAMISU_0 int INVALID_TASK_ID = ActivityTaskManager.INVALID_TASK_ID;
+ method TIRAMISU_0 boolean startUserInBackground(int userId);
+ method TIRAMISU_0 boolean startUserInForeground(int userId);
+ method TIRAMISU_0 int stopUserWithDelayedLocking(int userId, boolean force);
+ method TIRAMISU_0 boolean unlockUser(int userId);
+ method TIRAMISU_0 void stopAllTasksForUser(int userId);
+ method TIRAMISU_0 ActivityOptions createActivityOptions(Bundle bOptions);
+ method TIRAMISU_0 void setFocusedRootTask(int taskId);
+ method TIRAMISU_0 boolean removeTask(int taskId);
+ method TIRAMISU_0 void registerProcessObserverCallback(ProcessObserverCallback callback);
+ method TIRAMISU_0 void unregisterProcessObserverCallback(ProcessObserverCallback callback);
+ method TIRAMISU_0 int checkComponentPermission(String permission, int uid, int owningUid, boolean exported);
+class ActivityManagerHelper.ProcessObserverCallback package android.car.builtin.app
+ field TIRAMISU_0 IProcessObserver.Stub mIProcessObserver = new IProcessObserver.Stub() {
+
+ @Override
+ public void onForegroundActivitiesChanged(int pid, int uid, boolean foregroundActivities) throws RemoteException {
+ ProcessObserverCallback.this.onForegroundActivitiesChanged(pid, uid, foregroundActivities);
+ }
+
+ @Override
+ public void onForegroundServicesChanged(int pid, int uid, int fgServiceTypes) throws RemoteException {
+ // Not used
+ }
+
+ @Override
+ public void onProcessDied(int pid, int uid) throws RemoteException {
+ ProcessObserverCallback.this.onProcessDied(pid, uid);
+ }
+};
+ method TIRAMISU_0 void onForegroundActivitiesChanged(int pid, int uid, boolean foregroundActivities);
+ method TIRAMISU_0 void onProcessDied(int pid, int uid);
+class @hide @SystemApi KeyguardManagerHelper package android.car.builtin.app
+ method TIRAMISU_0 boolean isKeyguardLocked();
+class @hide @SystemApi PermissionHelper package android.car.builtin
+ field TIRAMISU_0 String MONITOR_INPUT = android.Manifest.permission.MONITOR_INPUT;
+class @hide @SystemApi AtomicFileHelper package android.car.builtin.util
+ method TIRAMISU_0 boolean exists(AtomicFile file);
+class @hide @SystemApi EventLogHelper package android.car.builtin.util
+ method TIRAMISU_0 void writeCarHelperStart();
+ method TIRAMISU_0 void writeCarHelperBootPhase(int phase);
+ method TIRAMISU_0 void writeCarHelperUserStarting(int userId);
+ method TIRAMISU_0 void writeCarHelperUserSwitching(int fromUserId, int toUserId);
+ method TIRAMISU_0 void writeCarHelperUserUnlocking(int userId);
+ method TIRAMISU_0 void writeCarHelperUserUnlocked(int userId);
+ method TIRAMISU_0 void writeCarHelperUserStopping(int userId);
+ method TIRAMISU_0 void writeCarHelperUserStopped(int userId);
+ method TIRAMISU_0 void writeCarHelperServiceConnected();
+ method TIRAMISU_0 void writeCarServiceInit(int numberServices);
+ method TIRAMISU_0 void writeCarServiceVhalReconnected(int numberServices);
+ method TIRAMISU_0 void writeCarServiceSetCarServiceHelper(int pid);
+ method TIRAMISU_0 void writeCarServiceOnUserLifecycle(int type, int fromUserId, int toUserId);
+ method TIRAMISU_0 void writeCarServiceCreate(boolean hasVhal);
+ method TIRAMISU_0 void writeCarServiceConnected(String interfaceName);
+ method TIRAMISU_0 void writeCarServiceDestroy(boolean hasVhal);
+ method TIRAMISU_0 void writeCarServiceVhalDied(long cookie);
+ method TIRAMISU_0 void writeCarServiceInitBootUser();
+ method TIRAMISU_0 void writeCarServiceOnUserRemoved(int userId);
+ method TIRAMISU_0 void writeCarUserServiceInitialUserInfoReq(int requestType, int timeout, int currentUserId, int currentUserFlags, int numberExistingUsers);
+ method TIRAMISU_0 void writeCarUserServiceInitialUserInfoResp(int status, int action, int userId, int flags, String safeName, String userLocales);
+ method TIRAMISU_0 void writeCarUserServiceSetInitialUser(int userId);
+ method TIRAMISU_0 void writeCarUserServiceSetLifecycleListener(int uid, String packageName);
+ method TIRAMISU_0 void writeCarUserServiceResetLifecycleListener(int uid, String packageName);
+ method TIRAMISU_0 void writeCarUserServiceSwitchUserReq(int userId, int timeout);
+ method TIRAMISU_0 void writeCarUserServiceSwitchUserResp(int halCallbackStatus, int userSwitchStatus, String errorMessage);
+ method TIRAMISU_0 void writeCarUserServiceLogoutUserReq(int userId, int timeout);
+ method TIRAMISU_0 void writeCarUserServiceLogoutUserResp(int halCallbackStatus, int userSwitchStatus, String errorMessage);
+ method TIRAMISU_0 void writeCarUserServicePostSwitchUserReq(int targetUserId, int currentUserId);
+ method TIRAMISU_0 void writeCarUserServiceGetUserAuthReq(int uid, int userId, int numberTypes);
+ method TIRAMISU_0 void writeCarUserServiceGetUserAuthResp(int numberValues);
+ method TIRAMISU_0 void writeCarUserServiceSwitchUserUiReq(int userId);
+ method TIRAMISU_0 void writeCarUserServiceSwitchUserFromHalReq(int requestId, int uid);
+ method TIRAMISU_0 void writeCarUserServiceSetUserAuthReq(int uid, int userId, int numberAssociations);
+ method TIRAMISU_0 void writeCarUserServiceSetUserAuthResp(int numberValues, String errorMessage);
+ method TIRAMISU_0 void writeCarUserServiceCreateUserReq(String safeName, String userType, int flags, int timeout, int hasCallerRestrictions);
+ method TIRAMISU_0 void writeCarUserServiceCreateUserResp(int status, int result, String errorMessage);
+ method TIRAMISU_0 void writeCarUserServiceCreateUserUserCreated(int userId, String safeName, String userType, int flags);
+ method TIRAMISU_0 void writeCarUserServiceCreateUserUserRemoved(int userId, String reason);
+ method TIRAMISU_0 void writeCarUserServiceRemoveUserReq(int userId, int hascallerrestrictions);
+ method TIRAMISU_0 void writeCarUserServiceRemoveUserResp(int userId, int result);
+ method TIRAMISU_0 void writeCarUserServiceNotifyAppLifecycleListener(int uid, String packageName, int eventType, int fromUserId, int toUserId);
+ method TIRAMISU_0 void writeCarUserServiceNotifyInternalLifecycleListener(String listenerName, int eventType, int fromUserId, int toUserId);
+ method TIRAMISU_0 void writeCarUserServicePreCreationRequested(int numberUsers, int numberGuests);
+ method TIRAMISU_0 void writeCarUserServicePreCreationStatus(int numberExistingUsers, int numberUsersToAdd, int numberUsersToRemove, int numberExistingGuests, int numberGuestsToAdd, int numberGuestsToRemove, int numberInvalidUsersToRemove);
+ method TIRAMISU_0 void writeCarUserServiceStartUserInBackgroundReq(int userId);
+ method TIRAMISU_0 void writeCarUserServiceStartUserInBackgroundResp(int userId, int result);
+ method TIRAMISU_0 void writeCarUserServiceStopUserReq(int userId);
+ method TIRAMISU_0 void writeCarUserServiceStopUserResp(int userId, int result);
+ method TIRAMISU_0 void writeCarUserServiceInitialUserInfoReqComplete(int requestType);
+ method TIRAMISU_0 void writeCarUserHalInitialUserInfoReq(int requestId, int requestType, int timeout);
+ method TIRAMISU_0 void writeCarUserHalInitialUserInfoResp(int requestId, int status, int action, int userId, int flags, String safeName, String userLocales);
+ method TIRAMISU_0 void writeCarUserHalSwitchUserReq(int requestId, int userId, int userFlags, int timeout);
+ method TIRAMISU_0 void writeCarUserHalSwitchUserResp(int requestId, int status, int result, String errorMessage);
+ method TIRAMISU_0 void writeCarUserHalPostSwitchUserReq(int requestId, int targetUserId, int currentUserId);
+ method TIRAMISU_0 void writeCarUserHalGetUserAuthReq(Object[] int32Values);
+ method TIRAMISU_0 void writeCarUserHalGetUserAuthResp(Object[] valuesAndError);
+ method TIRAMISU_0 void writeCarUserHalLegacySwitchUserReq(int requestId, int targetUserId, int currentUserId);
+ method TIRAMISU_0 void writeCarUserHalSetUserAuthReq(Object[] int32Values);
+ method TIRAMISU_0 void writeCarUserHalSetUserAuthResp(Object[] valuesAndError);
+ method TIRAMISU_0 void writeCarUserHalOemSwitchUserReq(int requestId, int targetUserId);
+ method TIRAMISU_0 void writeCarUserHalCreateUserReq(int requestId, String safeName, int flags, int timeout);
+ method TIRAMISU_0 void writeCarUserHalCreateUserResp(int requestId, int status, int result, String errorMessage);
+ method TIRAMISU_0 void writeCarUserHalRemoveUserReq(int targetUserId, int currentUserId);
+ method TIRAMISU_0 void writeCarUserManagerAddListener(int uid, String packageName, boolean hasFilter);
+ method TIRAMISU_0 void writeCarUserManagerRemoveListener(int uid, String packageName);
+ method TIRAMISU_0 void writeCarUserManagerDisconnected(int uid);
+ method TIRAMISU_0 void writeCarUserManagerSwitchUserReq(int uid, int userId);
+ method TIRAMISU_0 void writeCarUserManagerSwitchUserResp(int uid, int status, String errorMessage);
+ method TIRAMISU_0 void writeCarUserManagerLogoutUserReq(int uid);
+ method TIRAMISU_0 void writeCarUserManagerLogoutUserResp(int uid, int status, String errorMessage);
+ method TIRAMISU_0 void writeCarUserManagerGetUserAuthReq(Object[] types);
+ method TIRAMISU_0 void writeCarUserManagerGetUserAuthResp(Object[] values);
+ method TIRAMISU_0 void writeCarUserManagerSetUserAuthReq(Object[] typesAndValuesPairs);
+ method TIRAMISU_0 void writeCarUserManagerSetUserAuthResp(Object[] values);
+ method TIRAMISU_0 void writeCarUserManagerCreateUserReq(int uid, String safeName, String userType, int flags);
+ method TIRAMISU_0 void writeCarUserManagerCreateUserResp(int uid, int status, String errorMessage);
+ method TIRAMISU_0 void writeCarUserManagerRemoveUserReq(int uid, int userId);
+ method TIRAMISU_0 void writeCarUserManagerRemoveUserResp(int uid, int status);
+ method TIRAMISU_0 void writeCarUserManagerNotifyLifecycleListener(int numberListeners, int eventType, int fromUserId, int toUserId);
+ method TIRAMISU_0 void writeCarUserManagerPreCreateUserReq(int uid);
+ method TIRAMISU_0 void writeCarDevicePolicyManagerRemoveUserReq(int uid, int userId);
+ method TIRAMISU_0 void writeCarDevicePolicyManagerRemoveUserResp(int uid, int status);
+ method TIRAMISU_0 void writeCarDevicePolicyManagerCreateUserReq(int uid, String safeName, int flags);
+ method TIRAMISU_0 void writeCarDevicePolicyManagerCreateUserResp(int uid, int status);
+ method TIRAMISU_0 void writeCarDevicePolicyManagerStartUserInBackgroundReq(int uid, int userId);
+ method TIRAMISU_0 void writeCarDevicePolicyManagerStartUserInBackgroundResp(int uid, int status);
+ method TIRAMISU_0 void writeCarDevicePolicyManagerStopUserReq(int uid, int userId);
+ method TIRAMISU_0 void writeCarDevicePolicyManagerStopUserResp(int uid, int status);
+ method TIRAMISU_0 void writePowerPolicyChange(String policy);
+ method TIRAMISU_0 void writeCarPowerManagerStateChange(int state);
+ method TIRAMISU_0 void writeCarPowerManagerStateRequest(int state, int param);
+ method TIRAMISU_0 void writeGarageModeEvent(int status);
+class @hide @SystemApi Slogf package android.car.builtin.util
+ method TIRAMISU_0 boolean isLoggable(String tag, int level);
+ method TIRAMISU_0 int v(String tag, String msg);
+ method TIRAMISU_0 int v(String tag, String msg, Throwable tr);
+ method TIRAMISU_0 int d(String tag, String msg);
+ method TIRAMISU_0 int d(String tag, String msg, Throwable tr);
+ method TIRAMISU_0 int i(String tag, String msg);
+ method TIRAMISU_0 int i(String tag, String msg, Throwable tr);
+ method TIRAMISU_0 int w(String tag, String msg);
+ method TIRAMISU_0 int w(String tag, String msg, Throwable tr);
+ method TIRAMISU_0 int w(String tag, Throwable tr);
+ method TIRAMISU_0 int e(String tag, String msg);
+ method TIRAMISU_0 int e(String tag, String msg, Throwable tr);
+ method TIRAMISU_0 int wtf(String tag, String msg);
+ method TIRAMISU_0 int wtf(String tag, Throwable tr);
+ method TIRAMISU_0 int wtf(String tag, String msg, Throwable tr);
+ method TIRAMISU_0 void v(String tag, String format, Object args);
+ method TIRAMISU_0 void d(String tag, String format, Object args);
+ method TIRAMISU_0 void i(String tag, String format, Object args);
+ method TIRAMISU_0 void w(String tag, String format, Object args);
+ method TIRAMISU_0 void w(String tag, Exception exception, String format, Object args);
+ method TIRAMISU_0 void e(String tag, String format, Object args);
+ method TIRAMISU_0 void e(String tag, Exception exception, String format, Object args);
+ method TIRAMISU_0 void wtf(String tag, String format, Object args);
+ method TIRAMISU_0 void wtf(String tag, Exception exception, String format, Object args);
+class @hide @SystemApi AssistUtilsHelper package android.car.builtin.util
+ field TIRAMISU_0 String EXTRA_CAR_PUSH_TO_TALK = "com.android.car.input.EXTRA_CAR_PUSH_TO_TALK";
+ method TIRAMISU_0 boolean isSessionRunning(Context context);
+ method TIRAMISU_0 void hideCurrentSession(Context context);
+ method TIRAMISU_0 void registerVoiceInteractionSessionListenerHelper(Context context, VoiceInteractionSessionListenerHelper sessionListener);
+ method TIRAMISU_0 boolean showPushToTalkSessionForActiveService(Context context, VoiceInteractionSessionShowCallbackHelper callback);
+interface AssistUtilsHelper.VoiceInteractionSessionShowCallbackHelper package android.car.builtin.util
+ method void onFailed();
+ method void onShown();
+interface AssistUtilsHelper.VoiceInteractionSessionListenerHelper package android.car.builtin.util
+ method void onVoiceSessionShown();
+ method void onVoiceSessionHidden();
+class @hide @SystemApi TimeUtils package android.car.builtin.util
+ method TIRAMISU_0 void dumpTime(PrintWriter pw, long time);
+ method TIRAMISU_0 void formatDuration(long duration, PrintWriter pw);
+class @hide @SystemApi TimingsTraceLog package android.car.builtin.util
+ method TIRAMISU_0 void traceBegin(String name);
+ method TIRAMISU_0 void traceEnd();
+ method TIRAMISU_0 void logDuration(String name, long timeMs);
+class @hide @SystemApi ValidationHelper package android.car.builtin.util
+ method TIRAMISU_0 boolean isUserIdValid(int userId);
+ method TIRAMISU_0 boolean isAppIdValid(int appId);
+class @hide @SystemApi PowerManagerHelper package android.car.builtin.power
+ method TIRAMISU_0 int getMaximumScreenBrightnessSetting(Context context);
+ method TIRAMISU_0 int getMinimumScreenBrightnessSetting(Context context);
+ method TIRAMISU_0 void setDisplayState(Context context, boolean on, long upTime);
+ method TIRAMISU_0 void shutdown(Context context, boolean confirm, String reason, boolean wait);
+class @hide @SystemApi BinderHelper package android.car.builtin.os
+ method TIRAMISU_0 void dumpRemoteCallbackList(RemoteCallbackList<?> list, PrintWriter pw);
+ method TIRAMISU_0 boolean onTransactForCmd(int code, Parcel data, Parcel reply, int flags, ShellCommandListener cmdListener);
+interface BinderHelper.ShellCommandListener package android.car.builtin.os
+ method TIRAMISU_0 int onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err, String[] args);
+class @hide @SystemApi ServiceManagerHelper package android.car.builtin.os
+ method TIRAMISU_0 IBinder getService(String name);
+ method TIRAMISU_0 IBinder checkService(String name);
+ method TIRAMISU_0 IBinder waitForDeclaredService(String name);
+ method TIRAMISU_0 void addService(String name, IBinder service);
+class @hide @SystemApi SystemPropertiesHelper package android.car.builtin.os
+ method TIRAMISU_0 void set(String key, String val);
+class @hide @SystemApi ParcelHelper package android.car.builtin.os
+ method TIRAMISU_0 String[] readStringArray(Parcel parcel);
+ method TIRAMISU_0 byte[] readBlob(Parcel parcel);
+ method TIRAMISU_0 void writeBlob(Parcel parcel, byte[] b);
+ method TIRAMISU_0 ArraySet<? extends Object> readArraySet(Parcel parcel, ClassLoader loader);
+ method TIRAMISU_0 void writeArraySet(Parcel parcel, ArraySet<? extends Object> val);
+class @hide @SystemApi BuildHelper package android.car.builtin.os
+ method TIRAMISU_0 boolean isUserBuild();
+ method TIRAMISU_0 boolean isEngBuild();
+ method TIRAMISU_0 boolean isUserDebugBuild();
+ method TIRAMISU_0 boolean isDebuggableBuild();
+class @hide @SystemApi UserManagerHelper package android.car.builtin.os
+ field TIRAMISU_0 int USER_NULL = UserHandle.USER_NULL;
+ field TIRAMISU_0 int USER_SYSTEM = UserHandle.USER_SYSTEM;
+ field TIRAMISU_0 int FLAG_PRIMARY = UserInfo.FLAG_PRIMARY;
+ field TIRAMISU_0 int FLAG_ADMIN = UserInfo.FLAG_ADMIN;
+ field TIRAMISU_0 int FLAG_GUEST = UserInfo.FLAG_GUEST;
+ field TIRAMISU_0 int FLAG_RESTRICTED = UserInfo.FLAG_RESTRICTED;
+ field TIRAMISU_0 int FLAG_INITIALIZED = UserInfo.FLAG_INITIALIZED;
+ field TIRAMISU_0 int FLAG_MANAGED_PROFILE = UserInfo.FLAG_MANAGED_PROFILE;
+ field TIRAMISU_0 int FLAG_DISABLED = UserInfo.FLAG_DISABLED;
+ field TIRAMISU_0 int FLAG_QUIET_MODE = UserInfo.FLAG_QUIET_MODE;
+ field TIRAMISU_0 int FLAG_EPHEMERAL = UserInfo.FLAG_EPHEMERAL;
+ field TIRAMISU_0 int FLAG_DEMO = UserInfo.FLAG_DEMO;
+ field TIRAMISU_0 int FLAG_FULL = UserInfo.FLAG_FULL;
+ field TIRAMISU_0 int FLAG_SYSTEM = UserInfo.FLAG_SYSTEM;
+ field TIRAMISU_0 int FLAG_PROFILE = UserInfo.FLAG_PROFILE;
+ method TIRAMISU_0 List<UserHandle> getUserHandles(UserManager userManager, boolean excludePartial, boolean excludeDying, boolean excludePreCreated);
+ method TIRAMISU_0 boolean isEphemeralUser(UserManager userManager, UserHandle user);
+ method TIRAMISU_0 boolean isEnabledUser(UserManager userManager, UserHandle user);
+ method TIRAMISU_0 boolean isPreCreatedUser(UserManager userManager, UserHandle user);
+ method TIRAMISU_0 boolean isInitializedUser(UserManager userManager, UserHandle user);
+ method TIRAMISU_0 String getDefaultUserTypeForUserInfoFlags(int userInfoFlag);
+ method TIRAMISU_0 UserHandle preCreateUser(UserManager userManager, String type);
+ method TIRAMISU_0 String getDefaultUserName(Context context);
+ method TIRAMISU_0 int getMaxRunningUsers(Context context);
+ method TIRAMISU_0 boolean markGuestForDeletion(UserManager userManager, UserHandle user);
+ method TIRAMISU_0 int getUserId(int uid);
+class @hide @SystemApi SharedMemoryHelper package android.car.builtin.os
+ method TIRAMISU_0 ParcelFileDescriptor createParcelFileDescriptor(SharedMemory memory);
+class @hide @SystemApi TraceHelper package android.car.builtin.os
+ field TIRAMISU_0 long TRACE_TAG_CAR_SERVICE = Trace.TRACE_TAG_SYSTEM_SERVER;
+class @hide @SystemApi SettingsHelper package android.car.builtin.provider
+ field TIRAMISU_0 String SYSTEM_LOCALES = "system_locales";
+class @hide @SystemApi CarBuiltin package android.car.builtin
+ field TIRAMISU_0 int PLATFORM_VERSION_MINOR_INT = SystemProperties.getInt(PROPERTY_PLATFORM_MINOR_VERSION, /* def= */
+0);
diff --git a/tools/GenericCarApiBuilder/src/com/android/car/tool/apibuilder/GenerateAPI.java b/tools/GenericCarApiBuilder/src/com/android/car/tool/apibuilder/GenerateAPI.java
index 939b045..0942661 100644
--- a/tools/GenericCarApiBuilder/src/com/android/car/tool/apibuilder/GenerateAPI.java
+++ b/tools/GenericCarApiBuilder/src/com/android/car/tool/apibuilder/GenerateAPI.java
@@ -24,14 +24,17 @@
import com.github.javaparser.ast.body.MethodDeclaration;
import com.github.javaparser.ast.body.Parameter;
import com.github.javaparser.ast.expr.AnnotationExpr;
+import com.github.javaparser.ast.expr.MemberValuePair;
import com.github.javaparser.ast.visitor.VoidVisitorAdapter;
import java.io.File;
+import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.List;
/**
@@ -41,62 +44,122 @@
private static final boolean DBG = false;
private static final String ANDROID_BUILD_TOP = "ANDROID_BUILD_TOP";
- private static final String CAR_API_PATH = "/packages/services/Car/car-lib/src/android/car";
+ private static final String CAR_API_PATH =
+ "/packages/services/Car/car-lib/src/android/car";
+ private static final String CAR_BUILT_IN_API_PATH =
+ "/packages/services/Car/car-builtin-lib/src/android/car/builtin";
+ private static final String CAR_API_ANNOTATION_TEST_FILE =
+ "/packages/services/Car/tests/carservice_unit_test/res/raw/car_api_classes.txt";
+ private static final String CAR_BUILT_IN_ANNOTATION_TEST_FILE =
+ "/packages/services/Car/tests/carservice_unit_test/res/raw/"
+ + "car_built_in_api_classes.txt";
private static final String API_TXT_SAVE_PATH =
"/packages/services/Car/tools/GenericCarApiBuilder/";
- private static final String COMPLETE_API_LIST = "complete_api_list.txt";
- private static final String UN_ANNOTATED_API_LIST = "un_annotated_api_list.txt";
+ private static final String COMPLETE_CAR_API_LIST = "complete_car_api_list.txt";
+ private static final String COMPLETE_CAR_BUILT_IN_API_LIST =
+ "complete_car_built_in_api_list.txt";
private static final String TAB = " ";
+ // Arguments:
+ private static final String PRINT_CLASSES_ONLY = "--print-classes-only";
+ private static final String UPDATE_CLASSES_FOR_TEST = "--update-classes-for-test";
+ private static final String GENERATE_FULL_API_LIST = "--generate-full-api-list";
+
/**
* Main method for generate API txt file.
*/
public static void main(final String[] args) throws Exception {
try {
- String rootDir = System.getenv(ANDROID_BUILD_TOP);
- String carLibPath = rootDir + CAR_API_PATH;
- List<File> allJavaFiles = getAllFiles(new File(carLibPath));
+ if (args.length == 0) {
+ printHelp();
+ return;
+ }
- if (args.length > 0 && args[0].equalsIgnoreCase("--classes-only")) {
- for (int i = 0; i < allJavaFiles.size(); i++) {
- printAllClasses(allJavaFiles.get(i));
+ String rootDir = System.getenv(ANDROID_BUILD_TOP);
+ if (rootDir == null || rootDir.isEmpty()) {
+ // check for second optional argument
+ if (args.length > 2 && args[1].equalsIgnoreCase("--ANDROID-BUILD-TOP")) {
+ rootDir = args[2];
+ } else {
+ printHelp();
+ return;
+ }
+ }
+
+ List<File> allJavaFiles_carLib = getAllFiles(new File(rootDir + CAR_API_PATH));
+ List<File> allJavaFiles_carBuiltInLib = getAllFiles(
+ new File(rootDir + CAR_BUILT_IN_API_PATH));
+
+ if (args.length > 0 && args[0].equalsIgnoreCase(PRINT_CLASSES_ONLY)) {
+ for (int i = 0; i < allJavaFiles_carLib.size(); i++) {
+ printOrUpdateAllClasses(allJavaFiles_carLib.get(i), true, null);
+ }
+ for (int i = 0; i < allJavaFiles_carBuiltInLib.size(); i++) {
+ printOrUpdateAllClasses(allJavaFiles_carBuiltInLib.get(i), true, null);
}
return;
}
- List<String> allAPIs = new ArrayList<>();
- for (int i = 0; i < allJavaFiles.size(); i++) {
- allAPIs.addAll(parseJavaFile(allJavaFiles.get(i), /* onlyUnannotated= */ false));
- }
-
- // write all APIs by default.
- String toolPath = rootDir + API_TXT_SAVE_PATH;
- Path file = Paths.get(toolPath + COMPLETE_API_LIST);
- Files.write(file, allAPIs, StandardCharsets.UTF_8);
-
- // create only un-annotated file for manual work
- allAPIs = new ArrayList<>();
- for (int i = 0; i < allJavaFiles.size(); i++) {
- allAPIs.addAll(parseJavaFile(allJavaFiles.get(i), /* onlyUnannotated= */ true));
- }
-
- // write all un-annotated APIs.
- if (allAPIs.size() > 0) {
- if (args.length > 0 && args[0].equalsIgnoreCase("--write-un-annotated-to-file")) {
- file = Paths.get(toolPath + UN_ANNOTATED_API_LIST);
- Files.write(file, allAPIs, StandardCharsets.UTF_8);
- } else {
- System.out.println("*********Un-annotated APIs************");
- for (int i = 0; i < allAPIs.size(); i++) {
- System.out.println(allAPIs.get(i));
- }
+ if (args.length > 0 && args[0].equalsIgnoreCase(UPDATE_CLASSES_FOR_TEST)) {
+ List<String> api_list = new ArrayList<>();
+ for (int i = 0; i < allJavaFiles_carLib.size(); i++) {
+ printOrUpdateAllClasses(allJavaFiles_carLib.get(i), false, api_list);
}
+ writeListToFile(rootDir + CAR_API_ANNOTATION_TEST_FILE, api_list);
+
+ List<String> built_in_api_list = new ArrayList<>();
+ for (int i = 0; i < allJavaFiles_carBuiltInLib.size(); i++) {
+ printOrUpdateAllClasses(allJavaFiles_carBuiltInLib.get(i), false,
+ built_in_api_list);
+ }
+ writeListToFile(rootDir + CAR_BUILT_IN_ANNOTATION_TEST_FILE, built_in_api_list);
+ return;
+ }
+
+ if (args.length > 0 && args[0].equalsIgnoreCase(GENERATE_FULL_API_LIST)) {
+ List<String> allCarAPIs = new ArrayList<>();
+ for (int i = 0; i < allJavaFiles_carLib.size(); i++) {
+ allCarAPIs.addAll(
+ parseJavaFile(allJavaFiles_carLib.get(i)));
+ }
+ writeListToFile(rootDir + API_TXT_SAVE_PATH + COMPLETE_CAR_API_LIST, allCarAPIs);
+
+ List<String> allCarBuiltInAPIs = new ArrayList<>();
+ for (int i = 0; i < allJavaFiles_carBuiltInLib.size(); i++) {
+ allCarBuiltInAPIs.addAll(
+ parseJavaFile(allJavaFiles_carBuiltInLib.get(i)));
+ }
+ writeListToFile(rootDir + API_TXT_SAVE_PATH + COMPLETE_CAR_BUILT_IN_API_LIST,
+ allCarBuiltInAPIs);
+
+ return;
}
} catch (Exception e) {
throw e;
}
}
+ private static void writeListToFile(String filePath, List<String> data) throws IOException {
+ Path file = Paths.get(filePath);
+ Files.write(file, data, StandardCharsets.UTF_8);
+ }
+
+ private static void printHelp() {
+ System.out.println("**** Help ****");
+ System.out.println("At least one argument is required. Supported arguments - ");
+ System.out.println(PRINT_CLASSES_ONLY + " : Would print the list of valid class and"
+ + " interfaces.");
+ System.out.println(UPDATE_CLASSES_FOR_TEST + " : Would update the test file with the list"
+ + " of valid class and interfaces. These files updated are"
+ + " tests/carservice_unit_test/res/raw/car_api_classes.txt and"
+ + " tests/carservice_unit_test/res/raw/car_built_in_api_classes.txt");
+ System.out.println(GENERATE_FULL_API_LIST + " : Would generate full api list including the"
+ + " hidden APIs. Results would be saved in ");
+ System.out.println("Second optional argument is value of Git Root Directory. By default, "
+ + "it is environment variable ANDROID_BUILD_TOP. If environment variable is not set"
+ + "then provide using --ANDROID-BUILD-TOP <directory>");
+ }
+
private static List<File> getAllFiles(File folderName) {
List<File> allFiles = new ArrayList<>();
File[] files = folderName.listFiles();
@@ -112,10 +175,17 @@
allFiles.addAll(getAllFiles(files[i]));
}
}
+ // List files doesn't guarantee fixed order on all systems. It is better to sort the list.
+ Collections.sort(allFiles);
return allFiles;
}
- private static void printAllClasses(File file) throws Exception {
+ private static void printOrUpdateAllClasses(File file, boolean print, List<String> updateList)
+ throws Exception {
+ if (!print && updateList == null) {
+ throw new Exception("update list should not be null if not printing.");
+ }
+
CompilationUnit cu = StaticJavaParser.parse(file);
String packageName = cu.getPackageDeclaration().get().getNameAsString();
@@ -128,12 +198,18 @@
String className = classOrInterfaceDeclaration.getFullyQualifiedName().get()
.substring(packageName.length() + 1);
- System.out.println("\"" + packageName + "." + className.replace(".", "$") + "\",");
+ String useableClassName = packageName + "." + className.replace(".", "$");
+ if (print) {
+ System.out.println(useableClassName);
+ } else {
+ updateList.add(useableClassName);
+ }
+ super.visit(classOrInterfaceDeclaration, arg);
}
}.visit(cu, null);
}
- private static List<String> parseJavaFile(File file, boolean onlyUnannotated) throws Exception {
+ private static List<String> parseJavaFile(File file) throws Exception {
List<String> parsedList = new ArrayList<>();
// Add code to parse file
@@ -147,8 +223,8 @@
return;
}
- String className =
- n.getFullyQualifiedName().get().substring(packageName.length() + 1);
+ String className = n.getFullyQualifiedName().get()
+ .substring(packageName.length() + 1);
String classType = n.isInterface() ? "interface" : "class";
boolean hiddenClass = false;
@@ -165,7 +241,9 @@
}
}
- String classDeclaration = classType + " " + (hiddenClass ? "@hide " : "")
+ String classDeclaration = classType + " "
+ + (hiddenClass && !isClassSystemAPI ? "@hiddenOnly " : "")
+ + (hiddenClass ? "@hide " : "")
+ (isClassSystemAPI ? "@SystemApi " : "") + className + " package "
+ packageName;
@@ -174,8 +252,6 @@
System.out.println(classDeclaration);
}
- int originalSizeOfParseList = parsedList.size();
-
List<FieldDeclaration> fields = n.getFields();
for (int i = 0; i < fields.size(); i++) {
FieldDeclaration field = fields.get(i);
@@ -185,12 +261,12 @@
String fieldName = field.getVariables().get(0).getName().asString();
String fieldType = field.getVariables().get(0).getTypeAsString();
- boolean fieldInitialized =
- !field.getVariables().get(0).getInitializer().isEmpty();
+ boolean fieldInitialized = !field.getVariables().get(0).getInitializer()
+ .isEmpty();
String fieldInitializedValue = "";
if (fieldInitialized) {
- fieldInitializedValue =
- field.getVariables().get(0).getInitializer().get().toString();
+ fieldInitializedValue = field.getVariables().get(0).getInitializer().get()
+ .toString();
}
// special case
@@ -199,9 +275,8 @@
}
boolean isSystem = false;
- boolean isAddedIn = false;
- boolean isAddedInOrBefore = false;
boolean isHidden = false;
+ String version = "";
if (!field.getJavadoc().isEmpty()) {
isHidden = field.getJavadoc().get().toText().contains("@hide");
@@ -214,33 +289,36 @@
isSystem = true;
}
if (annotationString.contains("AddedInOrBefore")) {
- isAddedInOrBefore = true;
+ String major = getVersion(annotations.get(j), "majorVersion");
+ String minor = getVersion(annotations.get(j), "minorVersion");
+ if (!minor.equals("0")) {
+ System.out.println("ERROR: minor should be zero for " + field);
+ }
+ if (!major.equals("33")) {
+ System.out.println("ERROR: major should be 33 for " + field);
+ }
+ version = "TIRAMISU_0";
}
if (annotationString.equals("AddedIn")) {
- isAddedIn = true;
+ String major = getVersion(annotations.get(j), "majorVersion");
+ String minor = getVersion(annotations.get(j), "minorVersion");
+ if (!major.equals("33")) {
+ System.out.println("ERROR: major should be 33 for " + field);
+ }
+ version = "TIRAMISU_" + minor;
}
- }
+ if (annotationString.equals("ApiRequirements")) {
+ String major = getVersion(annotations.get(j), "minCarVersion");
+ version = major.split("\\.")[major.split("\\.").length - 1];
+ }
- if ((isAddedInOrBefore || isAddedIn) && onlyUnannotated) {
- continue;
}
StringBuilder sb = new StringBuilder();
sb.append("field ");
- if (isHidden) {
- sb.append("@hide ");
- }
-
- if (isSystem) {
- sb.append("@SystemApi ");
- }
-
- if (isAddedInOrBefore) {
- sb.append("@AddedInOrBefore ");
- }
-
- if (isAddedIn) {
- sb.append("@AddedIn ");
+ sb.append(version + " ");
+ if (isHidden && !isSystem) {
+ sb.append("@hiddenOnly ");
}
sb.append(fieldType);
@@ -253,7 +331,6 @@
}
sb.append(";");
-
if (DBG) {
System.out.printf("%s%s\n", TAB, sb);
}
@@ -271,9 +348,8 @@
String methodName = method.getName().asString();
boolean isSystem = false;
- boolean isAddedIn = false;
- boolean isAddedInOrBefore = false;
boolean isHidden = false;
+ String version = "";
if (!method.getJavadoc().isEmpty()) {
isHidden = method.getJavadoc().get().toText().contains("@hide");
}
@@ -284,35 +360,38 @@
if (annotationString.contains("SystemApi")) {
isSystem = true;
}
+
if (annotationString.contains("AddedInOrBefore")) {
- isAddedInOrBefore = true;
+ String major = getVersion(annotations.get(j), "majorVersion");
+ String minor = getVersion(annotations.get(j), "minorVersion");
+ if (!minor.equals("0")) {
+ System.out.println("ERROR: minor should be zero for " + method);
+ }
+ if (!major.equals("33")) {
+ System.out.println("ERROR: major should be 33 for " + method);
+ }
+ version = "TIRAMISU_0";
}
if (annotationString.equals("AddedIn")) {
- isAddedInOrBefore = true;
+ String major = getVersion(annotations.get(j), "majorVersion");
+ String minor = getVersion(annotations.get(j), "minorVersion");
+ if (!major.equals("33")) {
+ System.out.println("ERROR: major should be 33 for " + method);
+ }
+ version = "TIRAMISU_" + minor;
}
- }
+ if (annotationString.equals("ApiRequirements")) {
+ String major = getVersion(annotations.get(j), "minCarVersion");
+ version = major.split("\\.")[major.split("\\.").length - 1];
+ }
- if ((isAddedInOrBefore || isAddedIn) && onlyUnannotated) {
- continue;
}
StringBuilder sb = new StringBuilder();
sb.append("method ");
-
- if (isHidden) {
- sb.append("@hide ");
- }
-
- if (isSystem) {
- sb.append("@SystemApi ");
- }
-
- if (isAddedInOrBefore) {
- sb.append("@AddedInOrBefore ");
- }
-
- if (isAddedIn) {
- sb.append("@AddedIn ");
+ sb.append(version + " ");
+ if (isHidden && !isSystem) {
+ sb.append("@hiddenOnly ");
}
sb.append(returnType);
@@ -321,12 +400,12 @@
sb.append("(");
List<Parameter> parameters = method.getParameters();
- for (int j = 0; j < parameters.size(); j++) {
- Parameter parameter = parameters.get(j);
+ for (int k = 0; k < parameters.size(); k++) {
+ Parameter parameter = parameters.get(k);
sb.append(parameter.getTypeAsString());
sb.append(" ");
sb.append(parameter.getNameAsString());
- if (j < parameters.size() - 1) {
+ if (k < parameters.size() - 1) {
sb.append(", ");
}
}
@@ -337,17 +416,23 @@
parsedList.add(TAB + sb);
}
- if (parsedList.size() == originalSizeOfParseList) {
- // no method or field is added
- if (onlyUnannotated) {
- parsedList.remove(originalSizeOfParseList - 1);
- }
- }
-
super.visit(n, arg);
}
- }.visit(cu, null);
+ private String getVersion(AnnotationExpr annotationExpr, String parameterName) {
+ List<MemberValuePair> children = annotationExpr
+ .getChildNodesByType(MemberValuePair.class);
+ for (MemberValuePair memberValuePair : children) {
+ if (parameterName.equals(memberValuePair.getNameAsString())) {
+ if (memberValuePair.getValue() == null) {
+ return "0";
+ }
+ return memberValuePair.getValue().toString();
+ }
+ }
+ return "0";
+ }
+ }.visit(cu, null);
return parsedList;
}
}
diff --git a/vehicle-hal-support-lib/src/com/android/car/hal/test/AidlVehiclePropConfigBuilder.java b/vehicle-hal-support-lib/src/com/android/car/hal/test/AidlVehiclePropConfigBuilder.java
index 82d569e..8a37880 100644
--- a/vehicle-hal-support-lib/src/com/android/car/hal/test/AidlVehiclePropConfigBuilder.java
+++ b/vehicle-hal-support-lib/src/com/android/car/hal/test/AidlVehiclePropConfigBuilder.java
@@ -79,6 +79,18 @@
}
@CheckResult
+ public AidlVehiclePropConfigBuilder setMaxSampleRate(float maxSampleRate) {
+ mConfig.maxSampleRate = maxSampleRate;
+ return this;
+ }
+
+ @CheckResult
+ public AidlVehiclePropConfigBuilder setMinSampleRate(float minSampleRate) {
+ mConfig.minSampleRate = minSampleRate;
+ return this;
+ }
+
+ @CheckResult
public AidlVehiclePropConfigBuilder setConfigString(String configString) {
mConfig.configString = configString;
return this;