Merge "Enable removed api dex for car-lib" into rvc-dev
diff --git a/FrameworkPackageStubs/AndroidManifest.xml b/FrameworkPackageStubs/AndroidManifest.xml
index 912944c..6c25bcd 100644
--- a/FrameworkPackageStubs/AndroidManifest.xml
+++ b/FrameworkPackageStubs/AndroidManifest.xml
@@ -95,6 +95,10 @@
<action android:name="android.settings.USER_DICTIONARY_SETTINGS" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
+ <intent-filter android:priority="-1">
+ <action android:name="android.settings.PICTURE_IN_PICTURE_SETTINGS" />
+ <category android:name="android.intent.category.DEFAULT" />
+ </intent-filter>
</activity>
<!-- CDD Core Application Intents Stubs -->
diff --git a/car-internal-lib/src/com/android/internal/car/EventLogTags.logtags b/car-internal-lib/src/com/android/internal/car/EventLogTags.logtags
index 0c634ae..46af12b 100644
--- a/car-internal-lib/src/com/android/internal/car/EventLogTags.logtags
+++ b/car-internal-lib/src/com/android/internal/car/EventLogTags.logtags
@@ -82,6 +82,10 @@
150116 car_user_svc_create_user_resp (status|1),(result|1),(error_message|3)
150117 car_user_svc_create_user_user_created (user_id|1),(safe_name|3),(user_type|3),(flags|1)
150118 car_user_svc_create_user_user_removed (user_id|1),(reason|3)
+150119 car_user_svc_remove_user_req (user_id|1)
+150120 car_user_svc_remove_user_resp (user_id|1),(result|1)
+150121 car_user_svc_notify_app_lifecycle_listener (uid|1),(event_type|1),(from_user_id|1),(to_user_id|1)
+150122 car_user_svc_notify_internal_lifecycle_listener (listener_name|3),(event_type|1),(from_user_id|1),(to_user_id|1)
150140 car_user_hal_initial_user_info_req (request_id|1),(request_type|1),(timeout|1)
150141 car_user_hal_initial_user_info_resp (request_id|1),(status|1),(action|1),(user_id|1),(flags|1),(safe_name|3),(user_locales|3)
@@ -96,15 +100,19 @@
150150 car_user_hal_oem_switch_user_req (request_id|1),(target_user_id|1)
150151 car_user_hal_create_user_req (request_id|1),(safe_name|3),(flags|1),(timeout|1)
150152 car_user_hal_create_user_resp (request_id|1),(status|1),(result|1),(error_message|3)
+150153 car_user_hal_remove_user_req (target_user_id|1),(current_user_id|1)
150171 car_user_mgr_add_listener (uid|1)
150172 car_user_mgr_remove_listener (uid|1)
150173 car_user_mgr_disconnected (uid|1)
-150174 car_user_mgr_switch_user_request (uid|1),(user_id|1)
-150175 car_user_mgr_switch_user_response (uid|1),(status|1),(error_message|3)
+150174 car_user_mgr_switch_user_req (uid|1),(user_id|1)
+150175 car_user_mgr_switch_user_resp (uid|1),(status|1),(error_message|3)
150176 car_user_mgr_get_user_auth_req (types|4)
150177 car_user_mgr_get_user_auth_resp (values|4)
150178 car_user_mgr_set_user_auth_req (types_and_values_pairs|4)
150179 car_user_mgr_set_user_auth_resp (values|4)
150180 car_user_mgr_create_user_req (uid|1),(safe_name|3),(user_type|3),(flags|1)
150181 car_user_mgr_create_user_resp (uid|1),(status|1),(error_message|3)
+150182 car_user_mgr_remove_user_req (uid|1),(user_id|1)
+150183 car_user_mgr_remove_user_resp (uid|1),(status|1)
+150184 car_user_mgr_notify_lifecycle_listener (number_listeners|1),(event_type|1),(from_user_id|1),(to_user_id|1)
diff --git a/car-lib/Android.bp b/car-lib/Android.bp
index fbc68c7..39db28e 100644
--- a/car-lib/Android.bp
+++ b/car-lib/Android.bp
@@ -196,7 +196,7 @@
droidstubs {
name: "android.car-test-stubs-docs",
defaults: ["android.car-docs-default"],
- args: "--hide UnavailableSymbol --no-docs --stub-packages android.car* " +
+ args: "--hide HiddenSuperclass --hide UnavailableSymbol --no-docs --stub-packages android.car* " +
"--show-annotation android.annotation.TestApi ",
installable: false,
check_api: {
@@ -219,7 +219,7 @@
"android.car",
],
api_filename: "api.txt",
- args: "--hide UnavailableSymbol --no-docs --stub-packages android.car* ",
+ args: "--hide HiddenSuperclass --hide UnavailableSymbol --no-docs --stub-packages android.car* ",
installable: false,
product_variables: {
pdk: {
diff --git a/car-lib/src/android/car/ICarUserService.aidl b/car-lib/src/android/car/ICarUserService.aidl
index df5e6ab..b3823b3 100644
--- a/car-lib/src/android/car/ICarUserService.aidl
+++ b/car-lib/src/android/car/ICarUserService.aidl
@@ -18,6 +18,7 @@
import android.content.pm.UserInfo;
import android.car.user.UserCreationResult;
+import android.car.user.UserRemovalResult;
import android.car.user.UserIdentificationAssociationResponse;
import android.car.user.UserSwitchResult;
import com.android.internal.infra.AndroidFuture;
@@ -25,13 +26,14 @@
/** @hide */
interface ICarUserService {
- UserInfo createDriver(@nullable String name, boolean admin);
+ AndroidFuture<UserCreationResult> createDriver(@nullable String name, boolean admin);
UserInfo createPassenger(@nullable String name, int driverId);
void switchDriver(int driverId, in AndroidFuture<UserSwitchResult> receiver);
void switchUser(int tagerUserId, int timeoutMs, in AndroidFuture<UserSwitchResult> receiver);
void setUserSwitchUiCallback(in IResultReceiver callback);
void createUser(@nullable String name, String userType, int flags, int timeoutMs,
in AndroidFuture<UserCreationResult> receiver);
+ UserRemovalResult removeUser(int userId);
List<UserInfo> getAllDrivers();
List<UserInfo> getPassengers(int driverId);
boolean startPassenger(int passengerId, int zoneId);
diff --git a/car-lib/src/android/car/cluster/renderer/InstrumentClusterRenderingService.java b/car-lib/src/android/car/cluster/renderer/InstrumentClusterRenderingService.java
index 5272548..cdf0cca 100644
--- a/car-lib/src/android/car/cluster/renderer/InstrumentClusterRenderingService.java
+++ b/car-lib/src/android/car/cluster/renderer/InstrumentClusterRenderingService.java
@@ -412,13 +412,13 @@
startActivityAsUser(intent, mActivityOptions.toBundle(), UserHandle.CURRENT);
Log.i(TAG, String.format("Activity launched: %s (options: %s, displayId: %d)",
mActivityOptions, intent, mActivityOptions.getLaunchDisplayId()));
- } catch (ActivityNotFoundException ex) {
+ } catch (ActivityNotFoundException e) {
Log.w(TAG, "Unable to find activity for intent: " + intent);
return false;
- } catch (Exception ex) {
+ } catch (RuntimeException e) {
// Catch all other possible exception to prevent service disruption by misbehaving
// applications.
- Log.e(TAG, "Error trying to launch intent: " + intent + ". Ignored", ex);
+ Log.e(TAG, "Error trying to launch intent: " + intent + ". Ignored", e);
return false;
}
return true;
diff --git a/car-lib/src/android/car/hardware/hvac/CarHvacManager.java b/car-lib/src/android/car/hardware/hvac/CarHvacManager.java
index 54bda19..971f1fc 100644
--- a/car-lib/src/android/car/hardware/hvac/CarHvacManager.java
+++ b/car-lib/src/android/car/hardware/hvac/CarHvacManager.java
@@ -25,8 +25,6 @@
import android.car.hardware.property.CarPropertyManager;
import android.car.hardware.property.CarPropertyManager.CarPropertyEventCallback;
import android.car.hardware.property.ICarProperty;
-import android.car.hardware.property.PropertyAccessDeniedSecurityException;
-import android.car.hardware.property.PropertyNotAvailableException;
import android.os.IBinder;
import android.util.ArraySet;
import android.util.Log;
@@ -351,12 +349,9 @@
mCarPropertyMgr.unregisterCallback(mListenerToBase, c.getPropertyId());
}
- } catch (PropertyAccessDeniedSecurityException
- | PropertyNotAvailableException
- | IllegalArgumentException e) {
+ } catch (RuntimeException e) {
Log.e(TAG, "getPropertyList exception ", e);
}
-
if (mCallbacks.isEmpty()) {
mCarPropertyMgr.unregisterCallback(mListenerToBase);
mListenerToBase = null;
diff --git a/car-lib/src/android/car/media/CarAudioManager.java b/car-lib/src/android/car/media/CarAudioManager.java
index 31eb173..9f57617 100644
--- a/car-lib/src/android/car/media/CarAudioManager.java
+++ b/car-lib/src/android/car/media/CarAudioManager.java
@@ -32,8 +32,6 @@
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
-import android.view.Display;
-import android.view.DisplayAddress;
import java.util.ArrayList;
import java.util.Collections;
@@ -538,43 +536,6 @@
}
/**
- * Get the zone id for the display
- *
- * @param display display to query
- * @return zone id for display or
- * CarAudioManager.PRIMARY_AUDIO_ZONE if no match is found.
- * @hide
- */
- @RequiresPermission(Car.PERMISSION_CAR_CONTROL_AUDIO_SETTINGS)
- public int getZoneIdForDisplay(Display display) {
- DisplayAddress address = display.getAddress();
- if (address instanceof DisplayAddress.Physical) {
- DisplayAddress.Physical physicalAddress = (DisplayAddress.Physical) address;
- if (physicalAddress != null) {
- return getZoneIdForDisplayPortId(physicalAddress.getPort());
- }
- }
- return PRIMARY_AUDIO_ZONE;
- }
-
- /**
- * Get the zone id for the display port id passed in
- *
- * @param displayPortId display port id to query
- * @return zone id for display port id or
- * CarAudioManager.PRIMARY_AUDIO_ZONE if no match is found.
- * @hide
- */
- @RequiresPermission(Car.PERMISSION_CAR_CONTROL_AUDIO_SETTINGS)
- public int getZoneIdForDisplayPortId(byte displayPortId) {
- try {
- return mService.getZoneIdForDisplayPortId(displayPortId);
- } catch (RemoteException e) {
- return handleRemoteExceptionFromCarService(e, 0);
- }
- }
-
- /**
* Gets the output device for a given {@link AudioAttributes} usage in zoneId.
*
* <p><b>Note:</b> To be used for routing to a specific device. Most applications should
diff --git a/car-lib/src/android/car/media/ICarAudio.aidl b/car-lib/src/android/car/media/ICarAudio.aidl
index 7491a19..a8997ce 100644
--- a/car-lib/src/android/car/media/ICarAudio.aidl
+++ b/car-lib/src/android/car/media/ICarAudio.aidl
@@ -48,8 +48,6 @@
boolean setZoneIdForUid(int zoneId, int uid);
boolean clearZoneIdForUid(int uid);
- int getZoneIdForDisplayPortId(byte displayPortId);
-
String getOutputDeviceAddressForUsage(int zoneId, int usage);
List<AudioDeviceAttributes> getInputDevicesForZoneId(int zoneId);
diff --git a/car-lib/src/android/car/storagemonitoring/CarStorageMonitoringManager.java b/car-lib/src/android/car/storagemonitoring/CarStorageMonitoringManager.java
index ac59bac..6f993e3 100644
--- a/car-lib/src/android/car/storagemonitoring/CarStorageMonitoringManager.java
+++ b/car-lib/src/android/car/storagemonitoring/CarStorageMonitoringManager.java
@@ -47,9 +47,17 @@
private final SingleMessageHandler<IoStats> mMessageHandler;
private final Set<IoStatsListener> mListeners = new HashSet<>();
+ /**
+ * Implementers will be notified on every new I/O activity calculated stats.
+ */
public interface IoStatsListener {
+
+ /**
+ * Invoked when a new periodic snapshot delta of I/O activities is calculated.
+ */
void onSnapshot(IoStats snapshot);
}
+
private static final class ListenerToService extends IIoStatsListener.Stub {
private final WeakReference<CarStorageMonitoringManager> mManager;
@@ -109,7 +117,7 @@
* It will return either PRE_EOL_INFO_UNKNOWN if the value can't be determined,
* or one of PRE_EOL_INFO_{NORMAL|WARNING|URGENT} depending on the device state.
*/
- @RequiresPermission(value=Car.PERMISSION_STORAGE_MONITORING)
+ @RequiresPermission(value = Car.PERMISSION_STORAGE_MONITORING)
public int getPreEolIndicatorStatus() {
try {
return mService.getPreEolIndicatorStatus();
@@ -127,7 +135,7 @@
*
* If either or both indicators are not available, they will be reported as UNKNOWN.
*/
- @RequiresPermission(value=Car.PERMISSION_STORAGE_MONITORING)
+ @RequiresPermission(value = Car.PERMISSION_STORAGE_MONITORING)
public WearEstimate getWearEstimate() {
try {
return mService.getWearEstimate();
@@ -147,7 +155,7 @@
*
* If no indicators are available, an empty list will be returned.
*/
- @RequiresPermission(value=Car.PERMISSION_STORAGE_MONITORING)
+ @RequiresPermission(value = Car.PERMISSION_STORAGE_MONITORING)
public List<WearEstimateChange> getWearEstimateHistory() {
try {
return mService.getWearEstimateHistory();
@@ -166,7 +174,7 @@
*
* If the information is not available, an empty list will be returned.
*/
- @RequiresPermission(value=Car.PERMISSION_STORAGE_MONITORING)
+ @RequiresPermission(value = Car.PERMISSION_STORAGE_MONITORING)
public List<IoStatsEntry> getBootIoStats() {
try {
return mService.getBootIoStats();
@@ -196,7 +204,7 @@
*
* <p>If the information is not available, SHUTDOWN_COST_INFO_MISSING will be returned.</p>s
*/
- @RequiresPermission(value=Car.PERMISSION_STORAGE_MONITORING)
+ @RequiresPermission(value = Car.PERMISSION_STORAGE_MONITORING)
public long getShutdownDiskWriteAmount() {
try {
return mService.getShutdownDiskWriteAmount();
@@ -213,7 +221,7 @@
*
* If the information is not available, an empty list will be returned.
*/
- @RequiresPermission(value=Car.PERMISSION_STORAGE_MONITORING)
+ @RequiresPermission(value = Car.PERMISSION_STORAGE_MONITORING)
public List<IoStatsEntry> getAggregateIoStats() {
try {
return mService.getAggregateIoStats();
@@ -233,7 +241,7 @@
*
* If the information is not available, an empty list will be returned.
*/
- @RequiresPermission(value=Car.PERMISSION_STORAGE_MONITORING)
+ @RequiresPermission(value = Car.PERMISSION_STORAGE_MONITORING)
public List<IoStats> getIoStatsDeltas() {
try {
return mService.getIoStatsDeltas();
@@ -250,7 +258,7 @@
*
* The timing of availability of the deltas is configurable by the OEM.
*/
- @RequiresPermission(value=Car.PERMISSION_STORAGE_MONITORING)
+ @RequiresPermission(value = Car.PERMISSION_STORAGE_MONITORING)
public void registerListener(IoStatsListener listener) {
try {
if (mListeners.isEmpty()) {
@@ -268,7 +276,7 @@
/**
* This method removes a registered listener of I/O stats deltas.
*/
- @RequiresPermission(value=Car.PERMISSION_STORAGE_MONITORING)
+ @RequiresPermission(value = Car.PERMISSION_STORAGE_MONITORING)
public void unregisterListener(IoStatsListener listener) {
try {
if (!mListeners.remove(listener)) {
diff --git a/car-lib/src/android/car/user/CarUserManager.java b/car-lib/src/android/car/user/CarUserManager.java
index 1525889..a4daa42 100644
--- a/car-lib/src/android/car/user/CarUserManager.java
+++ b/car-lib/src/android/car/user/CarUserManager.java
@@ -20,6 +20,8 @@
import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL;
import static android.os.Process.myUid;
+import static com.android.internal.util.FunctionalUtils.getLambdaName;
+
import android.annotation.CallbackExecutor;
import android.annotation.IntDef;
import android.annotation.NonNull;
@@ -57,6 +59,7 @@
import java.util.List;
import java.util.Objects;
import java.util.concurrent.Executor;
+import java.util.stream.Collectors;
/**
* API to manage users related to car.
@@ -209,7 +212,7 @@
@Override
protected void onCompleted(UserSwitchResult result, Throwable err) {
if (result != null) {
- EventLog.writeEvent(EventLogTags.CAR_USER_MGR_SWITCH_USER_RESPONSE, uid,
+ EventLog.writeEvent(EventLogTags.CAR_USER_MGR_SWITCH_USER_RESP, uid,
result.getStatus(), result.getErrorMessage());
} else {
Log.w(TAG, "switchUser(" + targetUserId + ") failed: " + err);
@@ -217,7 +220,7 @@
super.onCompleted(result, err);
};
};
- EventLog.writeEvent(EventLogTags.CAR_USER_MGR_SWITCH_USER_REQUEST, uid, targetUserId);
+ EventLog.writeEvent(EventLogTags.CAR_USER_MGR_SWITCH_USER_REQ, uid, targetUserId);
mService.switchUser(targetUserId, HAL_TIMEOUT_MS, future);
return future;
} catch (RemoteException e) {
@@ -264,6 +267,28 @@
}
}
+ /**
+ * Removes a user.
+ *
+ * @hide
+ */
+ @RequiresPermission(android.Manifest.permission.MANAGE_USERS)
+ public UserRemovalResult removeUser(@UserIdInt int userId) {
+ int uid = myUid();
+ EventLog.writeEvent(EventLogTags.CAR_USER_MGR_REMOVE_USER_REQ, uid, userId);
+ int status = UserRemovalResult.STATUS_HAL_INTERNAL_FAILURE;
+ try {
+ UserRemovalResult result = mService.removeUser(userId);
+ status = result.getStatus();
+ return result;
+ } catch (RemoteException e) {
+ return handleRemoteExceptionFromCarService(e,
+ new UserRemovalResult(UserRemovalResult.STATUS_HAL_INTERNAL_FAILURE));
+ } finally {
+ EventLog.writeEvent(EventLogTags.CAR_USER_MGR_REMOVE_USER_RESP, uid, status);
+ }
+ }
+
/**
* Adds a listener for {@link UserLifecycleEvent user lifecycle events}.
*
@@ -298,6 +323,12 @@
if (mListeners == null) {
mListeners = new ArrayMap<>(1); // Most likely app will have just one listener
+ } else if (DBG) {
+ Log.d(TAG, "addListener(" + getLambdaName(listener) + "): context " + getContext()
+ + " already has " + mListeners.size() + " listeners: "
+ + mListeners.keySet().stream()
+ .map((l) -> getLambdaName(l))
+ .collect(Collectors.toList()), new Exception());
}
if (DBG) Log.d(TAG, "Adding listener: " + listener);
mListeners.put(listener, executor);
@@ -480,10 +511,15 @@
Log.w(TAG, "No listeners for event " + event);
return;
}
- for (int i = 0; i < listeners.size(); i++) {
+ int size = listeners.size();
+ EventLog.writeEvent(EventLogTags.CAR_USER_MGR_NOTIFY_LIFECYCLE_LISTENER,
+ size, eventType, from, to);
+ for (int i = 0; i < size; i++) {
UserLifecycleListener listener = listeners.keyAt(i);
Executor executor = listeners.valueAt(i);
- if (DBG) Log.d(TAG, "Calling listener " + listener + " for event " + event);
+ if (DBG) {
+ Log.d(TAG, "Calling " + getLambdaName(listener) + " for event " + event);
+ }
executor.execute(() -> listener.onEvent(event));
}
}
diff --git a/car-lib/src/android/car/user/ExperimentalCarUserManager.java b/car-lib/src/android/car/user/ExperimentalCarUserManager.java
index 1396971..fa7eb72 100644
--- a/car-lib/src/android/car/user/ExperimentalCarUserManager.java
+++ b/car-lib/src/android/car/user/ExperimentalCarUserManager.java
@@ -72,19 +72,21 @@
*
* @param name The name of the driver to be created.
* @param admin Whether the created driver will be an admin.
- * @return user id of the created driver, or {@code INVALID_USER_ID} if the driver could
- * not be created.
+ * @return an {@link AndroidFuture} that can be used to track operation's completion and
+ * retrieve its result (if any).
*
* @hide
*/
@RequiresPermission(android.Manifest.permission.MANAGE_USERS)
- @Nullable
- public int createDriver(@NonNull String name, boolean admin) {
+ public AndroidFuture<UserCreationResult> createDriver(@NonNull String name, boolean admin) {
try {
- UserInfo ui = mService.createDriver(name, admin);
- return ui != null ? ui.id : INVALID_USER_ID;
+ return mService.createDriver(name, admin);
} catch (RemoteException e) {
- return handleRemoteExceptionFromCarService(e, null);
+ AndroidFuture<UserCreationResult> future = new AndroidFuture<>();
+ future.complete(new UserCreationResult(UserCreationResult.STATUS_HAL_INTERNAL_FAILURE,
+ null, null));
+ handleRemoteExceptionFromCarService(e);
+ return future;
}
}
diff --git a/car-lib/src/android/car/user/UserCreationResult.java b/car-lib/src/android/car/user/UserCreationResult.java
index a79abee..328908f 100644
--- a/car-lib/src/android/car/user/UserCreationResult.java
+++ b/car-lib/src/android/car/user/UserCreationResult.java
@@ -69,15 +69,21 @@
public static final int STATUS_HAL_INTERNAL_FAILURE = CommonResults.STATUS_HAL_INTERNAL_FAILURE;
/**
- * Gets the user switch result status.
+ * {@link Status} called when given parameters or environment states are invalid for creating
+ * user - HAL or Android user creation is not requested.
+ */
+ public static final int STATUS_INVALID_REQUEST = CommonResults.STATUS_INVALID_REQUEST;
+
+ /**
+ * Gets the user creation result status.
*
* @return either {@link UserCreationResult#STATUS_SUCCESSFUL},
* {@link UserCreationResult#STATUS_ANDROID_FAILURE},
* {@link UserCreationResult#STATUS_HAL_FAILURE},
- * or
- * {@link UserCreationResult#STATUS_HAL_INTERNAL_FAILURE}
+ * {@link UserCreationResult#STATUS_HAL_INTERNAL_FAILURE}, or
+ * {@link UserCreationResult#STATUS_INVALID_REQUEST}.
*/
- private final int mStatus;
+ private final @Status int mStatus;
/**
* Gets the created user.
@@ -98,6 +104,8 @@
return mStatus == STATUS_SUCCESSFUL;
}
+ // TODO(b/158195639): if you change any status constant, you need to manually assign its values
+
// Code below generated by codegen v1.0.15.
@@ -118,7 +126,8 @@
STATUS_SUCCESSFUL,
STATUS_ANDROID_FAILURE,
STATUS_HAL_FAILURE,
- STATUS_HAL_INTERNAL_FAILURE
+ STATUS_HAL_INTERNAL_FAILURE,
+ STATUS_INVALID_REQUEST
})
@Retention(RetentionPolicy.SOURCE)
@DataClass.Generated.Member
@@ -136,6 +145,8 @@
return "STATUS_HAL_FAILURE";
case STATUS_HAL_INTERNAL_FAILURE:
return "STATUS_HAL_INTERNAL_FAILURE";
+ case STATUS_INVALID_REQUEST:
+ return "STATUS_INVALID_REQUEST";
default: return Integer.toHexString(value);
}
}
@@ -144,13 +155,13 @@
* Creates a new UserCreationResult.
*
* @param status
- * Gets the user switch result status.
+ * Gets the user creation result status.
*
* @return either {@link UserCreationResult#STATUS_SUCCESSFUL},
* {@link UserCreationResult#STATUS_ANDROID_FAILURE},
* {@link UserCreationResult#STATUS_HAL_FAILURE},
- * or
- * {@link UserCreationResult#STATUS_HAL_INTERNAL_FAILURE}
+ * {@link UserCreationResult#STATUS_HAL_INTERNAL_FAILURE}, or
+ * {@link UserCreationResult#STATUS_INVALID_REQUEST}.
* @param user
* Gets the created user.
* @param errorMessage
@@ -159,10 +170,25 @@
*/
@DataClass.Generated.Member
public UserCreationResult(
- int status,
+ @Status int status,
@Nullable UserInfo user,
@Nullable String errorMessage) {
this.mStatus = status;
+
+ if (!(mStatus == STATUS_SUCCESSFUL)
+ && !(mStatus == STATUS_ANDROID_FAILURE)
+ && !(mStatus == STATUS_HAL_FAILURE)
+ && !(mStatus == STATUS_HAL_INTERNAL_FAILURE)
+ && !(mStatus == STATUS_INVALID_REQUEST)) {
+ throw new java.lang.IllegalArgumentException(
+ "status was " + mStatus + " but must be one of: "
+ + "STATUS_SUCCESSFUL(" + STATUS_SUCCESSFUL + "), "
+ + "STATUS_ANDROID_FAILURE(" + STATUS_ANDROID_FAILURE + "), "
+ + "STATUS_HAL_FAILURE(" + STATUS_HAL_FAILURE + "), "
+ + "STATUS_HAL_INTERNAL_FAILURE(" + STATUS_HAL_INTERNAL_FAILURE + "), "
+ + "STATUS_INVALID_REQUEST(" + STATUS_INVALID_REQUEST + ")");
+ }
+
this.mUser = user;
this.mErrorMessage = errorMessage;
@@ -170,16 +196,16 @@
}
/**
- * Gets the user switch result status.
+ * Gets the user creation result status.
*
* @return either {@link UserCreationResult#STATUS_SUCCESSFUL},
* {@link UserCreationResult#STATUS_ANDROID_FAILURE},
* {@link UserCreationResult#STATUS_HAL_FAILURE},
- * or
- * {@link UserCreationResult#STATUS_HAL_INTERNAL_FAILURE}
+ * {@link UserCreationResult#STATUS_HAL_INTERNAL_FAILURE}, or
+ * {@link UserCreationResult#STATUS_INVALID_REQUEST}.
*/
@DataClass.Generated.Member
- public int getStatus() {
+ public @Status int getStatus() {
return mStatus;
}
@@ -206,7 +232,7 @@
// String fieldNameToString() { ... }
return "UserCreationResult { " +
- "status = " + mStatus + ", " +
+ "status = " + statusToString(mStatus) + ", " +
"user = " + mUser + ", " +
"errorMessage = " + mErrorMessage +
" }";
@@ -244,6 +270,21 @@
String errorMessage = (flg & 0x4) == 0 ? null : in.readString();
this.mStatus = status;
+
+ if (!(mStatus == STATUS_SUCCESSFUL)
+ && !(mStatus == STATUS_ANDROID_FAILURE)
+ && !(mStatus == STATUS_HAL_FAILURE)
+ && !(mStatus == STATUS_HAL_INTERNAL_FAILURE)
+ && !(mStatus == STATUS_INVALID_REQUEST)) {
+ throw new java.lang.IllegalArgumentException(
+ "status was " + mStatus + " but must be one of: "
+ + "STATUS_SUCCESSFUL(" + STATUS_SUCCESSFUL + "), "
+ + "STATUS_ANDROID_FAILURE(" + STATUS_ANDROID_FAILURE + "), "
+ + "STATUS_HAL_FAILURE(" + STATUS_HAL_FAILURE + "), "
+ + "STATUS_HAL_INTERNAL_FAILURE(" + STATUS_HAL_INTERNAL_FAILURE + "), "
+ + "STATUS_INVALID_REQUEST(" + STATUS_INVALID_REQUEST + ")");
+ }
+
this.mUser = user;
this.mErrorMessage = errorMessage;
@@ -265,10 +306,10 @@
};
@DataClass.Generated(
- time = 1591121994170L,
+ time = 1591401523007L,
codegenVersion = "1.0.15",
sourceFile = "packages/services/Car/car-lib/src/android/car/user/UserCreationResult.java",
- inputSignatures = "public static final int STATUS_SUCCESSFUL\npublic static final int STATUS_ANDROID_FAILURE\npublic static final int STATUS_HAL_FAILURE\npublic static final int STATUS_HAL_INTERNAL_FAILURE\nprivate final int mStatus\nprivate final @android.annotation.Nullable android.content.pm.UserInfo mUser\nprivate final @android.annotation.Nullable java.lang.String mErrorMessage\npublic boolean isSuccess()\nclass UserCreationResult extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genToString=true, genHiddenConstructor=true, genHiddenConstDefs=true)")
+ inputSignatures = "public static final int STATUS_SUCCESSFUL\npublic static final int STATUS_ANDROID_FAILURE\npublic static final int STATUS_HAL_FAILURE\npublic static final int STATUS_HAL_INTERNAL_FAILURE\npublic static final int STATUS_INVALID_REQUEST\nprivate final @android.car.user.UserCreationResult.Status int mStatus\nprivate final @android.annotation.Nullable android.content.pm.UserInfo mUser\nprivate final @android.annotation.Nullable java.lang.String mErrorMessage\npublic boolean isSuccess()\nclass UserCreationResult extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genToString=true, genHiddenConstructor=true, genHiddenConstDefs=true)")
@Deprecated
private void __metadata() {}
diff --git a/car-lib/src/android/car/user/UserRemovalResult.aidl b/car-lib/src/android/car/user/UserRemovalResult.aidl
new file mode 100644
index 0000000..00a0eba
--- /dev/null
+++ b/car-lib/src/android/car/user/UserRemovalResult.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.car.user;
+
+parcelable UserRemovalResult;
diff --git a/car-lib/src/android/car/user/UserRemovalResult.java b/car-lib/src/android/car/user/UserRemovalResult.java
new file mode 100644
index 0000000..dbfd8a6
--- /dev/null
+++ b/car-lib/src/android/car/user/UserRemovalResult.java
@@ -0,0 +1,249 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.car.user;
+
+import android.annotation.IntDef;
+import android.os.Parcelable;
+
+import com.android.internal.util.DataClass;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * User remove result.
+ *
+ * @hide
+ */
+@DataClass(
+ genToString = true,
+ genHiddenConstructor = true,
+ genHiddenConstDefs = true)
+public final class UserRemovalResult implements Parcelable {
+
+ /**
+ * When user remove is successful.
+ *
+ * @hide
+ */
+ public static final int STATUS_SUCCESSFUL = CommonResults.STATUS_SUCCESSFUL;
+
+ /**
+ * When user remove fails for android. Hal user is not removed.
+ *
+ * @hide
+ */
+ public static final int STATUS_ANDROID_FAILURE = CommonResults.STATUS_ANDROID_FAILURE;
+
+ /**
+ * When remove user fails for unknown error.
+ *
+ * @hide
+ */
+ public static final int STATUS_HAL_INTERNAL_FAILURE = CommonResults.STATUS_HAL_INTERNAL_FAILURE;
+
+ /**
+ * When user to remove is same as current user.
+ *
+ * @hide
+ */
+ public static final int STATUS_TARGET_USER_IS_CURRENT_USER =
+ CommonResults.LAST_COMMON_STATUS + 1;
+
+ /**
+ * When user to remove doesn't exits.
+ *
+ * @hide
+ */
+ public static final int STATUS_USER_DOES_NOT_EXIST = CommonResults.LAST_COMMON_STATUS + 2;
+
+ /**
+ * When user to remove is last admin user.
+ *
+ * @hide
+ */
+ public static final int STATUS_TARGET_USER_IS_LAST_ADMIN_USER =
+ CommonResults.LAST_COMMON_STATUS + 3;
+
+ /**
+ * Gets the user switch result status.
+ *
+ * @return either {@link UserRemovalResult#STATUS_SUCCESSFUL},
+ * {@link UserRemovalResult#STATUS_ANDROID_FAILURE},
+ * {@link UserRemovalResult#STATUS_HAL_INTERNAL_FAILURE},
+ * {@link UserRemovalResult#STATUS_TARGET_USER_IS_CURRENT_USER},
+ * {@link UserRemovalResult#STATUS_USER_DOES_NOT_EXIST}, or
+ * {@link UserRemovalResult#STATUS_TARGET_USER_IS_LAST_ADMIN_USER}.
+ */
+ private final @Status int mStatus;
+
+ public boolean isSuccess() {
+ return mStatus == STATUS_SUCCESSFUL;
+ }
+
+ // TODO(b/158195639): if you change any status constant, you need to manually assign its values
+ // (rather than using CommonResults) before running codegen to regenerate the class
+
+
+ // Code below generated by codegen v1.0.15.
+ //
+ // DO NOT MODIFY!
+ // CHECKSTYLE:OFF Generated code
+ //
+ // To regenerate run:
+ // $ codegen $ANDROID_BUILD_TOP/packages/services/Car/car-lib/src/android/car/user/UserRemovalResult.java
+ //
+ // To exclude the generated code from IntelliJ auto-formatting enable (one-time):
+ // Settings > Editor > Code Style > Formatter Control
+ //@formatter:off
+
+
+ /** @hide */
+ @IntDef(prefix = "STATUS_", value = {
+ STATUS_SUCCESSFUL,
+ STATUS_ANDROID_FAILURE,
+ STATUS_HAL_INTERNAL_FAILURE,
+ STATUS_TARGET_USER_IS_CURRENT_USER,
+ STATUS_USER_DOES_NOT_EXIST,
+ STATUS_TARGET_USER_IS_LAST_ADMIN_USER
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ @DataClass.Generated.Member
+ public @interface Status {}
+
+ /** @hide */
+ @DataClass.Generated.Member
+ public static String statusToString(@Status int value) {
+ switch (value) {
+ case STATUS_SUCCESSFUL:
+ return "STATUS_SUCCESSFUL";
+ case STATUS_ANDROID_FAILURE:
+ return "STATUS_ANDROID_FAILURE";
+ case STATUS_HAL_INTERNAL_FAILURE:
+ return "STATUS_HAL_INTERNAL_FAILURE";
+ case STATUS_TARGET_USER_IS_CURRENT_USER:
+ return "STATUS_TARGET_USER_IS_CURRENT_USER";
+ case STATUS_USER_DOES_NOT_EXIST:
+ return "STATUS_USER_DOES_NOT_EXIST";
+ case STATUS_TARGET_USER_IS_LAST_ADMIN_USER:
+ return "STATUS_TARGET_USER_IS_LAST_ADMIN_USER";
+ default: return Integer.toHexString(value);
+ }
+ }
+
+ /**
+ * Creates a new UserRemovalResult.
+ *
+ * @param status
+ * Gets the user switch result status.
+ *
+ * @return either {@link UserRemovalResult#STATUS_SUCCESSFUL},
+ * {@link UserRemovalResult#STATUS_ANDROID_FAILURE},
+ * {@link UserRemovalResult#STATUS_HAL_INTERNAL_FAILURE},
+ * {@link UserRemovalResult#STATUS_TARGET_USER_IS_CURRENT_USER},
+ * {@link UserRemovalResult#STATUS_USER_DOES_NOT_EXIST}, or
+ * {@link UserRemovalResult#STATUS_TARGET_USER_IS_LAST_ADMIN_USER}.
+ * @hide
+ */
+ @DataClass.Generated.Member
+ public UserRemovalResult(
+ int status) {
+ this.mStatus = status;
+
+ // onConstructed(); // You can define this method to get a callback
+ }
+
+ /**
+ * Gets the user switch result status.
+ *
+ * @return either {@link UserRemovalResult#STATUS_SUCCESSFUL},
+ * {@link UserRemovalResult#STATUS_ANDROID_FAILURE},
+ * {@link UserRemovalResult#STATUS_HAL_INTERNAL_FAILURE},
+ * {@link UserRemovalResult#STATUS_TARGET_USER_IS_CURRENT_USER},
+ * {@link UserRemovalResult#STATUS_USER_DOES_NOT_EXIST}, or
+ * {@link UserRemovalResult#STATUS_TARGET_USER_IS_LAST_ADMIN_USER}.
+ */
+ @DataClass.Generated.Member
+ public int getStatus() {
+ return mStatus;
+ }
+
+ @Override
+ @DataClass.Generated.Member
+ public String toString() {
+ // You can override field toString logic by defining methods like:
+ // String fieldNameToString() { ... }
+
+ return "UserRemovalResult { " +
+ "status = " + mStatus +
+ " }";
+ }
+
+ @Override
+ @DataClass.Generated.Member
+ public void writeToParcel(@android.annotation.NonNull android.os.Parcel dest, int flags) {
+ // You can override field parcelling by defining methods like:
+ // void parcelFieldName(Parcel dest, int flags) { ... }
+
+ dest.writeInt(mStatus);
+ }
+
+ @Override
+ @DataClass.Generated.Member
+ public int describeContents() { return 0; }
+
+ /** @hide */
+ @SuppressWarnings({"unchecked", "RedundantCast"})
+ @DataClass.Generated.Member
+ /* package-private */ UserRemovalResult(@android.annotation.NonNull android.os.Parcel in) {
+ // You can override field unparcelling by defining methods like:
+ // static FieldType unparcelFieldName(Parcel in) { ... }
+
+ int status = in.readInt();
+
+ this.mStatus = status;
+
+ // onConstructed(); // You can define this method to get a callback
+ }
+
+ @DataClass.Generated.Member
+ public static final @android.annotation.NonNull Parcelable.Creator<UserRemovalResult> CREATOR
+ = new Parcelable.Creator<UserRemovalResult>() {
+ @Override
+ public UserRemovalResult[] newArray(int size) {
+ return new UserRemovalResult[size];
+ }
+
+ @Override
+ public UserRemovalResult createFromParcel(@android.annotation.NonNull android.os.Parcel in) {
+ return new UserRemovalResult(in);
+ }
+ };
+
+ @DataClass.Generated(
+ time = 1591259644931L,
+ codegenVersion = "1.0.15",
+ sourceFile = "packages/services/Car/car-lib/src/android/car/user/UserRemovalResult.java",
+ inputSignatures = "public static final int STATUS_SUCCESSFUL\npublic static final int STATUS_ANDROID_FAILURE\npublic static final int STATUS_HAL_INTERNAL_FAILURE\npublic static final int STATUS_TARGET_USER_IS_CURRENT_USER\npublic static final int STATUS_USER_DOES_NOT_EXIST\npublic static final int STATUS_TARGET_USER_IS_LAST_ADMIN_USER\nprivate final int mStatus\npublic boolean isSuccess()\nclass UserRemovalResult extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genToString=true, genHiddenConstructor=true, genHiddenConstDefs=true)")
+ @Deprecated
+ private void __metadata() {}
+
+
+ //@formatter:on
+ // End of generated code
+
+}
diff --git a/car-lib/src/android/car/user/UserSwitchResult.java b/car-lib/src/android/car/user/UserSwitchResult.java
index 41da19b..55e2dbc 100644
--- a/car-lib/src/android/car/user/UserSwitchResult.java
+++ b/car-lib/src/android/car/user/UserSwitchResult.java
@@ -95,7 +95,7 @@
* {@link UserSwitchResult#STATUS_TARGET_USER_ABANDONED_DUE_TO_A_NEW_REQUEST}, or
* {@link UserSwitchResult#STATUS_INVALID_REQUEST}.
*/
- private final int mStatus;
+ private final @Status int mStatus;
/**
* Gets the error message, if any.
@@ -110,6 +110,8 @@
return mStatus == STATUS_SUCCESSFUL || mStatus == STATUS_ALREADY_REQUESTED_USER;
}
+ // TODO(b/158195639): if you change any status constant, you need to manually assign its values
+ // (rather than using CommonResults) before running codegen to regenerate the class
// Code below generated by codegen v1.0.15.
diff --git a/car-usb-handler/res/values-ur/strings.xml b/car-usb-handler/res/values-ur/strings.xml
index 0fe5553..109dd4c 100644
--- a/car-usb-handler/res/values-ur/strings.xml
+++ b/car-usb-handler/res/values-ur/strings.xml
@@ -19,9 +19,7 @@
<string name="app_name" msgid="6963366455471441257">"USB ہینڈلر"</string>
<string name="usb_saved_devices" msgid="2829442070749964872">"محفوظ کردہ آلات"</string>
<string name="usb_pref_delete_title" msgid="3885061814853467483">"USB آلہ کو ہینڈل کرنے والی اپپ کو ہٹائیں"</string>
- <!-- String.format failed for translation -->
- <!-- no translation found for usb_pref_delete_message (5849493572520646218) -->
- <skip />
+ <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_resolving_handlers" msgid="1943100136172948686">"تعاون یافتہ ہینڈلرز حاصل کر رہے ہیں"</string>
diff --git a/car-usb-handler/src/android/car/usb/handler/UsbDeviceHandlerResolver.java b/car-usb-handler/src/android/car/usb/handler/UsbDeviceHandlerResolver.java
index 8b2f425..a1be7dd 100644
--- a/car-usb-handler/src/android/car/usb/handler/UsbDeviceHandlerResolver.java
+++ b/car-usb-handler/src/android/car/usb/handler/UsbDeviceHandlerResolver.java
@@ -71,18 +71,16 @@
private final PackageManager mPackageManager;
private final UsbDeviceHandlerResolverCallback mDeviceCallback;
private final Context mContext;
- private final HandlerThread mHandlerThread;
- private final UsbDeviceResolverHandler mHandler;
private final AoapServiceManager mAoapServiceManager;
+ private HandlerThread mHandlerThread;
+ private UsbDeviceResolverHandler mHandler;
public UsbDeviceHandlerResolver(UsbManager manager, Context context,
UsbDeviceHandlerResolverCallback deviceListener) {
mUsbManager = manager;
mContext = context;
mDeviceCallback = deviceListener;
- mHandlerThread = new HandlerThread(TAG);
- mHandlerThread.start();
- mHandler = new UsbDeviceResolverHandler(mHandlerThread.getLooper());
+ createHandlerThread();
mPackageManager = context.getPackageManager();
mAoapServiceManager = new AoapServiceManager(mContext.getApplicationContext());
}
@@ -104,9 +102,22 @@
}
/**
+ * Listener for failed {@code startAosp} command.
+ *
+ * <p>If {@code startAosp} fails, the device could be left in a inconsistent state, that's why
+ * we go back to USB enumeration, instead of just repeating the command.
+ */
+ public interface StartAoapFailureListener {
+
+ /** Called if startAoap fails. */
+ void onFailure();
+ }
+
+ /**
* Dispatches device to component.
*/
- public boolean dispatch(UsbDevice device, ComponentName component, boolean inAoap) {
+ public boolean dispatch(UsbDevice device, ComponentName component, boolean inAoap,
+ StartAoapFailureListener failureListener) {
if (LOCAL_LOGD) {
Log.d(TAG, "dispatch: " + device + " component: " + component + " inAoap: " + inAoap);
}
@@ -128,10 +139,20 @@
packageMatches(activityInfo, intent.getAction(), device, true);
if (filter != null) {
+ if (!mHandlerThread.isAlive()) {
+ // Start a new thread. Used only when startAoap fails, and we need to
+ // re-enumerate device in order to try again.
+ createHandlerThread();
+ }
mHandlerThread.getThreadHandler().post(() -> {
if (mAoapServiceManager.canSwitchDeviceToAoap(device,
ComponentName.unflattenFromString(filter.mAoapService))) {
- requestAoapSwitch(device, filter);
+ try {
+ requestAoapSwitch(device, filter);
+ } catch (IOException e) {
+ Log.w(TAG, "Start AOAP command failed:" + e);
+ failureListener.onFailure();
+ }
} else {
Log.i(TAG, "Ignore AOAP switch for device " + device
+ " handled by " + filter.mAoapService);
@@ -151,6 +172,12 @@
return true;
}
+ private void createHandlerThread() {
+ mHandlerThread = new HandlerThread(TAG);
+ mHandlerThread.start();
+ mHandler = new UsbDeviceResolverHandler(mHandlerThread.getLooper());
+ }
+
private static Intent createDeviceAttachedIntent(UsbDevice device) {
Intent intent = new Intent(UsbManager.ACTION_USB_DEVICE_ATTACHED);
intent.putExtra(UsbManager.EXTRA_DEVICE, device);
@@ -192,7 +219,7 @@
return settings;
}
- private void requestAoapSwitch(UsbDevice device, UsbDeviceFilter filter) {
+ private void requestAoapSwitch(UsbDevice device, UsbDeviceFilter filter) throws IOException {
UsbDeviceConnection connection = UsbUtil.openConnection(mUsbManager, device);
if (connection == null) {
Log.e(TAG, "Failed to connect to usb device.");
@@ -209,11 +236,9 @@
filter.mAoapVersion,
filter.mAoapUri,
hashedSerial);
- } catch (IOException e) {
- Log.w(TAG, "Failed to switch device into AOAP mode", e);
+ } finally {
+ connection.close();
}
-
- connection.close();
}
private String getHashed(String serial) {
diff --git a/car-usb-handler/src/android/car/usb/handler/UsbHostController.java b/car-usb-handler/src/android/car/usb/handler/UsbHostController.java
index 3fcb67b..0da71ac 100644
--- a/car-usb-handler/src/android/car/usb/handler/UsbHostController.java
+++ b/car-usb-handler/src/android/car/usb/handler/UsbHostController.java
@@ -30,6 +30,7 @@
import com.android.internal.annotations.GuardedBy;
import java.util.ArrayList;
+import java.util.Iterator;
import java.util.List;
/**
@@ -300,6 +301,12 @@
private static final int DEVICE_REMOVE_TIMEOUT_MS = 500;
+ // Used to get the device that we are trying to connect to, if mActiveDevice is removed and
+ // startAoap fails afterwards. Used during USB enumeration when retrying to startAoap when
+ // there are multiple devices attached.
+ private int mLastDeviceId = 0;
+ private int mStartAoapRetries = 1;
+
private UsbHostControllerHandler(Looper looper) {
super(looper);
}
@@ -308,6 +315,24 @@
sendEmptyMessageDelayed(MSG_DEVICE_REMOVED, DEVICE_REMOVE_TIMEOUT_MS);
}
+ private void onFailure() {
+ if (mStartAoapRetries == 0) {
+ Log.w(TAG, "Reached maximum retry count for startAoap. Giving up Aoa handshake.");
+ return;
+ }
+ mStartAoapRetries--;
+
+ Log.d(TAG, "Restarting USB enumeration.");
+ Iterator<UsbDevice> deviceIterator = mUsbManager.getDeviceList().values().iterator();
+ while (deviceIterator.hasNext()) {
+ UsbDevice device = deviceIterator.next();
+ if (mLastDeviceId == device.getDeviceId()) {
+ processDevice(device);
+ return;
+ }
+ }
+ }
+
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
@@ -318,8 +343,10 @@
UsbHostControllerHandlerDispatchData data =
(UsbHostControllerHandlerDispatchData) msg.obj;
UsbDevice device = data.getUsbDevice();
+ mLastDeviceId = device.getDeviceId();
UsbDeviceSettings settings = data.getUsbDeviceSettings();
- if (!mUsbResolver.dispatch(device, settings.getHandler(), settings.getAoap())) {
+ if (!mUsbResolver.dispatch(device, settings.getHandler(), settings.getAoap(),
+ this::onFailure)) {
if (data.mRetries > 0) {
--data.mRetries;
Message nextMessage = Message.obtain(msg);
diff --git a/service/src/com/android/car/CarPowerManagementService.java b/service/src/com/android/car/CarPowerManagementService.java
index f9e15cc..aef68cd 100644
--- a/service/src/com/android/car/CarPowerManagementService.java
+++ b/service/src/com/android/car/CarPowerManagementService.java
@@ -44,6 +44,7 @@
import android.os.PowerManager;
import android.os.RemoteCallbackList;
import android.os.RemoteException;
+import android.os.ServiceManager;
import android.os.SystemClock;
import android.os.SystemProperties;
import android.os.UserHandle;
@@ -59,6 +60,7 @@
import com.android.car.user.CarUserService;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.app.IVoiceInteractionManagerService;
import java.io.PrintWriter;
import java.lang.ref.WeakReference;
@@ -137,6 +139,8 @@
private final CarUserService mUserService;
private final InitialUserSetter mInitialUserSetter;
+ private final IVoiceInteractionManagerService mVoiceInteractionManagerService;
+
// TODO: Make this OEM configurable.
private static final int SHUTDOWN_POLLING_INTERVAL_MS = 2000;
private static final int SHUTDOWN_EXTEND_MAX_MS = 5000;
@@ -168,13 +172,16 @@
this(context, context.getResources(), powerHal, systemInterface, UserManager.get(context),
carUserService, new InitialUserSetter(context,
(u) -> carUserService.setInitialUser(u),
- context.getString(R.string.default_guest_name)));
+ context.getString(R.string.default_guest_name)),
+ IVoiceInteractionManagerService.Stub.asInterface(
+ ServiceManager.getService(Context.VOICE_INTERACTION_MANAGER_SERVICE)));
}
@VisibleForTesting
public CarPowerManagementService(Context context, Resources resources, PowerHalService powerHal,
SystemInterface systemInterface, UserManager userManager, CarUserService carUserService,
- InitialUserSetter initialUserSetter) {
+ InitialUserSetter initialUserSetter,
+ IVoiceInteractionManagerService voiceInteractionService) {
mContext = context;
mHal = powerHal;
mSystemInterface = systemInterface;
@@ -194,6 +201,7 @@
}
mUserService = carUserService;
mInitialUserSetter = initialUserSetter;
+ mVoiceInteractionManagerService = voiceInteractionService;
}
@VisibleForTesting
@@ -408,6 +416,7 @@
mSystemInterface.setDisplayState(true);
sendPowerManagerEvent(CarPowerStateListener.ON);
+
mHal.sendOn();
try {
@@ -415,6 +424,8 @@
} catch (Exception e) {
Log.e(CarLog.TAG_POWER, "Could not switch user on resume", e);
}
+
+ setVoiceInteractionDisabled(false);
}
@VisibleForTesting // Ideally it should not be exposed, but it speeds up the unit tests
@@ -552,6 +563,7 @@
}
private void handleShutdownPrepare(CpmsState newState) {
+ setVoiceInteractionDisabled(true);
mSystemInterface.setDisplayState(false);
// Shutdown on finish if the system doesn't support deep sleep or doesn't allow it.
synchronized (mLock) {
@@ -619,6 +631,8 @@
throw new AssertionError("Should not return from PowerManager.reboot()");
}
}
+ setVoiceInteractionDisabled(true);
+
if (mustShutDown) {
// shutdown HU
mSystemInterface.shutdown();
@@ -628,6 +642,14 @@
mShutdownOnNextSuspend = false;
}
+ private void setVoiceInteractionDisabled(boolean disabled) {
+ try {
+ mVoiceInteractionManagerService.setDisabled(disabled);
+ } catch (RemoteException e) {
+ Log.w(TAG, "setVoiceIntefactionDisabled(" + disabled + ") failed", e);
+ }
+ }
+
@GuardedBy("mLock")
private void releaseTimerLocked() {
if (mTimer != null) {
diff --git a/service/src/com/android/car/CarShellCommand.java b/service/src/com/android/car/CarShellCommand.java
index ad7f31f..0a8c420 100644
--- a/service/src/com/android/car/CarShellCommand.java
+++ b/service/src/com/android/car/CarShellCommand.java
@@ -36,6 +36,7 @@
import android.car.user.CarUserManager;
import android.car.user.UserCreationResult;
import android.car.user.UserIdentificationAssociationResponse;
+import android.car.user.UserRemovalResult;
import android.car.user.UserSwitchResult;
import android.car.userlib.HalCallback;
import android.car.userlib.UserHalHelper;
@@ -46,6 +47,7 @@
import android.hardware.automotive.vehicle.V2_0.CreateUserStatus;
import android.hardware.automotive.vehicle.V2_0.InitialUserInfoResponse;
import android.hardware.automotive.vehicle.V2_0.InitialUserInfoResponseAction;
+import android.hardware.automotive.vehicle.V2_0.RemoveUserRequest;
import android.hardware.automotive.vehicle.V2_0.SwitchUserMessageType;
import android.hardware.automotive.vehicle.V2_0.SwitchUserRequest;
import android.hardware.automotive.vehicle.V2_0.SwitchUserStatus;
@@ -125,6 +127,7 @@
private static final String COMMAND_INJECT_ROTARY = "inject-rotary";
private static final String COMMAND_GET_INITIAL_USER_INFO = "get-initial-user-info";
private static final String COMMAND_SWITCH_USER = "switch-user";
+ private static final String COMMAND_REMOVE_USER = "remove-user";
private static final String COMMAND_CREATE_USER = "create-user";
private static final String COMMAND_GET_INITIAL_USER = "get-initial-user";
private static final String COMMAND_SET_USER_ID_TO_OCCUPANT_ZONE =
@@ -155,6 +158,8 @@
android.Manifest.permission.MANAGE_USERS);
USER_BUILD_COMMAND_TO_PERMISSION_MAP.put(COMMAND_SWITCH_USER,
android.Manifest.permission.MANAGE_USERS);
+ USER_BUILD_COMMAND_TO_PERMISSION_MAP.put(COMMAND_REMOVE_USER,
+ android.Manifest.permission.MANAGE_USERS);
USER_BUILD_COMMAND_TO_PERMISSION_MAP.put(COMMAND_CREATE_USER,
android.Manifest.permission.MANAGE_USERS);
USER_BUILD_COMMAND_TO_PERMISSION_MAP.put(COMMAND_GET_USER_AUTH_ASSOCIATION,
@@ -374,6 +379,10 @@
pw.println("\t The --hal-only option only calls HAL, without switching the user,");
pw.println("\t while the --timeout defines how long to wait for the HAL response.");
+ pw.printf("\t%s <USER_ID> [--hal-only]\n", COMMAND_REMOVE_USER);
+ pw.println("\t Removes user with USER_ID using the HAL integration.");
+ pw.println("\t The --hal-only option only calls HAL, without removing the user,");
+
pw.printf("\t%s [--hal-only] [--timeout TIMEOUT_MS] [--type TYPE] [--flags FLAGS] [NAME]\n",
COMMAND_CREATE_USER);
pw.println("\t Creates a new user using the HAL integration.");
@@ -609,6 +618,9 @@
case COMMAND_SWITCH_USER:
switchUser(args, writer);
break;
+ case COMMAND_REMOVE_USER:
+ removeUser(args, writer);
+ break;
case COMMAND_CREATE_USER:
createUser(args, writer);
break;
@@ -1111,6 +1123,52 @@
}
}
+ private void removeUser(String[] args, PrintWriter writer) {
+ if (args.length < 2) {
+ writer.println("Insufficient number of args");
+ return;
+ }
+
+ int userId = Integer.parseInt(args[1]);
+ boolean halOnly = false;
+
+ for (int i = 2; i < args.length; i++) {
+ String arg = args[i];
+ switch (arg) {
+ case "--hal-only":
+ halOnly = true;
+ break;
+ default:
+ writer.println("Invalid option at index " + i + ": " + arg);
+ return;
+ }
+ }
+
+ Log.d(TAG, "handleRemoveUser(): User to remove=" + userId + ", halOnly=" + halOnly);
+
+ if (halOnly) {
+ UserHalService userHal = mHal.getUserHal();
+ UsersInfo usersInfo = generateUsersInfo();
+ UserInfo userInfo = new UserInfo();
+ userInfo.userId = userId;
+ userInfo.flags = getUserHalFlags(userId);
+
+ RemoveUserRequest request = new RemoveUserRequest();
+ request.removedUserInfo = userInfo;
+ request.usersInfo = usersInfo;
+
+ userHal.removeUser(request);
+ writer.printf("User removal sent for HAL only.\n");
+ return;
+ }
+
+ CarUserManager carUserManager = getCarUserManager(mContext);
+ UserRemovalResult result = carUserManager.removeUser(userId);
+ if (result == null) return;
+ writer.printf("UserRemovalResult: status = %s\n",
+ UserRemovalResult.statusToString(result.getStatus()));
+ }
+
private static <T> T waitForFuture(@NonNull PrintWriter writer,
@NonNull AndroidFuture<T> future, int timeoutMs) {
T result = null;
diff --git a/service/src/com/android/car/audio/CarAudioService.java b/service/src/com/android/car/audio/CarAudioService.java
index b0dd41d..3efbd18 100644
--- a/service/src/com/android/car/audio/CarAudioService.java
+++ b/service/src/com/android/car/audio/CarAudioService.java
@@ -56,7 +56,6 @@
import android.text.TextUtils;
import android.util.Log;
import android.util.SparseIntArray;
-import android.view.DisplayAddress;
import android.view.KeyEvent;
import com.android.car.CarLocalServices;
@@ -1046,31 +1045,6 @@
return true;
}
- /**
- * Gets the zone id for the display port id.
- * @param displayPortId display port id to match
- * @return zone id for the display port id or
- * CarAudioManager.PRIMARY_AUDIO_ZONE if none are found
- */
- @Override
- public int getZoneIdForDisplayPortId(byte displayPortId) {
- enforcePermission(Car.PERMISSION_CAR_CONTROL_AUDIO_SETTINGS);
- requireDynamicRouting();
- synchronized (mImplLock) {
- for (int index = 0; index < mCarAudioZones.length; index++) {
- CarAudioZone zone = mCarAudioZones[index];
- List<DisplayAddress.Physical> displayAddresses = zone.getPhysicalDisplayAddresses();
- if (displayAddresses.stream().anyMatch(displayAddress->
- displayAddress.getPort() == displayPortId)) {
- return index;
- }
- }
-
- // Everything else defaults to primary audio zone
- return CarAudioManager.PRIMARY_AUDIO_ZONE;
- }
- }
-
@Override
public void registerVolumeCallback(@NonNull IBinder binder) {
synchronized (mImplLock) {
diff --git a/service/src/com/android/car/audio/CarAudioZone.java b/service/src/com/android/car/audio/CarAudioZone.java
index a87b4b1..f4a4a33 100644
--- a/service/src/com/android/car/audio/CarAudioZone.java
+++ b/service/src/com/android/car/audio/CarAudioZone.java
@@ -19,7 +19,6 @@
import android.media.AudioDeviceAttributes;
import android.media.AudioDeviceInfo;
import android.util.Log;
-import android.view.DisplayAddress;
import com.android.car.CarLog;
import com.android.internal.util.Preconditions;
@@ -45,14 +44,12 @@
private final int mId;
private final String mName;
private final List<CarVolumeGroup> mVolumeGroups;
- private final List<DisplayAddress.Physical> mPhysicalDisplayAddresses;
private List<AudioDeviceAttributes> mInputAudioDevice;
CarAudioZone(int id, String name) {
mId = id;
mName = name;
mVolumeGroups = new ArrayList<>();
- mPhysicalDisplayAddresses = new ArrayList<>();
mInputAudioDevice = new ArrayList<>();
}
@@ -96,23 +93,6 @@
}
/**
- * Associates a new display physical port with this audio zone. This can be used to
- * identify what zone an activity should produce sound in when launching on a particular display
- * @param physicalDisplayAddress port to associate with this zone
- */
- void addPhysicalDisplayAddress(DisplayAddress.Physical physicalDisplayAddress) {
- mPhysicalDisplayAddresses.add(physicalDisplayAddress);
- }
-
- /**
- * Gets list of ports for displays associated with this audio zone
- * @return list of Physical ports for displays associated with this audio zone
- */
- List<DisplayAddress.Physical> getPhysicalDisplayAddresses() {
- return mPhysicalDisplayAddresses;
- }
-
- /**
* @return Snapshot of available {@link CarVolumeGroup}s in array.
*/
CarVolumeGroup[] getVolumeGroups() {
@@ -173,11 +153,6 @@
void dump(String indent, PrintWriter writer) {
String internalIndent = indent + "\t";
writer.printf("%sCarAudioZone(%s:%d) isPrimary? %b\n", indent, mName, mId, isPrimaryZone());
- for (DisplayAddress.Physical physical: mPhysicalDisplayAddresses) {
- long port = (long) physical.getPort();
- writer.printf("%sDisplayAddress.Physical(%d)\n", internalIndent, port);
- }
- writer.println();
for (CarVolumeGroup group : mVolumeGroups) {
group.dump(internalIndent, writer);
diff --git a/service/src/com/android/car/audio/CarAudioZonesHelper.java b/service/src/com/android/car/audio/CarAudioZonesHelper.java
index 3ff25e9..1a4e0ad 100644
--- a/service/src/com/android/car/audio/CarAudioZonesHelper.java
+++ b/service/src/com/android/car/audio/CarAudioZonesHelper.java
@@ -22,7 +22,6 @@
import android.text.TextUtils;
import android.util.SparseIntArray;
import android.util.Xml;
-import android.view.DisplayAddress;
import com.android.car.audio.CarAudioContext.AudioContext;
import com.android.internal.util.Preconditions;
@@ -55,14 +54,11 @@
private static final String TAG_VOLUME_GROUP = "group";
private static final String TAG_AUDIO_DEVICE = "device";
private static final String TAG_CONTEXT = "context";
- private static final String TAG_DISPLAYS = "displays";
- private static final String TAG_DISPLAY = "display";
private static final String ATTR_VERSION = "version";
private static final String ATTR_IS_PRIMARY = "isPrimary";
private static final String ATTR_ZONE_NAME = "name";
private static final String ATTR_DEVICE_ADDRESS = "address";
private static final String ATTR_CONTEXT_NAME = "context";
- private static final String ATTR_PHYSICAL_PORT = "port";
private static final String ATTR_ZONE_ID = "audioZoneId";
private static final String ATTR_OCCUPANT_ZONE_ID = "occupantZoneId";
private static final String TAG_INPUT_DEVICES = "inputDevices";
@@ -132,7 +128,6 @@
private final Map<String, CarAudioDeviceInfo> mAddressToCarAudioDeviceInfo;
private final Map<String, AudioDeviceInfo> mAddressToInputAudioDeviceInfo;
private final InputStream mInputStream;
- private final Set<Long> mPortIds;
private final SparseIntArray mZoneIdToOccupantZoneIdMapping;
private final Set<Integer> mAudioZoneIds;
private final Set<String> mInputAudioDevices;
@@ -158,7 +153,6 @@
mAddressToInputAudioDeviceInfo =
CarAudioZonesHelper.generateAddressToInputAudioDeviceInfoMap(inputDeviceInfo);
mNextSecondaryZoneId = CarAudioManager.PRIMARY_AUDIO_ZONE + 1;
- mPortIds = new HashSet<>();
mZoneIdToOccupantZoneIdMapping = new SparseIntArray();
mAudioZoneIds = new HashSet<>();
mInputAudioDevices = new HashSet<>();
@@ -258,8 +252,6 @@
// Expect one <volumeGroups> in one audio zone
if (TAG_VOLUME_GROUPS.equals(parser.getName())) {
parseVolumeGroups(parser, zone);
- } else if (TAG_DISPLAYS.equals(parser.getName())) {
- parseDisplays(parser, zone);
} else if (TAG_INPUT_DEVICES.equals(parser.getName())) {
parseInputAudioDevices(parser, zone);
} else {
@@ -364,37 +356,6 @@
mInputAudioDevices.add(audioDeviceAddress);
}
- private void parseDisplays(XmlPullParser parser, CarAudioZone zone)
- throws IOException, XmlPullParserException {
- while (parser.next() != XmlPullParser.END_TAG) {
- if (parser.getEventType() != XmlPullParser.START_TAG) continue;
- if (TAG_DISPLAY.equals(parser.getName())) {
- zone.addPhysicalDisplayAddress(parsePhysicalDisplayAddress(parser));
- }
- skip(parser);
- }
- }
-
- private DisplayAddress.Physical parsePhysicalDisplayAddress(XmlPullParser parser) {
- String port = parser.getAttributeValue(NAMESPACE, ATTR_PHYSICAL_PORT);
- long portId;
- try {
- portId = Long.parseLong(port);
- } catch (NumberFormatException e) {
- throw new IllegalArgumentException(String.format("Port %s is not a number", port), e);
- }
- validatePortIsUnique(portId);
- return DisplayAddress.fromPhysicalDisplayId(portId);
- }
-
- private void validatePortIsUnique(Long portId) {
- if (mPortIds.contains(portId)) {
- throw new IllegalArgumentException(
- String.format("Port Id %d is already associated with a zone", portId));
- }
- mPortIds.add(portId);
- }
-
private void validateOccupantZoneIdIsUnique(int occupantZoneId) {
if (mZoneIdToOccupantZoneIdMapping.indexOfValue(occupantZoneId) > -1) {
throw new IllegalArgumentException(ATTR_OCCUPANT_ZONE_ID + " " + occupantZoneId
diff --git a/service/src/com/android/car/hal/UserHalService.java b/service/src/com/android/car/hal/UserHalService.java
index e76df37..645f563 100644
--- a/service/src/com/android/car/hal/UserHalService.java
+++ b/service/src/com/android/car/hal/UserHalService.java
@@ -17,6 +17,7 @@
import static android.car.VehiclePropertyIds.CREATE_USER;
import static android.car.VehiclePropertyIds.INITIAL_USER_INFO;
+import static android.car.VehiclePropertyIds.REMOVE_USER;
import static android.car.VehiclePropertyIds.SWITCH_USER;
import static android.car.VehiclePropertyIds.USER_IDENTIFICATION_ASSOCIATION;
@@ -34,6 +35,7 @@
import android.hardware.automotive.vehicle.V2_0.CreateUserResponse;
import android.hardware.automotive.vehicle.V2_0.CreateUserStatus;
import android.hardware.automotive.vehicle.V2_0.InitialUserInfoResponse;
+import android.hardware.automotive.vehicle.V2_0.RemoveUserRequest;
import android.hardware.automotive.vehicle.V2_0.SwitchUserMessageType;
import android.hardware.automotive.vehicle.V2_0.SwitchUserRequest;
import android.hardware.automotive.vehicle.V2_0.SwitchUserResponse;
@@ -166,6 +168,9 @@
mHandler.sendMessage(obtainMessage(
UserHalService::handleOnCreateUserResponse, this, value));
break;
+ case REMOVE_USER:
+ Log.w(TAG, "Received REMOVE_USER HAL event: " + value);
+ break;
case USER_IDENTIFICATION_ASSOCIATION:
mHandler.sendMessage(obtainMessage(
UserHalService::handleOnUserIdentificationAssociation, this, value));
@@ -302,6 +307,34 @@
}
/**
+ * Calls HAL to remove user.
+ *
+ * @throws IllegalStateException if the HAL does not support user management (callers should
+ * call {@link #isSupported()} first to avoid this exception).
+ */
+ public void removeUser(@NonNull RemoveUserRequest request) {
+ Objects.requireNonNull(request, "request cannot be null");
+
+ if (DBG) Log.d(TAG, "removeUser(" + request.removedUserInfo.userId + ")");
+ EventLog.writeEvent(EventLogTags.CAR_USER_HAL_REMOVE_USER_REQ,
+ request.removedUserInfo.userId, request.usersInfo.currentUser.userId);
+
+ VehiclePropValue propRequest;
+ synchronized (mLock) {
+ checkSupportedLocked();
+ request.requestId = getNextRequestId();
+ propRequest = UserHalHelper.toVehiclePropValue(request);
+
+ }
+ try {
+ if (DBG) Log.d(TAG, "Calling hal.set(): " + propRequest);
+ mHal.set(propRequest);
+ } catch (ServiceSpecificException e) {
+ Log.w(TAG, "Failed to set REMOVE USER", e);
+ }
+ }
+
+ /**
* Calls HAL to indicate an Android user was created.
*
* @param request info agout the created user.
diff --git a/service/src/com/android/car/user/CarUserService.java b/service/src/com/android/car/user/CarUserService.java
index 81d1b6c..8e08b28 100644
--- a/service/src/com/android/car/user/CarUserService.java
+++ b/service/src/com/android/car/user/CarUserService.java
@@ -35,6 +35,7 @@
import android.car.user.CarUserManager.UserLifecycleListener;
import android.car.user.UserCreationResult;
import android.car.user.UserIdentificationAssociationResponse;
+import android.car.user.UserRemovalResult;
import android.car.user.UserSwitchResult;
import android.car.userlib.CarUserManagerHelper;
import android.car.userlib.CommonConstants.CarUserServiceConstants;
@@ -53,6 +54,7 @@
import android.hardware.automotive.vehicle.V2_0.CreateUserStatus;
import android.hardware.automotive.vehicle.V2_0.InitialUserInfoResponse;
import android.hardware.automotive.vehicle.V2_0.InitialUserInfoResponseAction;
+import android.hardware.automotive.vehicle.V2_0.RemoveUserRequest;
import android.hardware.automotive.vehicle.V2_0.SwitchUserRequest;
import android.hardware.automotive.vehicle.V2_0.SwitchUserStatus;
import android.hardware.automotive.vehicle.V2_0.UserIdentificationGetRequest;
@@ -343,7 +345,7 @@
private void handleDumpListeners(@NonNull PrintWriter writer, String indent) {
CountDownLatch latch = new CountDownLatch(1);
mHandler.post(() -> {
- handleDumpUserLifecycleListeners(writer);
+ handleDumpServiceLifecycleListeners(writer);
handleDumpAppLifecycleListeners(writer, indent);
latch.countDown();
});
@@ -359,57 +361,69 @@
}
}
- private void handleDumpUserLifecycleListeners(@NonNull PrintWriter writer) {
+ private void handleDumpServiceLifecycleListeners(@NonNull PrintWriter writer) {
if (mUserLifecycleListeners.isEmpty()) {
- writer.println("No user lifecycle listeners");
+ writer.println("No lifecycle listeners for internal services");
return;
}
- writer.printf("%d user lifecycle listeners\n", mUserLifecycleListeners.size());
+ int size = mUserLifecycleListeners.size();
+ writer.printf("%d lifecycle listener%s for services\n", size, size == 1 ? "" : "s");
+ String indent = " ";
for (UserLifecycleListener listener : mUserLifecycleListeners) {
- writer.printf("Listener %s\n", listener);
+ writer.printf("%s%s\n", indent, FunctionalUtils.getLambdaName(listener));
}
}
private void handleDumpAppLifecycleListeners(@NonNull PrintWriter writer, String indent) {
- int numberListeners = mAppLifecycleListeners.size();
- if (numberListeners == 0) {
- writer.println("No lifecycle listeners");
+ int size = mAppLifecycleListeners.size();
+ if (size == 0) {
+ writer.println("No lifecycle listeners for apps");
return;
}
- writer.printf("%d lifecycle listeners\n", numberListeners);
- for (int i = 0; i < numberListeners; i++) {
+ writer.printf("%d lifecycle listener%s for apps \n", size, size == 1 ? "" : "s");
+ for (int i = 0; i < size; i++) {
int uid = mAppLifecycleListeners.keyAt(i);
IResultReceiver listener = mAppLifecycleListeners.valueAt(i);
- writer.printf("%suid: %d Listener %s\n", indent, uid, listener);
+ writer.printf("%suid: %d\n", indent, uid);
}
}
/**
- * Creates a driver who is a regular user and is allowed to login to the driving occupant zone.
- *
- * @param name The name of the driver to be created.
- * @param admin Whether the created driver will be an admin.
- * @return {@link UserInfo} object of the created driver, or {@code null} if the driver could
- * not be created.
+ * @see ExperimentalCarUserManager.createDriver
*/
@Override
- @Nullable
- public UserInfo createDriver(@NonNull String name, boolean admin) {
+ public AndroidFuture<UserCreationResult> createDriver(@NonNull String name, boolean admin) {
checkManageUsersPermission("createDriver");
Objects.requireNonNull(name, "name cannot be null");
+
+ AndroidFuture<UserCreationResult> future = new AndroidFuture<UserCreationResult>() {
+ @Override
+ protected void onCompleted(UserCreationResult result, Throwable err) {
+ if (result == null) {
+ Log.w(TAG, "createDriver(" + name + "," + admin + ") failed: " + err);
+ } else {
+ if (result.getStatus() == UserCreationResult.STATUS_SUCCESSFUL) {
+ assignDefaultIcon(result.getUser());
+ }
+ }
+ super.onCompleted(result, err);
+ };
+ };
+ int flags = 0;
if (admin) {
- return createNewAdminUser(name);
+ if (!(mUserManager.isAdminUser() || mUserManager.isSystemUser())) {
+ Log.e(TAG_USER, "Only admin users and system user can create other admins.");
+ sendUserCreationResultFailure(future, UserCreationResult.STATUS_INVALID_REQUEST);
+ return future;
+ }
+ flags = UserInfo.FLAG_ADMIN;
}
- return mCarUserManagerHelper.createNewNonAdminUser(name);
+ createUser(name, UserInfo.getDefaultUserType(flags), flags, mHalTimeoutMs, future);
+ return future;
}
/**
- * Creates a passenger who is a profile of the given driver.
- *
- * @param name The name of the passenger to be created.
- * @param driverId User id of the driver under whom a passenger is created.
- * @return {@link UserInfo} object of the created passenger, or {@code null} if the passenger
- * could not be created.
+ * @see ExperimentalCarUserManager.createPassenger
*/
@Override
@Nullable
@@ -425,6 +439,7 @@
Log.w(TAG_USER, "a guest driver cannot create a passenger");
return null;
}
+ // createPassenger doesn't use user HAL because user HAL doesn't support profile user yet.
UserInfo user = mUserManager.createProfileForUser(name,
UserManager.USER_TYPE_PROFILE_MANAGED, /* flags */ 0, driverId);
if (user == null) {
@@ -439,7 +454,7 @@
}
/**
- * @see CarUserManager.switchDriver
+ * @see ExperimentalCarUserManager.switchDriver
*/
@Override
public void switchDriver(@UserIdInt int driverId, AndroidFuture<UserSwitchResult> receiver) {
@@ -879,6 +894,62 @@
});
}
+ @Override
+ public UserRemovalResult removeUser(@UserIdInt int userId) {
+ checkManageUsersPermission("removeUser");
+ EventLog.writeEvent(EventLogTags.CAR_USER_SVC_REMOVE_USER_REQ, userId);
+ // If the requested user is the current user, return error.
+ if (ActivityManager.getCurrentUser() == userId) {
+ return logAndGetResults(userId,
+ UserRemovalResult.STATUS_TARGET_USER_IS_CURRENT_USER);
+ }
+
+ // If requested user is the only admin user, return error.
+ UserInfo userInfo = mUserManager.getUserInfo(userId);
+ if (userInfo == null) {
+ return logAndGetResults(userId, UserRemovalResult.STATUS_USER_DOES_NOT_EXIST);
+ }
+
+ android.hardware.automotive.vehicle.V2_0.UserInfo halUser =
+ new android.hardware.automotive.vehicle.V2_0.UserInfo();
+ halUser.userId = userInfo.id;
+ halUser.flags = UserHalHelper.convertFlags(userInfo);
+ UsersInfo usersInfo = UserHalHelper.newUsersInfo(mUserManager);
+
+ // Do not delete last admin user.
+ if (UserHalHelper.isAdmin(halUser.flags)) {
+ int size = usersInfo.existingUsers.size();
+ int totalAdminUsers = 0;
+ for (int i = 0; i < size; i++) {
+ if (UserHalHelper.isAdmin(usersInfo.existingUsers.get(i).flags)) {
+ totalAdminUsers++;
+ }
+ }
+ if (totalAdminUsers == 1) {
+ return logAndGetResults(userId,
+ UserRemovalResult.STATUS_TARGET_USER_IS_LAST_ADMIN_USER);
+ }
+ }
+
+ // First remove user from android and then remove from HAL because HAL remove user is one
+ // way call.
+ if (!mUserManager.removeUser(userId)) {
+ return logAndGetResults(userId, UserRemovalResult.STATUS_ANDROID_FAILURE);
+ }
+
+ RemoveUserRequest request = new RemoveUserRequest();
+ request.removedUserInfo = halUser;
+ request.usersInfo = usersInfo;
+ mHal.removeUser(request);
+ return logAndGetResults(userId, UserRemovalResult.STATUS_SUCCESSFUL);
+ }
+
+ private UserRemovalResult logAndGetResults(@UserIdInt int userId,
+ @UserRemovalResult.Status int result) {
+ EventLog.writeEvent(EventLogTags.CAR_USER_SVC_REMOVE_USER_RESP, userId, result);
+ return new UserRemovalResult(result);
+ }
+
private void sendUserSwitchUiCallback(@UserIdInt int targetUserId) {
if (mUserSwitchUiReceiver == null) {
Log.w(TAG_USER, "No User switch UI receiver.");
@@ -1492,23 +1563,27 @@
}
int userId = event.getUserId();
TimingsTraceLog t = new TimingsTraceLog(TAG_USER, Trace.TRACE_TAG_SYSTEM_SERVER);
- t.traceBegin("notify-app-listeners-user-" + userId + "-event-" + event.getEventType());
+ int eventType = event.getEventType();
+ t.traceBegin("notify-app-listeners-user-" + userId + "-event-" + eventType);
for (int i = 0; i < listenersSize; i++) {
int uid = mAppLifecycleListeners.keyAt(i);
+
IResultReceiver listener = mAppLifecycleListeners.valueAt(i);
Bundle data = new Bundle();
- data.putInt(CarUserManager.BUNDLE_PARAM_ACTION, event.getEventType());
+ data.putInt(CarUserManager.BUNDLE_PARAM_ACTION, eventType);
- int fromUid = event.getPreviousUserId();
- if (fromUid != UserHandle.USER_NULL) {
- data.putInt(CarUserManager.BUNDLE_PARAM_PREVIOUS_USER_ID, fromUid);
+ int fromUserId = event.getPreviousUserId();
+ if (fromUserId != UserHandle.USER_NULL) {
+ data.putInt(CarUserManager.BUNDLE_PARAM_PREVIOUS_USER_ID, fromUserId);
}
if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
Log.d(TAG_USER, "Notifying listener for uid " + uid);
}
+ EventLog.writeEvent(EventLogTags.CAR_USER_SVC_NOTIFY_APP_LIFECYCLE_LISTENER,
+ uid, eventType, fromUserId, userId);
try {
- t.traceBegin("notify-app-listener-" + uid);
+ t.traceBegin("notify-app-listener-uid-" + uid);
listener.send(userId, data);
} catch (RemoteException e) {
Log.e(TAG_USER, "Error calling lifecycle listener", e);
@@ -1529,10 +1604,13 @@
+ event);
}
- t.traceBegin("notify-listeners-user-" + event.getUserId() + "-event-"
- + event.getEventType());
+ int userId = event.getUserId();
+ int eventType = event.getEventType();
+ t.traceBegin("notify-listeners-user-" + userId + "-event-" + eventType);
for (UserLifecycleListener listener : mUserLifecycleListeners) {
String listenerName = FunctionalUtils.getLambdaName(listener);
+ EventLog.writeEvent(EventLogTags.CAR_USER_SVC_NOTIFY_INTERNAL_LIFECYCLE_LISTENER,
+ listenerName, eventType, event.getPreviousUserId(), userId);
try {
t.traceBegin("notify-listener-" + listenerName);
listener.onEvent(event);
@@ -1568,11 +1646,17 @@
private void notifyHalLegacySwitch(@UserIdInt int fromUserId, @UserIdInt int toUserId) {
synchronized (mLockUser) {
- if (mUserIdForUserSwitchInProcess != UserHandle.USER_NULL) return;
+ if (mUserIdForUserSwitchInProcess != UserHandle.USER_NULL) {
+ if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
+ Log.d(TAG, "notifyHalLegacySwitch(" + fromUserId + ", " + toUserId
+ + "): not needed, normal switch for " + mUserIdForUserSwitchInProcess);
+ }
+ return;
+ }
}
// switch HAL user
- UsersInfo usersInfo = UserHalHelper.newUsersInfo(mUserManager);
+ UsersInfo usersInfo = UserHalHelper.newUsersInfo(mUserManager, fromUserId);
SwitchUserRequest request = createUserSwitchRequest(toUserId, usersInfo);
mHal.legacyUserSwitch(request);
}
@@ -1617,42 +1701,15 @@
}
/**
- * Creates a new user on the system, the created user would be granted admin role.
- *
- * @param name Name to be given to the newly created user.
- * @return newly created admin user, {@code null} if it fails to create a user.
- */
- @Nullable
- private UserInfo createNewAdminUser(String name) {
- if (!(mUserManager.isAdminUser() || mUserManager.isSystemUser())) {
- // Only admins or system user can create other privileged users.
- Log.e(TAG_USER, "Only admin users and system user can create other admins.");
- return null;
- }
-
- UserInfo user = mUserManager.createUser(name, UserInfo.FLAG_ADMIN);
- if (user == null) {
- // Couldn't create user, most likely because there are too many.
- Log.w(TAG_USER, "can't create admin user.");
- return null;
- }
- assignDefaultIcon(user);
-
- return user;
- }
-
- /**
* Assigns a default icon to a user according to the user's id.
*
* @param userInfo User whose avatar is set to default icon.
- * @return Bitmap of the user icon.
*/
- private Bitmap assignDefaultIcon(UserInfo userInfo) {
+ private void assignDefaultIcon(UserInfo userInfo) {
int idForIcon = userInfo.isGuest() ? UserHandle.USER_NULL : userInfo.id;
Bitmap bitmap = UserIcons.convertToBitmap(
UserIcons.getDefaultUserIcon(mContext.getResources(), idForIcon, false));
mUserManager.setUserIcon(userInfo.id, bitmap);
- return bitmap;
}
private interface UserFilter {
diff --git a/surround_view/service-impl/Android.bp b/surround_view/service-impl/Android.bp
index b89f7ed..80c77a3 100644
--- a/surround_view/service-impl/Android.bp
+++ b/surround_view/service-impl/Android.bp
@@ -14,6 +14,35 @@
// limitations under the License.
//
+cc_library {
+ name : "libobj_reader",
+ vendor : true,
+ srcs: [
+ "MtlReader.cpp",
+ "ObjReader.cpp",
+ ],
+ shared_libs : [
+ "libbase",
+ ]
+}
+
+cc_test{
+ name : "obj_reader_tests",
+ test_suites : ["device-tests"],
+ vendor : true,
+ srcs : ["ObjReaderTests.cpp"],
+ shared_libs : [
+ "libobj_reader",
+ "libcutils",
+ "libbase",
+ "libutils",
+ ],
+ required: [
+ "VolvoXC40_low.obj",
+ "VolvoXC40_low.mtl",
+ ],
+}
+
cc_library{
name : "libvhal_handler",
vendor : true,
@@ -148,3 +177,15 @@
name:
"cam3.png", src : "test_data/3.png", sub_dir : "automotive/sv",
}
+
+prebuilt_etc {
+ name: "cube.obj",
+ src: "test_data/cube.obj",
+ sub_dir: "automotive/sv",
+}
+
+prebuilt_etc {
+ name: "cube.mtl",
+ src: "test_data/cube.mtl",
+ sub_dir: "automotive/sv",
+}
diff --git a/surround_view/service-impl/MtlReader.cpp b/surround_view/service-impl/MtlReader.cpp
new file mode 100644
index 0000000..d86a15a
--- /dev/null
+++ b/surround_view/service-impl/MtlReader.cpp
@@ -0,0 +1,167 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include "MtlReader.h"
+
+#include <android-base/logging.h>
+#include <cstdio>
+
+#define LOG_TAG "MtlReader"
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace sv {
+namespace V1_0 {
+namespace implementation {
+
+namespace {
+
+constexpr int kCharBufferSize = 128;
+
+void ReadFloat3(FILE* file, float* value) {
+ float temp[3];
+ int res = fscanf(file, "%f %f %f", &temp[0], &temp[1], &temp[2]);
+ 3 == res ? std::memcpy(value, temp, 3 * sizeof(float)) : nullptr;
+}
+
+void ReadFloat(FILE* file, float* value) {
+ float temp;
+ int res = fscanf(file, "%f", &temp);
+ *value = res > 0 ? temp : -1;
+}
+
+void ReadInt(FILE* file, int* value) {
+ int temp;
+ int res = fscanf(file, "%d", &temp);
+ *value = res > 0 ? temp : -1;
+}
+
+void ReadString(FILE* file, std::string* value) {
+ char temp[kCharBufferSize];
+ fscanf(file, "%s", temp);
+ *value = temp;
+}
+} // namespace
+
+bool ReadMtlFromFile(const std::string& mtlFilename,
+ std::map<std::string, MtlConfigParams>* params) {
+ FILE* file = fopen(mtlFilename.c_str(), "r");
+ if (!file) {
+ LOG(ERROR) << "Failed to open mtl file: " << mtlFilename;
+ return false;
+ }
+
+ std::string currentConfig;
+ while (true) {
+ char lineHeader[kCharBufferSize];
+ // read the first word of the line
+ int res = fscanf(file, "%s", lineHeader);
+
+ if (res == EOF) {
+ break; // EOF = End Of File. Quit the loop.
+ }
+
+ if (strcmp(lineHeader, "#") == 0) {
+ fgets(lineHeader, sizeof(lineHeader), file);
+ continue;
+ }
+ if (strcmp(lineHeader, "newmtl") == 0) {
+ res = fscanf(file, "%s", lineHeader);
+ if (params->find(lineHeader) != params->end()) {
+ fclose(file);
+ LOG(ERROR) << "Duplicated params of : " << lineHeader[0];
+ return false;
+ }
+ currentConfig = lineHeader;
+ continue;
+ }
+
+ if (strcmp(lineHeader, "Ns") == 0) {
+ ReadFloat(file, &((*params)[currentConfig].ns));
+ continue;
+ }
+ if (strcmp(lineHeader, "Ni") == 0) {
+ ReadFloat(file, &((*params)[currentConfig].ni));
+ continue;
+ }
+ if (strcmp(lineHeader, "d") == 0) {
+ ReadFloat(file, &((*params)[currentConfig].d));
+ continue;
+ }
+ if (strcmp(lineHeader, "Tr") == 0) {
+ ReadFloat(file, &((*params)[currentConfig].tr));
+ continue;
+ }
+ if (strcmp(lineHeader, "Tf") == 0) {
+ ReadFloat3(file, (*params)[currentConfig].tf);
+ continue;
+ }
+ if (strcmp(lineHeader, "illum") == 0) {
+ ReadInt(file, &((*params)[currentConfig].illum));
+ continue;
+ }
+ if (strcmp(lineHeader, "Ka") == 0) {
+ ReadFloat3(file, (*params)[currentConfig].ka);
+ continue;
+ }
+ if (strcmp(lineHeader, "Kd") == 0) {
+ ReadFloat3(file, (*params)[currentConfig].kd);
+ continue;
+ }
+ if (strcmp(lineHeader, "Ks") == 0) {
+ ReadFloat3(file, (*params)[currentConfig].ks);
+ continue;
+ }
+ if (strcmp(lineHeader, "Ke") == 0) {
+ ReadFloat3(file, (*params)[currentConfig].ke);
+ continue;
+ }
+ if (strcmp(lineHeader, "map_bump") == 0) {
+ ReadString(file, &((*params)[currentConfig].mapBump));
+ continue;
+ }
+ if (strcmp(lineHeader, "bump") == 0) {
+ ReadString(file, &((*params)[currentConfig].bump));
+ continue;
+ }
+ if (strcmp(lineHeader, "map_Ka") == 0) {
+ ReadString(file, &((*params)[currentConfig].mapKa));
+ continue;
+ }
+ if (strcmp(lineHeader, "map_Kd") == 0) {
+ ReadString(file, &((*params)[currentConfig].mapKd));
+ continue;
+ }
+ if (strcmp(lineHeader, "map_Ks") == 0) {
+ ReadString(file, &((*params)[currentConfig].mapKs));
+ continue;
+ } else {
+ LOG(WARNING) << "Unknown tag " << lineHeader << ". Skipped";
+ fgets(lineHeader, sizeof(lineHeader), file);
+ continue;
+ }
+ }
+
+ fclose(file);
+ return true;
+}
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace sv
+} // namespace automotive
+} // namespace hardware
+} // namespace android
diff --git a/surround_view/service-impl/MtlReader.h b/surround_view/service-impl/MtlReader.h
new file mode 100644
index 0000000..3e19876
--- /dev/null
+++ b/surround_view/service-impl/MtlReader.h
@@ -0,0 +1,180 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SURROUND_VIEW_SERVICE_IMPL_MTLREADER_H_
+#define SURROUND_VIEW_SERVICE_IMPL_MTLREADER_H_
+
+#include <map>
+#include <string>
+
+#include "core_lib.h"
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace sv {
+namespace V1_0 {
+namespace implementation {
+
+// Mtl defined params.
+struct MtlConfigParams {
+ // Ns exponent
+ // Specifies the specular exponent for the current material. This defines
+ // the focus of the specular highlight.
+ // Ns values normally range from 0 to 1000.
+ float ns = -1;
+
+ // optical_density
+ // Specifies the optical density for the surface. This is also known as
+ // index of refraction.
+ // "optical_density" is the value for the optical density. The values can
+ // range from 0.001 to 10. A value of 1.0 means that light does not bend
+ // as it passes through an object. Increasing the optical_density
+ // increases the amount of bending. Glass has an index of refraction of
+ // about 1.5. Values of less than 1.0 produce bizarre results and are not
+ // recommended.
+ float ni = -1;
+
+ // d defines the non-transparency of the material to be alpha.
+ // The default is 1.0 (not transparent at all).
+ // The quantities d and Tr are the opposites of each other.
+ float d = -1;
+
+ // The Tr statement specifies the transparency of the material to be alpha.
+ // The default is 0.0 (not transparent at all).
+ // The quantities d and Tr are the opposites of each other,
+ float tr = -1;
+
+ // The Tf statement specifies the transmission filter using RGB values.
+ // "r g b" are the values for the red, green, and blue components of the
+ // atmosphere. The g and b arguments are optional. If only r is
+ // specified, then g, and b are assumed to be equal to r. The r g b values
+ // are normally in the range of 0.0 to 1.0. Values outside this range
+ // increase or decrease the relectivity accordingly.
+ float tf[3] = {-1, -1, -1};
+
+ // illum_#
+ // The "illum" statement specifies the illumination model to use in the
+ // material. Illumination models are mathematical equations that represent
+ // various material lighting and shading effects.
+ //
+ // "illum_#"can be a number from 0 to 10. The illumination models are
+ // summarized below;
+ //
+ // Illumination Properties that are turned on in the
+ // model Property Editor
+ //
+ // 0 Color on and Ambient off
+ // 1 Color on and Ambient on
+ // 2 Highlight on
+ // 3 Reflection on and Ray trace on
+ // 4 Transparency: Glass on
+ // Reflection: Ray trace on
+ // 5 Reflection: Fresnel on and Ray trace on
+ // 6 Transparency: Refraction on
+ // Reflection: Fresnel off and Ray trace on
+ // 7 Transparency: Refraction on
+ // Reflection: Fresnel on and Ray trace on
+ // 8 Reflection on and Ray trace off
+ // 9 Transparency: Glass on
+ // Reflection: Ray trace off
+ // 10 Casts shadows onto invisible surfaces
+ int illum = -1;
+
+ // The Ka statement specifies the ambient reflectivity using RGB values.
+ // "r g b" are the values for the red, green, and blue components of the
+ // color. The g and b arguments are optional. If only r is specified,
+ // then g, and b are assumed to be equal to r. The r g b values are
+ // normally in the range of 0.0 to 1.0. Values outside this range increase
+ // or decrease the relectivity accordingly.
+ float ka[3] = {-1, -1, -1};
+
+ // The Kd statement specifies the diffuse reflectivity using RGB values.
+ // "r g b" are the values for the red, green, and blue components of the
+ // atmosphere. The g and b arguments are optional. If only r is
+ // specified, then g, and b are assumed to be equal to r. The r g b values
+ // are normally in the range of 0.0 to 1.0. Values outside this range
+ // increase or decrease the relectivity accordingly.
+ float kd[3] = {-1, -1, -1};
+
+ // The Ks statement specifies the specular reflectivity using RGB values.
+ // "r g b" are the values for the red, green, and blue components of the
+ // atmosphere. The g and b arguments are optional. If only r is
+ // specified, then g, and b are assumed to be equal to r. The r g b values
+ // are normally in the range of 0.0 to 1.0. Values outside this range
+ // increase or decrease the relectivity accordingly.
+ float ks[3] = {-1, -1, -1};
+
+ // Emissive coeficient. It goes together with ambient, diffuse and specular
+ // and represents the amount of light emitted by the material.
+ float ke[3] = {-1, -1, -1};
+
+ // Specifies that a color texture file or color procedural texture file is
+ // linked to the specular reflectivity of the material. During rendering,
+ // the map_Ks value is multiplied by the Ks value.
+ std::string mapKs;
+
+ // Specifies that a color texture file or a color procedural texture file
+ // is applied to the ambient reflectivity of the material. During
+ // rendering, the "map_Ka" value is multiplied by the "Ka" value.
+ std::string mapKa;
+
+ // Specifies that a color texture file or color procedural texture file is
+ // linked to the diffuse reflectivity of the material. During rendering,
+ // the map_Kd value is multiplied by the Kd value.
+ std::string mapKd;
+
+ // Same as bump
+ std::string mapBump;
+
+ // Specifies that a bump texture file or a bump procedural texture file is
+ // linked to the material.
+ std::string bump;
+
+ MtlConfigParams& operator=(const MtlConfigParams& rhs) {
+ ns = rhs.ns;
+ ni = rhs.ni;
+ d = rhs.d;
+ tr = rhs.tr;
+ std::memcpy(tf, rhs.tf, 3 * sizeof(float));
+ illum = rhs.illum;
+ std::memcpy(ka, rhs.ka, 3 * sizeof(float));
+ std::memcpy(kd, rhs.kd, 3 * sizeof(float));
+ std::memcpy(ks, rhs.ks, 3 * sizeof(float));
+ std::memcpy(ke, rhs.ke, 3 * sizeof(float));
+ mapKs = rhs.mapKs;
+ mapKa = rhs.mapKa;
+ mapKd = rhs.mapKd;
+ mapBump = rhs.mapBump;
+ bump = rhs.bump;
+
+ return *this;
+ }
+};
+
+// Reads mtl file associated with obj file.
+// |filename| is the full path and name of the obj file.
+bool ReadMtlFromFile(const std::string& mtlFilename,
+ std::map<std::string, MtlConfigParams>* params);
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace sv
+} // namespace automotive
+} // namespace hardware
+} // namespace android
+
+#endif // SURROUND_VIEW_SERVICE_IMPL_MTLREADER_H_
diff --git a/surround_view/service-impl/ObjReader.cpp b/surround_view/service-impl/ObjReader.cpp
new file mode 100644
index 0000000..174ef5b
--- /dev/null
+++ b/surround_view/service-impl/ObjReader.cpp
@@ -0,0 +1,304 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include "ObjReader.h"
+
+#include <array>
+#include <cstdio>
+#include <filesystem>
+#include <vector>
+
+#include "MtlReader.h"
+#include "core_lib.h"
+
+#include <android-base/logging.h>
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace sv {
+namespace V1_0 {
+namespace implementation {
+
+using android_auto::surround_view::CarMaterial;
+using android_auto::surround_view::CarVertex;
+
+namespace {
+
+constexpr int kNumberOfVerticesPerFace = 3;
+constexpr int kNumberOfAxes = 3;
+constexpr int kCharBufferSize = 128;
+
+const std::array<float, 16> kMat4Identity = {
+ /*row 0*/ 1, 0, 0, 0,
+ /*row 1*/ 0, 1, 0, 0,
+ /*row 2*/ 0, 0, 1, 0,
+ /*row 3*/ 0, 0, 0, 1};
+
+// Copies face vertices parsed from obj to car vertices.
+void CopyFaceToCarVertex(const std::vector<std::array<float, kNumberOfAxes>>& currentVertices,
+ const std::vector<std::array<float, kNumberOfAxes>>& currentTextures,
+ const std::vector<std::array<float, kNumberOfAxes>>& currentNormals,
+ int vertexId, int textureId, int normalId, CarVertex* carVertex) {
+ std::memcpy(carVertex->pos.data(), currentVertices[vertexId - 1].data(),
+ currentVertices[vertexId - 1].size() * sizeof(float));
+
+ if (textureId != -1) {
+ std::memcpy(carVertex->tex_coord.data(), currentTextures[textureId - 1].data(),
+ 2 * sizeof(float));
+ // Set texture coodinates as invalid.
+ carVertex->tex_coord = {-1.0, -1.0};
+ }
+
+ std::memcpy(carVertex->normal.data(), currentNormals[normalId - 1].data(),
+ currentNormals[normalId - 1].size() * sizeof(float));
+}
+
+} // namespace
+
+bool ReadObjFromFile(const std::string& objFilename, std::map<std::string, CarPart>* carPartsMap) {
+ return ReadObjFromFile(objFilename, ReadObjOptions(), carPartsMap);
+}
+
+bool ReadObjFromFile(const std::string& objFilename, const ReadObjOptions& option,
+ std::map<std::string, CarPart>* carPartsMap) {
+ FILE* file = fopen(objFilename.c_str(), "r");
+ if (!file) {
+ LOG(ERROR) << "Failed to open obj file: " << objFilename;
+ return false;
+ }
+
+ for (int i = 0; i < kNumberOfAxes; ++i) {
+ if (option.coordinateMapping[i] >= kNumberOfAxes || option.coordinateMapping[i] < 0) {
+ fclose(file);
+ LOG(ERROR) << "coordinateMapping index must be less than 3 and greater or equal "
+ "to 0.";
+ return false;
+ }
+ }
+
+ std::vector<std::array<float, kNumberOfAxes>> currentVertices;
+ std::vector<std::array<float, kNumberOfAxes>> currentNormals;
+ std::vector<std::array<float, kNumberOfAxes>> currentTextures;
+ std::map<std::string, MtlConfigParams> mtlConfigParamsMap;
+ std::string currentGroupName;
+ MtlConfigParams currentMtlConfig;
+
+ while (true) {
+ char lineHeader[kCharBufferSize];
+ // read the first word of the line
+ int res = fscanf(file, "%s", lineHeader);
+
+ if (res == EOF) {
+ break; // EOF = End Of File. Quit the loop.
+ }
+ if (strcmp(lineHeader, "#") == 0) {
+ fgets(lineHeader, sizeof(lineHeader), file);
+ continue;
+ }
+
+ // TODO(b/156558814): add object type support.
+ // TODO(b/156559272): add document for supported format.
+ // Only single group per line is supported.
+ if (strcmp(lineHeader, "g") == 0) {
+ res = fscanf(file, "%s", lineHeader);
+ currentGroupName = lineHeader;
+ currentMtlConfig = MtlConfigParams();
+
+ if (carPartsMap->find(currentGroupName) != carPartsMap->end()) {
+ LOG(WARNING) << "Duplicate group name: " << currentGroupName
+ << ". using car part name as: " << currentGroupName << "_dup";
+ currentGroupName.append("_dup");
+ }
+ carPartsMap->emplace(
+ std::make_pair(currentGroupName,
+ CarPart((std::vector<CarVertex>()), CarMaterial(), kMat4Identity,
+ std::string(), std::vector<std::string>())));
+ continue;
+ }
+
+ // no "g" case, assign it as default.
+ if (currentGroupName.empty()) {
+ currentGroupName = "default";
+ currentMtlConfig = MtlConfigParams();
+ carPartsMap->emplace(
+ std::make_pair(currentGroupName,
+ CarPart((std::vector<CarVertex>()), CarMaterial(), kMat4Identity,
+ std::string(), std::vector<std::string>())));
+ }
+
+ if (strcmp(lineHeader, "usemtl") == 0) {
+ res = fscanf(file, "%s", lineHeader);
+
+ // If material name not found.
+ if (mtlConfigParamsMap.find(lineHeader) == mtlConfigParamsMap.end()) {
+ carPartsMap->at(currentGroupName).material = CarMaterial();
+ LOG(ERROR) << "Material not found: $0" << lineHeader;
+ return false;
+ }
+
+ currentMtlConfig = mtlConfigParamsMap[lineHeader];
+
+ carPartsMap->at(currentGroupName).material.ka = {currentMtlConfig.ka[0],
+ currentMtlConfig.ka[1],
+ currentMtlConfig.ka[2]};
+
+ carPartsMap->at(currentGroupName).material.kd = {currentMtlConfig.kd[0],
+ currentMtlConfig.kd[1],
+ currentMtlConfig.kd[2]};
+
+ carPartsMap->at(currentGroupName).material.ks = {currentMtlConfig.ks[0],
+ currentMtlConfig.ks[1],
+ currentMtlConfig.ks[2]};
+
+ carPartsMap->at(currentGroupName).material.d = currentMtlConfig.d;
+
+ carPartsMap->at(currentGroupName).material.textures.clear();
+
+ continue;
+ }
+
+ if (strcmp(lineHeader, "mtllib") == 0) {
+ res = fscanf(file, "%s", lineHeader);
+ mtlConfigParamsMap.clear();
+ std::string mtlFilename;
+ if (option.mtlFilename.empty()) {
+ mtlFilename = objFilename.substr(0, objFilename.find_last_of("/"));
+ mtlFilename.append("/");
+ mtlFilename.append(lineHeader);
+ } else {
+ mtlFilename = option.mtlFilename;
+ }
+ if (!ReadMtlFromFile(mtlFilename, &mtlConfigParamsMap)) {
+ LOG(ERROR) << "Parse MTL file " << mtlFilename << " failed.";
+ return false;
+ }
+ continue;
+ }
+
+ if (strcmp(lineHeader, "v") == 0) {
+ std::array<float, kNumberOfAxes> pos;
+ fscanf(file, "%f %f %f\n", &pos[option.coordinateMapping[0]],
+ &pos[option.coordinateMapping[1]], &pos[option.coordinateMapping[2]]);
+ for (int i = 0; i < kNumberOfAxes; ++i) {
+ pos[i] *= option.scales[i];
+ pos[i] += option.offsets[i];
+ }
+ currentVertices.push_back(pos);
+ } else if (strcmp(lineHeader, "vt") == 0) {
+ std::array<float, kNumberOfAxes> texture;
+ fscanf(file, "%f %f %f\n", &texture[0], &texture[1], &texture[2]);
+ currentTextures.push_back(texture);
+ } else if (strcmp(lineHeader, "vn") == 0) {
+ std::array<float, kNumberOfAxes> normal;
+ fscanf(file, "%f %f %f\n", &normal[option.coordinateMapping[0]],
+ &normal[option.coordinateMapping[1]], &normal[option.coordinateMapping[2]]);
+ currentNormals.push_back(normal);
+ } else if (strcmp(lineHeader, "f") == 0) {
+ int vertexId[kNumberOfVerticesPerFace];
+ int textureId[kNumberOfVerticesPerFace] = {-1, -1, -1};
+ int normalId[kNumberOfVerticesPerFace];
+
+ // Face vertices supported formats:
+ // With texture: pos/texture/normal
+ // Without texture: pos//normal
+
+ // Scan first vertex position.
+ int matches = fscanf(file, "%d/", &vertexId[0]);
+
+ if (matches != 1) {
+ LOG(WARNING) << "Face index error. Skipped.";
+ fgets(lineHeader, sizeof(lineHeader), file);
+ continue;
+ }
+
+ // Try scanning first two face 2 vertices with texture format present.
+ bool isTexturePresent = true;
+ matches = fscanf(file, "%d/%d %d/%d/%d", &textureId[0], &normalId[0], &vertexId[1],
+ &textureId[1], &normalId[1]);
+
+ // If 5 matches not found, try scanning first 2 face vertices without
+ // texture format.
+ if (matches != 5) {
+ matches = fscanf(file, "/%d %d//%d", &normalId[0], &vertexId[1], &normalId[1]);
+
+ // If 3 matches not found return with error.
+ if (matches != 3) {
+ LOG(WARNING) << "Face format not supported. Skipped.";
+ fgets(lineHeader, sizeof(lineHeader), file);
+ continue;
+ }
+
+ isTexturePresent = false;
+ }
+
+ // Copy first two face vertices to car vertices.
+ std::array<CarVertex, kNumberOfVerticesPerFace> carVertices;
+ CopyFaceToCarVertex(currentVertices, currentTextures, currentNormals, vertexId[0],
+ textureId[0], normalId[0], &carVertices[0]);
+ CopyFaceToCarVertex(currentVertices, currentTextures, currentNormals, vertexId[1],
+ textureId[1], normalId[1], &carVertices[1]);
+
+ // Add a triangle that the first two vertices make with every subsequent
+ // face vertex 3 and onwards. Note this assumes the face is a convex
+ // polygon.
+ do {
+ if (isTexturePresent) {
+ matches = fscanf(file, " %d/%d/%d", &vertexId[2], &textureId[2], &normalId[2]);
+ // Warn if un-expected number of matches.
+ if (matches != 3 && matches != 0) {
+ LOG(WARNING) << "Face matches, expected 3, read: " << matches;
+ break;
+ }
+ } else {
+ // Warn if un-expected number of matches.
+ matches = fscanf(file, " %d//%d", &vertexId[2], &normalId[2]);
+ if (matches != 2 && matches != 0) {
+ LOG(WARNING) << "Face matches, expected 2, read: " << matches;
+ break;
+ }
+ }
+
+ if (matches == 0) {
+ break;
+ }
+
+ CopyFaceToCarVertex(currentVertices, currentTextures, currentNormals, vertexId[2],
+ textureId[2], normalId[2], &carVertices[2]);
+
+ carPartsMap->at(currentGroupName).vertices.push_back(carVertices[0]);
+ carPartsMap->at(currentGroupName).vertices.push_back(carVertices[1]);
+ carPartsMap->at(currentGroupName).vertices.push_back(carVertices[2]);
+
+ carVertices[1] = carVertices[2];
+ } while (true);
+
+ } else {
+ // LOG(WARNING) << "Unknown tag " << lineHeader << ". Skipped";
+ fgets(lineHeader, sizeof(lineHeader), file);
+ continue;
+ }
+ }
+
+ fclose(file);
+ return true;
+}
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace sv
+} // namespace automotive
+} // namespace hardware
+} // namespace android
diff --git a/surround_view/service-impl/ObjReader.h b/surround_view/service-impl/ObjReader.h
new file mode 100644
index 0000000..c19be14
--- /dev/null
+++ b/surround_view/service-impl/ObjReader.h
@@ -0,0 +1,78 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SURROUND_VIEW_SERVICE_IMPL_OBJREADER_H_
+#define SURROUND_VIEW_SERVICE_IMPL_OBJREADER_H_
+
+#include <map>
+#include <string>
+
+#include "core_lib.h"
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace sv {
+namespace V1_0 {
+namespace implementation {
+
+using android_auto::surround_view::CarPart;
+
+// ReadObjOptions for processing obj's vertex coordinates.
+// Sequence of processing ReadObjOptions:
+// 1. coordinate_mapping
+// 2. scales
+// 3. offsets
+struct ReadObjOptions {
+ // Maps obj coordinates to the output overlay coordinate.
+ // 0 <-> x, 1 <-> y, 2 <-> z
+ // Default is {0, 1, 2}, without coordinate changes.
+ int coordinateMapping[3] = {0, 1, 2};
+
+ // scale of each coordinate (after offsets).
+ float scales[3] = {1.0f, 1.0f, 1.0f};
+
+ // offset of each coordinate (after mapping).
+ float offsets[3] = {0, 0, 0};
+
+ // Optional mtl filename. String name is obj file is used if this is empty.
+ std::string mtlFilename;
+};
+
+// Reads obj file to vector of OverlayVertex.
+// |obj_filename| is the full path and name of the obj file.
+// |car_parts_map| is a map containing all car parts.
+// Now it only supports two face formats:
+// 1. f x/x/x x/x/x x/x/x ...
+// 2. f x//x x//x x//x ...
+// b/
+bool ReadObjFromFile(const std::string& objFilename, std::map<std::string, CarPart>* carPartsMap);
+
+// Reads obj file to vector of OverlayVertex.
+// |obj_filename| is the full path and name of the obj file.
+// |option| provides optional changes on the coordinates.
+// |car_parts_map| is a map containing all car parts.
+bool ReadObjFromFile(const std::string& obFilename, const ReadObjOptions& option,
+ std::map<std::string, CarPart>* carPartsMap);
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace sv
+} // namespace automotive
+} // namespace hardware
+} // namespace android
+
+#endif // SURROUND_VIEW_SERVICE_IMPL_OBJREADER_H_
diff --git a/surround_view/service-impl/ObjReaderTests.cpp b/surround_view/service-impl/ObjReaderTests.cpp
new file mode 100644
index 0000000..9dae171
--- /dev/null
+++ b/surround_view/service-impl/ObjReaderTests.cpp
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "ObjReaderTests"
+
+#include "ObjReader.h"
+
+#include "MtlReader.h"
+#include "core_lib.h"
+
+#include <gtest/gtest.h>
+#include <map>
+#include <string>
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace sv {
+namespace V1_0 {
+namespace implementation {
+namespace {
+
+TEST(ObjParserTests, ReadCubeSuccess) {
+ std::map<std::string, CarPart> carPartsMap;
+ EXPECT_TRUE(ReadObjFromFile("/etc/automotive/sv/cube.obj", &carPartsMap));
+ EXPECT_NE(carPartsMap.size(), 0);
+}
+
+} // namespace
+} // namespace implementation
+} // namespace V1_0
+} // namespace sv
+} // namespace automotive
+} // namespace hardware
+} // namespace android
diff --git a/surround_view/service-impl/lib/arm64/libcore_lib_shared.so b/surround_view/service-impl/lib/arm64/libcore_lib_shared.so
index 2421d41..3988762 100755
--- a/surround_view/service-impl/lib/arm64/libcore_lib_shared.so
+++ b/surround_view/service-impl/lib/arm64/libcore_lib_shared.so
Binary files differ
diff --git a/surround_view/service-impl/lib/x86-64/libcore_lib_shared.so b/surround_view/service-impl/lib/x86-64/libcore_lib_shared.so
index 34d1f6a..e9f94db 100755
--- a/surround_view/service-impl/lib/x86-64/libcore_lib_shared.so
+++ b/surround_view/service-impl/lib/x86-64/libcore_lib_shared.so
Binary files differ
diff --git a/surround_view/service-impl/lib/x86/libcore_lib_shared.so b/surround_view/service-impl/lib/x86/libcore_lib_shared.so
index c6ba2b6..b82d025 100755
--- a/surround_view/service-impl/lib/x86/libcore_lib_shared.so
+++ b/surround_view/service-impl/lib/x86/libcore_lib_shared.so
Binary files differ
diff --git a/surround_view/service-impl/test_data/cube.mtl b/surround_view/service-impl/test_data/cube.mtl
new file mode 100644
index 0000000..2f4e865
--- /dev/null
+++ b/surround_view/service-impl/test_data/cube.mtl
@@ -0,0 +1,5 @@
+newmtl flatwhite
+d 1.0000
+illum 1
+Ka 0.5000 0.5000 0.5000
+Kd 1.0000 1.0000 1.0000
diff --git a/surround_view/service-impl/test_data/cube.obj b/surround_view/service-impl/test_data/cube.obj
new file mode 100644
index 0000000..60ae1b2
--- /dev/null
+++ b/surround_view/service-impl/test_data/cube.obj
@@ -0,0 +1,32 @@
+mtllib cube.mtl
+g cube
+
+v 0.0 0.0 0.0
+v 0.0 0.0 1.0
+v 0.0 1.0 0.0
+v 0.0 1.0 1.0
+v 1.0 0.0 0.0
+v 1.0 0.0 1.0
+v 1.0 1.0 0.0
+v 1.0 1.0 1.0
+
+vn 0.0 0.0 1.0
+vn 0.0 0.0 -1.0
+vn 0.0 1.0 0.0
+vn 0.0 -1.0 0.0
+vn 1.0 0.0 0.0
+vn -1.0 0.0 0.0
+usemtl flatwhite
+f 1//2 7//2 5//2
+f 1//2 3//2 7//2
+f 1//6 4//6 3//6
+f 1//6 2//6 4//6
+f 3//3 8//3 7//3
+f 3//3 4//3 8//3
+f 5//5 7//5 8//5
+f 5//5 8//5 6//5
+f 1//4 5//4 6//4
+f 1//4 6//4 2//4
+f 2//1 6//1 8//1
+f 2//1 8//1 4//1
+
diff --git a/tests/CarDeveloperOptions/res/values-b+sr+Latn/strings.xml b/tests/CarDeveloperOptions/res/values-b+sr+Latn/strings.xml
index 8861afb..4c69e86 100644
--- a/tests/CarDeveloperOptions/res/values-b+sr+Latn/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-b+sr+Latn/strings.xml
@@ -3190,7 +3190,7 @@
<string name="other_sound_settings" msgid="5250376066099818676">"Drugi zvukovi"</string>
<string name="dial_pad_tones_title" msgid="8877212139988655769">"Tonovi numeričke tastature"</string>
<string name="screen_locking_sounds_title" msgid="4407110895465866809">"Zvukovi zaključavanja ekrana"</string>
- <string name="charging_sounds_title" msgid="5070437987230894287">"Menjajući zvuci i vibracija"</string>
+ <string name="charging_sounds_title" msgid="5070437987230894287">"Zvukovi i vibracija punjenja"</string>
<string name="docking_sounds_title" msgid="2573137471605541366">"Zvukovi montiranja"</string>
<string name="touch_sounds_title" msgid="165237488496165652">"Zvukovi pri dodiru"</string>
<string name="vibrate_on_touch_title" msgid="6360155469279157684">"Vibracija pri dodiru"</string>
diff --git a/tests/CarDeveloperOptions/res/values-be/strings.xml b/tests/CarDeveloperOptions/res/values-be/strings.xml
index ec27b37..8c34666 100644
--- a/tests/CarDeveloperOptions/res/values-be/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-be/strings.xml
@@ -3394,10 +3394,10 @@
<string name="hide_silent_icons_title" msgid="1070905516921542662">"Хаваць значкі стану для апавяшчэнняў без гуку"</string>
<string name="hide_silent_icons_summary" msgid="2624346914488256888">"Хаваць значкі для апавяшчэнняў без гуку на панэлі стану"</string>
<string name="notification_badging_title" msgid="6311699476970264712">"Паказваць значкі апавяшчэнняў"</string>
- <string name="notification_bubbles_title" msgid="9196562435741861317">"Дыялогі"</string>
+ <string name="notification_bubbles_title" msgid="9196562435741861317">"Усплывальныя апавяшчэнні"</string>
<string name="notification_bubbles_summary" msgid="4624512775901949578">"Адусюль атрымлівайце хуткі доступ да змесціва праграмы з дапамогай зменлівых спалучэнняў клавіш"</string>
<string name="bubbles_feature_education" msgid="8979109826818881018">"Некаторыя апавяшчэнні і іншае змесціва могуць паказвацца на экране ў выглядзе дыялогаў. Каб адкрыць дыялог, націсніце на яго. Каб закрыць дыялог, перацягніце яго ўніз экрана."</string>
- <string name="bubbles_app_toggle_title" msgid="6401217027603326439">"Дыялогі"</string>
+ <string name="bubbles_app_toggle_title" msgid="6401217027603326439">"Усплывальныя апавяшчэнні"</string>
<string name="bubbles_app_toggle_summary" msgid="7707611139796553855">"Дазваляе праграме \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" паказваць некаторыя апавяшчэнні ў выглядзе дыялогаў"</string>
<string name="bubbles_feature_disabled_dialog_title" msgid="3375452386012079293">"Уключыце дыялогі"</string>
<string name="bubbles_feature_disabled_dialog_text" msgid="326945485806386477">"Каб уключыць дыялогі для гэтай праграмы, уключыце дыялогі для прылады. Гэта паўплывае на іншыя праграмы, у якіх вы раней уключалі дыялогі."</string>
diff --git a/tests/CarDeveloperOptions/res/values-bn/strings.xml b/tests/CarDeveloperOptions/res/values-bn/strings.xml
index 78b74e4..c86b976 100644
--- a/tests/CarDeveloperOptions/res/values-bn/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-bn/strings.xml
@@ -3041,7 +3041,7 @@
<string name="connected_devices_dashboard_no_driving_mode_summary" msgid="3524409078596318803">"ব্লুটুথ, এনএফসি"</string>
<string name="connected_devices_dashboard_no_driving_mode_no_nfc_summary" msgid="7881286613528299400">"ব্লুটুথ"</string>
<string name="app_and_notification_dashboard_title" msgid="8448096608058843730">"অ্যাপ ও বিজ্ঞপ্তি"</string>
- <string name="app_and_notification_dashboard_summary" msgid="4165181440955038145">"অ্যাসিস্ট্যান্ট, সাম্প্রতিক অ্যাপ, ডিফল্ট অ্যাপ"</string>
+ <string name="app_and_notification_dashboard_summary" msgid="4165181440955038145">"Assistant, সাম্প্রতিক অ্যাপ, ডিফল্ট অ্যাপ"</string>
<string name="notification_settings_work_profile" msgid="7190550347842400029">"কাজের প্রোফাইলে অ্যাপের জন্য বিজ্ঞপ্তি অ্যাক্সেস উপলভ্য নয়।"</string>
<string name="account_dashboard_title" msgid="4734300939532555885">"অ্যাকাউন্ট"</string>
<string name="account_dashboard_default_summary" msgid="6822549669771936206">"কোনও অ্যাকাউন্ট যোগ করা হয়নি"</string>
@@ -4325,7 +4325,7 @@
<string name="battery_suggestion_summary" msgid="2669070349482656490"></string>
<string name="gesture_prevent_ringing_screen_title" msgid="4173494225145223638">"রিং হওয়া বন্ধ করুন"</string>
<string name="gesture_prevent_ringing_title" msgid="8827963588425673557">"রিং হওয়া বন্ধ করতে পাওয়ার ও ভলিউম বাড়ানোর বোতাম একসাথে প্রেস করুন"</string>
- <string name="gesture_prevent_ringing_sound_title" msgid="8642330448721033641">"রিং হওয়া আটকানোর শর্টকাট"</string>
+ <string name="gesture_prevent_ringing_sound_title" msgid="8642330448721033641">"রিংয়ের আরওয়াজ আটকানোর শর্টকাট"</string>
<string name="prevent_ringing_option_vibrate" msgid="6456505293904544108">"ভাইব্রেশন হতে দিন"</string>
<string name="prevent_ringing_option_mute" msgid="53662688921253613">"মিউট করুন"</string>
<string name="prevent_ringing_option_none" msgid="1450985763137666231">"যেমন আছে থাক"</string>
diff --git a/tests/CarDeveloperOptions/res/values-bs/strings.xml b/tests/CarDeveloperOptions/res/values-bs/strings.xml
index ba804e6..0bee24c 100644
--- a/tests/CarDeveloperOptions/res/values-bs/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-bs/strings.xml
@@ -3190,9 +3190,9 @@
<string name="other_sound_settings" msgid="5250376066099818676">"Drugi zvukovi"</string>
<string name="dial_pad_tones_title" msgid="8877212139988655769">"Tonovi tastature telefona"</string>
<string name="screen_locking_sounds_title" msgid="4407110895465866809">"Zvukovi zaključavanja ekrana"</string>
- <string name="charging_sounds_title" msgid="5070437987230894287">"Zvukovi/vibracija pri punjenju"</string>
+ <string name="charging_sounds_title" msgid="5070437987230894287">"Zvukovi/vibracija prilikom punjenja"</string>
<string name="docking_sounds_title" msgid="2573137471605541366">"Zvukovi priključne stanice"</string>
- <string name="touch_sounds_title" msgid="165237488496165652">"Zvukovi pri dodiru"</string>
+ <string name="touch_sounds_title" msgid="165237488496165652">"Zvukovi dodira"</string>
<string name="vibrate_on_touch_title" msgid="6360155469279157684">"Vibracija pri dodiru"</string>
<string name="vibrate_on_touch_summary" msgid="5504424764028676043">"Haptičke povratne informacije za dodir, tastaturu i drugo"</string>
<string name="dock_audio_media_title" msgid="1859521680502040781">"Zvučnik priključne stanice reprodukuje zvuk"</string>
@@ -3470,8 +3470,8 @@
<string name="notification_content_block_summary" msgid="2743896875255591743">"Nikad ne prikazuj obavještenja u nijansi ili na perifernim uređajima"</string>
<string name="notification_badge_title" msgid="8989086619255666442">"Dozvoli tačku za obavještenja"</string>
<string name="notification_channel_badge_title" msgid="8228215248332054612">"Prikaži tačku za obavještenja"</string>
- <string name="app_notification_override_dnd_title" msgid="1757042206738172601">"Zamijeni način rada Ne ometaj"</string>
- <string name="app_notification_override_dnd_summary" msgid="3152957611171210980">"Dozvolite da se obavještenja nastave pojavljivati kada je uključen način rada Ne ometaj"</string>
+ <string name="app_notification_override_dnd_title" msgid="1757042206738172601">"Zanemari način rada Ne ometaj"</string>
+ <string name="app_notification_override_dnd_summary" msgid="3152957611171210980">"Dozvoli da se obavještenja nastave pojavljivati kada je uključen način rada Ne ometaj"</string>
<string name="app_notification_visibility_override_title" msgid="2349335170165637672">"Na zaključavanju ekrana"</string>
<string name="app_notification_row_banned" msgid="2079325338122151677">"Blokirano"</string>
<string name="app_notification_row_priority" msgid="432299064888787236">"Prioritetna"</string>
@@ -3553,7 +3553,7 @@
<string name="zen_mode_media" msgid="3701280649874724055">"Reproduciraj zvukove medija"</string>
<string name="zen_mode_media_list" msgid="509327580522287125">"mediji"</string>
<string name="zen_mode_system" msgid="597437265986355038">"Dozvoli zvukove dodira"</string>
- <string name="zen_mode_system_list" msgid="480192458506838077">"zvuci dodira"</string>
+ <string name="zen_mode_system_list" msgid="480192458506838077">"zvukovi dodira"</string>
<string name="zen_mode_reminders" msgid="7560664194610054038">"Dozvoli podsjetnike"</string>
<string name="zen_mode_reminders_list" msgid="7347061314032326677">"podsjetnici"</string>
<string name="zen_mode_events" msgid="5784076928339534984">"Dozvoli događaje"</string>
diff --git a/tests/CarDeveloperOptions/res/values-ca/strings.xml b/tests/CarDeveloperOptions/res/values-ca/strings.xml
index 60f9de3..29423a2 100644
--- a/tests/CarDeveloperOptions/res/values-ca/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-ca/strings.xml
@@ -875,7 +875,7 @@
<string name="wifi_cellular_data_fallback_title" msgid="5067241930716252665">"Canvia automàticament a dades mòbils"</string>
<string name="wifi_cellular_data_fallback_summary" msgid="2721467405851519769">"Utilitza dades mòbils quan la Wi-Fi no tingui accés a Internet. És possible que s\'hi apliquin càrrecs per ús de dades."</string>
<string name="wifi_add_network" msgid="4094957940791876640">"Afegeix una xarxa"</string>
- <string name="wifi_configure_settings_preference_title" msgid="2678534679408777268">"Preferències de la Wi‑Fi"</string>
+ <string name="wifi_configure_settings_preference_title" msgid="2678534679408777268">"Preferències de Wi‑Fi"</string>
<string name="wifi_configure_settings_preference_summary_wakeup_on" msgid="5714892572614655675">"La Wi‑Fi es torna a connectar automàticament"</string>
<string name="wifi_configure_settings_preference_summary_wakeup_off" msgid="286904094152909651">"La Wi‑Fi no es torna a activar automàticament"</string>
<string name="wifi_access_points" msgid="1647976498906871869">"Xarxes Wi-Fi"</string>
@@ -3548,7 +3548,7 @@
<string name="zen_mode_screen_off" msgid="84211490206459038">"Quan la pantalla estigui apagada"</string>
<string name="zen_mode_screen_off_summary" msgid="8592179073243001267">"Permet que les notificacions silenciades pel mode No molestis encenguin la pantalla i facin parpellejar el llum"</string>
<string name="zen_mode_screen_off_summary_no_led" msgid="7255874108150630145">"Permet que les notificacions silenciades pel mode No molestis encenguin la pantalla"</string>
- <string name="notification_app_settings_button" msgid="3651180424198580907">"Configuració de les notificacions"</string>
+ <string name="notification_app_settings_button" msgid="3651180424198580907">"Configuració de notificacions"</string>
<string name="suggestion_button_text" msgid="5783566542423813847">"D\'acord"</string>
<string name="device_feedback" msgid="4042352891448769818">"Envia suggeriments sobre el dispositiu"</string>
<string name="restr_pin_enter_admin_pin" msgid="8577847751493521230">"Introdueix el PIN d\'administrador"</string>
diff --git a/tests/CarDeveloperOptions/res/values-es/strings.xml b/tests/CarDeveloperOptions/res/values-es/strings.xml
index eb24e4b..a7a06e2 100644
--- a/tests/CarDeveloperOptions/res/values-es/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-es/strings.xml
@@ -3140,7 +3140,7 @@
<string name="alarm_volume_option_title" msgid="3184076022438477047">"Volumen de alarma"</string>
<string name="ring_volume_option_title" msgid="2038924918468372264">"Volumen del tono"</string>
<string name="notification_volume_option_title" msgid="1358512611511348260">"Volumen de notificaciones"</string>
- <string name="ringtone_title" msgid="1409086028485922583">"Tono del teléfono"</string>
+ <string name="ringtone_title" msgid="1409086028485922583">"Tono de llamada del teléfono"</string>
<string name="notification_ringtone_title" msgid="2932960620843976285">"Sonido de notificación predeterminado"</string>
<string name="notification_unknown_sound_title" msgid="8043718667804838398">"Sonido proporcionado de app"</string>
<string name="notification_sound_default" msgid="2664544380802426260">"Sonido de notificación predeterminado"</string>
@@ -3422,7 +3422,7 @@
<string name="notification_content_block_summary" msgid="2743896875255591743">"No mostrar nunca notificaciones en el panel de notificaciones ni en dispositivos periféricos"</string>
<string name="notification_badge_title" msgid="8989086619255666442">"Permitir burbuja de notificación"</string>
<string name="notification_channel_badge_title" msgid="8228215248332054612">"Mostrar burbuja de notificación"</string>
- <string name="app_notification_override_dnd_title" msgid="1757042206738172601">"Omitir No molestar"</string>
+ <string name="app_notification_override_dnd_title" msgid="1757042206738172601">"Ignorar modo No molestar"</string>
<string name="app_notification_override_dnd_summary" msgid="3152957611171210980">"Permitir notificaciones cuando el modo No molestar esté activado"</string>
<string name="app_notification_visibility_override_title" msgid="2349335170165637672">"En la pantalla de bloqueo"</string>
<string name="app_notification_row_banned" msgid="2079325338122151677">"Bloqueada"</string>
diff --git a/tests/CarDeveloperOptions/res/values-fa/arrays.xml b/tests/CarDeveloperOptions/res/values-fa/arrays.xml
index 94410d3..2fcb737 100644
--- a/tests/CarDeveloperOptions/res/values-fa/arrays.xml
+++ b/tests/CarDeveloperOptions/res/values-fa/arrays.xml
@@ -111,7 +111,7 @@
<item msgid="8247986727324120082">"۲ دقیقه"</item>
<item msgid="2759776603549270587">"۵ دقیقه"</item>
<item msgid="167772676068860015">"۱ ساعت"</item>
- <item msgid="5985477119043628504">"بدون مهلت زمانی"</item>
+ <item msgid="5985477119043628504">"بدون درنگ"</item>
</string-array>
<string-array name="bluetooth_max_connected_audio_devices">
<item msgid="3800257971619063588">"استفاده از پیشفرض سیستم: <xliff:g id="DEFAULT_BLUETOOTH_MAX_CONNECTED_AUDIO_DEVICES">%1$d</xliff:g>"</item>
@@ -415,7 +415,7 @@
<item msgid="8754480102834556765">"آماده سازی..."</item>
<item msgid="3351334355574270250">"در حال اتصال..."</item>
<item msgid="8303882153995748352">"متصل"</item>
- <item msgid="9135049670787351881">"وقفه زمانی"</item>
+ <item msgid="9135049670787351881">"درنگ"</item>
<item msgid="2124868417182583926">"ناموفق"</item>
</string-array>
<string-array name="security_settings_premium_sms_values">
diff --git a/tests/CarDeveloperOptions/res/values-fa/strings.xml b/tests/CarDeveloperOptions/res/values-fa/strings.xml
index c715326..48e902e 100644
--- a/tests/CarDeveloperOptions/res/values-fa/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-fa/strings.xml
@@ -412,7 +412,7 @@
<string name="face_intro_error_unknown" msgid="3241592604198351134">"چهره بیشتری نمیتوان اضافه کرد"</string>
<string name="security_settings_face_enroll_error_dialog_title" msgid="3933492758701563051">"ثبت انجام نشد"</string>
<string name="security_settings_face_enroll_dialog_ok" msgid="1078348922734845090">"تأیید"</string>
- <string name="security_settings_face_enroll_error_timeout_dialog_message" msgid="4917894418448325405">"مهلت زمانی ثبت چهره به پایان رسید. دوباره امتحان کنید."</string>
+ <string name="security_settings_face_enroll_error_timeout_dialog_message" msgid="4917894418448325405">"درنگ ثبت چهره به پایان رسید. دوباره امتحان کنید."</string>
<string name="security_settings_face_enroll_error_generic_dialog_message" msgid="5160473187142616862">"ثبت چهره کار نکرد."</string>
<string name="security_settings_face_enroll_finish_title" msgid="6800717857394410769">"همه چیز تنظیم شد. خوب به نظر میرسد."</string>
<string name="security_settings_face_enroll_done" msgid="5409739233373490971">"تمام"</string>
@@ -488,7 +488,7 @@
<string name="security_settings_fingerprint_enroll_touch_dialog_title" msgid="7410398793283818609">"اووه، آن حسگر نیست"</string>
<string name="security_settings_fingerprint_enroll_touch_dialog_message" msgid="7192100314788868883">"با استفاده از انگشت اشاره، حسگر را در پشت تلفن لمس کنید."</string>
<string name="security_settings_fingerprint_enroll_error_dialog_title" msgid="1415709674142168770">"ثبت انجام نشد"</string>
- <string name="security_settings_fingerprint_enroll_error_timeout_dialog_message" msgid="498951203761192366">"مهلت زمانی ثبت اثر انگشت به پایان رسید. دوباره امتحان کنید."</string>
+ <string name="security_settings_fingerprint_enroll_error_timeout_dialog_message" msgid="498951203761192366">"درنگ ثبت اثر انگشت به پایان رسید. دوباره امتحان کنید."</string>
<string name="security_settings_fingerprint_enroll_error_generic_dialog_message" msgid="7896295829530444810">"ثبت اثر انگشت کار نمیکند. دوباره امتحان کنید یا از انگشت دیگری استفاده کنید."</string>
<string name="fingerprint_enroll_button_add" msgid="6335782936874996629">"افزودن مورد دیگر"</string>
<string name="fingerprint_enroll_button_next" msgid="6419214079104413695">"بعدی"</string>
@@ -3112,11 +3112,11 @@
<string name="keywords_face_settings" msgid="4117345666006836599">"چهره"</string>
<string name="keywords_fingerprint_settings" msgid="902902368701134163">"اثر انگشت، افزودن اثر انگشت"</string>
<string name="keywords_display_auto_brightness" msgid="1810596220466483996">"تار کردن صفحهنمایش، صفحه لمسی، باتری، روشنایی هوشمند، روشنایی پویا"</string>
- <string name="keywords_display_adaptive_sleep" msgid="1695357782432822811">"کمنور کردن صفحه، خواب، باتری، مهلت زمانی، توجه، نمایشگر، صفحه، بیفعالیتی"</string>
+ <string name="keywords_display_adaptive_sleep" msgid="1695357782432822811">"کمنور کردن صفحه، خواب، باتری، درنگ، توجه، نمایشگر، صفحه، بیفعالیتی"</string>
<string name="keywords_auto_rotate" msgid="4320791369951647513">"چرخاندن، چرخش، چرخش، پرتره، منظره، جهت، عمودی، افقی"</string>
<string name="keywords_system_update_settings" msgid="4419971277998986067">"ارتقا دادن، Android"</string>
<string name="keywords_zen_mode_settings" msgid="4103819458182535493">"«مزاحم نشوید»، زمانبندی، اعلانها، مسدود کردن، سکوت، لرزش، خواب، کار، کانونی کردن، صدا، صامت کردن، روز، روز هفته، آخر هفته، شبهای طول هفته، رویداد"</string>
- <string name="keywords_screen_timeout" msgid="4328381362313993666">"صفحه نمایش، زمان قفل شدن، مهلت زمانی، صفحه درحالت قفل"</string>
+ <string name="keywords_screen_timeout" msgid="4328381362313993666">"صفحه نمایش، زمان قفل شدن، درنگ، صفحه درحالت قفل"</string>
<string name="keywords_storage_settings" msgid="6422454520424236476">"حافظه، حافظه پنهان، داده، حذف، پاک کردن، آزاد، فضا"</string>
<string name="keywords_bluetooth_settings" msgid="1152229891590622822">"متصل، دستگاه، هدفونها، هدستها، بلندگو، بیسیم، مرتبطسازی، هدفونهای توگوشی، موسیقی، رسانه"</string>
<string name="keywords_wallpaper" msgid="7665778626293643625">"پسزمینه، صفحه نمایش، صفحه در حالت قفل، طرح زمینه"</string>
diff --git a/tests/CarDeveloperOptions/res/values-fi/strings.xml b/tests/CarDeveloperOptions/res/values-fi/strings.xml
index 61588ac..659ba8a 100644
--- a/tests/CarDeveloperOptions/res/values-fi/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-fi/strings.xml
@@ -246,7 +246,7 @@
<string name="band_mode_set" msgid="4962130364076526789">"Aseta"</string>
<string name="band_mode_failed" msgid="8350123391471974137">"Epäonnistui"</string>
<string name="band_mode_succeeded" msgid="5516613616395402809">"Onnistui"</string>
- <string name="sdcard_changes_instructions" msgid="4138217393448114001">"Muutokset tulevat voimaan, kun USB-kaapeli kytketään uudelleen."</string>
+ <string name="sdcard_changes_instructions" msgid="4138217393448114001">"Muutokset tulevat voimaan, kun USB-johto kytketään uudelleen."</string>
<string name="sdcard_settings_screen_mass_storage_text" msgid="7486030250999007641">"Ota USB-massamuisti käyttöön"</string>
<string name="sdcard_settings_total_bytes_label" msgid="6461741874400909157">"Tavuja yhteensä:"</string>
<string name="sdcard_settings_not_present_status" product="nosdcard" msgid="5419085128792417589">"USB-tallennustila ei käytössä."</string>
@@ -849,7 +849,7 @@
<string name="wifi_notify_open_networks" msgid="4782239203624619655">"Avaa verkkoilmoitus"</string>
<string name="wifi_notify_open_networks_summary" msgid="1383681260705466715">"Ilmoita, kun käytettävissä on laadukkaita julkisia verkkoja."</string>
<string name="wifi_wakeup" msgid="4963732992164721548">"Laita Wi-Fi päälle automaattisesti"</string>
- <string name="wifi_wakeup_summary" msgid="1152699417411690">"Wi-Fi laitetaan automaattisesti päälle, kun lähistöllä on kotiverkkosi tai muita laadukkaita tallennettuja verkkoja."</string>
+ <string name="wifi_wakeup_summary" msgid="1152699417411690">"Wi-Fi laitetaan automaattisesti päälle, kun lähistöllä on kotiverkkosi tai muita laadukkaita tallennettuja verkkoja"</string>
<string name="wifi_wakeup_summary_no_location" msgid="3007457288587966962">"Ei käytettävissä, koska sijainti on poistettu käytöstä. Ota "<annotation id="link">"sijainti"</annotation>" käyttöön."</string>
<string name="wifi_wakeup_summary_scanning_disabled" msgid="6820040651529910914">"Ei käytettävissä, koska Wi‑Fi-haku on pois päältä."</string>
<string name="wifi_wakeup_summary_scoring_disabled" msgid="7067018832237903151">"Valitse verkon arviointipalvelu, jotta voit käyttää tätä."</string>
diff --git a/tests/CarDeveloperOptions/res/values-gl/strings.xml b/tests/CarDeveloperOptions/res/values-gl/strings.xml
index d8f5367..51e5d0c 100644
--- a/tests/CarDeveloperOptions/res/values-gl/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-gl/strings.xml
@@ -4477,7 +4477,7 @@
<string name="contextual_card_dismiss_confirm_message" msgid="2352465079667730312">"Queres eliminar esta suxestión?"</string>
<string name="contextual_card_removed_message" msgid="4047307820743366876">"Quitouse a suxestión"</string>
<string name="contextual_card_undo_dismissal_text" msgid="5009245286931852012">"Desfacer"</string>
- <string name="low_storage_summary" msgid="4562224870189133400">"Queda pouco espazo. Utilizado: <xliff:g id="PERCENTAGE">%1$s</xliff:g>. Libre: <xliff:g id="FREE_SPACE">%2$s</xliff:g>"</string>
+ <string name="low_storage_summary" msgid="4562224870189133400">"Queda pouco espazo. En uso: <xliff:g id="PERCENTAGE">%1$s</xliff:g>. Libre: <xliff:g id="FREE_SPACE">%2$s</xliff:g>"</string>
<string name="contextual_card_feedback_send" msgid="8698649023854350623">"Enviar comentarios"</string>
<string name="contextual_card_feedback_confirm_message" msgid="3987973028353264878">"Queres indicarnos a túa opinión sobre esta suxestión?"</string>
<string name="copyable_slice_toast" msgid="1357518174923789947">"<xliff:g id="COPY_CONTENT">%1$s</xliff:g>: copiouse no portapapeis."</string>
diff --git a/tests/CarDeveloperOptions/res/values-gu/strings.xml b/tests/CarDeveloperOptions/res/values-gu/strings.xml
index 398c56d..49de15b 100644
--- a/tests/CarDeveloperOptions/res/values-gu/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-gu/strings.xml
@@ -3041,7 +3041,7 @@
<string name="connected_devices_dashboard_no_driving_mode_summary" msgid="3524409078596318803">"બ્લૂટૂથ, NFC"</string>
<string name="connected_devices_dashboard_no_driving_mode_no_nfc_summary" msgid="7881286613528299400">"બ્લૂટૂથ"</string>
<string name="app_and_notification_dashboard_title" msgid="8448096608058843730">"ઍપ્લિકેશનો અને નોટિફિકેશન"</string>
- <string name="app_and_notification_dashboard_summary" msgid="4165181440955038145">"આસિસ્ટંટ, તાજેતરની ઍપ, ડિફૉલ્ટ ઍપ"</string>
+ <string name="app_and_notification_dashboard_summary" msgid="4165181440955038145">"Assistant, તાજેતરની ઍપ, ડિફૉલ્ટ ઍપ"</string>
<string name="notification_settings_work_profile" msgid="7190550347842400029">"કાર્યાલયની પ્રોફાઇલમાં ઍપ માટે નોટિફિકેશન ઍક્સેસ ઉપલબ્ધ નથી."</string>
<string name="account_dashboard_title" msgid="4734300939532555885">"એકાઉન્ટ"</string>
<string name="account_dashboard_default_summary" msgid="6822549669771936206">"કોઈ એકાઉન્ટ ઉમેરવામાં આવ્યાં નથી"</string>
diff --git a/tests/CarDeveloperOptions/res/values-hy/strings.xml b/tests/CarDeveloperOptions/res/values-hy/strings.xml
index 0154721..5d6c540 100644
--- a/tests/CarDeveloperOptions/res/values-hy/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-hy/strings.xml
@@ -849,7 +849,7 @@
<string name="wifi_notify_open_networks" msgid="4782239203624619655">"Ծանուցումներ բաց ցանցերի մասին"</string>
<string name="wifi_notify_open_networks_summary" msgid="1383681260705466715">"Տեղեկացնել լավ ազդանշանով բաց ցանցերի հասանելիության մասին"</string>
<string name="wifi_wakeup" msgid="4963732992164721548">"Ավտոմատ միացնել Wi‑Fi-ը"</string>
- <string name="wifi_wakeup_summary" msgid="1152699417411690">"Wi‑Fi-ը կրկին կմիանա պահված լավ ազդանշանով պահված ցանցերի, օրինակ, ձեր տան ցանցի մոտակայքում"</string>
+ <string name="wifi_wakeup_summary" msgid="1152699417411690">"Wi‑Fi-ը կրկին կմիանա լավ ազդանշանով պահված ցանցերի, օրինակ, ձեր տան ցանցի մոտակայքում"</string>
<string name="wifi_wakeup_summary_no_location" msgid="3007457288587966962">"Անհասանելի է, քանի որ տեղորոշումն անջատված է։ Միացրեք "<annotation id="link">"տեղորոշումը"</annotation>"։"</string>
<string name="wifi_wakeup_summary_scanning_disabled" msgid="6820040651529910914">"Անհասանելի է, քանի որ Wi‑Fi ցանցերի որոնումն անջատված է"</string>
<string name="wifi_wakeup_summary_scoring_disabled" msgid="7067018832237903151">"Օգտագործելու համար ընտրեք ցանցի վարկանիշի մատակարարը"</string>
diff --git a/tests/CarDeveloperOptions/res/values-in/strings.xml b/tests/CarDeveloperOptions/res/values-in/strings.xml
index 6ada981..307e232 100644
--- a/tests/CarDeveloperOptions/res/values-in/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-in/strings.xml
@@ -2862,7 +2862,7 @@
<string name="user_summary_managed_profile_not_set_up" msgid="3032986082684011281">"Tidak disiapkan - Profil kerja"</string>
<string name="user_admin" msgid="805802526361071709">"Admin"</string>
<string name="user_you" msgid="8212549708652717106">"Anda (<xliff:g id="NAME">%s</xliff:g>)"</string>
- <string name="user_nickname" msgid="1088216221559125529">"Nama julukan"</string>
+ <string name="user_nickname" msgid="1088216221559125529">"Nama panggilan"</string>
<string name="user_add_user_type_title" msgid="8672326434351387845">"Tambahkan"</string>
<string name="user_add_max_count" msgid="4524573950126500416">"Anda dapat menambahkan maksimal <xliff:g id="USER_COUNT">%1$d</xliff:g> pengguna"</string>
<string name="user_add_user_item_summary" msgid="6114355152711455716">"Pengguna memiliki aplikasi dan konten mereka sendiri"</string>
@@ -3035,7 +3035,7 @@
<string name="network_dashboard_summary_mobile" msgid="5560545061217580626">"seluler"</string>
<string name="network_dashboard_summary_data_usage" msgid="4695629715072542102">"penggunaan kuota"</string>
<string name="network_dashboard_summary_hotspot" msgid="3928610802321995214">"hotspot"</string>
- <string name="connected_devices_dashboard_title" msgid="7795222675849060444">"Perangkat tersambung"</string>
+ <string name="connected_devices_dashboard_title" msgid="7795222675849060444">"Perangkat terhubung"</string>
<string name="connected_devices_dashboard_summary" msgid="1072664369515033179">"Bluetooth, mode mengemudi, NFC"</string>
<string name="connected_devices_dashboard_no_nfc_summary" msgid="2610085597733526722">"Bluetooth, mode mengemudi"</string>
<string name="connected_devices_dashboard_no_driving_mode_summary" msgid="3524409078596318803">"Bluetooth, NFC"</string>
diff --git a/tests/CarDeveloperOptions/res/values-it/strings.xml b/tests/CarDeveloperOptions/res/values-it/strings.xml
index 5c72158..02abed3 100644
--- a/tests/CarDeveloperOptions/res/values-it/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-it/strings.xml
@@ -4325,7 +4325,7 @@
<string name="battery_suggestion_summary" msgid="2669070349482656490"></string>
<string name="gesture_prevent_ringing_screen_title" msgid="4173494225145223638">"Disattiva suoneria"</string>
<string name="gesture_prevent_ringing_title" msgid="8827963588425673557">"Premi contemporaneamente i tasti di accensione e Volume su per"</string>
- <string name="gesture_prevent_ringing_sound_title" msgid="8642330448721033641">"Scorciatoia per impedire al telefono di suonare"</string>
+ <string name="gesture_prevent_ringing_sound_title" msgid="8642330448721033641">"Scorciatoia per disattivare la suoneria"</string>
<string name="prevent_ringing_option_vibrate" msgid="6456505293904544108">"Vibrazione"</string>
<string name="prevent_ringing_option_mute" msgid="53662688921253613">"Disattiva audio"</string>
<string name="prevent_ringing_option_none" msgid="1450985763137666231">"Non fare niente"</string>
diff --git a/tests/CarDeveloperOptions/res/values-km/strings.xml b/tests/CarDeveloperOptions/res/values-km/strings.xml
index 29c5ca4..c8b2bdb 100644
--- a/tests/CarDeveloperOptions/res/values-km/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-km/strings.xml
@@ -3136,7 +3136,7 @@
<string name="sound_settings_example_summary" msgid="2091822107298841827">"កម្រិតសំឡេងរោទ៍ត្រឹម 80%"</string>
<string name="media_volume_option_title" msgid="3553411883305505682">"កម្រិតសំឡេងមេឌៀ"</string>
<string name="remote_media_volume_option_title" msgid="6355710054191873836">"កម្រិតសំឡេងនៃការបញ្ជូន"</string>
- <string name="call_volume_option_title" msgid="5028003296631037334">"កម្រិតសំឡេងហៅ"</string>
+ <string name="call_volume_option_title" msgid="5028003296631037334">"កម្រិតសំឡេងហៅទូរសព្ទ"</string>
<string name="alarm_volume_option_title" msgid="3184076022438477047">"កម្រិតសំឡេងម៉ោងរោទ៍"</string>
<string name="ring_volume_option_title" msgid="2038924918468372264">"កម្រិតសំឡេងរោទ៍"</string>
<string name="notification_volume_option_title" msgid="1358512611511348260">"កម្រិតសំឡេងការជូនដំណឹង"</string>
@@ -3153,7 +3153,7 @@
<string name="docking_sounds_title" msgid="2573137471605541366">"សំឡេងភ្ជាប់"</string>
<string name="touch_sounds_title" msgid="165237488496165652">"សំឡេងប៉ះ"</string>
<string name="vibrate_on_touch_title" msgid="6360155469279157684">"ការញ័រពេលប៉ះ"</string>
- <string name="vibrate_on_touch_summary" msgid="5504424764028676043">"មតិស្ថាបនាតាមការប៉ះសម្រាប់ការចុច ក្ដារចុច និងច្រើនទៀត"</string>
+ <string name="vibrate_on_touch_summary" msgid="5504424764028676043">"ប្រតិកម្មញ័រពេលចុច ក្ដារចុច និងច្រើនទៀត"</string>
<string name="dock_audio_media_title" msgid="1859521680502040781">"ភ្ជាប់ការចាក់តាមអូប៉ាល័រ"</string>
<string name="dock_audio_media_disabled" msgid="4300752306178486302">"អូឌីយ៉ូទាំងអស់"</string>
<string name="dock_audio_media_enabled" msgid="2873275045878628153">"តែអូឌីយ៉ូមេឌៀប៉ុណ្ណោះ"</string>
@@ -4310,7 +4310,7 @@
<string name="change_wifi_state_title" msgid="5140754955787584174">"ការគ្រប់គ្រង Wi-Fi"</string>
<string name="change_wifi_state_app_detail_switch" msgid="6489090744937816260">"អនុញ្ញាតឱ្យកម្មវិធីគ្រប់គ្រង Wi-Fi"</string>
<string name="change_wifi_state_app_detail_summary" msgid="614854822469259860">"អនុញ្ញាតឱ្យកម្មវិធីនេះបើក ឬបិទ Wi-Fi ស្កេន និងភ្ជាប់បណ្តាញ Wi-Fi បញ្ចូល ឬលុបបណ្តាញ ឬចាប់ផ្តើមតែហតស្ប៉តមូលដ្ឋានប៉ុណ្ណោះ"</string>
- <string name="media_output_title" msgid="8710632337456601848">"ចាក់មេឌៀទៅកាន់"</string>
+ <string name="media_output_title" msgid="8710632337456601848">"ចាក់មេឌៀនៅលើ"</string>
<string name="media_output_default_summary" msgid="3159237976830415584">"ឧបករណ៍នេះ"</string>
<string name="media_output_summary" product="default" msgid="6294261435613551178">"ទូរសព្ទ"</string>
<string name="media_output_summary" product="tablet" msgid="6672024060360538526">"ថេប្លេត"</string>
diff --git a/tests/CarDeveloperOptions/res/values-kn/arrays.xml b/tests/CarDeveloperOptions/res/values-kn/arrays.xml
index 63d5f6a..2b09f58 100644
--- a/tests/CarDeveloperOptions/res/values-kn/arrays.xml
+++ b/tests/CarDeveloperOptions/res/values-kn/arrays.xml
@@ -223,7 +223,7 @@
<item msgid="2585253854462134715">"ಒರಟು ಸ್ಥಳ"</item>
<item msgid="1830619568689922920">"ಉತ್ಕೃಷ್ಟ ಸ್ಥಳ"</item>
<item msgid="3317274469481923141">"GPS"</item>
- <item msgid="8931785990160383356">"ಕಂಪನ"</item>
+ <item msgid="8931785990160383356">"ವೈಬ್ರೇಟ್"</item>
<item msgid="8632513128515114092">"ಓದುವ ಸಂಪರ್ಕಗಳು"</item>
<item msgid="3741042113569620272">"ಸಂಪರ್ಕಗಳನ್ನು ಮಾರ್ಪಡಿಸಿ"</item>
<item msgid="4204420969709009931">"ಕರೆಯ ಲಾಗ್ ಓದಿ"</item>
diff --git a/tests/CarDeveloperOptions/res/values-kn/strings.xml b/tests/CarDeveloperOptions/res/values-kn/strings.xml
index 5d1e489..ad359d0 100644
--- a/tests/CarDeveloperOptions/res/values-kn/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-kn/strings.xml
@@ -3124,7 +3124,7 @@
<string name="keywords_default_payment_app" msgid="845369409578423996">"ಪಾವತಿ, ಡಿಫಾಲ್ಟ್"</string>
<string name="keywords_ambient_display" msgid="8835182491798487184">"ಒಳಬರುವ ಅಧಿಸೂಚನೆ"</string>
<string name="keywords_hotspot_tethering" msgid="1723591462602613867">"usb ಟೆಥರ್, ಬ್ಲೂಟೂತ್ ಟೆಥರ್, ವೈಫೈ ಹಾಟ್ಸ್ಪಾಟ್"</string>
- <string name="keywords_touch_vibration" msgid="2081175517528255224">"ಹ್ಯಾಪ್ಟಿಕ್ಸ್, ಕಂಪನ, ಪರದೆ, ಸಂವೇದನೆ"</string>
+ <string name="keywords_touch_vibration" msgid="2081175517528255224">"ಹ್ಯಾಪ್ಟಿಕ್ಸ್, ವೈಬ್ರೇಟ್, ಪರದೆ, ಸಂವೇದನೆ"</string>
<string name="keywords_ring_vibration" msgid="4210509151866460210">"ಹ್ಯಾಪ್ಟಿಕ್ಸ್, ವೈಬ್ರೇಟ್, ಫೋನ್, ಕರೆ, ಸೂಕ್ಷ್ಮತೆ, ರಿಂಗ್"</string>
<string name="keywords_notification_vibration" msgid="1077515502086745166">"ಹ್ಯಾಪ್ಟಿಕ್ಸ್, ವೈಬ್ರೇಟ್, ಸೂಕ್ಷ್ಮತೆ"</string>
<string name="keywords_battery_saver_sticky" msgid="8733804259716284872">"ಬ್ಯಾಟರಿ ಸೇವರ್, ಸ್ಟಿಕಿ, ತಡೆ ಹಿಡಿ, ಪವರ್ ಸೇವರ್, ಬ್ಯಾಟರಿ"</string>
@@ -3149,7 +3149,7 @@
<string name="other_sound_settings" msgid="5250376066099818676">"ಇತರ ಧ್ವನಿಗಳು"</string>
<string name="dial_pad_tones_title" msgid="8877212139988655769">"ಡಯಲ್ ಪ್ಯಾಡ್ ಟೋನ್ಗಳು"</string>
<string name="screen_locking_sounds_title" msgid="4407110895465866809">"ಸ್ಕ್ರೀನ್ ಲಾಕಿಂಗ್ ಧ್ವನಿಗಳು"</string>
- <string name="charging_sounds_title" msgid="5070437987230894287">"ಚಾರ್ಜಿಂಗ್ ಧ್ವನಿಗಳು ಮತ್ತು ಕಂಪನ"</string>
+ <string name="charging_sounds_title" msgid="5070437987230894287">"ಚಾರ್ಜಿಂಗ್ ಧ್ವನಿಗಳು ಮತ್ತು ವೈಬ್ರೇಟ್"</string>
<string name="docking_sounds_title" msgid="2573137471605541366">"ಡಾಕಿಂಗ್ ಧ್ವನಿಗಳು"</string>
<string name="touch_sounds_title" msgid="165237488496165652">"ಸ್ಪರ್ಶ ಧ್ವನಿಗಳು"</string>
<string name="vibrate_on_touch_title" msgid="6360155469279157684">"ಸ್ಪರ್ಶಿಸಿದಾಗ ವೈಬ್ರೇಷನ್"</string>
@@ -4037,7 +4037,7 @@
<string name="notification_log_details_ashmem" msgid="4272241723105041393">"ಆಶ್ಮೆಮ್"</string>
<string name="notification_log_details_alerted" msgid="1891749888625061319">"ಅಧಿಸೂಚನೆಯ ಎಚ್ಚರಿಕೆಯನ್ನು ನೀಡಲಾಗಿದೆ"</string>
<string name="notification_log_details_sound" msgid="4028782443557466322">"ಶಬ್ದ"</string>
- <string name="notification_log_details_vibrate" msgid="8372400602058888072">"ಕಂಪನ"</string>
+ <string name="notification_log_details_vibrate" msgid="8372400602058888072">"ವೈಬ್ರೇಟ್"</string>
<string name="notification_log_details_vibrate_pattern" msgid="7015554755444260922">"ಪ್ಯಾಟರ್ನ್"</string>
<string name="notification_log_details_default" msgid="455451833359888182">"ಡಿಫಾಲ್ಟ್"</string>
<string name="notification_log_details_none" msgid="4294690532744821638">"ಯಾವುದೂ ಇಲ್ಲ"</string>
diff --git a/tests/CarDeveloperOptions/res/values-ky/strings.xml b/tests/CarDeveloperOptions/res/values-ky/strings.xml
index c436ab2..be41ac2 100644
--- a/tests/CarDeveloperOptions/res/values-ky/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-ky/strings.xml
@@ -3035,7 +3035,7 @@
<string name="network_dashboard_summary_mobile" msgid="5560545061217580626">"мобилдик"</string>
<string name="network_dashboard_summary_data_usage" msgid="4695629715072542102">"дайын-даректердин өткөрүлүшү"</string>
<string name="network_dashboard_summary_hotspot" msgid="3928610802321995214">"байланыш түйүнү"</string>
- <string name="connected_devices_dashboard_title" msgid="7795222675849060444">"Туташкан түзмөктөр"</string>
+ <string name="connected_devices_dashboard_title" msgid="7795222675849060444">"Байланышкан түзмөктөр"</string>
<string name="connected_devices_dashboard_summary" msgid="1072664369515033179">"Bluetooth, айдоо режими, NFC"</string>
<string name="connected_devices_dashboard_no_nfc_summary" msgid="2610085597733526722">"Bluetooth, айдоо режими"</string>
<string name="connected_devices_dashboard_no_driving_mode_summary" msgid="3524409078596318803">"Bluetooth, NFC"</string>
diff --git a/tests/CarDeveloperOptions/res/values-lo/strings.xml b/tests/CarDeveloperOptions/res/values-lo/strings.xml
index 4d48d74..f43a442 100644
--- a/tests/CarDeveloperOptions/res/values-lo/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-lo/strings.xml
@@ -3403,7 +3403,7 @@
<item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> ໝວດໝູ່</item>
<item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g> ໝວດໝູ່</item>
</plurals>
- <string name="no_channels" msgid="8884254729302501652">"This app has not posted any notifications"</string>
+ <string name="no_channels" msgid="8884254729302501652">"ແອັບນີ້ຍັງບໍ່ໄດ້ໂພສການແຈ້ງເຕືອນໃດເທື່ອ"</string>
<string name="app_settings_link" msgid="8465287765715790984">"ການຕັ້ງຄ່າເພີ່ມເຕີມໃນແອັບ"</string>
<string name="app_notification_listing_summary_zero" msgid="4047782719487686699">"ເປີດສຳລັບທຸກແອັບ"</string>
<plurals name="app_notification_listing_summary_others" formatted="false" msgid="1161774065480666519">
diff --git a/tests/CarDeveloperOptions/res/values-mk/strings.xml b/tests/CarDeveloperOptions/res/values-mk/strings.xml
index 56d2a0c..94c0d71 100644
--- a/tests/CarDeveloperOptions/res/values-mk/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-mk/strings.xml
@@ -1608,7 +1608,7 @@
<string name="master_clear_not_available" msgid="4676613348163652454">"Фабричкото ресетирање не е достапно за овој корисник"</string>
<string name="master_clear_progress_title" msgid="378953167274114857">"Се брише"</string>
<string name="master_clear_progress_text" msgid="5418958116008976218">"Почекајте..."</string>
- <string name="call_settings_title" msgid="5033906789261282752">"Поставки на повик"</string>
+ <string name="call_settings_title" msgid="5033906789261282752">"Поставки за повици"</string>
<string name="call_settings_summary" msgid="2119161087671450035">"Постави говорна пошта, проследување на повик, повик на чекање, ID на повикувач"</string>
<string name="tether_settings_title_usb" msgid="4265582654602420357">"Интернет преку USB"</string>
<string name="tether_settings_title_wifi" msgid="2060965130234484613">"Преносл. точка на пристап"</string>
diff --git a/tests/CarDeveloperOptions/res/values-ml/strings.xml b/tests/CarDeveloperOptions/res/values-ml/strings.xml
index a529cee..2f0c29a 100644
--- a/tests/CarDeveloperOptions/res/values-ml/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-ml/strings.xml
@@ -3105,7 +3105,7 @@
<string name="keywords_android_version" msgid="4842749998088987740">"android സുരക്ഷാ പാച്ച് നില, ബേസ്ബാൻഡ് പതിപ്പ്, കെർണൽ പതിപ്പ്"</string>
<string name="keywords_dark_ui_mode" msgid="1027966176887770318">"തീം, പ്രകാശം, ഇരുണ്ട മോഡ്"</string>
<string name="keywords_financial_apps_sms_access" msgid="3236014691838121857">"സാമ്പത്തിക ആപ്പ്, SMS, അനുമതി"</string>
- <string name="keywords_systemui_theme" msgid="9150908170417305866">"ഇരുണ്ട തീം"</string>
+ <string name="keywords_systemui_theme" msgid="9150908170417305866">"ഡാർക്ക് തീം"</string>
<string name="keywords_device_feedback" msgid="6948977907405738490">"ബഗ്"</string>
<string name="keywords_ambient_display_screen" msgid="5873935693887583428">"പാതിമയക്ക ഡിസ്പ്ലേ, ലോക്ക് സ്ക്രീൻ ഡിസ്പ്ലേ"</string>
<string name="keywords_lock_screen_notif" msgid="4914337222856805463">"ലോക്ക് സ്ക്രീൻ അറിയിപ്പ്, അറിയിപ്പുകൾ"</string>
@@ -4310,8 +4310,8 @@
<string name="change_wifi_state_title" msgid="5140754955787584174">"വൈഫൈ നിയന്ത്രണം"</string>
<string name="change_wifi_state_app_detail_switch" msgid="6489090744937816260">"വൈഫൈയെ നിയന്ത്രിക്കാൻ ആപ്പിനെ അനുവദിക്കുക"</string>
<string name="change_wifi_state_app_detail_summary" msgid="614854822469259860">"വൈഫൈ ഓണോ ഓഫോ ആക്കാനോ വൈഫൈ നെറ്റ്വർക്കുകൾ സ്കാൻ ചെയ്യാനോ അവയിലേക്ക് കണക്റ്റ് ചെയ്യാനോ നെറ്റ്വർക്കുകൾ ചേർക്കാനോ നീക്കം ചെയ്യാനോ ഉപകരണം ഉള്ളിടത്ത് മാത്രം പ്രവർത്തിക്കുന്ന ഒരു ഹോട്ട്സ്പോട്ട് ആരംഭിക്കാനോ ഈ ആപ്പിനെ അനുവദിക്കുക"</string>
- <string name="media_output_title" msgid="8710632337456601848">"ഇതിലേക്ക് മീഡിയ പ്ലേ ചെയ്യുക"</string>
- <string name="media_output_default_summary" msgid="3159237976830415584">"ഈ ഉപകരണം"</string>
+ <string name="media_output_title" msgid="8710632337456601848">"മീഡിയ പ്ലേ ചെയ്യുക:"</string>
+ <string name="media_output_default_summary" msgid="3159237976830415584">"ഈ ഉപകരണത്തിൽ"</string>
<string name="media_output_summary" product="default" msgid="6294261435613551178">"ഫോൺ"</string>
<string name="media_output_summary" product="tablet" msgid="6672024060360538526">"ടാബ്ലെറ്റ്"</string>
<string name="media_output_summary" product="device" msgid="5132223072593052660">"ഉപകരണം"</string>
diff --git a/tests/CarDeveloperOptions/res/values-my/strings.xml b/tests/CarDeveloperOptions/res/values-my/strings.xml
index 4ad5b8e..3716e91 100644
--- a/tests/CarDeveloperOptions/res/values-my/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-my/strings.xml
@@ -3332,7 +3332,7 @@
<string name="lock_screen_notifications_interstitial_title_profile" msgid="4043621508889929254">"ပရိုဖိုင်သတိပေးချက်များ"</string>
<string name="notifications_title" msgid="8334011924253810654">"အကြောင်းကြားချက်များ"</string>
<string name="app_notifications_title" msgid="1141791221581312325">"အက်ပ် အကြောင်းကြားချက်များ"</string>
- <string name="notification_channel_title" msgid="6637705960909690229">"အသိပေးချက် အမျိုးအစား"</string>
+ <string name="notification_channel_title" msgid="6637705960909690229">"အကြောင်းကြားချက် အမျိုးအစား"</string>
<string name="notification_group_title" msgid="6105337987437608590">"အကြောင်းကြားချက် အုပ်စုအမျိုးအစား"</string>
<string name="notification_importance_title" msgid="4131979083408000545">"အပြုအမူ"</string>
<string name="notification_importance_unspecified" msgid="2515778981253707724">"အသံကို ခွင့်ပြုရန်"</string>
diff --git a/tests/CarDeveloperOptions/res/values-or/strings.xml b/tests/CarDeveloperOptions/res/values-or/strings.xml
index bbc3273..17e330b 100644
--- a/tests/CarDeveloperOptions/res/values-or/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-or/strings.xml
@@ -1608,7 +1608,7 @@
<string name="master_clear_not_available" msgid="4676613348163652454">"ଏହି ଉପଯୋଗକର୍ତ୍ତାଙ୍କ ପାଇଁ ଫ୍ୟାକ୍ଟୋରୀ ରିସେଟ୍ ଉପଲବ୍ଧ ନାହିଁ"</string>
<string name="master_clear_progress_title" msgid="378953167274114857">"ଲିଭାଉଛି"</string>
<string name="master_clear_progress_text" msgid="5418958116008976218">"ଦୟାକରି ଅପେକ୍ଷା କରନ୍ତୁ..."</string>
- <string name="call_settings_title" msgid="5033906789261282752">"କଲ୍ ସେଟିଙ୍ଗ"</string>
+ <string name="call_settings_title" msgid="5033906789261282752">"କଲ୍ ସେଟିଂସ୍"</string>
<string name="call_settings_summary" msgid="2119161087671450035">"ଭଏସ୍ମେଲ୍, କଲ୍ ଫର୍ୱାର୍ଡିଙ୍ଗ, କଲ୍ ୱେଟିଙ୍ଗ, କଲର୍ ID ସେଟ୍ କରନ୍ତୁ"</string>
<string name="tether_settings_title_usb" msgid="4265582654602420357">"USB ଟିଥରିଂ"</string>
<string name="tether_settings_title_wifi" msgid="2060965130234484613">"ପୋର୍ଟବଲ୍ ହଟସ୍ପଟ୍"</string>
@@ -3147,13 +3147,13 @@
<string name="alarm_ringtone_title" msgid="6411326147408635902">"ଡିଫଲ୍ଟ ଆଲାର୍ମ ସାଉଣ୍ଡ"</string>
<string name="vibrate_when_ringing_title" msgid="2757996559847126952">"କଲ୍ ପାଇଁ ଭାଇବ୍ରେଟ୍ କରନ୍ତୁ"</string>
<string name="other_sound_settings" msgid="5250376066099818676">"ଅନ୍ୟାନ୍ୟ ଶବ୍ଦ"</string>
- <string name="dial_pad_tones_title" msgid="8877212139988655769">"ଡାୟଲ୍ ପ୍ୟାଡ୍ ଟୋନ୍"</string>
+ <string name="dial_pad_tones_title" msgid="8877212139988655769">"ଡାଏଲ୍ ପ୍ୟାଡ୍ ଟୋନ୍"</string>
<string name="screen_locking_sounds_title" msgid="4407110895465866809">"ସ୍କ୍ରୀନ୍ ଲକ୍ କରିବା ସାଉଣ୍ଡ"</string>
<string name="charging_sounds_title" msgid="5070437987230894287">"ସାଉଣ୍ଡ ଓ ଭାଇବ୍ରେସନ୍ ଚାର୍ଜ ହେଉଛି"</string>
<string name="docking_sounds_title" msgid="2573137471605541366">"ଡକ୍ କରିବା ଧ୍ୱନୀ"</string>
<string name="touch_sounds_title" msgid="165237488496165652">"ସ୍ପର୍ଶ ଶବ୍ଦ"</string>
- <string name="vibrate_on_touch_title" msgid="6360155469279157684">"ସ୍ପର୍ଶଜନିତ ଭାଇବ୍ରେଶନ୍"</string>
- <string name="vibrate_on_touch_summary" msgid="5504424764028676043">"ଟ୍ୟାପ୍, କୀ-ବୋର୍ଡ ଓ ଆହୁରି ଅଧିକ ପାଇଁ ସ୍ପର୍ଶ ମାଧ୍ୟମରେ ମତାମତ"</string>
+ <string name="vibrate_on_touch_title" msgid="6360155469279157684">"ସ୍ପର୍ଶ ଭାଇବ୍ରେସନ୍"</string>
+ <string name="vibrate_on_touch_summary" msgid="5504424764028676043">"ଟ୍ୟାପ୍, କୀ-ବୋର୍ଡ ଓ ଆହୁରି ଅଧିକ ପାଇଁ ହେପଟିକ୍ ମତାମତ"</string>
<string name="dock_audio_media_title" msgid="1859521680502040781">"ଡକ୍ ସ୍ପିକର୍ ବାଜିବ"</string>
<string name="dock_audio_media_disabled" msgid="4300752306178486302">"ସମସ୍ତ ଅଡିଓ"</string>
<string name="dock_audio_media_enabled" msgid="2873275045878628153">"କେବଳ ମିଡିଆ ଅଡିଓ"</string>
@@ -3293,7 +3293,7 @@
<string name="ringtones_install_custom_sound_title" msgid="210551218424553671">"କଷ୍ଟମ୍ ସାଉଣ୍ଡ ଯୋଡ଼ିବେ?"</string>
<string name="ringtones_install_custom_sound_content" msgid="6683649115132255452">"<xliff:g id="FOLDER_NAME">%s</xliff:g> ଫୋଲ୍ଡର୍କୁ ଏହି ଫାଇଲ୍ କପୀ କରାଯିବ"</string>
<string name="ringtones_category_preference_title" msgid="4491932700769815470">"ରିଙ୍ଗଟୋନ୍"</string>
- <string name="other_sound_category_preference_title" msgid="2045757472469840859">"ଅନ୍ୟାନ୍ୟ ସାଉଣ୍ଡ ଓ ଭାଇବ୍ରେଶନ୍"</string>
+ <string name="other_sound_category_preference_title" msgid="2045757472469840859">"ଅନ୍ୟ ସାଉଣ୍ଡ ଓ ଭାଇବ୍ରେସନ୍"</string>
<string name="configure_notification_settings" msgid="291914315140851270">"ବିଜ୍ଞପ୍ତି"</string>
<string name="recent_notifications" msgid="8125865995065032049">"କିଛି ସମୟ ପୂର୍ବରୁ ବିଜ୍ଞପ୍ତି ପଠାଇଥିବା ଆପ୍"</string>
<string name="recent_notifications_see_all_title" msgid="4089007770442871469">"ବିଗତ 7 ଦିନରୁ ସବୁଗୁଡ଼ିକୁ ଦେଖନ୍ତୁ"</string>
@@ -3423,7 +3423,7 @@
<string name="notification_badge_title" msgid="8989086619255666442">"ବିଜ୍ଞପ୍ତି ଡଟ୍ର ଅନୁମତି ଦିଅନ୍ତୁ"</string>
<string name="notification_channel_badge_title" msgid="8228215248332054612">"ବିଜ୍ଞପ୍ତି ଡଟ୍ ଦେଖାନ୍ତୁ"</string>
<string name="app_notification_override_dnd_title" msgid="1757042206738172601">"ବିରକ୍ତ କରନାହିଁ ଓଭରରାଇଡ"</string>
- <string name="app_notification_override_dnd_summary" msgid="3152957611171210980">"’ବିରକ୍ତ କରନ୍ତୁ ନାହିଁ’ ଅନ୍ ଥିବାବେଳେ ଏହି ବିଜ୍ଞପ୍ତିର ବାଧା ଦେବା ପ୍ରକ୍ରିୟାକୁ ଜାରି ରଖନ୍ତୁ"</string>
+ <string name="app_notification_override_dnd_summary" msgid="3152957611171210980">"\'ବିରକ୍ତ କରନ୍ତୁ ନାହିଁ\' ଚାଲୁଥିବା ବେଳେ ଏହି ବିଜ୍ଞପ୍ତିଗୁଡ଼ିକର ବାଧା ଦେବା ପ୍ରକ୍ରିୟାକୁ ଜାରି ରଖନ୍ତୁ"</string>
<string name="app_notification_visibility_override_title" msgid="2349335170165637672">"ଲକ୍ ସ୍କ୍ରୀନ୍ ଉପରେ"</string>
<string name="app_notification_row_banned" msgid="2079325338122151677">"ଅବରୋଧିତ"</string>
<string name="app_notification_row_priority" msgid="432299064888787236">"ପ୍ରାଥମିକତା"</string>
@@ -4310,7 +4310,7 @@
<string name="change_wifi_state_title" msgid="5140754955787584174">"ୱାଇ-ଫାଇର ନିୟନ୍ତ୍ରଣ"</string>
<string name="change_wifi_state_app_detail_switch" msgid="6489090744937816260">"ୱାଇ-ଫାଇକୁ ନିୟନ୍ତ୍ରଣ କରିବା ପାଇଁ ଆପ୍କୁ ଅନୁମତି ଦିଅନ୍ତୁ"</string>
<string name="change_wifi_state_app_detail_summary" msgid="614854822469259860">"ୱାଇ-ଫାଇକୁ ଚାଲୁ କରିବା କିମ୍ବା ବନ୍ଦ କରିବା, ୱାଇ-ଫାଇ ନେଟୱର୍କକୁ ଖୋଜିବା ଓ କନେକ୍ଟ କରିବା, ନେଟୱର୍କକୁ ଯୋଡ଼ିବା କିମ୍ବା କାଢ଼ିଦେବା କିମ୍ବା କେବଳ ସୀମିତ କ୍ଷେତ୍ରରେ କାମ କରୁଥିବା ହଟସ୍ପଟ୍କୁ ଚାଲୁ କରିବା ପାଇଁ ଏହି ଆପ୍କୁ ଅନୁମତି ଦେବା"</string>
- <string name="media_output_title" msgid="8710632337456601848">"ମିଡିଆ ଚଲାନ୍ତୁ"</string>
+ <string name="media_output_title" msgid="8710632337456601848">"ଏଥିରେ ମିଡିଆ ଚଲାନ୍ତୁ"</string>
<string name="media_output_default_summary" msgid="3159237976830415584">"ଏହି ଡିଭାଇସ୍"</string>
<string name="media_output_summary" product="default" msgid="6294261435613551178">"ଫୋନ୍"</string>
<string name="media_output_summary" product="tablet" msgid="6672024060360538526">"ଟାବଲେଟ୍"</string>
@@ -4330,7 +4330,7 @@
<string name="prevent_ringing_option_mute" msgid="53662688921253613">"ମ୍ୟୁଟ୍ କରନ୍ତୁ"</string>
<string name="prevent_ringing_option_none" msgid="1450985763137666231">"କିଛି କରନ୍ତୁ ନାହିଁ"</string>
<string name="prevent_ringing_option_vibrate_summary" msgid="7961818570574683926">"ଚାଲୁ (ଭାଇବ୍ରେଟ୍)"</string>
- <string name="prevent_ringing_option_mute_summary" msgid="3509459199090688328">"(ମ୍ୟୁଟ୍) ଅନ୍ ଅଛି"</string>
+ <string name="prevent_ringing_option_mute_summary" msgid="3509459199090688328">"ଚାଲୁ (ମ୍ୟୁଟ୍)"</string>
<string name="prevent_ringing_option_none_summary" msgid="5152618221093037451">"ଅଫ୍"</string>
<string name="pref_title_network_details" msgid="3971074015034595956">"ନେଟୱାର୍କ୍ ବିବରଣୀ"</string>
<string name="about_phone_device_name_warning" msgid="9088572775969880106">"ଆପଣଙ୍କ ଡିଭାଇସ୍ରେ ଥିବା ଆପ୍ଗୁଡ଼ିକୁ ଆପଣଙ୍କର ଡିଭାଇସ୍ ନାମ ଦେଖାଯାଉଛି। ବ୍ଲୁଟୂଥ୍ ଡିଭାଇସ୍ ସହ ଯୋଡ଼ି ହେବାବେଳେ କିମ୍ୱା ଏକ ୱାଇ-ଫାଇ ହଟସ୍ପଟ୍ ସେଟ୍ କରିବା ସମୟରେ, ଏହା ଅନ୍ୟ ଲୋକମାନଙ୍କୁ ମଧ୍ୟ ଦେଖାଦେଇପାରେ।"</string>
diff --git a/tests/CarDeveloperOptions/res/values-pt/strings.xml b/tests/CarDeveloperOptions/res/values-pt/strings.xml
index 41b6c14..1f678e4 100644
--- a/tests/CarDeveloperOptions/res/values-pt/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-pt/strings.xml
@@ -3031,7 +3031,7 @@
<item quantity="one">Mostrar %d item oculto</item>
<item quantity="other">Mostrar %d itens ocultos</item>
</plurals>
- <string name="network_dashboard_title" msgid="8288134139584687806">"Rede e internet"</string>
+ <string name="network_dashboard_title" msgid="8288134139584687806">"Rede e Internet"</string>
<string name="network_dashboard_summary_mobile" msgid="5560545061217580626">"rede móvel"</string>
<string name="network_dashboard_summary_data_usage" msgid="4695629715072542102">"uso de dados"</string>
<string name="network_dashboard_summary_hotspot" msgid="3928610802321995214">"ponto de acesso"</string>
@@ -3423,7 +3423,7 @@
<string name="notification_badge_title" msgid="8989086619255666442">"Permitir ponto de notificação"</string>
<string name="notification_channel_badge_title" msgid="8228215248332054612">"Mostrar ponto de notificação"</string>
<string name="app_notification_override_dnd_title" msgid="1757042206738172601">"Ignorar o Não perturbe"</string>
- <string name="app_notification_override_dnd_summary" msgid="3152957611171210980">"Permitir que essas notificações sejam mostradas mesmo quando o Não perturbe estiver ativado"</string>
+ <string name="app_notification_override_dnd_summary" msgid="3152957611171210980">"Permitir que as notificações sejam mostradas mesmo quando o Não perturbe estiver ativado"</string>
<string name="app_notification_visibility_override_title" msgid="2349335170165637672">"Na tela de bloqueio"</string>
<string name="app_notification_row_banned" msgid="2079325338122151677">"Bloqueadas"</string>
<string name="app_notification_row_priority" msgid="432299064888787236">"Prioridade"</string>
diff --git a/tests/CarDeveloperOptions/res/values-sk/strings.xml b/tests/CarDeveloperOptions/res/values-sk/strings.xml
index fbac769..0d97f16 100644
--- a/tests/CarDeveloperOptions/res/values-sk/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-sk/strings.xml
@@ -766,7 +766,7 @@
<string name="bluetooth_pairing_request" msgid="7221745525632573125">"Spárovať so zariadením <xliff:g id="DEVICE_NAME">%1$s</xliff:g>?"</string>
<string name="bluetooth_pairing_key_msg" msgid="1139230917419961975">"Párovací kód Bluetooth"</string>
<string name="bluetooth_enter_passkey_msg" msgid="6205151011298670207">"Zadajte párovací kód a potom stlačte tlačidlo Return alebo Enter"</string>
- <string name="bluetooth_enable_alphanumeric_pin" msgid="9138308197078115672">"Kód PIN obsahuje písmená alebo symboly"</string>
+ <string name="bluetooth_enable_alphanumeric_pin" msgid="9138308197078115672">"PIN obsahuje písmená či symboly"</string>
<string name="bluetooth_pin_values_hint" msgid="8044671726261326240">"Obvykle 0000 alebo 1234"</string>
<string name="bluetooth_pin_values_hint_16_digits" msgid="2665983525706661525">"Musí obsahovať 16 číslic"</string>
<string name="bluetooth_enter_pin_other_device" msgid="1727015949040507621">"Tento kód PIN bude možno treba zadať aj na druhom zariadení."</string>
diff --git a/tests/CarDeveloperOptions/res/values-sq/strings.xml b/tests/CarDeveloperOptions/res/values-sq/strings.xml
index 37c7aa3..ac2c3bc 100644
--- a/tests/CarDeveloperOptions/res/values-sq/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-sq/strings.xml
@@ -3555,7 +3555,7 @@
<string name="switch_on_text" msgid="7100491749799298324">"Aktivizuar"</string>
<string name="switch_off_text" msgid="3539551289454353555">"Joaktiv"</string>
<string name="screen_pinning_title" msgid="578020318289781102">"Gozhdimi i ekranit"</string>
- <string name="screen_pinning_description" msgid="3814537379086412278">"Kur ky funksion është i aktivizuar, mund të përdorësh gozhdimin e ekranit për të mbajtur pamjen aktuale të ekranit deri sa ta anulosh gozhdimin.\n\nPër të përdorur gozhdimin e ekranit:\n\n1. Sigurohu që gozhdimi i ekranit është i aktivizuar\n\n2. Hap \"Përmbledhja\"\n\n3. Trokit tek ikona e aplikacionit në krye të ekranit dhe më pas trokit te \"Gozhdo\""</string>
+ <string name="screen_pinning_description" msgid="3814537379086412278">"Kur ky cilësim është i aktivizuar, mund të përdorësh gozhdimin e ekranit për të mbajtur pamjen aktuale të ekranit deri sa ta anulosh gozhdimin.\n\nPër të përdorur gozhdimin e ekranit:\n\n1. Sigurohu që gozhdimi i ekranit është i aktivizuar\n\n2. Hap \"Përmbledhja\"\n\n3. Trokit tek ikona e aplikacionit në krye të ekranit dhe më pas trokit te \"Gozhdo\""</string>
<string name="screen_pinning_unlock_pattern" msgid="1060334707088339444">"Kërko motivin e shkyçjes para anulimit të mbërthimit"</string>
<string name="screen_pinning_unlock_pin" msgid="1441705536015645023">"Zhgozhdimi kërkon PIN-in"</string>
<string name="screen_pinning_unlock_password" msgid="1017776884000170841">"Kërko fjalëkalim para heqjes nga gozhdimi"</string>
diff --git a/tests/CarDeveloperOptions/res/values-sr/strings.xml b/tests/CarDeveloperOptions/res/values-sr/strings.xml
index fbee5c3..edf510e 100644
--- a/tests/CarDeveloperOptions/res/values-sr/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-sr/strings.xml
@@ -3190,7 +3190,7 @@
<string name="other_sound_settings" msgid="5250376066099818676">"Други звукови"</string>
<string name="dial_pad_tones_title" msgid="8877212139988655769">"Тонови нумеричке тастатуре"</string>
<string name="screen_locking_sounds_title" msgid="4407110895465866809">"Звукови закључавања екрана"</string>
- <string name="charging_sounds_title" msgid="5070437987230894287">"Мењајући звуци и вибрација"</string>
+ <string name="charging_sounds_title" msgid="5070437987230894287">"Звукови и вибрација пуњења"</string>
<string name="docking_sounds_title" msgid="2573137471605541366">"Звукови монтирања"</string>
<string name="touch_sounds_title" msgid="165237488496165652">"Звукови при додиру"</string>
<string name="vibrate_on_touch_title" msgid="6360155469279157684">"Вибрација при додиру"</string>
diff --git a/tests/CarDeveloperOptions/res/values-sv/strings.xml b/tests/CarDeveloperOptions/res/values-sv/strings.xml
index 5b2dcd1..68c7e34 100644
--- a/tests/CarDeveloperOptions/res/values-sv/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-sv/strings.xml
@@ -3149,7 +3149,7 @@
<string name="other_sound_settings" msgid="5250376066099818676">"Andra ljud"</string>
<string name="dial_pad_tones_title" msgid="8877212139988655769">"Knappsatsljud"</string>
<string name="screen_locking_sounds_title" msgid="4407110895465866809">"Ljud vid skärmlåsning"</string>
- <string name="charging_sounds_title" msgid="5070437987230894287">"Laddningsljud- och vibration"</string>
+ <string name="charging_sounds_title" msgid="5070437987230894287">"Laddningsljud och -vibration"</string>
<string name="docking_sounds_title" msgid="2573137471605541366">"Ljud via dockningsstationen"</string>
<string name="touch_sounds_title" msgid="165237488496165652">"Ljud vid tryck"</string>
<string name="vibrate_on_touch_title" msgid="6360155469279157684">"Vibration vid tryck"</string>
diff --git a/tests/CarDeveloperOptions/res/values-sw/strings.xml b/tests/CarDeveloperOptions/res/values-sw/strings.xml
index a07110a..b665336 100644
--- a/tests/CarDeveloperOptions/res/values-sw/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-sw/strings.xml
@@ -2094,7 +2094,7 @@
<string name="accessibility_vibration_settings_title" msgid="1902649657883159406">"Mtetemo"</string>
<string name="accessibility_notification_vibration_title" msgid="1005799039440510298">"Mtetemo wa arifa"</string>
<string name="accessibility_ring_vibration_title" msgid="7943341443551359985">"Mtetemo wa mlio"</string>
- <string name="accessibility_touch_vibration_title" msgid="285890135612038092">"Mtetemo wa mguso"</string>
+ <string name="accessibility_touch_vibration_title" msgid="285890135612038092">"Mtetemo inapoguswa"</string>
<string name="accessibility_service_master_switch_title" msgid="2734791644475782924">"Tumia huduma"</string>
<string name="accessibility_daltonizer_master_switch_title" msgid="4855011639012300777">"Tumia usahihishaji wa rangi"</string>
<string name="accessibility_caption_master_switch_title" msgid="6373335123229234053">"Tumia manukuu"</string>
@@ -3152,7 +3152,7 @@
<string name="charging_sounds_title" msgid="5070437987230894287">"Sauti za kuchaji na mtetemo"</string>
<string name="docking_sounds_title" msgid="2573137471605541366">"Kuambatisha sauti"</string>
<string name="touch_sounds_title" msgid="165237488496165652">"Sauti inapoguswa"</string>
- <string name="vibrate_on_touch_title" msgid="6360155469279157684">"Mtetemo wa mguso"</string>
+ <string name="vibrate_on_touch_title" msgid="6360155469279157684">"Mtetemo inapoguswa"</string>
<string name="vibrate_on_touch_summary" msgid="5504424764028676043">"Majibu unayoweza kuhisi kwa kugusa, kibodi na mengineyo"</string>
<string name="dock_audio_media_title" msgid="1859521680502040781">"Cheza kutumia spika ya kituo"</string>
<string name="dock_audio_media_disabled" msgid="4300752306178486302">"Sauti zote"</string>
@@ -3341,11 +3341,11 @@
<string name="notification_importance_low" msgid="7609797151662295364">"Onyesha chinichini"</string>
<string name="notification_importance_default" msgid="4091563759103917166">"Toa sauti"</string>
<string name="notification_importance_high" msgid="7973764540402436656">"Toa sauti na ibukizi kwenye skrini"</string>
- <string name="notification_importance_high_silent" msgid="3177662759865661155">"Ichomoze kwenye skrini"</string>
+ <string name="notification_importance_high_silent" msgid="3177662759865661155">"Zionekane kwenye skrini"</string>
<string name="notification_importance_min_title" msgid="705872537330744154">"Punguza"</string>
<string name="notification_importance_low_title" msgid="2956199021781786232">"Wastani"</string>
<string name="notification_importance_default_title" msgid="7985549807203332482">"Juu"</string>
- <string name="notification_importance_high_title" msgid="7258373094258585858">"Ichomoze kwenye skrini"</string>
+ <string name="notification_importance_high_title" msgid="7258373094258585858">"Zionekane kwenye skrini"</string>
<string name="notification_block_title" msgid="2570364198866886906">"Zuia"</string>
<string name="notification_silence_title" msgid="6959637402003838093">"Ionyeshe bila kutoa sauti"</string>
<string name="notification_alert_title" msgid="750683027055192648">"Arifa"</string>
diff --git a/tests/CarDeveloperOptions/res/values-te/strings.xml b/tests/CarDeveloperOptions/res/values-te/strings.xml
index b646142..6e54dda 100644
--- a/tests/CarDeveloperOptions/res/values-te/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-te/strings.xml
@@ -2323,9 +2323,9 @@
<string name="smart_battery_manager_title" msgid="5744035036663849515">"బ్యాటరీ మేనేజర్"</string>
<string name="smart_battery_title" msgid="4919670408532804351">"యాప్లను ఆటోమేటిక్గా నిర్వహించండి"</string>
<string name="smart_battery_summary" msgid="640027046471198174">"మీరు తరచుగా ఉపయోగించని యాప్ల కోసం బ్యాటరీని పరిమితం చేయండి"</string>
- <string name="smart_battery_footer" product="default" msgid="3971715848890205632">"యాప్లు బ్యాటరీ శక్తిని హరిస్తున్నయని బ్యాటరీ మేనేజర్ గుర్తించినప్పుడు, ఈ యాప్లను పరిమితం చేసే ఎంపిక మీకు ఉంటుంది. పరిమితం చేయబడిన యాప్లు సరిగ్గా పనిచేయకపోవచ్చు మరియు నోటిఫికేషన్లు రావడానికి ఆలస్యం కావచ్చు."</string>
- <string name="smart_battery_footer" product="tablet" msgid="3971715848890205632">"యాప్లు బ్యాటరీ శక్తిని హరిస్తున్నయని బ్యాటరీ మేనేజర్ గుర్తించినప్పుడు, ఈ యాప్లను పరిమితం చేసే ఎంపిక మీకు ఉంటుంది. పరిమితం చేయబడిన యాప్లు సరిగ్గా పనిచేయకపోవచ్చు మరియు నోటిఫికేషన్లు రావడానికి ఆలస్యం కావచ్చు."</string>
- <string name="smart_battery_footer" product="device" msgid="3971715848890205632">"యాప్లు బ్యాటరీ శక్తిని హరిస్తున్నయని బ్యాటరీ మేనేజర్ గుర్తించినప్పుడు, ఈ యాప్లను పరిమితం చేసే ఎంపిక మీకు ఉంటుంది. పరిమితం చేయబడిన యాప్లు సరిగ్గా పనిచేయకపోవచ్చు మరియు నోటిఫికేషన్లు రావడానికి ఆలస్యం కావచ్చు."</string>
+ <string name="smart_battery_footer" product="default" msgid="3971715848890205632">"ఏవైనా యాప్లు బ్యాటరీని అధికంగా వాడుతున్నాయని బ్యాటరీ మేనేజర్ గుర్తించినప్పుడు, ఆ యాప్లను పరిమితం చేసే ఎంపిక మీకు ఉంటుంది. పరిమితం చేయబడిన యాప్లు సరిగ్గా పనిచేయకపోవచ్చు, వాటి నోటిఫికేషన్లు రావడానికి ఆలస్యం కావచ్చు."</string>
+ <string name="smart_battery_footer" product="tablet" msgid="3971715848890205632">"ఏవైనా యాప్లు బ్యాటరీని అధికంగా వాడుతున్నాయని బ్యాటరీ మేనేజర్ గుర్తించినప్పుడు, ఆ యాప్లను పరిమితం చేసే ఎంపిక మీకు ఉంటుంది. పరిమితం చేయబడిన యాప్లు సరిగ్గా పనిచేయకపోవచ్చు, వాటి నోటిఫికేషన్లు రావడానికి ఆలస్యం కావచ్చు."</string>
+ <string name="smart_battery_footer" product="device" msgid="3971715848890205632">"ఏవైనా యాప్లు బ్యాటరీని అధికంగా వాడుతున్నాయని బ్యాటరీ మేనేజర్ గుర్తించినప్పుడు, ఆ యాప్లను పరిమితం చేసే ఎంపిక మీకు ఉంటుంది. పరిమితం చేయబడిన యాప్లు సరిగ్గా పనిచేయకపోవచ్చు, వాటి నోటిఫికేషన్లు రావడానికి ఆలస్యం కావచ్చు."</string>
<string name="restricted_app_title" msgid="4957644700640127606">"నియంత్రించబడిన యాప్లు"</string>
<plurals name="restricted_app_summary" formatted="false" msgid="7609538735465186040">
<item quantity="other">%1$d యాప్ల కోసం బ్యాటరీ వినియోగాన్ని పరిమితం చేయడం</item>
@@ -3041,7 +3041,7 @@
<string name="connected_devices_dashboard_no_driving_mode_summary" msgid="3524409078596318803">"బ్లూటూత్, NFC"</string>
<string name="connected_devices_dashboard_no_driving_mode_no_nfc_summary" msgid="7881286613528299400">"బ్లూటూత్"</string>
<string name="app_and_notification_dashboard_title" msgid="8448096608058843730">"యాప్లు & నోటిఫికేషన్లు"</string>
- <string name="app_and_notification_dashboard_summary" msgid="4165181440955038145">"అసిస్టెంట్, ఇటీవలి యాప్లు, డిఫాల్ట్ యాప్లు"</string>
+ <string name="app_and_notification_dashboard_summary" msgid="4165181440955038145">"Assistant, ఇటీవలి యాప్లు, డిఫాల్ట్ యాప్లు"</string>
<string name="notification_settings_work_profile" msgid="7190550347842400029">"కార్యాలయ ప్రొఫైల్లో ఉన్న యాప్లకు సంబంధించి నోటిఫికేషన్ యాక్సెస్ అందుబాటులో లేదు."</string>
<string name="account_dashboard_title" msgid="4734300939532555885">"ఖాతాలు"</string>
<string name="account_dashboard_default_summary" msgid="6822549669771936206">"ఖాతాలు జోడించబడలేదు"</string>
@@ -4473,7 +4473,7 @@
<string name="hwui_force_dark_title" msgid="3744825212652331461">"ఫోర్స్-డార్క్ను అధిగమించడం"</string>
<string name="hwui_force_dark_summary" msgid="2051891908674765817">"ఫోర్స్-డార్క్ ఫీచర్ను అధిగమించడం ఎల్లప్పుడూ ఆన్లో ఉండాలి"</string>
<string name="privacy_dashboard_title" msgid="8764930992456607513">"గోప్యత"</string>
- <string name="privacy_dashboard_summary" msgid="7916431309860824945">"అనుమతులు, ఖాతా కార్యకలాపం, వ్యక్తిగత డేటా"</string>
+ <string name="privacy_dashboard_summary" msgid="7916431309860824945">"అనుమతులు, ఖాతా యాక్టివిటీ, వ్యక్తిగత డేటా"</string>
<string name="contextual_card_dismiss_remove" msgid="1750420285615827309">"తీసివేయి"</string>
<string name="contextual_card_dismiss_keep" msgid="3204450672928193661">"Keep"</string>
<string name="contextual_card_dismiss_confirm_message" msgid="2352465079667730312">"ఈ సూచనని తీసేయాలా?"</string>
diff --git a/tests/CarDeveloperOptions/res/values-uk/strings.xml b/tests/CarDeveloperOptions/res/values-uk/strings.xml
index 2816cc8..b39d1a4 100644
--- a/tests/CarDeveloperOptions/res/values-uk/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-uk/strings.xml
@@ -1246,7 +1246,7 @@
<string name="adaptive_sleep_summary_off" msgid="2891586225954973431">"Вимкнено"</string>
<string name="adaptive_sleep_description" msgid="812673735459170009">"Не дає екрану вимикатись, якщо ви на нього дивитесь."</string>
<string name="adaptive_sleep_privacy" msgid="5706802215479902623">"Розпізнавання уваги за допомогою передньої камери визначає, чи дивиться користувач на екран. Ця функція працює лише на пристрої, не зберігає зображень і не надсилає їх у Google."</string>
- <string name="night_display_title" msgid="1305002424893349814">"Нічний режим"</string>
+ <string name="night_display_title" msgid="1305002424893349814">"Нічний екран"</string>
<string name="night_display_text" msgid="5330502493684652527">"У нічному режимі екран набуває бурштинового відтінку. Це знімає напруження очей при тьмяному освітленні та допомагає легше заснути."</string>
<string name="night_display_auto_mode_title" msgid="8493573087102481588">"Розклад"</string>
<string name="night_display_auto_mode_never" msgid="2897444637217807088">"Ніколи"</string>
@@ -4464,7 +4464,7 @@
<string name="change_wifi_state_title" msgid="5140754955787584174">"Керування Wi-Fi"</string>
<string name="change_wifi_state_app_detail_switch" msgid="6489090744937816260">"Дозволити додатку керувати Wi-Fi"</string>
<string name="change_wifi_state_app_detail_summary" msgid="614854822469259860">"Дозволити цьому додатку вмикати чи вимикати Wi-Fi, шукати мережі Wi-Fi та підключатися до них, додавати або видаляти мережі чи запускати лише локальну точку доступу"</string>
- <string name="media_output_title" msgid="8710632337456601848">"Відтворювати медіа-вміст у додатку"</string>
+ <string name="media_output_title" msgid="8710632337456601848">"Відтворення медіаконтенту"</string>
<string name="media_output_default_summary" msgid="3159237976830415584">"Цей пристрій"</string>
<string name="media_output_summary" product="default" msgid="6294261435613551178">"Телефон"</string>
<string name="media_output_summary" product="tablet" msgid="6672024060360538526">"Планшет"</string>
diff --git a/tests/CarDeveloperOptions/res/values-ur/strings.xml b/tests/CarDeveloperOptions/res/values-ur/strings.xml
index 787d550..4a881ea 100644
--- a/tests/CarDeveloperOptions/res/values-ur/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-ur/strings.xml
@@ -1128,7 +1128,7 @@
<string name="notification_sound_title" msgid="6812164482799723931">"ڈیفالٹ اطلاع کی آواز"</string>
<string name="incoming_call_volume_title" msgid="4736570528754310450">"رنگ ٹون"</string>
<string name="notification_volume_title" msgid="6022562909288085275">"اطلاع"</string>
- <string name="checkbox_notification_same_as_incoming_call" msgid="7312942422655861175">"اطلاعات کیلئے آنے والی کال کا والیوم استعمال کریں"</string>
+ <string name="checkbox_notification_same_as_incoming_call" msgid="7312942422655861175">"اطلاعات کیلئے اِن کمنگ کال کا والیوم استعمال کریں"</string>
<string name="home_work_profile_not_supported" msgid="6137073723297076818">"کام کے پروفائلز کا تعاون نہیں کرتا ہے"</string>
<string name="notification_sound_dialog_title" msgid="6653341809710423276">"ڈیفالٹ اطلاع کی آواز"</string>
<string name="media_volume_title" msgid="1030438549497800914">"میڈیا"</string>
@@ -3401,7 +3401,7 @@
<item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> زمرے</item>
<item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g> زمرہ</item>
</plurals>
- <string name="no_channels" msgid="8884254729302501652">"اس ایپ نے کوئی اطلاعات شائع نہیں کیا ہے"</string>
+ <string name="no_channels" msgid="8884254729302501652">"اس ایپ نے کوئی اطلاعات شائع نہیں کی ہیں"</string>
<string name="app_settings_link" msgid="8465287765715790984">"ایپ میں اضافی ترتیبات"</string>
<string name="app_notification_listing_summary_zero" msgid="4047782719487686699">"سبھی ایپس کے لیے آن ہے"</string>
<plurals name="app_notification_listing_summary_others" formatted="false" msgid="1161774065480666519">
diff --git a/tests/CarDeveloperOptions/res/values-uz/strings.xml b/tests/CarDeveloperOptions/res/values-uz/strings.xml
index 401fb18..f2fb286 100644
--- a/tests/CarDeveloperOptions/res/values-uz/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-uz/strings.xml
@@ -732,7 +732,7 @@
<string name="bluetooth_pairing_request" msgid="7221745525632573125">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> qurilmasiga ulansinmi?"</string>
<string name="bluetooth_pairing_key_msg" msgid="1139230917419961975">"Bluetooth orqali ulanish kodi"</string>
<string name="bluetooth_enter_passkey_msg" msgid="6205151011298670207">"Ulanish kodini kiriting va keyin “Return” yoki “Enter” tugmasini bosing"</string>
- <string name="bluetooth_enable_alphanumeric_pin" msgid="9138308197078115672">"PIN-kod harflar va belgilardan iborat bo‘ladi"</string>
+ <string name="bluetooth_enable_alphanumeric_pin" msgid="9138308197078115672">"Harflar yoki maxsus belgilardan iborat PIN kod"</string>
<string name="bluetooth_pin_values_hint" msgid="8044671726261326240">"Odatda 0000 yoki 1234"</string>
<string name="bluetooth_pin_values_hint_16_digits" msgid="2665983525706661525">"16 ta raqam bo‘lishi lozim"</string>
<string name="bluetooth_enter_pin_other_device" msgid="1727015949040507621">"Ushbu PIN kodni boshqa qurilmada ham terish lozim bo‘lishi mumkin."</string>
@@ -2754,7 +2754,7 @@
<string name="data_usage_metered_no" msgid="1961524615778610008">"Bepul"</string>
<string name="data_usage_disclaimer" msgid="4683321532922590425">"Aloqa operatorining hisob-kitobi qurilmanikidan farq qilishi mumkin."</string>
<string name="cryptkeeper_emergency_call" msgid="4625420047524693116">"Favqulodda chaqiruv"</string>
- <string name="cryptkeeper_return_to_call" msgid="4433942821196822815">"Chaqiruvga qaytish"</string>
+ <string name="cryptkeeper_return_to_call" msgid="4433942821196822815">"Suhbatga qaytish"</string>
<string name="vpn_name" msgid="3538818658670774080">"Tarmoq nomi"</string>
<string name="vpn_type" msgid="6389116710008658550">"Turi"</string>
<string name="vpn_server" msgid="5216559017318406820">"Server manzili"</string>
diff --git a/tests/CarDeveloperOptions/res/values-vi/strings.xml b/tests/CarDeveloperOptions/res/values-vi/strings.xml
index ab20398..1efea2d 100644
--- a/tests/CarDeveloperOptions/res/values-vi/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-vi/strings.xml
@@ -34,7 +34,7 @@
<string name="radio_info_data_connection_enable" msgid="2554249462719717119">"Bật kết nối dữ liệu"</string>
<string name="radio_info_data_connection_disable" msgid="2430609627397999371">"Tắt kết nối dữ liệu"</string>
<string name="volte_provisioned_switch_string" msgid="6326756678226686704">"Đã cấp phép VoLTE"</string>
- <string name="vt_provisioned_switch_string" msgid="7458479879009293613">"Đã cấp phép gọi điện video"</string>
+ <string name="vt_provisioned_switch_string" msgid="7458479879009293613">"Đã cấp phép gọi video"</string>
<string name="wfc_provisioned_switch_string" msgid="5446697646596639516">"Đã cấp phép gọi điện qua Wi-Fi"</string>
<string name="eab_provisioned_switch_string" msgid="3921103790584572430">"Đã cấp phép hiện diện/EAB"</string>
<string name="cbrs_data_switch_string" msgid="9120919504831536183">"Dữ liệu Cbrs"</string>
@@ -53,7 +53,7 @@
<string name="radio_info_ims_reg_status_not_registered" msgid="1286050699734226077">"Chưa được đăng ký"</string>
<string name="radio_info_ims_feature_status_available" msgid="2040629393134756058">"Khả dụng"</string>
<string name="radio_info_ims_feature_status_unavailable" msgid="3348223769202693596">"Không khả dụng"</string>
- <string name="radio_info_ims_reg_status" msgid="4771711884059371514">"Đăng ký IMS: <xliff:g id="STATUS">%1$s</xliff:g>\nThoại trên nền LTE: <xliff:g id="AVAILABILITY_0">%2$s</xliff:g>\nThoại qua Wi-Fi: <xliff:g id="AVAILABILITY_1">%3$s</xliff:g>\nGọi điện video: <xliff:g id="AVAILABILITY_2">%4$s</xliff:g>\nGiao diện UT: <xliff:g id="AVAILABILITY_3">%5$s</xliff:g>"</string>
+ <string name="radio_info_ims_reg_status" msgid="4771711884059371514">"Đăng ký IMS: <xliff:g id="STATUS">%1$s</xliff:g>\nThoại trên nền LTE: <xliff:g id="AVAILABILITY_0">%2$s</xliff:g>\nThoại qua Wi-Fi: <xliff:g id="AVAILABILITY_1">%3$s</xliff:g>\nGọi video: <xliff:g id="AVAILABILITY_2">%4$s</xliff:g>\nGiao diện UT: <xliff:g id="AVAILABILITY_3">%5$s</xliff:g>"</string>
<string name="radioInfo_service_in" msgid="1297020186765943857">"Đang sử dụng"</string>
<string name="radioInfo_service_out" msgid="8460363463722476510">"Không có dịch vụ"</string>
<string name="radioInfo_service_emergency" msgid="7674989004735662599">"Chỉ cuộc gọi khẩn cấp"</string>
@@ -3403,8 +3403,8 @@
<item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> loại</item>
<item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g> loại</item>
</plurals>
- <string name="no_channels" msgid="8884254729302501652">"Ứng dụng chưa đăng bất kỳ thông báo nào"</string>
- <string name="app_settings_link" msgid="8465287765715790984">"Cài đặt bổ sung trong ứng dụng"</string>
+ <string name="no_channels" msgid="8884254729302501652">"Ứng dụng này chưa đăng bất kỳ thông báo nào"</string>
+ <string name="app_settings_link" msgid="8465287765715790984">"Tùy chọn cài đặt bổ sung trong ứng dụng"</string>
<string name="app_notification_listing_summary_zero" msgid="4047782719487686699">"Đang bật cho tất cả ứng dụng"</string>
<plurals name="app_notification_listing_summary_others" formatted="false" msgid="1161774065480666519">
<item quantity="other">Tắt cho <xliff:g id="COUNT_1">%d</xliff:g> ứng dụng</item>
@@ -3422,7 +3422,7 @@
<string name="notification_content_block_summary" msgid="2743896875255591743">"Không bao giờ hiển thị thông báo trong ngăn thông báo hoặc trên thiết bị ngoại vi"</string>
<string name="notification_badge_title" msgid="8989086619255666442">"Cho phép dấu chấm thông báo"</string>
<string name="notification_channel_badge_title" msgid="8228215248332054612">"Hiển thị dấu chấm thông báo"</string>
- <string name="app_notification_override_dnd_title" msgid="1757042206738172601">"Ghi đè Không làm phiền"</string>
+ <string name="app_notification_override_dnd_title" msgid="1757042206738172601">"Vô hiệu hóa chế độ Không làm phiền"</string>
<string name="app_notification_override_dnd_summary" msgid="3152957611171210980">"Cho phép những thông báo này tiếp tục làm gián đoạn khi chế độ Không làm phiền đang bật"</string>
<string name="app_notification_visibility_override_title" msgid="2349335170165637672">"Trên màn hình khóa"</string>
<string name="app_notification_row_banned" msgid="2079325338122151677">"Bị chặn"</string>
@@ -3511,8 +3511,8 @@
<string name="zen_mode_bypassing_apps" msgid="3080739479028713449">"Cho phép ứng dụng ghi đè"</string>
<string name="zen_mode_bypassing_apps_title" msgid="2115024664615538847">"Ứng dụng ngoại lệ"</string>
<plurals name="zen_mode_bypassing_apps_subtext" formatted="false" msgid="8723144434730871572">
- <item quantity="other">Thông báo từ <xliff:g id="NUMBER">%1$d</xliff:g> ứng dụng có thể ghi đè chế độ Không làm phiền</item>
- <item quantity="one">Thông báo từ 1 ứng dụng có thể ghi đè chế độ Không làm phiền</item>
+ <item quantity="other">Thông báo từ <xliff:g id="NUMBER">%1$d</xliff:g> ứng dụng có thể vô hiệu hóa chế độ Không làm phiền</item>
+ <item quantity="one">Thông báo từ 1 ứng dụng có thể vô hiệu hóa chế độ Không làm phiền</item>
</plurals>
<string name="zen_mode_events_list" msgid="8578102701815684873">"sự kiện"</string>
<string name="zen_mode_all_callers" msgid="4455039040077343838">"bất kỳ ai"</string>
diff --git a/tests/CarDeveloperOptions/res/values-zh-rHK/strings.xml b/tests/CarDeveloperOptions/res/values-zh-rHK/strings.xml
index 51500a7..5e42e3c 100644
--- a/tests/CarDeveloperOptions/res/values-zh-rHK/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-zh-rHK/strings.xml
@@ -3423,7 +3423,7 @@
<string name="notification_content_block_summary" msgid="2743896875255591743">"永不在通知欄或周邊裝置上顯示通知"</string>
<string name="notification_badge_title" msgid="8989086619255666442">"允許通知圓點"</string>
<string name="notification_channel_badge_title" msgid="8228215248332054612">"顯示通知圓點"</string>
- <string name="app_notification_override_dnd_title" msgid="1757042206738172601">"蓋過「請勿騷擾」設定"</string>
+ <string name="app_notification_override_dnd_title" msgid="1757042206738172601">"忽略「請勿騷擾」設定"</string>
<string name="app_notification_override_dnd_summary" msgid="3152957611171210980">"「請勿騷擾」模式開啟時繼續接收這些通知"</string>
<string name="app_notification_visibility_override_title" msgid="2349335170165637672">"在上鎖畫面上"</string>
<string name="app_notification_row_banned" msgid="2079325338122151677">"已封鎖"</string>
@@ -3512,8 +3512,8 @@
<string name="zen_mode_bypassing_apps" msgid="3080739479028713449">"允許應用程式取代「請勿騷擾」"</string>
<string name="zen_mode_bypassing_apps_title" msgid="2115024664615538847">"應用程式例外情況"</string>
<plurals name="zen_mode_bypassing_apps_subtext" formatted="false" msgid="8723144434730871572">
- <item quantity="other"><xliff:g id="NUMBER">%1$d</xliff:g> 個應用程式的通知可蓋過「請勿騷擾」設定</item>
- <item quantity="one">1 個應用程式的通知可蓋過「請勿騷擾」設定</item>
+ <item quantity="other"><xliff:g id="NUMBER">%1$d</xliff:g> 個應用程式的通知可忽略「請勿騷擾」設定</item>
+ <item quantity="one">1 個應用程式的通知可忽略「請勿騷擾」設定</item>
</plurals>
<string name="zen_mode_events_list" msgid="8578102701815684873">"活動"</string>
<string name="zen_mode_all_callers" msgid="4455039040077343838">"任何人"</string>
diff --git a/tests/CarSecurityPermissionTest/src/com/android/car/media/CarAudioManagerPermissionTest.java b/tests/CarSecurityPermissionTest/src/com/android/car/media/CarAudioManagerPermissionTest.java
index cf98255..1e4391b 100644
--- a/tests/CarSecurityPermissionTest/src/com/android/car/media/CarAudioManagerPermissionTest.java
+++ b/tests/CarSecurityPermissionTest/src/com/android/car/media/CarAudioManagerPermissionTest.java
@@ -25,16 +25,12 @@
import static com.google.common.truth.Truth.assertThat;
-import static org.junit.Assume.assumeNotNull;
import static org.testng.Assert.expectThrows;
import android.car.Car;
import android.car.media.CarAudioManager;
import android.content.Context;
-import android.hardware.display.DisplayManager;
import android.os.Handler;
-import android.view.Display;
-import android.view.DisplayAddress;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.platform.app.InstrumentationRegistry;
@@ -43,9 +39,7 @@
import org.junit.Test;
import org.junit.runner.RunWith;
-import java.util.Arrays;
import java.util.Objects;
-import java.util.Optional;
/**
* This class contains security permission tests for the {@link CarAudioManager}'s system APIs.
@@ -220,22 +214,6 @@
}
@Test
- public void getZoneIdForDisplayPermission() {
- Display display = getPhysicalDisplay();
- assumeNotNull(display);
- Exception e = expectThrows(SecurityException.class,
- () -> mCarAudioManager.getZoneIdForDisplay(display));
- assertThat(e.getMessage()).contains(PERMISSION_CAR_CONTROL_AUDIO_SETTINGS);
- }
-
- @Test
- public void getZoneIdForDisplayPortIdPermission() {
- Exception e = expectThrows(SecurityException.class,
- () -> mCarAudioManager.getZoneIdForDisplayPortId(Byte.MAX_VALUE));
- assertThat(e.getMessage()).contains(PERMISSION_CAR_CONTROL_AUDIO_SETTINGS);
- }
-
- @Test
public void getOutputDeviceForUsagePermission() {
Exception e = expectThrows(SecurityException.class,
() -> mCarAudioManager.getOutputDeviceForUsage(PRIMARY_AUDIO_ZONE, USAGE_MEDIA));
@@ -255,12 +233,4 @@
() -> mCarAudioManager.onCarDisconnected());
assertThat(e.getMessage()).contains(PERMISSION_CAR_CONTROL_AUDIO_VOLUME);
}
-
- private Display getPhysicalDisplay() {
- DisplayManager displayManager = (DisplayManager) mContext.getSystemService(
- Context.DISPLAY_SERVICE);
- Optional<Display> physical = Arrays.stream(displayManager.getDisplays()).filter(
- display -> (display.getAddress() instanceof DisplayAddress.Physical)).findFirst();
- return physical.orElse(null);
- }
}
diff --git a/tests/CarSecurityPermissionTest/src/com/android/car/user/CarUserManagerPermissionTest.java b/tests/CarSecurityPermissionTest/src/com/android/car/user/CarUserManagerPermissionTest.java
index b0edd13..3a5ea1b 100644
--- a/tests/CarSecurityPermissionTest/src/com/android/car/user/CarUserManagerPermissionTest.java
+++ b/tests/CarSecurityPermissionTest/src/com/android/car/user/CarUserManagerPermissionTest.java
@@ -82,6 +82,12 @@
}
@Test
+ public void testRemoveUserPermission() throws Exception {
+ Exception e = expectThrows(SecurityException.class, () -> mCarUserManager.removeUser(100));
+ assertThat(e.getMessage()).contains(MANAGE_USERS);
+ }
+
+ @Test
public void testAddListenerPermission() {
UserLifecycleListener listener = (e) -> { };
diff --git a/tests/carservice_test/res/raw/car_audio_configuration.xml b/tests/carservice_test/res/raw/car_audio_configuration.xml
index b4bb08a..e1d75df 100644
--- a/tests/carservice_test/res/raw/car_audio_configuration.xml
+++ b/tests/carservice_test/res/raw/car_audio_configuration.xml
@@ -21,10 +21,6 @@
</device>
</group>
</volumeGroups>
- <displays>
- <display port="1"/>
- <display port="2"/>
- </displays>
</zone>
<zone name="rear seat zone" audioZoneId="2">
<volumeGroups>
diff --git a/tests/carservice_test/res/raw/car_audio_configuration_V1.xml b/tests/carservice_test/res/raw/car_audio_configuration_V1.xml
index 4aaaa6c..26b1c08 100644
--- a/tests/carservice_test/res/raw/car_audio_configuration_V1.xml
+++ b/tests/carservice_test/res/raw/car_audio_configuration_V1.xml
@@ -33,10 +33,6 @@
</device>
</group>
</volumeGroups>
- <displays>
- <display port="1"/>
- <display port="2"/>
- </displays>
</zone>
<zone name="rear seat zone">
<volumeGroups>
diff --git a/tests/carservice_test/res/raw/car_audio_configuration_V1_with_non_legacy_contexts.xml b/tests/carservice_test/res/raw/car_audio_configuration_V1_with_non_legacy_contexts.xml
index 03e9a0f..5c39ceb 100644
--- a/tests/carservice_test/res/raw/car_audio_configuration_V1_with_non_legacy_contexts.xml
+++ b/tests/carservice_test/res/raw/car_audio_configuration_V1_with_non_legacy_contexts.xml
@@ -33,10 +33,6 @@
</device>
</group>
</volumeGroups>
- <displays>
- <display port="1"/>
- <display port="2"/>
- </displays>
</zone>
<zone name="rear seat zone">
<volumeGroups>
diff --git a/tests/carservice_test/res/raw/car_audio_configuration_duplicate_audio_zone_id.xml b/tests/carservice_test/res/raw/car_audio_configuration_duplicate_audio_zone_id.xml
index 4b5abc5..8561968 100644
--- a/tests/carservice_test/res/raw/car_audio_configuration_duplicate_audio_zone_id.xml
+++ b/tests/carservice_test/res/raw/car_audio_configuration_duplicate_audio_zone_id.xml
@@ -37,10 +37,6 @@
</device>
</group>
</volumeGroups>
- <displays>
- <display port="1"/>
- <display port="2"/>
- </displays>
</zone>
<zone name="rear seat zone" audioZoneId="1" occupantZoneId="2">
<volumeGroups>
diff --git a/tests/carservice_test/res/raw/car_audio_configuration_duplicate_occupant_zone_id.xml b/tests/carservice_test/res/raw/car_audio_configuration_duplicate_occupant_zone_id.xml
index 1d15b36..8c1d0e8 100644
--- a/tests/carservice_test/res/raw/car_audio_configuration_duplicate_occupant_zone_id.xml
+++ b/tests/carservice_test/res/raw/car_audio_configuration_duplicate_occupant_zone_id.xml
@@ -37,10 +37,6 @@
</device>
</group>
</volumeGroups>
- <displays>
- <display port="1"/>
- <display port="2"/>
- </displays>
</zone>
<zone name="rear seat zone" audioZoneId="2" occupantZoneId="1">
<volumeGroups>
diff --git a/tests/carservice_test/res/raw/car_audio_configuration_duplicate_ports.xml b/tests/carservice_test/res/raw/car_audio_configuration_duplicate_ports.xml
index 288e8fb..dba13a2 100644
--- a/tests/carservice_test/res/raw/car_audio_configuration_duplicate_ports.xml
+++ b/tests/carservice_test/res/raw/car_audio_configuration_duplicate_ports.xml
@@ -17,10 +17,6 @@
</device>
</group>
</volumeGroups>
- <displays>
- <display port="1"/>
- <display port="1"/>
- </displays>
</zone>
</zones>
</carAudioConfiguration>
diff --git a/tests/carservice_test/res/raw/car_audio_configuration_empty_occupant_zone_id.xml b/tests/carservice_test/res/raw/car_audio_configuration_empty_occupant_zone_id.xml
index 182e606..972da37 100644
--- a/tests/carservice_test/res/raw/car_audio_configuration_empty_occupant_zone_id.xml
+++ b/tests/carservice_test/res/raw/car_audio_configuration_empty_occupant_zone_id.xml
@@ -37,10 +37,6 @@
</device>
</group>
</volumeGroups>
- <displays>
- <display port="1"/>
- <display port="2"/>
- </displays>
</zone>
<zone name="rear seat zone" audioZoneId="2">
<volumeGroups>
diff --git a/tests/carservice_test/res/raw/car_audio_configuration_negative_audio_zone_id.xml b/tests/carservice_test/res/raw/car_audio_configuration_negative_audio_zone_id.xml
index acdb784..060934b 100644
--- a/tests/carservice_test/res/raw/car_audio_configuration_negative_audio_zone_id.xml
+++ b/tests/carservice_test/res/raw/car_audio_configuration_negative_audio_zone_id.xml
@@ -37,10 +37,6 @@
</device>
</group>
</volumeGroups>
- <displays>
- <display port="1"/>
- <display port="2"/>
- </displays>
</zone>
<zone name="rear seat zone" audioZoneId="2">
<volumeGroups>
diff --git a/tests/carservice_test/res/raw/car_audio_configuration_negative_occupant_zone_id.xml b/tests/carservice_test/res/raw/car_audio_configuration_negative_occupant_zone_id.xml
index b7d7a62..cffad51 100644
--- a/tests/carservice_test/res/raw/car_audio_configuration_negative_occupant_zone_id.xml
+++ b/tests/carservice_test/res/raw/car_audio_configuration_negative_occupant_zone_id.xml
@@ -37,10 +37,6 @@
</device>
</group>
</volumeGroups>
- <displays>
- <display port="1"/>
- <display port="2"/>
- </displays>
</zone>
<zone name="rear seat zone" audioZoneId="2">
<volumeGroups>
diff --git a/tests/carservice_test/res/raw/car_audio_configuration_non_numerical_audio_zone_id.xml b/tests/carservice_test/res/raw/car_audio_configuration_non_numerical_audio_zone_id.xml
index 09168a6..8e1c41b 100644
--- a/tests/carservice_test/res/raw/car_audio_configuration_non_numerical_audio_zone_id.xml
+++ b/tests/carservice_test/res/raw/car_audio_configuration_non_numerical_audio_zone_id.xml
@@ -37,10 +37,6 @@
</device>
</group>
</volumeGroups>
- <displays>
- <display port="1"/>
- <display port="2"/>
- </displays>
</zone>
<zone name="rear seat zone" audioZoneId="2">
<volumeGroups>
diff --git a/tests/carservice_test/res/raw/car_audio_configuration_non_numerical_occupant_zone_id.xml b/tests/carservice_test/res/raw/car_audio_configuration_non_numerical_occupant_zone_id.xml
index af57c24..f00b169 100644
--- a/tests/carservice_test/res/raw/car_audio_configuration_non_numerical_occupant_zone_id.xml
+++ b/tests/carservice_test/res/raw/car_audio_configuration_non_numerical_occupant_zone_id.xml
@@ -37,10 +37,6 @@
</device>
</group>
</volumeGroups>
- <displays>
- <display port="1"/>
- <display port="2"/>
- </displays>
</zone>
<zone name="rear seat zone" audioZoneId="2">
<volumeGroups>
diff --git a/tests/carservice_test/res/raw/car_audio_configuration_non_numerical_port.xml b/tests/carservice_test/res/raw/car_audio_configuration_non_numerical_port.xml
index f6995bc..9adef24 100644
--- a/tests/carservice_test/res/raw/car_audio_configuration_non_numerical_port.xml
+++ b/tests/carservice_test/res/raw/car_audio_configuration_non_numerical_port.xml
@@ -21,9 +21,6 @@
</device>
</group>
</volumeGroups>
- <displays>
- <display port="one"/>
- </displays>
</zone>
</zones>
</carAudioConfiguration>
diff --git a/tests/carservice_test/res/raw/car_audio_configuration_non_primary_zone_with_primary_audio_zone_id.xml b/tests/carservice_test/res/raw/car_audio_configuration_non_primary_zone_with_primary_audio_zone_id.xml
index f822469..4364a1d 100644
--- a/tests/carservice_test/res/raw/car_audio_configuration_non_primary_zone_with_primary_audio_zone_id.xml
+++ b/tests/carservice_test/res/raw/car_audio_configuration_non_primary_zone_with_primary_audio_zone_id.xml
@@ -33,10 +33,6 @@
</device>
</group>
</volumeGroups>
- <displays>
- <display port="1"/>
- <display port="2"/>
- </displays>
</zone>
<zone name="rear seat zone" audioZoneId="0">
<volumeGroups>
diff --git a/tests/carservice_test/res/raw/car_audio_configuration_output_address_does_not_exist.xml b/tests/carservice_test/res/raw/car_audio_configuration_output_address_does_not_exist.xml
index 83c054c..a359d36 100644
--- a/tests/carservice_test/res/raw/car_audio_configuration_output_address_does_not_exist.xml
+++ b/tests/carservice_test/res/raw/car_audio_configuration_output_address_does_not_exist.xml
@@ -37,10 +37,6 @@
</device>
</group>
</volumeGroups>
- <displays>
- <display port="1"/>
- <display port="2"/>
- </displays>
</zone>
<zone name="rear seat zone" audioZoneId="2">
<volumeGroups>
diff --git a/tests/carservice_test/res/raw/car_audio_configuration_primary_zone_with_non_zero_audio_zone_id.xml b/tests/carservice_test/res/raw/car_audio_configuration_primary_zone_with_non_zero_audio_zone_id.xml
index 6f845e7..2d25716 100644
--- a/tests/carservice_test/res/raw/car_audio_configuration_primary_zone_with_non_zero_audio_zone_id.xml
+++ b/tests/carservice_test/res/raw/car_audio_configuration_primary_zone_with_non_zero_audio_zone_id.xml
@@ -37,10 +37,6 @@
</device>
</group>
</volumeGroups>
- <displays>
- <display port="1"/>
- <display port="2"/>
- </displays>
</zone>
<zone name="rear seat zone" audioZoneId="2">
<volumeGroups>
diff --git a/tests/carservice_test/src/com/android/car/audio/CarAudioZonesHelperTest.java b/tests/carservice_test/src/com/android/car/audio/CarAudioZonesHelperTest.java
index a37c0e4..fce0a78 100644
--- a/tests/carservice_test/src/com/android/car/audio/CarAudioZonesHelperTest.java
+++ b/tests/carservice_test/src/com/android/car/audio/CarAudioZonesHelperTest.java
@@ -28,7 +28,6 @@
import android.media.AudioDeviceAttributes;
import android.media.AudioDeviceInfo;
import android.util.SparseIntArray;
-import android.view.DisplayAddress;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
@@ -293,56 +292,6 @@
}
@Test
- public void loadAudioZones_parsesPhysicalDisplayAddresses() throws Exception {
- CarAudioZonesHelper cazh = new CarAudioZonesHelper(mCarAudioSettings, mInputStream,
- mCarAudioOutputDeviceInfos, mInputAudioDeviceInfos);
-
- CarAudioZone[] zones = cazh.loadAudioZones();
-
- CarAudioZone primaryZone = zones[0];
- List<DisplayAddress.Physical> primaryPhysicals = primaryZone.getPhysicalDisplayAddresses();
- assertThat(primaryPhysicals).hasSize(2);
- assertThat(primaryPhysicals.get(0).getPort()).isEqualTo(1);
- assertThat(primaryPhysicals.get(1).getPort()).isEqualTo(2);
- }
-
- @Test
- public void loadAudioZones_defaultsDisplayAddressesToEmptyList() throws Exception {
- CarAudioZonesHelper cazh = new CarAudioZonesHelper(mCarAudioSettings, mInputStream,
- mCarAudioOutputDeviceInfos, mInputAudioDeviceInfos);
-
- CarAudioZone[] zones = cazh.loadAudioZones();
-
- CarAudioZone rseZone = zones[1];
- List<DisplayAddress.Physical> rsePhysicals = rseZone.getPhysicalDisplayAddresses();
- assertThat(rsePhysicals).isEmpty();
- }
-
- @Test(expected = RuntimeException.class)
- public void loadAudioZones_throwsOnDuplicatePorts() throws Exception {
- try (InputStream duplicatePortStream = mContext.getResources().openRawResource(
- R.raw.car_audio_configuration_duplicate_ports)) {
- CarAudioZonesHelper cazh =
- new CarAudioZonesHelper(mCarAudioSettings, duplicatePortStream,
- mCarAudioOutputDeviceInfos, mInputAudioDeviceInfos);
-
- cazh.loadAudioZones();
- }
- }
-
- @Test
- public void loadAudioZones_throwsOnNonNumericalPort() {
- InputStream duplicatePortStream = mContext.getResources().openRawResource(
- R.raw.car_audio_configuration_non_numerical_port);
- CarAudioZonesHelper cazh = new CarAudioZonesHelper(mCarAudioSettings, duplicatePortStream,
- mCarAudioOutputDeviceInfos, mInputAudioDeviceInfos);
-
- IllegalArgumentException exception = expectThrows(IllegalArgumentException.class,
- cazh::loadAudioZones);
- assertThat(exception).hasMessageThat().contains("Port one is not a number");
- }
-
- @Test
public void loadAudioZones_passesOnMissingAudioZoneIdForPrimary() throws Exception {
try (InputStream missingAudioZoneIdStream = mContext.getResources().openRawResource(
R.raw.car_audio_configuration_no_audio_zone_id_for_primary_zone)) {
diff --git a/tests/carservice_unit_test/src/android/car/userlib/UserHalHelperTest.java b/tests/carservice_unit_test/src/android/car/userlib/UserHalHelperTest.java
index 4d64225..29a1946 100644
--- a/tests/carservice_unit_test/src/android/car/userlib/UserHalHelperTest.java
+++ b/tests/carservice_unit_test/src/android/car/userlib/UserHalHelperTest.java
@@ -17,6 +17,7 @@
package android.car.userlib;
import static android.car.userlib.UserHalHelper.CREATE_USER_PROPERTY;
+import static android.car.userlib.UserHalHelper.REMOVE_USER_PROPERTY;
import static android.car.userlib.UserHalHelper.SWITCH_USER_PROPERTY;
import static android.car.userlib.UserHalHelper.USER_IDENTIFICATION_ASSOCIATION_PROPERTY;
import static android.hardware.automotive.vehicle.V2_0.UserIdentificationAssociationSetValue.ASSOCIATE_CURRENT_USER;
@@ -50,6 +51,7 @@
import android.hardware.automotive.vehicle.V2_0.InitialUserInfoRequestType;
import android.hardware.automotive.vehicle.V2_0.InitialUserInfoResponse;
import android.hardware.automotive.vehicle.V2_0.InitialUserInfoResponseAction;
+import android.hardware.automotive.vehicle.V2_0.RemoveUserRequest;
import android.hardware.automotive.vehicle.V2_0.SwitchUserMessageType;
import android.hardware.automotive.vehicle.V2_0.SwitchUserRequest;
import android.hardware.automotive.vehicle.V2_0.UserFlags;
@@ -864,6 +866,62 @@
}
@Test
+ public void testRemoveUserRequestToVehiclePropValue_null() {
+ assertThrows(NullPointerException.class,
+ () -> UserHalHelper.toVehiclePropValue((RemoveUserRequest) null));
+ }
+
+ @Test
+ public void testRemoveUserRequestToVehiclePropValue_emptyRequest() {
+ RemoveUserRequest request = new RemoveUserRequest();
+
+ assertThrows(IllegalArgumentException.class,
+ () -> UserHalHelper.toVehiclePropValue(request));
+ }
+
+ @Test
+ public void testRemoveUserRequestToVehiclePropValue_missingRequestId() {
+ RemoveUserRequest request = new RemoveUserRequest();
+ request.removedUserInfo.userId = 11;
+ request.usersInfo.existingUsers.add(request.removedUserInfo);
+
+ assertThrows(IllegalArgumentException.class,
+ () -> UserHalHelper.toVehiclePropValue(request));
+ }
+
+ @Test
+ public void testRemoveUserRequestToVehiclePropValue_ok() {
+ RemoveUserRequest request = new RemoveUserRequest();
+ request.requestId = 42;
+
+ android.hardware.automotive.vehicle.V2_0.UserInfo user10 =
+ new android.hardware.automotive.vehicle.V2_0.UserInfo();
+ user10.userId = 10;
+ user10.flags = UserFlags.ADMIN;
+
+ // existing users
+ request.usersInfo.numberUsers = 1;
+ request.usersInfo.existingUsers.add(user10);
+
+ // current user
+ request.usersInfo.currentUser = user10;
+ // user to remove
+ request.removedUserInfo = user10;
+
+ VehiclePropValue propValue = UserHalHelper.toVehiclePropValue(request);
+
+ assertWithMessage("wrong prop on %s", propValue).that(propValue.prop)
+ .isEqualTo(REMOVE_USER_PROPERTY);
+ assertWithMessage("wrong int32values on %s", propValue).that(propValue.value.int32Values)
+ .containsExactly(42, // request id
+ 10, UserFlags.ADMIN, // user to remove
+ 10, UserFlags.ADMIN, // current user
+ 1, // number of users
+ 10, UserFlags.ADMIN // existing user 1
+ ).inOrder();
+ }
+
+ @Test
public void testCreateUserRequestToVehiclePropValue_null() {
assertThrows(NullPointerException.class,
() -> UserHalHelper.toVehiclePropValue((CreateUserRequest) null));
@@ -1066,12 +1124,12 @@
@Test
public void testNewUsersInfo_nullUm() {
- assertThrows(IllegalArgumentException.class, () -> UserHalHelper.newUsersInfo(null));
+ assertThrows(IllegalArgumentException.class, () -> UserHalHelper.newUsersInfo(null, 100));
}
@Test
public void testNewUsersInfo_nullUsers() {
- UsersInfo usersInfo = UserHalHelper.newUsersInfo(mUm);
+ UsersInfo usersInfo = UserHalHelper.newUsersInfo(mUm, 100);
assertEmptyUsersInfo(usersInfo);
}
@@ -1081,12 +1139,58 @@
List<UserInfo> users = new ArrayList<>();
AndroidMockitoHelper.mockUmGetUsers(mUm, users);
- UsersInfo usersInfo = UserHalHelper.newUsersInfo(mUm);
+ UsersInfo usersInfo = UserHalHelper.newUsersInfo(mUm, 100);
assertEmptyUsersInfo(usersInfo);
}
@Test
+ public void testNewUsersInfo_ok() {
+ UserInfo user100 = new UserInfoBuilder(100).setFlags(UserInfo.FLAG_ADMIN).build();
+ UserInfo user200 = new UserInfoBuilder(200).build();
+
+ AndroidMockitoHelper.mockUmGetUsers(mUm, user100, user200);
+ AndroidMockitoHelper.mockAmGetCurrentUser(300); // just to make sure it's not used
+
+ UsersInfo usersInfo = UserHalHelper.newUsersInfo(mUm, 100);
+
+ assertThat(usersInfo).isNotNull();
+ assertThat(usersInfo.currentUser.userId).isEqualTo(100);
+ assertThat(usersInfo.currentUser.flags).isEqualTo(UserFlags.ADMIN);
+
+ assertThat(usersInfo.numberUsers).isEqualTo(2);
+ assertThat(usersInfo.existingUsers).hasSize(2);
+
+ assertThat(usersInfo.existingUsers.get(0).userId).isEqualTo(100);
+ assertThat(usersInfo.existingUsers.get(0).flags).isEqualTo(UserFlags.ADMIN);
+ assertThat(usersInfo.existingUsers.get(1).userId).isEqualTo(200);
+ assertThat(usersInfo.existingUsers.get(1).flags).isEqualTo(UserFlags.NONE);
+ }
+
+ @Test
+ public void testNewUsersInfo_currentUser_ok() {
+ UserInfo user100 = new UserInfoBuilder(100).setFlags(UserInfo.FLAG_ADMIN).build();
+ UserInfo user200 = new UserInfoBuilder(200).build();
+
+ AndroidMockitoHelper.mockUmGetUsers(mUm, user100, user200);
+ AndroidMockitoHelper.mockAmGetCurrentUser(100);
+
+ UsersInfo usersInfo = UserHalHelper.newUsersInfo(mUm);
+
+ assertThat(usersInfo).isNotNull();
+ assertThat(usersInfo.currentUser.userId).isEqualTo(100);
+ assertThat(usersInfo.currentUser.flags).isEqualTo(UserFlags.ADMIN);
+
+ assertThat(usersInfo.numberUsers).isEqualTo(2);
+ assertThat(usersInfo.existingUsers).hasSize(2);
+
+ assertThat(usersInfo.existingUsers.get(0).userId).isEqualTo(100);
+ assertThat(usersInfo.existingUsers.get(0).flags).isEqualTo(UserFlags.ADMIN);
+ assertThat(usersInfo.existingUsers.get(1).userId).isEqualTo(200);
+ assertThat(usersInfo.existingUsers.get(1).flags).isEqualTo(UserFlags.NONE);
+ }
+
+ @Test
public void testNewUsersInfo_noCurrentUser() {
UserInfo user100 = new UserInfoBuilder(100).setFlags(UserInfo.FLAG_ADMIN).build();
UserInfo user200 = new UserInfoBuilder(200).build();
@@ -1110,29 +1214,6 @@
}
@Test
- public void testNewUsersInfo_ok() {
- UserInfo user100 = new UserInfoBuilder(100).setFlags(UserInfo.FLAG_ADMIN).build();
- UserInfo user200 = new UserInfoBuilder(200).build();
-
- AndroidMockitoHelper.mockUmGetUsers(mUm, user100, user200);
- AndroidMockitoHelper.mockAmGetCurrentUser(100);
-
- UsersInfo usersInfo = UserHalHelper.newUsersInfo(mUm);
-
- assertThat(usersInfo).isNotNull();
- assertThat(usersInfo.currentUser.userId).isEqualTo(100);
- assertThat(usersInfo.currentUser.flags).isEqualTo(UserFlags.ADMIN);
-
- assertThat(usersInfo.numberUsers).isEqualTo(2);
- assertThat(usersInfo.existingUsers).hasSize(2);
-
- assertThat(usersInfo.existingUsers.get(0).userId).isEqualTo(100);
- assertThat(usersInfo.existingUsers.get(0).flags).isEqualTo(UserFlags.ADMIN);
- assertThat(usersInfo.existingUsers.get(1).userId).isEqualTo(200);
- assertThat(usersInfo.existingUsers.get(1).flags).isEqualTo(UserFlags.NONE);
- }
-
- @Test
public void testCheckValidUsersInfo_null() {
assertThrows(IllegalArgumentException.class, () -> UserHalHelper.checkValid(null));
}
diff --git a/tests/carservice_unit_test/src/com/android/car/CarPowerManagementServiceTest.java b/tests/carservice_unit_test/src/com/android/car/CarPowerManagementServiceTest.java
index f146dcb..3cbfffc 100644
--- a/tests/carservice_unit_test/src/com/android/car/CarPowerManagementServiceTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/CarPowerManagementServiceTest.java
@@ -62,6 +62,7 @@
import com.android.car.systeminterface.WakeLockInterface;
import com.android.car.test.utils.TemporaryDirectory;
import com.android.car.user.CarUserService;
+import com.android.internal.app.IVoiceInteractionManagerService;
import org.junit.After;
import org.junit.Before;
@@ -107,6 +108,9 @@
private CarUserService mUserService;
@Mock
private InitialUserSetter mInitialUserSetter;
+ @Mock
+ private IVoiceInteractionManagerService mVoiceInteractionManagerService;
+
@Override
protected void onSessionBuilder(CustomMockitoSessionBuilder session) {
@@ -150,7 +154,8 @@
+ ", maxGarageModeRunningDurationInSecs="
+ mResources.getInteger(R.integer.maxGarageModeRunningDurationInSecs));
mService = new CarPowerManagementService(mContext, mResources, mPowerHal,
- mSystemInterface, mUserManager, mUserService, mInitialUserSetter);
+ mSystemInterface, mUserManager, mUserService, mInitialUserSetter,
+ mVoiceInteractionManagerService);
mService.init();
mService.setShutdownTimersForTest(0, 0);
mPowerHal.setSignalListener(mPowerSignalListener);
@@ -501,6 +506,7 @@
VehicleApPowerStateShutdownParam.CAN_SLEEP));
assertThat(mDisplayInterface.waitForDisplayStateChange(WAIT_TIMEOUT_MS)).isFalse();
assertStateReceivedForShutdownOrSleepWithPostpone(PowerHalService.SET_DEEP_SLEEP_ENTRY);
+ assertVoiceInteractionDisabled();
mPowerSignalListener.waitForSleepEntry(WAIT_TIMEOUT_MS);
// Send the finished signal
@@ -530,6 +536,7 @@
mSystemStateInterface.waitForSleepEntryAndWakeup(WAIT_TIMEOUT_MS);
// Since we just woke up from shutdown, wake up time will be 0
assertStateReceived(PowerHalService.SET_DEEP_SLEEP_EXIT, 0);
+ assertVoiceInteractionEnabled();
assertThat(mDisplayInterface.getDisplayState()).isFalse();
}
@@ -573,6 +580,14 @@
assertStateReceivedForShutdownOrSleepWithPostpone(lastState, expectedSecondParameter);
}
+ private void assertVoiceInteractionEnabled() throws Exception {
+ verify(mVoiceInteractionManagerService).setDisabled(false);
+ }
+
+ private void assertVoiceInteractionDisabled() throws Exception {
+ verify(mVoiceInteractionManagerService).setDisabled(true);
+ }
+
private static void waitForSemaphore(Semaphore semaphore, long timeoutMs)
throws InterruptedException {
if (!semaphore.tryAcquire(timeoutMs, TimeUnit.MILLISECONDS)) {
diff --git a/tests/carservice_unit_test/src/com/android/car/hal/UserHalServiceTest.java b/tests/carservice_unit_test/src/com/android/car/hal/UserHalServiceTest.java
index 25917c3..e6a81b6 100644
--- a/tests/carservice_unit_test/src/com/android/car/hal/UserHalServiceTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/hal/UserHalServiceTest.java
@@ -18,6 +18,7 @@
import static android.car.VehiclePropertyIds.CREATE_USER;
import static android.car.VehiclePropertyIds.CURRENT_GEAR;
import static android.car.VehiclePropertyIds.INITIAL_USER_INFO;
+import static android.car.VehiclePropertyIds.REMOVE_USER;
import static android.car.VehiclePropertyIds.SWITCH_USER;
import static android.car.VehiclePropertyIds.USER_IDENTIFICATION_ASSOCIATION;
import static android.car.test.mocks.CarArgumentMatchers.isProperty;
@@ -53,6 +54,7 @@
import android.hardware.automotive.vehicle.V2_0.CreateUserStatus;
import android.hardware.automotive.vehicle.V2_0.InitialUserInfoResponse;
import android.hardware.automotive.vehicle.V2_0.InitialUserInfoResponseAction;
+import android.hardware.automotive.vehicle.V2_0.RemoveUserRequest;
import android.hardware.automotive.vehicle.V2_0.SwitchUserMessageType;
import android.hardware.automotive.vehicle.V2_0.SwitchUserRequest;
import android.hardware.automotive.vehicle.V2_0.SwitchUserResponse;
@@ -684,6 +686,55 @@
}
@Test
+ public void testRemoveUser_nullRequest() {
+ RemoveUserRequest request = null;
+
+ assertThrows(NullPointerException.class,
+ () -> mUserHalService.removeUser(request));
+ }
+
+ @Test
+ public void testRemoveUser_noRequestId() {
+ RemoveUserRequest request = new RemoveUserRequest();
+
+ assertThrows(IllegalArgumentException.class,
+ () -> mUserHalService.removeUser(request));
+ }
+
+ @Test
+ public void testRemoveUser_noRemovedUserInfo() {
+ RemoveUserRequest request = new RemoveUserRequest();
+ request.requestId = 1;
+
+ assertThrows(IllegalArgumentException.class,
+ () -> mUserHalService.removeUser(request));
+ }
+
+ @Test
+ public void testRemoveUser_noUsersInfo() {
+ RemoveUserRequest request = new RemoveUserRequest();
+ request.requestId = 1;
+ request.removedUserInfo = mUser10;
+
+ assertThrows(IllegalArgumentException.class,
+ () -> mUserHalService.removeUser(request));
+ }
+
+ @Test
+ public void testRemoveUser_HalCalledWithCorrectProp() {
+ RemoveUserRequest request = new RemoveUserRequest();
+ request.removedUserInfo = mUser10;
+ request.usersInfo = mUsersInfo;
+ ArgumentCaptor<VehiclePropValue> propCaptor =
+ ArgumentCaptor.forClass(VehiclePropValue.class);
+
+ mUserHalService.removeUser(request);
+
+ verify(mVehicleHal).set(propCaptor.capture());
+ assertHalSetRemoveUserRequest(propCaptor.getValue(), mUser10);
+ }
+
+ @Test
public void testLegacyUserSwitch_noUsersInfo() {
SwitchUserRequest request = new SwitchUserRequest();
request.messageType = SwitchUserMessageType.ANDROID_SWITCH;
@@ -1366,6 +1417,17 @@
assertUsersInfo(req, mUsersInfo, 4);
}
+ private void assertHalSetRemoveUserRequest(VehiclePropValue req, UserInfo userInfo) {
+ assertThat(req.prop).isEqualTo(REMOVE_USER);
+ assertWithMessage("wrong request Id on %s", req).that(req.value.int32Values.get(0))
+ .isAtLeast(1);
+ assertWithMessage("user.id mismatch on %s", req).that(req.value.int32Values.get(1))
+ .isEqualTo(userInfo.userId);
+ assertWithMessage("user.flags mismatch on %s", req).that(req.value.int32Values.get(2))
+ .isEqualTo(userInfo.flags);
+ assertUsersInfo(req, mUsersInfo, 3);
+ }
+
private void assertHalSetCreateUserRequest(VehiclePropValue prop, CreateUserRequest request) {
assertThat(prop.prop).isEqualTo(CREATE_USER);
assertWithMessage("wrong request Id on %s", prop).that(prop.value.int32Values.get(0))
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 6100dbc..ae86874 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
@@ -41,6 +41,7 @@
import com.android.car.systeminterface.DisplayInterface;
import com.android.car.systeminterface.SystemInterface;
import com.android.car.systeminterface.SystemStateInterface;
+import com.android.internal.app.IVoiceInteractionManagerService;
import org.junit.After;
import org.junit.Before;
@@ -73,6 +74,8 @@
private Resources mResources;
@Mock
private Car mCar;
+ @Mock
+ private IVoiceInteractionManagerService mVoiceInteractionManagerService;
@Before
public void setUp() throws Exception {
@@ -204,7 +207,7 @@
+ ", maxGarageModeRunningDurationInSecs="
+ mResources.getInteger(R.integer.maxGarageModeRunningDurationInSecs));
mService = new CarPowerManagementService(mContext, mResources, mPowerHal,
- mSystemInterface, null, null, null);
+ mSystemInterface, null, null, null, mVoiceInteractionManagerService);
mService.init();
mService.setShutdownTimersForTest(0, 0);
assertStateReceived(MockedPowerHalService.SET_WAIT_FOR_VHAL, 0);
diff --git a/tests/carservice_unit_test/src/com/android/car/user/CarUserManagerUnitTest.java b/tests/carservice_unit_test/src/com/android/car/user/CarUserManagerUnitTest.java
index 540e1d1..1003957 100644
--- a/tests/carservice_unit_test/src/com/android/car/user/CarUserManagerUnitTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/user/CarUserManagerUnitTest.java
@@ -45,6 +45,7 @@
import android.car.user.CarUserManager.UserSwitchUiCallback;
import android.car.user.UserCreationResult;
import android.car.user.UserIdentificationAssociationResponse;
+import android.car.user.UserRemovalResult;
import android.car.user.UserSwitchResult;
import android.content.pm.UserInfo;
import android.content.pm.UserInfo.UserInfoFlag;
@@ -188,6 +189,28 @@
}
@Test
+ public void testRemoveUser_success() throws Exception {
+ int userId = 11;
+ int status = UserRemovalResult.STATUS_SUCCESSFUL;
+ when(mService.removeUser(userId)).thenReturn(new UserRemovalResult(status));
+
+ UserRemovalResult result = mMgr.removeUser(11);
+
+ assertThat(result.getStatus()).isEqualTo(UserRemovalResult.STATUS_SUCCESSFUL);
+ }
+
+ @Test
+ public void testRemoveUser_remoteException() throws Exception {
+ int userId = 11;
+ doThrow(new RemoteException("D'OH!")).when(mService).removeUser(eq(userId));
+ mockHandleRemoteExceptionFromCarServiceWithDefaultValue(mCar);
+
+ UserRemovalResult result = mMgr.removeUser(11);
+
+ assertThat(result.getStatus()).isEqualTo(UserRemovalResult.STATUS_HAL_INTERNAL_FAILURE);
+ }
+
+ @Test
public void testSetSwitchUserUICallback_success() throws Exception {
UserSwitchUiCallback callback = (u)-> { };
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 dc26946..79d3282 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
@@ -21,6 +21,7 @@
import static android.car.test.mocks.AndroidMockitoHelper.mockUmGetUserInfo;
import static android.car.test.mocks.AndroidMockitoHelper.mockUmGetUsers;
import static android.car.test.util.UserTestingHelper.UserInfoBuilder;
+import static android.content.pm.UserInfo.FLAG_ADMIN;
import static android.content.pm.UserInfo.FLAG_EPHEMERAL;
import static android.content.pm.UserInfo.FLAG_GUEST;
@@ -65,6 +66,7 @@
import android.car.user.CarUserManager.UserLifecycleListener;
import android.car.user.UserCreationResult;
import android.car.user.UserIdentificationAssociationResponse;
+import android.car.user.UserRemovalResult;
import android.car.user.UserSwitchResult;
import android.car.userlib.CarUserManagerHelper;
import android.car.userlib.HalCallback;
@@ -82,6 +84,7 @@
import android.hardware.automotive.vehicle.V2_0.InitialUserInfoRequestType;
import android.hardware.automotive.vehicle.V2_0.InitialUserInfoResponse;
import android.hardware.automotive.vehicle.V2_0.InitialUserInfoResponseAction;
+import android.hardware.automotive.vehicle.V2_0.RemoveUserRequest;
import android.hardware.automotive.vehicle.V2_0.SwitchUserRequest;
import android.hardware.automotive.vehicle.V2_0.SwitchUserResponse;
import android.hardware.automotive.vehicle.V2_0.SwitchUserStatus;
@@ -462,33 +465,37 @@
}
@Test
- public void testCreateAdminDriver_IfCurrentUserIsAdminUser() {
- doReturn(true).when(mMockedUserManager).isSystemUser();
- String userName = "testUser";
- UserInfo userInfo = new UserInfo();
- doReturn(userInfo).when(mMockedUserManager).createUser(userName, UserInfo.FLAG_ADMIN);
- assertEquals(userInfo, mCarUserService.createDriver(userName, true));
+ public void testCreateAdminDriver_IfCurrentUserIsAdminUser() throws Exception {
+ when(mMockedUserManager.isSystemUser()).thenReturn(true);
+ mockUmCreateUser(mMockedUserManager, "testUser", UserManager.USER_TYPE_FULL_SECONDARY,
+ UserInfo.FLAG_ADMIN, 10);
+ mockHalCreateUser(HalCallback.STATUS_OK, CreateUserStatus.SUCCESS);
+
+ AndroidFuture<UserCreationResult> future = mCarUserService.createDriver("testUser", true);
+
+ assertThat(getResult(future).getUser().name).isEqualTo("testUser");
+ assertThat(getResult(future).getUser().id).isEqualTo(10);
}
@Test
- public void testCreateAdminDriver_IfCurrentUserIsNotSystemUser() {
- doReturn(false).when(mMockedUserManager).isSystemUser();
- assertEquals(null, mCarUserService.createDriver("testUser", true));
+ public void testCreateAdminDriver_IfCurrentUserIsNotSystemUser() throws Exception {
+ when(mMockedUserManager.isSystemUser()).thenReturn(false);
+ AndroidFuture<UserCreationResult> future = mCarUserService.createDriver("testUser", true);
+ assertThat(getResult(future).getStatus())
+ .isEqualTo(UserCreationResult.STATUS_INVALID_REQUEST);
}
@Test
- public void testCreateNonAdminDriver() {
- String userName = "testUser";
- UserInfo userInfo = new UserInfo();
- doReturn(userInfo).when(mMockedCarUserManagerHelper).createNewNonAdminUser(userName);
- assertEquals(userInfo, mCarUserService.createDriver(userName, false));
- }
+ public void testCreateNonAdminDriver() throws Exception {
+ mockUmCreateUser(mMockedUserManager, "testUser", UserManager.USER_TYPE_FULL_SECONDARY,
+ NO_USER_INFO_FLAGS, 10);
+ mockHalCreateUser(HalCallback.STATUS_OK, CreateUserStatus.SUCCESS);
- @Test
- public void testCreateNonAdminDriver_IfMaximumUserAlreadyCreated() {
- String userName = "testUser";
- doReturn(null).when(mMockedUserManager).createUser(userName, NO_USER_INFO_FLAGS);
- assertEquals(null, mCarUserService.createDriver(userName, false));
+ AndroidFuture<UserCreationResult> future = mCarUserService.createDriver("testUser", false);
+
+ UserInfo userInfo = getResult(future).getUser();
+ assertThat(userInfo.name).isEqualTo("testUser");
+ assertThat(userInfo.id).isEqualTo(10);
}
@Test
@@ -658,6 +665,73 @@
}
@Test
+ public void testRemoveUser_currentUserCannotBeRemoved() throws Exception {
+ mockCurrentUser(mAdminUser);
+
+ UserRemovalResult result = mCarUserService.removeUser(mAdminUser.id);
+
+ assertThat(result.getStatus())
+ .isEqualTo(UserRemovalResult.STATUS_TARGET_USER_IS_CURRENT_USER);
+ }
+
+ @Test
+ public void testRemoveUser_userNotExist() throws Exception {
+ UserRemovalResult result = mCarUserService.removeUser(15);
+
+ assertThat(result.getStatus())
+ .isEqualTo(UserRemovalResult.STATUS_USER_DOES_NOT_EXIST);
+ }
+
+ @Test
+ public void testRemoveUser_lastAdminUser() throws Exception {
+ mockCurrentUser(mRegularUser);
+ mockExistingUsers();
+
+ UserRemovalResult result = mCarUserService.removeUser(mAdminUser.id);
+
+ assertThat(result.getStatus())
+ .isEqualTo(UserRemovalResult.STATUS_TARGET_USER_IS_LAST_ADMIN_USER);
+ }
+
+ @Test
+ public void testRemoveUser_notLastAdminUser_success() throws Exception {
+ // Give admin rights to regular user.
+ UserInfo currentUser = mRegularUser;
+ currentUser.flags = currentUser.flags | FLAG_ADMIN;
+ mockExistingUsersAndCurrentUser(currentUser);
+ int removeUserId = mAdminUser.id;
+ when(mMockedUserManager.removeUser(removeUserId)).thenReturn(true);
+
+ UserRemovalResult result = mCarUserService.removeUser(removeUserId);
+
+ assertThat(result.getStatus()).isEqualTo(UserRemovalResult.STATUS_SUCCESSFUL);
+ assertHalRemove(currentUser.id, removeUserId);
+ }
+
+ @Test
+ public void testRemoveUser_success() throws Exception {
+ mockExistingUsersAndCurrentUser(mAdminUser);
+ int removeUserId = mRegularUser.id;
+ when(mMockedUserManager.removeUser(removeUserId)).thenReturn(true);
+
+ UserRemovalResult result = mCarUserService.removeUser(removeUserId);
+
+ assertThat(result.getStatus()).isEqualTo(UserRemovalResult.STATUS_SUCCESSFUL);
+ assertHalRemove(mAdminUser.id, removeUserId);
+ }
+
+ @Test
+ public void testRemoveUser_androidFailure() throws Exception {
+ mockExistingUsersAndCurrentUser(mAdminUser);
+ int targetUserId = mRegularUser.id;
+ when(mMockedUserManager.removeUser(targetUserId)).thenReturn(false);
+
+ UserRemovalResult result = mCarUserService.removeUser(targetUserId);
+
+ assertThat(result.getStatus()).isEqualTo(UserRemovalResult.STATUS_ANDROID_FAILURE);
+ }
+
+ @Test
public void testSwitchUser_nullReceiver() throws Exception {
mockExistingUsersAndCurrentUser(mAdminUser);
@@ -964,8 +1038,8 @@
}
@Test
- public void testHalUserSwitchOnAndroidSwitch_successfulNoExitingUserSwitch() throws Exception {
- mockExistingUsersAndCurrentUser(mAdminUser);
+ public void testLegacyUserSwitch_ok() throws Exception {
+ mockExistingUsers();
sendUserSwitchingEvent(mAdminUser.id, mRegularUser.id);
@@ -973,7 +1047,8 @@
}
@Test
- public void testHalUserSwitchOnAndroidSwitch_failureExitingUserSwitch() throws Exception {
+ public void testLegacyUserSwitch_notCalledAfterNormalSwitch() throws Exception {
+ // Arrange - emulate normal switch
mockExistingUsersAndCurrentUser(mAdminUser);
int requestId = 42;
mSwitchUserResponse.status = SwitchUserStatus.SUCCESS;
@@ -982,8 +1057,10 @@
mockAmSwitchUser(mGuestUser, true);
mCarUserService.switchUser(mGuestUser.id, mAsyncCallTimeoutMs, mUserSwitchFuture);
+ // Act - trigger legacy switch
sendUserSwitchingEvent(mAdminUser.id, mGuestUser.id);
+ // Assert
verify(mUserHal, never()).legacyUserSwitch(any());
}
@@ -1877,6 +1954,14 @@
verify(mUserHal, never()).createUser(any(), eq(mAsyncCallTimeoutMs), any());
}
+ private void assertHalRemove(int currentId, int removeUserId) {
+ ArgumentCaptor<RemoveUserRequest> request =
+ ArgumentCaptor.forClass(RemoveUserRequest.class);
+ verify(mUserHal).removeUser(request.capture());
+ assertThat(request.getValue().removedUserInfo.userId).isEqualTo(removeUserId);
+ assertThat(request.getValue().usersInfo.currentUser.userId).isEqualTo(currentId);
+ }
+
@NonNull
private static SwitchUserRequest isSwitchUserRequest(int requestId,
@UserIdInt int currentUserId, @UserIdInt int targetUserId) {
diff --git a/tests/carservice_unit_test/src/com/android/car/user/ExperimentalCarUserManagerUnitTest.java b/tests/carservice_unit_test/src/com/android/car/user/ExperimentalCarUserManagerUnitTest.java
index 8b4dc55..2869d5d 100644
--- a/tests/carservice_unit_test/src/com/android/car/user/ExperimentalCarUserManagerUnitTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/user/ExperimentalCarUserManagerUnitTest.java
@@ -20,6 +20,7 @@
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.notNull;
import static org.mockito.Mockito.doAnswer;
@@ -33,6 +34,7 @@
import android.car.test.util.UserTestingHelper;
import android.car.user.CarUserManager;
import android.car.user.ExperimentalCarUserManager;
+import android.car.user.UserCreationResult;
import android.car.user.UserSwitchResult;
import android.content.pm.UserInfo;
import android.os.RemoteException;
@@ -66,23 +68,41 @@
@Test
public void testCreateDriver_Success_Admin() throws Exception {
- expectCreateDriverSucceed(10);
- int userId = mManager.createDriver("test driver", true);
- assertThat(userId).isEqualTo(10);
+ String name = "test driver";
+ int userId = 10;
+ expectCreateDriverSucceed(name, userId);
+
+ AndroidFuture<UserCreationResult> future = mManager.createDriver(name, true);
+
+ UserCreationResult result = getResult(future);
+ assertThat(result.getErrorMessage()).isNull();
+ assertThat(result.getStatus()).isEqualTo(UserCreationResult.STATUS_SUCCESSFUL);
+ assertThat(result.getUser().id).isEqualTo(userId);
}
@Test
public void testCreateDriver_Success_NonAdmin() throws Exception {
- expectCreateDriverSucceed(10);
- int userId = mManager.createDriver("test driver", false);
- assertThat(userId).isEqualTo(10);
+ String name = "test driver";
+ int userId = 10;
+ expectCreateDriverSucceed(name, userId);
+
+ AndroidFuture<UserCreationResult> future = mManager.createDriver(name, false);
+
+ UserCreationResult result = getResult(future);
+ assertThat(result.getErrorMessage()).isNull();
+ assertThat(result.getStatus()).isEqualTo(UserCreationResult.STATUS_SUCCESSFUL);
+ assertThat(result.getUser().id).isEqualTo(userId);
}
@Test
public void testCreateDriver_Error() throws Exception {
expectCreateDriverFail();
- int userId = mManager.createDriver("test driver", false);
- assertThat(userId).isEqualTo(UserHandle.USER_NULL);
+
+ AndroidFuture<UserCreationResult> future = mManager.createDriver("test driver", false);
+
+ assertThat(future).isNotNull();
+ UserCreationResult result = getResult(future);
+ assertThat(result.getStatus()).isEqualTo(UserSwitchResult.STATUS_HAL_INTERNAL_FAILURE);
}
@Test
@@ -165,13 +185,16 @@
assertThat(success).isFalse();
}
- private void expectCreateDriverSucceed(@UserIdInt int userId) throws Exception {
- UserInfo userInfo = UserTestingHelper.newUser(userId);
- when(mService.createDriver(eq("test driver"), anyBoolean())).thenReturn(userInfo);
+ private void expectCreateDriverSucceed(String name, @UserIdInt int userId) throws Exception {
+ AndroidFuture<UserCreationResult> future = new AndroidFuture<>();
+ future.complete(new UserCreationResult(UserCreationResult.STATUS_SUCCESSFUL,
+ UserTestingHelper.newUser(userId), null));
+ when(mService.createDriver(eq(name), anyBoolean())).thenReturn(future);
}
private void expectCreateDriverFail() throws Exception {
- when(mService.createDriver(eq("test driver"), anyBoolean())).thenReturn(null);
+ doThrow(new RemoteException("D'OH!")).when(mService)
+ .createDriver(anyString(), anyBoolean());
}
private void expectCreatePassengerSucceed() throws Exception {
diff --git a/user/car-user-lib/src/android/car/userlib/UserHalHelper.java b/user/car-user-lib/src/android/car/userlib/UserHalHelper.java
index cb03788..67a83c3 100644
--- a/user/car-user-lib/src/android/car/userlib/UserHalHelper.java
+++ b/user/car-user-lib/src/android/car/userlib/UserHalHelper.java
@@ -27,6 +27,7 @@
import android.hardware.automotive.vehicle.V2_0.InitialUserInfoRequestType;
import android.hardware.automotive.vehicle.V2_0.InitialUserInfoResponse;
import android.hardware.automotive.vehicle.V2_0.InitialUserInfoResponseAction;
+import android.hardware.automotive.vehicle.V2_0.RemoveUserRequest;
import android.hardware.automotive.vehicle.V2_0.SwitchUserRequest;
import android.hardware.automotive.vehicle.V2_0.UserFlags;
import android.hardware.automotive.vehicle.V2_0.UserIdentificationAssociation;
@@ -63,8 +64,10 @@
public static final int INITIAL_USER_INFO_PROPERTY = 299896583;
public static final int SWITCH_USER_PROPERTY = 299896584;
public static final int CREATE_USER_PROPERTY = 299896585;
+ public static final int REMOVE_USER_PROPERTY = 299896586;
public static final int USER_IDENTIFICATION_ASSOCIATION_PROPERTY = 299896587;
+
private static final String STRING_SEPARATOR = "\\|\\|";
/**
@@ -539,10 +542,40 @@
}
/**
- * Creates a {@link UsersInfo} instance populated with the current users.
+ * Creates a generic {@link VehiclePropValue} (that can be sent to HAL) from a
+ * {@link RemoveUserRequest}.
+ *
+ * @throws IllegalArgumentException if the request doesn't have the proper format.
+ */
+ @NonNull
+ public static VehiclePropValue toVehiclePropValue(@NonNull RemoveUserRequest request) {
+ checkArgument(request.requestId > 0, "invalid requestId on %s", request);
+ android.hardware.automotive.vehicle.V2_0.UserInfo removedUserInfo = request.removedUserInfo;
+ Objects.requireNonNull(removedUserInfo);
+ UsersInfo usersInfo = request.usersInfo;
+ checkValid(usersInfo);
+
+ VehiclePropValue propValue = createPropRequest(REMOVE_USER_PROPERTY, request.requestId);
+ addUserInfo(propValue, removedUserInfo);
+ addUsersInfo(propValue, usersInfo);
+ return propValue;
+ }
+
+ /**
+ * Creates a {@link UsersInfo} instance populated with the current users, using
+ * {@link ActivityManager#getCurrentUser()} as the current user.
*/
@NonNull
public static UsersInfo newUsersInfo(@NonNull UserManager um) {
+ return newUsersInfo(um, ActivityManager.getCurrentUser());
+ }
+
+ /**
+ * Creates a {@link UsersInfo} instance populated with the current users, using
+ * {@code userId} as the current user.
+ */
+ @NonNull
+ public static UsersInfo newUsersInfo(@NonNull UserManager um, @UserIdInt int userId) {
Preconditions.checkArgument(um != null, "UserManager cannot be null");
List<UserInfo> users = um.getUsers(/*excludeDying= */ true);
@@ -553,7 +586,7 @@
}
UsersInfo usersInfo = new UsersInfo();
- usersInfo.currentUser.userId = ActivityManager.getCurrentUser();
+ usersInfo.currentUser.userId = userId;
UserInfo currentUser = null;
usersInfo.numberUsers = users.size();