Merge "Import translations. DO NOT MERGE ANYWHERE" into main
diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
index f97100b..83db4cb 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
@@ -1433,10 +1433,10 @@
Slog.d(TAG, "Removing jobs for pkg " + pkgName + " at uid " + pkgUid);
}
synchronized (mLock) {
- // Exclude jobs scheduled on behalf of this app for now because SyncManager
+ // Exclude jobs scheduled on behalf of this app because SyncManager
// and other job proxy agents may not know to reschedule the job properly
// after force stop.
- // TODO(209852664): determine how to best handle syncs & other proxied jobs
+ // Proxied jobs will not be allowed to run if the source app is stopped.
cancelJobsForPackageAndUidLocked(pkgName, pkgUid,
/* includeSchedulingApp */ true, /* includeSourceApp */ false,
JobParameters.STOP_REASON_USER,
@@ -1448,7 +1448,9 @@
}
};
- private String getPackageName(Intent intent) {
+ /** Returns the package name stored in the intent's data. */
+ @Nullable
+ public static String getPackageName(Intent intent) {
Uri uri = intent.getData();
String pkg = uri != null ? uri.getSchemeSpecificPart() : null;
return pkg;
@@ -5365,6 +5367,14 @@
}
pw.println();
+ pw.println("Aconfig flags:");
+ pw.increaseIndent();
+ pw.print(Flags.FLAG_THROW_ON_UNSUPPORTED_BIAS_USAGE,
+ Flags.throwOnUnsupportedBiasUsage());
+ pw.println();
+ pw.decreaseIndent();
+ pw.println();
+
for (int i = mJobRestrictions.size() - 1; i >= 0; i--) {
mJobRestrictions.get(i).dumpConstants(pw);
}
diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerShellCommand.java b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerShellCommand.java
index 293088d..c14efae 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerShellCommand.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerShellCommand.java
@@ -58,6 +58,8 @@
return cancelJob(pw);
case "monitor-battery":
return monitorBattery(pw);
+ case "get-aconfig-flag-state":
+ return getAconfigFlagState(pw);
case "get-battery-seq":
return getBatterySeq(pw);
case "get-battery-charging":
@@ -336,6 +338,28 @@
return 0;
}
+ private int getAconfigFlagState(PrintWriter pw) throws Exception {
+ checkPermission("get aconfig flag state");
+
+ final String flagName = getNextArgRequired();
+
+ switch (flagName) {
+ case android.app.job.Flags.FLAG_JOB_DEBUG_INFO_APIS:
+ pw.println(android.app.job.Flags.jobDebugInfoApis());
+ break;
+ case android.app.job.Flags.FLAG_ENFORCE_MINIMUM_TIME_WINDOWS:
+ pw.println(android.app.job.Flags.enforceMinimumTimeWindows());
+ break;
+ case com.android.server.job.Flags.FLAG_THROW_ON_UNSUPPORTED_BIAS_USAGE:
+ pw.println(com.android.server.job.Flags.throwOnUnsupportedBiasUsage());
+ break;
+ default:
+ pw.println("Unknown flag: " + flagName);
+ break;
+ }
+ return 0;
+ }
+
private int getBatterySeq(PrintWriter pw) {
int seq = mInternal.getBatterySeq();
pw.println(seq);
@@ -693,6 +717,9 @@
pw.println(" monitor-battery [on|off]");
pw.println(" Control monitoring of all battery changes. Off by default. Turning");
pw.println(" on makes get-battery-seq useful.");
+ pw.println(" get-aconfig-flag-state FULL_FLAG_NAME");
+ pw.println(" Return the state of the specified aconfig flag, if known. The flag name");
+ pw.println(" must be fully qualified.");
pw.println(" get-battery-seq");
pw.println(" Return the last battery update sequence number that was received.");
pw.println(" get-battery-charging");
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/BackgroundJobsController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/BackgroundJobsController.java
index cd3ba6b..4aadc90 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/BackgroundJobsController.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/BackgroundJobsController.java
@@ -17,18 +17,26 @@
package com.android.server.job.controllers;
import static com.android.server.job.JobSchedulerService.NEVER_INDEX;
+import static com.android.server.job.JobSchedulerService.getPackageName;
import static com.android.server.job.JobSchedulerService.sElapsedRealtimeClock;
import android.app.ActivityManager;
import android.app.ActivityManagerInternal;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.PackageManagerInternal;
import android.os.SystemClock;
import android.os.UserHandle;
import android.util.ArraySet;
import android.util.IndentingPrintWriter;
import android.util.Log;
import android.util.Slog;
+import android.util.SparseArrayMap;
import android.util.proto.ProtoOutputStream;
+import com.android.internal.annotations.GuardedBy;
import com.android.server.AppStateTracker;
import com.android.server.AppStateTrackerImpl;
import com.android.server.AppStateTrackerImpl.Listener;
@@ -50,6 +58,8 @@
*
* - the uid-active boolean state expressed by the AppStateTracker. Jobs in 'active'
* uids are inherently eligible to run jobs regardless of the uid's standby bucket.
+ *
+ * - the app's stopped state
*/
public final class BackgroundJobsController extends StateController {
private static final String TAG = "JobScheduler.Background";
@@ -63,9 +73,48 @@
private final ActivityManagerInternal mActivityManagerInternal;
private final AppStateTrackerImpl mAppStateTracker;
+ private final PackageManagerInternal mPackageManagerInternal;
+
+ @GuardedBy("mLock")
+ private final SparseArrayMap<String, Boolean> mPackageStoppedState = new SparseArrayMap<>();
private final UpdateJobFunctor mUpdateJobFunctor = new UpdateJobFunctor();
+ private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ final String pkgName = getPackageName(intent);
+ final int pkgUid = intent.getIntExtra(Intent.EXTRA_UID, -1);
+ final String action = intent.getAction();
+ if (pkgUid == -1) {
+ Slog.e(TAG, "Didn't get package UID in intent (" + action + ")");
+ return;
+ }
+
+ if (DEBUG) {
+ Slog.d(TAG, "Got " + action + " for " + pkgUid + "/" + pkgName);
+ }
+
+ switch (action) {
+ case Intent.ACTION_PACKAGE_RESTARTED: {
+ synchronized (mLock) {
+ mPackageStoppedState.add(pkgUid, pkgName, Boolean.TRUE);
+ updateJobRestrictionsForUidLocked(pkgUid, false);
+ }
+ }
+ break;
+
+ case Intent.ACTION_PACKAGE_UNSTOPPED: {
+ synchronized (mLock) {
+ mPackageStoppedState.add(pkgUid, pkgName, Boolean.FALSE);
+ updateJobRestrictionsLocked(pkgUid, UNKNOWN);
+ }
+ }
+ break;
+ }
+ }
+ };
+
public BackgroundJobsController(JobSchedulerService service) {
super(service);
@@ -73,11 +122,18 @@
LocalServices.getService(ActivityManagerInternal.class));
mAppStateTracker = (AppStateTrackerImpl) Objects.requireNonNull(
LocalServices.getService(AppStateTracker.class));
+ mPackageManagerInternal = LocalServices.getService(PackageManagerInternal.class);
}
@Override
public void startTrackingLocked() {
mAppStateTracker.addListener(mForceAppStandbyListener);
+ final IntentFilter filter = new IntentFilter();
+ filter.addAction(Intent.ACTION_PACKAGE_RESTARTED);
+ filter.addAction(Intent.ACTION_PACKAGE_UNSTOPPED);
+ filter.addDataScheme("package");
+ mContext.registerReceiverAsUser(
+ mBroadcastReceiver, UserHandle.ALL, filter, null, null);
}
@Override
@@ -99,11 +155,45 @@
}
@Override
+ public void onAppRemovedLocked(String packageName, int uid) {
+ mPackageStoppedState.delete(uid, packageName);
+ }
+
+ @Override
+ public void onUserRemovedLocked(int userId) {
+ for (int u = mPackageStoppedState.numMaps() - 1; u >= 0; --u) {
+ final int uid = mPackageStoppedState.keyAt(u);
+ if (UserHandle.getUserId(uid) == userId) {
+ mPackageStoppedState.deleteAt(u);
+ }
+ }
+ }
+
+ @Override
public void dumpControllerStateLocked(final IndentingPrintWriter pw,
final Predicate<JobStatus> predicate) {
+ pw.println("Aconfig flags:");
+ pw.increaseIndent();
+ pw.print(android.content.pm.Flags.FLAG_STAY_STOPPED,
+ android.content.pm.Flags.stayStopped());
+ pw.println();
+ pw.decreaseIndent();
+ pw.println();
+
mAppStateTracker.dump(pw);
pw.println();
+ pw.println("Stopped packages:");
+ pw.increaseIndent();
+ mPackageStoppedState.forEach((uid, pkgName, isStopped) -> {
+ pw.print(uid);
+ pw.print(":");
+ pw.print(pkgName);
+ pw.print("=");
+ pw.println(isStopped);
+ });
+ pw.println();
+
mService.getJobStore().forEachJob(predicate, (jobStatus) -> {
final int uid = jobStatus.getSourceUid();
final String sourcePkg = jobStatus.getSourcePackageName();
@@ -205,14 +295,34 @@
}
}
+ private boolean isPackageStopped(String packageName, int uid) {
+ if (mPackageStoppedState.contains(uid, packageName)) {
+ return mPackageStoppedState.get(uid, packageName);
+ }
+ final boolean isStopped = mPackageManagerInternal.isPackageStopped(packageName, uid);
+ mPackageStoppedState.add(uid, packageName, isStopped);
+ return isStopped;
+ }
+
boolean updateSingleJobRestrictionLocked(JobStatus jobStatus, final long nowElapsed,
int activeState) {
final int uid = jobStatus.getSourceUid();
final String packageName = jobStatus.getSourcePackageName();
- final boolean isUserBgRestricted =
- !mActivityManagerInternal.isBgAutoRestrictedBucketFeatureFlagEnabled()
- && !mAppStateTracker.isRunAnyInBackgroundAppOpsAllowed(uid, packageName);
+ final boolean isSourcePkgStopped =
+ isPackageStopped(jobStatus.getSourcePackageName(), jobStatus.getSourceUid());
+ final boolean isCallingPkgStopped;
+ if (!jobStatus.isProxyJob()) {
+ isCallingPkgStopped = isSourcePkgStopped;
+ } else {
+ isCallingPkgStopped =
+ isPackageStopped(jobStatus.getCallingPackageName(), jobStatus.getUid());
+ }
+ final boolean isStopped = android.content.pm.Flags.stayStopped()
+ && (isCallingPkgStopped || isSourcePkgStopped);
+ final boolean isUserBgRestricted = isStopped
+ || (!mActivityManagerInternal.isBgAutoRestrictedBucketFeatureFlagEnabled()
+ && !mAppStateTracker.isRunAnyInBackgroundAppOpsAllowed(uid, packageName));
// If a job started with the foreground flag, it'll cause the UID to stay active
// and thus cause areJobsRestricted() to always return false, so if
// areJobsRestricted() returns false and the app is BG restricted and not TOP,
@@ -233,7 +343,8 @@
&& isUserBgRestricted
&& mService.getUidProcState(uid)
> ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE;
- final boolean canRun = !shouldStopImmediately
+ // Don't let jobs (including proxied jobs) run if the app is in the stopped state.
+ final boolean canRun = !isStopped && !shouldStopImmediately
&& !mAppStateTracker.areJobsRestricted(
uid, packageName, jobStatus.canRunInBatterySaver());
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java
index b7480649..d1f575e 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java
@@ -1102,6 +1102,12 @@
return job.getService();
}
+ /** Return the package name of the app that scheduled the job. */
+ public String getCallingPackageName() {
+ return job.getService().getPackageName();
+ }
+
+ /** Return the package name of the app on whose behalf the job was scheduled. */
public String getSourcePackageName() {
return sourcePackageName;
}
diff --git a/cmds/idmap2/Android.bp b/cmds/idmap2/Android.bp
index 55ec7da..6e51f00 100644
--- a/cmds/idmap2/Android.bp
+++ b/cmds/idmap2/Android.bp
@@ -86,6 +86,7 @@
static_libs: [
"libidmap2_policies",
"libidmap2_protos",
+ "libpng",
],
shared_libs: [
"libandroidfw",
@@ -107,6 +108,7 @@
"libcutils",
"libidmap2_policies",
"libidmap2_protos",
+ "libpng",
"libprotobuf-cpp-lite",
"libutils",
"libz",
@@ -185,6 +187,7 @@
static_libs: [
"libgmock",
"libidmap2_protos",
+ "libpng",
],
target: {
android: {
@@ -258,6 +261,7 @@
"libbase",
"libcutils",
"libidmap2",
+ "libpng",
"libprotobuf-cpp-lite",
"libutils",
"libz",
@@ -275,6 +279,7 @@
"libidmap2",
"libidmap2_policies",
"liblog",
+ "libpng",
"libprotobuf-cpp-lite",
"libutils",
"libziparchive",
diff --git a/cmds/idmap2/idmap2d/Idmap2Service.cpp b/cmds/idmap2/idmap2d/Idmap2Service.cpp
index d76ca5b..f264125 100644
--- a/cmds/idmap2/idmap2d/Idmap2Service.cpp
+++ b/cmds/idmap2/idmap2d/Idmap2Service.cpp
@@ -266,7 +266,8 @@
} else if (res.binaryData.has_value()) {
builder.SetResourceValue(res.resourceName, res.binaryData->get(),
res.binaryDataOffset, res.binaryDataSize,
- res.configuration.value_or(std::string()));
+ res.configuration.value_or(std::string()),
+ res.isNinePatch);
} else {
builder.SetResourceValue(res.resourceName, res.dataType, res.data,
res.configuration.value_or(std::string()));
diff --git a/cmds/idmap2/idmap2d/aidl/core/android/os/FabricatedOverlayInternalEntry.aidl b/cmds/idmap2/idmap2d/aidl/core/android/os/FabricatedOverlayInternalEntry.aidl
index 8ebd454..bca2ff3 100644
--- a/cmds/idmap2/idmap2d/aidl/core/android/os/FabricatedOverlayInternalEntry.aidl
+++ b/cmds/idmap2/idmap2d/aidl/core/android/os/FabricatedOverlayInternalEntry.aidl
@@ -28,4 +28,5 @@
@nullable @utf8InCpp String configuration;
long binaryDataOffset;
long binaryDataSize;
+ boolean isNinePatch;
}
\ No newline at end of file
diff --git a/cmds/idmap2/include/idmap2/FabricatedOverlay.h b/cmds/idmap2/include/idmap2/FabricatedOverlay.h
index 1e7d4c2..bfcd4b9 100644
--- a/cmds/idmap2/include/idmap2/FabricatedOverlay.h
+++ b/cmds/idmap2/include/idmap2/FabricatedOverlay.h
@@ -19,6 +19,8 @@
#include <libidmap2/proto/fabricated_v1.pb.h>
+#include "androidfw/Streams.h"
+
#include <istream>
#include <map>
#include <memory>
@@ -51,7 +53,8 @@
std::optional<android::base::borrowed_fd>&& binary_value,
off64_t data_binary_offset,
size_t data_binary_size,
- const std::string& configuration);
+ const std::string& configuration,
+ bool nine_patch);
inline Builder& setFrroPath(std::string frro_path) {
frro_path_ = std::move(frro_path);
@@ -70,6 +73,7 @@
off64_t data_binary_offset;
size_t data_binary_size;
std::string configuration;
+ bool nine_patch;
};
std::string package_name_;
@@ -81,7 +85,7 @@
};
struct BinaryData {
- android::base::borrowed_fd file_descriptor;
+ std::unique_ptr<android::InputStream> input_stream;
off64_t offset;
size_t size;
};
diff --git a/cmds/idmap2/include/idmap2/ResourceUtils.h b/cmds/idmap2/include/idmap2/ResourceUtils.h
index d4490ef4..9e463c9 100644
--- a/cmds/idmap2/include/idmap2/ResourceUtils.h
+++ b/cmds/idmap2/include/idmap2/ResourceUtils.h
@@ -45,6 +45,7 @@
std::optional<android::base::borrowed_fd> data_binary_value;
off64_t data_binary_offset;
size_t data_binary_size;
+ bool nine_patch;
};
struct TargetValueWithConfig {
diff --git a/cmds/idmap2/libidmap2/FabricatedOverlay.cpp b/cmds/idmap2/libidmap2/FabricatedOverlay.cpp
index 47daf23..16bb896 100644
--- a/cmds/idmap2/libidmap2/FabricatedOverlay.cpp
+++ b/cmds/idmap2/libidmap2/FabricatedOverlay.cpp
@@ -20,8 +20,16 @@
#include <sys/types.h> // umask
#include <android-base/file.h>
+#include <android-base/strings.h>
+#include <androidfw/BigBuffer.h>
+#include <androidfw/BigBufferStream.h>
+#include <androidfw/FileStream.h>
+#include <androidfw/Image.h>
+#include <androidfw/Png.h>
#include <androidfw/ResourceUtils.h>
+#include <androidfw/StringPiece.h>
#include <androidfw/StringPool.h>
+#include <androidfw/Streams.h>
#include <google/protobuf/io/coded_stream.h>
#include <google/protobuf/io/zero_copy_stream_impl.h>
#include <utils/ByteOrder.h>
@@ -32,9 +40,9 @@
#include <memory>
#include <string>
#include <utility>
+#include <sys/utsname.h>
namespace android::idmap2 {
-
constexpr auto kBufferSize = 1024;
namespace {
@@ -81,7 +89,7 @@
const std::string& resource_name, uint8_t data_type, uint32_t data_value,
const std::string& configuration) {
entries_.emplace_back(
- Entry{resource_name, data_type, data_value, "", std::nullopt, 0, 0, configuration});
+ Entry{resource_name, data_type, data_value, "", std::nullopt, 0, 0, configuration, false});
return *this;
}
@@ -89,18 +97,90 @@
const std::string& resource_name, uint8_t data_type, const std::string& data_string_value,
const std::string& configuration) {
entries_.emplace_back(
- Entry{resource_name, data_type, 0, data_string_value, std::nullopt, 0, 0, configuration});
+ Entry{resource_name,
+ data_type,
+ 0,
+ data_string_value,
+ std::nullopt,
+ 0,
+ 0,
+ configuration,
+ false});
return *this;
}
FabricatedOverlay::Builder& FabricatedOverlay::Builder::SetResourceValue(
const std::string& resource_name, std::optional<android::base::borrowed_fd>&& binary_value,
- off64_t data_binary_offset, size_t data_binary_size, const std::string& configuration) {
+ off64_t data_binary_offset, size_t data_binary_size, const std::string& configuration,
+ bool nine_patch) {
entries_.emplace_back(Entry{resource_name, 0, 0, "", binary_value,
- data_binary_offset, data_binary_size, configuration});
+ data_binary_offset, data_binary_size, configuration, nine_patch});
return *this;
}
+static Result<FabricatedOverlay::BinaryData> buildBinaryData(
+ pb::ResourceValue* pb_value, const TargetValue &value) {
+ pb_value->set_data_type(Res_value::TYPE_STRING);
+ size_t binary_size;
+ off64_t binary_offset;
+ std::unique_ptr<android::InputStream> binary_stream;
+
+ if (value.nine_patch) {
+ std::string file_contents;
+ file_contents.resize(value.data_binary_size);
+ if (!base::ReadFullyAtOffset(value.data_binary_value->get(), file_contents.data(),
+ value.data_binary_size, value.data_binary_offset)) {
+ return Error("Failed to read binary file data.");
+ }
+ const StringPiece content(file_contents.c_str(), file_contents.size());
+ android::PngChunkFilter png_chunk_filter(content);
+ android::AndroidLogDiagnostics diag;
+ auto png = android::ReadPng(&png_chunk_filter, &diag);
+ if (!png) {
+ return Error("Error opening file as png");
+ }
+
+ std::string err;
+ std::unique_ptr<NinePatch> nine_patch = NinePatch::Create(png->rows.get(),
+ png->width, png->height,
+ &err);
+ if (!nine_patch) {
+ return Error("%s", err.c_str());
+ }
+
+ png->width -= 2;
+ png->height -= 2;
+ memmove(png->rows.get(), png->rows.get() + 1, png->height * sizeof(uint8_t**));
+ for (int32_t h = 0; h < png->height; h++) {
+ memmove(png->rows[h], png->rows[h] + 4, png->width * 4);
+ }
+
+ android::BigBuffer buffer(value.data_binary_size);
+ android::BigBufferOutputStream buffer_output_stream(&buffer);
+ if (!android::WritePng(png.get(), nine_patch.get(), &buffer_output_stream, {},
+ &diag, false)) {
+ return Error("Error writing frro png");
+ }
+
+ binary_size = buffer.size();
+ binary_offset = 0;
+ android::BigBufferInputStream *buffer_input_stream
+ = new android::BigBufferInputStream(std::move(buffer));
+ binary_stream.reset(buffer_input_stream);
+ } else {
+ binary_size = value.data_binary_size;
+ binary_offset = value.data_binary_offset;
+ android::FileInputStream *fis
+ = new android::FileInputStream(value.data_binary_value.value());
+ binary_stream.reset(fis);
+ }
+
+ return FabricatedOverlay::BinaryData{
+ std::move(binary_stream),
+ binary_offset,
+ binary_size};
+}
+
Result<FabricatedOverlay> FabricatedOverlay::Builder::Build() {
using ConfigMap = std::map<std::string, TargetValue, std::less<>>;
using EntryMap = std::map<std::string, ConfigMap, std::less<>>;
@@ -150,7 +230,8 @@
value->second = TargetValue{res_entry.data_type, res_entry.data_value,
res_entry.data_string_value, res_entry.data_binary_value,
- res_entry.data_binary_offset, res_entry.data_binary_size};
+ res_entry.data_binary_offset, res_entry.data_binary_size,
+ res_entry.nine_patch};
}
pb::FabricatedOverlay overlay_pb;
@@ -183,18 +264,20 @@
auto ref = string_pool.MakeRef(value.second.data_string_value);
pb_value->set_data_value(ref.index());
} else if (value.second.data_binary_value.has_value()) {
- pb_value->set_data_type(Res_value::TYPE_STRING);
- std::string uri
- = StringPrintf("frro:/%s?offset=%d&size=%d", frro_path_.c_str(),
- static_cast<int> (FRRO_HEADER_SIZE + total_binary_bytes),
- static_cast<int> (value.second.data_binary_size));
- total_binary_bytes += value.second.data_binary_size;
- binary_files.emplace_back(FabricatedOverlay::BinaryData{
- value.second.data_binary_value->get(),
- value.second.data_binary_offset,
- value.second.data_binary_size});
- auto ref = string_pool.MakeRef(std::move(uri));
- pb_value->set_data_value(ref.index());
+ auto binary_data = buildBinaryData(pb_value, value.second);
+ if (!binary_data) {
+ return binary_data.GetError();
+ }
+ pb_value->set_data_type(Res_value::TYPE_STRING);
+
+ std::string uri
+ = StringPrintf("frro:/%s?offset=%d&size=%d", frro_path_.c_str(),
+ static_cast<int> (FRRO_HEADER_SIZE + total_binary_bytes),
+ static_cast<int> (binary_data->size));
+ total_binary_bytes += binary_data->size;
+ binary_files.emplace_back(std::move(*binary_data));
+ auto ref = string_pool.MakeRef(std::move(uri));
+ pb_value->set_data_value(ref.index());
} else {
pb_value->set_data_value(value.second.data_value);
}
@@ -311,9 +394,9 @@
Write32(stream, (*data)->pb_crc);
Write32(stream, total_binary_bytes_);
std::string file_contents;
- for (const FabricatedOverlay::BinaryData fd : binary_files_) {
- file_contents.resize(fd.size);
- if (!ReadFullyAtOffset(fd.file_descriptor, file_contents.data(), fd.size, fd.offset)) {
+ for (const FabricatedOverlay::BinaryData& bd : binary_files_) {
+ file_contents.resize(bd.size);
+ if (!bd.input_stream->ReadFullyAtOffset(file_contents.data(), bd.size, bd.offset)) {
return Error("Failed to read binary file data.");
}
stream.write(file_contents.data(), file_contents.length());
diff --git a/cmds/idmap2/self_targeting/SelfTargeting.cpp b/cmds/idmap2/self_targeting/SelfTargeting.cpp
index c7f5cf3..7f9c468 100644
--- a/cmds/idmap2/self_targeting/SelfTargeting.cpp
+++ b/cmds/idmap2/self_targeting/SelfTargeting.cpp
@@ -53,7 +53,7 @@
if (entry_params.data_binary_value.has_value()) {
builder.SetResourceValue(entry_params.resource_name, *entry_params.data_binary_value,
entry_params.binary_data_offset, entry_params.binary_data_size,
- entry_params.configuration);
+ entry_params.configuration, entry_params.nine_patch);
} else if (dataType >= Res_value::TYPE_FIRST_INT && dataType <= Res_value::TYPE_LAST_INT) {
builder.SetResourceValue(entry_params.resource_name, dataType,
entry_params.data_value, entry_params.configuration);
diff --git a/cmds/idmap2/tests/FabricatedOverlayTests.cpp b/cmds/idmap2/tests/FabricatedOverlayTests.cpp
index b460bb3..6b1c7e8 100644
--- a/cmds/idmap2/tests/FabricatedOverlayTests.cpp
+++ b/cmds/idmap2/tests/FabricatedOverlayTests.cpp
@@ -59,7 +59,7 @@
Res_value::TYPE_STRING,
"foobar",
"en-rUS-normal-xxhdpi-v21")
- .SetResourceValue("com.example.target:drawable/dr1", fd, 0, 8341, "port-xxhdpi-v7")
+ .SetResourceValue("com.example.target:drawable/dr1", fd, 0, 8341, "port-xxhdpi-v7", false)
.setFrroPath("/foo/bar/biz.frro")
.Build();
ASSERT_TRUE(overlay);
diff --git a/cmds/idmap2/tests/IdmapTests.cpp b/cmds/idmap2/tests/IdmapTests.cpp
index a3448fd..a384305 100644
--- a/cmds/idmap2/tests/IdmapTests.cpp
+++ b/cmds/idmap2/tests/IdmapTests.cpp
@@ -269,7 +269,7 @@
.SetResourceValue("integer/int1", Res_value::TYPE_INT_DEC, 2U, "land-xxhdpi-v7")
.SetResourceValue("string/str1", Res_value::TYPE_REFERENCE, 0x7f010000, "land")
.SetResourceValue("string/str2", Res_value::TYPE_STRING, "foobar", "xxhdpi-v7")
- .SetResourceValue("drawable/dr1", fd, 0, 8341, "port-xxhdpi-v7")
+ .SetResourceValue("drawable/dr1", fd, 0, 8341, "port-xxhdpi-v7", false)
.setFrroPath("/foo/bar/biz.frro")
.Build();
diff --git a/cmds/idmap2/tests/ResourceMappingTests.cpp b/cmds/idmap2/tests/ResourceMappingTests.cpp
index 40f98c2..db44c23 100644
--- a/cmds/idmap2/tests/ResourceMappingTests.cpp
+++ b/cmds/idmap2/tests/ResourceMappingTests.cpp
@@ -212,7 +212,7 @@
.SetResourceValue("integer/int1", Res_value::TYPE_INT_DEC, 2U, "")
.SetResourceValue("string/str1", Res_value::TYPE_REFERENCE, 0x7f010000, "")
.SetResourceValue("string/str2", Res_value::TYPE_STRING, "foobar", "")
- .SetResourceValue("drawable/dr1", fd, 0, 8341, "")
+ .SetResourceValue("drawable/dr1", fd, 0, 8341, "", false)
.setFrroPath("/foo/bar/biz.frro")
.Build();
diff --git a/core/api/current.txt b/core/api/current.txt
index 6e98706..7731fac 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -11787,6 +11787,7 @@
public class FabricatedOverlay {
ctor public FabricatedOverlay(@NonNull String, @NonNull String);
method @NonNull public android.content.om.OverlayIdentifier getIdentifier();
+ method @FlaggedApi("android.content.res.nine_patch_frro") @NonNull public void setNinePatchResourceValue(@NonNull String, @NonNull android.os.ParcelFileDescriptor, @Nullable String);
method @NonNull public void setResourceValue(@NonNull String, @IntRange(from=android.util.TypedValue.TYPE_FIRST_INT, to=android.util.TypedValue.TYPE_LAST_INT) int, int, @Nullable String);
method @NonNull public void setResourceValue(@NonNull String, int, @NonNull String, @Nullable String);
method @NonNull public void setResourceValue(@NonNull String, @NonNull android.os.ParcelFileDescriptor, @Nullable String);
@@ -13044,7 +13045,7 @@
field public static final int MATCH_DIRECT_BOOT_UNAWARE = 262144; // 0x40000
field public static final int MATCH_DISABLED_COMPONENTS = 512; // 0x200
field public static final int MATCH_DISABLED_UNTIL_USED_COMPONENTS = 32768; // 0x8000
- field @FlaggedApi("android.content.pm.quarantined_enabled") public static final long MATCH_QUARANTINED_COMPONENTS = 4294967296L; // 0x100000000L
+ field @FlaggedApi("android.content.pm.quarantined_enabled") public static final long MATCH_QUARANTINED_COMPONENTS = 8589934592L; // 0x200000000L
field public static final int MATCH_SYSTEM_ONLY = 1048576; // 0x100000
field public static final int MATCH_UNINSTALLED_PACKAGES = 8192; // 0x2000
field public static final long MAXIMUM_VERIFICATION_TIMEOUT = 3600000L; // 0x36ee80L
@@ -24168,6 +24169,7 @@
method @Nullable public android.media.MediaRouter2.RoutingController getController(@NonNull String);
method @NonNull public java.util.List<android.media.MediaRouter2.RoutingController> getControllers();
method @NonNull public static android.media.MediaRouter2 getInstance(@NonNull android.content.Context);
+ method @FlaggedApi("com.android.media.flags.enable_cross_user_routing_in_media_router2") @NonNull @RequiresPermission(anyOf={android.Manifest.permission.MEDIA_CONTENT_CONTROL, android.Manifest.permission.MEDIA_ROUTING_CONTROL}) public static android.media.MediaRouter2 getInstance(@NonNull android.content.Context, @NonNull android.os.Looper, @NonNull String, @NonNull android.os.UserHandle);
method @FlaggedApi("com.android.media.flags.enable_rlp_callbacks_in_media_router2") @Nullable public android.media.RouteListingPreference getRouteListingPreference();
method @NonNull public java.util.List<android.media.MediaRoute2Info> getRoutes();
method @NonNull public android.media.MediaRouter2.RoutingController getSystemController();
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index dc39bea..f5b9b17 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -251,6 +251,7 @@
field public static final String OBSERVE_SENSOR_PRIVACY = "android.permission.OBSERVE_SENSOR_PRIVACY";
field public static final String OPEN_ACCESSIBILITY_DETAILS_SETTINGS = "android.permission.OPEN_ACCESSIBILITY_DETAILS_SETTINGS";
field public static final String OVERRIDE_COMPAT_CHANGE_CONFIG_ON_RELEASE_BUILD = "android.permission.OVERRIDE_COMPAT_CHANGE_CONFIG_ON_RELEASE_BUILD";
+ field @FlaggedApi("com.android.input.flags.override_key_behavior_permission_apis") public static final String OVERRIDE_SYSTEM_KEY_BEHAVIOR_IN_FOCUSED_WINDOW = "android.permission.OVERRIDE_SYSTEM_KEY_BEHAVIOR_IN_FOCUSED_WINDOW";
field public static final String PACKAGE_VERIFICATION_AGENT = "android.permission.PACKAGE_VERIFICATION_AGENT";
field public static final String PACKET_KEEPALIVE_OFFLOAD = "android.permission.PACKET_KEEPALIVE_OFFLOAD";
field public static final String PEERS_MAC_ADDRESS = "android.permission.PEERS_MAC_ADDRESS";
@@ -13040,6 +13041,7 @@
method @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_HOTWORD_DETECTION) public final android.service.voice.HotwordDetector createHotwordDetector(@Nullable android.os.PersistableBundle, @Nullable android.os.SharedMemory, @NonNull java.util.concurrent.Executor, @NonNull android.service.voice.HotwordDetector.Callback);
method @NonNull @RequiresPermission("android.permission.MANAGE_VOICE_KEYPHRASES") public final android.media.voice.KeyphraseModelManager createKeyphraseModelManager();
method @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_HOTWORD_DETECTION) public final android.service.voice.VisualQueryDetector createVisualQueryDetector(@Nullable android.os.PersistableBundle, @Nullable android.os.SharedMemory, @NonNull java.util.concurrent.Executor, @NonNull android.service.voice.VisualQueryDetector.Callback);
+ method @FlaggedApi("android.service.voice.flags.allow_training_data_egress_from_hds") @RequiresPermission(android.Manifest.permission.MANAGE_HOTWORD_DETECTION) public void setIsReceiveSandboxedTrainingDataAllowed(boolean);
}
}
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index 71a05a9..98a78cf 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -1162,6 +1162,13 @@
field public static final int SHOW_IN_LAUNCHER_WITH_PARENT = 0; // 0x0
}
+ public static final class UserProperties.Builder {
+ ctor public UserProperties.Builder();
+ method @NonNull public android.content.pm.UserProperties build();
+ method @NonNull public android.content.pm.UserProperties.Builder setShowInQuietMode(int);
+ method @NonNull public android.content.pm.UserProperties.Builder setShowInSharingSurfaces(int);
+ }
+
}
package android.content.res {
@@ -1597,6 +1604,10 @@
method public void restoreDozeSettings(int);
}
+ public final class ColorDisplayManager {
+ method @FlaggedApi("android.app.modes_api") @RequiresPermission(android.Manifest.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS) public boolean isSaturationActivated();
+ }
+
public final class DisplayManager {
method public boolean areUserDisabledHdrTypesAllowed();
method @RequiresPermission(android.Manifest.permission.MODIFY_USER_PREFERRED_DISPLAY_MODE) public void clearGlobalUserPreferredDisplayMode();
diff --git a/core/java/android/accessibilityservice/AccessibilityService.java b/core/java/android/accessibilityservice/AccessibilityService.java
index 1000612..2a7dbab 100644
--- a/core/java/android/accessibilityservice/AccessibilityService.java
+++ b/core/java/android/accessibilityservice/AccessibilityService.java
@@ -566,8 +566,10 @@
public static final int GLOBAL_ACTION_TAKE_SCREENSHOT = 9;
/**
- * Action to send the KEYCODE_HEADSETHOOK KeyEvent, which is used to answer/hang up calls and
- * play/stop media
+ * Action to send the KEYCODE_HEADSETHOOK KeyEvent, which is used to answer and hang up calls
+ * and play and stop media. Calling takes priority. If there is an incoming call,
+ * this action can be used to answer that call, and if there is an ongoing call, to hang up on
+ * that call.
*/
public static final int GLOBAL_ACTION_KEYCODE_HEADSETHOOK = 10;
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 8af1216..adaaee2 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -2292,7 +2292,8 @@
case DUMP_HEAP: return "DUMP_HEAP";
case DUMP_ACTIVITY: return "DUMP_ACTIVITY";
case SET_CORE_SETTINGS: return "SET_CORE_SETTINGS";
- case UPDATE_PACKAGE_COMPATIBILITY_INFO: return "UPDATE_PACKAGE_COMPATIBILITY_INFO";
+ case UPDATE_PACKAGE_COMPATIBILITY_INFO:
+ return "UPDATE_PACKAGE_COMPATIBILITY_INFO";
case DUMP_PROVIDER: return "DUMP_PROVIDER";
case UNSTABLE_PROVIDER_DIED: return "UNSTABLE_PROVIDER_DIED";
case REQUEST_ASSIST_CONTEXT_EXTRAS: return "REQUEST_ASSIST_CONTEXT_EXTRAS";
@@ -3804,7 +3805,7 @@
boolean isSandboxActivityContext =
sandboxActivitySdkBasedContext()
- && SdkSandboxActivityAuthority.isSdkSandboxActivity(
+ && SdkSandboxActivityAuthority.isSdkSandboxActivityIntent(
mSystemContext, r.intent);
boolean isSandboxedSdkContextUsed = false;
ContextImpl activityBaseContext;
diff --git a/core/java/android/app/KeyguardManager.java b/core/java/android/app/KeyguardManager.java
index 6aad168..8b8576a 100644
--- a/core/java/android/app/KeyguardManager.java
+++ b/core/java/android/app/KeyguardManager.java
@@ -683,10 +683,11 @@
* <p>
* Specifically, this returns {@code true} if at least one of the following is true:
* <ul>
- * <li>The {@link Context}'s user has a secure lock screen. A full user has a secure lock
- * screen if its lock screen is set to PIN, pattern, or password, as opposed to swipe or none.
- * A profile that uses a unified challenge is considered to have a secure lock screen if and
- * only if its parent user has a secure lock screen.</li>
+ * <li>The {@link Context}'s user has a secure lock screen. A full user or a profile that uses
+ * a separate challenge has a secure lock screen if its lock screen is set to PIN, pattern, or
+ * password, as opposed to swipe or none. A profile that uses a unified challenge is
+ * considered to have a secure lock screen if and only if its parent user has a secure lock
+ * screen.</li>
* <li>At least one SIM card is currently locked and requires a PIN.</li>
* </ul>
* <p>
@@ -733,8 +734,15 @@
* <p>
* For a user that is not the current user but can be switched to (usually this means "another
* full user"), and that has a PIN, pattern, or password, the device is always considered
- * locked. For a profile with a unified challenge, the device is considered locked if and only
- * if the device is locked for the parent user.
+ * locked.
+ * <p>
+ * For a profile with a unified challenge, the device locked state is the same as that of the
+ * parent user.
+ * <p>
+ * For a profile with a separate challenge, the device becomes unlocked when the profile's PIN,
+ * pattern, password, or biometric is verified. It becomes locked when the parent user becomes
+ * locked, the screen turns off, the device reboots, the device policy controller locks the
+ * profile, or the timeout set by the device policy controller expires.
*
* @return {@code true} if the device is currently locked for the user
* @see #isKeyguardLocked()
@@ -770,9 +778,10 @@
* Returns whether the user has a secure lock screen.
* <p>
* This returns {@code true} if the {@link Context}'s user has a secure lock screen. A full user
- * has a secure lock screen if its lock screen is set to PIN, pattern, or password, as opposed
- * to swipe or none. A profile that uses a unified challenge is considered to have a secure lock
- * screen if and only if its parent user has a secure lock screen.
+ * or a profile that uses a separate challenge has a secure lock screen if its lock screen is
+ * set to PIN, pattern, or password, as opposed to swipe or none. A profile that uses a unified
+ * challenge is considered to have a secure lock screen if and only if its parent user has a
+ * secure lock screen.
* <p>
* This method does not consider whether the lock screen is currently showing or not.
* <p>
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index c003540..013bcdd 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -9209,12 +9209,6 @@
* You can opt-out of this behavior by using {@link Notification.Builder#setColorized(boolean)}.
* <p>
*
- * <p>
- * Starting at {@link android.os.Build.VERSION_CODES#VANILLA_ICE_CREAM Android V} the
- * {@link Notification#FLAG_NO_CLEAR NO_CLEAR flag} will be set for valid MediaStyle
- * notifications.
- * <p>
- *
* To use this style with your Notification, feed it to
* {@link Notification.Builder#setStyle(android.app.Notification.Style)} like so:
* <pre class="prettyprint">
diff --git a/core/java/android/app/WallpaperManager.java b/core/java/android/app/WallpaperManager.java
index d660078..820ff3e 100644
--- a/core/java/android/app/WallpaperManager.java
+++ b/core/java/android/app/WallpaperManager.java
@@ -21,6 +21,8 @@
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.os.ParcelFileDescriptor.MODE_READ_ONLY;
+import static com.android.window.flags.Flags.multiCrop;
+
import android.annotation.FloatRange;
import android.annotation.IntDef;
import android.annotation.NonNull;
@@ -857,8 +859,7 @@
*/
public static boolean isMultiCropEnabled() {
if (sGlobals == null) {
- sIsMultiCropEnabled = SystemProperties.getBoolean(
- "persist.wm.debug.wallpaper_multi_crop", false);
+ sIsMultiCropEnabled = multiCrop();
}
if (sIsMultiCropEnabled == null) {
try {
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index fc3a906..1e538c5 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -9146,7 +9146,7 @@
@UserHandleAware(enabledSinceTargetSdkVersion = Build.VERSION_CODES.VANILLA_ICE_CREAM)
public boolean isDeviceOwnerApp(String packageName) {
throwIfParentInstance("isDeviceOwnerApp");
- if (android.permission.flags.Flags.roleControllerInSystemServer()
+ if (android.permission.flags.Flags.systemServerRoleControllerEnabled()
&& CompatChanges.isChangeEnabled(IS_DEVICE_OWNER_USER_AWARE)) {
return isDeviceOwnerAppOnContextUser(packageName);
}
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 38bcfa2..23a5d4d 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -2805,7 +2805,7 @@
* and the package in the stopped state cannot self-start for any reason unless there's an
* explicit request to start a component in the package. The {@link #ACTION_PACKAGE_UNSTOPPED}
* broadcast is sent when such an explicit process start occurs and the package is taken
- * out of the stopped state.
+ * out of the stopped state. The data contains the name of the package.
* </p>
* <ul>
* <li> {@link #EXTRA_UID} containing the integer uid assigned to the package.
@@ -12606,8 +12606,11 @@
}
/**
- * @deprecated Use {@link SdkSandboxActivityAuthority#isSdkSandboxActivity} instead.
+ * @deprecated Use {@link SdkSandboxActivityAuthority#isSdkSandboxActivityIntent} instead.
* Once the other API is finalized this method will be removed.
+ *
+ * TODO(b/300059435): remove as part of the cleanup.
+ *
* @hide
*/
@Deprecated
diff --git a/core/java/android/content/om/FabricatedOverlay.java b/core/java/android/content/om/FabricatedOverlay.java
index df2d7e7..40ffb0f 100644
--- a/core/java/android/content/om/FabricatedOverlay.java
+++ b/core/java/android/content/om/FabricatedOverlay.java
@@ -281,8 +281,8 @@
@NonNull ParcelFileDescriptor value,
@Nullable String configuration) {
ensureValidResourceName(resourceName);
- mEntries.add(
- generateFabricatedOverlayInternalEntry(resourceName, value, configuration));
+ mEntries.add(generateFabricatedOverlayInternalEntry(
+ resourceName, value, configuration, false));
return this;
}
@@ -361,6 +361,16 @@
}
/**
+ * Set the package that owns the overlay
+ *
+ * @param owningPackage the package that should own the overlay.
+ * @hide
+ */
+ public void setOwningPackage(@NonNull String owningPackage) {
+ mOverlay.packageName = owningPackage;
+ }
+
+ /**
* Set the target overlayable name of the overlay
*
* The target package defines may define several overlayables. The {@link FabricatedOverlay}
@@ -442,13 +452,14 @@
@NonNull
private static FabricatedOverlayInternalEntry generateFabricatedOverlayInternalEntry(
@NonNull String resourceName, @NonNull ParcelFileDescriptor parcelFileDescriptor,
- @Nullable String configuration) {
+ @Nullable String configuration, boolean isNinePatch) {
final FabricatedOverlayInternalEntry entry = new FabricatedOverlayInternalEntry();
entry.resourceName = resourceName;
entry.binaryData = Objects.requireNonNull(parcelFileDescriptor);
entry.configuration = configuration;
entry.binaryDataOffset = 0;
entry.binaryDataSize = parcelFileDescriptor.getStatSize();
+ entry.isNinePatch = isNinePatch;
return entry;
}
@@ -534,7 +545,26 @@
@Nullable String configuration) {
ensureValidResourceName(resourceName);
mOverlay.entries.add(
- generateFabricatedOverlayInternalEntry(resourceName, value, configuration));
+ generateFabricatedOverlayInternalEntry(resourceName, value, configuration, false));
+ }
+
+ /**
+ * Sets the resource value in the fabricated overlay from a nine patch.
+ *
+ * @param resourceName name of the target resource to overlay (in the form
+ * [package]:type/entry)
+ * @param value the file descriptor whose contents are the value of the frro
+ * @param configuration The string representation of the config this overlay is enabled for
+ */
+ @NonNull
+ @FlaggedApi(android.content.res.Flags.FLAG_NINE_PATCH_FRRO)
+ public void setNinePatchResourceValue(
+ @NonNull String resourceName,
+ @NonNull ParcelFileDescriptor value,
+ @Nullable String configuration) {
+ ensureValidResourceName(resourceName);
+ mOverlay.entries.add(
+ generateFabricatedOverlayInternalEntry(resourceName, value, configuration, true));
}
/**
diff --git a/core/java/android/content/pm/ActivityInfo.java b/core/java/android/content/pm/ActivityInfo.java
index 323592c..d13d962 100644
--- a/core/java/android/content/pm/ActivityInfo.java
+++ b/core/java/android/content/pm/ActivityInfo.java
@@ -55,6 +55,7 @@
* from the AndroidManifest.xml's <activity> and
* <receiver> tags.
*/
+@android.ravenwood.annotation.RavenwoodKeepWholeClass
public class ActivityInfo extends ComponentInfo implements Parcelable {
private static final Parcelling.BuiltIn.ForStringSet sForStringSet =
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index f0b99f1..16a80e9 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -66,6 +66,7 @@
* corresponds to information collected from the AndroidManifest.xml's
* <application> tag.
*/
+@android.ravenwood.annotation.RavenwoodKeepWholeClass
public class ApplicationInfo extends PackageItemInfo implements Parcelable {
private static final ForBoolean sForBoolean = Parcelling.Cache.getOrCreate(ForBoolean.class);
private static final Parcelling.BuiltIn.ForStringSet sForStringSet =
@@ -1386,6 +1387,7 @@
*
* @see #category
*/
+ @android.ravenwood.annotation.RavenwoodThrow(blockedBy = android.content.res.Resources.class)
public static CharSequence getCategoryTitle(Context context, @Category int category) {
switch (category) {
case ApplicationInfo.CATEGORY_GAME:
@@ -2187,6 +2189,7 @@
* @return Returns a CharSequence containing the application's description.
* If there is no description, null is returned.
*/
+ @android.ravenwood.annotation.RavenwoodThrow(blockedBy = android.content.res.Resources.class)
public CharSequence loadDescription(PackageManager pm) {
if (descriptionRes != 0) {
CharSequence label = pm.getText(packageName, descriptionRes, this);
@@ -2222,6 +2225,7 @@
}
/** {@hide} */
+ @android.ravenwood.annotation.RavenwoodThrow(blockedBy = Environment.class)
public void initForUser(int userId) {
uid = UserHandle.getUid(userId, UserHandle.getAppId(uid));
@@ -2414,6 +2418,7 @@
* @hide
*/
@Override
+ @android.ravenwood.annotation.RavenwoodThrow(blockedBy = android.content.res.Resources.class)
public Drawable loadDefaultIcon(PackageManager pm) {
if ((flags & FLAG_EXTERNAL_STORAGE) != 0
&& isPackageUnavailable(pm)) {
@@ -2424,6 +2429,7 @@
}
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
+ @android.ravenwood.annotation.RavenwoodThrow(blockedBy = PackageManager.class)
private boolean isPackageUnavailable(PackageManager pm) {
try {
return pm.getPackageInfo(packageName, 0) == null;
diff --git a/core/java/android/content/pm/ComponentInfo.java b/core/java/android/content/pm/ComponentInfo.java
index 42847c8..ff48ffa 100644
--- a/core/java/android/content/pm/ComponentInfo.java
+++ b/core/java/android/content/pm/ComponentInfo.java
@@ -37,6 +37,7 @@
* implement Parcelable, but does provide convenience methods to assist
* in the implementation of Parcelable in subclasses.
*/
+@android.ravenwood.annotation.RavenwoodKeepWholeClass
public class ComponentInfo extends PackageItemInfo {
/**
* Global information about the application/package this component is a
@@ -258,6 +259,7 @@
* @hide
*/
@Override
+ @android.ravenwood.annotation.RavenwoodThrow(blockedBy = android.content.res.Resources.class)
public Drawable loadDefaultIcon(PackageManager pm) {
return applicationInfo.loadIcon(pm);
}
@@ -265,6 +267,7 @@
/**
* @hide
*/
+ @android.ravenwood.annotation.RavenwoodThrow(blockedBy = android.content.res.Resources.class)
@Override protected Drawable loadDefaultBanner(PackageManager pm) {
return applicationInfo.loadBanner(pm);
}
@@ -273,6 +276,7 @@
* @hide
*/
@Override
+ @android.ravenwood.annotation.RavenwoodThrow(blockedBy = android.content.res.Resources.class)
protected Drawable loadDefaultLogo(PackageManager pm) {
return applicationInfo.loadLogo(pm);
}
diff --git a/core/java/android/content/pm/PackageInfo.java b/core/java/android/content/pm/PackageInfo.java
index 5736a6d..5dee65b 100644
--- a/core/java/android/content/pm/PackageInfo.java
+++ b/core/java/android/content/pm/PackageInfo.java
@@ -29,6 +29,7 @@
* Overall information about the contents of a package. This corresponds
* to all of the information collected from AndroidManifest.xml.
*/
+@android.ravenwood.annotation.RavenwoodKeepWholeClass
public class PackageInfo implements Parcelable {
/**
* The name of this package. From the <manifest> tag's "name"
diff --git a/core/java/android/content/pm/PackageItemInfo.java b/core/java/android/content/pm/PackageItemInfo.java
index 70e6f98..1f821b9 100644
--- a/core/java/android/content/pm/PackageItemInfo.java
+++ b/core/java/android/content/pm/PackageItemInfo.java
@@ -49,6 +49,7 @@
* itself implement Parcelable, but does provide convenience methods to assist
* in the implementation of Parcelable in subclasses.
*/
+@android.ravenwood.annotation.RavenwoodKeepWholeClass
public class PackageItemInfo {
/**
@@ -214,6 +215,7 @@
* @return Returns a CharSequence containing the item's label. If the
* item does not have a label, its name is returned.
*/
+ @android.ravenwood.annotation.RavenwoodThrow(blockedBy = android.content.res.Resources.class)
public @NonNull CharSequence loadLabel(@NonNull PackageManager pm) {
if (sForceSafeLabels && !Objects.equals(packageName, ActivityThread.currentPackageName())) {
return loadSafeLabel(pm, DEFAULT_MAX_LABEL_SIZE_PX, SAFE_STRING_FLAG_TRIM
@@ -226,6 +228,7 @@
}
/** {@hide} */
+ @android.ravenwood.annotation.RavenwoodThrow(blockedBy = android.content.res.Resources.class)
public CharSequence loadUnsafeLabel(PackageManager pm) {
if (nonLocalizedLabel != null) {
return nonLocalizedLabel;
@@ -248,6 +251,7 @@
*/
@SystemApi
@Deprecated
+ @android.ravenwood.annotation.RavenwoodThrow(blockedBy = android.content.res.Resources.class)
public @NonNull CharSequence loadSafeLabel(@NonNull PackageManager pm) {
return loadSafeLabel(pm, DEFAULT_MAX_LABEL_SIZE_PX, SAFE_STRING_FLAG_TRIM
| SAFE_STRING_FLAG_FIRST_LINE);
@@ -261,6 +265,7 @@
* @hide
*/
@SystemApi
+ @android.ravenwood.annotation.RavenwoodThrow(blockedBy = android.content.res.Resources.class)
public @NonNull CharSequence loadSafeLabel(@NonNull PackageManager pm,
@FloatRange(from = 0) float ellipsizeDip, @TextUtils.SafeStringFlags int flags) {
Objects.requireNonNull(pm);
@@ -281,6 +286,7 @@
* item does not have an icon, the item's default icon is returned
* such as the default activity icon.
*/
+ @android.ravenwood.annotation.RavenwoodThrow(blockedBy = android.content.res.Resources.class)
public Drawable loadIcon(PackageManager pm) {
return pm.loadItemIcon(this, getApplicationInfo());
}
@@ -298,6 +304,7 @@
* item does not have an icon, the item's default icon is returned
* such as the default activity icon.
*/
+ @android.ravenwood.annotation.RavenwoodThrow(blockedBy = android.content.res.Resources.class)
public Drawable loadUnbadgedIcon(PackageManager pm) {
return pm.loadUnbadgedItemIcon(this, getApplicationInfo());
}
@@ -313,6 +320,7 @@
* @return Returns a Drawable containing the item's banner. If the item
* does not have a banner, this method will return null.
*/
+ @android.ravenwood.annotation.RavenwoodThrow(blockedBy = android.content.res.Resources.class)
public Drawable loadBanner(PackageManager pm) {
if (banner != 0) {
Drawable dr = pm.getDrawable(packageName, banner, getApplicationInfo());
@@ -334,6 +342,7 @@
*
* @hide
*/
+ @android.ravenwood.annotation.RavenwoodThrow(blockedBy = android.content.res.Resources.class)
public Drawable loadDefaultIcon(PackageManager pm) {
return pm.getDefaultActivityIcon();
}
@@ -349,6 +358,7 @@
*
* @hide
*/
+ @android.ravenwood.annotation.RavenwoodThrow(blockedBy = android.content.res.Resources.class)
protected Drawable loadDefaultBanner(PackageManager pm) {
return null;
}
@@ -364,6 +374,7 @@
* @return Returns a Drawable containing the item's logo. If the item
* does not have a logo, this method will return null.
*/
+ @android.ravenwood.annotation.RavenwoodThrow(blockedBy = android.content.res.Resources.class)
public Drawable loadLogo(PackageManager pm) {
if (logo != 0) {
Drawable d = pm.getDrawable(packageName, logo, getApplicationInfo());
@@ -385,6 +396,7 @@
*
* @hide
*/
+ @android.ravenwood.annotation.RavenwoodThrow(blockedBy = android.content.res.Resources.class)
protected Drawable loadDefaultLogo(PackageManager pm) {
return null;
}
@@ -402,6 +414,7 @@
* assigned as the given meta-data. If the meta-data name is not defined
* or the XML resource could not be found, null is returned.
*/
+ @android.ravenwood.annotation.RavenwoodThrow(blockedBy = android.content.res.Resources.class)
public XmlResourceParser loadXmlMetaData(PackageManager pm, String name) {
if (metaData != null) {
int resid = metaData.getInt(name);
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 7bb673a..607e904 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -1279,7 +1279,7 @@
* @see #isPackageQuarantined
*/
@FlaggedApi(android.content.pm.Flags.FLAG_QUARANTINED_ENABLED)
- public static final long MATCH_QUARANTINED_COMPONENTS = 0x100000000L;
+ public static final long MATCH_QUARANTINED_COMPONENTS = 1L << 33;
/**
* Flag for {@link #addCrossProfileIntentFilter}: if this flag is set: when
diff --git a/core/java/android/content/pm/PathPermission.java b/core/java/android/content/pm/PathPermission.java
index 11c9a7d..743ff9a 100644
--- a/core/java/android/content/pm/PathPermission.java
+++ b/core/java/android/content/pm/PathPermission.java
@@ -24,6 +24,7 @@
* Description of permissions needed to access a particular path
* in a {@link ProviderInfo}.
*/
+@android.ravenwood.annotation.RavenwoodKeepWholeClass
public class PathPermission extends PatternMatcher {
private final String mReadPermission;
private final String mWritePermission;
diff --git a/core/java/android/content/pm/ProviderInfo.java b/core/java/android/content/pm/ProviderInfo.java
index 3984ade..9e553db 100644
--- a/core/java/android/content/pm/ProviderInfo.java
+++ b/core/java/android/content/pm/ProviderInfo.java
@@ -27,6 +27,7 @@
* {@link android.content.pm.PackageManager#resolveContentProvider(java.lang.String, int)
* PackageManager.resolveContentProvider()}.
*/
+@android.ravenwood.annotation.RavenwoodKeepWholeClass
public final class ProviderInfo extends ComponentInfo
implements Parcelable {
diff --git a/core/java/android/content/pm/ResolveInfo.java b/core/java/android/content/pm/ResolveInfo.java
index 36c03fd..25bb9e1 100644
--- a/core/java/android/content/pm/ResolveInfo.java
+++ b/core/java/android/content/pm/ResolveInfo.java
@@ -42,6 +42,7 @@
* information collected from the AndroidManifest.xml's
* <intent> tags.
*/
+@android.ravenwood.annotation.RavenwoodKeepWholeClass
public class ResolveInfo implements Parcelable {
private static final String TAG = "ResolveInfo";
private static final String INTENT_FORWARDER_ACTIVITY =
@@ -227,6 +228,7 @@
* item does not have a label, its name is returned.
*/
@NonNull
+ @android.ravenwood.annotation.RavenwoodThrow(blockedBy = android.content.res.Resources.class)
public CharSequence loadLabel(@NonNull PackageManager pm) {
if (nonLocalizedLabel != null) {
return nonLocalizedLabel;
@@ -304,6 +306,7 @@
* @return Returns a Drawable containing the resolution's icon. If the
* item does not have an icon, the default activity icon is returned.
*/
+ @android.ravenwood.annotation.RavenwoodThrow(blockedBy = android.content.res.Resources.class)
public Drawable loadIcon(PackageManager pm) {
Drawable dr = null;
if (resolvePackageName != null && iconResourceId != 0) {
diff --git a/core/java/android/content/pm/ServiceInfo.java b/core/java/android/content/pm/ServiceInfo.java
index 9869179..4d704c3 100644
--- a/core/java/android/content/pm/ServiceInfo.java
+++ b/core/java/android/content/pm/ServiceInfo.java
@@ -31,6 +31,7 @@
* service. This corresponds to information collected from the
* AndroidManifest.xml's <service> tags.
*/
+@android.ravenwood.annotation.RavenwoodKeepWholeClass
public class ServiceInfo extends ComponentInfo
implements Parcelable {
/**
diff --git a/core/java/android/content/pm/Signature.java b/core/java/android/content/pm/Signature.java
index a69eee7..f173334 100644
--- a/core/java/android/content/pm/Signature.java
+++ b/core/java/android/content/pm/Signature.java
@@ -43,6 +43,7 @@
* <p>
* This class name is slightly misleading, since it's not actually a signature.
*/
+@android.ravenwood.annotation.RavenwoodKeepWholeClass
public class Signature implements Parcelable {
private final byte[] mSignature;
private int mHashCode;
diff --git a/core/java/android/content/pm/UserProperties.java b/core/java/android/content/pm/UserProperties.java
index 445ca0c..56e8291 100644
--- a/core/java/android/content/pm/UserProperties.java
+++ b/core/java/android/content/pm/UserProperties.java
@@ -1076,6 +1076,8 @@
* Intended for building default values (and so all properties are present in the built object).
* @hide
*/
+ @TestApi
+ @SuppressLint("UnflaggedApi") // b/306636213
public static final class Builder {
// UserProperties fields and their default values.
private @ShowInLauncher int mShowInLauncher = SHOW_IN_LAUNCHER_WITH_PARENT;
@@ -1099,54 +1101,82 @@
private boolean mDeleteAppWithParent = false;
private boolean mAlwaysVisible = false;
+ /**
+ * @hide
+ */
+ @SuppressLint("UnflaggedApi") // b/306636213
+ @TestApi
+ public Builder() {}
+
+ /** @hide */
public Builder setShowInLauncher(@ShowInLauncher int showInLauncher) {
mShowInLauncher = showInLauncher;
return this;
}
+ /** @hide */
public Builder setStartWithParent(boolean startWithParent) {
mStartWithParent = startWithParent;
return this;
}
- /** Sets the value for {@link #mShowInSettings} */
+ /** Sets the value for {@link #mShowInSettings}
+ * @hide
+ */
public Builder setShowInSettings(@ShowInSettings int showInSettings) {
mShowInSettings = showInSettings;
return this;
}
- /** Sets the value for {@link #mShowInQuietMode} */
+ /** Sets the value for {@link #mShowInQuietMode}
+ * @hide
+ */
+ @TestApi
+ @SuppressLint("UnflaggedApi") // b/306636213
+ @NonNull
public Builder setShowInQuietMode(@ShowInQuietMode int showInQuietMode) {
mShowInQuietMode = showInQuietMode;
return this;
}
- /** Sets the value for {@link #mShowInSharingSurfaces}. */
+ /** Sets the value for {@link #mShowInSharingSurfaces}.
+ * @hide
+ */
+ @TestApi
+ @SuppressLint("UnflaggedApi") // b/306636213
+ @NonNull
public Builder setShowInSharingSurfaces(@ShowInSharingSurfaces int showInSharingSurfaces) {
mShowInSharingSurfaces = showInSharingSurfaces;
return this;
}
- /** Sets the value for {@link #mInheritDevicePolicy}*/
+ /** Sets the value for {@link #mInheritDevicePolicy}
+ * @hide
+ */
public Builder setInheritDevicePolicy(
@InheritDevicePolicy int inheritRestrictionsDevicePolicy) {
mInheritDevicePolicy = inheritRestrictionsDevicePolicy;
return this;
}
+ /** @hide */
public Builder setUseParentsContacts(boolean useParentsContacts) {
mUseParentsContacts = useParentsContacts;
return this;
}
- /** Sets the value for {@link #mUpdateCrossProfileIntentFiltersOnOTA} */
+ /** Sets the value for {@link #mUpdateCrossProfileIntentFiltersOnOTA}
+ * @hide
+ */
public Builder setUpdateCrossProfileIntentFiltersOnOTA(boolean
updateCrossProfileIntentFiltersOnOTA) {
mUpdateCrossProfileIntentFiltersOnOTA = updateCrossProfileIntentFiltersOnOTA;
return this;
}
- /** Sets the value for {@link #mCrossProfileIntentFilterAccessControl} */
+ /** Sets the value for {@link #mCrossProfileIntentFilterAccessControl}
+ * @hide
+ */
public Builder setCrossProfileIntentFilterAccessControl(
@CrossProfileIntentFilterAccessControlLevel int
crossProfileIntentFilterAccessControl) {
@@ -1154,24 +1184,30 @@
return this;
}
- /** Sets the value for {@link #mCrossProfileIntentResolutionStrategy} */
+ /** Sets the value for {@link #mCrossProfileIntentResolutionStrategy}
+ * @hide
+ */
public Builder setCrossProfileIntentResolutionStrategy(@CrossProfileIntentResolutionStrategy
int crossProfileIntentResolutionStrategy) {
mCrossProfileIntentResolutionStrategy = crossProfileIntentResolutionStrategy;
return this;
}
+ /** @hide */
public Builder setMediaSharedWithParent(boolean mediaSharedWithParent) {
mMediaSharedWithParent = mediaSharedWithParent;
return this;
}
+ /** @hide */
public Builder setCredentialShareableWithParent(boolean credentialShareableWithParent) {
mCredentialShareableWithParent = credentialShareableWithParent;
return this;
}
- /** Sets the value for {@link #mAuthAlwaysRequiredToDisableQuietMode} */
+ /** Sets the value for {@link #mAuthAlwaysRequiredToDisableQuietMode}
+ * @hide
+ */
public Builder setAuthAlwaysRequiredToDisableQuietMode(
boolean authAlwaysRequiredToDisableQuietMode) {
mAuthAlwaysRequiredToDisableQuietMode =
@@ -1179,19 +1215,28 @@
return this;
}
- /** Sets the value for {@link #mDeleteAppWithParent}*/
+ /** Sets the value for {@link #mDeleteAppWithParent}
+ * @hide
+ */
public Builder setDeleteAppWithParent(boolean deleteAppWithParent) {
mDeleteAppWithParent = deleteAppWithParent;
return this;
}
- /** Sets the value for {@link #mAlwaysVisible}*/
+ /** Sets the value for {@link #mAlwaysVisible}
+ * @hide
+ */
public Builder setAlwaysVisible(boolean alwaysVisible) {
mAlwaysVisible = alwaysVisible;
return this;
}
- /** Builds a UserProperties object with *all* values populated. */
+ /** Builds a UserProperties object with *all* values populated.
+ * @hide
+ */
+ @TestApi
+ @SuppressLint("UnflaggedApi") // b/306636213
+ @NonNull
public UserProperties build() {
return new UserProperties(
mShowInLauncher,
diff --git a/core/java/android/content/res/flags.aconfig b/core/java/android/content/res/flags.aconfig
index 40592a1..3a00d91 100644
--- a/core/java/android/content/res/flags.aconfig
+++ b/core/java/android/content/res/flags.aconfig
@@ -24,3 +24,10 @@
# This flag is read in PackageParser at boot time, and in aapt2 which is a build tool.
is_fixed_read_only: true
}
+
+flag {
+ name: "nine_patch_frro"
+ namespace: "resource_manager"
+ description: "Feature flag for creating an frro from a 9-patch"
+ bug: "309232726"
+}
diff --git a/core/java/android/hardware/display/ColorDisplayManager.java b/core/java/android/hardware/display/ColorDisplayManager.java
index aafa7d5..f927b8b 100644
--- a/core/java/android/hardware/display/ColorDisplayManager.java
+++ b/core/java/android/hardware/display/ColorDisplayManager.java
@@ -17,12 +17,14 @@
package android.hardware.display;
import android.Manifest;
+import android.annotation.FlaggedApi;
import android.annotation.IntDef;
import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
import android.annotation.SystemService;
+import android.annotation.TestApi;
import android.content.ContentResolver;
import android.content.Context;
import android.metrics.LogMaker;
@@ -397,6 +399,8 @@
* @return {@code true} if the display is not at full saturation
* @hide
*/
+ @TestApi
+ @FlaggedApi(android.app.Flags.FLAG_MODES_API)
@RequiresPermission(Manifest.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS)
public boolean isSaturationActivated() {
return mManager.isSaturationActivated();
diff --git a/core/java/android/os/OWNERS b/core/java/android/os/OWNERS
index 655debc..209a595 100644
--- a/core/java/android/os/OWNERS
+++ b/core/java/android/os/OWNERS
@@ -90,4 +90,5 @@
# IThermal interfaces
per-file IThermal* = file:/THERMAL_OWNERS
-
+per-file CoolingDevice.java = file:/THERMAL_OWNERS
+per-file Temperature.java = file:/THERMAL_OWNERS
diff --git a/core/java/android/permission/flags.aconfig b/core/java/android/permission/flags.aconfig
index 5cbc18e..cbeb821 100644
--- a/core/java/android/permission/flags.aconfig
+++ b/core/java/android/permission/flags.aconfig
@@ -16,7 +16,7 @@
}
flag {
- name: "role_controller_in_system_server"
+ name: "system_server_role_controller_enabled"
is_fixed_read_only: true
namespace: "permissions"
description: "enable role controller in system server"
diff --git a/core/java/android/security/FileIntegrityManager.java b/core/java/android/security/FileIntegrityManager.java
index dae3202..025aac9 100644
--- a/core/java/android/security/FileIntegrityManager.java
+++ b/core/java/android/security/FileIntegrityManager.java
@@ -53,10 +53,10 @@
* verification, although the app APIs are only made available to apps in a later SDK version.
* Only when this method returns true, the other fs-verity APIs in the same class can succeed.
*
- * <p>The app may not need this method and just call the other APIs (i.e. {@link
- * #setupFsVerity(File)} and {@link #getFsVerityDigest(File)}) normally and handle any failure.
- * If some app feature really depends on fs-verity (e.g. protecting integrity of a large file
- * download), an early check of support status may avoid any cost if it is to fail late.
+ * <p>The app may not need this method and just call the other APIs normally and handle any
+ * failure. If some app feature really depends on fs-verity (e.g. protecting integrity of a
+ * large file download), an early check of support status may avoid any cost if it is to fail
+ * late.
*
* <p>Note: for historical reasons this is named {@code isApkVeritySupported()} instead of
* {@code isFsVeritySupported()}. It has also been available since API level 30, predating the
diff --git a/core/java/android/service/autofill/FillRequest.java b/core/java/android/service/autofill/FillRequest.java
index 7ec1483..ca20801 100644
--- a/core/java/android/service/autofill/FillRequest.java
+++ b/core/java/android/service/autofill/FillRequest.java
@@ -127,6 +127,12 @@
*/
public static final @RequestFlags int FLAG_SCREEN_HAS_CREDMAN_FIELD = 0x400;
+ /**
+ * Indicate whether the user has focused on a credman field view.
+ * @hide
+ */
+ public static final @RequestFlags int FLAG_VIEW_REQUESTS_CREDMAN_SERVICE = 0x800;
+
/** @hide */
public static final int INVALID_REQUEST_ID = Integer.MIN_VALUE;
@@ -241,7 +247,8 @@
FLAG_IME_SHOWING,
FLAG_RESET_FILL_DIALOG_STATE,
FLAG_PCC_DETECTION,
- FLAG_SCREEN_HAS_CREDMAN_FIELD
+ FLAG_SCREEN_HAS_CREDMAN_FIELD,
+ FLAG_VIEW_REQUESTS_CREDMAN_SERVICE
})
@Retention(RetentionPolicy.SOURCE)
@DataClass.Generated.Member
@@ -275,6 +282,8 @@
return "FLAG_PCC_DETECTION";
case FLAG_SCREEN_HAS_CREDMAN_FIELD:
return "FLAG_SCREEN_HAS_CREDMAN_FIELD";
+ case FLAG_VIEW_REQUESTS_CREDMAN_SERVICE:
+ return "FLAG_VIEW_REQUESTS_CREDMAN_SERVICE";
default: return Integer.toHexString(value);
}
}
@@ -368,7 +377,8 @@
| FLAG_IME_SHOWING
| FLAG_RESET_FILL_DIALOG_STATE
| FLAG_PCC_DETECTION
- | FLAG_SCREEN_HAS_CREDMAN_FIELD);
+ | FLAG_SCREEN_HAS_CREDMAN_FIELD
+ | FLAG_VIEW_REQUESTS_CREDMAN_SERVICE);
this.mInlineSuggestionsRequest = inlineSuggestionsRequest;
this.mDelayedFillIntentSender = delayedFillIntentSender;
@@ -555,7 +565,8 @@
| FLAG_IME_SHOWING
| FLAG_RESET_FILL_DIALOG_STATE
| FLAG_PCC_DETECTION
- | FLAG_SCREEN_HAS_CREDMAN_FIELD);
+ | FLAG_SCREEN_HAS_CREDMAN_FIELD
+ | FLAG_VIEW_REQUESTS_CREDMAN_SERVICE);
this.mInlineSuggestionsRequest = inlineSuggestionsRequest;
this.mDelayedFillIntentSender = delayedFillIntentSender;
@@ -577,10 +588,10 @@
};
@DataClass.Generated(
- time = 1682097266850L,
+ time = 1701010178309L,
codegenVersion = "1.0.23",
sourceFile = "frameworks/base/core/java/android/service/autofill/FillRequest.java",
- inputSignatures = "public static final @android.service.autofill.FillRequest.RequestFlags int FLAG_MANUAL_REQUEST\npublic static final @android.service.autofill.FillRequest.RequestFlags int FLAG_COMPATIBILITY_MODE_REQUEST\npublic static final @android.service.autofill.FillRequest.RequestFlags int FLAG_PASSWORD_INPUT_TYPE\npublic static final @android.service.autofill.FillRequest.RequestFlags int FLAG_VIEW_NOT_FOCUSED\npublic static final @android.service.autofill.FillRequest.RequestFlags int FLAG_SUPPORTS_FILL_DIALOG\npublic static final @android.service.autofill.FillRequest.RequestFlags int FLAG_IME_SHOWING\npublic static final @android.service.autofill.FillRequest.RequestFlags int FLAG_RESET_FILL_DIALOG_STATE\npublic static final @android.service.autofill.FillRequest.RequestFlags int FLAG_PCC_DETECTION\npublic static final @android.service.autofill.FillRequest.RequestFlags int FLAG_SCREEN_HAS_CREDMAN_FIELD\npublic static final int INVALID_REQUEST_ID\nprivate final int mId\nprivate final @android.annotation.NonNull java.util.List<android.service.autofill.FillContext> mFillContexts\nprivate final @android.annotation.NonNull java.util.List<java.lang.String> mHints\nprivate final @android.annotation.Nullable android.os.Bundle mClientState\nprivate final @android.service.autofill.FillRequest.RequestFlags int mFlags\nprivate final @android.annotation.Nullable android.view.inputmethod.InlineSuggestionsRequest mInlineSuggestionsRequest\nprivate final @android.annotation.Nullable android.content.IntentSender mDelayedFillIntentSender\nprivate void onConstructed()\nclass FillRequest extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genToString=true, genHiddenConstructor=true, genHiddenConstDefs=true)")
+ inputSignatures = "public static final @android.service.autofill.FillRequest.RequestFlags int FLAG_MANUAL_REQUEST\npublic static final @android.service.autofill.FillRequest.RequestFlags int FLAG_COMPATIBILITY_MODE_REQUEST\npublic static final @android.service.autofill.FillRequest.RequestFlags int FLAG_PASSWORD_INPUT_TYPE\npublic static final @android.service.autofill.FillRequest.RequestFlags int FLAG_VIEW_NOT_FOCUSED\npublic static final @android.service.autofill.FillRequest.RequestFlags int FLAG_SUPPORTS_FILL_DIALOG\npublic static final @android.service.autofill.FillRequest.RequestFlags int FLAG_IME_SHOWING\npublic static final @android.service.autofill.FillRequest.RequestFlags int FLAG_RESET_FILL_DIALOG_STATE\npublic static final @android.service.autofill.FillRequest.RequestFlags int FLAG_PCC_DETECTION\npublic static final @android.service.autofill.FillRequest.RequestFlags int FLAG_SCREEN_HAS_CREDMAN_FIELD\npublic static final @android.service.autofill.FillRequest.RequestFlags int FLAG_VIEW_REQUESTS_CREDMAN_SERVICE\npublic static final int INVALID_REQUEST_ID\nprivate final int mId\nprivate final @android.annotation.NonNull java.util.List<android.service.autofill.FillContext> mFillContexts\nprivate final @android.annotation.NonNull java.util.List<java.lang.String> mHints\nprivate final @android.annotation.Nullable android.os.Bundle mClientState\nprivate final @android.service.autofill.FillRequest.RequestFlags int mFlags\nprivate final @android.annotation.Nullable android.view.inputmethod.InlineSuggestionsRequest mInlineSuggestionsRequest\nprivate final @android.annotation.Nullable android.content.IntentSender mDelayedFillIntentSender\nprivate void onConstructed()\nclass FillRequest 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/core/java/android/service/notification/DeviceEffectsApplier.java b/core/java/android/service/notification/DeviceEffectsApplier.java
new file mode 100644
index 0000000..234ff4d
--- /dev/null
+++ b/core/java/android/service/notification/DeviceEffectsApplier.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.service.notification;
+
+/**
+ * Responsible for making any service calls needed to apply the set of {@link ZenDeviceEffects} that
+ * make sense for the current platform.
+ * @hide
+ */
+public interface DeviceEffectsApplier {
+ /**
+ * Applies the {@link ZenDeviceEffects} to the device.
+ *
+ * <p>The supplied {@code effects} represents the "consolidated" device effects, i.e. the
+ * union of the effects of all the {@link ZenModeConfig.ZenRule} instances that are currently
+ * active. If no rules are active (or no active rules specify custom effects) then {@code
+ * effects} will be all-default (i.e. {@link ZenDeviceEffects#hasEffects} will return {@code
+ * false}.
+ *
+ * <p>This will be called whenever the set of consolidated effects changes (normally through
+ * the activation or deactivation of zen rules).
+ */
+ void apply(ZenDeviceEffects effects);
+}
diff --git a/core/java/android/service/notification/ZenDeviceEffects.java b/core/java/android/service/notification/ZenDeviceEffects.java
index db0b7ff..0e82b6c 100644
--- a/core/java/android/service/notification/ZenDeviceEffects.java
+++ b/core/java/android/service/notification/ZenDeviceEffects.java
@@ -18,6 +18,7 @@
import android.annotation.FlaggedApi;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.app.Flags;
import android.os.Parcel;
import android.os.Parcelable;
@@ -359,6 +360,27 @@
return this;
}
+ /**
+ * Applies the effects that are {@code true} on the supplied {@link ZenDeviceEffects} to
+ * this builder (essentially logically-ORing the effect set).
+ * @hide
+ */
+ @NonNull
+ public Builder add(@Nullable ZenDeviceEffects effects) {
+ if (effects == null) return this;
+ if (effects.shouldDisplayGrayscale()) setShouldDisplayGrayscale(true);
+ if (effects.shouldSuppressAmbientDisplay()) setShouldSuppressAmbientDisplay(true);
+ if (effects.shouldDimWallpaper()) setShouldDimWallpaper(true);
+ if (effects.shouldUseNightMode()) setShouldUseNightMode(true);
+ if (effects.shouldDisableAutoBrightness()) setShouldDisableAutoBrightness(true);
+ if (effects.shouldDisableTapToWake()) setShouldDisableTapToWake(true);
+ if (effects.shouldDisableTiltToWake()) setShouldDisableTiltToWake(true);
+ if (effects.shouldDisableTouch()) setShouldDisableTouch(true);
+ if (effects.shouldMinimizeRadioUsage()) setShouldMinimizeRadioUsage(true);
+ if (effects.shouldMaximizeDoze()) setShouldMaximizeDoze(true);
+ return this;
+ }
+
/** Builds a {@link ZenDeviceEffects} object based on the builder's state. */
@NonNull
public ZenDeviceEffects build() {
diff --git a/core/java/android/service/voice/VoiceInteractionService.java b/core/java/android/service/voice/VoiceInteractionService.java
index c716cd2..fba0923 100644
--- a/core/java/android/service/voice/VoiceInteractionService.java
+++ b/core/java/android/service/voice/VoiceInteractionService.java
@@ -1024,21 +1024,31 @@
}
}
- /** Set sandboxed detection training data egress op.
+ /**
+ * Allow/disallow receiving training data from trusted process.
*
- * <p> This method can be called by a preinstalled assistant to allow/disallow training data
- * egress from trusted process.
+ * <p> This method can be called by a preinstalled assistant to receive/stop receiving
+ * training data via {@link HotwordDetector.Callback#onTrainingData(HotwordTrainingData)}.
+ * These training data events are produced during sandboxed detection (in trusted process).
*
- * @return whether was able to update sandboxed detection op successfully.
- * @throws SecurityException if assistant is not a preinstalled assistant.
+ * @param allowed whether to allow/disallow receiving training data produced during
+ * sandboxed detection (from trusted process).
+ * @throws SecurityException if caller is not a preinstalled assistant or if caller is not the
+ * active assistant.
*
* @hide
*/
+ //TODO(b/315053245): Add mitigations to make API no-op once user has modified setting.
+ @SystemApi
@FlaggedApi(Flags.FLAG_ALLOW_TRAINING_DATA_EGRESS_FROM_HDS)
- public boolean setSandboxedDetectionTrainingDataOp(int opMode) {
- Log.i(TAG, "Setting training data egress op-mode to " + opMode);
+ @RequiresPermission(Manifest.permission.MANAGE_HOTWORD_DETECTION)
+ public void setIsReceiveSandboxedTrainingDataAllowed(boolean allowed) {
+ Log.i(TAG, "setIsReceiveSandboxedTrainingDataAllowed to " + allowed);
+ if (mSystemService == null) {
+ throw new IllegalStateException("Not available until onReady() is called");
+ }
try {
- return mSystemService.setSandboxedDetectionTrainingDataOp(opMode);
+ mSystemService.setIsReceiveSandboxedTrainingDataAllowed(allowed);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
diff --git a/core/java/android/util/DayOfMonthCursor.java b/core/java/android/util/DayOfMonthCursor.java
index 393b98e..ac5dc3a 100644
--- a/core/java/android/util/DayOfMonthCursor.java
+++ b/core/java/android/util/DayOfMonthCursor.java
@@ -32,6 +32,7 @@
*
* @hide
*/
+@android.ravenwood.annotation.RavenwoodKeepWholeClass
public class DayOfMonthCursor extends MonthDisplayHelper {
private int mRow;
diff --git a/core/java/android/util/DumpableContainer.java b/core/java/android/util/DumpableContainer.java
index fef5acd..24640c9 100644
--- a/core/java/android/util/DumpableContainer.java
+++ b/core/java/android/util/DumpableContainer.java
@@ -20,6 +20,7 @@
/**
* Represents a container that manages {@link Dumpable dumpables}.
*/
+@android.ravenwood.annotation.RavenwoodKeepWholeClass
public interface DumpableContainer {
/**
diff --git a/core/java/android/util/KeyValueListParser.java b/core/java/android/util/KeyValueListParser.java
index fbc66e6..783b2d6 100644
--- a/core/java/android/util/KeyValueListParser.java
+++ b/core/java/android/util/KeyValueListParser.java
@@ -28,6 +28,7 @@
* can be used.
* @hide
*/
+@android.ravenwood.annotation.RavenwoodKeepWholeClass
public class KeyValueListParser {
private final ArrayMap<String, String> mValues = new ArrayMap<>();
private final TextUtils.StringSplitter mSplitter;
diff --git a/core/java/android/util/LongArrayQueue.java b/core/java/android/util/LongArrayQueue.java
index 354f8df..b9752fe 100644
--- a/core/java/android/util/LongArrayQueue.java
+++ b/core/java/android/util/LongArrayQueue.java
@@ -28,6 +28,7 @@
*
* @hide
*/
+@android.ravenwood.annotation.RavenwoodKeepWholeClass
public class LongArrayQueue {
private long[] mValues;
diff --git a/core/java/android/util/LongSparseLongArray.java b/core/java/android/util/LongSparseLongArray.java
index d4a0126..86268fa 100644
--- a/core/java/android/util/LongSparseLongArray.java
+++ b/core/java/android/util/LongSparseLongArray.java
@@ -46,6 +46,7 @@
*
* @hide
*/
+@android.ravenwood.annotation.RavenwoodKeepWholeClass
public class LongSparseLongArray implements Cloneable {
@UnsupportedAppUsage(maxTargetSdk = 28) // The type isn't even public.
private long[] mKeys;
diff --git a/core/java/android/util/MonthDisplayHelper.java b/core/java/android/util/MonthDisplayHelper.java
index c3f13fc..3bd292b 100644
--- a/core/java/android/util/MonthDisplayHelper.java
+++ b/core/java/android/util/MonthDisplayHelper.java
@@ -24,6 +24,7 @@
*
* Not thread safe.
*/
+@android.ravenwood.annotation.RavenwoodKeepWholeClass
public class MonthDisplayHelper {
// display pref
diff --git a/core/java/android/util/RecurrenceRule.java b/core/java/android/util/RecurrenceRule.java
index 39d1f2c..dc470d7 100644
--- a/core/java/android/util/RecurrenceRule.java
+++ b/core/java/android/util/RecurrenceRule.java
@@ -42,6 +42,7 @@
*
* @hide
*/
+@android.ravenwood.annotation.RavenwoodKeepWholeClass
public class RecurrenceRule implements Parcelable {
private static final String TAG = "RecurrenceRule";
private static final boolean LOGD = Log.isLoggable(TAG, Log.DEBUG);
diff --git a/core/java/android/util/RotationUtils.java b/core/java/android/util/RotationUtils.java
index f20767b..07ab996 100644
--- a/core/java/android/util/RotationUtils.java
+++ b/core/java/android/util/RotationUtils.java
@@ -36,6 +36,7 @@
*
* @hide
*/
+@android.ravenwood.annotation.RavenwoodKeepWholeClass
public class RotationUtils {
/**
diff --git a/core/java/android/util/SparseDoubleArray.java b/core/java/android/util/SparseDoubleArray.java
index 4b0cbe4..8a0b11e 100644
--- a/core/java/android/util/SparseDoubleArray.java
+++ b/core/java/android/util/SparseDoubleArray.java
@@ -41,6 +41,7 @@
*
* @hide
*/
+@android.ravenwood.annotation.RavenwoodKeepWholeClass
public class SparseDoubleArray implements Cloneable {
/**
* The int->double map, but storing the doubles as longs using
diff --git a/core/java/android/util/SparseSetArray.java b/core/java/android/util/SparseSetArray.java
index 61f29a4..80f6a4a08 100644
--- a/core/java/android/util/SparseSetArray.java
+++ b/core/java/android/util/SparseSetArray.java
@@ -22,6 +22,7 @@
*
* @hide
*/
+@android.ravenwood.annotation.RavenwoodKeepWholeClass
public class SparseSetArray<T> {
private final SparseArray<ArraySet<T>> mData;
diff --git a/core/java/android/util/StateSet.java b/core/java/android/util/StateSet.java
index 4bbc0f8..16d6082 100644
--- a/core/java/android/util/StateSet.java
+++ b/core/java/android/util/StateSet.java
@@ -34,7 +34,6 @@
* and not have static methods here but there is some concern about
* performance since these methods are called during view drawing.
*/
-
public class StateSet {
/**
* The order here is very important to
diff --git a/core/java/android/util/Xml.java b/core/java/android/util/Xml.java
index 2a33caa..ec6e90b 100644
--- a/core/java/android/util/Xml.java
+++ b/core/java/android/util/Xml.java
@@ -334,6 +334,7 @@
*
* @hide
*/
+ @android.ravenwood.annotation.RavenwoodKeep
public static void copy(@NonNull XmlPullParser in, @NonNull XmlSerializer out)
throws XmlPullParserException, IOException {
// Some parsers may have already consumed the event that starts the
@@ -393,6 +394,7 @@
* unsupported, which can confuse serializers. This method normalizes empty
* strings to be {@code null}.
*/
+ @android.ravenwood.annotation.RavenwoodKeep
private static @Nullable String normalizeNamespace(@Nullable String namespace) {
if (namespace == null || namespace.isEmpty()) {
return null;
diff --git a/core/java/android/view/AttachedSurfaceControl.java b/core/java/android/view/AttachedSurfaceControl.java
index f28574e..fd5517d 100644
--- a/core/java/android/view/AttachedSurfaceControl.java
+++ b/core/java/android/view/AttachedSurfaceControl.java
@@ -27,6 +27,9 @@
import com.android.window.flags.Flags;
+import java.util.concurrent.Executor;
+import java.util.function.Consumer;
+
/**
* Provides an interface to the root-Surface of a View Hierarchy or Window. This
* is used in combination with the {@link android.view.SurfaceControl} API to enable
@@ -194,6 +197,42 @@
}
/**
+ * Add a trusted presentation listener on the SurfaceControl associated with this window.
+ *
+ * @param t Transaction that the trusted presentation listener is added on. This should
+ * be applied by the caller.
+ * @param thresholds The {@link SurfaceControl.TrustedPresentationThresholds} that will specify
+ * when the to invoke the callback.
+ * @param executor The {@link Executor} where the callback will be invoked on.
+ * @param listener The {@link Consumer} that will receive the callbacks when entered or
+ * exited the threshold.
+ *
+ * @see SurfaceControl.Transaction#setTrustedPresentationCallback(SurfaceControl,
+ * SurfaceControl.TrustedPresentationThresholds, Executor, Consumer)
+ *
+ * @hide b/287076178 un-hide with API bump
+ */
+ default void addTrustedPresentationCallback(@NonNull SurfaceControl.Transaction t,
+ @NonNull SurfaceControl.TrustedPresentationThresholds thresholds,
+ @NonNull Executor executor, @NonNull Consumer<Boolean> listener) {
+ }
+
+ /**
+ * Remove a trusted presentation listener on the SurfaceControl associated with this window.
+ *
+ * @param t Transaction that the trusted presentation listener removed on. This should
+ * be applied by the caller.
+ * @param listener The {@link Consumer} that was previously registered with
+ * addTrustedPresentationCallback that should be removed.
+ *
+ * @see SurfaceControl.Transaction#clearTrustedPresentationCallback(SurfaceControl)
+ * @hide b/287076178 un-hide with API bump
+ */
+ default void removeTrustedPresentationCallback(@NonNull SurfaceControl.Transaction t,
+ @NonNull Consumer<Boolean> listener) {
+ }
+
+ /**
* Transfer the currently in progress touch gesture from the host to the requested
* {@link SurfaceControlViewHost.SurfacePackage}. This requires that the
* SurfaceControlViewHost was created with the current host's inputToken.
diff --git a/core/java/android/view/HdrRenderState.java b/core/java/android/view/HdrRenderState.java
new file mode 100644
index 0000000..2fbbf48
--- /dev/null
+++ b/core/java/android/view/HdrRenderState.java
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.view;
+
+import android.os.SystemClock;
+
+import com.android.graphics.hwui.flags.Flags;
+
+import java.util.function.Consumer;
+
+/** @hide */
+class HdrRenderState implements Consumer<Display> {
+ // Targeting an animation from 1x to 5x over 400ms means we need to increase by 0.01/ms
+ private static final float TRANSITION_PER_MS = 0.01f;
+
+ private static final boolean FLAG_ANIMATE_ENABLED = Flags.animateHdrTransitions();
+
+ private final ViewRootImpl mViewRoot;
+
+ private boolean mIsListenerRegistered = false;
+ private boolean mUpdateHdrSdrRatioInfo = false;
+ private float mDesiredHdrSdrRatio = 1f;
+ private float mTargetHdrSdrRatio = 1f;
+ private float mRenderHdrSdrRatio = 1f;
+ private float mPreviousRenderRatio = 1f;
+ private long mLastUpdateMillis = -1;
+
+ HdrRenderState(ViewRootImpl viewRoot) {
+ mViewRoot = viewRoot;
+ }
+
+ @Override
+ public void accept(Display display) {
+ forceUpdateHdrSdrRatio();
+ mViewRoot.invalidate();
+ }
+
+ boolean isHdrEnabled() {
+ return mDesiredHdrSdrRatio >= 1.01f;
+ }
+
+ void stopListening() {
+ if (mIsListenerRegistered) {
+ mViewRoot.mDisplay.unregisterHdrSdrRatioChangedListener(this);
+ mIsListenerRegistered = false;
+ }
+ }
+
+ void startListening() {
+ if (isHdrEnabled() && !mIsListenerRegistered && mViewRoot.mDisplay != null) {
+ mViewRoot.mDisplay.registerHdrSdrRatioChangedListener(mViewRoot.mExecutor, this);
+ }
+ }
+
+ /** @return true if something changed, else false */
+ boolean updateForFrame(long frameTimeMillis) {
+ boolean hasUpdate = mUpdateHdrSdrRatioInfo;
+ mUpdateHdrSdrRatioInfo = false;
+ mRenderHdrSdrRatio = mTargetHdrSdrRatio;
+ long timeDelta = Math.max(Math.min(32, frameTimeMillis - mLastUpdateMillis), 8);
+ final float maxStep = timeDelta * TRANSITION_PER_MS;
+ mLastUpdateMillis = frameTimeMillis;
+ if (hasUpdate && FLAG_ANIMATE_ENABLED) {
+ if (mTargetHdrSdrRatio == 1.0f) {
+ mPreviousRenderRatio = mTargetHdrSdrRatio;
+ } else {
+ float delta = mTargetHdrSdrRatio - mPreviousRenderRatio;
+ if (delta > maxStep) {
+ mRenderHdrSdrRatio = mPreviousRenderRatio + maxStep;
+ mUpdateHdrSdrRatioInfo = true;
+ mViewRoot.invalidate();
+ }
+ mPreviousRenderRatio = mRenderHdrSdrRatio;
+ }
+ }
+ return hasUpdate;
+ }
+
+ float getDesiredHdrSdrRatio() {
+ return mDesiredHdrSdrRatio;
+ }
+
+ float getRenderHdrSdrRatio() {
+ return mRenderHdrSdrRatio;
+ }
+
+ void forceUpdateHdrSdrRatio() {
+ mTargetHdrSdrRatio = Math.min(mDesiredHdrSdrRatio, mViewRoot.mDisplay.getHdrSdrRatio());
+ mUpdateHdrSdrRatioInfo = true;
+ }
+
+ void setDesiredHdrSdrRatio(float desiredRatio) {
+ mLastUpdateMillis = SystemClock.uptimeMillis();
+ // TODO: When decreasing the desired ratio we need to animate it downwards
+ if (desiredRatio != mDesiredHdrSdrRatio) {
+ mDesiredHdrSdrRatio = desiredRatio;
+ forceUpdateHdrSdrRatio();
+ mViewRoot.invalidate();
+
+ if (isHdrEnabled()) {
+ startListening();
+ } else {
+ stopListening();
+ }
+ }
+ }
+}
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index 36b74e3..17bbee6d0 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -73,8 +73,6 @@
import android.window.ITaskFpsCallback;
import android.window.ScreenCapture;
import android.window.WindowContextInfo;
-import android.window.ITrustedPresentationListener;
-import android.window.TrustedPresentationThresholds;
/**
* System private interface to the window manager.
@@ -1077,10 +1075,4 @@
@JavaPassthrough(annotation = "@android.annotation.RequiresPermission(android.Manifest"
+ ".permission.MONITOR_INPUT)")
void unregisterDecorViewGestureListener(IDecorViewGestureListener listener, int displayId);
-
- void registerTrustedPresentationListener(in IBinder window, in ITrustedPresentationListener listener,
- in TrustedPresentationThresholds thresholds, int id);
-
-
- void unregisterTrustedPresentationListener(in ITrustedPresentationListener listener, int id);
}
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 1a4dbef..1530aa7 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -735,10 +735,7 @@
private BLASTBufferQueue mBlastBufferQueue;
- private boolean mUpdateHdrSdrRatioInfo = false;
- private float mDesiredHdrSdrRatio = 1f;
- private float mRenderHdrSdrRatio = 1f;
- private Consumer<Display> mHdrSdrRatioChangedListener = null;
+ private final HdrRenderState mHdrRenderState = new HdrRenderState(this);
/**
* Child container layer of {@code mSurface} with the same bounds as its parent, and cropped to
@@ -1813,7 +1810,7 @@
mAttachInfo.mThreadedRenderer = renderer;
renderer.setSurfaceControl(mSurfaceControl, mBlastBufferQueue);
updateColorModeIfNeeded(attrs.getColorMode(), attrs.getDesiredHdrHeadroom());
- updateRenderHdrSdrRatio();
+ mHdrRenderState.forceUpdateHdrSdrRatio();
updateForceDarkMode();
mAttachInfo.mHardwareAccelerated = true;
mAttachInfo.mHardwareAccelerationRequested = true;
@@ -2156,9 +2153,7 @@
private void updateInternalDisplay(int displayId, Resources resources) {
final Display preferredDisplay =
ResourcesManager.getInstance().getAdjustedDisplay(displayId, resources);
- if (mHdrSdrRatioChangedListener != null && mDisplay != null) {
- mDisplay.unregisterHdrSdrRatioChangedListener(mHdrSdrRatioChangedListener);
- }
+ mHdrRenderState.stopListening();
if (preferredDisplay == null) {
// Fallback to use default display.
Slog.w(TAG, "Cannot get desired display with Id: " + displayId);
@@ -2167,9 +2162,7 @@
} else {
mDisplay = preferredDisplay;
}
- if (mHdrSdrRatioChangedListener != null && mDisplay != null) {
- mDisplay.registerHdrSdrRatioChangedListener(mExecutor, mHdrSdrRatioChangedListener);
- }
+ mHdrRenderState.startListening();
mContext.updateDisplay(mDisplay.getDisplayId());
}
@@ -5154,11 +5147,12 @@
useAsyncReport = true;
- if (mUpdateHdrSdrRatioInfo) {
- mUpdateHdrSdrRatioInfo = false;
+ if (mHdrRenderState.updateForFrame(mAttachInfo.mDrawingTime)) {
+ final float renderRatio = mHdrRenderState.getRenderHdrSdrRatio();
applyTransactionOnDraw(mTransaction.setExtendedRangeBrightness(
- getSurfaceControl(), mRenderHdrSdrRatio, mDesiredHdrSdrRatio));
- mAttachInfo.mThreadedRenderer.setTargetHdrSdrRatio(mRenderHdrSdrRatio);
+ getSurfaceControl(), renderRatio,
+ mHdrRenderState.getDesiredHdrSdrRatio()));
+ mAttachInfo.mThreadedRenderer.setTargetHdrSdrRatio(renderRatio);
}
if (activeSyncGroup != null) {
@@ -5769,11 +5763,6 @@
}
}
- private void updateRenderHdrSdrRatio() {
- mRenderHdrSdrRatio = Math.min(mDesiredHdrSdrRatio, mDisplay.getHdrSdrRatio());
- mUpdateHdrSdrRatioInfo = true;
- }
-
private void updateColorModeIfNeeded(@ActivityInfo.ColorMode int colorMode,
float desiredRatio) {
if (mAttachInfo.mThreadedRenderer == null) {
@@ -5793,22 +5782,8 @@
if (desiredRatio == 0 || desiredRatio > automaticRatio) {
desiredRatio = automaticRatio;
}
- if (desiredRatio != mDesiredHdrSdrRatio) {
- mDesiredHdrSdrRatio = desiredRatio;
- updateRenderHdrSdrRatio();
- invalidate();
- if (mDesiredHdrSdrRatio < 1.01f) {
- mDisplay.unregisterHdrSdrRatioChangedListener(mHdrSdrRatioChangedListener);
- mHdrSdrRatioChangedListener = null;
- } else {
- mHdrSdrRatioChangedListener = display -> {
- updateRenderHdrSdrRatio();
- invalidate();
- };
- mDisplay.registerHdrSdrRatioChangedListener(mExecutor, mHdrSdrRatioChangedListener);
- }
- }
+ mHdrRenderState.setDesiredHdrSdrRatio(desiredRatio);
}
@Override
@@ -6428,7 +6403,7 @@
}
final ViewRootHandler mHandler = new ViewRootHandler();
- private final Executor mExecutor = (Runnable r) -> {
+ final Executor mExecutor = (Runnable r) -> {
mHandler.post(r);
};
@@ -8764,7 +8739,7 @@
if (mAttachInfo.mThreadedRenderer != null) {
mAttachInfo.mThreadedRenderer.setSurfaceControl(mSurfaceControl, mBlastBufferQueue);
}
- updateRenderHdrSdrRatio();
+ mHdrRenderState.forceUpdateHdrSdrRatio();
if (mPreviousTransformHint != transformHint) {
mPreviousTransformHint = transformHint;
dispatchTransformHintChanged(transformHint);
@@ -9312,9 +9287,7 @@
private void destroyHardwareRenderer() {
ThreadedRenderer hardwareRenderer = mAttachInfo.mThreadedRenderer;
- if (mHdrSdrRatioChangedListener != null) {
- mDisplay.unregisterHdrSdrRatioChangedListener(mHdrSdrRatioChangedListener);
- }
+ mHdrRenderState.stopListening();
if (hardwareRenderer != null) {
if (mHardwareRendererObserver != null) {
@@ -12032,6 +12005,18 @@
scheduleTraversals();
}
+ @Override
+ public void addTrustedPresentationCallback(@NonNull SurfaceControl.Transaction t,
+ @NonNull SurfaceControl.TrustedPresentationThresholds thresholds,
+ @NonNull Executor executor, @NonNull Consumer<Boolean> listener) {
+ t.setTrustedPresentationCallback(getSurfaceControl(), thresholds, executor, listener);
+ }
+
+ @Override
+ public void removeTrustedPresentationCallback(@NonNull SurfaceControl.Transaction t,
+ @NonNull Consumer<Boolean> listener) {
+ t.clearTrustedPresentationCallback(getSurfaceControl());
+ }
private void logAndTrace(String msg) {
if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) {
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index f668088..046ea77 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -122,9 +122,7 @@
import android.view.WindowInsets.Type;
import android.view.WindowInsets.Type.InsetsType;
import android.view.accessibility.AccessibilityNodeInfo;
-import android.window.ITrustedPresentationListener;
import android.window.TaskFpsCallback;
-import android.window.TrustedPresentationThresholds;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -5886,35 +5884,4 @@
default boolean replaceContentOnDisplayWithSc(int displayId, @NonNull SurfaceControl sc) {
throw new UnsupportedOperationException();
}
-
- /**
- * Add a trusted presentation listener associated with a window. If the listener has already
- * been registered, an AndroidRuntimeException will be thrown.
- *
- * @param window The Window to add the trusted presentation listener for
- * @param thresholds The {@link TrustedPresentationThresholds} that will specify
- * when the to invoke the callback.
- * @param executor The {@link Executor} where the callback will be invoked on.
- * @param listener The {@link ITrustedPresentationListener} that will receive the callbacks
- * when entered or exited trusted presentation per the thresholds.
- *
- * @hide b/287076178 un-hide with API bump
- */
- default void registerTrustedPresentationListener(@NonNull IBinder window,
- @NonNull TrustedPresentationThresholds thresholds, @NonNull Executor executor,
- @NonNull Consumer<Boolean> listener) {
- throw new UnsupportedOperationException();
- }
-
- /**
- * Removes a presentation listener associated with a window. If the listener was not previously
- * registered, the call will be a noop.
- *
- * @hide
- * @see #registerTrustedPresentationListener(IBinder,
- * TrustedPresentationThresholds, Executor, Consumer)
- */
- default void unregisterTrustedPresentationListener(@NonNull Consumer<Boolean> listener) {
- throw new UnsupportedOperationException();
- }
}
diff --git a/core/java/android/view/WindowManagerGlobal.java b/core/java/android/view/WindowManagerGlobal.java
index a7d814e..214f1ec 100644
--- a/core/java/android/view/WindowManagerGlobal.java
+++ b/core/java/android/view/WindowManagerGlobal.java
@@ -30,13 +30,9 @@
import android.os.ServiceManager;
import android.os.SystemProperties;
import android.util.AndroidRuntimeException;
-import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.Log;
-import android.util.Pair;
import android.view.inputmethod.InputMethodManager;
-import android.window.ITrustedPresentationListener;
-import android.window.TrustedPresentationThresholds;
import com.android.internal.util.FastPrintWriter;
@@ -47,7 +43,6 @@
import java.util.ArrayList;
import java.util.WeakHashMap;
import java.util.concurrent.Executor;
-import java.util.function.Consumer;
import java.util.function.IntConsumer;
/**
@@ -148,9 +143,6 @@
private Runnable mSystemPropertyUpdater;
- private final TrustedPresentationListener mTrustedPresentationListener =
- new TrustedPresentationListener();
-
private WindowManagerGlobal() {
}
@@ -332,7 +324,7 @@
final Context context = view.getContext();
if (context != null
&& (context.getApplicationInfo().flags
- & ApplicationInfo.FLAG_HARDWARE_ACCELERATED) != 0) {
+ & ApplicationInfo.FLAG_HARDWARE_ACCELERATED) != 0) {
wparams.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
}
}
@@ -490,7 +482,7 @@
if (who != null) {
WindowLeaked leak = new WindowLeaked(
what + " " + who + " has leaked window "
- + root.getView() + " that was originally added here");
+ + root.getView() + " that was originally added here");
leak.setStackTrace(root.getLocation().getStackTrace());
Log.e(TAG, "", leak);
}
@@ -798,86 +790,6 @@
}
}
- public void registerTrustedPresentationListener(@NonNull IBinder window,
- @NonNull TrustedPresentationThresholds thresholds, Executor executor,
- @NonNull Consumer<Boolean> listener) {
- mTrustedPresentationListener.addListener(window, thresholds, listener, executor);
- }
-
- public void unregisterTrustedPresentationListener(@NonNull Consumer<Boolean> listener) {
- mTrustedPresentationListener.removeListener(listener);
- }
-
- private final class TrustedPresentationListener extends
- ITrustedPresentationListener.Stub {
- private static int sId = 0;
- private final ArrayMap<Consumer<Boolean>, Pair<Integer, Executor>> mListeners =
- new ArrayMap<>();
-
- private final Object mTplLock = new Object();
-
- private void addListener(IBinder window, TrustedPresentationThresholds thresholds,
- Consumer<Boolean> listener, Executor executor) {
- synchronized (mTplLock) {
- if (mListeners.containsKey(listener)) {
- throw new AndroidRuntimeException("Trying to add duplicate listener");
- }
- int id = sId++;
- mListeners.put(listener, new Pair<>(id, executor));
- try {
- WindowManagerGlobal.getWindowManagerService()
- .registerTrustedPresentationListener(window, this, thresholds, id);
- } catch (RemoteException e) {
- e.rethrowAsRuntimeException();
- }
- }
- }
-
- private void removeListener(Consumer<Boolean> listener) {
- synchronized (mTplLock) {
- var removedListener = mListeners.remove(listener);
- if (removedListener == null) {
- Log.i(TAG, "listener " + listener + " does not exist.");
- return;
- }
-
- try {
- WindowManagerGlobal.getWindowManagerService()
- .unregisterTrustedPresentationListener(this, removedListener.first);
- } catch (RemoteException e) {
- e.rethrowAsRuntimeException();
- }
- }
- }
-
- @Override
- public void onTrustedPresentationChanged(int[] inTrustedStateListenerIds,
- int[] outOfTrustedStateListenerIds) {
- ArrayList<Runnable> firedListeners = new ArrayList<>();
- synchronized (mTplLock) {
- mListeners.forEach((listener, idExecutorPair) -> {
- final var listenerId = idExecutorPair.first;
- final var executor = idExecutorPair.second;
- for (int id : inTrustedStateListenerIds) {
- if (listenerId == id) {
- firedListeners.add(() -> executor.execute(
- () -> listener.accept(/*presentationState*/true)));
- }
- }
- for (int id : outOfTrustedStateListenerIds) {
- if (listenerId == id) {
- firedListeners.add(() -> executor.execute(
- () -> listener.accept(/*presentationState*/false)));
- }
- }
- });
- }
- for (int i = 0; i < firedListeners.size(); i++) {
- firedListeners.get(i).run();
- }
- }
- }
-
/** @hide */
public void addWindowlessRoot(ViewRootImpl impl) {
synchronized (mLock) {
@@ -889,7 +801,7 @@
public void removeWindowlessRoot(ViewRootImpl impl) {
synchronized (mLock) {
mWindowlessRoots.remove(impl);
- }
+ }
}
public void setRecentsAppBehindSystemBars(boolean behindSystemBars) {
diff --git a/core/java/android/view/WindowManagerImpl.java b/core/java/android/view/WindowManagerImpl.java
index b4b1fde..d7b74b3 100644
--- a/core/java/android/view/WindowManagerImpl.java
+++ b/core/java/android/view/WindowManagerImpl.java
@@ -37,7 +37,6 @@
import android.util.Log;
import android.window.ITaskFpsCallback;
import android.window.TaskFpsCallback;
-import android.window.TrustedPresentationThresholds;
import android.window.WindowContext;
import android.window.WindowMetricsController;
import android.window.WindowProvider;
@@ -509,17 +508,4 @@
}
return false;
}
-
- @Override
- public void registerTrustedPresentationListener(@NonNull IBinder window,
- @NonNull TrustedPresentationThresholds thresholds, @NonNull Executor executor,
- @NonNull Consumer<Boolean> listener) {
- mGlobal.registerTrustedPresentationListener(window, thresholds, executor, listener);
- }
-
- @Override
- public void unregisterTrustedPresentationListener(@NonNull Consumer<Boolean> listener) {
- mGlobal.unregisterTrustedPresentationListener(listener);
-
- }
}
diff --git a/core/java/android/view/accessibility/AccessibilityManager.java b/core/java/android/view/accessibility/AccessibilityManager.java
index 3dbe65e..a38092a 100644
--- a/core/java/android/view/accessibility/AccessibilityManager.java
+++ b/core/java/android/view/accessibility/AccessibilityManager.java
@@ -185,16 +185,31 @@
/**
* Annotations for the shortcut type.
+ * <p>Note: Keep in sync with {@link #SHORTCUT_TYPES}.</p>
* @hide
*/
@Retention(RetentionPolicy.SOURCE)
@IntDef(value = {
+ // LINT.IfChange(shortcut_type_intdef)
ACCESSIBILITY_BUTTON,
ACCESSIBILITY_SHORTCUT_KEY
+ // LINT.ThenChange(:shortcut_type_array)
})
public @interface ShortcutType {}
/**
+ * Used for iterating through {@link ShortcutType}.
+ * <p>Note: Keep in sync with {@link ShortcutType}.</p>
+ * @hide
+ */
+ public static final int[] SHORTCUT_TYPES = {
+ // LINT.IfChange(shortcut_type_array)
+ ACCESSIBILITY_BUTTON,
+ ACCESSIBILITY_SHORTCUT_KEY,
+ // LINT.ThenChange(:shortcut_type_intdef)
+ };
+
+ /**
* Annotations for content flag of UI.
* @hide
*/
@@ -914,6 +929,28 @@
}
/**
+ * Returns whether the user must be shown the AccessibilityService warning dialog
+ * before the AccessibilityService (or any shortcut for the service) can be enabled.
+ * @hide
+ */
+ @RequiresPermission(Manifest.permission.MANAGE_ACCESSIBILITY)
+ public boolean isAccessibilityServiceWarningRequired(@NonNull AccessibilityServiceInfo info) {
+ final IAccessibilityManager service;
+ synchronized (mLock) {
+ service = getServiceLocked();
+ if (service == null) {
+ return true;
+ }
+ }
+ try {
+ return service.isAccessibilityServiceWarningRequired(info);
+ } catch (RemoteException re) {
+ Log.e(LOG_TAG, "Error while checking isAccessibilityServiceWarningRequired: ", re);
+ return true;
+ }
+ }
+
+ /**
* Registers an {@link AccessibilityStateChangeListener} for changes in
* the global accessibility state of the system. Equivalent to calling
* {@link #addAccessibilityStateChangeListener(AccessibilityStateChangeListener, Handler)}
diff --git a/core/java/android/view/accessibility/IAccessibilityManager.aidl b/core/java/android/view/accessibility/IAccessibilityManager.aidl
index f741080..9c04c27 100644
--- a/core/java/android/view/accessibility/IAccessibilityManager.aidl
+++ b/core/java/android/view/accessibility/IAccessibilityManager.aidl
@@ -128,6 +128,9 @@
boolean isAccessibilityTargetAllowed(String packageName, int uid, int userId);
boolean sendRestrictedDialogIntent(String packageName, int uid, int userId);
+ @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.MANAGE_ACCESSIBILITY)")
+ boolean isAccessibilityServiceWarningRequired(in AccessibilityServiceInfo info);
+
parcelable WindowTransformationSpec {
float[] transformationMatrix;
MagnificationSpec magnificationSpec;
diff --git a/core/java/android/view/accessibility/flags/accessibility_flags.aconfig b/core/java/android/view/accessibility/flags/accessibility_flags.aconfig
index b299678..7ab5446 100644
--- a/core/java/android/view/accessibility/flags/accessibility_flags.aconfig
+++ b/core/java/android/view/accessibility/flags/accessibility_flags.aconfig
@@ -10,6 +10,13 @@
}
flag {
+ name: "a11y_qs_shortcut"
+ namespace: "accessibility"
+ description: "Add Quick Setting as one of the a11y shortcut options"
+ bug: "297554934"
+}
+
+flag {
namespace: "accessibility"
name: "allow_shortcut_chooser_on_lockscreen"
description: "Allows the a11y shortcut disambig dialog to appear on the lockscreen"
@@ -17,6 +24,13 @@
}
flag {
+ name: "cleanup_accessibility_warning_dialog"
+ namespace: "accessibility"
+ description: "Cleans up duplicated or broken logic surrounding the accessibility warning dialog."
+ bug: "303511250"
+}
+
+flag {
namespace: "accessibility"
name: "collection_info_item_counts"
description: "Fields for total items and the number of important for accessibility items in a collection"
@@ -24,13 +38,6 @@
}
flag {
- name: "deduplicate_accessibility_warning_dialog"
- namespace: "accessibility"
- description: "Removes duplicate definition of the accessibility warning dialog."
- bug: "303511250"
-}
-
-flag {
namespace: "accessibility"
name: "flash_notification_system_api"
description: "Makes flash notification APIs as system APIs for calling from mainline module"
diff --git a/core/java/android/view/autofill/AutofillManager.java b/core/java/android/view/autofill/AutofillManager.java
index 96574f5..6bc2a13 100644
--- a/core/java/android/view/autofill/AutofillManager.java
+++ b/core/java/android/view/autofill/AutofillManager.java
@@ -24,6 +24,7 @@
import static android.service.autofill.FillRequest.FLAG_SCREEN_HAS_CREDMAN_FIELD;
import static android.service.autofill.FillRequest.FLAG_SUPPORTS_FILL_DIALOG;
import static android.service.autofill.FillRequest.FLAG_VIEW_NOT_FOCUSED;
+import static android.service.autofill.FillRequest.FLAG_VIEW_REQUESTS_CREDMAN_SERVICE;
import static android.view.ContentInfo.SOURCE_AUTOFILL;
import static android.view.autofill.Helper.sDebug;
import static android.view.autofill.Helper.sVerbose;
@@ -61,7 +62,6 @@
import android.service.autofill.AutofillService;
import android.service.autofill.FillEventHistory;
import android.service.autofill.Flags;
-import android.service.autofill.IFillCallback;
import android.service.autofill.UserData;
import android.text.TextUtils;
import android.util.ArrayMap;
@@ -729,6 +729,9 @@
// focus due to autofill showing biometric activity, password manager, or password breach check.
private boolean mRelayoutFix;
+ // Indicates whether the credman integration is enabled.
+ private final boolean mIsCredmanIntegrationEnabled;
+
// Indicates whether called the showAutofillDialog() method.
private boolean mShowAutofillDialogCalled = false;
@@ -952,6 +955,7 @@
AutofillFeatureFlags.shouldAlwaysIncludeWebviewInAssistStructure();
mRelayoutFix = Flags.relayout();
+ mIsCredmanIntegrationEnabled = Flags.autofillCredmanIntegration();
}
/**
@@ -1804,7 +1808,9 @@
}
return mCallback;
}
-
+ if (mIsCredmanIntegrationEnabled && isCredmanRequested(view)) {
+ flags |= FLAG_VIEW_REQUESTS_CREDMAN_SERVICE;
+ }
mIsFillRequested.set(true);
// don't notify entered when Activity is already in background
@@ -3384,6 +3390,9 @@
}
private boolean isCredmanRequested(View view) {
+ if (view == null) {
+ return false;
+ }
if (view.isCredential()) {
return true;
}
diff --git a/core/java/android/view/contentcapture/MainContentCaptureSession.java b/core/java/android/view/contentcapture/MainContentCaptureSession.java
index 14ec14b..966161f 100644
--- a/core/java/android/view/contentcapture/MainContentCaptureSession.java
+++ b/core/java/android/view/contentcapture/MainContentCaptureSession.java
@@ -31,6 +31,7 @@
import static android.view.contentcapture.ContentCaptureHelper.sDebug;
import static android.view.contentcapture.ContentCaptureHelper.sVerbose;
import static android.view.contentcapture.ContentCaptureManager.RESULT_CODE_FALSE;
+import static android.view.contentcapture.flags.Flags.runOnBackgroundThreadEnabled;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -209,14 +210,14 @@
binder = resultData.getBinder(EXTRA_BINDER);
if (binder == null) {
Log.wtf(TAG, "No " + EXTRA_BINDER + " extra result");
- mainSession.mHandler.post(() -> mainSession.resetSession(
+ mainSession.runOnContentCaptureThread(() -> mainSession.resetSession(
STATE_DISABLED | STATE_INTERNAL_ERROR));
return;
}
} else {
binder = null;
}
- mainSession.mHandler.post(() ->
+ mainSession.runOnContentCaptureThread(() ->
mainSession.onSessionStarted(resultCode, binder));
}
}
@@ -256,7 +257,13 @@
*/
void start(@NonNull IBinder token, @NonNull IBinder shareableActivityToken,
@NonNull ComponentName component, int flags) {
- runOnContentCaptureThread(() -> startImpl(token, shareableActivityToken, component, flags));
+ if (runOnBackgroundThreadEnabled()) {
+ runOnContentCaptureThread(
+ () -> startImpl(token, shareableActivityToken, component, flags));
+ } else {
+ // Preserve the control arm behaviour.
+ startImpl(token, shareableActivityToken, component, flags);
+ }
}
private void startImpl(@NonNull IBinder token, @NonNull IBinder shareableActivityToken,
@@ -613,7 +620,12 @@
@VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
@Override
public void flush(@FlushReason int reason) {
- runOnContentCaptureThread(() -> flushImpl(reason));
+ if (runOnBackgroundThreadEnabled()) {
+ runOnContentCaptureThread(() -> flushImpl(reason));
+ } else {
+ // Preserve the control arm behaviour.
+ flushImpl(reason);
+ }
}
private void flushImpl(@FlushReason int reason) {
@@ -904,7 +916,12 @@
/** public because is also used by ViewRootImpl */
public void notifyContentCaptureEvents(
@NonNull SparseArray<ArrayList<Object>> contentCaptureEvents) {
- runOnContentCaptureThread(() -> notifyContentCaptureEventsImpl(contentCaptureEvents));
+ if (runOnBackgroundThreadEnabled()) {
+ runOnContentCaptureThread(() -> notifyContentCaptureEventsImpl(contentCaptureEvents));
+ } else {
+ // Preserve the control arm behaviour.
+ notifyContentCaptureEventsImpl(contentCaptureEvents);
+ }
}
private void notifyContentCaptureEventsImpl(
@@ -1076,19 +1093,30 @@
* </p>
*/
private void runOnContentCaptureThread(@NonNull Runnable r) {
- if (!mHandler.getLooper().isCurrentThread()) {
- mHandler.post(r);
+ if (runOnBackgroundThreadEnabled()) {
+ if (!mHandler.getLooper().isCurrentThread()) {
+ mHandler.post(r);
+ } else {
+ r.run();
+ }
} else {
- r.run();
+ // Preserve the control arm behaviour to always post to the handler.
+ mHandler.post(r);
}
}
private void clearAndRunOnContentCaptureThread(@NonNull Runnable r, int what) {
- if (!mHandler.getLooper().isCurrentThread()) {
+ if (runOnBackgroundThreadEnabled()) {
+ if (!mHandler.getLooper().isCurrentThread()) {
+ mHandler.removeMessages(what);
+ mHandler.post(r);
+ } else {
+ r.run();
+ }
+ } else {
+ // Preserve the control arm behaviour to always post to the handler.
mHandler.removeMessages(what);
mHandler.post(r);
- } else {
- r.run();
}
}
}
diff --git a/core/java/android/view/inputmethod/ImeTracker.java b/core/java/android/view/inputmethod/ImeTracker.java
index d4cfd63..fab8c77 100644
--- a/core/java/android/view/inputmethod/ImeTracker.java
+++ b/core/java/android/view/inputmethod/ImeTracker.java
@@ -737,7 +737,7 @@
*/
public void onCancelAnimation(@AnimationType int animType) {
final int cujType = getImeInsetsCujFromAnimation(animType);
- if (cujType == -1) {
+ if (cujType != -1) {
InteractionJankMonitor.getInstance().cancel(cujType);
}
}
diff --git a/core/java/android/window/TrustedPresentationListener.java b/core/java/android/window/TrustedPresentationListener.java
deleted file mode 100644
index 02fd6d9..0000000
--- a/core/java/android/window/TrustedPresentationListener.java
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * Copyright 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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.window;
-
-/**
- * @hide
- */
-public interface TrustedPresentationListener {
-
- void onTrustedPresentationChanged(boolean inTrustedPresentationState);
-
-}
diff --git a/core/java/android/window/TrustedPresentationThresholds.aidl b/core/java/android/window/TrustedPresentationThresholds.aidl
deleted file mode 100644
index d7088bf..0000000
--- a/core/java/android/window/TrustedPresentationThresholds.aidl
+++ /dev/null
@@ -1,3 +0,0 @@
-package android.window;
-
-parcelable TrustedPresentationThresholds;
diff --git a/core/java/android/window/TrustedPresentationThresholds.java b/core/java/android/window/TrustedPresentationThresholds.java
deleted file mode 100644
index 801d35c..0000000
--- a/core/java/android/window/TrustedPresentationThresholds.java
+++ /dev/null
@@ -1,127 +0,0 @@
-/*
- * Copyright 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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.window;
-
-import android.annotation.FloatRange;
-import android.annotation.IntRange;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.view.SurfaceControl;
-
-import androidx.annotation.NonNull;
-
-/**
- * @hide
- */
-public final class TrustedPresentationThresholds implements Parcelable {
- /**
- * The min alpha the {@link SurfaceControl} is required to have to be considered inside the
- * threshold.
- */
- @FloatRange(from = 0f, fromInclusive = false, to = 1f)
- public final float mMinAlpha;
-
- /**
- * The min fraction of the SurfaceControl that was presented to the user to be considered
- * inside the threshold.
- */
- @FloatRange(from = 0f, fromInclusive = false, to = 1f)
- public final float mMinFractionRendered;
-
- /**
- * The time in milliseconds required for the {@link SurfaceControl} to be in the threshold.
- */
- @IntRange(from = 1)
- public final int mStabilityRequirementMs;
-
- private void checkValid() {
- if (mMinAlpha <= 0 || mMinFractionRendered <= 0 || mStabilityRequirementMs < 1) {
- throw new IllegalArgumentException(
- "TrustedPresentationThresholds values are invalid");
- }
- }
-
- /**
- * Creates a new TrustedPresentationThresholds.
- *
- * @param minAlpha The min alpha the {@link SurfaceControl} is required to
- * have to be considered inside the
- * threshold.
- * @param minFractionRendered The min fraction of the SurfaceControl that was presented
- * to the user to be considered
- * inside the threshold.
- * @param stabilityRequirementMs The time in milliseconds required for the
- * {@link SurfaceControl} to be in the threshold.
- */
- public TrustedPresentationThresholds(
- @FloatRange(from = 0f, fromInclusive = false, to = 1f) float minAlpha,
- @FloatRange(from = 0f, fromInclusive = false, to = 1f) float minFractionRendered,
- @IntRange(from = 1) int stabilityRequirementMs) {
- this.mMinAlpha = minAlpha;
- this.mMinFractionRendered = minFractionRendered;
- this.mStabilityRequirementMs = stabilityRequirementMs;
- checkValid();
- }
-
- @Override
- public String toString() {
- return "TrustedPresentationThresholds { "
- + "minAlpha = " + mMinAlpha + ", "
- + "minFractionRendered = " + mMinFractionRendered + ", "
- + "stabilityRequirementMs = " + mStabilityRequirementMs
- + " }";
- }
-
- @Override
- public void writeToParcel(@NonNull Parcel dest, int flags) {
- dest.writeFloat(mMinAlpha);
- dest.writeFloat(mMinFractionRendered);
- dest.writeInt(mStabilityRequirementMs);
- }
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- /**
- * @hide
- */
- TrustedPresentationThresholds(@NonNull Parcel in) {
- mMinAlpha = in.readFloat();
- mMinFractionRendered = in.readFloat();
- mStabilityRequirementMs = in.readInt();
-
- checkValid();
- }
-
- /**
- * @hide
- */
- public static final @NonNull Creator<TrustedPresentationThresholds> CREATOR =
- new Creator<TrustedPresentationThresholds>() {
- @Override
- public TrustedPresentationThresholds[] newArray(int size) {
- return new TrustedPresentationThresholds[size];
- }
-
- @Override
- public TrustedPresentationThresholds createFromParcel(@NonNull Parcel in) {
- return new TrustedPresentationThresholds(in);
- }
- };
-}
diff --git a/core/java/android/window/flags/wallpaper_manager.aconfig b/core/java/android/window/flags/wallpaper_manager.aconfig
index 09be0cf..f03c993 100644
--- a/core/java/android/window/flags/wallpaper_manager.aconfig
+++ b/core/java/android/window/flags/wallpaper_manager.aconfig
@@ -5,4 +5,11 @@
namespace: "wear_frameworks"
description: "Allow out of focus process to update wallpaper complications"
bug: "271132915"
-}
\ No newline at end of file
+}
+
+flag {
+ name: "multi_crop"
+ namespace: "systemui"
+ description: "Support storing different wallpaper crops for different display dimensions. Only effective after rebooting."
+ bug: "281648899"
+}
diff --git a/core/java/com/android/internal/accessibility/dialog/AccessibilityShortcutChooserActivity.java b/core/java/com/android/internal/accessibility/dialog/AccessibilityShortcutChooserActivity.java
index d4eccd4..7d06e3f 100644
--- a/core/java/com/android/internal/accessibility/dialog/AccessibilityShortcutChooserActivity.java
+++ b/core/java/com/android/internal/accessibility/dialog/AccessibilityShortcutChooserActivity.java
@@ -37,6 +37,7 @@
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
+import android.view.accessibility.AccessibilityManager;
import android.view.accessibility.Flags;
import android.widget.AdapterView;
@@ -114,18 +115,39 @@
private void onTargetChecked(AdapterView<?> parent, View view, int position, long id) {
final AccessibilityTarget target = mTargets.get(position);
- if (!target.isShortcutEnabled()) {
- if (target instanceof AccessibilityServiceTarget
- || target instanceof AccessibilityActivityTarget) {
+ if (Flags.cleanupAccessibilityWarningDialog()) {
+ if (target instanceof AccessibilityServiceTarget serviceTarget) {
if (sendRestrictedDialogIntentIfNeeded(target)) {
return;
}
+ final AccessibilityManager am = getSystemService(AccessibilityManager.class);
+ if (am.isAccessibilityServiceWarningRequired(
+ serviceTarget.getAccessibilityServiceInfo())) {
+ showPermissionDialogIfNeeded(this, (AccessibilityServiceTarget) target,
+ position, mTargetAdapter);
+ return;
+ }
}
+ if (target instanceof AccessibilityActivityTarget activityTarget) {
+ if (!activityTarget.isShortcutEnabled()
+ && sendRestrictedDialogIntentIfNeeded(activityTarget)) {
+ return;
+ }
+ }
+ } else {
+ if (!target.isShortcutEnabled()) {
+ if (target instanceof AccessibilityServiceTarget
+ || target instanceof AccessibilityActivityTarget) {
+ if (sendRestrictedDialogIntentIfNeeded(target)) {
+ return;
+ }
+ }
- if (target instanceof AccessibilityServiceTarget) {
- showPermissionDialogIfNeeded(this, (AccessibilityServiceTarget) target,
- position, mTargetAdapter);
- return;
+ if (target instanceof AccessibilityServiceTarget) {
+ showPermissionDialogIfNeeded(this, (AccessibilityServiceTarget) target,
+ position, mTargetAdapter);
+ return;
+ }
}
}
@@ -156,7 +178,7 @@
return;
}
- if (Flags.deduplicateAccessibilityWarningDialog()) {
+ if (Flags.cleanupAccessibilityWarningDialog()) {
mPermissionDialog = AccessibilityServiceWarning
.createAccessibilityServiceWarningDialog(context,
serviceTarget.getAccessibilityServiceInfo(),
diff --git a/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl b/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl
index ea4fc39..82ee8fc 100644
--- a/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl
+++ b/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl
@@ -390,12 +390,12 @@
int type);
/**
- * Sets the sandboxed detection training data egress op to provided op-mode.
+ * Allows/disallows receiving training data from trusted process.
* Caller must be the active assistant and a preinstalled assistant.
*
- * @param opMode app-op mode to set training data egress op to.
- *
- * @return whether was able to successfully set training data egress op.
+ * @param allowed whether to allow/disallow receiving training data produced during
+ * sandboxed detection (from trusted process).
*/
- boolean setSandboxedDetectionTrainingDataOp(int opMode);
+ @EnforcePermission("MANAGE_HOTWORD_DETECTION")
+ void setIsReceiveSandboxedTrainingDataAllowed(boolean allowed);
}
diff --git a/core/java/com/android/internal/os/SomeArgs.java b/core/java/com/android/internal/os/SomeArgs.java
index b12df6e..4701af3 100644
--- a/core/java/com/android/internal/os/SomeArgs.java
+++ b/core/java/com/android/internal/os/SomeArgs.java
@@ -26,6 +26,7 @@
* it is responsibility of the client to recycle and instance
* once it is no longer used.
*/
+@android.ravenwood.annotation.RavenwoodKeepWholeClass
public final class SomeArgs {
private static final int MAX_POOL_SIZE = 10;
diff --git a/core/java/com/android/internal/policy/KeyInterceptionInfo.java b/core/java/com/android/internal/policy/KeyInterceptionInfo.java
index 964be01..b20f6d2 100644
--- a/core/java/com/android/internal/policy/KeyInterceptionInfo.java
+++ b/core/java/com/android/internal/policy/KeyInterceptionInfo.java
@@ -26,10 +26,12 @@
public final int layoutParamsPrivateFlags;
// Debug friendly name to help identify the window
public final String windowTitle;
+ public final int windowOwnerUid;
- public KeyInterceptionInfo(int type, int flags, String title) {
+ public KeyInterceptionInfo(int type, int flags, String title, int uid) {
layoutParamsType = type;
layoutParamsPrivateFlags = flags;
windowTitle = title;
+ windowOwnerUid = uid;
}
}
diff --git a/core/java/com/android/internal/protolog/ProtoLogGroup.java b/core/java/com/android/internal/protolog/ProtoLogGroup.java
index 8c2a525..4bb7c33 100644
--- a/core/java/com/android/internal/protolog/ProtoLogGroup.java
+++ b/core/java/com/android/internal/protolog/ProtoLogGroup.java
@@ -93,7 +93,6 @@
WM_DEBUG_DREAM(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, true, Consts.TAG_WM),
WM_DEBUG_DIMMER(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, false, Consts.TAG_WM),
- WM_DEBUG_TPL(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, false, Consts.TAG_WM),
TEST_GROUP(true, true, false, "WindowManagerProtoLogTest");
private final boolean mEnabled;
diff --git a/core/java/com/android/internal/util/BitUtils.java b/core/java/com/android/internal/util/BitUtils.java
index 154ea52..d928bbc 100644
--- a/core/java/com/android/internal/util/BitUtils.java
+++ b/core/java/com/android/internal/util/BitUtils.java
@@ -31,6 +31,7 @@
* sugar methods for {@link ByteBuffer}. Useful for networking and packet manipulations.
* {@hide}
*/
+@android.ravenwood.annotation.RavenwoodKeepWholeClass
public final class BitUtils {
private BitUtils() {}
diff --git a/core/java/com/android/internal/util/BitwiseInputStream.java b/core/java/com/android/internal/util/BitwiseInputStream.java
index ffae3ce..91f89f3 100644
--- a/core/java/com/android/internal/util/BitwiseInputStream.java
+++ b/core/java/com/android/internal/util/BitwiseInputStream.java
@@ -26,6 +26,7 @@
*
* NOTE -- This class is not threadsafe.
*/
+@android.ravenwood.annotation.RavenwoodKeepWholeClass
public class BitwiseInputStream {
// The byte array being read from.
diff --git a/core/java/com/android/internal/util/BitwiseOutputStream.java b/core/java/com/android/internal/util/BitwiseOutputStream.java
index 9f41508..9b7568b 100644
--- a/core/java/com/android/internal/util/BitwiseOutputStream.java
+++ b/core/java/com/android/internal/util/BitwiseOutputStream.java
@@ -26,6 +26,7 @@
*
* NOTE -- This class is not threadsafe.
*/
+@android.ravenwood.annotation.RavenwoodKeepWholeClass
public class BitwiseOutputStream {
// The byte array being written to, which will be grown as needed.
diff --git a/core/java/com/android/internal/util/CallbackRegistry.java b/core/java/com/android/internal/util/CallbackRegistry.java
index 0f228d4..0ae8e1d 100644
--- a/core/java/com/android/internal/util/CallbackRegistry.java
+++ b/core/java/com/android/internal/util/CallbackRegistry.java
@@ -39,6 +39,7 @@
* @param <T> The notification sender type. Typically this is the containing class.
* @param <A> Opaque argument used to pass additional data beyond an int.
*/
+@android.ravenwood.annotation.RavenwoodKeepWholeClass
public class CallbackRegistry<C, T, A> implements Cloneable {
private static final String TAG = "CallbackRegistry";
diff --git a/core/java/com/android/internal/util/DumpUtils.java b/core/java/com/android/internal/util/DumpUtils.java
index 8fe2b9c..d1ff034 100644
--- a/core/java/com/android/internal/util/DumpUtils.java
+++ b/core/java/com/android/internal/util/DumpUtils.java
@@ -37,6 +37,7 @@
* Test:
atest FrameworksCoreTests:DumpUtilsTest
*/
+@android.ravenwood.annotation.RavenwoodKeepWholeClass
public final class DumpUtils {
/**
@@ -92,6 +93,8 @@
* @return true if access should be granted.
* @hide
*/
+ @android.ravenwood.annotation.RavenwoodThrow(
+ blockedBy = android.permission.PermissionManager.class)
public static boolean checkDumpPermission(Context context, String tag, PrintWriter pw) {
if (context.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
!= PackageManager.PERMISSION_GRANTED) {
@@ -112,6 +115,8 @@
* @return true if access should be granted.
* @hide
*/
+ @android.ravenwood.annotation.RavenwoodThrow(
+ blockedBy = android.permission.PermissionManager.class)
public static boolean checkUsageStatsPermission(Context context, String tag, PrintWriter pw) {
// System internals always get access
final int uid = Binder.getCallingUid();
@@ -166,6 +171,8 @@
* @return true if access should be granted.
* @hide
*/
+ @android.ravenwood.annotation.RavenwoodThrow(
+ blockedBy = android.permission.PermissionManager.class)
public static boolean checkDumpAndUsageStatsPermission(Context context, String tag,
PrintWriter pw) {
return checkDumpPermission(context, tag, pw) && checkUsageStatsPermission(context, tag, pw);
diff --git a/core/java/com/android/internal/util/FastMath.java b/core/java/com/android/internal/util/FastMath.java
index b7dbee5..6e8fef28 100644
--- a/core/java/com/android/internal/util/FastMath.java
+++ b/core/java/com/android/internal/util/FastMath.java
@@ -21,6 +21,7 @@
/**
* Fast and loose math routines.
*/
+@android.ravenwood.annotation.RavenwoodKeepWholeClass
public class FastMath {
/**
diff --git a/core/java/com/android/internal/util/FastPrintWriter.java b/core/java/com/android/internal/util/FastPrintWriter.java
index 63124de..fcd6df0 100644
--- a/core/java/com/android/internal/util/FastPrintWriter.java
+++ b/core/java/com/android/internal/util/FastPrintWriter.java
@@ -32,6 +32,7 @@
import java.nio.charset.CoderResult;
import java.nio.charset.CodingErrorAction;
+@android.ravenwood.annotation.RavenwoodKeepWholeClass
public class FastPrintWriter extends PrintWriter {
private static class DummyWriter extends Writer {
@Override
diff --git a/core/java/com/android/internal/util/GrowingArrayUtils.java b/core/java/com/android/internal/util/GrowingArrayUtils.java
index 8c12e36..83d06d1 100644
--- a/core/java/com/android/internal/util/GrowingArrayUtils.java
+++ b/core/java/com/android/internal/util/GrowingArrayUtils.java
@@ -29,6 +29,7 @@
*
* @hide
*/
+@android.ravenwood.annotation.RavenwoodKeepWholeClass
public final class GrowingArrayUtils {
/**
diff --git a/core/java/com/android/internal/util/HeavyHitterSketch.java b/core/java/com/android/internal/util/HeavyHitterSketch.java
index e18acaf..2973d30 100644
--- a/core/java/com/android/internal/util/HeavyHitterSketch.java
+++ b/core/java/com/android/internal/util/HeavyHitterSketch.java
@@ -35,6 +35,7 @@
* <p>
* {@hide}
*/
+@android.ravenwood.annotation.RavenwoodKeepWholeClass
public interface HeavyHitterSketch<T> {
/**
* Return the default implementation.
diff --git a/core/java/com/android/internal/util/LineBreakBufferedWriter.java b/core/java/com/android/internal/util/LineBreakBufferedWriter.java
index 552a93f..8393b22 100644
--- a/core/java/com/android/internal/util/LineBreakBufferedWriter.java
+++ b/core/java/com/android/internal/util/LineBreakBufferedWriter.java
@@ -27,6 +27,7 @@
*
* Note: this class is not thread-safe.
*/
+@android.ravenwood.annotation.RavenwoodKeepWholeClass
public class LineBreakBufferedWriter extends PrintWriter {
/**
diff --git a/core/java/com/android/internal/util/ObjectUtils.java b/core/java/com/android/internal/util/ObjectUtils.java
index 0e7b93d..292ee14 100644
--- a/core/java/com/android/internal/util/ObjectUtils.java
+++ b/core/java/com/android/internal/util/ObjectUtils.java
@@ -22,6 +22,7 @@
import java.util.Objects;
/** @hide */
+@android.ravenwood.annotation.RavenwoodKeepWholeClass
public class ObjectUtils {
private ObjectUtils() {}
diff --git a/core/java/com/android/internal/util/Parcelling.java b/core/java/com/android/internal/util/Parcelling.java
index 3147c34..70c3869 100644
--- a/core/java/com/android/internal/util/Parcelling.java
+++ b/core/java/com/android/internal/util/Parcelling.java
@@ -38,6 +38,7 @@
*
* @param <T> the type being [un]parcelled
*/
+@android.ravenwood.annotation.RavenwoodKeepWholeClass
public interface Parcelling<T> {
/**
diff --git a/core/java/com/android/internal/util/ParseUtils.java b/core/java/com/android/internal/util/ParseUtils.java
index a591f4a..a16ce2b 100644
--- a/core/java/com/android/internal/util/ParseUtils.java
+++ b/core/java/com/android/internal/util/ParseUtils.java
@@ -23,6 +23,7 @@
* Test:
atest /android/pi-dev/frameworks/base/core/tests/coretests/src/com/android/internal/util/ParseUtilsTest.java
*/
+@android.ravenwood.annotation.RavenwoodKeepWholeClass
public final class ParseUtils {
private ParseUtils() {
}
diff --git a/core/java/com/android/internal/util/ProcFileReader.java b/core/java/com/android/internal/util/ProcFileReader.java
index b726d5d..6cf241e 100644
--- a/core/java/com/android/internal/util/ProcFileReader.java
+++ b/core/java/com/android/internal/util/ProcFileReader.java
@@ -32,6 +32,7 @@
* Currently doesn't support formats based on {@code \0}, tabs.
* Consecutive spaces are treated as a single delimiter.
*/
+@android.ravenwood.annotation.RavenwoodKeepWholeClass
public class ProcFileReader implements Closeable {
private final InputStream mStream;
private final byte[] mBuffer;
diff --git a/core/java/com/android/internal/util/ProgressReporter.java b/core/java/com/android/internal/util/ProgressReporter.java
index 7a8efba..5640d8f 100644
--- a/core/java/com/android/internal/util/ProgressReporter.java
+++ b/core/java/com/android/internal/util/ProgressReporter.java
@@ -25,6 +25,7 @@
import android.util.MathUtils;
import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
/**
* Tracks and reports progress of a single task to a {@link IProgressListener}.
@@ -175,7 +176,8 @@
}
}
- int getProgress() {
+ @VisibleForTesting
+ public int getProgress() {
return mProgress;
}
diff --git a/core/java/com/android/internal/util/QuickSelect.java b/core/java/com/android/internal/util/QuickSelect.java
index 17739c9..052efed 100644
--- a/core/java/com/android/internal/util/QuickSelect.java
+++ b/core/java/com/android/internal/util/QuickSelect.java
@@ -28,6 +28,7 @@
*
* @hide
*/
+@android.ravenwood.annotation.RavenwoodKeepWholeClass
public final class QuickSelect {
private static <T> int selectImpl(@NonNull List<T> list, int left, int right, int k,
@NonNull Comparator<? super T> comparator) {
diff --git a/core/java/com/android/internal/util/RingBuffer.java b/core/java/com/android/internal/util/RingBuffer.java
index 8fc4c30..0488659 100644
--- a/core/java/com/android/internal/util/RingBuffer.java
+++ b/core/java/com/android/internal/util/RingBuffer.java
@@ -27,6 +27,7 @@
* full, oldest events are dropped when new events are added.
* {@hide}
*/
+@android.ravenwood.annotation.RavenwoodKeepWholeClass
public class RingBuffer<T> {
// Array for storing events.
diff --git a/core/java/com/android/internal/util/StringPool.java b/core/java/com/android/internal/util/StringPool.java
index c5180a3..94f6ec9 100644
--- a/core/java/com/android/internal/util/StringPool.java
+++ b/core/java/com/android/internal/util/StringPool.java
@@ -23,6 +23,7 @@
*
* @hide
*/
+@android.ravenwood.annotation.RavenwoodKeepWholeClass
public final class StringPool {
private final String[] mPool = new String[512];
diff --git a/core/java/com/android/internal/util/dump/DumpableContainerImpl.java b/core/java/com/android/internal/util/dump/DumpableContainerImpl.java
index ccec6c6..bb5224f 100644
--- a/core/java/com/android/internal/util/dump/DumpableContainerImpl.java
+++ b/core/java/com/android/internal/util/dump/DumpableContainerImpl.java
@@ -32,6 +32,7 @@
*
* @hide
*/
+@android.ravenwood.annotation.RavenwoodKeepWholeClass
public final class DumpableContainerImpl implements DumpableContainer {
private static final String TAG = DumpableContainerImpl.class.getSimpleName();
diff --git a/core/java/com/google/android/collect/Lists.java b/core/java/com/google/android/collect/Lists.java
index 585847d..392b87e 100644
--- a/core/java/com/google/android/collect/Lists.java
+++ b/core/java/com/google/android/collect/Lists.java
@@ -25,6 +25,7 @@
* Provides static methods for creating {@code List} instances easily, and other
* utility methods for working with lists.
*/
+@android.ravenwood.annotation.RavenwoodKeepWholeClass
public class Lists {
/**
diff --git a/core/java/com/google/android/collect/Maps.java b/core/java/com/google/android/collect/Maps.java
index cd4c128..6492b03 100644
--- a/core/java/com/google/android/collect/Maps.java
+++ b/core/java/com/google/android/collect/Maps.java
@@ -24,6 +24,7 @@
/**
* Provides static methods for creating mutable {@code Maps} instances easily.
*/
+@android.ravenwood.annotation.RavenwoodKeepWholeClass
public class Maps {
/**
* Creates a {@code HashMap} instance.
diff --git a/core/java/com/google/android/collect/Sets.java b/core/java/com/google/android/collect/Sets.java
index e242915..76eaf21 100644
--- a/core/java/com/google/android/collect/Sets.java
+++ b/core/java/com/google/android/collect/Sets.java
@@ -31,6 +31,7 @@
* other static methods for working with Sets.
*
*/
+@android.ravenwood.annotation.RavenwoodKeepWholeClass
public class Sets {
/**
diff --git a/core/jni/com_android_internal_content_om_OverlayManagerImpl.cpp b/core/jni/com_android_internal_content_om_OverlayManagerImpl.cpp
index 0c39a69..358531a 100644
--- a/core/jni/com_android_internal_content_om_OverlayManagerImpl.cpp
+++ b/core/jni/com_android_internal_content_om_OverlayManagerImpl.cpp
@@ -46,6 +46,7 @@
jfieldID configuration;
jfieldID binaryDataOffset;
jfieldID binaryDataSize;
+ jfieldID isNinePatch;
} gFabricatedOverlayInternalEntryOffsets;
static struct parcel_file_descriptor_offsets_t {
@@ -288,13 +289,16 @@
env->GetLongField(entry, gFabricatedOverlayInternalEntryOffsets.binaryDataOffset);
const auto data_size =
env->GetLongField(entry, gFabricatedOverlayInternalEntryOffsets.binaryDataSize);
+ const auto nine_patch =
+ env->GetBooleanField(entry, gFabricatedOverlayInternalEntryOffsets.isNinePatch);
entries_params.push_back(
FabricatedOverlayEntryParameters{resourceName.c_str(), (DataType)dataType,
(DataValue)data,
string_data.value_or(std::string()), binary_data,
static_cast<off64_t>(data_offset),
static_cast<size_t>(data_size),
- configuration.value_or(std::string())});
+ configuration.value_or(std::string()),
+ static_cast<bool>(nine_patch)});
ALOGV("resourceName = %s, dataType = 0x%08x, data = 0x%08x, dataString = %s,"
" binaryData = %d, configuration = %s",
resourceName.c_str(), dataType, data, string_data.value_or(std::string()).c_str(),
@@ -455,6 +459,9 @@
gFabricatedOverlayInternalEntryOffsets.binaryDataSize =
GetFieldIDOrDie(env, gFabricatedOverlayInternalEntryOffsets.classObject,
"binaryDataSize", "J");
+ gFabricatedOverlayInternalEntryOffsets.isNinePatch =
+ GetFieldIDOrDie(env, gFabricatedOverlayInternalEntryOffsets.classObject, "isNinePatch",
+ "Z");
jclass parcelFileDescriptorClass =
android::FindClassOrDie(env, "android/os/ParcelFileDescriptor");
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index c55b808..dd93586 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -7832,6 +7832,22 @@
<permission android:name="android.permission.PREPARE_FACTORY_RESET"
android:protectionLevel="signature|privileged" />
+ <!-- @SystemApi Allows focused window to override the default behavior of supported system keys.
+ The following keycodes are supported:
+ <p> KEYCODE_STEM_PRIMARY
+ <p>If an app is granted this permission and has a focused window, it will be allowed to
+ receive supported key events that are otherwise handled by the system. The app can choose
+ to consume the key events and trigger its own behavior, in which case the default key
+ behavior will be skipped.
+ <p>For example, KEYCODE_STEM_PRIMARY by default opens recent app launcher. If the foreground
+ fitness app is granted this permission, it can repurpose the KEYCODE_STEM_PRIMARY button
+ to pause/resume the current fitness session.
+ <p>Protection level: signature|privileged
+ @FlaggedApi("com.android.input.flags.override_key_behavior_permission_apis")
+ @hide -->
+ <permission android:name="android.permission.OVERRIDE_SYSTEM_KEY_BEHAVIOR_IN_FOCUSED_WINDOW"
+ android:protectionLevel="signature|privileged" />
+
<!-- Attribution for Geofencing service. -->
<attribution android:tag="GeofencingService" android:label="@string/geofencing_service"/>
<!-- Attribution for Country Detector. -->
diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
index 625b1413..356c5e1 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -2359,18 +2359,11 @@
<string name="keyboard_layout_notification_more_than_three_selected_message" msgid="1581834181578206937">"Sleutelborduitleg is gestel op <xliff:g id="LAYOUT_1">%1$s</xliff:g>, <xliff:g id="LAYOUT_2">%2$s</xliff:g>, <xliff:g id="LAYOUT_3">%3$s</xliff:g> … Tik om dit te verander."</string>
<string name="keyboard_layout_notification_multiple_selected_title" msgid="5242444914367024499">"Fisieke sleutelborde is opgestel"</string>
<string name="keyboard_layout_notification_multiple_selected_message" msgid="6576533454124419202">"Tik om sleutelborde te bekyk"</string>
- <!-- no translation found for profile_label_private (6463418670715290696) -->
- <skip />
- <!-- no translation found for profile_label_clone (769106052210954285) -->
- <skip />
- <!-- no translation found for profile_label_work (3495359133038584618) -->
- <skip />
- <!-- no translation found for profile_label_work_2 (4691533661598632135) -->
- <skip />
- <!-- no translation found for profile_label_work_3 (4834572253956798917) -->
- <skip />
- <!-- no translation found for profile_label_test (9168641926186071947) -->
- <skip />
- <!-- no translation found for profile_label_communal (8743921499944800427) -->
- <skip />
+ <string name="profile_label_private" msgid="6463418670715290696">"Privaat"</string>
+ <string name="profile_label_clone" msgid="769106052210954285">"Kloon"</string>
+ <string name="profile_label_work" msgid="3495359133038584618">"Werk"</string>
+ <string name="profile_label_work_2" msgid="4691533661598632135">"Werk 2"</string>
+ <string name="profile_label_work_3" msgid="4834572253956798917">"Werk 3"</string>
+ <string name="profile_label_test" msgid="9168641926186071947">"Toets"</string>
+ <string name="profile_label_communal" msgid="8743921499944800427">"Gemeenskaplik"</string>
</resources>
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index 04fb300..8af993f 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -2363,18 +2363,11 @@
<string name="keyboard_layout_notification_more_than_three_selected_message" msgid="1581834181578206937">"تم ضبط تنسيق لوحة المفاتيح على <xliff:g id="LAYOUT_1">%1$s</xliff:g> و<xliff:g id="LAYOUT_2">%2$s</xliff:g> و<xliff:g id="LAYOUT_3">%3$s</xliff:g>… انقر لتغييره."</string>
<string name="keyboard_layout_notification_multiple_selected_title" msgid="5242444914367024499">"تم إعداد لوحات المفاتيح الخارجية"</string>
<string name="keyboard_layout_notification_multiple_selected_message" msgid="6576533454124419202">"انقر لعرض لوحات المفاتيح."</string>
- <!-- no translation found for profile_label_private (6463418670715290696) -->
- <skip />
- <!-- no translation found for profile_label_clone (769106052210954285) -->
- <skip />
- <!-- no translation found for profile_label_work (3495359133038584618) -->
- <skip />
- <!-- no translation found for profile_label_work_2 (4691533661598632135) -->
- <skip />
- <!-- no translation found for profile_label_work_3 (4834572253956798917) -->
- <skip />
- <!-- no translation found for profile_label_test (9168641926186071947) -->
- <skip />
- <!-- no translation found for profile_label_communal (8743921499944800427) -->
- <skip />
+ <string name="profile_label_private" msgid="6463418670715290696">"ملف شخصي خاص"</string>
+ <string name="profile_label_clone" msgid="769106052210954285">"نسخة طبق الأصل"</string>
+ <string name="profile_label_work" msgid="3495359133038584618">"ملف العمل"</string>
+ <string name="profile_label_work_2" msgid="4691533661598632135">"ملف العمل 2"</string>
+ <string name="profile_label_work_3" msgid="4834572253956798917">"ملف العمل 3"</string>
+ <string name="profile_label_test" msgid="9168641926186071947">"ملف شخصي تجريبي"</string>
+ <string name="profile_label_communal" msgid="8743921499944800427">"ملف شخصي مشترك"</string>
</resources>
diff --git a/core/res/res/values-as/strings.xml b/core/res/res/values-as/strings.xml
index 826844f..5e3d0f6 100644
--- a/core/res/res/values-as/strings.xml
+++ b/core/res/res/values-as/strings.xml
@@ -2359,18 +2359,11 @@
<string name="keyboard_layout_notification_more_than_three_selected_message" msgid="1581834181578206937">"কীব’ৰ্ডৰ লে’আউট <xliff:g id="LAYOUT_1">%1$s</xliff:g>, <xliff:g id="LAYOUT_2">%2$s</xliff:g>, <xliff:g id="LAYOUT_3">%3$s</xliff:g> হিচাপে ছেট কৰা হৈছে… সলনি কৰিবলৈ টিপক।"</string>
<string name="keyboard_layout_notification_multiple_selected_title" msgid="5242444914367024499">"ভৌতিক কীব’ৰ্ড কনফিগাৰ কৰা হৈছে"</string>
<string name="keyboard_layout_notification_multiple_selected_message" msgid="6576533454124419202">"কীব’ৰ্ড চাবলৈ টিপক"</string>
- <!-- no translation found for profile_label_private (6463418670715290696) -->
- <skip />
- <!-- no translation found for profile_label_clone (769106052210954285) -->
- <skip />
- <!-- no translation found for profile_label_work (3495359133038584618) -->
- <skip />
- <!-- no translation found for profile_label_work_2 (4691533661598632135) -->
- <skip />
- <!-- no translation found for profile_label_work_3 (4834572253956798917) -->
- <skip />
- <!-- no translation found for profile_label_test (9168641926186071947) -->
- <skip />
- <!-- no translation found for profile_label_communal (8743921499944800427) -->
- <skip />
+ <string name="profile_label_private" msgid="6463418670715290696">"ব্যক্তিগত"</string>
+ <string name="profile_label_clone" msgid="769106052210954285">"ক্ল’ন"</string>
+ <string name="profile_label_work" msgid="3495359133038584618">"কৰ্মস্থান"</string>
+ <string name="profile_label_work_2" msgid="4691533661598632135">"কৰ্মস্থান ২"</string>
+ <string name="profile_label_work_3" msgid="4834572253956798917">"কৰ্মস্থান ৩"</string>
+ <string name="profile_label_test" msgid="9168641926186071947">"পৰীক্ষা"</string>
+ <string name="profile_label_communal" msgid="8743921499944800427">"শ্বেয়াৰ কৰা"</string>
</resources>
diff --git a/core/res/res/values-az/strings.xml b/core/res/res/values-az/strings.xml
index 66a5670..a000117 100644
--- a/core/res/res/values-az/strings.xml
+++ b/core/res/res/values-az/strings.xml
@@ -2359,18 +2359,11 @@
<string name="keyboard_layout_notification_more_than_three_selected_message" msgid="1581834181578206937">"Klaviatura düzəni <xliff:g id="LAYOUT_1">%1$s</xliff:g>, <xliff:g id="LAYOUT_2">%2$s</xliff:g>, <xliff:g id="LAYOUT_3">%3$s</xliff:g> kimi ayarlanıb… Dəyişmək üçün toxunun."</string>
<string name="keyboard_layout_notification_multiple_selected_title" msgid="5242444914367024499">"Fiziki klaviaturalar konfiqurasiya edilib"</string>
<string name="keyboard_layout_notification_multiple_selected_message" msgid="6576533454124419202">"Klaviaturalara baxmaq üçün toxunun"</string>
- <!-- no translation found for profile_label_private (6463418670715290696) -->
- <skip />
- <!-- no translation found for profile_label_clone (769106052210954285) -->
- <skip />
- <!-- no translation found for profile_label_work (3495359133038584618) -->
- <skip />
- <!-- no translation found for profile_label_work_2 (4691533661598632135) -->
- <skip />
- <!-- no translation found for profile_label_work_3 (4834572253956798917) -->
- <skip />
- <!-- no translation found for profile_label_test (9168641926186071947) -->
- <skip />
- <!-- no translation found for profile_label_communal (8743921499944800427) -->
- <skip />
+ <string name="profile_label_private" msgid="6463418670715290696">"Şəxsi"</string>
+ <string name="profile_label_clone" msgid="769106052210954285">"Klon"</string>
+ <string name="profile_label_work" msgid="3495359133038584618">"İş"</string>
+ <string name="profile_label_work_2" msgid="4691533661598632135">"İş 2"</string>
+ <string name="profile_label_work_3" msgid="4834572253956798917">"İş 3"</string>
+ <string name="profile_label_test" msgid="9168641926186071947">"Test"</string>
+ <string name="profile_label_communal" msgid="8743921499944800427">"Kommunal"</string>
</resources>
diff --git a/core/res/res/values-b+sr+Latn/strings.xml b/core/res/res/values-b+sr+Latn/strings.xml
index b6121ed..080d1bdda 100644
--- a/core/res/res/values-b+sr+Latn/strings.xml
+++ b/core/res/res/values-b+sr+Latn/strings.xml
@@ -2360,18 +2360,11 @@
<string name="keyboard_layout_notification_more_than_three_selected_message" msgid="1581834181578206937">"Raspored tastature je podešen na <xliff:g id="LAYOUT_1">%1$s</xliff:g>, <xliff:g id="LAYOUT_2">%2$s</xliff:g>, <xliff:g id="LAYOUT_3">%3$s</xliff:g>… Dodirnite da biste promenili."</string>
<string name="keyboard_layout_notification_multiple_selected_title" msgid="5242444914367024499">"Fizičke tastature su konfigurisane"</string>
<string name="keyboard_layout_notification_multiple_selected_message" msgid="6576533454124419202">"Dodirnite da biste videli tastature"</string>
- <!-- no translation found for profile_label_private (6463418670715290696) -->
- <skip />
- <!-- no translation found for profile_label_clone (769106052210954285) -->
- <skip />
- <!-- no translation found for profile_label_work (3495359133038584618) -->
- <skip />
- <!-- no translation found for profile_label_work_2 (4691533661598632135) -->
- <skip />
- <!-- no translation found for profile_label_work_3 (4834572253956798917) -->
- <skip />
- <!-- no translation found for profile_label_test (9168641926186071947) -->
- <skip />
- <!-- no translation found for profile_label_communal (8743921499944800427) -->
- <skip />
+ <string name="profile_label_private" msgid="6463418670715290696">"Privatno"</string>
+ <string name="profile_label_clone" msgid="769106052210954285">"Klonirano"</string>
+ <string name="profile_label_work" msgid="3495359133038584618">"Posao"</string>
+ <string name="profile_label_work_2" msgid="4691533661598632135">"Posao 2"</string>
+ <string name="profile_label_work_3" msgid="4834572253956798917">"Posao 3"</string>
+ <string name="profile_label_test" msgid="9168641926186071947">"Test"</string>
+ <string name="profile_label_communal" msgid="8743921499944800427">"Zajedničko"</string>
</resources>
diff --git a/core/res/res/values-be/strings.xml b/core/res/res/values-be/strings.xml
index 3c01f1b..1cca6ff 100644
--- a/core/res/res/values-be/strings.xml
+++ b/core/res/res/values-be/strings.xml
@@ -2361,18 +2361,11 @@
<string name="keyboard_layout_notification_more_than_three_selected_message" msgid="1581834181578206937">"Раскладка клавіятуры наладжана для наступных моў: <xliff:g id="LAYOUT_1">%1$s</xliff:g>, <xliff:g id="LAYOUT_2">%2$s</xliff:g>, <xliff:g id="LAYOUT_3">%3$s</xliff:g>… Націсніце, каб змяніць."</string>
<string name="keyboard_layout_notification_multiple_selected_title" msgid="5242444914367024499">"Фізічныя клавіятуры наладжаны"</string>
<string name="keyboard_layout_notification_multiple_selected_message" msgid="6576533454124419202">"Націсніце, каб праглядзець клавіятуры"</string>
- <!-- no translation found for profile_label_private (6463418670715290696) -->
- <skip />
- <!-- no translation found for profile_label_clone (769106052210954285) -->
- <skip />
- <!-- no translation found for profile_label_work (3495359133038584618) -->
- <skip />
- <!-- no translation found for profile_label_work_2 (4691533661598632135) -->
- <skip />
- <!-- no translation found for profile_label_work_3 (4834572253956798917) -->
- <skip />
- <!-- no translation found for profile_label_test (9168641926186071947) -->
- <skip />
- <!-- no translation found for profile_label_communal (8743921499944800427) -->
- <skip />
+ <string name="profile_label_private" msgid="6463418670715290696">"Прыватны"</string>
+ <string name="profile_label_clone" msgid="769106052210954285">"Клон"</string>
+ <string name="profile_label_work" msgid="3495359133038584618">"Працоўны"</string>
+ <string name="profile_label_work_2" msgid="4691533661598632135">"Працоўны 2"</string>
+ <string name="profile_label_work_3" msgid="4834572253956798917">"Працоўны 3"</string>
+ <string name="profile_label_test" msgid="9168641926186071947">"Тэставы"</string>
+ <string name="profile_label_communal" msgid="8743921499944800427">"Супольны"</string>
</resources>
diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
index 3b1ff9e..8f994ca 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -2359,18 +2359,11 @@
<string name="keyboard_layout_notification_more_than_three_selected_message" msgid="1581834181578206937">"За клавиатурната подредба са зададени <xliff:g id="LAYOUT_1">%1$s</xliff:g>, <xliff:g id="LAYOUT_2">%2$s</xliff:g> и <xliff:g id="LAYOUT_3">%3$s</xliff:g>… Докоснете за промяна."</string>
<string name="keyboard_layout_notification_multiple_selected_title" msgid="5242444914367024499">"Физическите клавиатури са конфигурирани"</string>
<string name="keyboard_layout_notification_multiple_selected_message" msgid="6576533454124419202">"Докоснете за преглед на клавиатурите"</string>
- <!-- no translation found for profile_label_private (6463418670715290696) -->
- <skip />
- <!-- no translation found for profile_label_clone (769106052210954285) -->
- <skip />
- <!-- no translation found for profile_label_work (3495359133038584618) -->
- <skip />
- <!-- no translation found for profile_label_work_2 (4691533661598632135) -->
- <skip />
- <!-- no translation found for profile_label_work_3 (4834572253956798917) -->
- <skip />
- <!-- no translation found for profile_label_test (9168641926186071947) -->
- <skip />
- <!-- no translation found for profile_label_communal (8743921499944800427) -->
- <skip />
+ <string name="profile_label_private" msgid="6463418670715290696">"Частни"</string>
+ <string name="profile_label_clone" msgid="769106052210954285">"Клониране"</string>
+ <string name="profile_label_work" msgid="3495359133038584618">"Служебни"</string>
+ <string name="profile_label_work_2" msgid="4691533661598632135">"Служебни 2"</string>
+ <string name="profile_label_work_3" msgid="4834572253956798917">"Служебни 3"</string>
+ <string name="profile_label_test" msgid="9168641926186071947">"Тестване"</string>
+ <string name="profile_label_communal" msgid="8743921499944800427">"Общи"</string>
</resources>
diff --git a/core/res/res/values-bn/strings.xml b/core/res/res/values-bn/strings.xml
index 58dd7c2..f85df40 100644
--- a/core/res/res/values-bn/strings.xml
+++ b/core/res/res/values-bn/strings.xml
@@ -2359,18 +2359,11 @@
<string name="keyboard_layout_notification_more_than_three_selected_message" msgid="1581834181578206937">"কীবোর্ড লেআউট <xliff:g id="LAYOUT_1">%1$s</xliff:g>, <xliff:g id="LAYOUT_2">%2$s</xliff:g>, <xliff:g id="LAYOUT_3">%3$s</xliff:g>-এ সেট করা আছে… পালটাতে ট্যাপ করুন।"</string>
<string name="keyboard_layout_notification_multiple_selected_title" msgid="5242444914367024499">"ফিজিক্যাল কীবোর্ড কনফিগার করা হয়েছে"</string>
<string name="keyboard_layout_notification_multiple_selected_message" msgid="6576533454124419202">"কীবোর্ড দেখতে ট্যাপ করুন"</string>
- <!-- no translation found for profile_label_private (6463418670715290696) -->
- <skip />
- <!-- no translation found for profile_label_clone (769106052210954285) -->
- <skip />
- <!-- no translation found for profile_label_work (3495359133038584618) -->
- <skip />
- <!-- no translation found for profile_label_work_2 (4691533661598632135) -->
- <skip />
- <!-- no translation found for profile_label_work_3 (4834572253956798917) -->
- <skip />
- <!-- no translation found for profile_label_test (9168641926186071947) -->
- <skip />
- <!-- no translation found for profile_label_communal (8743921499944800427) -->
- <skip />
+ <string name="profile_label_private" msgid="6463418670715290696">"ব্যক্তিগত"</string>
+ <string name="profile_label_clone" msgid="769106052210954285">"ক্লোন করুন"</string>
+ <string name="profile_label_work" msgid="3495359133038584618">"অফিস"</string>
+ <string name="profile_label_work_2" msgid="4691533661598632135">"২য় অফিস"</string>
+ <string name="profile_label_work_3" msgid="4834572253956798917">"৩য় অফিস"</string>
+ <string name="profile_label_test" msgid="9168641926186071947">"পরীক্ষা"</string>
+ <string name="profile_label_communal" msgid="8743921499944800427">"কমিউনাল"</string>
</resources>
diff --git a/core/res/res/values-bs/strings.xml b/core/res/res/values-bs/strings.xml
index aa66e02..5d207a8 100644
--- a/core/res/res/values-bs/strings.xml
+++ b/core/res/res/values-bs/strings.xml
@@ -2360,18 +2360,11 @@
<string name="keyboard_layout_notification_more_than_three_selected_message" msgid="1581834181578206937">"Raspored tastature je postavljen na <xliff:g id="LAYOUT_1">%1$s</xliff:g>, <xliff:g id="LAYOUT_2">%2$s</xliff:g>, <xliff:g id="LAYOUT_3">%3$s</xliff:g>… Dodirnite da promijenite."</string>
<string name="keyboard_layout_notification_multiple_selected_title" msgid="5242444914367024499">"Fizičke tastature su konfigurirane"</string>
<string name="keyboard_layout_notification_multiple_selected_message" msgid="6576533454124419202">"Dodirnite da pregledate tastature"</string>
- <!-- no translation found for profile_label_private (6463418670715290696) -->
- <skip />
- <!-- no translation found for profile_label_clone (769106052210954285) -->
- <skip />
- <!-- no translation found for profile_label_work (3495359133038584618) -->
- <skip />
- <!-- no translation found for profile_label_work_2 (4691533661598632135) -->
- <skip />
- <!-- no translation found for profile_label_work_3 (4834572253956798917) -->
- <skip />
- <!-- no translation found for profile_label_test (9168641926186071947) -->
- <skip />
- <!-- no translation found for profile_label_communal (8743921499944800427) -->
- <skip />
+ <string name="profile_label_private" msgid="6463418670715290696">"Privatno"</string>
+ <string name="profile_label_clone" msgid="769106052210954285">"Klon"</string>
+ <string name="profile_label_work" msgid="3495359133038584618">"Poslovno"</string>
+ <string name="profile_label_work_2" msgid="4691533661598632135">"2. poslovno"</string>
+ <string name="profile_label_work_3" msgid="4834572253956798917">"3. poslovno"</string>
+ <string name="profile_label_test" msgid="9168641926186071947">"Testno"</string>
+ <string name="profile_label_communal" msgid="8743921499944800427">"Opće"</string>
</resources>
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index be8654d..cf3a8ad 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -2360,18 +2360,11 @@
<string name="keyboard_layout_notification_more_than_three_selected_message" msgid="1581834181578206937">"Disseny del teclat definit en <xliff:g id="LAYOUT_1">%1$s</xliff:g>, <xliff:g id="LAYOUT_2">%2$s</xliff:g>, <xliff:g id="LAYOUT_3">%3$s</xliff:g>… Toca per canviar-ho."</string>
<string name="keyboard_layout_notification_multiple_selected_title" msgid="5242444914367024499">"Teclats físic configurats"</string>
<string name="keyboard_layout_notification_multiple_selected_message" msgid="6576533454124419202">"Toca per veure els teclats"</string>
- <!-- no translation found for profile_label_private (6463418670715290696) -->
- <skip />
- <!-- no translation found for profile_label_clone (769106052210954285) -->
- <skip />
- <!-- no translation found for profile_label_work (3495359133038584618) -->
- <skip />
- <!-- no translation found for profile_label_work_2 (4691533661598632135) -->
- <skip />
- <!-- no translation found for profile_label_work_3 (4834572253956798917) -->
- <skip />
- <!-- no translation found for profile_label_test (9168641926186071947) -->
- <skip />
- <!-- no translation found for profile_label_communal (8743921499944800427) -->
- <skip />
+ <string name="profile_label_private" msgid="6463418670715290696">"Privat"</string>
+ <string name="profile_label_clone" msgid="769106052210954285">"Clon"</string>
+ <string name="profile_label_work" msgid="3495359133038584618">"Treball"</string>
+ <string name="profile_label_work_2" msgid="4691533661598632135">"Treball 2"</string>
+ <string name="profile_label_work_3" msgid="4834572253956798917">"Treball 3"</string>
+ <string name="profile_label_test" msgid="9168641926186071947">"Prova"</string>
+ <string name="profile_label_communal" msgid="8743921499944800427">"Compartit"</string>
</resources>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index 35def43..0d586e4 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -2359,18 +2359,11 @@
<string name="keyboard_layout_notification_more_than_three_selected_message" msgid="1581834181578206937">"Tastaturlayoutet er angivet som <xliff:g id="LAYOUT_1">%1$s</xliff:g>, <xliff:g id="LAYOUT_2">%2$s</xliff:g>, <xliff:g id="LAYOUT_3">%3$s</xliff:g>… Tryk for at ændre dette."</string>
<string name="keyboard_layout_notification_multiple_selected_title" msgid="5242444914367024499">"Fysiske tastaturer er konfigureret"</string>
<string name="keyboard_layout_notification_multiple_selected_message" msgid="6576533454124419202">"Tryk for at se tastaturer"</string>
- <!-- no translation found for profile_label_private (6463418670715290696) -->
- <skip />
- <!-- no translation found for profile_label_clone (769106052210954285) -->
- <skip />
- <!-- no translation found for profile_label_work (3495359133038584618) -->
- <skip />
- <!-- no translation found for profile_label_work_2 (4691533661598632135) -->
- <skip />
- <!-- no translation found for profile_label_work_3 (4834572253956798917) -->
- <skip />
- <!-- no translation found for profile_label_test (9168641926186071947) -->
- <skip />
- <!-- no translation found for profile_label_communal (8743921499944800427) -->
- <skip />
+ <string name="profile_label_private" msgid="6463418670715290696">"Privat"</string>
+ <string name="profile_label_clone" msgid="769106052210954285">"Klon"</string>
+ <string name="profile_label_work" msgid="3495359133038584618">"Arbejde"</string>
+ <string name="profile_label_work_2" msgid="4691533661598632135">"Arbejde 2"</string>
+ <string name="profile_label_work_3" msgid="4834572253956798917">"Arbejde 3"</string>
+ <string name="profile_label_test" msgid="9168641926186071947">"Test"</string>
+ <string name="profile_label_communal" msgid="8743921499944800427">"Fælles"</string>
</resources>
diff --git a/core/res/res/values-en-rAU/strings.xml b/core/res/res/values-en-rAU/strings.xml
index 179bdb4..6c47dd6 100644
--- a/core/res/res/values-en-rAU/strings.xml
+++ b/core/res/res/values-en-rAU/strings.xml
@@ -2359,18 +2359,11 @@
<string name="keyboard_layout_notification_more_than_three_selected_message" msgid="1581834181578206937">"Keyboard layout set to <xliff:g id="LAYOUT_1">%1$s</xliff:g>, <xliff:g id="LAYOUT_2">%2$s</xliff:g>, <xliff:g id="LAYOUT_3">%3$s</xliff:g>… Tap to change."</string>
<string name="keyboard_layout_notification_multiple_selected_title" msgid="5242444914367024499">"Physical keyboards configured"</string>
<string name="keyboard_layout_notification_multiple_selected_message" msgid="6576533454124419202">"Tap to view keyboards"</string>
- <!-- no translation found for profile_label_private (6463418670715290696) -->
- <skip />
- <!-- no translation found for profile_label_clone (769106052210954285) -->
- <skip />
- <!-- no translation found for profile_label_work (3495359133038584618) -->
- <skip />
- <!-- no translation found for profile_label_work_2 (4691533661598632135) -->
- <skip />
- <!-- no translation found for profile_label_work_3 (4834572253956798917) -->
- <skip />
- <!-- no translation found for profile_label_test (9168641926186071947) -->
- <skip />
- <!-- no translation found for profile_label_communal (8743921499944800427) -->
- <skip />
+ <string name="profile_label_private" msgid="6463418670715290696">"Private"</string>
+ <string name="profile_label_clone" msgid="769106052210954285">"Clone"</string>
+ <string name="profile_label_work" msgid="3495359133038584618">"Work"</string>
+ <string name="profile_label_work_2" msgid="4691533661598632135">"Work 2"</string>
+ <string name="profile_label_work_3" msgid="4834572253956798917">"Work 3"</string>
+ <string name="profile_label_test" msgid="9168641926186071947">"Test"</string>
+ <string name="profile_label_communal" msgid="8743921499944800427">"Communal"</string>
</resources>
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index 2a4f88e..5c26afa 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -2359,18 +2359,11 @@
<string name="keyboard_layout_notification_more_than_three_selected_message" msgid="1581834181578206937">"Keyboard layout set to <xliff:g id="LAYOUT_1">%1$s</xliff:g>, <xliff:g id="LAYOUT_2">%2$s</xliff:g>, <xliff:g id="LAYOUT_3">%3$s</xliff:g>… Tap to change."</string>
<string name="keyboard_layout_notification_multiple_selected_title" msgid="5242444914367024499">"Physical keyboards configured"</string>
<string name="keyboard_layout_notification_multiple_selected_message" msgid="6576533454124419202">"Tap to view keyboards"</string>
- <!-- no translation found for profile_label_private (6463418670715290696) -->
- <skip />
- <!-- no translation found for profile_label_clone (769106052210954285) -->
- <skip />
- <!-- no translation found for profile_label_work (3495359133038584618) -->
- <skip />
- <!-- no translation found for profile_label_work_2 (4691533661598632135) -->
- <skip />
- <!-- no translation found for profile_label_work_3 (4834572253956798917) -->
- <skip />
- <!-- no translation found for profile_label_test (9168641926186071947) -->
- <skip />
- <!-- no translation found for profile_label_communal (8743921499944800427) -->
- <skip />
+ <string name="profile_label_private" msgid="6463418670715290696">"Private"</string>
+ <string name="profile_label_clone" msgid="769106052210954285">"Clone"</string>
+ <string name="profile_label_work" msgid="3495359133038584618">"Work"</string>
+ <string name="profile_label_work_2" msgid="4691533661598632135">"Work 2"</string>
+ <string name="profile_label_work_3" msgid="4834572253956798917">"Work 3"</string>
+ <string name="profile_label_test" msgid="9168641926186071947">"Test"</string>
+ <string name="profile_label_communal" msgid="8743921499944800427">"Communal"</string>
</resources>
diff --git a/core/res/res/values-en-rIN/strings.xml b/core/res/res/values-en-rIN/strings.xml
index 0f08d2f..80da8b9 100644
--- a/core/res/res/values-en-rIN/strings.xml
+++ b/core/res/res/values-en-rIN/strings.xml
@@ -2359,18 +2359,11 @@
<string name="keyboard_layout_notification_more_than_three_selected_message" msgid="1581834181578206937">"Keyboard layout set to <xliff:g id="LAYOUT_1">%1$s</xliff:g>, <xliff:g id="LAYOUT_2">%2$s</xliff:g>, <xliff:g id="LAYOUT_3">%3$s</xliff:g>… Tap to change."</string>
<string name="keyboard_layout_notification_multiple_selected_title" msgid="5242444914367024499">"Physical keyboards configured"</string>
<string name="keyboard_layout_notification_multiple_selected_message" msgid="6576533454124419202">"Tap to view keyboards"</string>
- <!-- no translation found for profile_label_private (6463418670715290696) -->
- <skip />
- <!-- no translation found for profile_label_clone (769106052210954285) -->
- <skip />
- <!-- no translation found for profile_label_work (3495359133038584618) -->
- <skip />
- <!-- no translation found for profile_label_work_2 (4691533661598632135) -->
- <skip />
- <!-- no translation found for profile_label_work_3 (4834572253956798917) -->
- <skip />
- <!-- no translation found for profile_label_test (9168641926186071947) -->
- <skip />
- <!-- no translation found for profile_label_communal (8743921499944800427) -->
- <skip />
+ <string name="profile_label_private" msgid="6463418670715290696">"Private"</string>
+ <string name="profile_label_clone" msgid="769106052210954285">"Clone"</string>
+ <string name="profile_label_work" msgid="3495359133038584618">"Work"</string>
+ <string name="profile_label_work_2" msgid="4691533661598632135">"Work 2"</string>
+ <string name="profile_label_work_3" msgid="4834572253956798917">"Work 3"</string>
+ <string name="profile_label_test" msgid="9168641926186071947">"Test"</string>
+ <string name="profile_label_communal" msgid="8743921499944800427">"Communal"</string>
</resources>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index 29f0f8f..051528d 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -2360,18 +2360,11 @@
<string name="keyboard_layout_notification_more_than_three_selected_message" msgid="1581834181578206937">"Diseño del teclado definido como <xliff:g id="LAYOUT_1">%1$s</xliff:g>, <xliff:g id="LAYOUT_2">%2$s</xliff:g>, <xliff:g id="LAYOUT_3">%3$s</xliff:g>… Toca para cambiarlo."</string>
<string name="keyboard_layout_notification_multiple_selected_title" msgid="5242444914367024499">"Teclados físicos configurados"</string>
<string name="keyboard_layout_notification_multiple_selected_message" msgid="6576533454124419202">"Toca para ver los teclados"</string>
- <!-- no translation found for profile_label_private (6463418670715290696) -->
- <skip />
- <!-- no translation found for profile_label_clone (769106052210954285) -->
- <skip />
- <!-- no translation found for profile_label_work (3495359133038584618) -->
- <skip />
- <!-- no translation found for profile_label_work_2 (4691533661598632135) -->
- <skip />
- <!-- no translation found for profile_label_work_3 (4834572253956798917) -->
- <skip />
- <!-- no translation found for profile_label_test (9168641926186071947) -->
- <skip />
- <!-- no translation found for profile_label_communal (8743921499944800427) -->
- <skip />
+ <string name="profile_label_private" msgid="6463418670715290696">"Privado"</string>
+ <string name="profile_label_clone" msgid="769106052210954285">"Clon"</string>
+ <string name="profile_label_work" msgid="3495359133038584618">"Trabajo"</string>
+ <string name="profile_label_work_2" msgid="4691533661598632135">"Trabajo 2"</string>
+ <string name="profile_label_work_3" msgid="4834572253956798917">"Trabajo 3"</string>
+ <string name="profile_label_test" msgid="9168641926186071947">"Prueba"</string>
+ <string name="profile_label_communal" msgid="8743921499944800427">"Común"</string>
</resources>
diff --git a/core/res/res/values-et/strings.xml b/core/res/res/values-et/strings.xml
index 4a42b00..f44b8a4 100644
--- a/core/res/res/values-et/strings.xml
+++ b/core/res/res/values-et/strings.xml
@@ -2359,18 +2359,11 @@
<string name="keyboard_layout_notification_more_than_three_selected_message" msgid="1581834181578206937">"Klaviatuuripaigutuseks on määratud <xliff:g id="LAYOUT_1">%1$s</xliff:g>, <xliff:g id="LAYOUT_2">%2$s</xliff:g>, <xliff:g id="LAYOUT_3">%3$s</xliff:g> … puudutage muutmiseks."</string>
<string name="keyboard_layout_notification_multiple_selected_title" msgid="5242444914367024499">"Füüsilised klaviatuurid on seadistatud"</string>
<string name="keyboard_layout_notification_multiple_selected_message" msgid="6576533454124419202">"Puudutage klaviatuuride vaatamiseks"</string>
- <!-- no translation found for profile_label_private (6463418670715290696) -->
- <skip />
- <!-- no translation found for profile_label_clone (769106052210954285) -->
- <skip />
- <!-- no translation found for profile_label_work (3495359133038584618) -->
- <skip />
- <!-- no translation found for profile_label_work_2 (4691533661598632135) -->
- <skip />
- <!-- no translation found for profile_label_work_3 (4834572253956798917) -->
- <skip />
- <!-- no translation found for profile_label_test (9168641926186071947) -->
- <skip />
- <!-- no translation found for profile_label_communal (8743921499944800427) -->
- <skip />
+ <string name="profile_label_private" msgid="6463418670715290696">"Privaatne"</string>
+ <string name="profile_label_clone" msgid="769106052210954285">"Kloon"</string>
+ <string name="profile_label_work" msgid="3495359133038584618">"Töö"</string>
+ <string name="profile_label_work_2" msgid="4691533661598632135">"Töö 2"</string>
+ <string name="profile_label_work_3" msgid="4834572253956798917">"Töö 3"</string>
+ <string name="profile_label_test" msgid="9168641926186071947">"Test"</string>
+ <string name="profile_label_communal" msgid="8743921499944800427">"Jagatud"</string>
</resources>
diff --git a/core/res/res/values-eu/strings.xml b/core/res/res/values-eu/strings.xml
index 3b76e88..8bf5d97 100644
--- a/core/res/res/values-eu/strings.xml
+++ b/core/res/res/values-eu/strings.xml
@@ -2359,18 +2359,11 @@
<string name="keyboard_layout_notification_more_than_three_selected_message" msgid="1581834181578206937">"Ezarri da <xliff:g id="LAYOUT_1">%1$s</xliff:g>, <xliff:g id="LAYOUT_2">%2$s</xliff:g> eta <xliff:g id="LAYOUT_3">%3$s</xliff:g> gisa teklatuaren diseinua… Diseinu hori aldatzeko, sakatu hau."</string>
<string name="keyboard_layout_notification_multiple_selected_title" msgid="5242444914367024499">"Konfiguratu dira teklatu fisikoak"</string>
<string name="keyboard_layout_notification_multiple_selected_message" msgid="6576533454124419202">"Sakatu hau teklatuak ikusteko"</string>
- <!-- no translation found for profile_label_private (6463418670715290696) -->
- <skip />
- <!-- no translation found for profile_label_clone (769106052210954285) -->
- <skip />
- <!-- no translation found for profile_label_work (3495359133038584618) -->
- <skip />
- <!-- no translation found for profile_label_work_2 (4691533661598632135) -->
- <skip />
- <!-- no translation found for profile_label_work_3 (4834572253956798917) -->
- <skip />
- <!-- no translation found for profile_label_test (9168641926186071947) -->
- <skip />
- <!-- no translation found for profile_label_communal (8743921499944800427) -->
- <skip />
+ <string name="profile_label_private" msgid="6463418670715290696">"Pribatua"</string>
+ <string name="profile_label_clone" msgid="769106052210954285">"Klona"</string>
+ <string name="profile_label_work" msgid="3495359133038584618">"Lanekoa"</string>
+ <string name="profile_label_work_2" msgid="4691533661598632135">"Lanekoa 2"</string>
+ <string name="profile_label_work_3" msgid="4834572253956798917">"Lanekoa 3"</string>
+ <string name="profile_label_test" msgid="9168641926186071947">"Probakoa"</string>
+ <string name="profile_label_communal" msgid="8743921499944800427">"Partekatua"</string>
</resources>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index 71dbc43..c1b67ad 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -2359,18 +2359,11 @@
<string name="keyboard_layout_notification_more_than_three_selected_message" msgid="1581834181578206937">"جانمایی صفحهکلید چنین تنظیم شد: <xliff:g id="LAYOUT_1">%1$s</xliff:g>، <xliff:g id="LAYOUT_2">%2$s</xliff:g>، <xliff:g id="LAYOUT_3">%3$s</xliff:g>… برای تغییر ضربه بزنید"</string>
<string name="keyboard_layout_notification_multiple_selected_title" msgid="5242444914367024499">"صفحهکلیدهای فیزیکی پیکربندی شدند"</string>
<string name="keyboard_layout_notification_multiple_selected_message" msgid="6576533454124419202">"برای مشاهده صفحهکلیدها ضربه بزنید"</string>
- <!-- no translation found for profile_label_private (6463418670715290696) -->
- <skip />
- <!-- no translation found for profile_label_clone (769106052210954285) -->
- <skip />
- <!-- no translation found for profile_label_work (3495359133038584618) -->
- <skip />
- <!-- no translation found for profile_label_work_2 (4691533661598632135) -->
- <skip />
- <!-- no translation found for profile_label_work_3 (4834572253956798917) -->
- <skip />
- <!-- no translation found for profile_label_test (9168641926186071947) -->
- <skip />
- <!-- no translation found for profile_label_communal (8743921499944800427) -->
- <skip />
+ <string name="profile_label_private" msgid="6463418670715290696">"خصوصی"</string>
+ <string name="profile_label_clone" msgid="769106052210954285">"مشابهسازی"</string>
+ <string name="profile_label_work" msgid="3495359133038584618">"کار"</string>
+ <string name="profile_label_work_2" msgid="4691533661598632135">"کار ۲"</string>
+ <string name="profile_label_work_3" msgid="4834572253956798917">"کار ۳"</string>
+ <string name="profile_label_test" msgid="9168641926186071947">"آزمایش"</string>
+ <string name="profile_label_communal" msgid="8743921499944800427">"عمومی"</string>
</resources>
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index c69bafe..8c64345 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -2359,18 +2359,11 @@
<string name="keyboard_layout_notification_more_than_three_selected_message" msgid="1581834181578206937">"Näppäimistöasetteluksi valittu <xliff:g id="LAYOUT_1">%1$s</xliff:g>, <xliff:g id="LAYOUT_2">%2$s</xliff:g>, <xliff:g id="LAYOUT_3">%3$s</xliff:g>… Muuta asetuksia napauttamalla."</string>
<string name="keyboard_layout_notification_multiple_selected_title" msgid="5242444914367024499">"Fyysiset näppäimistöt määritetty"</string>
<string name="keyboard_layout_notification_multiple_selected_message" msgid="6576533454124419202">"Katso näppäimistöt napauttamalla"</string>
- <!-- no translation found for profile_label_private (6463418670715290696) -->
- <skip />
- <!-- no translation found for profile_label_clone (769106052210954285) -->
- <skip />
- <!-- no translation found for profile_label_work (3495359133038584618) -->
- <skip />
- <!-- no translation found for profile_label_work_2 (4691533661598632135) -->
- <skip />
- <!-- no translation found for profile_label_work_3 (4834572253956798917) -->
- <skip />
- <!-- no translation found for profile_label_test (9168641926186071947) -->
- <skip />
- <!-- no translation found for profile_label_communal (8743921499944800427) -->
- <skip />
+ <string name="profile_label_private" msgid="6463418670715290696">"Yksityinen"</string>
+ <string name="profile_label_clone" msgid="769106052210954285">"Kloonaus"</string>
+ <string name="profile_label_work" msgid="3495359133038584618">"Työ"</string>
+ <string name="profile_label_work_2" msgid="4691533661598632135">"Työ 2"</string>
+ <string name="profile_label_work_3" msgid="4834572253956798917">"Työ 3"</string>
+ <string name="profile_label_test" msgid="9168641926186071947">"Testi"</string>
+ <string name="profile_label_communal" msgid="8743921499944800427">"Jaettu"</string>
</resources>
diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml
index 6c88f45..177fd13 100644
--- a/core/res/res/values-fr-rCA/strings.xml
+++ b/core/res/res/values-fr-rCA/strings.xml
@@ -2360,18 +2360,11 @@
<string name="keyboard_layout_notification_more_than_three_selected_message" msgid="1581834181578206937">"Disposition du clavier définie à <xliff:g id="LAYOUT_1">%1$s</xliff:g>, <xliff:g id="LAYOUT_2">%2$s</xliff:g>, <xliff:g id="LAYOUT_3">%3$s</xliff:g>… Touchez pour modifier."</string>
<string name="keyboard_layout_notification_multiple_selected_title" msgid="5242444914367024499">"Claviers physiques configurés"</string>
<string name="keyboard_layout_notification_multiple_selected_message" msgid="6576533454124419202">"Touchez pour afficher les claviers"</string>
- <!-- no translation found for profile_label_private (6463418670715290696) -->
- <skip />
- <!-- no translation found for profile_label_clone (769106052210954285) -->
- <skip />
- <!-- no translation found for profile_label_work (3495359133038584618) -->
- <skip />
- <!-- no translation found for profile_label_work_2 (4691533661598632135) -->
- <skip />
- <!-- no translation found for profile_label_work_3 (4834572253956798917) -->
- <skip />
- <!-- no translation found for profile_label_test (9168641926186071947) -->
- <skip />
- <!-- no translation found for profile_label_communal (8743921499944800427) -->
- <skip />
+ <string name="profile_label_private" msgid="6463418670715290696">"Privé"</string>
+ <string name="profile_label_clone" msgid="769106052210954285">"Clone"</string>
+ <string name="profile_label_work" msgid="3495359133038584618">"Professionnel"</string>
+ <string name="profile_label_work_2" msgid="4691533661598632135">"Professionnel 2"</string>
+ <string name="profile_label_work_3" msgid="4834572253956798917">"Professionnel 3"</string>
+ <string name="profile_label_test" msgid="9168641926186071947">"Test"</string>
+ <string name="profile_label_communal" msgid="8743921499944800427">"Commun"</string>
</resources>
diff --git a/core/res/res/values-gl/strings.xml b/core/res/res/values-gl/strings.xml
index c1e2bbf..6600c29 100644
--- a/core/res/res/values-gl/strings.xml
+++ b/core/res/res/values-gl/strings.xml
@@ -2359,18 +2359,11 @@
<string name="keyboard_layout_notification_more_than_three_selected_message" msgid="1581834181578206937">"O deseño do teclado estableceuse en <xliff:g id="LAYOUT_1">%1$s</xliff:g>, <xliff:g id="LAYOUT_2">%2$s</xliff:g>, <xliff:g id="LAYOUT_3">%3$s</xliff:g>… Toca para cambialo."</string>
<string name="keyboard_layout_notification_multiple_selected_title" msgid="5242444914367024499">"Configuráronse varios teclados físicos"</string>
<string name="keyboard_layout_notification_multiple_selected_message" msgid="6576533454124419202">"Toca para ver os teclados"</string>
- <!-- no translation found for profile_label_private (6463418670715290696) -->
- <skip />
- <!-- no translation found for profile_label_clone (769106052210954285) -->
- <skip />
- <!-- no translation found for profile_label_work (3495359133038584618) -->
- <skip />
- <!-- no translation found for profile_label_work_2 (4691533661598632135) -->
- <skip />
- <!-- no translation found for profile_label_work_3 (4834572253956798917) -->
- <skip />
- <!-- no translation found for profile_label_test (9168641926186071947) -->
- <skip />
- <!-- no translation found for profile_label_communal (8743921499944800427) -->
- <skip />
+ <string name="profile_label_private" msgid="6463418670715290696">"Privado"</string>
+ <string name="profile_label_clone" msgid="769106052210954285">"Clonado"</string>
+ <string name="profile_label_work" msgid="3495359133038584618">"Traballo"</string>
+ <string name="profile_label_work_2" msgid="4691533661598632135">"Traballo 2"</string>
+ <string name="profile_label_work_3" msgid="4834572253956798917">"Traballo 3"</string>
+ <string name="profile_label_test" msgid="9168641926186071947">"Proba"</string>
+ <string name="profile_label_communal" msgid="8743921499944800427">"Compartido"</string>
</resources>
diff --git a/core/res/res/values-gu/strings.xml b/core/res/res/values-gu/strings.xml
index da75282..d847869 100644
--- a/core/res/res/values-gu/strings.xml
+++ b/core/res/res/values-gu/strings.xml
@@ -2359,18 +2359,11 @@
<string name="keyboard_layout_notification_more_than_three_selected_message" msgid="1581834181578206937">"કીબોર્ડનું લેઆઉટ <xliff:g id="LAYOUT_1">%1$s</xliff:g>, <xliff:g id="LAYOUT_2">%2$s</xliff:g>, <xliff:g id="LAYOUT_3">%3$s</xliff:g> પર સેટ કરવામાં આવ્યું છે… બદલવા માટે ટૅપ કરો."</string>
<string name="keyboard_layout_notification_multiple_selected_title" msgid="5242444914367024499">"ભૌતિક કીબોર્ડની ગોઠવણી કરવામાં આવી છે"</string>
<string name="keyboard_layout_notification_multiple_selected_message" msgid="6576533454124419202">"કીબોર્ડ જોવા માટે ટૅપ કરો"</string>
- <!-- no translation found for profile_label_private (6463418670715290696) -->
- <skip />
- <!-- no translation found for profile_label_clone (769106052210954285) -->
- <skip />
- <!-- no translation found for profile_label_work (3495359133038584618) -->
- <skip />
- <!-- no translation found for profile_label_work_2 (4691533661598632135) -->
- <skip />
- <!-- no translation found for profile_label_work_3 (4834572253956798917) -->
- <skip />
- <!-- no translation found for profile_label_test (9168641926186071947) -->
- <skip />
- <!-- no translation found for profile_label_communal (8743921499944800427) -->
- <skip />
+ <string name="profile_label_private" msgid="6463418670715290696">"ખાનગી"</string>
+ <string name="profile_label_clone" msgid="769106052210954285">"ક્લોન કરો"</string>
+ <string name="profile_label_work" msgid="3495359133038584618">"ઑફિસ"</string>
+ <string name="profile_label_work_2" msgid="4691533661598632135">"ઑફિસ 2"</string>
+ <string name="profile_label_work_3" msgid="4834572253956798917">"ઑફિસ 3"</string>
+ <string name="profile_label_test" msgid="9168641926186071947">"પરીક્ષણ કરો"</string>
+ <string name="profile_label_communal" msgid="8743921499944800427">"કૉમ્યુનલ"</string>
</resources>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index d448b51..aaa4c52 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -2359,18 +2359,11 @@
<string name="keyboard_layout_notification_more_than_three_selected_message" msgid="1581834181578206937">"कीबोर्ड का लेआउट <xliff:g id="LAYOUT_1">%1$s</xliff:g>, <xliff:g id="LAYOUT_2">%2$s</xliff:g>, <xliff:g id="LAYOUT_3">%3$s</xliff:g>… पर सेट कर दिया गया है. इसे बदलने के लिए टैप करें."</string>
<string name="keyboard_layout_notification_multiple_selected_title" msgid="5242444914367024499">"फ़िज़िकल कीबोर्ड कॉन्फ़िगर किए गए"</string>
<string name="keyboard_layout_notification_multiple_selected_message" msgid="6576533454124419202">"कीबोर्ड देखने के लिए टैप करें"</string>
- <!-- no translation found for profile_label_private (6463418670715290696) -->
- <skip />
- <!-- no translation found for profile_label_clone (769106052210954285) -->
- <skip />
- <!-- no translation found for profile_label_work (3495359133038584618) -->
- <skip />
- <!-- no translation found for profile_label_work_2 (4691533661598632135) -->
- <skip />
- <!-- no translation found for profile_label_work_3 (4834572253956798917) -->
- <skip />
- <!-- no translation found for profile_label_test (9168641926186071947) -->
- <skip />
- <!-- no translation found for profile_label_communal (8743921499944800427) -->
- <skip />
+ <string name="profile_label_private" msgid="6463418670715290696">"निजी"</string>
+ <string name="profile_label_clone" msgid="769106052210954285">"क्लोन"</string>
+ <string name="profile_label_work" msgid="3495359133038584618">"ऑफ़िस"</string>
+ <string name="profile_label_work_2" msgid="4691533661598632135">"ऑफ़िस 2"</string>
+ <string name="profile_label_work_3" msgid="4834572253956798917">"ऑफ़िस 3"</string>
+ <string name="profile_label_test" msgid="9168641926186071947">"टेस्ट"</string>
+ <string name="profile_label_communal" msgid="8743921499944800427">"कम्यूनिटी"</string>
</resources>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index 5ee1527..0e82b26 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -2360,18 +2360,11 @@
<string name="keyboard_layout_notification_more_than_three_selected_message" msgid="1581834181578206937">"Raspored tipkovnice postavljen je na <xliff:g id="LAYOUT_1">%1$s</xliff:g>, <xliff:g id="LAYOUT_2">%2$s</xliff:g>, <xliff:g id="LAYOUT_3">%3$s</xliff:g>… Dodirnite da biste ga promijenili."</string>
<string name="keyboard_layout_notification_multiple_selected_title" msgid="5242444914367024499">"Fizičke su tipkovnice konfigurirane"</string>
<string name="keyboard_layout_notification_multiple_selected_message" msgid="6576533454124419202">"Dodirnite da bi se prikazale tipkovnice"</string>
- <!-- no translation found for profile_label_private (6463418670715290696) -->
- <skip />
- <!-- no translation found for profile_label_clone (769106052210954285) -->
- <skip />
- <!-- no translation found for profile_label_work (3495359133038584618) -->
- <skip />
- <!-- no translation found for profile_label_work_2 (4691533661598632135) -->
- <skip />
- <!-- no translation found for profile_label_work_3 (4834572253956798917) -->
- <skip />
- <!-- no translation found for profile_label_test (9168641926186071947) -->
- <skip />
- <!-- no translation found for profile_label_communal (8743921499944800427) -->
- <skip />
+ <string name="profile_label_private" msgid="6463418670715290696">"Privatno"</string>
+ <string name="profile_label_clone" msgid="769106052210954285">"Kloniranje"</string>
+ <string name="profile_label_work" msgid="3495359133038584618">"Posao"</string>
+ <string name="profile_label_work_2" msgid="4691533661598632135">"Posao 2"</string>
+ <string name="profile_label_work_3" msgid="4834572253956798917">"Posao 3"</string>
+ <string name="profile_label_test" msgid="9168641926186071947">"Test"</string>
+ <string name="profile_label_communal" msgid="8743921499944800427">"Zajedničko"</string>
</resources>
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index 2c4c77e..f223650 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -2359,18 +2359,11 @@
<string name="keyboard_layout_notification_more_than_three_selected_message" msgid="1581834181578206937">"A billentyűzetkiosztás a következőkre van beállítva: <xliff:g id="LAYOUT_1">%1$s</xliff:g>, <xliff:g id="LAYOUT_2">%2$s</xliff:g>, <xliff:g id="LAYOUT_3">%3$s</xliff:g>… A módosításhoz koppintson."</string>
<string name="keyboard_layout_notification_multiple_selected_title" msgid="5242444914367024499">"Fizikai billentyűzetek beállítva"</string>
<string name="keyboard_layout_notification_multiple_selected_message" msgid="6576533454124419202">"Koppintson a billentyűzetek megtekintéséhez"</string>
- <!-- no translation found for profile_label_private (6463418670715290696) -->
- <skip />
- <!-- no translation found for profile_label_clone (769106052210954285) -->
- <skip />
- <!-- no translation found for profile_label_work (3495359133038584618) -->
- <skip />
- <!-- no translation found for profile_label_work_2 (4691533661598632135) -->
- <skip />
- <!-- no translation found for profile_label_work_3 (4834572253956798917) -->
- <skip />
- <!-- no translation found for profile_label_test (9168641926186071947) -->
- <skip />
- <!-- no translation found for profile_label_communal (8743921499944800427) -->
- <skip />
+ <string name="profile_label_private" msgid="6463418670715290696">"Privát"</string>
+ <string name="profile_label_clone" msgid="769106052210954285">"Klón"</string>
+ <string name="profile_label_work" msgid="3495359133038584618">"Munkahelyi"</string>
+ <string name="profile_label_work_2" msgid="4691533661598632135">"2. munkahelyi"</string>
+ <string name="profile_label_work_3" msgid="4834572253956798917">"3. munkahelyi"</string>
+ <string name="profile_label_test" msgid="9168641926186071947">"Teszt"</string>
+ <string name="profile_label_communal" msgid="8743921499944800427">"Közös"</string>
</resources>
diff --git a/core/res/res/values-hy/strings.xml b/core/res/res/values-hy/strings.xml
index 482e075..ca227df 100644
--- a/core/res/res/values-hy/strings.xml
+++ b/core/res/res/values-hy/strings.xml
@@ -2359,18 +2359,11 @@
<string name="keyboard_layout_notification_more_than_three_selected_message" msgid="1581834181578206937">"Ստեղնաշարի համար կարգավորված են <xliff:g id="LAYOUT_1">%1$s</xliff:g>, <xliff:g id="LAYOUT_2">%2$s</xliff:g>, <xliff:g id="LAYOUT_3">%3$s</xliff:g> դասավորությունները։ Հպեք փոխելու համար։"</string>
<string name="keyboard_layout_notification_multiple_selected_title" msgid="5242444914367024499">"Ֆիզիկական ստեղնաշարերը կարգավորված են"</string>
<string name="keyboard_layout_notification_multiple_selected_message" msgid="6576533454124419202">"Հպեք՝ ստեղնաշարերը դիտելու համար"</string>
- <!-- no translation found for profile_label_private (6463418670715290696) -->
- <skip />
- <!-- no translation found for profile_label_clone (769106052210954285) -->
- <skip />
- <!-- no translation found for profile_label_work (3495359133038584618) -->
- <skip />
- <!-- no translation found for profile_label_work_2 (4691533661598632135) -->
- <skip />
- <!-- no translation found for profile_label_work_3 (4834572253956798917) -->
- <skip />
- <!-- no translation found for profile_label_test (9168641926186071947) -->
- <skip />
- <!-- no translation found for profile_label_communal (8743921499944800427) -->
- <skip />
+ <string name="profile_label_private" msgid="6463418670715290696">"Անձնական"</string>
+ <string name="profile_label_clone" msgid="769106052210954285">"Կլոն"</string>
+ <string name="profile_label_work" msgid="3495359133038584618">"Աշխատանքային"</string>
+ <string name="profile_label_work_2" msgid="4691533661598632135">"Աշխատանքային 2"</string>
+ <string name="profile_label_work_3" msgid="4834572253956798917">"Աշխատանքային 3"</string>
+ <string name="profile_label_test" msgid="9168641926186071947">"Փորձնական"</string>
+ <string name="profile_label_communal" msgid="8743921499944800427">"Ընդհանուր"</string>
</resources>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index f18d834..86a0858 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -2359,18 +2359,11 @@
<string name="keyboard_layout_notification_more_than_three_selected_message" msgid="1581834181578206937">"Tata letak keyboard disetel ke <xliff:g id="LAYOUT_1">%1$s</xliff:g>, <xliff:g id="LAYOUT_2">%2$s</xliff:g>, <xliff:g id="LAYOUT_3">%3$s</xliff:g>… Ketuk untuk mengubah."</string>
<string name="keyboard_layout_notification_multiple_selected_title" msgid="5242444914367024499">"Keyboard fisik telah dikonfigurasi"</string>
<string name="keyboard_layout_notification_multiple_selected_message" msgid="6576533454124419202">"Ketuk untuk melihat keyboard"</string>
- <!-- no translation found for profile_label_private (6463418670715290696) -->
- <skip />
- <!-- no translation found for profile_label_clone (769106052210954285) -->
- <skip />
- <!-- no translation found for profile_label_work (3495359133038584618) -->
- <skip />
- <!-- no translation found for profile_label_work_2 (4691533661598632135) -->
- <skip />
- <!-- no translation found for profile_label_work_3 (4834572253956798917) -->
- <skip />
- <!-- no translation found for profile_label_test (9168641926186071947) -->
- <skip />
- <!-- no translation found for profile_label_communal (8743921499944800427) -->
- <skip />
+ <string name="profile_label_private" msgid="6463418670715290696">"Pribadi"</string>
+ <string name="profile_label_clone" msgid="769106052210954285">"Clone"</string>
+ <string name="profile_label_work" msgid="3495359133038584618">"Kerja"</string>
+ <string name="profile_label_work_2" msgid="4691533661598632135">"Kerja 2"</string>
+ <string name="profile_label_work_3" msgid="4834572253956798917">"Kerja 3"</string>
+ <string name="profile_label_test" msgid="9168641926186071947">"Pengujian"</string>
+ <string name="profile_label_communal" msgid="8743921499944800427">"Umum"</string>
</resources>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index 076c5a3..1cc244f 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -2360,18 +2360,11 @@
<string name="keyboard_layout_notification_more_than_three_selected_message" msgid="1581834181578206937">"Layout tastiera impostato su <xliff:g id="LAYOUT_1">%1$s</xliff:g>, <xliff:g id="LAYOUT_2">%2$s</xliff:g>, <xliff:g id="LAYOUT_3">%3$s</xliff:g>… Tocca per cambiare l\'impostazione."</string>
<string name="keyboard_layout_notification_multiple_selected_title" msgid="5242444914367024499">"Tastiere fisiche configurate"</string>
<string name="keyboard_layout_notification_multiple_selected_message" msgid="6576533454124419202">"Tocca per visualizzare le tastiere"</string>
- <!-- no translation found for profile_label_private (6463418670715290696) -->
- <skip />
- <!-- no translation found for profile_label_clone (769106052210954285) -->
- <skip />
- <!-- no translation found for profile_label_work (3495359133038584618) -->
- <skip />
- <!-- no translation found for profile_label_work_2 (4691533661598632135) -->
- <skip />
- <!-- no translation found for profile_label_work_3 (4834572253956798917) -->
- <skip />
- <!-- no translation found for profile_label_test (9168641926186071947) -->
- <skip />
- <!-- no translation found for profile_label_communal (8743921499944800427) -->
- <skip />
+ <string name="profile_label_private" msgid="6463418670715290696">"Privato"</string>
+ <string name="profile_label_clone" msgid="769106052210954285">"Clone"</string>
+ <string name="profile_label_work" msgid="3495359133038584618">"Lavoro"</string>
+ <string name="profile_label_work_2" msgid="4691533661598632135">"Lavoro 2"</string>
+ <string name="profile_label_work_3" msgid="4834572253956798917">"Lavoro 3"</string>
+ <string name="profile_label_test" msgid="9168641926186071947">"Test"</string>
+ <string name="profile_label_communal" msgid="8743921499944800427">"Condiviso"</string>
</resources>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index 8931518..390f6f1 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -2359,18 +2359,11 @@
<string name="keyboard_layout_notification_more_than_three_selected_message" msgid="1581834181578206937">"キーボードのレイアウトは<xliff:g id="LAYOUT_1">%1$s</xliff:g>、<xliff:g id="LAYOUT_2">%2$s</xliff:g>、<xliff:g id="LAYOUT_3">%3$s</xliff:g>などに設定されています。タップで変更できます。"</string>
<string name="keyboard_layout_notification_multiple_selected_title" msgid="5242444914367024499">"物理キーボードの設定完了"</string>
<string name="keyboard_layout_notification_multiple_selected_message" msgid="6576533454124419202">"タップするとキーボードを表示できます"</string>
- <!-- no translation found for profile_label_private (6463418670715290696) -->
- <skip />
- <!-- no translation found for profile_label_clone (769106052210954285) -->
- <skip />
- <!-- no translation found for profile_label_work (3495359133038584618) -->
- <skip />
- <!-- no translation found for profile_label_work_2 (4691533661598632135) -->
- <skip />
- <!-- no translation found for profile_label_work_3 (4834572253956798917) -->
- <skip />
- <!-- no translation found for profile_label_test (9168641926186071947) -->
- <skip />
- <!-- no translation found for profile_label_communal (8743921499944800427) -->
- <skip />
+ <string name="profile_label_private" msgid="6463418670715290696">"非公開"</string>
+ <string name="profile_label_clone" msgid="769106052210954285">"複製"</string>
+ <string name="profile_label_work" msgid="3495359133038584618">"仕事用"</string>
+ <string name="profile_label_work_2" msgid="4691533661598632135">"仕事用 2"</string>
+ <string name="profile_label_work_3" msgid="4834572253956798917">"仕事用 3"</string>
+ <string name="profile_label_test" msgid="9168641926186071947">"テスト"</string>
+ <string name="profile_label_communal" msgid="8743921499944800427">"共用"</string>
</resources>
diff --git a/core/res/res/values-kk/strings.xml b/core/res/res/values-kk/strings.xml
index 3e33115..8eab926 100644
--- a/core/res/res/values-kk/strings.xml
+++ b/core/res/res/values-kk/strings.xml
@@ -2329,13 +2329,13 @@
<string name="system_locale_title" msgid="711882686834677268">"Жүйенің әдепкі параметрі"</string>
<string name="default_card_name" msgid="9198284935962911468">"<xliff:g id="CARDNUMBER">%d</xliff:g>-КАРТА"</string>
<string name="permlab_companionProfileWatch" msgid="2457738382085872542">"Сағаттарды басқаруға арналған қосымша сағат профилінің рұқсаты"</string>
- <string name="permdesc_companionProfileWatch" msgid="5655698581110449397">"Қосымша қолданбаға сағаттарды басқаруға рұқсат беріледі."</string>
+ <string name="permdesc_companionProfileWatch" msgid="5655698581110449397">"Серік қолданбаға сағаттарды басқаруға рұқсат беріледі."</string>
<string name="permlab_observeCompanionDevicePresence" msgid="9008994909653990465">"Серіктес құрылғының бар-жоғын бақылау"</string>
- <string name="permdesc_observeCompanionDevicePresence" msgid="3011699826788697852">"Қосымша қолданбаға қолданбалар маңайда немесе алыста болған кезде қосымша құрылғының бар болуын бақылауға рұқсат беріледі."</string>
+ <string name="permdesc_observeCompanionDevicePresence" msgid="3011699826788697852">"Серік қолданбаға құрылғылар маңайда немесе алыста болуына қарамастан серік құрылғыны табуға рұқсат беріледі."</string>
<string name="permlab_deliverCompanionMessages" msgid="3931552294842980887">"Ілеспе хабарлар жеткізу"</string>
- <string name="permdesc_deliverCompanionMessages" msgid="2170847384281412850">"Қосымша қолданбаға ілеспе хабарларды басқа құрылғыларға жеткізуге рұқсат беріледі."</string>
+ <string name="permdesc_deliverCompanionMessages" msgid="2170847384281412850">"Серік қолданбаға басқа құрылғыларға серік хабарлар жеткізуге рұқсат беріледі."</string>
<string name="permlab_startForegroundServicesFromBackground" msgid="6363004936218638382">"Экрандық режимдегі қызметтерді фоннан іске қосу"</string>
- <string name="permdesc_startForegroundServicesFromBackground" msgid="4071826571656001537">"Қосымша қолданбаға экрандық режимдегі қызметтерді фоннан іске қосуға рұқсат беріледі."</string>
+ <string name="permdesc_startForegroundServicesFromBackground" msgid="4071826571656001537">"Серік қолданбаға экрандық режимдегі қызметтерді фоннан іске қосуға рұқсат беріледі."</string>
<string name="mic_access_on_toast" msgid="2666925317663845156">"Микрофон қолжетімді."</string>
<string name="mic_access_off_toast" msgid="8111040892954242437">"Микрофон блокталған."</string>
<string name="connected_display_unavailable_notification_title" msgid="5265409360902073556">"Дисплейге көшірмені көрсету мүмкін емес"</string>
@@ -2359,18 +2359,11 @@
<string name="keyboard_layout_notification_more_than_three_selected_message" msgid="1581834181578206937">"Пернетақта схемасы \"<xliff:g id="LAYOUT_1">%1$s</xliff:g>\", \"<xliff:g id="LAYOUT_2">%2$s</xliff:g>\", \"<xliff:g id="LAYOUT_3">%3$s</xliff:g>\" деп орнатылды… Өзгерту үшін түртіңіз."</string>
<string name="keyboard_layout_notification_multiple_selected_title" msgid="5242444914367024499">"Физикалық пернетақталар конфигурацияланды"</string>
<string name="keyboard_layout_notification_multiple_selected_message" msgid="6576533454124419202">"Пернетақталарды көру үшін түртіңіз."</string>
- <!-- no translation found for profile_label_private (6463418670715290696) -->
- <skip />
- <!-- no translation found for profile_label_clone (769106052210954285) -->
- <skip />
- <!-- no translation found for profile_label_work (3495359133038584618) -->
- <skip />
- <!-- no translation found for profile_label_work_2 (4691533661598632135) -->
- <skip />
- <!-- no translation found for profile_label_work_3 (4834572253956798917) -->
- <skip />
- <!-- no translation found for profile_label_test (9168641926186071947) -->
- <skip />
- <!-- no translation found for profile_label_communal (8743921499944800427) -->
- <skip />
+ <string name="profile_label_private" msgid="6463418670715290696">"Жеке"</string>
+ <string name="profile_label_clone" msgid="769106052210954285">"Клон"</string>
+ <string name="profile_label_work" msgid="3495359133038584618">"Жұмыс"</string>
+ <string name="profile_label_work_2" msgid="4691533661598632135">"Жұмыс 2"</string>
+ <string name="profile_label_work_3" msgid="4834572253956798917">"Жұмыс 3"</string>
+ <string name="profile_label_test" msgid="9168641926186071947">"Сынақ"</string>
+ <string name="profile_label_communal" msgid="8743921499944800427">"Жалпы"</string>
</resources>
diff --git a/core/res/res/values-km/strings.xml b/core/res/res/values-km/strings.xml
index 0bcf992..c677a3d 100644
--- a/core/res/res/values-km/strings.xml
+++ b/core/res/res/values-km/strings.xml
@@ -2359,18 +2359,11 @@
<string name="keyboard_layout_notification_more_than_three_selected_message" msgid="1581834181578206937">"បានកំណត់ប្លង់ក្ដារចុចទៅ <xliff:g id="LAYOUT_1">%1$s</xliff:g>, <xliff:g id="LAYOUT_2">%2$s</xliff:g>, <xliff:g id="LAYOUT_3">%3$s</xliff:g>… សូមចុចដើម្បីប្ដូរ។"</string>
<string name="keyboard_layout_notification_multiple_selected_title" msgid="5242444914367024499">"បានកំណត់រចនាសម្ព័ន្ធក្ដារចុចរូបវន្ត"</string>
<string name="keyboard_layout_notification_multiple_selected_message" msgid="6576533454124419202">"ចុចដើម្បីមើលក្ដារចុច"</string>
- <!-- no translation found for profile_label_private (6463418670715290696) -->
- <skip />
- <!-- no translation found for profile_label_clone (769106052210954285) -->
- <skip />
- <!-- no translation found for profile_label_work (3495359133038584618) -->
- <skip />
- <!-- no translation found for profile_label_work_2 (4691533661598632135) -->
- <skip />
- <!-- no translation found for profile_label_work_3 (4834572253956798917) -->
- <skip />
- <!-- no translation found for profile_label_test (9168641926186071947) -->
- <skip />
- <!-- no translation found for profile_label_communal (8743921499944800427) -->
- <skip />
+ <string name="profile_label_private" msgid="6463418670715290696">"ឯកជន"</string>
+ <string name="profile_label_clone" msgid="769106052210954285">"ក្លូន"</string>
+ <string name="profile_label_work" msgid="3495359133038584618">"ការងារ"</string>
+ <string name="profile_label_work_2" msgid="4691533661598632135">"ការងារទី 2"</string>
+ <string name="profile_label_work_3" msgid="4834572253956798917">"ការងារទី 3"</string>
+ <string name="profile_label_test" msgid="9168641926186071947">"ការធ្វើតេស្ត"</string>
+ <string name="profile_label_communal" msgid="8743921499944800427">"ទូទៅ"</string>
</resources>
diff --git a/core/res/res/values-kn/strings.xml b/core/res/res/values-kn/strings.xml
index a69601a..bb99b5d 100644
--- a/core/res/res/values-kn/strings.xml
+++ b/core/res/res/values-kn/strings.xml
@@ -2359,18 +2359,11 @@
<string name="keyboard_layout_notification_more_than_three_selected_message" msgid="1581834181578206937">"ಕೀಬೋರ್ಡ್ ಲೇಔಟ್ ಅನ್ನು <xliff:g id="LAYOUT_1">%1$s</xliff:g>, <xliff:g id="LAYOUT_2">%2$s</xliff:g>, <xliff:g id="LAYOUT_3">%3$s</xliff:g> ಗೆ ಸೆಟ್ ಮಾಡಲಾಗಿದೆ… ಬದಲಾಯಿಸಲು ಟ್ಯಾಪ್ ಮಾಡಿ."</string>
<string name="keyboard_layout_notification_multiple_selected_title" msgid="5242444914367024499">"ಭೌತಿಕ ಕೀಬೋರ್ಡ್ಗಳನ್ನು ಕಾನ್ಫಿಗರ್ ಮಾಡಲಾಗಿದೆ"</string>
<string name="keyboard_layout_notification_multiple_selected_message" msgid="6576533454124419202">"ಕೀಬೋರ್ಡ್ಗಳನ್ನು ವೀಕ್ಷಿಸಲು ಟ್ಯಾಪ್ ಮಾಡಿ"</string>
- <!-- no translation found for profile_label_private (6463418670715290696) -->
- <skip />
- <!-- no translation found for profile_label_clone (769106052210954285) -->
- <skip />
- <!-- no translation found for profile_label_work (3495359133038584618) -->
- <skip />
- <!-- no translation found for profile_label_work_2 (4691533661598632135) -->
- <skip />
- <!-- no translation found for profile_label_work_3 (4834572253956798917) -->
- <skip />
- <!-- no translation found for profile_label_test (9168641926186071947) -->
- <skip />
- <!-- no translation found for profile_label_communal (8743921499944800427) -->
- <skip />
+ <string name="profile_label_private" msgid="6463418670715290696">"ಖಾಸಗಿ"</string>
+ <string name="profile_label_clone" msgid="769106052210954285">"ಕ್ಲೋನ್"</string>
+ <string name="profile_label_work" msgid="3495359133038584618">"ಕೆಲಸ"</string>
+ <string name="profile_label_work_2" msgid="4691533661598632135">"ಕೆಲಸ 2"</string>
+ <string name="profile_label_work_3" msgid="4834572253956798917">"ಕೆಲಸ 3"</string>
+ <string name="profile_label_test" msgid="9168641926186071947">"ಪರೀಕ್ಷೆ"</string>
+ <string name="profile_label_communal" msgid="8743921499944800427">"ಸಮುದಾಯ"</string>
</resources>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index 77d45c7..82a3b26 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -2359,18 +2359,11 @@
<string name="keyboard_layout_notification_more_than_three_selected_message" msgid="1581834181578206937">"키보드 레이아웃이 <xliff:g id="LAYOUT_1">%1$s</xliff:g>, <xliff:g id="LAYOUT_2">%2$s</xliff:g>, <xliff:g id="LAYOUT_3">%3$s</xliff:g>로 설정됩니다. 변경하려면 탭하세요."</string>
<string name="keyboard_layout_notification_multiple_selected_title" msgid="5242444914367024499">"실제 키보드에 구성됨"</string>
<string name="keyboard_layout_notification_multiple_selected_message" msgid="6576533454124419202">"키보드를 보려면 탭하세요."</string>
- <!-- no translation found for profile_label_private (6463418670715290696) -->
- <skip />
- <!-- no translation found for profile_label_clone (769106052210954285) -->
- <skip />
- <!-- no translation found for profile_label_work (3495359133038584618) -->
- <skip />
- <!-- no translation found for profile_label_work_2 (4691533661598632135) -->
- <skip />
- <!-- no translation found for profile_label_work_3 (4834572253956798917) -->
- <skip />
- <!-- no translation found for profile_label_test (9168641926186071947) -->
- <skip />
- <!-- no translation found for profile_label_communal (8743921499944800427) -->
- <skip />
+ <string name="profile_label_private" msgid="6463418670715290696">"비공개"</string>
+ <string name="profile_label_clone" msgid="769106052210954285">"복사"</string>
+ <string name="profile_label_work" msgid="3495359133038584618">"직장"</string>
+ <string name="profile_label_work_2" msgid="4691533661598632135">"직장 2"</string>
+ <string name="profile_label_work_3" msgid="4834572253956798917">"직장 3"</string>
+ <string name="profile_label_test" msgid="9168641926186071947">"테스트"</string>
+ <string name="profile_label_communal" msgid="8743921499944800427">"공동"</string>
</resources>
diff --git a/core/res/res/values-ky/strings.xml b/core/res/res/values-ky/strings.xml
index ee7b407..11950aa2 100644
--- a/core/res/res/values-ky/strings.xml
+++ b/core/res/res/values-ky/strings.xml
@@ -2359,18 +2359,11 @@
<string name="keyboard_layout_notification_more_than_three_selected_message" msgid="1581834181578206937">"Баскычтопко төмөнкү калып коюлду: <xliff:g id="LAYOUT_1">%1$s</xliff:g>, <xliff:g id="LAYOUT_2">%2$s</xliff:g>, <xliff:g id="LAYOUT_3">%3$s</xliff:g>… Өзгөртүү үчүн басыңыз."</string>
<string name="keyboard_layout_notification_multiple_selected_title" msgid="5242444914367024499">"Физикалык баскычтоптор конфигурацияланды"</string>
<string name="keyboard_layout_notification_multiple_selected_message" msgid="6576533454124419202">"Баскычтопторду көрүү үчүн басыңыз"</string>
- <!-- no translation found for profile_label_private (6463418670715290696) -->
- <skip />
- <!-- no translation found for profile_label_clone (769106052210954285) -->
- <skip />
- <!-- no translation found for profile_label_work (3495359133038584618) -->
- <skip />
- <!-- no translation found for profile_label_work_2 (4691533661598632135) -->
- <skip />
- <!-- no translation found for profile_label_work_3 (4834572253956798917) -->
- <skip />
- <!-- no translation found for profile_label_test (9168641926186071947) -->
- <skip />
- <!-- no translation found for profile_label_communal (8743921499944800427) -->
- <skip />
+ <string name="profile_label_private" msgid="6463418670715290696">"Купуя"</string>
+ <string name="profile_label_clone" msgid="769106052210954285">"Клон"</string>
+ <string name="profile_label_work" msgid="3495359133038584618">"Жумуш"</string>
+ <string name="profile_label_work_2" msgid="4691533661598632135">"Жумуш 2"</string>
+ <string name="profile_label_work_3" msgid="4834572253956798917">"Жумуш 3"</string>
+ <string name="profile_label_test" msgid="9168641926186071947">"Сыноо"</string>
+ <string name="profile_label_communal" msgid="8743921499944800427">"Жалпы"</string>
</resources>
diff --git a/core/res/res/values-lo/strings.xml b/core/res/res/values-lo/strings.xml
index d9698e3..3e887a5 100644
--- a/core/res/res/values-lo/strings.xml
+++ b/core/res/res/values-lo/strings.xml
@@ -2359,18 +2359,11 @@
<string name="keyboard_layout_notification_more_than_three_selected_message" msgid="1581834181578206937">"ຕັ້ງໂຄງຮ່າງແປ້ນພິມເປັນ <xliff:g id="LAYOUT_1">%1$s</xliff:g>, <xliff:g id="LAYOUT_2">%2$s</xliff:g>, <xliff:g id="LAYOUT_3">%3$s</xliff:g>… ແຕະເພື່ອປ່ຽນແປງ."</string>
<string name="keyboard_layout_notification_multiple_selected_title" msgid="5242444914367024499">"ຕັ້ງຄ່າແປ້ນພິມແທ້ແລ້ວ"</string>
<string name="keyboard_layout_notification_multiple_selected_message" msgid="6576533454124419202">"ແຕະເພື່ອເບິ່ງແປ້ນພິມ"</string>
- <!-- no translation found for profile_label_private (6463418670715290696) -->
- <skip />
- <!-- no translation found for profile_label_clone (769106052210954285) -->
- <skip />
- <!-- no translation found for profile_label_work (3495359133038584618) -->
- <skip />
- <!-- no translation found for profile_label_work_2 (4691533661598632135) -->
- <skip />
- <!-- no translation found for profile_label_work_3 (4834572253956798917) -->
- <skip />
- <!-- no translation found for profile_label_test (9168641926186071947) -->
- <skip />
- <!-- no translation found for profile_label_communal (8743921499944800427) -->
- <skip />
+ <string name="profile_label_private" msgid="6463418670715290696">"ສ່ວນຕົວ"</string>
+ <string name="profile_label_clone" msgid="769106052210954285">"ໂຄລນ"</string>
+ <string name="profile_label_work" msgid="3495359133038584618">"ວຽກ"</string>
+ <string name="profile_label_work_2" msgid="4691533661598632135">"ວຽກ 2"</string>
+ <string name="profile_label_work_3" msgid="4834572253956798917">"ວຽກ 3"</string>
+ <string name="profile_label_test" msgid="9168641926186071947">"ທົດສອບ"</string>
+ <string name="profile_label_communal" msgid="8743921499944800427">"ສ່ວນກາງ"</string>
</resources>
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index 2a2a088..c77f785 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -2361,18 +2361,11 @@
<string name="keyboard_layout_notification_more_than_three_selected_message" msgid="1581834181578206937">"Išdėstymas nustatytas į <xliff:g id="LAYOUT_1">%1$s</xliff:g>, <xliff:g id="LAYOUT_2">%2$s</xliff:g>, <xliff:g id="LAYOUT_3">%3$s</xliff:g>… Palieskite, kad pakeistumėte."</string>
<string name="keyboard_layout_notification_multiple_selected_title" msgid="5242444914367024499">"Sukonfigūruotos fizinės klaviatūros"</string>
<string name="keyboard_layout_notification_multiple_selected_message" msgid="6576533454124419202">"Palieskite, kad peržiūrėtumėte klaviatūras"</string>
- <!-- no translation found for profile_label_private (6463418670715290696) -->
- <skip />
- <!-- no translation found for profile_label_clone (769106052210954285) -->
- <skip />
- <!-- no translation found for profile_label_work (3495359133038584618) -->
- <skip />
- <!-- no translation found for profile_label_work_2 (4691533661598632135) -->
- <skip />
- <!-- no translation found for profile_label_work_3 (4834572253956798917) -->
- <skip />
- <!-- no translation found for profile_label_test (9168641926186071947) -->
- <skip />
- <!-- no translation found for profile_label_communal (8743921499944800427) -->
- <skip />
+ <string name="profile_label_private" msgid="6463418670715290696">"Privatu"</string>
+ <string name="profile_label_clone" msgid="769106052210954285">"Identiška kopija"</string>
+ <string name="profile_label_work" msgid="3495359133038584618">"Darbas"</string>
+ <string name="profile_label_work_2" msgid="4691533661598632135">"Darbas (2)"</string>
+ <string name="profile_label_work_3" msgid="4834572253956798917">"Darbas (3)"</string>
+ <string name="profile_label_test" msgid="9168641926186071947">"Bandymas"</string>
+ <string name="profile_label_communal" msgid="8743921499944800427">"Bendruomenės"</string>
</resources>
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index 8c7c206..f443d8e 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -2360,18 +2360,11 @@
<string name="keyboard_layout_notification_more_than_three_selected_message" msgid="1581834181578206937">"Ir iestatīti šādi tastatūras izkārtojumi: <xliff:g id="LAYOUT_1">%1$s</xliff:g>, <xliff:g id="LAYOUT_2">%2$s</xliff:g>, <xliff:g id="LAYOUT_3">%3$s</xliff:g>… Lai to mainītu, pieskarieties."</string>
<string name="keyboard_layout_notification_multiple_selected_title" msgid="5242444914367024499">"Fiziskās tastatūras ir konfigurētas"</string>
<string name="keyboard_layout_notification_multiple_selected_message" msgid="6576533454124419202">"Lai skatītu tastatūras, pieskarieties"</string>
- <!-- no translation found for profile_label_private (6463418670715290696) -->
- <skip />
- <!-- no translation found for profile_label_clone (769106052210954285) -->
- <skip />
- <!-- no translation found for profile_label_work (3495359133038584618) -->
- <skip />
- <!-- no translation found for profile_label_work_2 (4691533661598632135) -->
- <skip />
- <!-- no translation found for profile_label_work_3 (4834572253956798917) -->
- <skip />
- <!-- no translation found for profile_label_test (9168641926186071947) -->
- <skip />
- <!-- no translation found for profile_label_communal (8743921499944800427) -->
- <skip />
+ <string name="profile_label_private" msgid="6463418670715290696">"Privāts"</string>
+ <string name="profile_label_clone" msgid="769106052210954285">"Klons"</string>
+ <string name="profile_label_work" msgid="3495359133038584618">"Darbam"</string>
+ <string name="profile_label_work_2" msgid="4691533661598632135">"Darbam (2.)"</string>
+ <string name="profile_label_work_3" msgid="4834572253956798917">"Darbam (3.)"</string>
+ <string name="profile_label_test" msgid="9168641926186071947">"Testēšanai"</string>
+ <string name="profile_label_communal" msgid="8743921499944800427">"Kopīgs"</string>
</resources>
diff --git a/core/res/res/values-mk/strings.xml b/core/res/res/values-mk/strings.xml
index 4d2f72e..0c1d552 100644
--- a/core/res/res/values-mk/strings.xml
+++ b/core/res/res/values-mk/strings.xml
@@ -2359,18 +2359,11 @@
<string name="keyboard_layout_notification_more_than_three_selected_message" msgid="1581834181578206937">"Распоредот на тастатурата е поставен на <xliff:g id="LAYOUT_1">%1$s</xliff:g>, <xliff:g id="LAYOUT_2">%2$s</xliff:g>, <xliff:g id="LAYOUT_3">%3$s</xliff:g>… Допрете за да промените."</string>
<string name="keyboard_layout_notification_multiple_selected_title" msgid="5242444914367024499">"Физичките тастатури се конфигурирани"</string>
<string name="keyboard_layout_notification_multiple_selected_message" msgid="6576533454124419202">"Допрете за да ги видите тастатурите"</string>
- <!-- no translation found for profile_label_private (6463418670715290696) -->
- <skip />
- <!-- no translation found for profile_label_clone (769106052210954285) -->
- <skip />
- <!-- no translation found for profile_label_work (3495359133038584618) -->
- <skip />
- <!-- no translation found for profile_label_work_2 (4691533661598632135) -->
- <skip />
- <!-- no translation found for profile_label_work_3 (4834572253956798917) -->
- <skip />
- <!-- no translation found for profile_label_test (9168641926186071947) -->
- <skip />
- <!-- no translation found for profile_label_communal (8743921499944800427) -->
- <skip />
+ <string name="profile_label_private" msgid="6463418670715290696">"Приватен профил"</string>
+ <string name="profile_label_clone" msgid="769106052210954285">"Клониран профил"</string>
+ <string name="profile_label_work" msgid="3495359133038584618">"Работен профил"</string>
+ <string name="profile_label_work_2" msgid="4691533661598632135">"Работен профил 2"</string>
+ <string name="profile_label_work_3" msgid="4834572253956798917">"Работен профил 3"</string>
+ <string name="profile_label_test" msgid="9168641926186071947">"Профил за тестирање"</string>
+ <string name="profile_label_communal" msgid="8743921499944800427">"Профил на заедницата"</string>
</resources>
diff --git a/core/res/res/values-ml/strings.xml b/core/res/res/values-ml/strings.xml
index be40575..18eb4a9 100644
--- a/core/res/res/values-ml/strings.xml
+++ b/core/res/res/values-ml/strings.xml
@@ -2359,18 +2359,11 @@
<string name="keyboard_layout_notification_more_than_three_selected_message" msgid="1581834181578206937">"കീബോർഡ് ലേഔട്ട് ആയി ഇനിപ്പറയുന്നവ സജ്ജീകരിച്ചു: <xliff:g id="LAYOUT_1">%1$s</xliff:g>, <xliff:g id="LAYOUT_2">%2$s</xliff:g>, <xliff:g id="LAYOUT_3">%3$s</xliff:g>… മാറ്റാൻ ടാപ്പ് ചെയ്യുക."</string>
<string name="keyboard_layout_notification_multiple_selected_title" msgid="5242444914367024499">"യഥാർത്ഥ കീബോർഡുകൾ കോൺഫിഗർ ചെയ്തു"</string>
<string name="keyboard_layout_notification_multiple_selected_message" msgid="6576533454124419202">"കീബോർഡുകൾ കാണാൻ ടാപ്പ് ചെയ്യുക"</string>
- <!-- no translation found for profile_label_private (6463418670715290696) -->
- <skip />
- <!-- no translation found for profile_label_clone (769106052210954285) -->
- <skip />
- <!-- no translation found for profile_label_work (3495359133038584618) -->
- <skip />
- <!-- no translation found for profile_label_work_2 (4691533661598632135) -->
- <skip />
- <!-- no translation found for profile_label_work_3 (4834572253956798917) -->
- <skip />
- <!-- no translation found for profile_label_test (9168641926186071947) -->
- <skip />
- <!-- no translation found for profile_label_communal (8743921499944800427) -->
- <skip />
+ <string name="profile_label_private" msgid="6463418670715290696">"സ്വകാര്യം"</string>
+ <string name="profile_label_clone" msgid="769106052210954285">"ക്ലോൺ ചെയ്യുക"</string>
+ <string name="profile_label_work" msgid="3495359133038584618">"ഔദ്യോഗികം"</string>
+ <string name="profile_label_work_2" msgid="4691533661598632135">"ഔദ്യോഗികം 2"</string>
+ <string name="profile_label_work_3" msgid="4834572253956798917">"ഔദ്യോഗികം 3"</string>
+ <string name="profile_label_test" msgid="9168641926186071947">"ടെസ്റ്റ്"</string>
+ <string name="profile_label_communal" msgid="8743921499944800427">"കമ്മ്യൂണൽ"</string>
</resources>
diff --git a/core/res/res/values-mn/strings.xml b/core/res/res/values-mn/strings.xml
index c215b88..ed656cd 100644
--- a/core/res/res/values-mn/strings.xml
+++ b/core/res/res/values-mn/strings.xml
@@ -2359,18 +2359,11 @@
<string name="keyboard_layout_notification_more_than_three_selected_message" msgid="1581834181578206937">"Гарын бүдүүвчийг <xliff:g id="LAYOUT_1">%1$s</xliff:g>, <xliff:g id="LAYOUT_2">%2$s</xliff:g>, <xliff:g id="LAYOUT_3">%3$s</xliff:g> болгож тохируулсан… Өөрчлөхийн тулд товшино уу."</string>
<string name="keyboard_layout_notification_multiple_selected_title" msgid="5242444914367024499">"Биет гарыг тохируулсан"</string>
<string name="keyboard_layout_notification_multiple_selected_message" msgid="6576533454124419202">"Гарыг харахын тулд товшино уу"</string>
- <!-- no translation found for profile_label_private (6463418670715290696) -->
- <skip />
- <!-- no translation found for profile_label_clone (769106052210954285) -->
- <skip />
- <!-- no translation found for profile_label_work (3495359133038584618) -->
- <skip />
- <!-- no translation found for profile_label_work_2 (4691533661598632135) -->
- <skip />
- <!-- no translation found for profile_label_work_3 (4834572253956798917) -->
- <skip />
- <!-- no translation found for profile_label_test (9168641926186071947) -->
- <skip />
- <!-- no translation found for profile_label_communal (8743921499944800427) -->
- <skip />
+ <string name="profile_label_private" msgid="6463418670715290696">"Хувийн"</string>
+ <string name="profile_label_clone" msgid="769106052210954285">"Клон"</string>
+ <string name="profile_label_work" msgid="3495359133038584618">"Ажил"</string>
+ <string name="profile_label_work_2" msgid="4691533661598632135">"Ажил 2"</string>
+ <string name="profile_label_work_3" msgid="4834572253956798917">"Ажил 3"</string>
+ <string name="profile_label_test" msgid="9168641926186071947">"Туршилт"</string>
+ <string name="profile_label_communal" msgid="8743921499944800427">"Нийтийн"</string>
</resources>
diff --git a/core/res/res/values-mr/strings.xml b/core/res/res/values-mr/strings.xml
index 03fcc17..ff475fe 100644
--- a/core/res/res/values-mr/strings.xml
+++ b/core/res/res/values-mr/strings.xml
@@ -2359,18 +2359,11 @@
<string name="keyboard_layout_notification_more_than_three_selected_message" msgid="1581834181578206937">"कीबोर्ड लेआउट <xliff:g id="LAYOUT_1">%1$s</xliff:g>, <xliff:g id="LAYOUT_2">%2$s</xliff:g>, <xliff:g id="LAYOUT_3">%3$s</xliff:g> वर सेट करा… बदलण्यासाठी टॅप करा."</string>
<string name="keyboard_layout_notification_multiple_selected_title" msgid="5242444914367024499">"वास्तविक कीबोर्ड कॉंफिगर केला"</string>
<string name="keyboard_layout_notification_multiple_selected_message" msgid="6576533454124419202">"कीबोर्ड पाहण्यासाठी टॅप करा"</string>
- <!-- no translation found for profile_label_private (6463418670715290696) -->
- <skip />
- <!-- no translation found for profile_label_clone (769106052210954285) -->
- <skip />
- <!-- no translation found for profile_label_work (3495359133038584618) -->
- <skip />
- <!-- no translation found for profile_label_work_2 (4691533661598632135) -->
- <skip />
- <!-- no translation found for profile_label_work_3 (4834572253956798917) -->
- <skip />
- <!-- no translation found for profile_label_test (9168641926186071947) -->
- <skip />
- <!-- no translation found for profile_label_communal (8743921499944800427) -->
- <skip />
+ <string name="profile_label_private" msgid="6463418670715290696">"खाजगी"</string>
+ <string name="profile_label_clone" msgid="769106052210954285">"क्लोन"</string>
+ <string name="profile_label_work" msgid="3495359133038584618">"ऑफिस"</string>
+ <string name="profile_label_work_2" msgid="4691533661598632135">"ऑफिस २"</string>
+ <string name="profile_label_work_3" msgid="4834572253956798917">"ऑफिस ३"</string>
+ <string name="profile_label_test" msgid="9168641926186071947">"चाचणी"</string>
+ <string name="profile_label_communal" msgid="8743921499944800427">"सामुदायिक"</string>
</resources>
diff --git a/core/res/res/values-ms/strings.xml b/core/res/res/values-ms/strings.xml
index 84b79a8..4821fc8 100644
--- a/core/res/res/values-ms/strings.xml
+++ b/core/res/res/values-ms/strings.xml
@@ -2359,18 +2359,11 @@
<string name="keyboard_layout_notification_more_than_three_selected_message" msgid="1581834181578206937">"Reka letak papan kekunci ditetapkan kepada <xliff:g id="LAYOUT_1">%1$s</xliff:g>, <xliff:g id="LAYOUT_2">%2$s</xliff:g>, <xliff:g id="LAYOUT_3">%3$s</xliff:g>… Ketik untuk menukar reka letak."</string>
<string name="keyboard_layout_notification_multiple_selected_title" msgid="5242444914367024499">"Papan kekunci fizikal dikonfigurasikan"</string>
<string name="keyboard_layout_notification_multiple_selected_message" msgid="6576533454124419202">"Ketik untuk melihat papan kekunci"</string>
- <!-- no translation found for profile_label_private (6463418670715290696) -->
- <skip />
- <!-- no translation found for profile_label_clone (769106052210954285) -->
- <skip />
- <!-- no translation found for profile_label_work (3495359133038584618) -->
- <skip />
- <!-- no translation found for profile_label_work_2 (4691533661598632135) -->
- <skip />
- <!-- no translation found for profile_label_work_3 (4834572253956798917) -->
- <skip />
- <!-- no translation found for profile_label_test (9168641926186071947) -->
- <skip />
- <!-- no translation found for profile_label_communal (8743921499944800427) -->
- <skip />
+ <string name="profile_label_private" msgid="6463418670715290696">"Peribadi"</string>
+ <string name="profile_label_clone" msgid="769106052210954285">"Klon"</string>
+ <string name="profile_label_work" msgid="3495359133038584618">"Kerja"</string>
+ <string name="profile_label_work_2" msgid="4691533661598632135">"Kerja 2"</string>
+ <string name="profile_label_work_3" msgid="4834572253956798917">"Kerja 3"</string>
+ <string name="profile_label_test" msgid="9168641926186071947">"Ujian"</string>
+ <string name="profile_label_communal" msgid="8743921499944800427">"Umum"</string>
</resources>
diff --git a/core/res/res/values-my/strings.xml b/core/res/res/values-my/strings.xml
index 01906b9..6981e82 100644
--- a/core/res/res/values-my/strings.xml
+++ b/core/res/res/values-my/strings.xml
@@ -2359,18 +2359,11 @@
<string name="keyboard_layout_notification_more_than_three_selected_message" msgid="1581834181578206937">"ကီးဘုတ်အပြင်အဆင်ကို <xliff:g id="LAYOUT_1">%1$s</xliff:g>၊ <xliff:g id="LAYOUT_2">%2$s</xliff:g>၊ <xliff:g id="LAYOUT_3">%3$s</xliff:g> သို့ သတ်မှတ်လိုက်သည်… ပြောင်းရန် တို့ပါ။"</string>
<string name="keyboard_layout_notification_multiple_selected_title" msgid="5242444914367024499">"ပကတိကီးဘုတ်များကို စီစဉ်သတ်မှတ်ထားသည်"</string>
<string name="keyboard_layout_notification_multiple_selected_message" msgid="6576533454124419202">"ကီးဘုတ်များကြည့်ရန် တို့ပါ"</string>
- <!-- no translation found for profile_label_private (6463418670715290696) -->
- <skip />
- <!-- no translation found for profile_label_clone (769106052210954285) -->
- <skip />
- <!-- no translation found for profile_label_work (3495359133038584618) -->
- <skip />
- <!-- no translation found for profile_label_work_2 (4691533661598632135) -->
- <skip />
- <!-- no translation found for profile_label_work_3 (4834572253956798917) -->
- <skip />
- <!-- no translation found for profile_label_test (9168641926186071947) -->
- <skip />
- <!-- no translation found for profile_label_communal (8743921499944800427) -->
- <skip />
+ <string name="profile_label_private" msgid="6463418670715290696">"သီးသန့်"</string>
+ <string name="profile_label_clone" msgid="769106052210954285">"ဆင်တူပြုလုပ်ရန်"</string>
+ <string name="profile_label_work" msgid="3495359133038584618">"အလုပ်"</string>
+ <string name="profile_label_work_2" msgid="4691533661598632135">"အလုပ် ၂"</string>
+ <string name="profile_label_work_3" msgid="4834572253956798917">"အလုပ် ၃"</string>
+ <string name="profile_label_test" msgid="9168641926186071947">"စမ်းသပ်မှု"</string>
+ <string name="profile_label_communal" msgid="8743921499944800427">"အများသုံး"</string>
</resources>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index d8e3b40..e667b93 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -2359,18 +2359,11 @@
<string name="keyboard_layout_notification_more_than_three_selected_message" msgid="1581834181578206937">"Tastaturoppsettet er satt til <xliff:g id="LAYOUT_1">%1$s</xliff:g>, <xliff:g id="LAYOUT_2">%2$s</xliff:g>, <xliff:g id="LAYOUT_3">%3$s</xliff:g> … Trykk for å endre det."</string>
<string name="keyboard_layout_notification_multiple_selected_title" msgid="5242444914367024499">"De fysiske tastaturene er konfigurert"</string>
<string name="keyboard_layout_notification_multiple_selected_message" msgid="6576533454124419202">"Trykk for å se tastaturene"</string>
- <!-- no translation found for profile_label_private (6463418670715290696) -->
- <skip />
- <!-- no translation found for profile_label_clone (769106052210954285) -->
- <skip />
- <!-- no translation found for profile_label_work (3495359133038584618) -->
- <skip />
- <!-- no translation found for profile_label_work_2 (4691533661598632135) -->
- <skip />
- <!-- no translation found for profile_label_work_3 (4834572253956798917) -->
- <skip />
- <!-- no translation found for profile_label_test (9168641926186071947) -->
- <skip />
- <!-- no translation found for profile_label_communal (8743921499944800427) -->
- <skip />
+ <string name="profile_label_private" msgid="6463418670715290696">"Privat"</string>
+ <string name="profile_label_clone" msgid="769106052210954285">"Klone"</string>
+ <string name="profile_label_work" msgid="3495359133038584618">"Jobb"</string>
+ <string name="profile_label_work_2" msgid="4691533661598632135">"Jobb 2"</string>
+ <string name="profile_label_work_3" msgid="4834572253956798917">"Jobb 3"</string>
+ <string name="profile_label_test" msgid="9168641926186071947">"Test"</string>
+ <string name="profile_label_communal" msgid="8743921499944800427">"Felles"</string>
</resources>
diff --git a/core/res/res/values-ne/strings.xml b/core/res/res/values-ne/strings.xml
index 126f612..bb06243 100644
--- a/core/res/res/values-ne/strings.xml
+++ b/core/res/res/values-ne/strings.xml
@@ -2359,18 +2359,11 @@
<string name="keyboard_layout_notification_more_than_three_selected_message" msgid="1581834181578206937">"किबोर्ड लेआउट <xliff:g id="LAYOUT_1">%1$s</xliff:g>, <xliff:g id="LAYOUT_2">%2$s</xliff:g>, <xliff:g id="LAYOUT_3">%3$s</xliff:g> भाषामा सेट गरिएको छ… बदल्न ट्याप गर्नुहोस्।"</string>
<string name="keyboard_layout_notification_multiple_selected_title" msgid="5242444914367024499">"भौतिक किबोर्डहरू कन्फिगर गरिएका छन्"</string>
<string name="keyboard_layout_notification_multiple_selected_message" msgid="6576533454124419202">"किबोर्डहरू हेर्न ट्याप गर्नुहोस्"</string>
- <!-- no translation found for profile_label_private (6463418670715290696) -->
- <skip />
- <!-- no translation found for profile_label_clone (769106052210954285) -->
- <skip />
- <!-- no translation found for profile_label_work (3495359133038584618) -->
- <skip />
- <!-- no translation found for profile_label_work_2 (4691533661598632135) -->
- <skip />
- <!-- no translation found for profile_label_work_3 (4834572253956798917) -->
- <skip />
- <!-- no translation found for profile_label_test (9168641926186071947) -->
- <skip />
- <!-- no translation found for profile_label_communal (8743921499944800427) -->
- <skip />
+ <string name="profile_label_private" msgid="6463418670715290696">"निजी"</string>
+ <string name="profile_label_clone" msgid="769106052210954285">"क्लोन"</string>
+ <string name="profile_label_work" msgid="3495359133038584618">"कार्य प्रोफाइल"</string>
+ <string name="profile_label_work_2" msgid="4691533661598632135">"कार्य प्रोफाइल २"</string>
+ <string name="profile_label_work_3" msgid="4834572253956798917">"कार्य प्रोफाइल ३"</string>
+ <string name="profile_label_test" msgid="9168641926186071947">"परीक्षण"</string>
+ <string name="profile_label_communal" msgid="8743921499944800427">"सामुदायिक"</string>
</resources>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index bc18797..40239a6 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -2359,18 +2359,11 @@
<string name="keyboard_layout_notification_more_than_three_selected_message" msgid="1581834181578206937">"Toetsenbordindeling ingesteld op <xliff:g id="LAYOUT_1">%1$s</xliff:g>, <xliff:g id="LAYOUT_2">%2$s</xliff:g>, <xliff:g id="LAYOUT_3">%3$s</xliff:g>… Tik om te wijzigen."</string>
<string name="keyboard_layout_notification_multiple_selected_title" msgid="5242444914367024499">"Fysieke toetsenborden zijn ingesteld"</string>
<string name="keyboard_layout_notification_multiple_selected_message" msgid="6576533454124419202">"Tik om toetsenborden te bekijken"</string>
- <!-- no translation found for profile_label_private (6463418670715290696) -->
- <skip />
- <!-- no translation found for profile_label_clone (769106052210954285) -->
- <skip />
- <!-- no translation found for profile_label_work (3495359133038584618) -->
- <skip />
- <!-- no translation found for profile_label_work_2 (4691533661598632135) -->
- <skip />
- <!-- no translation found for profile_label_work_3 (4834572253956798917) -->
- <skip />
- <!-- no translation found for profile_label_test (9168641926186071947) -->
- <skip />
- <!-- no translation found for profile_label_communal (8743921499944800427) -->
- <skip />
+ <string name="profile_label_private" msgid="6463418670715290696">"Privé"</string>
+ <string name="profile_label_clone" msgid="769106052210954285">"Kloon"</string>
+ <string name="profile_label_work" msgid="3495359133038584618">"Werk"</string>
+ <string name="profile_label_work_2" msgid="4691533661598632135">"Werk 2"</string>
+ <string name="profile_label_work_3" msgid="4834572253956798917">"Werk 3"</string>
+ <string name="profile_label_test" msgid="9168641926186071947">"Test"</string>
+ <string name="profile_label_communal" msgid="8743921499944800427">"Gemeenschappelijk"</string>
</resources>
diff --git a/core/res/res/values-or/strings.xml b/core/res/res/values-or/strings.xml
index 7f66887..fc4824d 100644
--- a/core/res/res/values-or/strings.xml
+++ b/core/res/res/values-or/strings.xml
@@ -2359,18 +2359,11 @@
<string name="keyboard_layout_notification_more_than_three_selected_message" msgid="1581834181578206937">"କୀବୋର୍ଡ ଲେଆଉଟକୁ <xliff:g id="LAYOUT_1">%1$s</xliff:g>, <xliff:g id="LAYOUT_2">%2$s</xliff:g>, <xliff:g id="LAYOUT_3">%3$s</xliff:g>ରେ ସେଟ କରାଯାଇଛି… ପରିବର୍ତ୍ତନ କରିବାକୁ ଟାପ କରନ୍ତୁ।"</string>
<string name="keyboard_layout_notification_multiple_selected_title" msgid="5242444914367024499">"ଫିଜିକାଲ କୀବୋର୍ଡଗୁଡ଼ିକୁ କନଫିଗର କରାଯାଇଛି"</string>
<string name="keyboard_layout_notification_multiple_selected_message" msgid="6576533454124419202">"କୀବୋର୍ଡଗୁଡ଼ିକୁ ଦେଖିବା ପାଇଁ ଟାପ କରନ୍ତୁ"</string>
- <!-- no translation found for profile_label_private (6463418670715290696) -->
- <skip />
- <!-- no translation found for profile_label_clone (769106052210954285) -->
- <skip />
- <!-- no translation found for profile_label_work (3495359133038584618) -->
- <skip />
- <!-- no translation found for profile_label_work_2 (4691533661598632135) -->
- <skip />
- <!-- no translation found for profile_label_work_3 (4834572253956798917) -->
- <skip />
- <!-- no translation found for profile_label_test (9168641926186071947) -->
- <skip />
- <!-- no translation found for profile_label_communal (8743921499944800427) -->
- <skip />
+ <string name="profile_label_private" msgid="6463418670715290696">"ପ୍ରାଇଭେଟ"</string>
+ <string name="profile_label_clone" msgid="769106052210954285">"କ୍ଲୋନ"</string>
+ <string name="profile_label_work" msgid="3495359133038584618">"ୱାର୍କ"</string>
+ <string name="profile_label_work_2" msgid="4691533661598632135">"ୱାର୍କ 2"</string>
+ <string name="profile_label_work_3" msgid="4834572253956798917">"ୱାର୍କ 3"</string>
+ <string name="profile_label_test" msgid="9168641926186071947">"ଟେଷ୍ଟ"</string>
+ <string name="profile_label_communal" msgid="8743921499944800427">"କମ୍ୟୁନାଲ"</string>
</resources>
diff --git a/core/res/res/values-pa/strings.xml b/core/res/res/values-pa/strings.xml
index 0396149..f828dae 100644
--- a/core/res/res/values-pa/strings.xml
+++ b/core/res/res/values-pa/strings.xml
@@ -2359,18 +2359,11 @@
<string name="keyboard_layout_notification_more_than_three_selected_message" msgid="1581834181578206937">"ਕੀ-ਬੋਰਡ ਦਾ ਖਾਕਾ <xliff:g id="LAYOUT_1">%1$s</xliff:g>, <xliff:g id="LAYOUT_2">%2$s</xliff:g>, <xliff:g id="LAYOUT_3">%3$s</xliff:g> \'ਤੇ ਸੈੱਟ ਹੈ… ਬਦਲਣ ਲਈ ਟੈਪ ਕਰੋ।"</string>
<string name="keyboard_layout_notification_multiple_selected_title" msgid="5242444914367024499">"ਭੌਤਿਕ ਕੀ-ਬੋਰਡਾਂ ਦਾ ਸੰਰੂਪਣ ਕੀਤਾ ਗਿਆ"</string>
<string name="keyboard_layout_notification_multiple_selected_message" msgid="6576533454124419202">"ਕੀ-ਬੋਰਡਾਂ ਨੂੰ ਦੇਖਣ ਲਈ ਟੈਪ ਕਰੋ"</string>
- <!-- no translation found for profile_label_private (6463418670715290696) -->
- <skip />
- <!-- no translation found for profile_label_clone (769106052210954285) -->
- <skip />
- <!-- no translation found for profile_label_work (3495359133038584618) -->
- <skip />
- <!-- no translation found for profile_label_work_2 (4691533661598632135) -->
- <skip />
- <!-- no translation found for profile_label_work_3 (4834572253956798917) -->
- <skip />
- <!-- no translation found for profile_label_test (9168641926186071947) -->
- <skip />
- <!-- no translation found for profile_label_communal (8743921499944800427) -->
- <skip />
+ <string name="profile_label_private" msgid="6463418670715290696">"ਨਿੱਜੀ"</string>
+ <string name="profile_label_clone" msgid="769106052210954285">"ਕਲੋਨ"</string>
+ <string name="profile_label_work" msgid="3495359133038584618">"ਕਾਰਜ"</string>
+ <string name="profile_label_work_2" msgid="4691533661598632135">"ਕੰਮ ਸੰਬੰਧੀ 2"</string>
+ <string name="profile_label_work_3" msgid="4834572253956798917">"ਕੰਮ ਸੰਬੰਧੀ 3"</string>
+ <string name="profile_label_test" msgid="9168641926186071947">"ਜਾਂਚ"</string>
+ <string name="profile_label_communal" msgid="8743921499944800427">"ਭਾਈਚਾਰਕ"</string>
</resources>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index 66d5570..f083436 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -2361,18 +2361,11 @@
<string name="keyboard_layout_notification_more_than_three_selected_message" msgid="1581834181578206937">"Ustawiono układ klawiatury <xliff:g id="LAYOUT_1">%1$s</xliff:g>, <xliff:g id="LAYOUT_2">%2$s</xliff:g>, <xliff:g id="LAYOUT_3">%3$s</xliff:g>… Kliknij, aby to zmienić."</string>
<string name="keyboard_layout_notification_multiple_selected_title" msgid="5242444914367024499">"Skonfigurowano klawiatury fizyczne"</string>
<string name="keyboard_layout_notification_multiple_selected_message" msgid="6576533454124419202">"Kliknij, aby wyświetlić klawiatury"</string>
- <!-- no translation found for profile_label_private (6463418670715290696) -->
- <skip />
- <!-- no translation found for profile_label_clone (769106052210954285) -->
- <skip />
- <!-- no translation found for profile_label_work (3495359133038584618) -->
- <skip />
- <!-- no translation found for profile_label_work_2 (4691533661598632135) -->
- <skip />
- <!-- no translation found for profile_label_work_3 (4834572253956798917) -->
- <skip />
- <!-- no translation found for profile_label_test (9168641926186071947) -->
- <skip />
- <!-- no translation found for profile_label_communal (8743921499944800427) -->
- <skip />
+ <string name="profile_label_private" msgid="6463418670715290696">"Prywatny"</string>
+ <string name="profile_label_clone" msgid="769106052210954285">"Klon"</string>
+ <string name="profile_label_work" msgid="3495359133038584618">"Służbowy"</string>
+ <string name="profile_label_work_2" msgid="4691533661598632135">"Służbowy 2"</string>
+ <string name="profile_label_work_3" msgid="4834572253956798917">"Służbowy 3"</string>
+ <string name="profile_label_test" msgid="9168641926186071947">"Testowy"</string>
+ <string name="profile_label_communal" msgid="8743921499944800427">"Wspólny"</string>
</resources>
diff --git a/core/res/res/values-pt-rBR/strings.xml b/core/res/res/values-pt-rBR/strings.xml
index e32c738..1634488 100644
--- a/core/res/res/values-pt-rBR/strings.xml
+++ b/core/res/res/values-pt-rBR/strings.xml
@@ -2360,18 +2360,11 @@
<string name="keyboard_layout_notification_more_than_three_selected_message" msgid="1581834181578206937">"Layout do teclado definido como <xliff:g id="LAYOUT_1">%1$s</xliff:g>, <xliff:g id="LAYOUT_2">%2$s</xliff:g>, <xliff:g id="LAYOUT_3">%3$s</xliff:g>… Toque para mudar."</string>
<string name="keyboard_layout_notification_multiple_selected_title" msgid="5242444914367024499">"Teclados físicos configurados"</string>
<string name="keyboard_layout_notification_multiple_selected_message" msgid="6576533454124419202">"Toque para conferir os teclados"</string>
- <!-- no translation found for profile_label_private (6463418670715290696) -->
- <skip />
- <!-- no translation found for profile_label_clone (769106052210954285) -->
- <skip />
- <!-- no translation found for profile_label_work (3495359133038584618) -->
- <skip />
- <!-- no translation found for profile_label_work_2 (4691533661598632135) -->
- <skip />
- <!-- no translation found for profile_label_work_3 (4834572253956798917) -->
- <skip />
- <!-- no translation found for profile_label_test (9168641926186071947) -->
- <skip />
- <!-- no translation found for profile_label_communal (8743921499944800427) -->
- <skip />
+ <string name="profile_label_private" msgid="6463418670715290696">"Particular"</string>
+ <string name="profile_label_clone" msgid="769106052210954285">"Clone"</string>
+ <string name="profile_label_work" msgid="3495359133038584618">"Trabalho"</string>
+ <string name="profile_label_work_2" msgid="4691533661598632135">"Trabalho 2"</string>
+ <string name="profile_label_work_3" msgid="4834572253956798917">"Trabalho 3"</string>
+ <string name="profile_label_test" msgid="9168641926186071947">"Teste"</string>
+ <string name="profile_label_communal" msgid="8743921499944800427">"Público"</string>
</resources>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index e32c738..1634488 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -2360,18 +2360,11 @@
<string name="keyboard_layout_notification_more_than_three_selected_message" msgid="1581834181578206937">"Layout do teclado definido como <xliff:g id="LAYOUT_1">%1$s</xliff:g>, <xliff:g id="LAYOUT_2">%2$s</xliff:g>, <xliff:g id="LAYOUT_3">%3$s</xliff:g>… Toque para mudar."</string>
<string name="keyboard_layout_notification_multiple_selected_title" msgid="5242444914367024499">"Teclados físicos configurados"</string>
<string name="keyboard_layout_notification_multiple_selected_message" msgid="6576533454124419202">"Toque para conferir os teclados"</string>
- <!-- no translation found for profile_label_private (6463418670715290696) -->
- <skip />
- <!-- no translation found for profile_label_clone (769106052210954285) -->
- <skip />
- <!-- no translation found for profile_label_work (3495359133038584618) -->
- <skip />
- <!-- no translation found for profile_label_work_2 (4691533661598632135) -->
- <skip />
- <!-- no translation found for profile_label_work_3 (4834572253956798917) -->
- <skip />
- <!-- no translation found for profile_label_test (9168641926186071947) -->
- <skip />
- <!-- no translation found for profile_label_communal (8743921499944800427) -->
- <skip />
+ <string name="profile_label_private" msgid="6463418670715290696">"Particular"</string>
+ <string name="profile_label_clone" msgid="769106052210954285">"Clone"</string>
+ <string name="profile_label_work" msgid="3495359133038584618">"Trabalho"</string>
+ <string name="profile_label_work_2" msgid="4691533661598632135">"Trabalho 2"</string>
+ <string name="profile_label_work_3" msgid="4834572253956798917">"Trabalho 3"</string>
+ <string name="profile_label_test" msgid="9168641926186071947">"Teste"</string>
+ <string name="profile_label_communal" msgid="8743921499944800427">"Público"</string>
</resources>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index 2f16db3..cda23a5 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -2361,18 +2361,11 @@
<string name="keyboard_layout_notification_more_than_three_selected_message" msgid="1581834181578206937">"Настроены раскладки клавиатуры для яз.: <xliff:g id="LAYOUT_1">%1$s</xliff:g>, <xliff:g id="LAYOUT_2">%2$s</xliff:g>, <xliff:g id="LAYOUT_3">%3$s</xliff:g> и др. Нажмите, чтобы изменить."</string>
<string name="keyboard_layout_notification_multiple_selected_title" msgid="5242444914367024499">"Физические клавиатуры настроены"</string>
<string name="keyboard_layout_notification_multiple_selected_message" msgid="6576533454124419202">"Нажмите, чтобы посмотреть подключенные клавиатуры."</string>
- <!-- no translation found for profile_label_private (6463418670715290696) -->
- <skip />
- <!-- no translation found for profile_label_clone (769106052210954285) -->
- <skip />
- <!-- no translation found for profile_label_work (3495359133038584618) -->
- <skip />
- <!-- no translation found for profile_label_work_2 (4691533661598632135) -->
- <skip />
- <!-- no translation found for profile_label_work_3 (4834572253956798917) -->
- <skip />
- <!-- no translation found for profile_label_test (9168641926186071947) -->
- <skip />
- <!-- no translation found for profile_label_communal (8743921499944800427) -->
- <skip />
+ <string name="profile_label_private" msgid="6463418670715290696">"Личный"</string>
+ <string name="profile_label_clone" msgid="769106052210954285">"Клон"</string>
+ <string name="profile_label_work" msgid="3495359133038584618">"Рабочий"</string>
+ <string name="profile_label_work_2" msgid="4691533661598632135">"Рабочий 2"</string>
+ <string name="profile_label_work_3" msgid="4834572253956798917">"Рабочий 3"</string>
+ <string name="profile_label_test" msgid="9168641926186071947">"Тестовый"</string>
+ <string name="profile_label_communal" msgid="8743921499944800427">"Совместный"</string>
</resources>
diff --git a/core/res/res/values-si/strings.xml b/core/res/res/values-si/strings.xml
index ac86d7b..4e26aa2 100644
--- a/core/res/res/values-si/strings.xml
+++ b/core/res/res/values-si/strings.xml
@@ -2359,18 +2359,11 @@
<string name="keyboard_layout_notification_more_than_three_selected_message" msgid="1581834181578206937">"යතුරු පුවරුව <xliff:g id="LAYOUT_1">%1$s</xliff:g>, <xliff:g id="LAYOUT_2">%2$s</xliff:g>, <xliff:g id="LAYOUT_3">%3$s</xliff:g> ලෙස සකසා ඇත… වෙනස් කිරීමට තට්ටු කරන්න."</string>
<string name="keyboard_layout_notification_multiple_selected_title" msgid="5242444914367024499">"භෞතික යතුරු පුවරුව වින්යාස කෙරිණි"</string>
<string name="keyboard_layout_notification_multiple_selected_message" msgid="6576533454124419202">"යතුරු පුවරු බැලීමට තට්ටු කරන්න"</string>
- <!-- no translation found for profile_label_private (6463418670715290696) -->
- <skip />
- <!-- no translation found for profile_label_clone (769106052210954285) -->
- <skip />
- <!-- no translation found for profile_label_work (3495359133038584618) -->
- <skip />
- <!-- no translation found for profile_label_work_2 (4691533661598632135) -->
- <skip />
- <!-- no translation found for profile_label_work_3 (4834572253956798917) -->
- <skip />
- <!-- no translation found for profile_label_test (9168641926186071947) -->
- <skip />
- <!-- no translation found for profile_label_communal (8743921499944800427) -->
- <skip />
+ <string name="profile_label_private" msgid="6463418670715290696">"පෞද්ගලික"</string>
+ <string name="profile_label_clone" msgid="769106052210954285">"ක්ලෝන කරන්න"</string>
+ <string name="profile_label_work" msgid="3495359133038584618">"කාර්යාලය"</string>
+ <string name="profile_label_work_2" msgid="4691533661598632135">"කාර්යාලය 2"</string>
+ <string name="profile_label_work_3" msgid="4834572253956798917">"කාර්යාලය 3"</string>
+ <string name="profile_label_test" msgid="9168641926186071947">"පරීක්ෂණය"</string>
+ <string name="profile_label_communal" msgid="8743921499944800427">"වාර්ගික"</string>
</resources>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index d1d7897..089372e 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -2361,18 +2361,11 @@
<string name="keyboard_layout_notification_more_than_three_selected_message" msgid="1581834181578206937">"Rozloženie klávesnice je nastavené na jazyky <xliff:g id="LAYOUT_1">%1$s</xliff:g>, <xliff:g id="LAYOUT_2">%2$s</xliff:g> a <xliff:g id="LAYOUT_3">%3$s</xliff:g>… Môžete to zmeniť klepnutím."</string>
<string name="keyboard_layout_notification_multiple_selected_title" msgid="5242444914367024499">"Fyzické klávesnice sú nakonfigurované"</string>
<string name="keyboard_layout_notification_multiple_selected_message" msgid="6576533454124419202">"Klávesnice si zobrazíte klepnutím"</string>
- <!-- no translation found for profile_label_private (6463418670715290696) -->
- <skip />
- <!-- no translation found for profile_label_clone (769106052210954285) -->
- <skip />
- <!-- no translation found for profile_label_work (3495359133038584618) -->
- <skip />
- <!-- no translation found for profile_label_work_2 (4691533661598632135) -->
- <skip />
- <!-- no translation found for profile_label_work_3 (4834572253956798917) -->
- <skip />
- <!-- no translation found for profile_label_test (9168641926186071947) -->
- <skip />
- <!-- no translation found for profile_label_communal (8743921499944800427) -->
- <skip />
+ <string name="profile_label_private" msgid="6463418670715290696">"Súkromný"</string>
+ <string name="profile_label_clone" msgid="769106052210954285">"Klon"</string>
+ <string name="profile_label_work" msgid="3495359133038584618">"Pracovný"</string>
+ <string name="profile_label_work_2" msgid="4691533661598632135">"2. pracovný"</string>
+ <string name="profile_label_work_3" msgid="4834572253956798917">"3. pracovný"</string>
+ <string name="profile_label_test" msgid="9168641926186071947">"Testovací"</string>
+ <string name="profile_label_communal" msgid="8743921499944800427">"Spoločný"</string>
</resources>
diff --git a/core/res/res/values-sq/strings.xml b/core/res/res/values-sq/strings.xml
index 2cd76fd..8965801 100644
--- a/core/res/res/values-sq/strings.xml
+++ b/core/res/res/values-sq/strings.xml
@@ -2359,18 +2359,11 @@
<string name="keyboard_layout_notification_more_than_three_selected_message" msgid="1581834181578206937">"Struktura e tastierës u caktua në: <xliff:g id="LAYOUT_1">%1$s</xliff:g>, <xliff:g id="LAYOUT_2">%2$s</xliff:g>, <xliff:g id="LAYOUT_3">%3$s</xliff:g>… Trokit për ta ndryshuar."</string>
<string name="keyboard_layout_notification_multiple_selected_title" msgid="5242444914367024499">"Tastierat fizike u konfiguruan"</string>
<string name="keyboard_layout_notification_multiple_selected_message" msgid="6576533454124419202">"Trokit për të parë tastierat"</string>
- <!-- no translation found for profile_label_private (6463418670715290696) -->
- <skip />
- <!-- no translation found for profile_label_clone (769106052210954285) -->
- <skip />
- <!-- no translation found for profile_label_work (3495359133038584618) -->
- <skip />
- <!-- no translation found for profile_label_work_2 (4691533661598632135) -->
- <skip />
- <!-- no translation found for profile_label_work_3 (4834572253956798917) -->
- <skip />
- <!-- no translation found for profile_label_test (9168641926186071947) -->
- <skip />
- <!-- no translation found for profile_label_communal (8743921499944800427) -->
- <skip />
+ <string name="profile_label_private" msgid="6463418670715290696">"Privat"</string>
+ <string name="profile_label_clone" msgid="769106052210954285">"Klon"</string>
+ <string name="profile_label_work" msgid="3495359133038584618">"Puna"</string>
+ <string name="profile_label_work_2" msgid="4691533661598632135">"Puna 2"</string>
+ <string name="profile_label_work_3" msgid="4834572253956798917">"Puna 3"</string>
+ <string name="profile_label_test" msgid="9168641926186071947">"Test"</string>
+ <string name="profile_label_communal" msgid="8743921499944800427">"I përbashkët"</string>
</resources>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index 9e77bf6..f81d24d 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -2360,18 +2360,11 @@
<string name="keyboard_layout_notification_more_than_three_selected_message" msgid="1581834181578206937">"Распоред тастатуре је подешен на <xliff:g id="LAYOUT_1">%1$s</xliff:g>, <xliff:g id="LAYOUT_2">%2$s</xliff:g>, <xliff:g id="LAYOUT_3">%3$s</xliff:g>… Додирните да бисте променили."</string>
<string name="keyboard_layout_notification_multiple_selected_title" msgid="5242444914367024499">"Физичке тастатуре су конфигурисане"</string>
<string name="keyboard_layout_notification_multiple_selected_message" msgid="6576533454124419202">"Додирните да бисте видели тастатуре"</string>
- <!-- no translation found for profile_label_private (6463418670715290696) -->
- <skip />
- <!-- no translation found for profile_label_clone (769106052210954285) -->
- <skip />
- <!-- no translation found for profile_label_work (3495359133038584618) -->
- <skip />
- <!-- no translation found for profile_label_work_2 (4691533661598632135) -->
- <skip />
- <!-- no translation found for profile_label_work_3 (4834572253956798917) -->
- <skip />
- <!-- no translation found for profile_label_test (9168641926186071947) -->
- <skip />
- <!-- no translation found for profile_label_communal (8743921499944800427) -->
- <skip />
+ <string name="profile_label_private" msgid="6463418670715290696">"Приватно"</string>
+ <string name="profile_label_clone" msgid="769106052210954285">"Клонирано"</string>
+ <string name="profile_label_work" msgid="3495359133038584618">"Посао"</string>
+ <string name="profile_label_work_2" msgid="4691533661598632135">"Посао 2"</string>
+ <string name="profile_label_work_3" msgid="4834572253956798917">"Посао 3"</string>
+ <string name="profile_label_test" msgid="9168641926186071947">"Тест"</string>
+ <string name="profile_label_communal" msgid="8743921499944800427">"Заједничко"</string>
</resources>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index ab5bfca..994ea61 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -2359,18 +2359,11 @@
<string name="keyboard_layout_notification_more_than_three_selected_message" msgid="1581834181578206937">"Tangentbordslayouten är inställd på <xliff:g id="LAYOUT_1">%1$s</xliff:g>, <xliff:g id="LAYOUT_2">%2$s</xliff:g>, <xliff:g id="LAYOUT_3">%3$s</xliff:g> … Tryck om du vill ändra."</string>
<string name="keyboard_layout_notification_multiple_selected_title" msgid="5242444914367024499">"Fysiska tangentbord har konfigurerats"</string>
<string name="keyboard_layout_notification_multiple_selected_message" msgid="6576533454124419202">"Tryck för att visa tangentbord"</string>
- <!-- no translation found for profile_label_private (6463418670715290696) -->
- <skip />
- <!-- no translation found for profile_label_clone (769106052210954285) -->
- <skip />
- <!-- no translation found for profile_label_work (3495359133038584618) -->
- <skip />
- <!-- no translation found for profile_label_work_2 (4691533661598632135) -->
- <skip />
- <!-- no translation found for profile_label_work_3 (4834572253956798917) -->
- <skip />
- <!-- no translation found for profile_label_test (9168641926186071947) -->
- <skip />
- <!-- no translation found for profile_label_communal (8743921499944800427) -->
- <skip />
+ <string name="profile_label_private" msgid="6463418670715290696">"Privat"</string>
+ <string name="profile_label_clone" msgid="769106052210954285">"Klon"</string>
+ <string name="profile_label_work" msgid="3495359133038584618">"Arbete"</string>
+ <string name="profile_label_work_2" msgid="4691533661598632135">"Arbete 2"</string>
+ <string name="profile_label_work_3" msgid="4834572253956798917">"Arbete 3"</string>
+ <string name="profile_label_test" msgid="9168641926186071947">"Test"</string>
+ <string name="profile_label_communal" msgid="8743921499944800427">"Allmän"</string>
</resources>
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index 61c0b17..912c588 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -2359,18 +2359,11 @@
<string name="keyboard_layout_notification_more_than_three_selected_message" msgid="1581834181578206937">"Muundo wa kibodi umewekwa kuwa <xliff:g id="LAYOUT_1">%1$s</xliff:g>, <xliff:g id="LAYOUT_2">%2$s</xliff:g>, <xliff:g id="LAYOUT_3">%3$s</xliff:g>… Gusa ili ubadilishe."</string>
<string name="keyboard_layout_notification_multiple_selected_title" msgid="5242444914367024499">"Mipangilio ya kibodi halisi imewekwa"</string>
<string name="keyboard_layout_notification_multiple_selected_message" msgid="6576533454124419202">"Gusa ili uangalie kibodi"</string>
- <!-- no translation found for profile_label_private (6463418670715290696) -->
- <skip />
- <!-- no translation found for profile_label_clone (769106052210954285) -->
- <skip />
- <!-- no translation found for profile_label_work (3495359133038584618) -->
- <skip />
- <!-- no translation found for profile_label_work_2 (4691533661598632135) -->
- <skip />
- <!-- no translation found for profile_label_work_3 (4834572253956798917) -->
- <skip />
- <!-- no translation found for profile_label_test (9168641926186071947) -->
- <skip />
- <!-- no translation found for profile_label_communal (8743921499944800427) -->
- <skip />
+ <string name="profile_label_private" msgid="6463418670715290696">"Wa faragha"</string>
+ <string name="profile_label_clone" msgid="769106052210954285">"Nakala"</string>
+ <string name="profile_label_work" msgid="3495359133038584618">"Wa kazini"</string>
+ <string name="profile_label_work_2" msgid="4691533661598632135">"Wa 2 wa Kazini"</string>
+ <string name="profile_label_work_3" msgid="4834572253956798917">"Wa 3 wa Kazini"</string>
+ <string name="profile_label_test" msgid="9168641926186071947">"Jaribio"</string>
+ <string name="profile_label_communal" msgid="8743921499944800427">"Unaoshirikiwa"</string>
</resources>
diff --git a/core/res/res/values-ta/strings.xml b/core/res/res/values-ta/strings.xml
index edf6c2d..8ba07fb 100644
--- a/core/res/res/values-ta/strings.xml
+++ b/core/res/res/values-ta/strings.xml
@@ -2359,18 +2359,11 @@
<string name="keyboard_layout_notification_more_than_three_selected_message" msgid="1581834181578206937">"கீபோர்டு தளவமைப்பு <xliff:g id="LAYOUT_1">%1$s</xliff:g>, <xliff:g id="LAYOUT_2">%2$s</xliff:g>, <xliff:g id="LAYOUT_3">%3$s</xliff:g>… ஆகிய மொழிகளில் அமைக்கப்பட்டது, மாற்ற தட்டவும்."</string>
<string name="keyboard_layout_notification_multiple_selected_title" msgid="5242444914367024499">"கீபோர்டுகள் உள்ளமைக்கப்பட்டன"</string>
<string name="keyboard_layout_notification_multiple_selected_message" msgid="6576533454124419202">"கீபோர்டுகளைப் பார்க்க தட்டவும்"</string>
- <!-- no translation found for profile_label_private (6463418670715290696) -->
- <skip />
- <!-- no translation found for profile_label_clone (769106052210954285) -->
- <skip />
- <!-- no translation found for profile_label_work (3495359133038584618) -->
- <skip />
- <!-- no translation found for profile_label_work_2 (4691533661598632135) -->
- <skip />
- <!-- no translation found for profile_label_work_3 (4834572253956798917) -->
- <skip />
- <!-- no translation found for profile_label_test (9168641926186071947) -->
- <skip />
- <!-- no translation found for profile_label_communal (8743921499944800427) -->
- <skip />
+ <string name="profile_label_private" msgid="6463418670715290696">"தனிப்பட்டது"</string>
+ <string name="profile_label_clone" msgid="769106052210954285">"குளோன்"</string>
+ <string name="profile_label_work" msgid="3495359133038584618">"பணி"</string>
+ <string name="profile_label_work_2" msgid="4691533661598632135">"பணி 2"</string>
+ <string name="profile_label_work_3" msgid="4834572253956798917">"பணி 3"</string>
+ <string name="profile_label_test" msgid="9168641926186071947">"பரிசோதனை"</string>
+ <string name="profile_label_communal" msgid="8743921499944800427">"பொது"</string>
</resources>
diff --git a/core/res/res/values-te/strings.xml b/core/res/res/values-te/strings.xml
index d862e2f..ce7b8bc 100644
--- a/core/res/res/values-te/strings.xml
+++ b/core/res/res/values-te/strings.xml
@@ -2359,18 +2359,11 @@
<string name="keyboard_layout_notification_more_than_three_selected_message" msgid="1581834181578206937">"కీబోర్డ్ లేఅవుట్ <xliff:g id="LAYOUT_1">%1$s</xliff:g>, <xliff:g id="LAYOUT_2">%2$s</xliff:g>, <xliff:g id="LAYOUT_3">%3$s</xliff:g>కు సెట్ చేయబడింది… మార్చడానికి ట్యాప్ చేయండి."</string>
<string name="keyboard_layout_notification_multiple_selected_title" msgid="5242444914367024499">"ఫిజికల్ కీబోర్డ్లు కాన్ఫిగర్ చేయబడ్డాయి"</string>
<string name="keyboard_layout_notification_multiple_selected_message" msgid="6576533454124419202">"కీబోర్డ్లను చూడటానికి ట్యాప్ చేయండి"</string>
- <!-- no translation found for profile_label_private (6463418670715290696) -->
- <skip />
- <!-- no translation found for profile_label_clone (769106052210954285) -->
- <skip />
- <!-- no translation found for profile_label_work (3495359133038584618) -->
- <skip />
- <!-- no translation found for profile_label_work_2 (4691533661598632135) -->
- <skip />
- <!-- no translation found for profile_label_work_3 (4834572253956798917) -->
- <skip />
- <!-- no translation found for profile_label_test (9168641926186071947) -->
- <skip />
- <!-- no translation found for profile_label_communal (8743921499944800427) -->
- <skip />
+ <string name="profile_label_private" msgid="6463418670715290696">"ప్రైవేట్"</string>
+ <string name="profile_label_clone" msgid="769106052210954285">"క్లోన్ చేయండి"</string>
+ <string name="profile_label_work" msgid="3495359133038584618">"ఆఫీస్"</string>
+ <string name="profile_label_work_2" msgid="4691533661598632135">"ఆఫీస్ 2"</string>
+ <string name="profile_label_work_3" msgid="4834572253956798917">"ఆఫీస్ 3"</string>
+ <string name="profile_label_test" msgid="9168641926186071947">"పరీక్ష"</string>
+ <string name="profile_label_communal" msgid="8743921499944800427">"కమ్యూనల్"</string>
</resources>
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index bda7e8a..b26389e 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -2359,18 +2359,11 @@
<string name="keyboard_layout_notification_more_than_three_selected_message" msgid="1581834181578206937">"ตั้งค่ารูปแบบแป้นพิมพ์เป็นภาษา<xliff:g id="LAYOUT_1">%1$s</xliff:g>, <xliff:g id="LAYOUT_2">%2$s</xliff:g>, <xliff:g id="LAYOUT_3">%3$s</xliff:g>… แตะเพื่อเปลี่ยน"</string>
<string name="keyboard_layout_notification_multiple_selected_title" msgid="5242444914367024499">"กำหนดค่าแป้นพิมพ์จริงแล้ว"</string>
<string name="keyboard_layout_notification_multiple_selected_message" msgid="6576533454124419202">"แตะเพื่อดูแป้นพิมพ์"</string>
- <!-- no translation found for profile_label_private (6463418670715290696) -->
- <skip />
- <!-- no translation found for profile_label_clone (769106052210954285) -->
- <skip />
- <!-- no translation found for profile_label_work (3495359133038584618) -->
- <skip />
- <!-- no translation found for profile_label_work_2 (4691533661598632135) -->
- <skip />
- <!-- no translation found for profile_label_work_3 (4834572253956798917) -->
- <skip />
- <!-- no translation found for profile_label_test (9168641926186071947) -->
- <skip />
- <!-- no translation found for profile_label_communal (8743921499944800427) -->
- <skip />
+ <string name="profile_label_private" msgid="6463418670715290696">"ส่วนตัว"</string>
+ <string name="profile_label_clone" msgid="769106052210954285">"โคลน"</string>
+ <string name="profile_label_work" msgid="3495359133038584618">"งาน"</string>
+ <string name="profile_label_work_2" msgid="4691533661598632135">"งาน 2"</string>
+ <string name="profile_label_work_3" msgid="4834572253956798917">"งาน 3"</string>
+ <string name="profile_label_test" msgid="9168641926186071947">"ทดสอบ"</string>
+ <string name="profile_label_communal" msgid="8743921499944800427">"ส่วนกลาง"</string>
</resources>
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index 53201ea..ceb8828 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -2359,18 +2359,11 @@
<string name="keyboard_layout_notification_more_than_three_selected_message" msgid="1581834181578206937">"Naitakda ang layout ng keyboard sa <xliff:g id="LAYOUT_1">%1$s</xliff:g>, <xliff:g id="LAYOUT_2">%2$s</xliff:g>, <xliff:g id="LAYOUT_3">%3$s</xliff:g>… I-tap para baguhin."</string>
<string name="keyboard_layout_notification_multiple_selected_title" msgid="5242444914367024499">"Na-configure ang mga pisikal na keyboard"</string>
<string name="keyboard_layout_notification_multiple_selected_message" msgid="6576533454124419202">"I-tap para tingnan ang mga keyboard"</string>
- <!-- no translation found for profile_label_private (6463418670715290696) -->
- <skip />
- <!-- no translation found for profile_label_clone (769106052210954285) -->
- <skip />
- <!-- no translation found for profile_label_work (3495359133038584618) -->
- <skip />
- <!-- no translation found for profile_label_work_2 (4691533661598632135) -->
- <skip />
- <!-- no translation found for profile_label_work_3 (4834572253956798917) -->
- <skip />
- <!-- no translation found for profile_label_test (9168641926186071947) -->
- <skip />
- <!-- no translation found for profile_label_communal (8743921499944800427) -->
- <skip />
+ <string name="profile_label_private" msgid="6463418670715290696">"Pribado"</string>
+ <string name="profile_label_clone" msgid="769106052210954285">"I-clone"</string>
+ <string name="profile_label_work" msgid="3495359133038584618">"Trabaho"</string>
+ <string name="profile_label_work_2" msgid="4691533661598632135">"Trabaho 2"</string>
+ <string name="profile_label_work_3" msgid="4834572253956798917">"Trabaho 3"</string>
+ <string name="profile_label_test" msgid="9168641926186071947">"Test"</string>
+ <string name="profile_label_communal" msgid="8743921499944800427">"Communal"</string>
</resources>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index ee1168f..528d1e5 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -2359,18 +2359,11 @@
<string name="keyboard_layout_notification_more_than_three_selected_message" msgid="1581834181578206937">"Klavye düzeni <xliff:g id="LAYOUT_1">%1$s</xliff:g>, <xliff:g id="LAYOUT_2">%2$s</xliff:g>, <xliff:g id="LAYOUT_3">%3$s</xliff:g> olarak ayarlandı… Değiştirmek için dokunun."</string>
<string name="keyboard_layout_notification_multiple_selected_title" msgid="5242444914367024499">"Fiziksel klavyeler yapılandırıldı"</string>
<string name="keyboard_layout_notification_multiple_selected_message" msgid="6576533454124419202">"Klavyeleri görüntülemek için dokunun"</string>
- <!-- no translation found for profile_label_private (6463418670715290696) -->
- <skip />
- <!-- no translation found for profile_label_clone (769106052210954285) -->
- <skip />
- <!-- no translation found for profile_label_work (3495359133038584618) -->
- <skip />
- <!-- no translation found for profile_label_work_2 (4691533661598632135) -->
- <skip />
- <!-- no translation found for profile_label_work_3 (4834572253956798917) -->
- <skip />
- <!-- no translation found for profile_label_test (9168641926186071947) -->
- <skip />
- <!-- no translation found for profile_label_communal (8743921499944800427) -->
- <skip />
+ <string name="profile_label_private" msgid="6463418670715290696">"Gizli"</string>
+ <string name="profile_label_clone" msgid="769106052210954285">"Klon"</string>
+ <string name="profile_label_work" msgid="3495359133038584618">"İş"</string>
+ <string name="profile_label_work_2" msgid="4691533661598632135">"İş 2"</string>
+ <string name="profile_label_work_3" msgid="4834572253956798917">"İş 3"</string>
+ <string name="profile_label_test" msgid="9168641926186071947">"Test"</string>
+ <string name="profile_label_communal" msgid="8743921499944800427">"Paylaşılan"</string>
</resources>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index b1adf52..b0421ee 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -2361,18 +2361,11 @@
<string name="keyboard_layout_notification_more_than_three_selected_message" msgid="1581834181578206937">"Вибрано такі розкладки клавіатури: <xliff:g id="LAYOUT_1">%1$s</xliff:g>, <xliff:g id="LAYOUT_2">%2$s</xliff:g>, <xliff:g id="LAYOUT_3">%3$s</xliff:g>… Натисніть, щоб змінити."</string>
<string name="keyboard_layout_notification_multiple_selected_title" msgid="5242444914367024499">"Фізичні клавіатури налаштовано"</string>
<string name="keyboard_layout_notification_multiple_selected_message" msgid="6576533454124419202">"Натисніть, щоб переглянути клавіатури"</string>
- <!-- no translation found for profile_label_private (6463418670715290696) -->
- <skip />
- <!-- no translation found for profile_label_clone (769106052210954285) -->
- <skip />
- <!-- no translation found for profile_label_work (3495359133038584618) -->
- <skip />
- <!-- no translation found for profile_label_work_2 (4691533661598632135) -->
- <skip />
- <!-- no translation found for profile_label_work_3 (4834572253956798917) -->
- <skip />
- <!-- no translation found for profile_label_test (9168641926186071947) -->
- <skip />
- <!-- no translation found for profile_label_communal (8743921499944800427) -->
- <skip />
+ <string name="profile_label_private" msgid="6463418670715290696">"Приватний профіль"</string>
+ <string name="profile_label_clone" msgid="769106052210954285">"Копія профілю"</string>
+ <string name="profile_label_work" msgid="3495359133038584618">"Робочий профіль"</string>
+ <string name="profile_label_work_2" msgid="4691533661598632135">"Робочий профіль 2"</string>
+ <string name="profile_label_work_3" msgid="4834572253956798917">"Робочий профіль 3"</string>
+ <string name="profile_label_test" msgid="9168641926186071947">"Тестовий профіль"</string>
+ <string name="profile_label_communal" msgid="8743921499944800427">"Спільний профіль"</string>
</resources>
diff --git a/core/res/res/values-ur/strings.xml b/core/res/res/values-ur/strings.xml
index 92fd266..767ee1c 100644
--- a/core/res/res/values-ur/strings.xml
+++ b/core/res/res/values-ur/strings.xml
@@ -2359,18 +2359,11 @@
<string name="keyboard_layout_notification_more_than_three_selected_message" msgid="1581834181578206937">"کی بورڈ لے آؤٹ <xliff:g id="LAYOUT_1">%1$s</xliff:g>، <xliff:g id="LAYOUT_2">%2$s</xliff:g>، <xliff:g id="LAYOUT_3">%3$s</xliff:g> پر سیٹ ہے… تبدیل کرنے کے لیے تھپتھپائیں۔"</string>
<string name="keyboard_layout_notification_multiple_selected_title" msgid="5242444914367024499">"فزیکل کی بورڈز کنفیگر کئے گئے"</string>
<string name="keyboard_layout_notification_multiple_selected_message" msgid="6576533454124419202">"کی بورڈز دیکھنے کے لیے تھپتھپائیں"</string>
- <!-- no translation found for profile_label_private (6463418670715290696) -->
- <skip />
- <!-- no translation found for profile_label_clone (769106052210954285) -->
- <skip />
- <!-- no translation found for profile_label_work (3495359133038584618) -->
- <skip />
- <!-- no translation found for profile_label_work_2 (4691533661598632135) -->
- <skip />
- <!-- no translation found for profile_label_work_3 (4834572253956798917) -->
- <skip />
- <!-- no translation found for profile_label_test (9168641926186071947) -->
- <skip />
- <!-- no translation found for profile_label_communal (8743921499944800427) -->
- <skip />
+ <string name="profile_label_private" msgid="6463418670715290696">"نجی"</string>
+ <string name="profile_label_clone" msgid="769106052210954285">"کلون"</string>
+ <string name="profile_label_work" msgid="3495359133038584618">"دفتری پروفائل"</string>
+ <string name="profile_label_work_2" msgid="4691533661598632135">"دوسری دفتری پروفائل"</string>
+ <string name="profile_label_work_3" msgid="4834572253956798917">"تیسری دفتری پروفائل"</string>
+ <string name="profile_label_test" msgid="9168641926186071947">"ٹیسٹ"</string>
+ <string name="profile_label_communal" msgid="8743921499944800427">"کمیونل"</string>
</resources>
diff --git a/core/res/res/values-uz/strings.xml b/core/res/res/values-uz/strings.xml
index 79d9f9d..e48d641 100644
--- a/core/res/res/values-uz/strings.xml
+++ b/core/res/res/values-uz/strings.xml
@@ -2359,18 +2359,11 @@
<string name="keyboard_layout_notification_more_than_three_selected_message" msgid="1581834181578206937">"Klaviatura terilmasi bunga sozlandi: <xliff:g id="LAYOUT_1">%1$s</xliff:g>, <xliff:g id="LAYOUT_2">%2$s</xliff:g>, <xliff:g id="LAYOUT_3">%3$s</xliff:g>… Oʻzgartirish uchun ustiga bosing."</string>
<string name="keyboard_layout_notification_multiple_selected_title" msgid="5242444914367024499">"Tashqi klaviaturalar sozlandi"</string>
<string name="keyboard_layout_notification_multiple_selected_message" msgid="6576533454124419202">"Klaviaturalarni ochish uchun ustiga bosing"</string>
- <!-- no translation found for profile_label_private (6463418670715290696) -->
- <skip />
- <!-- no translation found for profile_label_clone (769106052210954285) -->
- <skip />
- <!-- no translation found for profile_label_work (3495359133038584618) -->
- <skip />
- <!-- no translation found for profile_label_work_2 (4691533661598632135) -->
- <skip />
- <!-- no translation found for profile_label_work_3 (4834572253956798917) -->
- <skip />
- <!-- no translation found for profile_label_test (9168641926186071947) -->
- <skip />
- <!-- no translation found for profile_label_communal (8743921499944800427) -->
- <skip />
+ <string name="profile_label_private" msgid="6463418670715290696">"Yopiq"</string>
+ <string name="profile_label_clone" msgid="769106052210954285">"Nusxasini yaratish"</string>
+ <string name="profile_label_work" msgid="3495359133038584618">"Ish"</string>
+ <string name="profile_label_work_2" msgid="4691533661598632135">"Ish 2"</string>
+ <string name="profile_label_work_3" msgid="4834572253956798917">"Ish 3"</string>
+ <string name="profile_label_test" msgid="9168641926186071947">"Test"</string>
+ <string name="profile_label_communal" msgid="8743921499944800427">"Umumiy"</string>
</resources>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index 2ddf49f..a14fa75 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -2359,18 +2359,11 @@
<string name="keyboard_layout_notification_more_than_three_selected_message" msgid="1581834181578206937">"Đã thiết lập bố cục bàn phím thành <xliff:g id="LAYOUT_1">%1$s</xliff:g>, <xliff:g id="LAYOUT_2">%2$s</xliff:g>, <xliff:g id="LAYOUT_3">%3$s</xliff:g>… Hãy nhấn để thay đổi."</string>
<string name="keyboard_layout_notification_multiple_selected_title" msgid="5242444914367024499">"Đã định cấu hình bàn phím vật lý"</string>
<string name="keyboard_layout_notification_multiple_selected_message" msgid="6576533454124419202">"Nhấn để xem bàn phím"</string>
- <!-- no translation found for profile_label_private (6463418670715290696) -->
- <skip />
- <!-- no translation found for profile_label_clone (769106052210954285) -->
- <skip />
- <!-- no translation found for profile_label_work (3495359133038584618) -->
- <skip />
- <!-- no translation found for profile_label_work_2 (4691533661598632135) -->
- <skip />
- <!-- no translation found for profile_label_work_3 (4834572253956798917) -->
- <skip />
- <!-- no translation found for profile_label_test (9168641926186071947) -->
- <skip />
- <!-- no translation found for profile_label_communal (8743921499944800427) -->
- <skip />
+ <string name="profile_label_private" msgid="6463418670715290696">"Riêng tư"</string>
+ <string name="profile_label_clone" msgid="769106052210954285">"Sao chép"</string>
+ <string name="profile_label_work" msgid="3495359133038584618">"Công việc"</string>
+ <string name="profile_label_work_2" msgid="4691533661598632135">"Công việc 2"</string>
+ <string name="profile_label_work_3" msgid="4834572253956798917">"Công việc 3"</string>
+ <string name="profile_label_test" msgid="9168641926186071947">"Kiểm thử"</string>
+ <string name="profile_label_communal" msgid="8743921499944800427">"Dùng chung"</string>
</resources>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index f3b6a39..db98b34 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -2359,18 +2359,11 @@
<string name="keyboard_layout_notification_more_than_three_selected_message" msgid="1581834181578206937">"键盘布局已设为<xliff:g id="LAYOUT_1">%1$s</xliff:g>、<xliff:g id="LAYOUT_2">%2$s</xliff:g>、<xliff:g id="LAYOUT_3">%3$s</xliff:g>…点按即可更改。"</string>
<string name="keyboard_layout_notification_multiple_selected_title" msgid="5242444914367024499">"已配置物理键盘"</string>
<string name="keyboard_layout_notification_multiple_selected_message" msgid="6576533454124419202">"点按即可查看键盘"</string>
- <!-- no translation found for profile_label_private (6463418670715290696) -->
- <skip />
- <!-- no translation found for profile_label_clone (769106052210954285) -->
- <skip />
- <!-- no translation found for profile_label_work (3495359133038584618) -->
- <skip />
- <!-- no translation found for profile_label_work_2 (4691533661598632135) -->
- <skip />
- <!-- no translation found for profile_label_work_3 (4834572253956798917) -->
- <skip />
- <!-- no translation found for profile_label_test (9168641926186071947) -->
- <skip />
- <!-- no translation found for profile_label_communal (8743921499944800427) -->
- <skip />
+ <string name="profile_label_private" msgid="6463418670715290696">"私密"</string>
+ <string name="profile_label_clone" msgid="769106052210954285">"克隆"</string>
+ <string name="profile_label_work" msgid="3495359133038584618">"工作"</string>
+ <string name="profile_label_work_2" msgid="4691533661598632135">"工作 2"</string>
+ <string name="profile_label_work_3" msgid="4834572253956798917">"工作 3"</string>
+ <string name="profile_label_test" msgid="9168641926186071947">"测试"</string>
+ <string name="profile_label_communal" msgid="8743921499944800427">"共用"</string>
</resources>
diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml
index bf72080..b3e7959 100644
--- a/core/res/res/values-zh-rHK/strings.xml
+++ b/core/res/res/values-zh-rHK/strings.xml
@@ -2359,18 +2359,11 @@
<string name="keyboard_layout_notification_more_than_three_selected_message" msgid="1581834181578206937">"鍵盤版面配置已設定為<xliff:g id="LAYOUT_1">%1$s</xliff:g>、<xliff:g id="LAYOUT_2">%2$s</xliff:g>、<xliff:g id="LAYOUT_3">%3$s</xliff:g>…輕按即可變更。"</string>
<string name="keyboard_layout_notification_multiple_selected_title" msgid="5242444914367024499">"已設定實體鍵盤"</string>
<string name="keyboard_layout_notification_multiple_selected_message" msgid="6576533454124419202">"輕按即可查看鍵盤"</string>
- <!-- no translation found for profile_label_private (6463418670715290696) -->
- <skip />
- <!-- no translation found for profile_label_clone (769106052210954285) -->
- <skip />
- <!-- no translation found for profile_label_work (3495359133038584618) -->
- <skip />
- <!-- no translation found for profile_label_work_2 (4691533661598632135) -->
- <skip />
- <!-- no translation found for profile_label_work_3 (4834572253956798917) -->
- <skip />
- <!-- no translation found for profile_label_test (9168641926186071947) -->
- <skip />
- <!-- no translation found for profile_label_communal (8743921499944800427) -->
- <skip />
+ <string name="profile_label_private" msgid="6463418670715290696">"私人"</string>
+ <string name="profile_label_clone" msgid="769106052210954285">"複製"</string>
+ <string name="profile_label_work" msgid="3495359133038584618">"工作"</string>
+ <string name="profile_label_work_2" msgid="4691533661598632135">"工作 2"</string>
+ <string name="profile_label_work_3" msgid="4834572253956798917">"工作 3"</string>
+ <string name="profile_label_test" msgid="9168641926186071947">"測試"</string>
+ <string name="profile_label_communal" msgid="8743921499944800427">"共用"</string>
</resources>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index 1158cfd..247499d 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -2359,18 +2359,11 @@
<string name="keyboard_layout_notification_more_than_three_selected_message" msgid="1581834181578206937">"鍵盤配置已設為<xliff:g id="LAYOUT_1">%1$s</xliff:g>、<xliff:g id="LAYOUT_2">%2$s</xliff:g>、<xliff:g id="LAYOUT_3">%3$s</xliff:g>…輕觸即可變更。"</string>
<string name="keyboard_layout_notification_multiple_selected_title" msgid="5242444914367024499">"已設定實體鍵盤"</string>
<string name="keyboard_layout_notification_multiple_selected_message" msgid="6576533454124419202">"輕觸即可查看鍵盤"</string>
- <!-- no translation found for profile_label_private (6463418670715290696) -->
- <skip />
- <!-- no translation found for profile_label_clone (769106052210954285) -->
- <skip />
- <!-- no translation found for profile_label_work (3495359133038584618) -->
- <skip />
- <!-- no translation found for profile_label_work_2 (4691533661598632135) -->
- <skip />
- <!-- no translation found for profile_label_work_3 (4834572253956798917) -->
- <skip />
- <!-- no translation found for profile_label_test (9168641926186071947) -->
- <skip />
- <!-- no translation found for profile_label_communal (8743921499944800427) -->
- <skip />
+ <string name="profile_label_private" msgid="6463418670715290696">"私人"</string>
+ <string name="profile_label_clone" msgid="769106052210954285">"副本"</string>
+ <string name="profile_label_work" msgid="3495359133038584618">"工作"</string>
+ <string name="profile_label_work_2" msgid="4691533661598632135">"工作 2"</string>
+ <string name="profile_label_work_3" msgid="4834572253956798917">"工作 3"</string>
+ <string name="profile_label_test" msgid="9168641926186071947">"測試"</string>
+ <string name="profile_label_communal" msgid="8743921499944800427">"通用"</string>
</resources>
diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml
index db7c253..976a35e 100644
--- a/core/res/res/values-zu/strings.xml
+++ b/core/res/res/values-zu/strings.xml
@@ -2359,18 +2359,11 @@
<string name="keyboard_layout_notification_more_than_three_selected_message" msgid="1581834181578206937">"Uhlaka lwekhibhodi lusethelwe ku-<xliff:g id="LAYOUT_1">%1$s</xliff:g>, <xliff:g id="LAYOUT_2">%2$s</xliff:g>, <xliff:g id="LAYOUT_3">%3$s</xliff:g>… Thepha ukuze ushintshe."</string>
<string name="keyboard_layout_notification_multiple_selected_title" msgid="5242444914367024499">"Amakhibhodi aphathekayo amisiwe"</string>
<string name="keyboard_layout_notification_multiple_selected_message" msgid="6576533454124419202">"Thepha ukuze ubuke amakhibhodi"</string>
- <!-- no translation found for profile_label_private (6463418670715290696) -->
- <skip />
- <!-- no translation found for profile_label_clone (769106052210954285) -->
- <skip />
- <!-- no translation found for profile_label_work (3495359133038584618) -->
- <skip />
- <!-- no translation found for profile_label_work_2 (4691533661598632135) -->
- <skip />
- <!-- no translation found for profile_label_work_3 (4834572253956798917) -->
- <skip />
- <!-- no translation found for profile_label_test (9168641926186071947) -->
- <skip />
- <!-- no translation found for profile_label_communal (8743921499944800427) -->
- <skip />
+ <string name="profile_label_private" msgid="6463418670715290696">"Okuyimfihlo"</string>
+ <string name="profile_label_clone" msgid="769106052210954285">"Yenza i-Clone"</string>
+ <string name="profile_label_work" msgid="3495359133038584618">"Umsebenzi"</string>
+ <string name="profile_label_work_2" msgid="4691533661598632135">"Umsebenzi 2"</string>
+ <string name="profile_label_work_3" msgid="4834572253956798917">"Umsebenzi 3"</string>
+ <string name="profile_label_test" msgid="9168641926186071947">"Hlola"</string>
+ <string name="profile_label_communal" msgid="8743921499944800427">"Okomphakathi"</string>
</resources>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index ba1f392..1229453 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -693,6 +693,16 @@
-->
</integer-array>
+ <!-- The device states (supplied by DeviceStateManager) that should be treated as concurrent
+ display state. Default is empty. -->
+ <integer-array name="config_concurrentDisplayDeviceStates">
+ <!-- Example:
+ <item>0</item>
+ <item>1</item>
+ <item>2</item>
+ -->
+ </integer-array>
+
<!-- Indicates whether the window manager reacts to half-fold device states by overriding
rotation. -->
<bool name="config_windowManagerHalfFoldAutoRotateOverride">false</bool>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 7787c5d..93aacdf 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -4142,6 +4142,7 @@
<java-symbol type="array" name="config_foldedDeviceStates" />
<java-symbol type="array" name="config_halfFoldedDeviceStates" />
<java-symbol type="array" name="config_rearDisplayDeviceStates" />
+ <java-symbol type="array" name="config_concurrentDisplayDeviceStates" />
<java-symbol type="bool" name="config_windowManagerHalfFoldAutoRotateOverride" />
<java-symbol type="bool" name="config_windowManagerPauseRotationWhenUnfolding" />
<java-symbol type="integer" name="config_pauseRotationWhenUnfolding_hingeEventTimeout" />
diff --git a/core/res/res/values/themes_material.xml b/core/res/res/values/themes_material.xml
index cd4c0d6..8e2fb34 100644
--- a/core/res/res/values/themes_material.xml
+++ b/core/res/res/values/themes_material.xml
@@ -181,6 +181,7 @@
<item name="windowSharedElementExitTransition">@transition/move</item>
<item name="windowContentTransitions">false</item>
<item name="windowActivityTransitions">true</item>
+ <item name="windowSwipeToDismiss">@empty</item>
<!-- Dialog attributes -->
<item name="dialogTheme">@style/ThemeOverlay.Material.Dialog</item>
@@ -554,6 +555,7 @@
<item name="windowSharedElementExitTransition">@transition/move</item>
<item name="windowContentTransitions">false</item>
<item name="windowActivityTransitions">true</item>
+ <item name="windowSwipeToDismiss">@empty</item>
<!-- Dialog attributes -->
<item name="dialogTheme">@style/ThemeOverlay.Material.Dialog</item>
diff --git a/core/tests/coretests/Android.bp b/core/tests/coretests/Android.bp
index 37f592f..0ad349b 100644
--- a/core/tests/coretests/Android.bp
+++ b/core/tests/coretests/Android.bp
@@ -167,12 +167,24 @@
android_ravenwood_test {
name: "FrameworksCoreTestsRavenwood",
+ libs: [
+ "android.test.runner",
+ "android.test.base",
+ ],
static_libs: [
+ "core-test-rules", // for libcore.dalvik.system.CloseGuardSupport
+ "androidx.core_core",
"androidx.annotation_annotation",
"androidx.test.rules",
+ "androidx.test.ext.junit",
+ "mockito_ravenwood",
+ "platform-test-annotations",
],
srcs: [
"src/android/os/FileUtilsTest.java",
+ "src/android/util/**/*.java",
+ "src/com/android/internal/util/**/*.java",
+ "testdoubles/src/com/android/internal/util/**/*.java",
],
auto_gen_config: true,
}
diff --git a/core/tests/coretests/src/android/util/ArrayMapTest.java b/core/tests/coretests/src/android/util/ArrayMapTest.java
index b212cf6..1e444ad 100644
--- a/core/tests/coretests/src/android/util/ArrayMapTest.java
+++ b/core/tests/coretests/src/android/util/ArrayMapTest.java
@@ -14,11 +14,17 @@
package android.util;
+import static org.junit.Assert.fail;
+
+import android.platform.test.annotations.IgnoreUnderRavenwood;
+import android.platform.test.ravenwood.RavenwoodRule;
+
import androidx.test.filters.LargeTest;
+import androidx.test.runner.AndroidJUnit4;
-import junit.framework.TestCase;
-
+import org.junit.Rule;
import org.junit.Test;
+import org.junit.runner.RunWith;
import java.util.ConcurrentModificationException;
@@ -26,10 +32,14 @@
* Unit tests for ArrayMap that don't belong in CTS.
*/
@LargeTest
-public class ArrayMapTest extends TestCase {
+@RunWith(AndroidJUnit4.class)
+public class ArrayMapTest {
private static final String TAG = "ArrayMapTest";
ArrayMap<String, String> map = new ArrayMap<>();
+ @Rule
+ public final RavenwoodRule mRavenwood = new RavenwoodRule();
+
/**
* Attempt to generate a ConcurrentModificationException in ArrayMap.
* <p>
@@ -41,6 +51,7 @@
* @throws Exception
*/
@Test
+ @IgnoreUnderRavenwood(reason = "Long test runtime")
public void testConcurrentModificationException() throws Exception {
final int TEST_LEN_MS = 5000;
System.out.println("Starting ArrayMap concurrency test");
diff --git a/core/tests/coretests/src/android/util/ArraySetTest.java b/core/tests/coretests/src/android/util/ArraySetTest.java
index f1bebfb..51de634 100644
--- a/core/tests/coretests/src/android/util/ArraySetTest.java
+++ b/core/tests/coretests/src/android/util/ArraySetTest.java
@@ -16,12 +16,14 @@
package android.util;
-import androidx.test.filters.LargeTest;
+import static org.junit.Assert.fail;
-import junit.framework.TestCase;
+import androidx.test.filters.LargeTest;
+import androidx.test.runner.AndroidJUnit4;
import org.junit.After;
import org.junit.Test;
+import org.junit.runner.RunWith;
import java.util.ConcurrentModificationException;
@@ -29,7 +31,8 @@
* Unit tests for ArraySet that don't belong in CTS.
*/
@LargeTest
-public class ArraySetTest extends TestCase {
+@RunWith(AndroidJUnit4.class)
+public class ArraySetTest {
private static final String TAG = "ArraySetTest";
ArraySet<String> mSet = new ArraySet<>();
diff --git a/core/tests/coretests/src/android/util/Base64Test.java b/core/tests/coretests/src/android/util/Base64Test.java
index 15c51af..b648266 100644
--- a/core/tests/coretests/src/android/util/Base64Test.java
+++ b/core/tests/coretests/src/android/util/Base64Test.java
@@ -16,9 +16,16 @@
package android.util;
-import androidx.test.filters.LargeTest;
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
-import junit.framework.TestCase;
+import androidx.test.filters.LargeTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Ignore;
+import org.junit.Test;
+import org.junit.runner.RunWith;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
@@ -32,7 +39,8 @@
import java.util.stream.Collectors;
@LargeTest
-public class Base64Test extends TestCase {
+@RunWith(AndroidJUnit4.class)
+public class Base64Test {
private static final String TAG = "Base64Test";
/** Decodes a string, returning a string. */
@@ -62,7 +70,7 @@
}
/** Assert that actual equals the first len bytes of expected. */
- private void assertEquals(byte[] expected, int len, byte[] actual) {
+ private void assertPartialEquals(byte[] expected, int len, byte[] actual) {
assertEquals(len, actual.length);
for (int i = 0; i < len; ++i) {
assertEquals(expected[i], actual[i]);
@@ -70,21 +78,14 @@
}
/** Assert that actual equals the first len bytes of expected. */
- private void assertEquals(byte[] expected, int len, byte[] actual, int alen) {
+ private void assertPartialEquals(byte[] expected, int len, byte[] actual, int alen) {
assertEquals(len, alen);
for (int i = 0; i < len; ++i) {
assertEquals(expected[i], actual[i]);
}
}
- /** Assert that actual equals the first len bytes of expected. */
- private void assertEquals(byte[] expected, byte[] actual) {
- assertEquals(expected.length, actual.length);
- for (int i = 0; i < expected.length; ++i) {
- assertEquals(expected[i], actual[i]);
- }
- }
-
+ @Test
public void testDecodeExtraChars() throws Exception {
// padding 0
assertEquals("hello, world", decodeString("aGVsbG8sIHdvcmxk"));
@@ -131,28 +132,30 @@
(byte) 0xcc, (byte) 0xbb, (byte) 0xaa,
(byte) 0x99, (byte) 0x88, (byte) 0x77 };
+ @Test
public void testBinaryDecode() throws Exception {
- assertEquals(BYTES, 0, Base64.decode("", 0));
- assertEquals(BYTES, 1, Base64.decode("/w==", 0));
- assertEquals(BYTES, 2, Base64.decode("/+4=", 0));
- assertEquals(BYTES, 3, Base64.decode("/+7d", 0));
- assertEquals(BYTES, 4, Base64.decode("/+7dzA==", 0));
- assertEquals(BYTES, 5, Base64.decode("/+7dzLs=", 0));
- assertEquals(BYTES, 6, Base64.decode("/+7dzLuq", 0));
- assertEquals(BYTES, 7, Base64.decode("/+7dzLuqmQ==", 0));
- assertEquals(BYTES, 8, Base64.decode("/+7dzLuqmYg=", 0));
+ assertPartialEquals(BYTES, 0, Base64.decode("", 0));
+ assertPartialEquals(BYTES, 1, Base64.decode("/w==", 0));
+ assertPartialEquals(BYTES, 2, Base64.decode("/+4=", 0));
+ assertPartialEquals(BYTES, 3, Base64.decode("/+7d", 0));
+ assertPartialEquals(BYTES, 4, Base64.decode("/+7dzA==", 0));
+ assertPartialEquals(BYTES, 5, Base64.decode("/+7dzLs=", 0));
+ assertPartialEquals(BYTES, 6, Base64.decode("/+7dzLuq", 0));
+ assertPartialEquals(BYTES, 7, Base64.decode("/+7dzLuqmQ==", 0));
+ assertPartialEquals(BYTES, 8, Base64.decode("/+7dzLuqmYg=", 0));
}
+ @Test
public void testWebSafe() throws Exception {
- assertEquals(BYTES, 0, Base64.decode("", Base64.URL_SAFE));
- assertEquals(BYTES, 1, Base64.decode("_w==", Base64.URL_SAFE));
- assertEquals(BYTES, 2, Base64.decode("_-4=", Base64.URL_SAFE));
- assertEquals(BYTES, 3, Base64.decode("_-7d", Base64.URL_SAFE));
- assertEquals(BYTES, 4, Base64.decode("_-7dzA==", Base64.URL_SAFE));
- assertEquals(BYTES, 5, Base64.decode("_-7dzLs=", Base64.URL_SAFE));
- assertEquals(BYTES, 6, Base64.decode("_-7dzLuq", Base64.URL_SAFE));
- assertEquals(BYTES, 7, Base64.decode("_-7dzLuqmQ==", Base64.URL_SAFE));
- assertEquals(BYTES, 8, Base64.decode("_-7dzLuqmYg=", Base64.URL_SAFE));
+ assertPartialEquals(BYTES, 0, Base64.decode("", Base64.URL_SAFE));
+ assertPartialEquals(BYTES, 1, Base64.decode("_w==", Base64.URL_SAFE));
+ assertPartialEquals(BYTES, 2, Base64.decode("_-4=", Base64.URL_SAFE));
+ assertPartialEquals(BYTES, 3, Base64.decode("_-7d", Base64.URL_SAFE));
+ assertPartialEquals(BYTES, 4, Base64.decode("_-7dzA==", Base64.URL_SAFE));
+ assertPartialEquals(BYTES, 5, Base64.decode("_-7dzLs=", Base64.URL_SAFE));
+ assertPartialEquals(BYTES, 6, Base64.decode("_-7dzLuq", Base64.URL_SAFE));
+ assertPartialEquals(BYTES, 7, Base64.decode("_-7dzLuqmQ==", Base64.URL_SAFE));
+ assertPartialEquals(BYTES, 8, Base64.decode("_-7dzLuqmYg=", Base64.URL_SAFE));
assertEquals("", Base64.encodeToString(BYTES, 0, 0, Base64.URL_SAFE));
assertEquals("_w==\n", Base64.encodeToString(BYTES, 0, 1, Base64.URL_SAFE));
@@ -165,6 +168,7 @@
assertEquals("_-7dzLuqmYg=\n", Base64.encodeToString(BYTES, 0, 8, Base64.URL_SAFE));
}
+ @Test
public void testFlags() throws Exception {
assertEquals("YQ==\n", encodeToString("a", 0));
assertEquals("YQ==", encodeToString("a", Base64.NO_WRAP));
@@ -195,6 +199,7 @@
assertEquals("YWJjZA\r\n", encodeToString("abcd", Base64.CRLF | Base64.NO_PADDING));
}
+ @Test
public void testLineLength() throws Exception {
String in_56 = "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcd";
String in_57 = in_56 + "e";
@@ -245,7 +250,9 @@
* us to get at package-private members (Base64.Encoder in
* this case).
*/
- public void XXXtestEncodeInternal() throws Exception {
+ @Test
+ @Ignore
+ public void testEncodeInternal() throws Exception {
byte[] input = { (byte) 0x61, (byte) 0x62, (byte) 0x63 };
byte[] output = new byte[100];
@@ -253,11 +260,11 @@
output);
encoder.process(input, 0, 3, false);
- assertEquals("YWJj".getBytes(), 4, encoder.output, encoder.op);
+ assertPartialEquals("YWJj".getBytes(), 4, encoder.output, encoder.op);
assertEquals(0, encoder.tailLen);
encoder.process(input, 0, 3, false);
- assertEquals("YWJj".getBytes(), 4, encoder.output, encoder.op);
+ assertPartialEquals("YWJj".getBytes(), 4, encoder.output, encoder.op);
assertEquals(0, encoder.tailLen);
encoder.process(input, 0, 1, false);
@@ -269,7 +276,7 @@
assertEquals(2, encoder.tailLen);
encoder.process(input, 0, 1, false);
- assertEquals("YWFh".getBytes(), 4, encoder.output, encoder.op);
+ assertPartialEquals("YWFh".getBytes(), 4, encoder.output, encoder.op);
assertEquals(0, encoder.tailLen);
encoder.process(input, 0, 2, false);
@@ -277,15 +284,15 @@
assertEquals(2, encoder.tailLen);
encoder.process(input, 0, 2, false);
- assertEquals("YWJh".getBytes(), 4, encoder.output, encoder.op);
+ assertPartialEquals("YWJh".getBytes(), 4, encoder.output, encoder.op);
assertEquals(1, encoder.tailLen);
encoder.process(input, 0, 2, false);
- assertEquals("YmFi".getBytes(), 4, encoder.output, encoder.op);
+ assertPartialEquals("YmFi".getBytes(), 4, encoder.output, encoder.op);
assertEquals(0, encoder.tailLen);
encoder.process(input, 0, 1, true);
- assertEquals("YQ".getBytes(), 2, encoder.output, encoder.op);
+ assertPartialEquals("YQ".getBytes(), 2, encoder.output, encoder.op);
}
private static final String lipsum =
@@ -311,6 +318,7 @@
"molestie dapibus commodo. Ut vel tellus at massa gravida " +
"semper non sed orci.";
+ @Test
public void testInputStream() throws Exception {
int[] flagses = { Base64.DEFAULT,
Base64.NO_PADDING,
@@ -343,7 +351,7 @@
while ((b = b64is.read(actual, ap, actual.length-ap)) != -1) {
ap += b;
}
- assertEquals(actual, ap, plain);
+ assertPartialEquals(actual, ap, plain);
// read individual bytes
bais = new ByteArrayInputStream(encoded);
@@ -352,7 +360,7 @@
while ((b = b64is.read()) != -1) {
actual[ap++] = (byte) b;
}
- assertEquals(actual, ap, plain);
+ assertPartialEquals(actual, ap, plain);
// mix reads of variously-sized arrays with one-byte reads
bais = new ByteArrayInputStream(encoded);
@@ -371,7 +379,7 @@
}
}
}
- assertEquals(actual, ap, plain);
+ assertPartialEquals(actual, ap, plain);
// ----- test encoding ("plain" -> "encoded") -----
@@ -382,7 +390,7 @@
while ((b = b64is.read(actual, ap, actual.length-ap)) != -1) {
ap += b;
}
- assertEquals(actual, ap, encoded);
+ assertPartialEquals(actual, ap, encoded);
// read individual bytes
bais = new ByteArrayInputStream(plain);
@@ -391,7 +399,7 @@
while ((b = b64is.read()) != -1) {
actual[ap++] = (byte) b;
}
- assertEquals(actual, ap, encoded);
+ assertPartialEquals(actual, ap, encoded);
// mix reads of variously-sized arrays with one-byte reads
bais = new ByteArrayInputStream(plain);
@@ -410,11 +418,12 @@
}
}
}
- assertEquals(actual, ap, encoded);
+ assertPartialEquals(actual, ap, encoded);
}
}
/** http://b/3026478 */
+ @Test
public void testSingleByteReads() throws IOException {
InputStream in = new Base64InputStream(
new ByteArrayInputStream("/v8=".getBytes()), Base64.DEFAULT);
@@ -426,6 +435,7 @@
* Tests that Base64OutputStream produces exactly the same results
* as calling Base64.encode/.decode on an in-memory array.
*/
+ @Test
public void testOutputStream() throws Exception {
int[] flagses = { Base64.DEFAULT,
Base64.NO_PADDING,
@@ -456,7 +466,7 @@
b64os.write(plain);
b64os.close();
actual = baos.toByteArray();
- assertEquals(encoded, actual);
+ assertArrayEquals(encoded, actual);
// many calls to write(int)
baos = new ByteArrayOutputStream();
@@ -466,7 +476,7 @@
}
b64os.close();
actual = baos.toByteArray();
- assertEquals(encoded, actual);
+ assertArrayEquals(encoded, actual);
// intermixed sequences of write(int) with
// write(byte[],int,int) of various lengths.
@@ -489,7 +499,7 @@
}
b64os.close();
actual = baos.toByteArray();
- assertEquals(encoded, actual);
+ assertArrayEquals(encoded, actual);
// ----- test decoding ("encoded" -> "plain") -----
@@ -499,7 +509,7 @@
b64os.write(encoded);
b64os.close();
actual = baos.toByteArray();
- assertEquals(plain, actual);
+ assertArrayEquals(plain, actual);
// many calls to write(int)
baos = new ByteArrayOutputStream();
@@ -509,7 +519,7 @@
}
b64os.close();
actual = baos.toByteArray();
- assertEquals(plain, actual);
+ assertArrayEquals(plain, actual);
// intermixed sequences of write(int) with
// write(byte[],int,int) of various lengths.
@@ -532,10 +542,11 @@
}
b64os.close();
actual = baos.toByteArray();
- assertEquals(plain, actual);
+ assertArrayEquals(plain, actual);
}
}
+ @Test
public void testOutputStream_ioExceptionDuringClose() {
OutputStream out = new OutputStream() {
@Override public void write(int b) throws IOException { }
@@ -551,6 +562,7 @@
}
}
+ @Test
public void testOutputStream_ioExceptionDuringCloseAndWrite() {
OutputStream out = new OutputStream() {
@Override public void write(int b) throws IOException {
@@ -583,6 +595,7 @@
}
}
+ @Test
public void testOutputStream_ioExceptionDuringWrite() {
OutputStream out = new OutputStream() {
@Override public void write(int b) throws IOException {
diff --git a/core/tests/coretests/src/android/util/CharsetUtilsTest.java b/core/tests/coretests/src/android/util/CharsetUtilsTest.java
index c295451..fbbe311 100644
--- a/core/tests/coretests/src/android/util/CharsetUtilsTest.java
+++ b/core/tests/coretests/src/android/util/CharsetUtilsTest.java
@@ -18,6 +18,9 @@
import static org.junit.Assert.assertEquals;
+import android.platform.test.annotations.IgnoreUnderRavenwood;
+import android.platform.test.ravenwood.RavenwoodRule;
+
import androidx.test.runner.AndroidJUnit4;
import com.android.internal.util.HexDump;
@@ -25,18 +28,25 @@
import dalvik.system.VMRuntime;
import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(AndroidJUnit4.class)
+@IgnoreUnderRavenwood(blockedBy = CharsetUtils.class)
public class CharsetUtilsTest {
+ @Rule
+ public final RavenwoodRule mRavenwood = new RavenwoodRule();
+
private byte[] dest;
private long destPtr;
@Before
public void setUp() {
- dest = (byte[]) VMRuntime.getRuntime().newNonMovableArray(byte.class, 8);
- destPtr = VMRuntime.getRuntime().addressOf(dest);
+ if (!RavenwoodRule.isUnderRavenwood()) {
+ dest = (byte[]) VMRuntime.getRuntime().newNonMovableArray(byte.class, 8);
+ destPtr = VMRuntime.getRuntime().addressOf(dest);
+ }
}
@Test
diff --git a/core/tests/coretests/src/android/util/CloseGuardTest.java b/core/tests/coretests/src/android/util/CloseGuardTest.java
index d86c7b7..15c57b1 100644
--- a/core/tests/coretests/src/android/util/CloseGuardTest.java
+++ b/core/tests/coretests/src/android/util/CloseGuardTest.java
@@ -16,6 +16,9 @@
package android.util;
+import android.platform.test.annotations.IgnoreUnderRavenwood;
+import android.platform.test.ravenwood.RavenwoodRule;
+
import libcore.dalvik.system.CloseGuardSupport;
import org.junit.Rule;
@@ -23,10 +26,21 @@
import org.junit.rules.TestRule;
/** Unit tests for {@link android.util.CloseGuard} */
+@IgnoreUnderRavenwood(blockedBy = CloseGuard.class)
public class CloseGuardTest {
+ @Rule
+ public final RavenwoodRule mRavenwood = new RavenwoodRule();
@Rule
- public final TestRule rule = CloseGuardSupport.getRule();
+ public final TestRule rule;
+
+ public CloseGuardTest() {
+ if (!RavenwoodRule.isUnderRavenwood()) {
+ rule = CloseGuardSupport.getRule();
+ } else {
+ rule = null;
+ }
+ }
@Test
public void testEnabled_NotOpen() throws Throwable {
diff --git a/core/tests/coretests/src/android/util/DayOfMonthCursorTest.java b/core/tests/coretests/src/android/util/DayOfMonthCursorTest.java
index 572e9b0..72bd578 100644
--- a/core/tests/coretests/src/android/util/DayOfMonthCursorTest.java
+++ b/core/tests/coretests/src/android/util/DayOfMonthCursorTest.java
@@ -16,30 +16,40 @@
package android.util;
-import androidx.test.filters.SmallTest;
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
-import junit.framework.TestCase;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
import java.util.Calendar;
/**
* Unit tests for {@link DayOfMonthCursor}.
*/
-public class DayOfMonthCursorTest extends TestCase {
+@RunWith(AndroidJUnit4.class)
+public class DayOfMonthCursorTest {
+ @Test
@SmallTest
public void testMonthRows() {
DayOfMonthCursor mc = new DayOfMonthCursor(2007,
Calendar.SEPTEMBER, 11, Calendar.SUNDAY);
- assertArraysEqual(new int[]{26, 27, 28, 29, 30, 31, 1},
+ assertArrayEquals(new int[]{26, 27, 28, 29, 30, 31, 1},
mc.getDigitsForRow(0));
- assertArraysEqual(new int[]{2, 3, 4, 5, 6, 7, 8},
+ assertArrayEquals(new int[]{2, 3, 4, 5, 6, 7, 8},
mc.getDigitsForRow(1));
- assertArraysEqual(new int[]{30, 1, 2, 3, 4, 5, 6},
+ assertArrayEquals(new int[]{30, 1, 2, 3, 4, 5, 6},
mc.getDigitsForRow(5));
}
+ @Test
@SmallTest
public void testMoveLeft() {
DayOfMonthCursor mc = new DayOfMonthCursor(2007,
@@ -70,6 +80,7 @@
assertEquals(5, mc.getSelectedColumn());
}
+ @Test
@SmallTest
public void testMoveRight() {
DayOfMonthCursor mc = new DayOfMonthCursor(2007,
@@ -100,6 +111,7 @@
assertEquals(1, mc.getSelectedColumn());
}
+ @Test
@SmallTest
public void testMoveUp() {
DayOfMonthCursor mc = new DayOfMonthCursor(2007,
@@ -124,6 +136,7 @@
assertEquals(4, mc.getSelectedColumn());
}
+ @Test
@SmallTest
public void testMoveDown() {
DayOfMonthCursor mc = new DayOfMonthCursor(2007,
@@ -147,12 +160,4 @@
assertEquals(1, mc.getSelectedRow());
assertEquals(0, mc.getSelectedColumn());
}
-
- private void assertArraysEqual(int[] expected, int[] actual) {
- assertEquals("array length", expected.length, actual.length);
- for (int i = 0; i < expected.length; i++) {
- assertEquals("index " + i,
- expected[i], actual[i]);
- }
- }
}
diff --git a/core/tests/coretests/src/android/util/HashedStringCacheTest.java b/core/tests/coretests/src/android/util/HashedStringCacheTest.java
index 2292473..08c85ac 100644
--- a/core/tests/coretests/src/android/util/HashedStringCacheTest.java
+++ b/core/tests/coretests/src/android/util/HashedStringCacheTest.java
@@ -26,28 +26,37 @@
import android.content.SharedPreferences;
import android.os.Environment;
import android.os.storage.StorageManager;
+import android.platform.test.annotations.IgnoreUnderRavenwood;
+import android.platform.test.ravenwood.RavenwoodRule;
import androidx.test.InstrumentationRegistry;
import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
import java.io.File;
-
/**
* Unit tests for {@link HashedStringCache}.
*/
+@IgnoreUnderRavenwood(blockedBy = HashedStringCache.class)
public class HashedStringCacheTest {
private static final String TAG = "HashedStringCacheTest";
private Context mContext;
private static final String TEST_STRING = "test_string";
+ @Rule
+ public final RavenwoodRule mRavenwood = new RavenwoodRule();
+
@Before
public void setup() {
- mContext = null;
- mContext = InstrumentationRegistry.getContext();
- clearSharedPreferences();
+ if (!RavenwoodRule.isUnderRavenwood()) {
+ mContext = InstrumentationRegistry.getContext();
+ clearSharedPreferences();
+ } else {
+ mContext = null;
+ }
}
@Test
diff --git a/core/tests/coretests/src/android/util/LogNullabilityTest.java b/core/tests/coretests/src/android/util/LogNullabilityTest.java
index 370885d..475e347 100644
--- a/core/tests/coretests/src/android/util/LogNullabilityTest.java
+++ b/core/tests/coretests/src/android/util/LogNullabilityTest.java
@@ -19,6 +19,8 @@
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.fail;
+import android.platform.test.ravenwood.RavenwoodRule;
+
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
@@ -35,8 +37,10 @@
Log.i(null, "");
Log.w(null, "");
Log.e(null, "");
- Log.wtf(null, "");
- Log.wtfStack(null, "");
+ if (!RavenwoodRule.isUnderRavenwood()) {
+ Log.wtf(null, "");
+ Log.wtfStack(null, "");
+ }
Log.println(Log.INFO, null, "");
// Implicit assertions of not crashing.
@@ -49,7 +53,9 @@
Log.i(null, "", new Throwable());
Log.w(null, "", new Throwable());
Log.e(null, "", new Throwable());
- Log.wtf(null, "", new Throwable());
+ if (!RavenwoodRule.isUnderRavenwood()) {
+ Log.wtf(null, "", new Throwable());
+ }
Log.printlns(Log.LOG_ID_MAIN, Log.INFO, null, "", new Throwable());
// Implicit assertions of not crashing.
@@ -84,8 +90,10 @@
} catch (NullPointerException expected) {
}
- Log.wtf("", (String) null);
- Log.wtfStack("", (String) null);
+ if (!RavenwoodRule.isUnderRavenwood()) {
+ Log.wtf("", (String) null);
+ Log.wtfStack("", (String) null);
+ }
// Implicit assertion of not crashing.
@@ -103,15 +111,10 @@
Log.i("", null, new Throwable());
Log.w("", null, new Throwable());
Log.e("", null, new Throwable());
- Log.wtf("", null, new Throwable());
-
- // Implicit assertions of not crashing.
-
- try {
- Log.printlns(Log.LOG_ID_MAIN, Log.INFO, "", null, new Throwable());
- fail();
- } catch (NullPointerException expected) {
+ if (!RavenwoodRule.isUnderRavenwood()) {
+ Log.wtf("", null, new Throwable());
}
+ Log.printlns(Log.LOG_ID_MAIN, Log.INFO, "", null, new Throwable());
}
@Test
@@ -121,7 +124,9 @@
Log.i("", "", null);
Log.w("", "", null);
Log.e("", "", null);
- Log.wtf("", "", null);
+ if (!RavenwoodRule.isUnderRavenwood()) {
+ Log.wtf("", "", null);
+ }
// Warning has its own (String, Throwable) overload.
Log.w("", (Throwable) null);
@@ -131,10 +136,12 @@
// Implicit assertions of not crashing.
// WTF has its own (String, Throwable) overload with different behavior.
- try {
- Log.wtf("", (Throwable) null);
- fail();
- } catch (NullPointerException expected) {
+ if (!RavenwoodRule.isUnderRavenwood()) {
+ try {
+ Log.wtf("", (Throwable) null);
+ fail();
+ } catch (NullPointerException expected) {
+ }
}
}
@@ -145,15 +152,10 @@
Log.i("", null, null);
Log.w("", null, null);
Log.e("", null, null);
- Log.wtf("", null, null);
-
- // Implicit assertions of not crashing.
-
- try {
- Log.printlns(Log.LOG_ID_MAIN, Log.INFO, "", null, null);
- fail();
- } catch (NullPointerException expected) {
+ if (!RavenwoodRule.isUnderRavenwood()) {
+ Log.wtf("", null, null);
}
+ Log.printlns(Log.LOG_ID_MAIN, Log.INFO, "", null, null);
}
@Test
diff --git a/core/tests/coretests/src/android/util/LogTest.java b/core/tests/coretests/src/android/util/LogTest.java
index d783c12..f9966a1 100644
--- a/core/tests/coretests/src/android/util/LogTest.java
+++ b/core/tests/coretests/src/android/util/LogTest.java
@@ -20,23 +20,24 @@
import android.test.PerformanceTestCase;
import androidx.test.filters.Suppress;
+import androidx.test.runner.AndroidJUnit4;
import junit.framework.TestCase;
+import org.junit.Assert;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
//This is an empty TestCase.
@Suppress
-public class LogTest extends TestCase {
+@RunWith(AndroidJUnit4.class)
+public class LogTest {
private static final String PROPERTY_TAG = "log.tag.LogTest";
private static final String LOG_TAG = "LogTest";
-
- // TODO: remove this test once we uncomment out the following test.
- public void testLogTestDummy() {
- return;
- }
-
-
- /* TODO: This test is commented out because we will not be able to set properities. Fix the test.
+ @Test
+ @Ignore
public void testIsLoggable() {
// First clear any SystemProperty setting for our test key.
SystemProperties.set(PROPERTY_TAG, null);
@@ -129,8 +130,7 @@
Assert.assertFalse(Log.isLoggable(LOG_TAG, Log.ERROR));
Assert.assertFalse(Log.isLoggable(LOG_TAG, Log.ASSERT));
}
- */
-
+
public static class PerformanceTest extends TestCase implements PerformanceTestCase {
private static final int ITERATIONS = 1000;
diff --git a/core/tests/coretests/src/android/util/LongSparseLongArrayTest.java b/core/tests/coretests/src/android/util/LongSparseLongArrayTest.java
index a1d48e6..9dbaae0d 100644
--- a/core/tests/coretests/src/android/util/LongSparseLongArrayTest.java
+++ b/core/tests/coretests/src/android/util/LongSparseLongArrayTest.java
@@ -16,9 +16,13 @@
package android.util;
-import androidx.test.filters.LargeTest;
+import static org.junit.Assert.assertEquals;
-import junit.framework.TestCase;
+import androidx.test.filters.LargeTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
import java.util.HashMap;
import java.util.Iterator;
@@ -29,9 +33,11 @@
* Tests for {@link LongSparseLongArray}.
*/
@LargeTest
-public class LongSparseLongArrayTest extends TestCase {
+@RunWith(AndroidJUnit4.class)
+public class LongSparseLongArrayTest {
private static final String TAG = "LongSparseLongArrayTest";
+ @Test
public void testSimplePut() throws Exception {
final LongSparseLongArray array = new LongSparseLongArray(5);
for (int i = 0; i < 48; i++) {
@@ -45,6 +51,7 @@
}
}
+ @Test
public void testSimplePutBackwards() throws Exception {
final LongSparseLongArray array = new LongSparseLongArray(5);
for (int i = 47; i >= 0; i--) {
@@ -58,6 +65,7 @@
}
}
+ @Test
public void testMiddleInsert() throws Exception {
final LongSparseLongArray array = new LongSparseLongArray(5);
for (int i = 0; i < 48; i++) {
@@ -74,6 +82,7 @@
assertEquals(1024, array.get(special, -1));
}
+ @Test
public void testFuzz() throws Exception {
final Random r = new Random();
diff --git a/core/tests/coretests/src/android/util/LruCacheTest.java b/core/tests/coretests/src/android/util/LruCacheTest.java
index 1928bfd..10e8308 100644
--- a/core/tests/coretests/src/android/util/LruCacheTest.java
+++ b/core/tests/coretests/src/android/util/LruCacheTest.java
@@ -16,7 +16,14 @@
package android.util;
-import junit.framework.TestCase;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.fail;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
import java.util.ArrayList;
import java.util.Arrays;
@@ -24,13 +31,15 @@
import java.util.List;
import java.util.Map;
-public final class LruCacheTest extends TestCase {
+@RunWith(AndroidJUnit4.class)
+public final class LruCacheTest {
private int expectedCreateCount;
private int expectedPutCount;
private int expectedHitCount;
private int expectedMissCount;
private int expectedEvictionCount;
+ @Test
public void testStatistics() {
LruCache<String, String> cache = new LruCache<String, String>(3);
assertStatistics(cache);
@@ -80,6 +89,7 @@
assertSnapshot(cache, "e", "E", "b", "B", "c", "C");
}
+ @Test
public void testStatisticsWithCreate() {
LruCache<String, String> cache = newCreatingCache();
assertStatistics(cache);
@@ -104,18 +114,21 @@
assertSnapshot(cache, "cc", "created-cc", "dd", "created-dd", "aa", "created-aa");
}
+ @Test
public void testCreateOnCacheMiss() {
LruCache<String, String> cache = newCreatingCache();
String created = cache.get("aa");
assertEquals("created-aa", created);
}
+ @Test
public void testNoCreateOnCacheHit() {
LruCache<String, String> cache = newCreatingCache();
cache.put("aa", "put-aa");
assertEquals("put-aa", cache.get("aa"));
}
+ @Test
public void testConstructorDoesNotAllowZeroCacheSize() {
try {
new LruCache<String, String>(0);
@@ -124,6 +137,7 @@
}
}
+ @Test
public void testCannotPutNullKey() {
LruCache<String, String> cache = new LruCache<String, String>(3);
try {
@@ -133,6 +147,7 @@
}
}
+ @Test
public void testCannotPutNullValue() {
LruCache<String, String> cache = new LruCache<String, String>(3);
try {
@@ -142,6 +157,7 @@
}
}
+ @Test
public void testToString() {
LruCache<String, String> cache = new LruCache<String, String>(3);
assertEquals("LruCache[maxSize=3,hits=0,misses=0,hitRate=0%]", cache.toString());
@@ -160,6 +176,7 @@
assertEquals("LruCache[maxSize=3,hits=3,misses=2,hitRate=60%]", cache.toString());
}
+ @Test
public void testEvictionWithSingletonCache() {
LruCache<String, String> cache = new LruCache<String, String>(1);
cache.put("a", "A");
@@ -167,6 +184,7 @@
assertSnapshot(cache, "b", "B");
}
+ @Test
public void testEntryEvictedWhenFull() {
List<String> log = new ArrayList<String>();
LruCache<String, String> cache = newRemovalLogCache(log);
@@ -184,6 +202,7 @@
* Replacing the value for a key doesn't cause an eviction but it does bring
* the replaced entry to the front of the queue.
*/
+ @Test
public void testPutCauseEviction() {
List<String> log = new ArrayList<String>();
LruCache<String, String> cache = newRemovalLogCache(log);
@@ -196,6 +215,7 @@
assertSnapshot(cache, "a", "A", "c", "C", "b", "B2");
}
+ @Test
public void testCustomSizesImpactsSize() {
LruCache<String, String> cache = new LruCache<String, String>(10) {
@Override protected int sizeOf(String key, String value) {
@@ -212,6 +232,7 @@
assertEquals(6, cache.size());
}
+ @Test
public void testEvictionWithCustomSizes() {
LruCache<String, String> cache = new LruCache<String, String>(4) {
@Override protected int sizeOf(String key, String value) {
@@ -241,6 +262,7 @@
assertSnapshot(cache, "j", "JJJ");
}
+ @Test
public void testEvictionThrowsWhenSizesAreInconsistent() {
LruCache<String, int[]> cache = new LruCache<String, int[]>(4) {
@Override protected int sizeOf(String key, int[] value) {
@@ -263,6 +285,7 @@
}
}
+ @Test
public void testEvictionThrowsWhenSizesAreNegative() {
LruCache<String, String> cache = new LruCache<String, String>(4) {
@Override protected int sizeOf(String key, String value) {
@@ -282,6 +305,7 @@
* because evicting a small element may be insufficient to make room for a
* large element.
*/
+ @Test
public void testDifferentElementSizes() {
LruCache<String, String> cache = new LruCache<String, String>(10) {
@Override protected int sizeOf(String key, String value) {
@@ -299,6 +323,7 @@
assertSnapshot(cache, "e", "12345678");
}
+ @Test
public void testEvictAll() {
List<String> log = new ArrayList<String>();
LruCache<String, String> cache = newRemovalLogCache(log);
@@ -310,6 +335,7 @@
assertEquals(Arrays.asList("a=A", "b=B", "c=C"), log);
}
+ @Test
public void testEvictAllEvictsSizeZeroElements() {
LruCache<String, String> cache = new LruCache<String, String>(10) {
@Override protected int sizeOf(String key, String value) {
@@ -323,6 +349,7 @@
assertSnapshot(cache);
}
+ @Test
public void testRemoveWithCustomSizes() {
LruCache<String, String> cache = new LruCache<String, String>(10) {
@Override protected int sizeOf(String key, String value) {
@@ -335,6 +362,7 @@
assertEquals(4, cache.size());
}
+ @Test
public void testRemoveAbsentElement() {
LruCache<String, String> cache = new LruCache<String, String>(10);
cache.put("a", "A");
@@ -343,6 +371,7 @@
assertEquals(2, cache.size());
}
+ @Test
public void testRemoveNullThrows() {
LruCache<String, String> cache = new LruCache<String, String>(10);
try {
@@ -352,6 +381,7 @@
}
}
+ @Test
public void testRemoveCallsEntryRemoved() {
List<String> log = new ArrayList<String>();
LruCache<String, String> cache = newRemovalLogCache(log);
@@ -360,6 +390,7 @@
assertEquals(Arrays.asList("a=A>null"), log);
}
+ @Test
public void testPutCallsEntryRemoved() {
List<String> log = new ArrayList<String>();
LruCache<String, String> cache = newRemovalLogCache(log);
@@ -368,6 +399,7 @@
assertEquals(Arrays.asList("a=A>A2"), log);
}
+ @Test
public void testEntryRemovedIsCalledWithoutSynchronization() {
LruCache<String, String> cache = new LruCache<String, String>(3) {
@Override protected void entryRemoved(
@@ -385,6 +417,7 @@
cache.evictAll(); // multiple eviction
}
+ @Test
public void testCreateIsCalledWithoutSynchronization() {
LruCache<String, String> cache = new LruCache<String, String>(3) {
@Override protected String create(String key) {
@@ -401,6 +434,7 @@
* working. The map value should be returned by get(), and the created value
* should be released with entryRemoved().
*/
+ @Test
public void testCreateWithConcurrentPut() {
final List<String> log = new ArrayList<String>();
LruCache<String, String> cache = new LruCache<String, String>(3) {
@@ -423,6 +457,7 @@
* the first create to return is returned by both gets. The other created
* values should be released with entryRemove().
*/
+ @Test
public void testCreateWithConcurrentCreate() {
final List<String> log = new ArrayList<String>();
LruCache<String, Integer> cache = new LruCache<String, Integer>(3) {
diff --git a/core/tests/coretests/src/android/util/MonthDisplayHelperTest.java b/core/tests/coretests/src/android/util/MonthDisplayHelperTest.java
index 30d5f77..06f970f 100644
--- a/core/tests/coretests/src/android/util/MonthDisplayHelperTest.java
+++ b/core/tests/coretests/src/android/util/MonthDisplayHelperTest.java
@@ -16,18 +16,26 @@
package android.util;
-import androidx.test.filters.SmallTest;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
-import junit.framework.TestCase;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
import java.util.Calendar;
/**
* Unit tests for {@link MonthDisplayHelper}.
*/
-public class MonthDisplayHelperTest extends TestCase {
+@RunWith(AndroidJUnit4.class)
+public class MonthDisplayHelperTest {
+ @Test
@SmallTest
public void testFirstDayOfMonth() {
@@ -40,12 +48,14 @@
new MonthDisplayHelper(2007, Calendar.SEPTEMBER).getFirstDayOfMonth());
}
+ @Test
@SmallTest
public void testNumberOfDaysInCurrentMonth() {
assertEquals(30,
new MonthDisplayHelper(2007, Calendar.SEPTEMBER).getNumberOfDaysInMonth());
}
+ @Test
@SmallTest
public void testMonthRows() {
MonthDisplayHelper helper = new MonthDisplayHelper(2007, Calendar.SEPTEMBER);
@@ -59,6 +69,7 @@
}
+ @Test
@SmallTest
public void testMonthRowsWeekStartsMonday() {
MonthDisplayHelper helper = new MonthDisplayHelper(2007,
@@ -74,6 +85,7 @@
helper.getDigitsForRow(5));
}
+ @Test
@SmallTest
public void testMonthRowsWeekStartsSaturday() {
MonthDisplayHelper helper = new MonthDisplayHelper(2007,
@@ -98,6 +110,7 @@
helper.getDigitsForRow(4));
}
+ @Test
@SmallTest
public void testGetDayAt() {
MonthDisplayHelper helper = new MonthDisplayHelper(2007,
@@ -109,6 +122,7 @@
assertEquals(2, helper.getDayAt(5, 2));
}
+ @Test
@SmallTest
public void testPrevMonth() {
MonthDisplayHelper helper = new MonthDisplayHelper(2007,
@@ -124,6 +138,7 @@
helper.getDigitsForRow(0));
}
+ @Test
@SmallTest
public void testPrevMonthRollOver() {
MonthDisplayHelper helper = new MonthDisplayHelper(2007,
@@ -135,6 +150,7 @@
assertEquals(Calendar.DECEMBER, helper.getMonth());
}
+ @Test
@SmallTest
public void testNextMonth() {
MonthDisplayHelper helper = new MonthDisplayHelper(2007,
@@ -150,6 +166,7 @@
helper.getDigitsForRow(0));
}
+ @Test
@SmallTest
public void testGetRowOf() {
MonthDisplayHelper helper = new MonthDisplayHelper(2007,
@@ -162,6 +179,7 @@
assertEquals(3, helper.getRowOf(19));
}
+ @Test
@SmallTest
public void testGetColumnOf() {
MonthDisplayHelper helper = new MonthDisplayHelper(2007,
@@ -174,6 +192,7 @@
assertEquals(0, helper.getColumnOf(26));
}
+ @Test
@SmallTest
public void testWithinCurrentMonth() {
MonthDisplayHelper helper = new MonthDisplayHelper(2007,
diff --git a/core/tests/coretests/src/android/util/NtpTrustedTimeTest.java b/core/tests/coretests/src/android/util/NtpTrustedTimeTest.java
index 4de27c3..ce1eabc 100644
--- a/core/tests/coretests/src/android/util/NtpTrustedTimeTest.java
+++ b/core/tests/coretests/src/android/util/NtpTrustedTimeTest.java
@@ -31,10 +31,15 @@
import static java.util.Arrays.asList;
import android.net.Network;
+import android.platform.test.annotations.IgnoreUnderRavenwood;
+import android.platform.test.ravenwood.RavenwoodRule;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
+import androidx.test.platform.app.InstrumentationRegistry;
+import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InOrder;
@@ -51,7 +56,10 @@
@SmallTest
@RunWith(AndroidJUnit4.class)
+@IgnoreUnderRavenwood(blockedBy = NtpTrustedTime.class)
public class NtpTrustedTimeTest {
+ @Rule
+ public final RavenwoodRule mRavenwood = new RavenwoodRule();
private static final Duration VALID_TIMEOUT = Duration.ofSeconds(5);
diff --git a/core/tests/coretests/src/android/util/PatternsTest.java b/core/tests/coretests/src/android/util/PatternsTest.java
index dd8f73f..a180ec3 100644
--- a/core/tests/coretests/src/android/util/PatternsTest.java
+++ b/core/tests/coretests/src/android/util/PatternsTest.java
@@ -16,17 +16,25 @@
package android.util;
-import androidx.test.filters.SmallTest;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
-import junit.framework.TestCase;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
-public class PatternsTest extends TestCase {
+@RunWith(AndroidJUnit4.class)
+public class PatternsTest {
// Tests for Patterns.TOP_LEVEL_DOMAIN
+ @Test
@SmallTest
public void testTldPattern() throws Exception {
boolean t;
@@ -58,36 +66,42 @@
// Tests for Patterns.IANA_TOP_LEVEL_DOMAINS
+ @Test
@SmallTest
public void testIanaTopLevelDomains_matchesValidTld() throws Exception {
Pattern pattern = Pattern.compile(Patterns.IANA_TOP_LEVEL_DOMAINS);
assertTrue("Should match 'com'", pattern.matcher("com").matches());
}
+ @Test
@SmallTest
public void testIanaTopLevelDomains_matchesValidNewTld() throws Exception {
Pattern pattern = Pattern.compile(Patterns.IANA_TOP_LEVEL_DOMAINS);
assertTrue("Should match 'me'", pattern.matcher("me").matches());
}
+ @Test
@SmallTest
public void testIanaTopLevelDomains_matchesPunycodeTld() throws Exception {
Pattern pattern = Pattern.compile(Patterns.IANA_TOP_LEVEL_DOMAINS);
assertTrue("Should match Punycode TLD", pattern.matcher("xn--qxam").matches());
}
+ @Test
@SmallTest
public void testIanaTopLevelDomains_matchesIriTLD() throws Exception {
Pattern pattern = Pattern.compile(Patterns.IANA_TOP_LEVEL_DOMAINS);
assertTrue("Should match IRI TLD", pattern.matcher("\uD55C\uAD6D").matches());
}
+ @Test
@SmallTest
public void testIanaTopLevelDomains_doesNotMatchWrongTld() throws Exception {
Pattern pattern = Pattern.compile(Patterns.IANA_TOP_LEVEL_DOMAINS);
assertFalse("Should not match 'mem'", pattern.matcher("mem").matches());
}
+ @Test
@SmallTest
public void testIanaTopLevelDomains_doesNotMatchWrongPunycodeTld() throws Exception {
Pattern pattern = Pattern.compile(Patterns.IANA_TOP_LEVEL_DOMAINS);
@@ -96,6 +110,7 @@
// Tests for Patterns.WEB_URL
+ @Test
@SmallTest
public void testWebUrl_matchesValidUrlWithSchemeAndHostname() throws Exception {
String url = "http://www.android.com";
@@ -103,6 +118,7 @@
Patterns.WEB_URL.matcher(url).matches());
}
+ @Test
@SmallTest
public void testWebUrl_matchesValidUrlWithSchemeHostnameAndNewTld() throws Exception {
String url = "http://www.android.me";
@@ -110,6 +126,7 @@
Patterns.WEB_URL.matcher(url).matches());
}
+ @Test
@SmallTest
public void testWebUrl_matchesValidUrlWithHostnameAndNewTld() throws Exception {
String url = "android.me";
@@ -117,6 +134,7 @@
Patterns.WEB_URL.matcher(url).matches());
}
+ @Test
@SmallTest
public void testWebUrl_matchesChinesePunycodeUrlWithProtocol() throws Exception {
String url = "http://xn--fsqu00a.xn--0zwm56d";
@@ -124,6 +142,7 @@
Patterns.WEB_URL.matcher(url).matches());
}
+ @Test
@SmallTest
public void testWebUrl_matchesChinesePunycodeUrlWithoutProtocol() throws Exception {
String url = "xn--fsqu00a.xn--0zwm56d";
@@ -131,6 +150,7 @@
Patterns.WEB_URL.matcher(url).matches());
}
+ @Test
@SmallTest
public void testWebUrl_matchesArabicPunycodeUrlWithProtocol() throws Exception {
String url = "http://xn--4gbrim.xn----rmckbbajlc6dj7bxne2c.xn--wgbh1c/ar/default.aspx";
@@ -138,6 +158,7 @@
Patterns.WEB_URL.matcher(url).matches());
}
+ @Test
@SmallTest
public void testWebUrl_matchesArabicPunycodeUrlWithoutProtocol() throws Exception {
String url = "xn--4gbrim.xn----rmckbbajlc6dj7bxne2c.xn--wgbh1c/ar/default.aspx";
@@ -145,6 +166,7 @@
Patterns.WEB_URL.matcher(url).matches());
}
+ @Test
@SmallTest
public void testWebUrl_matchesUrlWithUnicodeDomainNameWithProtocol() throws Exception {
String url = "http://\uD604\uAE08\uC601\uC218\uC99D.kr";
@@ -152,6 +174,7 @@
Patterns.WEB_URL.matcher(url).matches());
}
+ @Test
@SmallTest
public void testWebUrl_matchesUrlWithUnicodeDomainNameWithoutProtocol() throws Exception {
String url = "\uD604\uAE08\uC601\uC218\uC99D.kr";
@@ -159,6 +182,7 @@
Patterns.WEB_URL.matcher(url).matches());
}
+ @Test
@SmallTest
public void testWebUrl_matchesUrlWithUnicodeTld() throws Exception {
String url = "\uB3C4\uBA54\uC778.\uD55C\uAD6D";
@@ -166,6 +190,7 @@
Patterns.WEB_URL.matcher(url).matches());
}
+ @Test
@SmallTest
public void testWebUrl_matchesUrlWithUnicodePath() throws Exception {
String url = "http://brainstormtech.blogs.fortune.cnn.com/2010/03/11/" +
@@ -174,19 +199,22 @@
Patterns.WEB_URL.matcher(url).matches());
}
+ @Test
@SmallTest
public void testWebUrl_doesNotMatchValidUrlWithInvalidProtocol() throws Exception {
- String url = "ftp://www.example.com";
+ String url = "invalid://www.example.com";
assertFalse("Should not match URL with invalid protocol",
Patterns.WEB_URL.matcher(url).matches());
}
+ @Test
@SmallTest
public void testWebUrl_matchesValidUrlWithPort() throws Exception {
String url = "http://www.example.com:8080";
assertTrue("Should match URL with port", Patterns.WEB_URL.matcher(url).matches());
}
+ @Test
@SmallTest
public void testWebUrl_matchesUrlWithPortAndQuery() throws Exception {
String url = "http://www.example.com:8080/?foo=bar";
@@ -194,12 +222,14 @@
Patterns.WEB_URL.matcher(url).matches());
}
+ @Test
@SmallTest
public void testWebUrl_matchesUrlWithTilde() throws Exception {
String url = "http://www.example.com:8080/~user/?foo=bar";
assertTrue("Should match URL with tilde", Patterns.WEB_URL.matcher(url).matches());
}
+ @Test
@SmallTest
public void testWebUrl_matchesProtocolCaseInsensitive() throws Exception {
String url = "hTtP://android.com";
@@ -207,6 +237,7 @@
Patterns.WEB_URL.matcher(url).matches());
}
+ @Test
@SmallTest
public void testWebUrl_matchesDomainNameWithDash() throws Exception {
String url = "http://a-nd.r-oid.com";
@@ -218,6 +249,7 @@
Patterns.WEB_URL.matcher(url).matches());
}
+ @Test
@SmallTest
public void testWebUrl_matchesDomainNameWithUnderscore() throws Exception {
String url = "http://a_nd.r_oid.com";
@@ -229,6 +261,7 @@
Patterns.WEB_URL.matcher(url).matches());
}
+ @Test
@SmallTest
public void testWebUrl_matchesPathAndQueryWithDollarSign() throws Exception {
String url = "http://android.com/path$?v=$val";
@@ -240,6 +273,7 @@
Patterns.WEB_URL.matcher(url).matches());
}
+ @Test
@SmallTest
public void testWebUrl_matchesEmptyPathWithQueryParams() throws Exception {
String url = "http://android.com?q=v";
@@ -261,6 +295,7 @@
// Tests for Patterns.AUTOLINK_WEB_URL
+ @Test
@SmallTest
public void testAutoLinkWebUrl_matchesValidUrlWithSchemeAndHostname() throws Exception {
String url = "http://www.android.com";
@@ -268,6 +303,7 @@
Patterns.AUTOLINK_WEB_URL.matcher(url).matches());
}
+ @Test
@SmallTest
public void testAutoLinkWebUrl_matchesValidUrlWithSchemeHostnameAndNewTld() throws Exception {
String url = "http://www.android.me";
@@ -275,6 +311,7 @@
Patterns.AUTOLINK_WEB_URL.matcher(url).matches());
}
+ @Test
@SmallTest
public void testAutoLinkWebUrl_matchesValidUrlWithHostnameAndNewTld() throws Exception {
String url = "android.me";
@@ -286,6 +323,7 @@
Patterns.AUTOLINK_WEB_URL.matcher(url).matches());
}
+ @Test
@SmallTest
public void testAutoLinkWebUrl_matchesChinesePunycodeUrlWithProtocol() throws Exception {
String url = "http://xn--fsqu00a.xn--0zwm56d";
@@ -293,6 +331,7 @@
Patterns.AUTOLINK_WEB_URL.matcher(url).matches());
}
+ @Test
@SmallTest
public void testAutoLinkWebUrl_matchesChinesePunycodeUrlWithoutProtocol() throws Exception {
String url = "xn--fsqu00a.xn--0zwm56d";
@@ -300,6 +339,7 @@
Patterns.AUTOLINK_WEB_URL.matcher(url).matches());
}
+ @Test
@SmallTest
public void testAutoLinkWebUrl_matchesArabicPunycodeUrlWithProtocol() throws Exception {
String url = "http://xn--4gbrim.xn--rmckbbajlc6dj7bxne2c.xn--wgbh1c/ar/default.aspx";
@@ -307,6 +347,7 @@
Patterns.AUTOLINK_WEB_URL.matcher(url).matches());
}
+ @Test
@SmallTest
public void testAutoLinkWebUrl_matchesArabicPunycodeUrlWithoutProtocol() throws Exception {
String url = "xn--4gbrim.xn--rmckbbajlc6dj7bxne2c.xn--wgbh1c/ar/default.aspx";
@@ -314,6 +355,7 @@
Patterns.AUTOLINK_WEB_URL.matcher(url).matches());
}
+ @Test
@SmallTest
public void testAutoLinkWebUrl_doesNotMatchPunycodeTldThatStartsWithDash() throws Exception {
String url = "http://xn--fsqu00a.-xn--0zwm56d";
@@ -321,6 +363,7 @@
Patterns.AUTOLINK_WEB_URL.matcher(url).matches());
}
+ @Test
@SmallTest
public void testAutoLinkWebUrl_doesNotMatchPunycodeTldThatEndsWithDash() throws Exception {
String url = "http://xn--fsqu00a.xn--0zwm56d-";
@@ -328,6 +371,7 @@
Patterns.AUTOLINK_WEB_URL.matcher(url).matches());
}
+ @Test
@SmallTest
public void testAutoLinkWebUrl_matchesUrlWithUnicodeDomainName() throws Exception {
String url = "http://\uD604\uAE08\uC601\uC218\uC99D.kr";
@@ -339,6 +383,7 @@
Patterns.AUTOLINK_WEB_URL.matcher(url).matches());
}
+ @Test
@SmallTest
public void testAutoLinkWebUrl_matchesUrlWithUnicodeTld() throws Exception {
String url = "\uB3C4\uBA54\uC778.\uD55C\uAD6D";
@@ -346,6 +391,7 @@
Patterns.AUTOLINK_WEB_URL.matcher(url).matches());
}
+ @Test
@SmallTest
public void testAutoLinkWebUrl_matchesUrlWithUnicodePath() throws Exception {
String url = "http://brainstormtech.blogs.fortune.cnn.com/2010/03/11/" +
@@ -354,13 +400,15 @@
Patterns.AUTOLINK_WEB_URL.matcher(url).matches());
}
+ @Test
@SmallTest
public void testAutoLinkWebUrl_doesNotMatchValidUrlWithInvalidProtocol() throws Exception {
- String url = "ftp://www.example.com";
+ String url = "invalid://www.example.com";
assertFalse("Should not match URL with invalid protocol",
Patterns.AUTOLINK_WEB_URL.matcher(url).matches());
}
+ @Test
@SmallTest
public void testAutoLinkWebUrl_matchesValidUrlWithPort() throws Exception {
String url = "http://www.example.com:8080";
@@ -368,6 +416,7 @@
Patterns.AUTOLINK_WEB_URL.matcher(url).matches());
}
+ @Test
@SmallTest
public void testAutoLinkWebUrl_matchesUrlWithPortAndQuery() throws Exception {
String url = "http://www.example.com:8080/?foo=bar";
@@ -375,6 +424,7 @@
Patterns.AUTOLINK_WEB_URL.matcher(url).matches());
}
+ @Test
@SmallTest
public void testAutoLinkWebUrl_matchesUrlWithTilde() throws Exception {
String url = "http://www.example.com:8080/~user/?foo=bar";
@@ -382,6 +432,7 @@
Patterns.AUTOLINK_WEB_URL.matcher(url).matches());
}
+ @Test
@SmallTest
public void testAutoLinkWebUrl_matchesProtocolCaseInsensitive() throws Exception {
String url = "hTtP://android.com";
@@ -389,6 +440,7 @@
Patterns.AUTOLINK_WEB_URL.matcher(url).matches());
}
+ @Test
@SmallTest
public void testAutoLinkWebUrl_matchesUrlStartingWithHttpAndDoesNotHaveTld() throws Exception {
String url = "http://android/#notld///a/n/d/r/o/i/d&p1=1&p2=2";
@@ -396,6 +448,7 @@
Patterns.AUTOLINK_WEB_URL.matcher(url).matches());
}
+ @Test
@SmallTest
public void testAutoLinkWebUrl_doesNotMatchUrlsWithoutProtocolAndWithUnknownTld()
throws Exception {
@@ -405,13 +458,15 @@
Patterns.AUTOLINK_WEB_URL.matcher(url).matches());
}
+ @Test
@SmallTest
public void testAutoLinkWebUrl_doesNotPartiallyMatchUnknownProtocol() throws Exception {
- String url = "ftp://foo.bar/baz";
+ String url = "invalid://foo.bar/baz";
assertFalse("Should not partially match URL with unknown protocol",
Patterns.AUTOLINK_WEB_URL.matcher(url).find());
}
+ @Test
@SmallTest
public void testAutoLinkWebUrl_matchesValidUrlWithEmoji() throws Exception {
String url = "Thank\u263A.com";
@@ -419,6 +474,7 @@
Patterns.AUTOLINK_WEB_URL.matcher(url).matches());
}
+ @Test
@SmallTest
public void testAutoLinkWebUrl_doesNotMatchUrlsWithEmojiWithoutProtocolAndWithoutKnownTld()
throws Exception {
@@ -427,6 +483,7 @@
Patterns.AUTOLINK_WEB_URL.matcher(url).matches());
}
+ @Test
@SmallTest
public void testAutoLinkWebUrl_doesNotMatchEmailAddress()
throws Exception {
@@ -435,6 +492,7 @@
Patterns.AUTOLINK_WEB_URL.matcher(url).matches());
}
+ @Test
@SmallTest
public void testAutoLinkWebUrl_matchesDomainNameWithSurrogatePairs() throws Exception {
String url = "android\uD83C\uDF38.com";
@@ -442,6 +500,7 @@
Patterns.AUTOLINK_WEB_URL.matcher(url).matches());
}
+ @Test
@SmallTest
public void testAutoLinkWebUrl_matchesTldWithSurrogatePairs() throws Exception {
String url = "http://android.\uD83C\uDF38com";
@@ -449,6 +508,7 @@
Patterns.AUTOLINK_WEB_URL.matcher(url).matches());
}
+ @Test
@SmallTest
public void testAutoLinkWebUrl_matchesPathWithSurrogatePairs() throws Exception {
String url = "http://android.com/path-with-\uD83C\uDF38?v=\uD83C\uDF38";
@@ -456,6 +516,7 @@
Patterns.AUTOLINK_WEB_URL.matcher(url).matches());
}
+ @Test
@SmallTest
public void testAutoLinkWebUrl_doesNotMatchUrlWithExcludedSurrogate() throws Exception {
String url = "http://android\uD83F\uDFFE.com";
@@ -463,6 +524,7 @@
Patterns.AUTOLINK_WEB_URL.matcher(url).matches());
}
+ @Test
@SmallTest
public void testAutoLinkWebUrl_doesNotMatchUnicodeSpaces() throws Exception {
String part1 = "http://and";
@@ -493,6 +555,7 @@
}
}
+ @Test
@SmallTest
public void testAutoLinkWebUrl_matchesDomainNameWithDash() throws Exception {
String url = "http://a-nd.r-oid.com";
@@ -504,6 +567,7 @@
Patterns.AUTOLINK_WEB_URL.matcher(url).matches());
}
+ @Test
@SmallTest
public void testAutoLinkWebUrl_matchesDomainNameWithUnderscore() throws Exception {
String url = "http://a_nd.r_oid.com";
@@ -515,6 +579,7 @@
Patterns.AUTOLINK_WEB_URL.matcher(url).matches());
}
+ @Test
@SmallTest
public void testAutoLinkWebUrl_matchesPathAndQueryWithDollarSign() throws Exception {
String url = "http://android.com/path$?v=$val";
@@ -526,6 +591,7 @@
Patterns.AUTOLINK_WEB_URL.matcher(url).matches());
}
+ @Test
@SmallTest
public void testAutoLinkWebUrl_matchesEmptyPathWithQueryParams() throws Exception {
String url = "http://android.com?q=v";
@@ -547,6 +613,7 @@
// Tests for Patterns.IP_ADDRESS
+ @Test
@SmallTest
public void testIpPattern() throws Exception {
boolean t;
@@ -560,6 +627,7 @@
// Tests for Patterns.DOMAIN_NAME
+ @Test
@SmallTest
public void testDomain_matchesPunycodeTld() throws Exception {
String domain = "xn--fsqu00a.xn--0zwm56d";
@@ -567,6 +635,7 @@
Patterns.DOMAIN_NAME.matcher(domain).matches());
}
+ @Test
@SmallTest
public void testDomain_doesNotMatchPunycodeThatStartsWithDash() throws Exception {
String domain = "xn--fsqu00a.-xn--0zwm56d";
@@ -574,6 +643,7 @@
Patterns.DOMAIN_NAME.matcher(domain).matches());
}
+ @Test
@SmallTest
public void testDomain_doesNotMatchPunycodeThatEndsWithDash() throws Exception {
String domain = "xn--fsqu00a.xn--0zwm56d-";
@@ -581,6 +651,7 @@
Patterns.DOMAIN_NAME.matcher(domain).matches());
}
+ @Test
@SmallTest
public void testDomain_doesNotMatchPunycodeLongerThanAllowed() throws Exception {
String tld = "xn--";
@@ -592,6 +663,7 @@
Patterns.DOMAIN_NAME.matcher(domain).matches());
}
+ @Test
@SmallTest
public void testDomain_matchesObsoleteTld() throws Exception {
String domain = "test.yu";
@@ -599,6 +671,7 @@
Patterns.DOMAIN_NAME.matcher(domain).matches());
}
+ @Test
@SmallTest
public void testDomain_matchesWithSubDomain() throws Exception {
String domain = "mail.example.com";
@@ -606,6 +679,7 @@
Patterns.DOMAIN_NAME.matcher(domain).matches());
}
+ @Test
@SmallTest
public void testDomain_matchesWithoutSubDomain() throws Exception {
String domain = "android.me";
@@ -613,6 +687,7 @@
Patterns.DOMAIN_NAME.matcher(domain).matches());
}
+ @Test
@SmallTest
public void testDomain_matchesUnicodeDomainNames() throws Exception {
String domain = "\uD604\uAE08\uC601\uC218\uC99D.kr";
@@ -620,6 +695,7 @@
Patterns.DOMAIN_NAME.matcher(domain).matches());
}
+ @Test
@SmallTest
public void testDomain_doesNotMatchInvalidDomain() throws Exception {
String domain = "__+&42.xer";
@@ -627,6 +703,7 @@
Patterns.DOMAIN_NAME.matcher(domain).matches());
}
+ @Test
@SmallTest
public void testDomain_matchesPunycodeArabicDomainName() throws Exception {
String domain = "xn--4gbrim.xn----rmckbbajlc6dj7bxne2c.xn--wgbh1c";
@@ -634,6 +711,7 @@
Patterns.DOMAIN_NAME.matcher(domain).matches());
}
+ @Test
@SmallTest
public void testDomain_matchesDomainNameWithDash() throws Exception {
String url = "http://a-nd.r-oid.com";
@@ -645,6 +723,7 @@
Patterns.AUTOLINK_WEB_URL.matcher(url).matches());
}
+ @Test
@SmallTest
public void testDomain_matchesDomainNameWithUnderscore() throws Exception {
String url = "http://a_nd.r_oid.com";
@@ -658,6 +737,7 @@
// Tests for Patterns.AUTOLINK_EMAIL_ADDRESS
+ @Test
@SmallTest
public void testAutoLinkEmailAddress_matchesShortValidEmail() throws Exception {
String email = "a@a.co";
@@ -665,6 +745,7 @@
Patterns.AUTOLINK_EMAIL_ADDRESS.matcher(email).matches());
}
+ @Test
@SmallTest
public void testAutoLinkEmailAddress_matchesRegularEmail() throws Exception {
String email = "email@android.com";
@@ -672,6 +753,7 @@
Patterns.AUTOLINK_EMAIL_ADDRESS.matcher(email).matches());
}
+ @Test
@SmallTest
public void testAutoLinkEmailAddress_matchesEmailWithMultipleSubdomains() throws Exception {
String email = "email@e.somelongdomainnameforandroid.abc.uk";
@@ -679,6 +761,7 @@
Patterns.AUTOLINK_EMAIL_ADDRESS.matcher(email).matches());
}
+ @Test
@SmallTest
public void testAutoLinkEmailAddress_matchesLocalPartWithDot() throws Exception {
String email = "e.mail@android.com";
@@ -686,6 +769,7 @@
Patterns.AUTOLINK_EMAIL_ADDRESS.matcher(email).matches());
}
+ @Test
@SmallTest
public void testAutoLinkEmailAddress_matchesLocalPartWithPlus() throws Exception {
String email = "e+mail@android.com";
@@ -693,6 +777,7 @@
Patterns.AUTOLINK_EMAIL_ADDRESS.matcher(email).matches());
}
+ @Test
@SmallTest
public void testAutoLinkEmailAddress_matchesLocalPartWithUnderscore() throws Exception {
String email = "e_mail@android.com";
@@ -700,6 +785,7 @@
Patterns.AUTOLINK_EMAIL_ADDRESS.matcher(email).matches());
}
+ @Test
@SmallTest
public void testAutoLinkEmailAddress_matchesLocalPartWithDash() throws Exception {
String email = "e-mail@android.com";
@@ -707,6 +793,7 @@
Patterns.AUTOLINK_EMAIL_ADDRESS.matcher(email).matches());
}
+ @Test
@SmallTest
public void testAutoLinkEmailAddress_matchesLocalPartWithApostrophe() throws Exception {
String email = "e'mail@android.com";
@@ -714,6 +801,7 @@
Patterns.AUTOLINK_EMAIL_ADDRESS.matcher(email).matches());
}
+ @Test
@SmallTest
public void testAutoLinkEmailAddress_matchesLocalPartWithDigits() throws Exception {
String email = "123@android.com";
@@ -721,6 +809,7 @@
Patterns.AUTOLINK_EMAIL_ADDRESS.matcher(email).matches());
}
+ @Test
@SmallTest
public void testAutoLinkEmailAddress_matchesUnicodeLocalPart() throws Exception {
String email = "\uD604\uAE08\uC601\uC218\uC99D@android.kr";
@@ -728,6 +817,7 @@
Patterns.AUTOLINK_EMAIL_ADDRESS.matcher(email).matches());
}
+ @Test
@SmallTest
public void testAutoLinkEmailAddress_matchesLocalPartWithEmoji() throws Exception {
String email = "smiley\u263A@android.com";
@@ -735,6 +825,7 @@
Patterns.AUTOLINK_EMAIL_ADDRESS.matcher(email).matches());
}
+ @Test
@SmallTest
public void testAutoLinkEmailAddress_matchesLocalPartWithSurrogatePairs() throws Exception {
String email = "\uD83C\uDF38@android.com";
@@ -742,6 +833,7 @@
Patterns.AUTOLINK_EMAIL_ADDRESS.matcher(email).matches());
}
+ @Test
@SmallTest
public void testAutoLinkEmailAddress_matchesDomainWithDash() throws Exception {
String email = "email@an-droid.com";
@@ -749,6 +841,7 @@
Patterns.AUTOLINK_EMAIL_ADDRESS.matcher(email).matches());
}
+ @Test
@SmallTest
public void testAutoLinkEmailAddress_matchesUnicodeDomain() throws Exception {
String email = "email@\uD604\uAE08\uC601\uC218\uC99D.kr";
@@ -756,6 +849,7 @@
Patterns.AUTOLINK_EMAIL_ADDRESS.matcher(email).matches());
}
+ @Test
@SmallTest
public void testAutoLinkEmailAddress_matchesUnicodeLocalPartAndDomain() throws Exception {
String email = "\uD604\uAE08\uC601\uC218\uC99D@\uD604\uAE08\uC601\uC218\uC99D.kr";
@@ -763,6 +857,7 @@
Patterns.AUTOLINK_EMAIL_ADDRESS.matcher(email).matches());
}
+ @Test
@SmallTest
public void testAutoLinkEmailAddress_matchesDomainWithEmoji() throws Exception {
String email = "smiley@\u263Aandroid.com";
@@ -770,6 +865,7 @@
Patterns.AUTOLINK_EMAIL_ADDRESS.matcher(email).matches());
}
+ @Test
@SmallTest
public void testAutoLinkEmailAddress_matchesDomainWithSurrogatePairs() throws Exception {
String email = "email@\uD83C\uDF38android.com";
@@ -777,6 +873,7 @@
Patterns.AUTOLINK_EMAIL_ADDRESS.matcher(email).matches());
}
+ @Test
@SmallTest
public void testAutoLinkEmailAddress_matchesLocalPartAndDomainWithSurrogatePairs()
throws Exception {
@@ -785,6 +882,7 @@
Patterns.AUTOLINK_EMAIL_ADDRESS.matcher(email).matches());
}
+ @Test
@SmallTest
public void testAutoLinkEmailAddress_doesNotMatchStringWithoutAtSign() throws Exception {
String email = "android.com";
@@ -792,6 +890,7 @@
Patterns.AUTOLINK_EMAIL_ADDRESS.matcher(email).matches());
}
+ @Test
@SmallTest
public void testAutoLinkEmailAddress_doesNotMatchPlainString() throws Exception {
String email = "email";
@@ -799,6 +898,7 @@
Patterns.AUTOLINK_EMAIL_ADDRESS.matcher(email).matches());
}
+ @Test
@SmallTest
public void testAutoLinkEmailAddress_doesNotMatchStringWithMultipleAtSigns() throws Exception {
String email = "email@android@android.com";
@@ -806,6 +906,7 @@
Patterns.AUTOLINK_EMAIL_ADDRESS.matcher(email).matches());
}
+ @Test
@SmallTest
public void testAutoLinkEmailAddress_doesNotMatchEmailWithoutTld() throws Exception {
String email = "email@android";
@@ -813,6 +914,7 @@
Patterns.AUTOLINK_EMAIL_ADDRESS.matcher(email).matches());
}
+ @Test
@SmallTest
public void testAutoLinkEmailAddress_doesNotMatchLocalPartEndingWithDot() throws Exception {
String email = "email.@android.com";
@@ -820,6 +922,7 @@
Patterns.AUTOLINK_EMAIL_ADDRESS.matcher(email).matches());
}
+ @Test
@SmallTest
public void testAutoLinkEmailAddress_doesNotMatchLocalPartStartingWithDot() throws Exception {
String email = ".email@android.com";
@@ -827,6 +930,7 @@
Patterns.AUTOLINK_EMAIL_ADDRESS.matcher(email).matches());
}
+ @Test
@SmallTest
public void testAutoLinkEmailAddress_doesNotMatchDomainStartingWithDash() throws Exception {
String email = "email@-android.com";
@@ -834,6 +938,7 @@
Patterns.AUTOLINK_EMAIL_ADDRESS.matcher(email).matches());
}
+ @Test
@SmallTest
public void testAutoLinkEmailAddress_doesNotMatchDomainWithConsecutiveDots() throws Exception {
String email = "email@android..com";
@@ -841,6 +946,7 @@
Patterns.AUTOLINK_EMAIL_ADDRESS.matcher(email).matches());
}
+ @Test
@SmallTest
public void testAutoLinkEmailAddress_doesNotMatchEmailWithIpAsDomain() throws Exception {
String email = "email@127.0.0.1";
@@ -848,6 +954,7 @@
Patterns.AUTOLINK_EMAIL_ADDRESS.matcher(email).matches());
}
+ @Test
@SmallTest
public void testAutoLinkEmailAddress_doesNotMatchEmailWithInvalidTld() throws Exception {
String email = "email@android.c";
@@ -855,6 +962,7 @@
Patterns.AUTOLINK_EMAIL_ADDRESS.matcher(email).matches());
}
+ @Test
@SmallTest
public void testAutoLinkEmailAddress_matchesLocalPartUpTo64Chars() throws Exception {
String localPart = "";
@@ -871,6 +979,7 @@
Patterns.AUTOLINK_EMAIL_ADDRESS.matcher(email).matches());
}
+ @Test
@SmallTest
public void testAutoLinkEmailAddress_matchesSubdomainUpTo63Chars() throws Exception {
String subdomain = "";
@@ -888,6 +997,7 @@
Patterns.AUTOLINK_EMAIL_ADDRESS.matcher(email).matches());
}
+ @Test
@SmallTest
public void testAutoLinkEmailAddress_matchesDomainUpTo255Chars() throws Exception {
String longDomain = "";
@@ -909,6 +1019,7 @@
// Tests for Patterns.PHONE
+ @Test
@SmallTest
public void testPhonePattern() throws Exception {
boolean t;
diff --git a/core/tests/coretests/src/android/util/RecurrenceRuleTest.java b/core/tests/coretests/src/android/util/RecurrenceRuleTest.java
index caa1208..32548b4 100644
--- a/core/tests/coretests/src/android/util/RecurrenceRuleTest.java
+++ b/core/tests/coretests/src/android/util/RecurrenceRuleTest.java
@@ -16,9 +16,17 @@
package android.util;
-import androidx.test.filters.SmallTest;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
-import junit.framework.TestCase;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
import java.time.Clock;
import java.time.Instant;
@@ -28,19 +36,18 @@
import java.util.Iterator;
@SmallTest
-public class RecurrenceRuleTest extends TestCase {
+@RunWith(AndroidJUnit4.class)
+public class RecurrenceRuleTest {
static Clock sOriginalClock;
- @Override
- protected void setUp() throws Exception {
- super.setUp();
+ @Before
+ public void setUp() throws Exception {
sOriginalClock = RecurrenceRule.sClock;
}
- @Override
- protected void tearDown() throws Exception {
- super.tearDown();
+ @After
+ public void tearDown() throws Exception {
RecurrenceRule.sClock = sOriginalClock;
}
@@ -48,6 +55,7 @@
RecurrenceRule.sClock = Clock.fixed(instant, ZoneId.systemDefault());
}
+ @Test
public void testSimpleMonth() throws Exception {
setClock(Instant.parse("2015-11-20T10:15:30.00Z"));
final RecurrenceRule r = new RecurrenceRule(
@@ -68,6 +76,7 @@
ZonedDateTime.parse("2015-11-14T00:00:00.00Z")), it.next());
}
+ @Test
public void testSimpleDays() throws Exception {
setClock(Instant.parse("2015-01-01T10:15:30.00Z"));
final RecurrenceRule r = new RecurrenceRule(
@@ -89,6 +98,7 @@
assertFalse(it.hasNext());
}
+ @Test
public void testNotRecurring() throws Exception {
setClock(Instant.parse("2015-01-01T10:15:30.00Z"));
final RecurrenceRule r = new RecurrenceRule(
@@ -106,6 +116,7 @@
assertFalse(it.hasNext());
}
+ @Test
public void testNever() throws Exception {
setClock(Instant.parse("2015-01-01T10:15:30.00Z"));
final RecurrenceRule r = RecurrenceRule.buildNever();
@@ -116,6 +127,7 @@
assertFalse(it.hasNext());
}
+ @Test
public void testSane() throws Exception {
final RecurrenceRule r = new RecurrenceRule(
ZonedDateTime.parse("1980-01-31T00:00:00.000Z"),
diff --git a/core/tests/coretests/src/android/util/SparseSetArrayTest.java b/core/tests/coretests/src/android/util/SparseSetArrayTest.java
index 3c17486a..1df1090 100644
--- a/core/tests/coretests/src/android/util/SparseSetArrayTest.java
+++ b/core/tests/coretests/src/android/util/SparseSetArrayTest.java
@@ -17,9 +17,13 @@
import static com.google.common.truth.Truth.assertThat;
+import android.platform.test.annotations.IgnoreUnderRavenwood;
+import android.platform.test.ravenwood.RavenwoodRule;
+
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -29,6 +33,9 @@
@SmallTest
@RunWith(AndroidJUnit4.class)
public class SparseSetArrayTest {
+ @Rule
+ public final RavenwoodRule mRavenwood = new RavenwoodRule();
+
@Test
public void testAddAll() {
final SparseSetArray<Integer> sparseSetArray = new SparseSetArray<>();
@@ -51,6 +58,7 @@
}
@Test
+ @IgnoreUnderRavenwood(reason = "b/315036461")
public void testCopyConstructor() {
final SparseSetArray<Integer> sparseSetArray = new SparseSetArray<>();
diff --git a/core/tests/coretests/src/android/util/StateSetTest.java b/core/tests/coretests/src/android/util/StateSetTest.java
index b5d6270..dfd1523 100644
--- a/core/tests/coretests/src/android/util/StateSetTest.java
+++ b/core/tests/coretests/src/android/util/StateSetTest.java
@@ -16,16 +16,29 @@
package android.util;
-import androidx.test.filters.SmallTest;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
-import junit.framework.TestCase;
+import android.platform.test.annotations.IgnoreUnderRavenwood;
+import android.platform.test.ravenwood.RavenwoodRule;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
/**
* Tests for {@link StateSet}
*/
+@RunWith(AndroidJUnit4.class)
+@IgnoreUnderRavenwood(blockedBy = StateSet.class)
+public class StateSetTest {
+ @Rule
+ public final RavenwoodRule mRavenwood = new RavenwoodRule();
-public class StateSetTest extends TestCase {
-
+ @Test
@SmallTest
public void testStateSetPositiveMatches() throws Exception {
int[] stateSpec = new int[2];
@@ -48,6 +61,7 @@
assertTrue(StateSet.stateSetMatches(stateSpec, stateSet));
}
+ @Test
@SmallTest
public void testStatesSetMatchMixEmUp() throws Exception {
int[] stateSpec = new int[2];
@@ -70,6 +84,7 @@
assertTrue(StateSet.stateSetMatches(stateSpec, stateSet));
}
+ @Test
@SmallTest
public void testStateSetNegativeMatches() throws Exception {
int[] stateSpec = new int[2];
@@ -92,6 +107,7 @@
assertFalse(StateSet.stateSetMatches(stateSpec, stateSet));
}
+ @Test
@SmallTest
public void testEmptySetMatchesNegtives() throws Exception {
int[] stateSpec = {-12345, -6789};
@@ -101,6 +117,7 @@
assertTrue(StateSet.stateSetMatches(stateSpec, stateSet2));
}
+ @Test
@SmallTest
public void testEmptySetFailsPositives() throws Exception {
int[] stateSpec = {12345};
@@ -110,6 +127,7 @@
assertFalse(StateSet.stateSetMatches(stateSpec, stateSet2));
}
+ @Test
@SmallTest
public void testEmptySetMatchesWildcard() throws Exception {
int[] stateSpec = StateSet.WILD_CARD;
@@ -119,6 +137,7 @@
assertTrue(StateSet.stateSetMatches(stateSpec, stateSet2));
}
+ @Test
@SmallTest
public void testSingleStatePositiveMatches() throws Exception {
int[] stateSpec = new int[2];
@@ -135,6 +154,7 @@
assertFalse(StateSet.stateSetMatches(stateSpec, state));
}
+ @Test
@SmallTest
public void testSingleStateNegativeMatches() throws Exception {
int[] stateSpec = new int[2];
@@ -151,6 +171,7 @@
assertTrue(StateSet.stateSetMatches(stateSpec, state));
}
+ @Test
@SmallTest
public void testZeroStateOnlyMatchesDefault() throws Exception {
int[] stateSpec = new int[3];
@@ -166,6 +187,7 @@
assertTrue(StateSet.stateSetMatches(stateSpec, state));
}
+ @Test
@SmallTest
public void testNullStateOnlyMatchesDefault() throws Exception {
int[] stateSpec = new int[3];
diff --git a/core/tests/coretests/src/android/util/apk/SourceStampVerifierTest.java b/core/tests/coretests/src/android/util/apk/SourceStampVerifierTest.java
index e0c583d..48e76f7 100644
--- a/core/tests/coretests/src/android/util/apk/SourceStampVerifierTest.java
+++ b/core/tests/coretests/src/android/util/apk/SourceStampVerifierTest.java
@@ -26,12 +26,16 @@
import static java.nio.file.StandardCopyOption.REPLACE_EXISTING;
import android.content.Context;
+import android.platform.test.annotations.IgnoreUnderRavenwood;
+import android.platform.test.ravenwood.RavenwoodRule;
import androidx.test.core.app.ApplicationProvider;
import libcore.io.Streams;
import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
@@ -48,13 +52,21 @@
/** Unit test for {@link android.util.apk.SourceStampVerifier} */
@RunWith(JUnit4.class)
+@IgnoreUnderRavenwood(blockedBy = SourceStampVerifier.class)
public class SourceStampVerifierTest {
+ @Rule
+ public final RavenwoodRule mRavenwood = new RavenwoodRule();
- private final Context mContext = ApplicationProvider.getApplicationContext();
+ private Context mContext;
private File mPrimaryApk;
private File mSecondaryApk;
+ @Before
+ public void setUp() throws Exception {
+ mContext = ApplicationProvider.getApplicationContext();
+ }
+
@After
public void tearDown() throws Exception {
if (mPrimaryApk != null) {
diff --git a/core/tests/coretests/src/android/view/menu/MenuScenario.java b/core/tests/coretests/src/android/view/menu/MenuScenario.java
index 668aec4..a1615af 100644
--- a/core/tests/coretests/src/android/view/menu/MenuScenario.java
+++ b/core/tests/coretests/src/android/view/menu/MenuScenario.java
@@ -18,7 +18,7 @@
import android.app.Activity;
import android.os.Bundle;
-import android.util.ListScenario;
+import android.widget.ListScenario;
import android.util.SparseArray;
import android.view.Menu;
import android.view.MenuItem;
diff --git a/core/tests/coretests/src/android/util/GridScenario.java b/core/tests/coretests/src/android/widget/GridScenario.java
similarity index 99%
rename from core/tests/coretests/src/android/util/GridScenario.java
rename to core/tests/coretests/src/android/widget/GridScenario.java
index e7ee1cd..d740808 100644
--- a/core/tests/coretests/src/android/util/GridScenario.java
+++ b/core/tests/coretests/src/android/widget/GridScenario.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2007 The Android Open Source Project
+ * Copyright (C) 2023 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.util;
+package android.widget;
import android.app.Activity;
import android.os.Bundle;
diff --git a/core/tests/coretests/src/android/util/InternalSelectionView.java b/core/tests/coretests/src/android/widget/InternalSelectionView.java
similarity index 98%
rename from core/tests/coretests/src/android/util/InternalSelectionView.java
rename to core/tests/coretests/src/android/widget/InternalSelectionView.java
index 4a1baef..f2d3182 100644
--- a/core/tests/coretests/src/android/util/InternalSelectionView.java
+++ b/core/tests/coretests/src/android/widget/InternalSelectionView.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2007 The Android Open Source Project
+ * Copyright (C) 2023 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.util;
+package android.widget;
import android.content.Context;
import android.content.res.TypedArray;
@@ -22,6 +22,7 @@
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
+import android.util.AttributeSet;
import android.view.KeyEvent;
import android.view.View;
diff --git a/core/tests/coretests/src/android/util/ListScenario.java b/core/tests/coretests/src/android/widget/ListScenario.java
similarity index 98%
rename from core/tests/coretests/src/android/util/ListScenario.java
rename to core/tests/coretests/src/android/widget/ListScenario.java
index 74dc4b4..589d90d 100644
--- a/core/tests/coretests/src/android/util/ListScenario.java
+++ b/core/tests/coretests/src/android/widget/ListScenario.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2007 The Android Open Source Project
+ * Copyright (C) 2023 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,20 +14,15 @@
* limitations under the License.
*/
-package android.util;
+package android.widget;
import android.app.Activity;
import android.graphics.Rect;
import android.os.Bundle;
+import android.util.ListItemFactory;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
-import android.widget.AdapterView;
-import android.widget.BaseAdapter;
-import android.widget.EditText;
-import android.widget.LinearLayout;
-import android.widget.ListView;
-import android.widget.TextView;
import com.google.android.collect.Maps;
diff --git a/core/tests/coretests/src/android/util/ScrollViewScenario.java b/core/tests/coretests/src/android/widget/ScrollViewScenario.java
similarity index 98%
rename from core/tests/coretests/src/android/util/ScrollViewScenario.java
rename to core/tests/coretests/src/android/widget/ScrollViewScenario.java
index ab1a642..ff2ab05 100644
--- a/core/tests/coretests/src/android/util/ScrollViewScenario.java
+++ b/core/tests/coretests/src/android/widget/ScrollViewScenario.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2008 The Android Open Source Project
+ * Copyright (C) 2023 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.util;
+package android.widget;
import android.app.Activity;
import android.content.Context;
@@ -23,6 +23,7 @@
import android.view.ViewGroup;
import android.view.Window;
import android.widget.Button;
+import android.widget.InternalSelectionView;
import android.widget.LinearLayout;
import android.widget.ScrollView;
import android.widget.TextView;
diff --git a/core/tests/coretests/src/android/widget/focus/AdjacentVerticalRectLists.java b/core/tests/coretests/src/android/widget/focus/AdjacentVerticalRectLists.java
index 85a4509..7e2f293 100644
--- a/core/tests/coretests/src/android/widget/focus/AdjacentVerticalRectLists.java
+++ b/core/tests/coretests/src/android/widget/focus/AdjacentVerticalRectLists.java
@@ -18,7 +18,7 @@
import android.app.Activity;
import android.os.Bundle;
-import android.util.InternalSelectionView;
+import android.widget.InternalSelectionView;
import android.view.ViewGroup;
import android.widget.LinearLayout;
@@ -30,7 +30,7 @@
* rectangle of the previously focused view. The view taking focus can use this
* to set an internal selection more appropriate using this rect.
*
- * This Activity excercises that behavior using three adjacent {@link android.util.InternalSelectionView}
+ * This Activity excercises that behavior using three adjacent {@link InternalSelectionView}
* that report interesting rects when giving up focus, and use interesting rects
* when taking focus to best select the internal row to show as selected.
*/
diff --git a/core/tests/coretests/src/android/widget/focus/FocusChangeWithInterestingRectHintTest.java b/core/tests/coretests/src/android/widget/focus/FocusChangeWithInterestingRectHintTest.java
index 26dc233..16a0b35 100644
--- a/core/tests/coretests/src/android/widget/focus/FocusChangeWithInterestingRectHintTest.java
+++ b/core/tests/coretests/src/android/widget/focus/FocusChangeWithInterestingRectHintTest.java
@@ -17,7 +17,7 @@
package android.widget.focus;
import android.test.ActivityInstrumentationTestCase;
-import android.util.InternalSelectionView;
+import android.widget.InternalSelectionView;
import android.view.KeyEvent;
import androidx.test.filters.LargeTest;
@@ -31,7 +31,7 @@
* rectangle of the previously focused view. The view taking focus can use this
* to set an internal selection more appropriate using this rect.
*
- * This tests that behavior using three adjacent {@link android.util.InternalSelectionView}
+ * This tests that behavior using three adjacent {@link InternalSelectionView}
* that report interesting rects when giving up focus, and use interesting rects
* when taking focus to best select the internal row to show as selected.
*
diff --git a/core/tests/coretests/src/android/widget/focus/ListOfInternalSelectionViews.java b/core/tests/coretests/src/android/widget/focus/ListOfInternalSelectionViews.java
index c5e69b6..4231b40 100644
--- a/core/tests/coretests/src/android/widget/focus/ListOfInternalSelectionViews.java
+++ b/core/tests/coretests/src/android/widget/focus/ListOfInternalSelectionViews.java
@@ -18,7 +18,7 @@
import android.app.Activity;
import android.os.Bundle;
-import android.util.InternalSelectionView;
+import android.widget.InternalSelectionView;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
diff --git a/core/tests/coretests/src/android/widget/focus/ScrollingThroughListOfFocusablesTest.java b/core/tests/coretests/src/android/widget/focus/ScrollingThroughListOfFocusablesTest.java
index e6e76cc..46190c4 100644
--- a/core/tests/coretests/src/android/widget/focus/ScrollingThroughListOfFocusablesTest.java
+++ b/core/tests/coretests/src/android/widget/focus/ScrollingThroughListOfFocusablesTest.java
@@ -18,7 +18,7 @@
import android.graphics.Rect;
import android.test.InstrumentationTestCase;
-import android.util.InternalSelectionView;
+import android.widget.InternalSelectionView;
import android.view.KeyEvent;
import android.widget.ListView;
diff --git a/core/tests/coretests/src/android/widget/gridview/GridDelete.java b/core/tests/coretests/src/android/widget/gridview/GridDelete.java
index b040f69..5f4326c 100644
--- a/core/tests/coretests/src/android/widget/gridview/GridDelete.java
+++ b/core/tests/coretests/src/android/widget/gridview/GridDelete.java
@@ -16,7 +16,7 @@
package android.widget.gridview;
-import android.util.GridScenario;
+import android.widget.GridScenario;
import android.view.KeyEvent;
import android.view.View;
import android.view.ViewGroup;
diff --git a/core/tests/coretests/src/android/widget/gridview/GridSetSelection.java b/core/tests/coretests/src/android/widget/gridview/GridSetSelection.java
index a3cda3b..140dd7b 100644
--- a/core/tests/coretests/src/android/widget/gridview/GridSetSelection.java
+++ b/core/tests/coretests/src/android/widget/gridview/GridSetSelection.java
@@ -16,7 +16,7 @@
package android.widget.gridview;
-import android.util.GridScenario;
+import android.widget.GridScenario;
/**
* Basic stacking from top scenario, nothing fancy. Items do not
diff --git a/core/tests/coretests/src/android/widget/gridview/GridSetSelectionBaseTest.java b/core/tests/coretests/src/android/widget/gridview/GridSetSelectionBaseTest.java
index db4f2dc..1428fea 100644
--- a/core/tests/coretests/src/android/widget/gridview/GridSetSelectionBaseTest.java
+++ b/core/tests/coretests/src/android/widget/gridview/GridSetSelectionBaseTest.java
@@ -18,7 +18,7 @@
import android.test.ActivityInstrumentationTestCase;
import android.test.ViewAsserts;
-import android.util.GridScenario;
+import android.widget.GridScenario;
import android.widget.GridView;
import androidx.test.filters.MediumTest;
diff --git a/core/tests/coretests/src/android/widget/gridview/GridSetSelectionMany.java b/core/tests/coretests/src/android/widget/gridview/GridSetSelectionMany.java
index a6d481f..7176619 100644
--- a/core/tests/coretests/src/android/widget/gridview/GridSetSelectionMany.java
+++ b/core/tests/coretests/src/android/widget/gridview/GridSetSelectionMany.java
@@ -16,7 +16,7 @@
package android.widget.gridview;
-import android.util.GridScenario;
+import android.widget.GridScenario;
/**
* Basic stacking from top scenario, nothing fancy. Items do
diff --git a/core/tests/coretests/src/android/widget/gridview/GridSetSelectionStackFromBottom.java b/core/tests/coretests/src/android/widget/gridview/GridSetSelectionStackFromBottom.java
index dfcd5fc..01bb2be 100644
--- a/core/tests/coretests/src/android/widget/gridview/GridSetSelectionStackFromBottom.java
+++ b/core/tests/coretests/src/android/widget/gridview/GridSetSelectionStackFromBottom.java
@@ -16,7 +16,7 @@
package android.widget.gridview;
-import android.util.GridScenario;
+import android.widget.GridScenario;
/**
* Basic stacking from bottom scenario, nothing fancy. Items do not
diff --git a/core/tests/coretests/src/android/widget/gridview/GridSetSelectionStackFromBottomMany.java b/core/tests/coretests/src/android/widget/gridview/GridSetSelectionStackFromBottomMany.java
index 26a567e..d79ee88 100644
--- a/core/tests/coretests/src/android/widget/gridview/GridSetSelectionStackFromBottomMany.java
+++ b/core/tests/coretests/src/android/widget/gridview/GridSetSelectionStackFromBottomMany.java
@@ -16,7 +16,7 @@
package android.widget.gridview;
-import android.util.GridScenario;
+import android.widget.GridScenario;
/**
* Basic stacking from bottom scenario, nothing fancy. Items do
diff --git a/core/tests/coretests/src/android/widget/gridview/GridSimple.java b/core/tests/coretests/src/android/widget/gridview/GridSimple.java
index 67bb751..6ca7eaa 100644
--- a/core/tests/coretests/src/android/widget/gridview/GridSimple.java
+++ b/core/tests/coretests/src/android/widget/gridview/GridSimple.java
@@ -18,7 +18,7 @@
import android.graphics.drawable.PaintDrawable;
import android.os.Bundle;
-import android.util.GridScenario;
+import android.widget.GridScenario;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
diff --git a/core/tests/coretests/src/android/widget/gridview/GridSingleColumn.java b/core/tests/coretests/src/android/widget/gridview/GridSingleColumn.java
index 566e71b..aaed9ba 100644
--- a/core/tests/coretests/src/android/widget/gridview/GridSingleColumn.java
+++ b/core/tests/coretests/src/android/widget/gridview/GridSingleColumn.java
@@ -16,7 +16,7 @@
package android.widget.gridview;
-import android.util.GridScenario;
+import android.widget.GridScenario;
import android.widget.GridView;
/**
diff --git a/core/tests/coretests/src/android/widget/gridview/GridStackFromBottom.java b/core/tests/coretests/src/android/widget/gridview/GridStackFromBottom.java
index 2f0a88f..457b00d 100644
--- a/core/tests/coretests/src/android/widget/gridview/GridStackFromBottom.java
+++ b/core/tests/coretests/src/android/widget/gridview/GridStackFromBottom.java
@@ -16,7 +16,7 @@
package android.widget.gridview;
-import android.util.GridScenario;
+import android.widget.GridScenario;
/**
* Basic bottom stacking from bottom scenario, nothing fancy. Items do not
diff --git a/core/tests/coretests/src/android/widget/gridview/GridStackFromBottomMany.java b/core/tests/coretests/src/android/widget/gridview/GridStackFromBottomMany.java
index 33a9592..9029bc5 100644
--- a/core/tests/coretests/src/android/widget/gridview/GridStackFromBottomMany.java
+++ b/core/tests/coretests/src/android/widget/gridview/GridStackFromBottomMany.java
@@ -16,7 +16,7 @@
package android.widget.gridview;
-import android.util.GridScenario;
+import android.widget.GridScenario;
/**
* Basic bottom stacking from bottom scenario, nothing fancy. The grid items do not fit on the
diff --git a/core/tests/coretests/src/android/widget/gridview/GridVerticalSpacing.java b/core/tests/coretests/src/android/widget/gridview/GridVerticalSpacing.java
index 0d01d30..6aa864f 100644
--- a/core/tests/coretests/src/android/widget/gridview/GridVerticalSpacing.java
+++ b/core/tests/coretests/src/android/widget/gridview/GridVerticalSpacing.java
@@ -16,7 +16,7 @@
package android.widget.gridview;
-import android.util.GridScenario;
+import android.widget.GridScenario;
/**
* A grid with vertical spacing between rows
diff --git a/core/tests/coretests/src/android/widget/gridview/GridVerticalSpacingStackFromBottom.java b/core/tests/coretests/src/android/widget/gridview/GridVerticalSpacingStackFromBottom.java
index bd68680..25ef682 100644
--- a/core/tests/coretests/src/android/widget/gridview/GridVerticalSpacingStackFromBottom.java
+++ b/core/tests/coretests/src/android/widget/gridview/GridVerticalSpacingStackFromBottom.java
@@ -16,7 +16,7 @@
package android.widget.gridview;
-import android.util.GridScenario;
+import android.widget.GridScenario;
/**
* A grid with vertical spacing between rows that stacks from the bottom
diff --git a/core/tests/coretests/src/android/widget/listview/AdjacentListsWithAdjacentISVsInside.java b/core/tests/coretests/src/android/widget/listview/AdjacentListsWithAdjacentISVsInside.java
index 62b93d6..1e57d69 100644
--- a/core/tests/coretests/src/android/widget/listview/AdjacentListsWithAdjacentISVsInside.java
+++ b/core/tests/coretests/src/android/widget/listview/AdjacentListsWithAdjacentISVsInside.java
@@ -18,7 +18,7 @@
import android.app.Activity;
import android.os.Bundle;
-import android.util.InternalSelectionView;
+import android.widget.InternalSelectionView;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
diff --git a/core/tests/coretests/src/android/widget/listview/ListBottomGravity.java b/core/tests/coretests/src/android/widget/listview/ListBottomGravity.java
index cd76d70..5d319c5 100644
--- a/core/tests/coretests/src/android/widget/listview/ListBottomGravity.java
+++ b/core/tests/coretests/src/android/widget/listview/ListBottomGravity.java
@@ -16,7 +16,7 @@
package android.widget.listview;
-import android.util.ListScenario;
+import android.widget.ListScenario;
/**
* Basic bottom gravity scenario, nothing fancy. Items do not
diff --git a/core/tests/coretests/src/android/widget/listview/ListBottomGravityMany.java b/core/tests/coretests/src/android/widget/listview/ListBottomGravityMany.java
index e048e3e..331fd12 100644
--- a/core/tests/coretests/src/android/widget/listview/ListBottomGravityMany.java
+++ b/core/tests/coretests/src/android/widget/listview/ListBottomGravityMany.java
@@ -16,7 +16,7 @@
package android.widget.listview;
-import android.util.ListScenario;
+import android.widget.ListScenario;
/**
* Basic bottom gravity scenario, nothing fancy. There are
diff --git a/core/tests/coretests/src/android/widget/listview/ListButtonsDiagonalAcrossItems.java b/core/tests/coretests/src/android/widget/listview/ListButtonsDiagonalAcrossItems.java
index 8640741..bc7c19f 100644
--- a/core/tests/coretests/src/android/widget/listview/ListButtonsDiagonalAcrossItems.java
+++ b/core/tests/coretests/src/android/widget/listview/ListButtonsDiagonalAcrossItems.java
@@ -19,7 +19,7 @@
import static android.util.ListItemFactory.Slot;
import android.util.ListItemFactory;
-import android.util.ListScenario;
+import android.widget.ListScenario;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
diff --git a/core/tests/coretests/src/android/widget/listview/ListEndingWithMultipleSeparators.java b/core/tests/coretests/src/android/widget/listview/ListEndingWithMultipleSeparators.java
index 85f9924..834f0d1 100644
--- a/core/tests/coretests/src/android/widget/listview/ListEndingWithMultipleSeparators.java
+++ b/core/tests/coretests/src/android/widget/listview/ListEndingWithMultipleSeparators.java
@@ -16,7 +16,7 @@
package android.widget.listview;
-import android.util.ListScenario;
+import android.widget.ListScenario;
public class ListEndingWithMultipleSeparators extends ListScenario {
diff --git a/core/tests/coretests/src/android/widget/listview/ListGetSelectedView.java b/core/tests/coretests/src/android/widget/listview/ListGetSelectedView.java
index 5639195..abd5d2e 100644
--- a/core/tests/coretests/src/android/widget/listview/ListGetSelectedView.java
+++ b/core/tests/coretests/src/android/widget/listview/ListGetSelectedView.java
@@ -16,7 +16,7 @@
package android.widget.listview;
-import android.util.ListScenario;
+import android.widget.ListScenario;
/**
* Basic top gravity scenario. This test is made to check that getSelectedView() will return
diff --git a/core/tests/coretests/src/android/widget/listview/ListHeterogeneous.java b/core/tests/coretests/src/android/widget/listview/ListHeterogeneous.java
index 74eda3b..fd24d61 100644
--- a/core/tests/coretests/src/android/widget/listview/ListHeterogeneous.java
+++ b/core/tests/coretests/src/android/widget/listview/ListHeterogeneous.java
@@ -17,7 +17,7 @@
package android.widget.listview;
import android.util.ListItemFactory;
-import android.util.ListScenario;
+import android.widget.ListScenario;
import android.view.View;
import android.view.ViewGroup;
diff --git a/core/tests/coretests/src/android/widget/listview/ListHorizontalFocusWithinItemWins.java b/core/tests/coretests/src/android/widget/listview/ListHorizontalFocusWithinItemWins.java
index e98de9c..7ce5ee3 100644
--- a/core/tests/coretests/src/android/widget/listview/ListHorizontalFocusWithinItemWins.java
+++ b/core/tests/coretests/src/android/widget/listview/ListHorizontalFocusWithinItemWins.java
@@ -20,7 +20,7 @@
import android.content.Context;
import android.util.ListItemFactory;
-import android.util.ListScenario;
+import android.widget.ListScenario;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
diff --git a/core/tests/coretests/src/android/widget/listview/ListInterleaveFocusables.java b/core/tests/coretests/src/android/widget/listview/ListInterleaveFocusables.java
index 0ec7a24..b613741 100644
--- a/core/tests/coretests/src/android/widget/listview/ListInterleaveFocusables.java
+++ b/core/tests/coretests/src/android/widget/listview/ListInterleaveFocusables.java
@@ -17,7 +17,7 @@
package android.widget.listview;
import android.util.ListItemFactory;
-import android.util.ListScenario;
+import android.widget.ListScenario;
import android.view.View;
import android.view.ViewGroup;
diff --git a/core/tests/coretests/src/android/widget/listview/ListItemFocusableAboveUnfocusable.java b/core/tests/coretests/src/android/widget/listview/ListItemFocusableAboveUnfocusable.java
index 3159e53..dc40f5f 100644
--- a/core/tests/coretests/src/android/widget/listview/ListItemFocusableAboveUnfocusable.java
+++ b/core/tests/coretests/src/android/widget/listview/ListItemFocusableAboveUnfocusable.java
@@ -17,7 +17,7 @@
package android.widget.listview;
import android.util.ListItemFactory;
-import android.util.ListScenario;
+import android.widget.ListScenario;
import android.view.View;
import android.view.ViewGroup;
diff --git a/core/tests/coretests/src/android/widget/listview/ListItemFocusablesClose.java b/core/tests/coretests/src/android/widget/listview/ListItemFocusablesClose.java
index 861e2a91..d21d234 100644
--- a/core/tests/coretests/src/android/widget/listview/ListItemFocusablesClose.java
+++ b/core/tests/coretests/src/android/widget/listview/ListItemFocusablesClose.java
@@ -17,7 +17,7 @@
package android.widget.listview;
import android.util.ListItemFactory;
-import android.util.ListScenario;
+import android.widget.ListScenario;
import android.view.View;
import android.view.ViewGroup;
diff --git a/core/tests/coretests/src/android/widget/listview/ListItemFocusablesFarApart.java b/core/tests/coretests/src/android/widget/listview/ListItemFocusablesFarApart.java
index e9c9c1d..0bb080b 100644
--- a/core/tests/coretests/src/android/widget/listview/ListItemFocusablesFarApart.java
+++ b/core/tests/coretests/src/android/widget/listview/ListItemFocusablesFarApart.java
@@ -17,7 +17,7 @@
package android.widget.listview;
import android.util.ListItemFactory;
-import android.util.ListScenario;
+import android.widget.ListScenario;
import android.view.View;
import android.view.ViewGroup;
diff --git a/core/tests/coretests/src/android/widget/listview/ListItemISVAndButton.java b/core/tests/coretests/src/android/widget/listview/ListItemISVAndButton.java
index 2a0e013..cbe07cc 100644
--- a/core/tests/coretests/src/android/widget/listview/ListItemISVAndButton.java
+++ b/core/tests/coretests/src/android/widget/listview/ListItemISVAndButton.java
@@ -17,8 +17,8 @@
package android.widget.listview;
import android.content.Context;
-import android.util.InternalSelectionView;
-import android.util.ListScenario;
+import android.widget.InternalSelectionView;
+import android.widget.ListScenario;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
diff --git a/core/tests/coretests/src/android/widget/listview/ListItemsExpandOnSelection.java b/core/tests/coretests/src/android/widget/listview/ListItemsExpandOnSelection.java
index d80fd90..240119e 100644
--- a/core/tests/coretests/src/android/widget/listview/ListItemsExpandOnSelection.java
+++ b/core/tests/coretests/src/android/widget/listview/ListItemsExpandOnSelection.java
@@ -17,7 +17,7 @@
package android.widget.listview;
import android.content.Context;
-import android.util.ListScenario;
+import android.widget.ListScenario;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AbsListView;
diff --git a/core/tests/coretests/src/android/widget/listview/ListLastItemPartiallyVisible.java b/core/tests/coretests/src/android/widget/listview/ListLastItemPartiallyVisible.java
index d733749..48c70d6 100644
--- a/core/tests/coretests/src/android/widget/listview/ListLastItemPartiallyVisible.java
+++ b/core/tests/coretests/src/android/widget/listview/ListLastItemPartiallyVisible.java
@@ -16,7 +16,7 @@
package android.widget.listview;
-import android.util.ListScenario;
+import android.widget.ListScenario;
/**
* A list where the very last item is partially visible, but still requires scrolling
diff --git a/core/tests/coretests/src/android/widget/listview/ListOfItemsShorterThanScreen.java b/core/tests/coretests/src/android/widget/listview/ListOfItemsShorterThanScreen.java
index 46decfa..55af8d4 100644
--- a/core/tests/coretests/src/android/widget/listview/ListOfItemsShorterThanScreen.java
+++ b/core/tests/coretests/src/android/widget/listview/ListOfItemsShorterThanScreen.java
@@ -16,7 +16,7 @@
package android.widget.listview;
-import android.util.ListScenario;
+import android.widget.ListScenario;
public class ListOfItemsShorterThanScreen extends ListScenario {
diff --git a/core/tests/coretests/src/android/widget/listview/ListOfItemsTallerThanScreen.java b/core/tests/coretests/src/android/widget/listview/ListOfItemsTallerThanScreen.java
index 0d88993..2b619e9 100644
--- a/core/tests/coretests/src/android/widget/listview/ListOfItemsTallerThanScreen.java
+++ b/core/tests/coretests/src/android/widget/listview/ListOfItemsTallerThanScreen.java
@@ -16,7 +16,7 @@
package android.widget.listview;
-import android.util.ListScenario;
+import android.widget.ListScenario;
public class ListOfItemsTallerThanScreen extends ListScenario {
diff --git a/core/tests/coretests/src/android/widget/listview/ListOfShortShortTallShortShort.java b/core/tests/coretests/src/android/widget/listview/ListOfShortShortTallShortShort.java
index 1639aa4..09f56b3 100644
--- a/core/tests/coretests/src/android/widget/listview/ListOfShortShortTallShortShort.java
+++ b/core/tests/coretests/src/android/widget/listview/ListOfShortShortTallShortShort.java
@@ -16,7 +16,7 @@
package android.widget.listview;
-import android.util.ListScenario;
+import android.widget.ListScenario;
/**
* Exposes fading in and out multiple items.
diff --git a/core/tests/coretests/src/android/widget/listview/ListOfShortTallShort.java b/core/tests/coretests/src/android/widget/listview/ListOfShortTallShort.java
index 960e129..8ad8fff 100644
--- a/core/tests/coretests/src/android/widget/listview/ListOfShortTallShort.java
+++ b/core/tests/coretests/src/android/widget/listview/ListOfShortTallShort.java
@@ -16,7 +16,7 @@
package android.widget.listview;
-import android.util.ListScenario;
+import android.widget.ListScenario;
/**
* Two short items separated by one that is taller than the screen.
diff --git a/core/tests/coretests/src/android/widget/listview/ListOfThinItems.java b/core/tests/coretests/src/android/widget/listview/ListOfThinItems.java
index 007479f..3f703af 100644
--- a/core/tests/coretests/src/android/widget/listview/ListOfThinItems.java
+++ b/core/tests/coretests/src/android/widget/listview/ListOfThinItems.java
@@ -16,7 +16,7 @@
package android.widget.listview;
-import android.util.ListScenario;
+import android.widget.ListScenario;
public class ListOfThinItems extends ListScenario {
diff --git a/core/tests/coretests/src/android/widget/listview/ListOfTouchables.java b/core/tests/coretests/src/android/widget/listview/ListOfTouchables.java
index 70b9081..f1dcdad 100644
--- a/core/tests/coretests/src/android/widget/listview/ListOfTouchables.java
+++ b/core/tests/coretests/src/android/widget/listview/ListOfTouchables.java
@@ -16,7 +16,7 @@
package android.widget.listview;
-import android.util.ListScenario;
+import android.widget.ListScenario;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
diff --git a/core/tests/coretests/src/android/widget/listview/ListSetSelection.java b/core/tests/coretests/src/android/widget/listview/ListSetSelection.java
index af8e899..a107117 100644
--- a/core/tests/coretests/src/android/widget/listview/ListSetSelection.java
+++ b/core/tests/coretests/src/android/widget/listview/ListSetSelection.java
@@ -17,7 +17,7 @@
package android.widget.listview;
import android.os.Bundle;
-import android.util.ListScenario;
+import android.widget.ListScenario;
import android.view.KeyEvent;
import android.view.View;
import android.widget.Button;
diff --git a/core/tests/coretests/src/android/widget/listview/ListSimple.java b/core/tests/coretests/src/android/widget/listview/ListSimple.java
index f53638e..9b3a98f 100644
--- a/core/tests/coretests/src/android/widget/listview/ListSimple.java
+++ b/core/tests/coretests/src/android/widget/listview/ListSimple.java
@@ -17,7 +17,7 @@
package android.widget.listview;
import android.os.Bundle;
-import android.util.ListScenario;
+import android.widget.ListScenario;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
diff --git a/core/tests/coretests/src/android/widget/listview/ListTopGravity.java b/core/tests/coretests/src/android/widget/listview/ListTopGravity.java
index 31339e9..67ef6d1 100644
--- a/core/tests/coretests/src/android/widget/listview/ListTopGravity.java
+++ b/core/tests/coretests/src/android/widget/listview/ListTopGravity.java
@@ -16,7 +16,7 @@
package android.widget.listview;
-import android.util.ListScenario;
+import android.widget.ListScenario;
/**
* Basic top gravity scenario, nothing fancy. Items do not
diff --git a/core/tests/coretests/src/android/widget/listview/ListTopGravityMany.java b/core/tests/coretests/src/android/widget/listview/ListTopGravityMany.java
index 5592ad9..9618c81 100644
--- a/core/tests/coretests/src/android/widget/listview/ListTopGravityMany.java
+++ b/core/tests/coretests/src/android/widget/listview/ListTopGravityMany.java
@@ -16,7 +16,7 @@
package android.widget.listview;
-import android.util.ListScenario;
+import android.widget.ListScenario;
/**
* Basic top gravity scenario, nothing fancy. There are
diff --git a/core/tests/coretests/src/android/widget/listview/ListWithEditTextHeader.java b/core/tests/coretests/src/android/widget/listview/ListWithEditTextHeader.java
index 5303faf..1a204a2 100644
--- a/core/tests/coretests/src/android/widget/listview/ListWithEditTextHeader.java
+++ b/core/tests/coretests/src/android/widget/listview/ListWithEditTextHeader.java
@@ -16,7 +16,7 @@
package android.widget.listview;
-import android.util.ListScenario;
+import android.widget.ListScenario;
/**
* A list view with a single edit text in a header.
diff --git a/core/tests/coretests/src/android/widget/listview/ListWithFirstScreenUnSelectable.java b/core/tests/coretests/src/android/widget/listview/ListWithFirstScreenUnSelectable.java
index 5261283..d6e7c6f 100644
--- a/core/tests/coretests/src/android/widget/listview/ListWithFirstScreenUnSelectable.java
+++ b/core/tests/coretests/src/android/widget/listview/ListWithFirstScreenUnSelectable.java
@@ -16,7 +16,7 @@
package android.widget.listview;
-import android.util.ListScenario;
+import android.widget.ListScenario;
/**
* The first item is unselectable, and takes up the whole screen.
diff --git a/core/tests/coretests/src/android/widget/listview/ListWithHeaders.java b/core/tests/coretests/src/android/widget/listview/ListWithHeaders.java
index 6030582..fa2832e 100644
--- a/core/tests/coretests/src/android/widget/listview/ListWithHeaders.java
+++ b/core/tests/coretests/src/android/widget/listview/ListWithHeaders.java
@@ -17,7 +17,7 @@
package android.widget.listview;
import android.os.Bundle;
-import android.util.ListScenario;
+import android.widget.ListScenario;
import android.widget.Button;
import android.widget.ListAdapter;
import android.widget.ListView;
diff --git a/core/tests/coretests/src/android/widget/listview/ListWithNoFadingEdge.java b/core/tests/coretests/src/android/widget/listview/ListWithNoFadingEdge.java
index b870fc8..f8b4f78 100644
--- a/core/tests/coretests/src/android/widget/listview/ListWithNoFadingEdge.java
+++ b/core/tests/coretests/src/android/widget/listview/ListWithNoFadingEdge.java
@@ -16,7 +16,7 @@
package android.widget.listview;
-import android.util.ListScenario;
+import android.widget.ListScenario;
public class ListWithNoFadingEdge extends ListScenario {
diff --git a/core/tests/coretests/src/android/widget/listview/ListWithOffScreenNextSelectable.java b/core/tests/coretests/src/android/widget/listview/ListWithOffScreenNextSelectable.java
index 2e65bd0..b8f14d2 100644
--- a/core/tests/coretests/src/android/widget/listview/ListWithOffScreenNextSelectable.java
+++ b/core/tests/coretests/src/android/widget/listview/ListWithOffScreenNextSelectable.java
@@ -16,7 +16,7 @@
package android.widget.listview;
-import android.util.ListScenario;
+import android.widget.ListScenario;
/**
* Pressing down from position 0 requires looking past positions 1, 2 and 3 to
diff --git a/core/tests/coretests/src/android/widget/listview/ListWithOnItemSelectedAction.java b/core/tests/coretests/src/android/widget/listview/ListWithOnItemSelectedAction.java
index 13e770c..afc4c3b 100644
--- a/core/tests/coretests/src/android/widget/listview/ListWithOnItemSelectedAction.java
+++ b/core/tests/coretests/src/android/widget/listview/ListWithOnItemSelectedAction.java
@@ -16,7 +16,7 @@
package android.widget.listview;
-import android.util.ListScenario;
+import android.widget.ListScenario;
import android.widget.TextView;
/**
diff --git a/core/tests/coretests/src/android/widget/listview/ListWithScreenOfNoSelectables.java b/core/tests/coretests/src/android/widget/listview/ListWithScreenOfNoSelectables.java
index 108ac4d..fe33bf0 100644
--- a/core/tests/coretests/src/android/widget/listview/ListWithScreenOfNoSelectables.java
+++ b/core/tests/coretests/src/android/widget/listview/ListWithScreenOfNoSelectables.java
@@ -16,7 +16,7 @@
package android.widget.listview;
-import android.util.ListScenario;
+import android.widget.ListScenario;
public class ListWithScreenOfNoSelectables extends ListScenario {
diff --git a/core/tests/coretests/src/android/widget/listview/ListWithSeparators.java b/core/tests/coretests/src/android/widget/listview/ListWithSeparators.java
index 0f4f2d8..1a3955a 100644
--- a/core/tests/coretests/src/android/widget/listview/ListWithSeparators.java
+++ b/core/tests/coretests/src/android/widget/listview/ListWithSeparators.java
@@ -16,7 +16,7 @@
package android.widget.listview;
-import android.util.ListScenario;
+import android.widget.ListScenario;
/**
* Basic separator scenario, nothing fancy.
diff --git a/core/tests/coretests/src/android/widget/listview/focus/AdjacentListsWithAdjacentISVsInsideTest.java b/core/tests/coretests/src/android/widget/listview/focus/AdjacentListsWithAdjacentISVsInsideTest.java
index e9baabf..09c140e 100644
--- a/core/tests/coretests/src/android/widget/listview/focus/AdjacentListsWithAdjacentISVsInsideTest.java
+++ b/core/tests/coretests/src/android/widget/listview/focus/AdjacentListsWithAdjacentISVsInsideTest.java
@@ -17,7 +17,7 @@
package android.widget.listview.focus;
import android.test.ActivityInstrumentationTestCase;
-import android.util.InternalSelectionView;
+import android.widget.InternalSelectionView;
import android.view.KeyEvent;
import android.widget.ListView;
import android.widget.listview.AdjacentListsWithAdjacentISVsInside;
diff --git a/core/tests/coretests/src/android/widget/scroll/ButtonAboveTallInternalSelectionView.java b/core/tests/coretests/src/android/widget/scroll/ButtonAboveTallInternalSelectionView.java
index a30985b..30f5c67 100644
--- a/core/tests/coretests/src/android/widget/scroll/ButtonAboveTallInternalSelectionView.java
+++ b/core/tests/coretests/src/android/widget/scroll/ButtonAboveTallInternalSelectionView.java
@@ -16,8 +16,8 @@
package android.widget.scroll;
-import android.util.InternalSelectionView;
-import android.util.ScrollViewScenario;
+import android.widget.InternalSelectionView;
+import android.widget.ScrollViewScenario;
import android.widget.Button;
/**
diff --git a/core/tests/coretests/src/android/widget/scroll/ButtonAboveTallInternalSelectionViewTest.java b/core/tests/coretests/src/android/widget/scroll/ButtonAboveTallInternalSelectionViewTest.java
index 825aa1a..d977ab4 100644
--- a/core/tests/coretests/src/android/widget/scroll/ButtonAboveTallInternalSelectionViewTest.java
+++ b/core/tests/coretests/src/android/widget/scroll/ButtonAboveTallInternalSelectionViewTest.java
@@ -17,7 +17,7 @@
package android.widget.scroll;
import android.test.ActivityInstrumentationTestCase;
-import android.util.InternalSelectionView;
+import android.widget.InternalSelectionView;
import android.view.KeyEvent;
import androidx.test.filters.MediumTest;
diff --git a/core/tests/coretests/src/android/widget/scroll/ButtonsWithTallTextViewInBetween.java b/core/tests/coretests/src/android/widget/scroll/ButtonsWithTallTextViewInBetween.java
index 47d36dd..5149fd4 100644
--- a/core/tests/coretests/src/android/widget/scroll/ButtonsWithTallTextViewInBetween.java
+++ b/core/tests/coretests/src/android/widget/scroll/ButtonsWithTallTextViewInBetween.java
@@ -16,7 +16,7 @@
package android.widget.scroll;
-import android.util.ScrollViewScenario;
+import android.widget.ScrollViewScenario;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.TextView;
diff --git a/core/tests/coretests/src/android/widget/scroll/ShortButtons.java b/core/tests/coretests/src/android/widget/scroll/ShortButtons.java
index 90ede7d..01d3b53 100644
--- a/core/tests/coretests/src/android/widget/scroll/ShortButtons.java
+++ b/core/tests/coretests/src/android/widget/scroll/ShortButtons.java
@@ -16,7 +16,7 @@
package android.widget.scroll;
-import android.util.ScrollViewScenario;
+import android.widget.ScrollViewScenario;
import android.widget.Button;
import android.widget.LinearLayout;
diff --git a/core/tests/coretests/src/android/widget/scroll/TallTextAboveButton.java b/core/tests/coretests/src/android/widget/scroll/TallTextAboveButton.java
index 4096fe9..bf800c0 100644
--- a/core/tests/coretests/src/android/widget/scroll/TallTextAboveButton.java
+++ b/core/tests/coretests/src/android/widget/scroll/TallTextAboveButton.java
@@ -16,7 +16,7 @@
package android.widget.scroll;
-import android.util.ScrollViewScenario;
+import android.widget.ScrollViewScenario;
/**
* An (unfocusable) text view that takes up more than the height
diff --git a/core/tests/coretests/src/android/widget/scroll/arrowscroll/MultiPageTextWithPadding.java b/core/tests/coretests/src/android/widget/scroll/arrowscroll/MultiPageTextWithPadding.java
index 7d5a8d8..6febdf9 100644
--- a/core/tests/coretests/src/android/widget/scroll/arrowscroll/MultiPageTextWithPadding.java
+++ b/core/tests/coretests/src/android/widget/scroll/arrowscroll/MultiPageTextWithPadding.java
@@ -16,7 +16,7 @@
package android.widget.scroll.arrowscroll;
-import android.util.ScrollViewScenario;
+import android.widget.ScrollViewScenario;
/**
* One TextView with a text covering several pages. Padding is added
diff --git a/core/tests/coretests/src/com/android/internal/accessibility/AccessibilityShortcutChooserActivityTest.java b/core/tests/coretests/src/com/android/internal/accessibility/AccessibilityShortcutChooserActivityTest.java
index 088b57f..6374e5d 100644
--- a/core/tests/coretests/src/com/android/internal/accessibility/AccessibilityShortcutChooserActivityTest.java
+++ b/core/tests/coretests/src/com/android/internal/accessibility/AccessibilityShortcutChooserActivityTest.java
@@ -18,7 +18,6 @@
import static androidx.test.espresso.Espresso.onView;
import static androidx.test.espresso.action.ViewActions.click;
-import static androidx.test.espresso.action.ViewActions.doubleClick;
import static androidx.test.espresso.action.ViewActions.scrollTo;
import static androidx.test.espresso.action.ViewActions.swipeUp;
import static androidx.test.espresso.assertion.ViewAssertions.doesNotExist;
@@ -85,10 +84,13 @@
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
+import org.mockito.Mockito;
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;
+import org.mockito.stubbing.Answer;
import java.util.Collections;
+import java.util.concurrent.atomic.AtomicBoolean;
/**
* Tests for {@link AccessibilityShortcutChooserActivity}.
@@ -151,6 +153,8 @@
when(mAccessibilityManagerService.getInstalledAccessibilityServiceList(
anyInt())).thenReturn(new ParceledListSlice<>(
Collections.singletonList(mAccessibilityServiceInfo)));
+ when(mAccessibilityManagerService.isAccessibilityServiceWarningRequired(any()))
+ .thenReturn(true);
when(mAccessibilityManagerService.isAccessibilityTargetAllowed(
anyString(), anyInt(), anyInt())).thenReturn(true);
when(mKeyguardManager.isKeyguardLocked()).thenReturn(false);
@@ -169,7 +173,7 @@
}
@Test
- @RequiresFlagsDisabled(Flags.FLAG_DEDUPLICATE_ACCESSIBILITY_WARNING_DIALOG)
+ @RequiresFlagsDisabled(Flags.FLAG_CLEANUP_ACCESSIBILITY_WARNING_DIALOG)
public void selectTestService_oldPermissionDialog_deny_dialogIsHidden() {
launchActivity();
openShortcutsList();
@@ -183,7 +187,7 @@
}
@Test
- @RequiresFlagsEnabled(Flags.FLAG_DEDUPLICATE_ACCESSIBILITY_WARNING_DIALOG)
+ @RequiresFlagsEnabled(Flags.FLAG_CLEANUP_ACCESSIBILITY_WARNING_DIALOG)
public void selectTestService_permissionDialog_allow_rowChecked() {
launchActivity();
openShortcutsList();
@@ -197,7 +201,7 @@
}
@Test
- @RequiresFlagsEnabled(Flags.FLAG_DEDUPLICATE_ACCESSIBILITY_WARNING_DIALOG)
+ @RequiresFlagsEnabled(Flags.FLAG_CLEANUP_ACCESSIBILITY_WARNING_DIALOG)
public void selectTestService_permissionDialog_deny_rowNotChecked() {
launchActivity();
openShortcutsList();
@@ -211,7 +215,7 @@
}
@Test
- @RequiresFlagsEnabled(Flags.FLAG_DEDUPLICATE_ACCESSIBILITY_WARNING_DIALOG)
+ @RequiresFlagsEnabled(Flags.FLAG_CLEANUP_ACCESSIBILITY_WARNING_DIALOG)
public void selectTestService_permissionDialog_uninstall_callsUninstaller_rowRemoved() {
launchActivity();
openShortcutsList();
@@ -227,6 +231,59 @@
}
@Test
+ @RequiresFlagsEnabled(Flags.FLAG_CLEANUP_ACCESSIBILITY_WARNING_DIALOG)
+ public void selectTestService_permissionDialog_notShownWhenNotRequired() throws Exception {
+ when(mAccessibilityManagerService.isAccessibilityServiceWarningRequired(any()))
+ .thenReturn(false);
+ launchActivity();
+ openShortcutsList();
+
+ // Clicking the test service should not show a permission dialog window,
+ assertThat(mDevice.findObject(By.text(TEST_LABEL)).clickAndWait(
+ Until.newWindow(), UI_TIMEOUT_MS)).isFalse();
+ // and should become checked.
+ assertThat(mDevice.findObject(By.checked(true))).isNotNull();
+ }
+
+ @Test
+ @RequiresFlagsEnabled(Flags.FLAG_CLEANUP_ACCESSIBILITY_WARNING_DIALOG)
+ public void selectTestService_notPermittedByAdmin_blockedEvenIfNoWarningRequired()
+ throws Exception {
+ when(mAccessibilityManagerService.isAccessibilityServiceWarningRequired(any()))
+ .thenReturn(false);
+ when(mAccessibilityManagerService.isAccessibilityTargetAllowed(
+ eq(TEST_COMPONENT_NAME.getPackageName()), anyInt(), anyInt())).thenReturn(false);
+ // This test class mocks AccessibilityManagerService, so the restricted dialog window
+ // will not actually appear and therefore cannot be used for a wait Until.newWindow().
+ // To still allow smart waiting in this test we can instead set up the mocked method
+ // to update an atomic boolean and wait for that to be set.
+ final Object waitObject = new Object();
+ final AtomicBoolean calledSendRestrictedDialogIntent = new AtomicBoolean(false);
+ Mockito.doAnswer((Answer<Void>) invocation -> {
+ synchronized (waitObject) {
+ calledSendRestrictedDialogIntent.set(true);
+ waitObject.notify();
+ }
+ return null;
+ }).when(mAccessibilityManagerService).sendRestrictedDialogIntent(
+ eq(TEST_COMPONENT_NAME.getPackageName()), anyInt(), anyInt());
+ launchActivity();
+ openShortcutsList();
+
+ mDevice.findObject(By.text(TEST_LABEL)).click();
+ final long timeout = System.currentTimeMillis() + UI_TIMEOUT_MS;
+ synchronized (waitObject) {
+ while (!calledSendRestrictedDialogIntent.get() &&
+ (System.currentTimeMillis() < timeout)) {
+ waitObject.wait(timeout - System.currentTimeMillis());
+ }
+ }
+
+ assertThat(calledSendRestrictedDialogIntent.get()).isTrue();
+ assertThat(mDevice.findObject(By.checked(true))).isNull();
+ }
+
+ @Test
public void clickServiceTarget_notPermittedByAdmin_sendRestrictedDialogIntent()
throws Exception {
when(mAccessibilityManagerService.isAccessibilityTargetAllowed(
@@ -329,7 +386,7 @@
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- if (Flags.deduplicateAccessibilityWarningDialog()) {
+ if (Flags.cleanupAccessibilityWarningDialog()) {
// Setting the Theme is necessary here for the dialog to use the proper style
// resources as designated in its layout XML.
setTheme(R.style.Theme_DeviceDefault_DayNight);
diff --git a/core/tests/coretests/src/com/android/internal/accessibility/dialog/AccessibilityServiceWarningTest.java b/core/tests/coretests/src/com/android/internal/accessibility/dialog/AccessibilityServiceWarningTest.java
index b76dd51..24aab61 100644
--- a/core/tests/coretests/src/com/android/internal/accessibility/dialog/AccessibilityServiceWarningTest.java
+++ b/core/tests/coretests/src/com/android/internal/accessibility/dialog/AccessibilityServiceWarningTest.java
@@ -58,7 +58,7 @@
@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper
@RequiresFlagsEnabled(
- android.view.accessibility.Flags.FLAG_DEDUPLICATE_ACCESSIBILITY_WARNING_DIALOG)
+ android.view.accessibility.Flags.FLAG_CLEANUP_ACCESSIBILITY_WARNING_DIALOG)
public class AccessibilityServiceWarningTest {
private static final String A11Y_SERVICE_PACKAGE_LABEL = "TestA11yService";
private static final String A11Y_SERVICE_SUMMARY = "TestA11yService summary";
diff --git a/core/tests/coretests/src/com/android/internal/util/BitUtilsTest.java b/core/tests/coretests/src/com/android/internal/util/BitUtilsTest.java
index fdba811..fdde36a 100644
--- a/core/tests/coretests/src/com/android/internal/util/BitUtilsTest.java
+++ b/core/tests/coretests/src/com/android/internal/util/BitUtilsTest.java
@@ -30,8 +30,8 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
-import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
import org.junit.Test;
import org.junit.runner.RunWith;
diff --git a/core/tests/coretests/src/com/android/internal/util/ContrastColorUtilTest.java b/core/tests/coretests/src/com/android/internal/util/ContrastColorUtilTest.java
index 5f5bf11..e6ebfef 100644
--- a/core/tests/coretests/src/com/android/internal/util/ContrastColorUtilTest.java
+++ b/core/tests/coretests/src/com/android/internal/util/ContrastColorUtilTest.java
@@ -23,6 +23,8 @@
import android.content.Context;
import android.content.res.ColorStateList;
import android.graphics.Color;
+import android.platform.test.annotations.IgnoreUnderRavenwood;
+import android.platform.test.ravenwood.RavenwoodRule;
import android.text.Spannable;
import android.text.SpannableString;
import android.text.SpannableStringBuilder;
@@ -32,23 +34,21 @@
import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
import com.android.internal.R;
-import junit.framework.TestCase;
-
-import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
+import org.junit.runner.RunWith;
-public class ContrastColorUtilTest extends TestCase {
+@RunWith(AndroidJUnit4.class)
+@IgnoreUnderRavenwood(blockedBy = Color.class)
+public class ContrastColorUtilTest {
+ @Rule
+ public final RavenwoodRule mRavenwood = new RavenwoodRule();
- private Context mContext;
-
- @Before
- public void setUp() {
- mContext = InstrumentationRegistry.getContext();
- }
-
+ @Test
@SmallTest
public void testEnsureTextContrastAgainstDark() {
int darkBg = 0xFF35302A;
@@ -70,6 +70,7 @@
assertContrastIsWithinRange(selfContrastColor, darkBg, 4.5, 4.75);
}
+ @Test
@SmallTest
public void testEnsureTextContrastAgainstLight() {
int lightBg = 0xFFFFF8F2;
@@ -91,13 +92,16 @@
assertContrastIsWithinRange(selfContrastColor, lightBg, 4.5, 4.75);
}
+ @Test
public void testBuilder_ensureColorSpanContrast_removesAllFullLengthColorSpans() {
+ Context context = InstrumentationRegistry.getContext();
+
Spannable text = new SpannableString("blue text with yellow and green");
text.setSpan(new ForegroundColorSpan(Color.YELLOW), 15, 21,
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
text.setSpan(new ForegroundColorSpan(Color.BLUE), 0, text.length(),
Spanned.SPAN_INCLUSIVE_INCLUSIVE);
- TextAppearanceSpan taSpan = new TextAppearanceSpan(mContext,
+ TextAppearanceSpan taSpan = new TextAppearanceSpan(context,
R.style.TextAppearance_DeviceDefault_Notification_Title);
assertThat(taSpan.getTextColor()).isNotNull(); // it must be set to prove it is cleared.
text.setSpan(taSpan, 0, text.length(),
@@ -123,6 +127,7 @@
assertThat(((ForegroundColorSpan) spans[2]).getForegroundColor()).isEqualTo(Color.GREEN);
}
+ @Test
public void testBuilder_ensureColorSpanContrast_partialLength_adjusted() {
int background = 0xFFFF0101; // Slightly lighter red
CharSequence text = new SpannableStringBuilder()
@@ -138,14 +143,17 @@
assertContrastIsWithinRange(foregroundColor, background, 3, 3.2);
}
+ @Test
public void testBuilder_ensureColorSpanContrast_worksWithComplexInput() {
+ Context context = InstrumentationRegistry.getContext();
+
Spannable text = new SpannableString("blue text with yellow and green and cyan");
text.setSpan(new ForegroundColorSpan(Color.YELLOW), 15, 21,
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
text.setSpan(new ForegroundColorSpan(Color.BLUE), 0, text.length(),
Spanned.SPAN_INCLUSIVE_INCLUSIVE);
// cyan TextAppearanceSpan
- TextAppearanceSpan taSpan = new TextAppearanceSpan(mContext,
+ TextAppearanceSpan taSpan = new TextAppearanceSpan(context,
R.style.TextAppearance_DeviceDefault_Notification_Title);
taSpan = new TextAppearanceSpan(taSpan.getFamily(), taSpan.getTextStyle(),
taSpan.getTextSize(), ColorStateList.valueOf(Color.CYAN), null);
diff --git a/core/tests/coretests/src/com/android/internal/util/DumpUtilsTest.java b/core/tests/coretests/src/com/android/internal/util/DumpUtilsTest.java
index 36c2a62..d2d3c13 100644
--- a/core/tests/coretests/src/com/android/internal/util/DumpUtilsTest.java
+++ b/core/tests/coretests/src/com/android/internal/util/DumpUtilsTest.java
@@ -25,10 +25,16 @@
import static com.google.common.truth.Truth.assertWithMessage;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
import android.content.ComponentName;
import android.util.SparseArray;
-import junit.framework.TestCase;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
import java.io.PrintWriter;
import java.io.StringWriter;
@@ -37,7 +43,8 @@
* Run with:
atest FrameworksCoreTests:DumpUtilsTest
*/
-public class DumpUtilsTest extends TestCase {
+@RunWith(AndroidJUnit4.class)
+public class DumpUtilsTest {
private final StringWriter mStringWriter = new StringWriter();
private final PrintWriter mPrintWriter = new PrintWriter(mStringWriter);
@@ -56,6 +63,7 @@
return () -> cn(componentName);
}
+ @Test
public void testIsPlatformPackage() {
assertTrue(isPlatformPackage("android"));
assertTrue(isPlatformPackage("android.abc"));
@@ -79,6 +87,7 @@
assertFalse(isPlatformPackage(wcn("com.google.def/abc")));
}
+ @Test
public void testIsNonPlatformPackage() {
assertFalse(isNonPlatformPackage("android"));
assertFalse(isNonPlatformPackage("android.abc"));
@@ -102,6 +111,7 @@
assertTrue(isNonPlatformPackage(wcn("com.google.def/abc")));
}
+ @Test
public void testIsPlatformCriticalPackage() {
for (final ComponentName componentName : CRITICAL_SECTION_COMPONENTS) {
assertTrue(isPlatformCriticalPackage(() -> componentName));
@@ -115,6 +125,7 @@
assertFalse(isPlatformCriticalPackage(null));
}
+ @Test
public void testIsPlatformNonCriticalPackage() {
for (final ComponentName componentName : CRITICAL_SECTION_COMPONENTS) {
assertFalse(isPlatformNonCriticalPackage(() -> componentName));
@@ -128,6 +139,7 @@
assertFalse(isPlatformNonCriticalPackage(null));
}
+ @Test
public void testFilterRecord() {
assertFalse(filterRecord(null).test(wcn("com.google.p/abc")));
assertFalse(filterRecord(null).test(wcn("com.android.p/abc")));
@@ -178,6 +190,7 @@
wcn("com.google/.abc")));
}
+ @Test
public void testDumpSparseArray_empty() {
SparseArray<String> array = new SparseArray<>();
@@ -188,6 +201,7 @@
assertWithMessage("empty array dump").that(output).isEqualTo("...No whatevers\n");
}
+ @Test
public void testDumpSparseArray_oneElement() {
SparseArray<String> array = new SparseArray<>();
array.put(1, "uno");
@@ -201,6 +215,7 @@
+ "..0: 1->uno\n");
}
+ @Test
public void testDumpSparseArray_oneNullElement() {
SparseArray<String> array = new SparseArray<>();
array.put(1, null);
@@ -214,6 +229,7 @@
+ "..0: 1->(null)\n");
}
+ @Test
public void testDumpSparseArray_multipleElements() {
SparseArray<String> array = new SparseArray<>();
array.put(1, "uno");
@@ -231,6 +247,7 @@
+ "..2: 42->(null)\n");
}
+ @Test
public void testDumpSparseArray_keyDumperOnly() {
SparseArray<String> array = new SparseArray<>();
array.put(1, "uno");
@@ -251,6 +268,7 @@
+ "_2=42_(null)\n");
}
+ @Test
public void testDumpSparseArray_valueDumperOnly() {
SparseArray<String> array = new SparseArray<>();
array.put(1, "uno");
@@ -272,6 +290,7 @@
+ "..2: 42->(null)\n");
}
+ @Test
public void testDumpSparseArray_keyAndValueDumpers() {
SparseArray<String> array = new SparseArray<>();
array.put(1, "uno");
@@ -295,6 +314,7 @@
+ "_2=42_(null)\n");
}
+ @Test
public void testDumpSparseArrayValues() {
SparseArray<String> array = new SparseArray<>();
array.put(1, "uno");
@@ -306,7 +326,7 @@
String output = flushPrintWriter();
assertWithMessage("dump of %s", array).that(output).isEqualTo(""
- + ".3 numbers:\n"
+ + ".3 number(s):\n"
+ "..uno\n"
+ "..duo\n"
+ "..(null)\n");
diff --git a/core/tests/coretests/src/com/android/internal/util/DumpableContainerImplTest.java b/core/tests/coretests/src/com/android/internal/util/DumpableContainerImplTest.java
index 589e4f9..61d4e3d 100644
--- a/core/tests/coretests/src/com/android/internal/util/DumpableContainerImplTest.java
+++ b/core/tests/coretests/src/com/android/internal/util/DumpableContainerImplTest.java
@@ -17,30 +17,32 @@
import static com.google.common.truth.Truth.assertWithMessage;
-import static org.testng.Assert.assertThrows;
-
import android.util.Dumpable;
+import androidx.test.runner.AndroidJUnit4;
+
import com.android.internal.util.dump.DumpableContainerImpl;
import org.junit.Test;
+import org.junit.runner.RunWith;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.concurrent.atomic.AtomicReference;
-public final class DumpableContainerImplTest {
+@RunWith(AndroidJUnit4.class)
+public class DumpableContainerImplTest {
private final DumpableContainerImpl mImpl = new DumpableContainerImpl();
private final StringWriter mSw = new StringWriter();
private final PrintWriter mWriter = new PrintWriter(mSw);
- @Test
+ @Test(expected = NullPointerException.class)
public void testAddDumpable_null() {
- assertThrows(NullPointerException.class, () -> mImpl.addDumpable(null));
+ mImpl.addDumpable(null);
}
- @Test
+ @Test(expected = NullPointerException.class)
public void testAddDumpable_dumpableWithoutName() {
Dumpable namelessDumpable = new Dumpable() {
@@ -55,7 +57,7 @@
}
};
- assertThrows(NullPointerException.class, () -> mImpl.addDumpable(namelessDumpable));
+ mImpl.addDumpable(namelessDumpable);
}
@Test
@@ -179,9 +181,9 @@
+ "......6 Args: 4,8,15,16,23,42,\n");
}
- @Test
+ @Test(expected = NullPointerException.class)
public void testRemoveDumpable_null() {
- assertThrows(NullPointerException.class, () -> mImpl.removeDumpable(null));
+ mImpl.removeDumpable(null);
}
@Test
diff --git a/core/tests/coretests/src/com/android/internal/util/FakeLatencyTrackerTest.java b/core/tests/coretests/src/com/android/internal/util/FakeLatencyTrackerTest.java
index 3946cdf..6bd67ea 100644
--- a/core/tests/coretests/src/com/android/internal/util/FakeLatencyTrackerTest.java
+++ b/core/tests/coretests/src/com/android/internal/util/FakeLatencyTrackerTest.java
@@ -24,12 +24,15 @@
import static com.google.common.truth.Truth.assertThat;
+import android.platform.test.annotations.IgnoreUnderRavenwood;
+import android.platform.test.ravenwood.RavenwoodRule;
import android.provider.DeviceConfig;
-import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.runner.AndroidJUnit4;
import org.junit.After;
import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -42,7 +45,10 @@
* {@link LatencyTrackerTest}
*/
@RunWith(AndroidJUnit4.class)
+@IgnoreUnderRavenwood(blockedBy = DeviceConfig.class)
public class FakeLatencyTrackerTest {
+ @Rule
+ public final RavenwoodRule mRavenwood = new RavenwoodRule();
private FakeLatencyTracker mFakeLatencyTracker;
private int mInitialSyncDisabledMode;
diff --git a/core/tests/coretests/src/com/android/internal/util/FastDataTest.java b/core/tests/coretests/src/com/android/internal/util/FastDataTest.java
index de325ab..316b95ac 100644
--- a/core/tests/coretests/src/com/android/internal/util/FastDataTest.java
+++ b/core/tests/coretests/src/com/android/internal/util/FastDataTest.java
@@ -21,6 +21,7 @@
import static org.junit.Assert.fail;
import android.annotation.NonNull;
+import android.platform.test.ravenwood.RavenwoodRule;
import android.util.ExceptionUtils;
import com.android.modules.utils.FastDataInput;
@@ -29,6 +30,7 @@
import libcore.util.HexEncoding;
import org.junit.Assume;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
@@ -51,6 +53,9 @@
@RunWith(Parameterized.class)
public class FastDataTest {
+ @Rule
+ public final RavenwoodRule mRavenwood = new RavenwoodRule();
+
private final boolean use4ByteSequence;
private static final String TEST_SHORT_STRING = "a";
@@ -59,7 +64,12 @@
@Parameters(name = "use4ByteSequence={0}")
public static Collection<Object[]> data() {
- return Arrays.asList(new Object[][] { {true}, {false} });
+ if (RavenwoodRule.isUnderRavenwood()) {
+ // TODO: 4-byte sequences are only supported on ART
+ return Arrays.asList(new Object[][]{{false}});
+ } else {
+ return Arrays.asList(new Object[][]{{true}, {false}});
+ }
}
public FastDataTest(boolean use4ByteSequence) {
diff --git a/core/tests/coretests/src/com/android/internal/util/FastMathTest.java b/core/tests/coretests/src/com/android/internal/util/FastMathTest.java
new file mode 100644
index 0000000..dd26334
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/util/FastMathTest.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.util;
+
+import static org.junit.Assert.assertEquals;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+public class FastMathTest {
+ @Test
+ public void testRound() {
+ assertEquals(-1, FastMath.round(-1.0f));
+ assertEquals(0, FastMath.round(0.0f));
+ assertEquals(1, FastMath.round(1.0f));
+ }
+}
diff --git a/core/tests/coretests/src/com/android/internal/util/GrowingArrayUtilsTest.java b/core/tests/coretests/src/com/android/internal/util/GrowingArrayUtilsTest.java
new file mode 100644
index 0000000..8456161
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/util/GrowingArrayUtilsTest.java
@@ -0,0 +1,140 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.util;
+
+import static com.android.internal.util.GrowingArrayUtils.append;
+import static com.android.internal.util.GrowingArrayUtils.insert;
+
+import static org.junit.Assert.assertArrayEquals;
+
+import android.util.EmptyArray;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.Arrays;
+
+@RunWith(AndroidJUnit4.class)
+public class GrowingArrayUtilsTest {
+ private final Object TEST_OBJECT = new Object();
+
+ @Test
+ public void testAppend_Object() {
+ assertArrayEqualsPrefix(new Object[]{TEST_OBJECT},
+ append(EmptyArray.OBJECT, 0, TEST_OBJECT));
+ assertArrayEqualsPrefix(new Object[]{TEST_OBJECT, TEST_OBJECT},
+ append(new Object[]{TEST_OBJECT}, 1, TEST_OBJECT));
+ assertArrayEqualsPrefix(new Object[]{TEST_OBJECT},
+ append(new Object[]{null, null}, 0, TEST_OBJECT));
+ }
+
+ @Test
+ public void testInsert_Object() {
+ assertArrayEqualsPrefix(new Object[]{TEST_OBJECT},
+ insert(EmptyArray.OBJECT, 0, 0, TEST_OBJECT));
+ assertArrayEqualsPrefix(new Object[]{null, TEST_OBJECT},
+ insert(new Object[]{TEST_OBJECT}, 1, 0, null));
+ assertArrayEqualsPrefix(new Object[]{TEST_OBJECT, null},
+ insert(new Object[]{TEST_OBJECT}, 1, 1, null));
+ assertArrayEqualsPrefix(new Object[]{TEST_OBJECT, null, TEST_OBJECT},
+ insert(new Object[]{TEST_OBJECT, TEST_OBJECT}, 2, 1, null));
+ }
+
+ @Test
+ public void testAppend_Int() {
+ assertArrayEqualsPrefix(new int[]{42},
+ append(EmptyArray.INT, 0, 42));
+ assertArrayEqualsPrefix(new int[]{42, 42},
+ append(new int[]{42}, 1, 42));
+ assertArrayEqualsPrefix(new int[]{42},
+ append(new int[]{0, 0}, 0, 42));
+ }
+
+ @Test
+ public void testInsert_Int() {
+ assertArrayEqualsPrefix(new int[]{42},
+ insert(EmptyArray.INT, 0, 0, 42));
+ assertArrayEqualsPrefix(new int[]{21, 42},
+ insert(new int[]{42}, 1, 0, 21));
+ assertArrayEqualsPrefix(new int[]{42, 21},
+ insert(new int[]{42}, 1, 1, 21));
+ assertArrayEqualsPrefix(new int[]{42, 21, 43},
+ insert(new int[]{42, 43}, 2, 1, 21));
+ }
+
+ @Test
+ public void testAppend_Long() {
+ assertArrayEqualsPrefix(new long[]{42},
+ append(EmptyArray.LONG, 0, 42));
+ assertArrayEqualsPrefix(new long[]{42, 42},
+ append(new long[]{42}, 1, 42));
+ assertArrayEqualsPrefix(new long[]{42},
+ append(new long[]{0, 0}, 0, 42));
+ }
+
+ @Test
+ public void testInsert_Long() {
+ assertArrayEqualsPrefix(new long[]{42},
+ insert(EmptyArray.LONG, 0, 0, 42));
+ assertArrayEqualsPrefix(new long[]{21, 42},
+ insert(new long[]{42}, 1, 0, 21));
+ assertArrayEqualsPrefix(new long[]{42, 21},
+ insert(new long[]{42}, 1, 1, 21));
+ assertArrayEqualsPrefix(new long[]{42, 21, 43},
+ insert(new long[]{42, 43}, 2, 1, 21));
+ }
+
+ @Test
+ public void testAppend_Boolean() {
+ assertArrayEqualsPrefix(new boolean[]{true},
+ append(EmptyArray.BOOLEAN, 0, true));
+ assertArrayEqualsPrefix(new boolean[]{true, true},
+ append(new boolean[]{true}, 1, true));
+ assertArrayEqualsPrefix(new boolean[]{true},
+ append(new boolean[]{false, false}, 0, true));
+ }
+
+ @Test
+ public void testInsert_Boolean() {
+ assertArrayEqualsPrefix(new boolean[]{true},
+ insert(EmptyArray.BOOLEAN, 0, 0, true));
+ assertArrayEqualsPrefix(new boolean[]{false, true},
+ insert(new boolean[]{true}, 1, 0, false));
+ assertArrayEqualsPrefix(new boolean[]{true, false},
+ insert(new boolean[]{true}, 1, 1, false));
+ assertArrayEqualsPrefix(new boolean[]{true, false, true},
+ insert(new boolean[]{true, true}, 2, 1, false));
+ }
+
+ private <T> void assertArrayEqualsPrefix(T[] expected, T[] actual) {
+ assertArrayEquals(expected, Arrays.copyOf(actual, expected.length));
+ }
+
+ private void assertArrayEqualsPrefix(int[] expected, int[] actual) {
+ assertArrayEquals(expected, Arrays.copyOf(actual, expected.length));
+ }
+
+ private void assertArrayEqualsPrefix(long[] expected, long[] actual) {
+ assertArrayEquals(expected, Arrays.copyOf(actual, expected.length));
+ }
+
+ private void assertArrayEqualsPrefix(boolean[] expected, boolean[] actual) {
+ assertArrayEquals(expected, Arrays.copyOf(actual, expected.length));
+ }
+}
diff --git a/core/tests/coretests/src/com/android/internal/util/HexDumpTest.java b/core/tests/coretests/src/com/android/internal/util/HexDumpTest.java
index f1cd89b..dcffa1c 100644
--- a/core/tests/coretests/src/com/android/internal/util/HexDumpTest.java
+++ b/core/tests/coretests/src/com/android/internal/util/HexDumpTest.java
@@ -19,14 +19,22 @@
import static com.android.internal.util.HexDump.hexStringToByteArray;
import static com.android.internal.util.HexDump.toHexString;
-import junit.framework.TestCase;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.Arrays;
import java.util.Random;
-public final class HexDumpTest extends TestCase {
+@RunWith(AndroidJUnit4.class)
+public final class HexDumpTest {
+ @Test
public void testBytesToHexString() {
assertEquals("abcdef", HexDump.toHexString(
new byte[] { (byte) 0xab, (byte) 0xcd, (byte) 0xef }, false));
@@ -34,12 +42,14 @@
new byte[] { (byte) 0xab, (byte) 0xcd, (byte) 0xef }, true));
}
+ @Test
public void testNullByteArray() {
assertThrows(
NullPointerException.class,
() -> HexDump.toHexString(null));
}
+ @Test
public void testBytesToHexString_allByteValues() {
byte[] bytes = new byte[256];
for (int i = 0; i < bytes.length; i++) {
@@ -57,6 +67,7 @@
assertEquals(expected, HexDump.toHexString(bytes));
}
+ @Test
public void testRoundTrip_fromBytes() {
Random deterministicRandom = new Random(31337); // arbitrary but deterministic
for (int length = 0; length < 100; length++) {
@@ -68,6 +79,7 @@
}
}
+ @Test
public void testRoundTrip_fromString() {
String hexString = "0123456789ABCDEF72f9a3438934c378d34f32a8b932";
for (int length = 0; length < hexString.length(); length += 2) {
@@ -77,6 +89,7 @@
}
}
+ @Test
public void testToHexString_offsetLength() {
byte[] bytes = new byte[32];
for (int i = 0; i < 16; i++) {
@@ -97,6 +110,7 @@
}
}
+ @Test
public void testToHexString_case() {
byte[] bytes = new byte[32];
for (int i = 0; i < 16; i++) {
@@ -113,16 +127,19 @@
assertEquals(expected.toUpperCase(), toHexString(bytes));
}
+ @Test
public void testHexStringToByteArray_empty() {
assertBytesEqual(new byte[0], HexDump.hexStringToByteArray(""));
}
+ @Test
public void testHexStringToByteArray_null() {
assertThrows(
NullPointerException.class,
() -> HexDump.hexStringToByteArray((String) null));
}
+ @Test
public void testHexStringToByteArray_invalidCharacters() {
// IllegalArgumentException would probably have been better than RuntimeException, but it
// might be too late to change now.
@@ -137,6 +154,7 @@
() -> HexDump.hexStringToByteArray("abcdefgh"));
}
+ @Test
public void testHexStringToByteArray_oddLength() {
// IllegalArgumentException would probably have been better than
// StringIndexOutOfBoundsException, but it might be too late to change now.
diff --git a/core/tests/coretests/src/com/android/internal/util/LatencyTrackerTest.java b/core/tests/coretests/src/com/android/internal/util/LatencyTrackerTest.java
index f24894e..010f724 100644
--- a/core/tests/coretests/src/com/android/internal/util/LatencyTrackerTest.java
+++ b/core/tests/coretests/src/com/android/internal/util/LatencyTrackerTest.java
@@ -25,9 +25,11 @@
import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth.assertWithMessage;
+import android.platform.test.annotations.IgnoreUnderRavenwood;
+import android.platform.test.ravenwood.RavenwoodRule;
import android.provider.DeviceConfig;
-import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.runner.AndroidJUnit4;
import com.android.internal.util.LatencyTracker.ActionProperties;
@@ -49,7 +51,11 @@
import java.util.stream.Collectors;
@RunWith(AndroidJUnit4.class)
+@IgnoreUnderRavenwood(blockedBy = DeviceConfig.class)
public class LatencyTrackerTest {
+ @Rule
+ public final RavenwoodRule mRavenwood = new RavenwoodRule();
+
private static final String ENUM_NAME_PREFIX = "UIACTION_LATENCY_REPORTED__ACTION__";
@Rule
diff --git a/core/tests/coretests/src/com/android/internal/util/LineBreakBufferedWriterTest.java b/core/tests/coretests/src/com/android/internal/util/LineBreakBufferedWriterTest.java
index b2a2265..e6418fa 100644
--- a/core/tests/coretests/src/com/android/internal/util/LineBreakBufferedWriterTest.java
+++ b/core/tests/coretests/src/com/android/internal/util/LineBreakBufferedWriterTest.java
@@ -16,7 +16,13 @@
package com.android.internal.util;
-import junit.framework.TestCase;
+import static org.junit.Assert.assertEquals;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
import java.io.ByteArrayOutputStream;
import java.io.Writer;
@@ -26,18 +32,18 @@
/**
* Tests for {@link IndentingPrintWriter}.
*/
-public class LineBreakBufferedWriterTest extends TestCase {
+@RunWith(AndroidJUnit4.class)
+public class LineBreakBufferedWriterTest {
private ByteArrayOutputStream mStream;
private RecordingWriter mWriter;
- @Override
- protected void setUp() throws Exception {
- super.setUp();
-
+ @Before
+ public void setUp() throws Exception {
mWriter = new RecordingWriter();
}
+ @Test
public void testLessThanBufferSize() {
final LineBreakBufferedWriter lw = new LineBreakBufferedWriter(mWriter, 1000);
@@ -49,6 +55,7 @@
assertOutput("Hello\nWorld\nTest\n");
}
+ @Test
public void testMoreThanBufferSizeNoLineBreaks() {
final LineBreakBufferedWriter lw = new LineBreakBufferedWriter(mWriter, 20);
@@ -71,6 +78,7 @@
}
}
+ @Test
public void testMoreThanBufferSizeNoLineBreaksSingleString() {
final LineBreakBufferedWriter lw = new LineBreakBufferedWriter(mWriter, 20);
@@ -92,6 +100,7 @@
}
}
+ @Test
public void testMoreThanBufferSizeLineBreakBefore() {
final LineBreakBufferedWriter lw = new LineBreakBufferedWriter(mWriter, 20);
@@ -104,6 +113,7 @@
assertOutput("aaaaaaaaaa", "bbbbcccccccccc");
}
+ @Test
public void testMoreThanBufferSizeLineBreakBeforeSingleString() {
final LineBreakBufferedWriter lw = new LineBreakBufferedWriter(mWriter, 20);
@@ -115,6 +125,7 @@
assertOutput("aaaaaaaaaa", "bbbbcccccccccc");
}
+ @Test
public void testMoreThanBufferSizeLineBreakNew() {
final LineBreakBufferedWriter lw = new LineBreakBufferedWriter(mWriter, 20);
@@ -127,6 +138,7 @@
assertOutput("aaaaaaaaaabbbbbc\nd", "ddddddddd");
}
+ @Test
public void testMoreThanBufferSizeLineBreakBeforeAndNew() {
final LineBreakBufferedWriter lw = new LineBreakBufferedWriter(mWriter, 20);
@@ -139,6 +151,7 @@
assertOutput("aaaaaaaaaa\nbbbbbc\nd", "ddddddddd");
}
+ @Test
public void testMoreThanBufferSizeInt() {
final LineBreakBufferedWriter lw = new LineBreakBufferedWriter(mWriter, 15);
@@ -151,6 +164,7 @@
assertOutput("123456789098765", "4321");
}
+ @Test
public void testMoreThanBufferSizeChar() {
final LineBreakBufferedWriter lw = new LineBreakBufferedWriter(mWriter, 15);
@@ -165,6 +179,7 @@
assertOutput("$$$$$$$$$$%%%%%", "%%%%%");
}
+ @Test
public void testMoreThanBufferSizeLineBreakNewChars() {
final LineBreakBufferedWriter lw = new LineBreakBufferedWriter(mWriter, 20);
@@ -177,6 +192,7 @@
assertOutput("aaaaaaaaaabbbbbc\nd", "ddddddddd");
}
+ @Test
public void testMoreThenInitialCapacitySimpleWrites() {
// This check is different from testMoreThanBufferSizeChar. The initial capacity is lower
// than the maximum buffer size here.
diff --git a/core/tests/coretests/src/com/android/internal/util/ParseUtilsTest.java b/core/tests/coretests/src/com/android/internal/util/ParseUtilsTest.java
index 867152e..d24cbfe 100644
--- a/core/tests/coretests/src/com/android/internal/util/ParseUtilsTest.java
+++ b/core/tests/coretests/src/com/android/internal/util/ParseUtilsTest.java
@@ -16,13 +16,23 @@
package com.android.internal.util;
-import junit.framework.TestCase;
+import static org.junit.Assert.assertEquals;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
/**
* Run with:
atest /android/pi-dev/frameworks/base/core/tests/coretests/src/com/android/internal/util/ParseUtilsTest.java
*/
-public class ParseUtilsTest extends TestCase {
+@RunWith(AndroidJUnit4.class)
+public class ParseUtilsTest {
+ private static final float DELTA_FLOAT = 0.0f;
+ private static final double DELTA_DOUBLE = 0.0d;
+
+ @Test
public void testParseInt() {
assertEquals(1, ParseUtils.parseInt(null, 1));
assertEquals(1, ParseUtils.parseInt("", 1));
@@ -33,6 +43,7 @@
assertEquals(-2, ParseUtils.parseInt("-2", 1));
}
+ @Test
public void testParseIntWithBase() {
assertEquals(1, ParseUtils.parseIntWithBase(null, 10, 1));
assertEquals(1, ParseUtils.parseIntWithBase("", 10, 1));
@@ -45,6 +56,7 @@
assertEquals(-3, ParseUtils.parseIntWithBase("-10", 3, 1));
}
+ @Test
public void testParseLong() {
assertEquals(1L, ParseUtils.parseLong(null, 1));
assertEquals(1L, ParseUtils.parseLong("", 1));
@@ -52,6 +64,7 @@
assertEquals(2L, ParseUtils.parseLong("2", 1));
}
+ @Test
public void testParseLongWithBase() {
assertEquals(1L, ParseUtils.parseLongWithBase(null, 10, 1));
assertEquals(1L, ParseUtils.parseLongWithBase("", 10, 1));
@@ -69,20 +82,23 @@
assertEquals(10_000_000_000L, ParseUtils.parseLongWithBase(null, 10, 10_000_000_000L));
}
+ @Test
public void testParseFloat() {
- assertEquals(0.5f, ParseUtils.parseFloat(null, 0.5f));
- assertEquals(0.5f, ParseUtils.parseFloat("", 0.5f));
- assertEquals(0.5f, ParseUtils.parseFloat("1x", 0.5f));
- assertEquals(1.5f, ParseUtils.parseFloat("1.5", 0.5f));
+ assertEquals(0.5f, ParseUtils.parseFloat(null, 0.5f), DELTA_FLOAT);
+ assertEquals(0.5f, ParseUtils.parseFloat("", 0.5f), DELTA_FLOAT);
+ assertEquals(0.5f, ParseUtils.parseFloat("1x", 0.5f), DELTA_FLOAT);
+ assertEquals(1.5f, ParseUtils.parseFloat("1.5", 0.5f), DELTA_FLOAT);
}
+ @Test
public void testParseDouble() {
- assertEquals(0.5, ParseUtils.parseDouble(null, 0.5));
- assertEquals(0.5, ParseUtils.parseDouble("", 0.5));
- assertEquals(0.5, ParseUtils.parseDouble("1x", 0.5));
- assertEquals(1.5, ParseUtils.parseDouble("1.5", 0.5));
+ assertEquals(0.5, ParseUtils.parseDouble(null, 0.5), DELTA_DOUBLE);
+ assertEquals(0.5, ParseUtils.parseDouble("", 0.5), DELTA_DOUBLE);
+ assertEquals(0.5, ParseUtils.parseDouble("1x", 0.5), DELTA_DOUBLE);
+ assertEquals(1.5, ParseUtils.parseDouble("1.5", 0.5), DELTA_DOUBLE);
}
+ @Test
public void testParseBoolean() {
assertEquals(false, ParseUtils.parseBoolean(null, false));
assertEquals(true, ParseUtils.parseBoolean(null, true));
diff --git a/core/tests/coretests/src/com/android/internal/util/ProgressReporterTest.java b/core/tests/coretests/src/com/android/internal/util/ProgressReporterTest.java
index 87f2a8a..0d21335 100644
--- a/core/tests/coretests/src/com/android/internal/util/ProgressReporterTest.java
+++ b/core/tests/coretests/src/com/android/internal/util/ProgressReporterTest.java
@@ -16,14 +16,28 @@
package com.android.internal.util;
-import junit.framework.TestCase;
+import static org.junit.Assert.assertEquals;
-public class ProgressReporterTest extends TestCase {
+import android.platform.test.annotations.IgnoreUnderRavenwood;
+import android.platform.test.ravenwood.RavenwoodRule;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+@IgnoreUnderRavenwood(blockedBy = ProgressReporter.class)
+public class ProgressReporterTest {
+ @Rule
+ public final RavenwoodRule mRavenwood = new RavenwoodRule();
+
private ProgressReporter r;
- @Override
- protected void setUp() throws Exception {
- super.setUp();
+ @Before
+ public void setUp() throws Exception {
r = new ProgressReporter(0);
}
@@ -37,6 +51,7 @@
assertEquals("len", len, range[1]);
}
+ @Test
public void testBasic() throws Exception {
assertProgress(0);
@@ -50,6 +65,7 @@
assertProgress(100);
}
+ @Test
public void testSegment() throws Exception {
r.setProgress(20);
assertProgress(20);
@@ -68,6 +84,7 @@
assertProgress(80);
}
+ @Test
public void testSegmentOvershoot() throws Exception {
r.setProgress(20);
assertProgress(20);
@@ -87,6 +104,7 @@
assertProgress(60);
}
+ @Test
public void testSegmentNested() throws Exception {
r.setProgress(20);
assertProgress(20);
diff --git a/core/tests/coretests/src/com/android/internal/util/RingBufferTest.java b/core/tests/coretests/src/com/android/internal/util/RingBufferTest.java
index 4497770..d7a100a 100644
--- a/core/tests/coretests/src/com/android/internal/util/RingBufferTest.java
+++ b/core/tests/coretests/src/com/android/internal/util/RingBufferTest.java
@@ -20,8 +20,8 @@
import static org.junit.Assert.assertNull;
import static org.junit.Assert.fail;
-import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
import org.junit.Test;
import org.junit.runner.RunWith;
diff --git a/core/tests/coretests/src/com/android/internal/util/TokenBucketTest.java b/core/tests/coretests/src/com/android/internal/util/TokenBucketTest.java
index 8b30828..ef579fe 100644
--- a/core/tests/coretests/src/com/android/internal/util/TokenBucketTest.java
+++ b/core/tests/coretests/src/com/android/internal/util/TokenBucketTest.java
@@ -16,22 +16,29 @@
package com.android.internal.util;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertThrows;
+import static org.junit.Assert.assertTrue;
import android.os.SystemClock;
import android.text.format.DateUtils;
-import junit.framework.TestCase;
+import androidx.test.runner.AndroidJUnit4;
-public class TokenBucketTest extends TestCase {
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+public class TokenBucketTest {
static final int FILL_DELTA_VERY_SHORT = 1;
static final int FILL_DELTA_VERY_LONG = Integer.MAX_VALUE;
+ @Test
public void testArgumentValidation() {
assertThrow(() -> new TokenBucket(0, 1, 1));
assertThrow(() -> new TokenBucket(1, 0, 1));
- assertThrow(() -> new TokenBucket(1, 1, 0));
assertThrow(() -> new TokenBucket(0, 1));
assertThrow(() -> new TokenBucket(1, 0));
assertThrow(() -> new TokenBucket(-1, 1, 1));
@@ -46,6 +53,7 @@
new TokenBucket(5000, 1);
}
+ @Test
public void testInitialCapacity() {
drain(new TokenBucket(FILL_DELTA_VERY_LONG, 1), 1);
drain(new TokenBucket(FILL_DELTA_VERY_LONG, 10), 10);
@@ -62,6 +70,7 @@
drain(new TokenBucket((int) DateUtils.DAY_IN_MILLIS, 200), 200);
}
+ @Test
public void testReset() {
TokenBucket tb = new TokenBucket(FILL_DELTA_VERY_LONG, 100, 10);
drain(tb, 10);
@@ -77,6 +86,7 @@
drain(tb, 30);
}
+ @Test
public void testFill() throws Exception {
int delta = 50;
TokenBucket tb = new TokenBucket(delta, 10, 0);
@@ -88,6 +98,7 @@
assertTrue(tb.has());
}
+ @Test
public void testRefill() throws Exception {
TokenBucket tb = new TokenBucket(FILL_DELTA_VERY_SHORT, 10, 10);
@@ -107,6 +118,7 @@
assertEquals(10, tb.get(100));
}
+ @Test
public void testAverage() throws Exception {
final int delta = 3;
final int want = 60;
@@ -124,6 +136,7 @@
assertDuration(want * delta, SystemClock.elapsedRealtime() - start);
}
+ @Test
public void testBurst() throws Exception {
final int delta = 2;
final int capacity = 20;
diff --git a/core/tests/utiltests/Android.bp b/core/tests/utiltests/Android.bp
index 967047e..2ccee71 100644
--- a/core/tests/utiltests/Android.bp
+++ b/core/tests/utiltests/Android.bp
@@ -54,21 +54,20 @@
android_ravenwood_test {
name: "FrameworksUtilTestsRavenwood",
+ libs: [
+ "android.test.mock",
+ ],
static_libs: [
"androidx.annotation_annotation",
"androidx.test.rules",
"mockito_ravenwood",
+ "frameworks-base-testutils",
+ "servicestests-utils",
],
srcs: [
- "src/android/util/AtomicFileTest.java",
- "src/android/util/DataUnitTest.java",
- "src/android/util/EventLogTest.java",
- "src/android/util/IndentingPrintWriterTest.java",
- "src/android/util/IntArrayTest.java",
- "src/android/util/LocalLogTest.java",
- "src/android/util/LongArrayTest.java",
- "src/android/util/SlogTest.java",
- "src/android/util/TimeUtilsTest.java",
+ "src/android/util/IRemoteMemoryIntArray.aidl",
+ "src/android/util/**/*.java",
+ "src/com/android/internal/util/**/*.java",
],
auto_gen_config: true,
}
diff --git a/core/tests/utiltests/src/android/util/MemoryIntArrayTest.java b/core/tests/utiltests/src/android/util/MemoryIntArrayTest.java
index 1966e122..51013e4 100644
--- a/core/tests/utiltests/src/android/util/MemoryIntArrayTest.java
+++ b/core/tests/utiltests/src/android/util/MemoryIntArrayTest.java
@@ -23,11 +23,14 @@
import static org.junit.Assert.fail;
import android.os.Parcel;
+import android.platform.test.annotations.IgnoreUnderRavenwood;
+import android.platform.test.ravenwood.RavenwoodRule;
-import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.runner.AndroidJUnit4;
import libcore.io.IoUtils;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -35,13 +38,17 @@
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
-
-import androidx.test.ext.junit.runners.AndroidJUnit4;
@RunWith(AndroidJUnit4.class)
+@IgnoreUnderRavenwood(blockedBy = MemoryIntArray.class)
public class MemoryIntArrayTest {
+ @Rule
+ public final RavenwoodRule mRavenwood = new RavenwoodRule();
+
static {
- System.loadLibrary("cutils");
- System.loadLibrary("memoryintarraytest");
+ if (!RavenwoodRule.isUnderRavenwood()) {
+ System.loadLibrary("cutils");
+ System.loadLibrary("memoryintarraytest");
+ }
}
@Test
diff --git a/core/tests/utiltests/src/android/util/MetadataReaderTest.java b/core/tests/utiltests/src/android/util/MetadataReaderTest.java
index a828edb..14feed8 100644
--- a/core/tests/utiltests/src/android/util/MetadataReaderTest.java
+++ b/core/tests/utiltests/src/android/util/MetadataReaderTest.java
@@ -16,37 +16,47 @@
package android.util;
+import static org.junit.Assert.assertEquals;
+
import android.media.ExifInterface;
import android.os.Bundle;
+import android.platform.test.annotations.IgnoreUnderRavenwood;
+import android.platform.test.ravenwood.RavenwoodRule;
import android.provider.DocumentsContract;
import android.provider.MetadataReader;
-import libcore.io.IoUtils;
+import androidx.test.runner.AndroidJUnit4;
-import junit.framework.TestCase;
+import libcore.io.IoUtils;
import org.junit.After;
import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
+import org.junit.runner.RunWith;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
-public class MetadataReaderTest extends TestCase {
+@RunWith(AndroidJUnit4.class)
+@IgnoreUnderRavenwood(blockedBy = MetadataReader.class)
+public class MetadataReaderTest {
+ @Rule
+ public final RavenwoodRule mRavenwood = new RavenwoodRule();
private InputStream mInputStream;
private Bundle mData;
@Before
- protected void setUp() throws Exception {
+ public void setUp() throws Exception {
mInputStream = getClass().getClassLoader().getResourceAsStream("res/drawable/image.jpg");
mData = new Bundle();
}
@After
- protected void tearDown() throws Exception {
+ public void tearDown() throws Exception {
IoUtils.closeQuietly(mInputStream);
}
diff --git a/core/tests/utiltests/src/android/util/SystemConfigFileCommitEventLoggerTest.java b/core/tests/utiltests/src/android/util/SystemConfigFileCommitEventLoggerTest.java
index 5f6c201..3bb79ec 100644
--- a/core/tests/utiltests/src/android/util/SystemConfigFileCommitEventLoggerTest.java
+++ b/core/tests/utiltests/src/android/util/SystemConfigFileCommitEventLoggerTest.java
@@ -21,12 +21,22 @@
import static org.mockito.Mockito.times;
import android.os.SystemClock;
+import android.platform.test.annotations.IgnoreUnderRavenwood;
+import android.platform.test.ravenwood.RavenwoodRule;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Rule;
import org.junit.Test;
+import org.junit.runner.RunWith;
import org.mockito.Mockito;
-
+@RunWith(AndroidJUnit4.class)
+@IgnoreUnderRavenwood(blockedBy = SystemConfigFileCommitEventLogger.class)
public class SystemConfigFileCommitEventLoggerTest {
+ @Rule
+ public final RavenwoodRule mRavenwood = new RavenwoodRule();
+
@Test
public void testSimple() throws Exception {
var logger = spy(new SystemConfigFileCommitEventLogger("name"));
diff --git a/core/tests/utiltests/src/com/android/internal/util/ArrayUtilsTest.java b/core/tests/utiltests/src/com/android/internal/util/ArrayUtilsTest.java
index 72f3af6..0c5e966 100644
--- a/core/tests/utiltests/src/com/android/internal/util/ArrayUtilsTest.java
+++ b/core/tests/utiltests/src/com/android/internal/util/ArrayUtilsTest.java
@@ -17,19 +17,28 @@
package com.android.internal.util;
import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
-import junit.framework.TestCase;
-
/**
* Tests for {@link ArrayUtils}
*/
-public class ArrayUtilsTest extends TestCase {
+@RunWith(AndroidJUnit4.class)
+public class ArrayUtilsTest {
+ @Test
public void testContains() throws Exception {
final Object A = new Object();
final Object B = new Object();
@@ -46,6 +55,7 @@
assertFalse(ArrayUtils.contains(new Object[] { null }, A));
}
+ @Test
public void testIndexOf() throws Exception {
final Object A = new Object();
final Object B = new Object();
@@ -66,6 +76,7 @@
assertEquals(2, ArrayUtils.indexOf(new Object[] { A, null, B }, B));
}
+ @Test
public void testContainsAll() throws Exception {
final Object A = new Object();
final Object B = new Object();
@@ -86,6 +97,7 @@
assertFalse(ArrayUtils.containsAll(new Object[] { A }, new Object[] { null }));
}
+ @Test
public void testContainsInt() throws Exception {
assertTrue(ArrayUtils.contains(new int[] { 1, 2, 3 }, 1));
assertTrue(ArrayUtils.contains(new int[] { 1, 2, 3 }, 2));
@@ -96,6 +108,7 @@
assertFalse(ArrayUtils.contains(new int[] { }, 2));
}
+ @Test
public void testAppendInt() throws Exception {
assertArrayEquals(new int[] { 1 },
ArrayUtils.appendInt(null, 1));
@@ -107,6 +120,7 @@
ArrayUtils.appendInt(new int[] { 1, 2 }, 1));
}
+ @Test
public void testRemoveInt() throws Exception {
assertNull(ArrayUtils.removeInt(null, 1));
assertArrayEquals(new int[] { },
@@ -123,6 +137,7 @@
ArrayUtils.removeInt(new int[] { 1, 2, 3, 1 }, 1));
}
+ @Test
public void testContainsLong() throws Exception {
assertTrue(ArrayUtils.contains(new long[] { 1, 2, 3 }, 1));
assertTrue(ArrayUtils.contains(new long[] { 1, 2, 3 }, 2));
@@ -133,6 +148,7 @@
assertFalse(ArrayUtils.contains(new long[] { }, 2));
}
+ @Test
public void testAppendLong() throws Exception {
assertArrayEquals(new long[] { 1 },
ArrayUtils.appendLong(null, 1));
@@ -144,6 +160,7 @@
ArrayUtils.appendLong(new long[] { 1, 2 }, 1));
}
+ @Test
public void testRemoveLong() throws Exception {
assertNull(ArrayUtils.removeLong(null, 1));
assertArrayEquals(new long[] { },
@@ -160,6 +177,7 @@
ArrayUtils.removeLong(new long[] { 1, 2, 3, 1 }, 1));
}
+ @Test
public void testConcat_zeroObjectArrays() {
// empty varargs array
assertArrayEquals(new String[] {}, ArrayUtils.concat(String.class));
@@ -167,16 +185,19 @@
assertArrayEquals(new String[] {}, ArrayUtils.concat(String.class, (String[][]) null));
}
+ @Test
public void testConcat_oneObjectArray() {
assertArrayEquals(new String[] { "1", "2" },
ArrayUtils.concat(String.class, new String[] { "1", "2" }));
}
+ @Test
public void testConcat_oneEmptyObjectArray() {
assertArrayEquals(new String[] {}, ArrayUtils.concat(String.class, (String[]) null));
assertArrayEquals(new String[] {}, ArrayUtils.concat(String.class, new String[] {}));
}
+ @Test
public void testConcat_twoObjectArrays() {
assertArrayEquals(new Long[] { 1L },
ArrayUtils.concat(Long.class, new Long[] { 1L }, new Long[] {}));
@@ -188,6 +209,7 @@
ArrayUtils.concat(Long.class, new Long[] { 1L, 2L }, new Long[] { 3L, 4L }));
}
+ @Test
public void testConcat_twoEmptyObjectArrays() {
assertArrayEquals(new Long[] {}, ArrayUtils.concat(Long.class, null, null));
assertArrayEquals(new Long[] {}, ArrayUtils.concat(Long.class, new Long[] {}, null));
@@ -196,6 +218,7 @@
ArrayUtils.concat(Long.class, new Long[] {}, new Long[] {}));
}
+ @Test
public void testConcat_threeObjectArrays() {
String[] array1 = { "1", "2" };
String[] array2 = { "3", "4" };
@@ -205,6 +228,7 @@
assertArrayEquals(expectation, ArrayUtils.concat(String.class, array1, array2, array3));
}
+ @Test
public void testConcat_threeObjectArraysWithNull() {
String[] array1 = { "1", "2" };
String[] array2 = null;
@@ -214,6 +238,7 @@
assertArrayEquals(expectation, ArrayUtils.concat(String.class, array1, array2, array3));
}
+ @Test
public void testConcat_zeroByteArrays() {
// empty varargs array
assertArrayEquals(new byte[] {}, ArrayUtils.concat());
@@ -221,15 +246,18 @@
assertArrayEquals(new byte[] {}, ArrayUtils.concat((byte[][]) null));
}
+ @Test
public void testConcat_oneByteArray() {
assertArrayEquals(new byte[] { 1, 2 }, ArrayUtils.concat(new byte[] { 1, 2 }));
}
+ @Test
public void testConcat_oneEmptyByteArray() {
assertArrayEquals(new byte[] {}, ArrayUtils.concat((byte[]) null));
assertArrayEquals(new byte[] {}, ArrayUtils.concat(new byte[] {}));
}
+ @Test
public void testConcat_twoByteArrays() {
assertArrayEquals(new byte[] { 1 }, ArrayUtils.concat(new byte[] { 1 }, new byte[] {}));
assertArrayEquals(new byte[] { 1 }, ArrayUtils.concat(new byte[] {}, new byte[] { 1 }));
@@ -239,6 +267,7 @@
ArrayUtils.concat(new byte[] { 1, 2 }, new byte[] { 3, 4 }));
}
+ @Test
public void testConcat_twoEmptyByteArrays() {
assertArrayEquals(new byte[] {}, ArrayUtils.concat((byte[]) null, null));
assertArrayEquals(new byte[] {}, ArrayUtils.concat(new byte[] {}, null));
@@ -246,6 +275,7 @@
assertArrayEquals(new byte[] {}, ArrayUtils.concat(new byte[] {}, new byte[] {}));
}
+ @Test
public void testConcat_threeByteArrays() {
byte[] array1 = { 1, 2 };
byte[] array2 = { 3, 4 };
@@ -255,6 +285,7 @@
assertArrayEquals(expectation, ArrayUtils.concat(array1, array2, array3));
}
+ @Test
public void testConcat_threeByteArraysWithNull() {
byte[] array1 = { 1, 2 };
byte[] array2 = null;
@@ -264,6 +295,7 @@
assertArrayEquals(expectation, ArrayUtils.concat(array1, array2, array3));
}
+ @Test
@SmallTest
public void testUnstableRemoveIf() throws Exception {
java.util.function.Predicate<Object> isNull = new java.util.function.Predicate<Object>() {
@@ -357,31 +389,37 @@
assertEquals(0, collection.size());
}
+ @Test
@SmallTest
public void testThrowsIfOutOfBounds_passesWhenRangeInsideArray() {
ArrayUtils.throwsIfOutOfBounds(10, 2, 6);
}
+ @Test
@SmallTest
public void testThrowsIfOutOfBounds_passesWhenRangeIsWholeArray() {
ArrayUtils.throwsIfOutOfBounds(10, 0, 10);
}
+ @Test
@SmallTest
public void testThrowsIfOutOfBounds_passesWhenEmptyRangeAtStart() {
ArrayUtils.throwsIfOutOfBounds(10, 0, 0);
}
+ @Test
@SmallTest
public void testThrowsIfOutOfBounds_passesWhenEmptyRangeAtEnd() {
ArrayUtils.throwsIfOutOfBounds(10, 10, 0);
}
+ @Test
@SmallTest
public void testThrowsIfOutOfBounds_passesWhenEmptyArray() {
ArrayUtils.throwsIfOutOfBounds(0, 0, 0);
}
+ @Test
@SmallTest
public void testThrowsIfOutOfBounds_failsWhenRangeStartNegative() {
try {
@@ -392,6 +430,7 @@
}
}
+ @Test
@SmallTest
public void testThrowsIfOutOfBounds_failsWhenCountNegative() {
try {
@@ -402,6 +441,7 @@
}
}
+ @Test
@SmallTest
public void testThrowsIfOutOfBounds_failsWhenRangeStartTooHigh() {
try {
@@ -412,6 +452,7 @@
}
}
+ @Test
@SmallTest
public void testThrowsIfOutOfBounds_failsWhenRangeEndTooHigh() {
try {
@@ -422,6 +463,7 @@
}
}
+ @Test
@SmallTest
public void testThrowsIfOutOfBounds_failsWhenLengthNegative() {
try {
@@ -432,6 +474,7 @@
}
}
+ @Test
@SmallTest
public void testThrowsIfOutOfBounds_failsWhenOverflowRangeEndTooHigh() {
try {
diff --git a/core/tests/utiltests/src/com/android/internal/util/BitwiseStreamsTest.java b/core/tests/utiltests/src/com/android/internal/util/BitwiseStreamsTest.java
index 306f58f..092d699 100644
--- a/core/tests/utiltests/src/com/android/internal/util/BitwiseStreamsTest.java
+++ b/core/tests/utiltests/src/com/android/internal/util/BitwiseStreamsTest.java
@@ -16,20 +16,23 @@
package com.android.internal.util;
-import com.android.internal.util.BitwiseInputStream;
-import com.android.internal.util.BitwiseOutputStream;
-import com.android.internal.util.HexDump;
-
-import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.SmallTest;
+import static org.junit.Assert.assertEquals;
import android.util.Log;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
import java.util.Random;
-public class BitwiseStreamsTest extends AndroidTestCase {
+@RunWith(AndroidJUnit4.class)
+public class BitwiseStreamsTest {
private final static String LOG_TAG = "BitwiseStreamsTest";
+ @Test
@SmallTest
public void testOne() throws Exception {
int offset = 3;
@@ -45,6 +48,7 @@
assertEquals(HexDump.toHexString(inBuf), HexDump.toHexString(inBufDup));
}
+ @Test
@SmallTest
public void testTwo() throws Exception {
int offset = 3;
@@ -59,6 +63,7 @@
assertEquals(HexDump.toHexString(inBuf), HexDump.toHexString(inBufDup));
}
+ @Test
@SmallTest
public void testThree() throws Exception {
int offset = 4;
@@ -73,6 +78,7 @@
assertEquals(HexDump.toHexString(inBuf), HexDump.toHexString(inBufDup));
}
+ @Test
@SmallTest
public void testFour() throws Exception {
int offset = 7;
@@ -90,6 +96,7 @@
assertEquals(HexDump.toHexString(inBuf), HexDump.toHexString(inBufDup));
}
+ @Test
@SmallTest
public void testFive() throws Exception {
Random random = new Random();
@@ -111,6 +118,7 @@
}
}
+ @Test
@SmallTest
public void testSix() throws Exception {
int num_runs = 10;
@@ -134,6 +142,7 @@
Log.d(LOG_TAG, "repeated encode-decode took " + (end - start) + " ms");
}
+ @Test
@SmallTest
public void testExpandArray() throws Exception {
Random random = new Random();
diff --git a/core/tests/utiltests/src/com/android/internal/util/CallbackRegistryTest.java b/core/tests/utiltests/src/com/android/internal/util/CallbackRegistryTest.java
index 1581abb..9a1402e 100644
--- a/core/tests/utiltests/src/com/android/internal/util/CallbackRegistryTest.java
+++ b/core/tests/utiltests/src/com/android/internal/util/CallbackRegistryTest.java
@@ -15,19 +15,21 @@
*/
package com.android.internal.util;
-import junit.framework.TestCase;
-
-import org.junit.Test;
-
-import java.util.ArrayList;
-import java.util.Objects;
-
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
-public class CallbackRegistryTest extends TestCase {
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.ArrayList;
+import java.util.Objects;
+
+@RunWith(AndroidJUnit4.class)
+public class CallbackRegistryTest {
final Integer callback1 = 1;
final Integer callback2 = 2;
@@ -50,6 +52,7 @@
deepNotifyCount[callback]++;
}
+ @Test
public void testAddListener() {
CallbackRegistry.NotifierCallback<Integer, CallbackRegistryTest, Integer> notifier =
new CallbackRegistry.NotifierCallback<Integer, CallbackRegistryTest, Integer>() {
@@ -89,6 +92,7 @@
assertEquals(otherListener, callbacks.get(0));
}
+ @Test
public void testSimpleNotify() {
CallbackRegistry.NotifierCallback<Integer, CallbackRegistryTest, Integer> notifier =
new CallbackRegistry.NotifierCallback<Integer, CallbackRegistryTest, Integer>() {
@@ -108,6 +112,7 @@
assertEquals(1, notify2);
}
+ @Test
public void testRemoveWhileNotifying() {
CallbackRegistry.NotifierCallback<Integer, CallbackRegistryTest, Integer> notifier =
new CallbackRegistry.NotifierCallback<Integer, CallbackRegistryTest, Integer>() {
@@ -135,6 +140,7 @@
assertEquals(callback3, callbacks.get(0));
}
+ @Test
public void testDeepRemoveWhileNotifying() {
CallbackRegistry.NotifierCallback<Integer, CallbackRegistryTest, Integer> notifier =
new CallbackRegistry.NotifierCallback<Integer, CallbackRegistryTest, Integer>() {
@@ -159,6 +165,7 @@
assertEquals(0, callbacks.size());
}
+ @Test
public void testAddRemovedListener() {
CallbackRegistry.NotifierCallback<Integer, CallbackRegistryTest, Integer> notifier =
@@ -191,6 +198,7 @@
assertEquals(1, notify3);
}
+ @Test
public void testVeryDeepRemoveWhileNotifying() {
final Integer[] callbacks = new Integer[deepNotifyCount.length];
for (int i = 0; i < callbacks.length; i++) {
@@ -221,6 +229,7 @@
assertEquals(0, callbackList.size());
}
+ @Test
public void testClear() {
CallbackRegistry.NotifierCallback<Integer, CallbackRegistryTest, Integer> notifier =
new CallbackRegistry.NotifierCallback<Integer, CallbackRegistryTest, Integer>() {
@@ -245,6 +254,7 @@
}
}
+ @Test
public void testNestedClear() {
CallbackRegistry.NotifierCallback<Integer, CallbackRegistryTest, Integer> notifier =
new CallbackRegistry.NotifierCallback<Integer, CallbackRegistryTest, Integer>() {
@@ -268,6 +278,7 @@
assertEquals(0, callbackList.size());
}
+ @Test
public void testIsEmpty() throws Exception {
CallbackRegistry.NotifierCallback<Integer, CallbackRegistryTest, Integer> notifier =
new CallbackRegistry.NotifierCallback<Integer, CallbackRegistryTest, Integer>() {
@@ -284,6 +295,7 @@
assertFalse(registry.isEmpty());
}
+ @Test
public void testClone() throws Exception {
CallbackRegistry.NotifierCallback<Integer, CallbackRegistryTest, Integer> notifier =
new CallbackRegistry.NotifierCallback<Integer, CallbackRegistryTest, Integer>() {
diff --git a/core/tests/utiltests/src/com/android/internal/util/CharSequencesTest.java b/core/tests/utiltests/src/com/android/internal/util/CharSequencesTest.java
index 469a4cc..9888540 100644
--- a/core/tests/utiltests/src/com/android/internal/util/CharSequencesTest.java
+++ b/core/tests/utiltests/src/com/android/internal/util/CharSequencesTest.java
@@ -18,12 +18,26 @@
import static com.android.internal.util.CharSequences.forAsciiBytes;
-import android.test.suitebuilder.annotation.SmallTest;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
-import junit.framework.TestCase;
+import android.platform.test.annotations.IgnoreUnderRavenwood;
+import android.platform.test.ravenwood.RavenwoodRule;
-public class CharSequencesTest extends TestCase {
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+@IgnoreUnderRavenwood(blockedBy = CharSequences.class)
+public class CharSequencesTest {
+ @Rule
+ public final RavenwoodRule mRavenwood = new RavenwoodRule();
+
+ @Test
@SmallTest
public void testCharSequences() {
String s = "Hello Bob";
diff --git a/core/tests/utiltests/src/com/android/internal/util/FastXmlSerializerTest.java b/core/tests/utiltests/src/com/android/internal/util/FastXmlSerializerTest.java
index 3cef336..7723d58 100644
--- a/core/tests/utiltests/src/com/android/internal/util/FastXmlSerializerTest.java
+++ b/core/tests/utiltests/src/com/android/internal/util/FastXmlSerializerTest.java
@@ -16,13 +16,23 @@
package com.android.internal.util;
-import android.test.suitebuilder.annotation.LargeTest;
-import android.test.suitebuilder.annotation.SmallTest;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import android.platform.test.annotations.IgnoreUnderRavenwood;
+import android.platform.test.ravenwood.RavenwoodRule;
+import android.provider.DeviceConfig;
import android.util.Log;
import android.util.Xml;
-import junit.framework.TestCase;
+import androidx.test.filters.LargeTest;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlSerializer;
@@ -34,7 +44,9 @@
* Tests for {@link FastXmlSerializer}
*/
@SmallTest
-public class FastXmlSerializerTest extends TestCase {
+@RunWith(AndroidJUnit4.class)
+@IgnoreUnderRavenwood(blockedBy = Xml.class)
+public class FastXmlSerializerTest {
private static final String TAG = "FastXmlSerializerTest";
private static final boolean ENABLE_DUMP = false; // DO NOT SUBMIT WITH TRUE.
@@ -42,6 +54,10 @@
private static final String ROOT_TAG = "root";
private static final String ATTR = "attr";
+ @Rule
+ public final RavenwoodRule mRavenwood = new RavenwoodRule();
+
+ @Test
public void testEmptyText() throws Exception {
final ByteArrayOutputStream stream = new ByteArrayOutputStream();
@@ -128,6 +144,7 @@
return ok;
}
+ @Test
@LargeTest
public void testAllCharacters() throws Exception {
boolean ok = true;
diff --git a/core/tests/utiltests/src/com/android/internal/util/FileRotatorTest.java b/core/tests/utiltests/src/com/android/internal/util/FileRotatorTest.java
index 73e47e16..47c1795 100644
--- a/core/tests/utiltests/src/com/android/internal/util/FileRotatorTest.java
+++ b/core/tests/utiltests/src/com/android/internal/util/FileRotatorTest.java
@@ -23,16 +23,23 @@
import static android.text.format.DateUtils.WEEK_IN_MILLIS;
import static android.text.format.DateUtils.YEAR_IN_MILLIS;
-import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.Suppress;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+
import android.util.Log;
+import androidx.test.runner.AndroidJUnit4;
+
import com.android.internal.util.FileRotator.Reader;
import com.android.internal.util.FileRotator.Writer;
-import com.android.internal.util.test.FsUtil;
import com.google.android.collect.Lists;
+import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
@@ -40,6 +47,7 @@
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
+import java.nio.file.Files;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Random;
@@ -47,7 +55,8 @@
/**
* Tests for {@link FileRotator}.
*/
-public class FileRotatorTest extends AndroidTestCase {
+@RunWith(AndroidJUnit4.class)
+public class FileRotatorTest {
private static final String TAG = "FileRotatorTest";
private File mBasePath;
@@ -59,14 +68,12 @@
// TODO: test throwing rolls back correctly
- @Override
- protected void setUp() throws Exception {
- super.setUp();
-
- mBasePath = getContext().getFilesDir();
- FsUtil.deleteContents(mBasePath);
+ @Before
+ public void setUp() throws Exception {
+ mBasePath = Files.createTempDirectory(TAG).toFile();
}
+ @Test
public void testEmpty() throws Exception {
final FileRotator rotate1 = new FileRotator(
mBasePath, PREFIX, DAY_IN_MILLIS, WEEK_IN_MILLIS);
@@ -85,6 +92,7 @@
assertReadAll(rotate2);
}
+ @Test
public void testCombine() throws Exception {
final FileRotator rotate = new FileRotator(
mBasePath, PREFIX, DAY_IN_MILLIS, WEEK_IN_MILLIS);
@@ -106,6 +114,7 @@
assertReadAll(rotate, "bar");
}
+ @Test
public void testRotate() throws Exception {
final FileRotator rotate = new FileRotator(
mBasePath, PREFIX, DAY_IN_MILLIS, WEEK_IN_MILLIS);
@@ -138,6 +147,7 @@
assertReadAll(rotate, "bar", "baz");
}
+ @Test
public void testDelete() throws Exception {
final FileRotator rotate = new FileRotator(
mBasePath, PREFIX, MINUTE_IN_MILLIS, DAY_IN_MILLIS);
@@ -168,6 +178,7 @@
assertReadAll(rotate);
}
+ @Test
public void testThrowRestoresBackup() throws Exception {
final FileRotator rotate = new FileRotator(
mBasePath, PREFIX, MINUTE_IN_MILLIS, DAY_IN_MILLIS);
@@ -201,6 +212,7 @@
assertReadAll(rotate, "foo");
}
+ @Test
public void testOtherFilesAndMalformed() throws Exception {
final FileRotator rotate = new FileRotator(
mBasePath, PREFIX, SECOND_IN_MILLIS, SECOND_IN_MILLIS);
@@ -229,6 +241,7 @@
private static final String BLUE = "blue";
private static final String YELLOW = "yellow";
+ @Test
public void testQueryMatch() throws Exception {
final FileRotator rotate = new FileRotator(
mBasePath, PREFIX, HOUR_IN_MILLIS, YEAR_IN_MILLIS);
@@ -277,6 +290,7 @@
assertReadMatching(rotate, Long.MIN_VALUE, TEST_TIME - DAY_IN_MILLIS);
}
+ @Test
public void testClockRollingBackwards() throws Exception {
final FileRotator rotate = new FileRotator(
mBasePath, PREFIX, DAY_IN_MILLIS, YEAR_IN_MILLIS);
@@ -325,7 +339,8 @@
assertReadAll(rotate, "meow", "yay");
}
- @Suppress
+ @Test
+ @Ignore
public void testFuzz() throws Exception {
final FileRotator rotate = new FileRotator(
mBasePath, PREFIX, HOUR_IN_MILLIS, DAY_IN_MILLIS);
@@ -352,6 +367,7 @@
Log.d(TAG, Arrays.toString(mBasePath.list()));
}
+ @Test
public void testRecoverAtomic() throws Exception {
write("rotator.1024-2048", "foo");
write("rotator.1024-2048.backup", "bar");
@@ -366,6 +382,7 @@
assertReadAll(rotate, "bar");
}
+ @Test
public void testReadSorted() throws Exception {
write("rotator.1024-2048", "2");
write("rotator.2048-4096", "3");
@@ -376,11 +393,11 @@
assertReadAll(rotate, "1", "2", "3");
}
+ @Test
public void testFileSystemInaccessible() throws Exception {
- File inaccessibleDir = null;
- String dirPath = getContext().getFilesDir() + File.separator + "inaccessible";
- inaccessibleDir = new File(dirPath);
- final FileRotator rotate = new FileRotator(inaccessibleDir, PREFIX, SECOND_IN_MILLIS, SECOND_IN_MILLIS);
+ File inaccessibleDir = mBasePath.toPath().resolve("does_not_exist").toFile();
+ final FileRotator rotate = new FileRotator(inaccessibleDir, PREFIX,
+ SECOND_IN_MILLIS, SECOND_IN_MILLIS);
// rotate should not throw on dir not mkdir-ed (or otherwise inaccessible)
rotate.maybeRotate(TEST_TIME);
diff --git a/core/tests/utiltests/src/com/android/internal/util/HeavyHitterSketchTest.java b/core/tests/utiltests/src/com/android/internal/util/HeavyHitterSketchTest.java
index f2285a1..74184ca 100644
--- a/core/tests/utiltests/src/com/android/internal/util/HeavyHitterSketchTest.java
+++ b/core/tests/utiltests/src/com/android/internal/util/HeavyHitterSketchTest.java
@@ -16,10 +16,17 @@
package com.android.internal.util;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
import android.util.ArraySet;
import android.util.Pair;
-import junit.framework.TestCase;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
import java.util.ArrayList;
import java.util.Comparator;
@@ -32,7 +39,8 @@
/**
* Tests for {@link HeavyHitterSketch}.
*/
-public final class HeavyHitterSketchTest extends TestCase {
+@RunWith(AndroidJUnit4.class)
+public final class HeavyHitterSketchTest {
private static final float EPSILON = 0.00001f;
@@ -163,6 +171,7 @@
return input;
}
+ @Test
public void testPositive() throws Exception {
// Simple case
verify(new int[]{2, 9, 9, 9, 7, 6, 4, 9, 9, 9, 3, 9}, 2, new int[]{9},
@@ -179,6 +188,7 @@
new float[]{0.32f, 0.24f, 0.16f, 0.08f});
}
+ @Test
public void testNegative() throws Exception {
// Simple case
verifyNotExpected(new int[]{2, 9, 9, 9, 7, 6, 4, 9, 9, 9, 3, 9}, 2, new int[]{0, 1, 2});
@@ -193,6 +203,7 @@
verifyNotExpected(input, 12, new int[]{0, 1, 2, 1000, 1005});
}
+ @Test
public void testFalsePositive() throws Exception {
// Simple case
verifyNotExpected(new int[]{2, 9, 2, 2, 7, 6, 4, 9, 9, 9, 3, 9}, 2, new int[]{9});
diff --git a/core/tests/utiltests/src/com/android/internal/util/InlinePresentationStyleUtilsTest.java b/core/tests/utiltests/src/com/android/internal/util/InlinePresentationStyleUtilsTest.java
index 35c5681..7203b8c 100644
--- a/core/tests/utiltests/src/com/android/internal/util/InlinePresentationStyleUtilsTest.java
+++ b/core/tests/utiltests/src/com/android/internal/util/InlinePresentationStyleUtilsTest.java
@@ -22,20 +22,28 @@
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
+import android.graphics.Color;
import android.os.Binder;
import android.os.Bundle;
+import android.platform.test.annotations.IgnoreUnderRavenwood;
+import android.platform.test.ravenwood.RavenwoodRule;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
import com.android.internal.widget.InlinePresentationStyleUtils;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(AndroidJUnit4.class)
@SmallTest
+@IgnoreUnderRavenwood(blockedBy = InlinePresentationStyleUtils.class)
public class InlinePresentationStyleUtilsTest {
+ @Rule
+ public final RavenwoodRule mRavenwood = new RavenwoodRule();
+
@Test
public void testBundleEquals_empty() {
Bundle bundle1 = new Bundle();
diff --git a/core/tests/utiltests/src/com/android/internal/util/LockPatternUtilsTest.java b/core/tests/utiltests/src/com/android/internal/util/LockPatternUtilsTest.java
index 0b70199..0df5b0a 100644
--- a/core/tests/utiltests/src/com/android/internal/util/LockPatternUtilsTest.java
+++ b/core/tests/utiltests/src/com/android/internal/util/LockPatternUtilsTest.java
@@ -43,6 +43,8 @@
import android.os.Looper;
import android.os.RemoteException;
import android.os.UserManager;
+import android.platform.test.annotations.IgnoreUnderRavenwood;
+import android.platform.test.ravenwood.RavenwoodRule;
import android.provider.Settings;
import android.test.mock.MockContentResolver;
@@ -58,6 +60,7 @@
import com.google.android.collect.Lists;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
@@ -68,7 +71,10 @@
@RunWith(AndroidJUnit4.class)
@SmallTest
+@IgnoreUnderRavenwood(blockedBy = LockPatternUtils.class)
public class LockPatternUtilsTest {
+ @Rule
+ public final RavenwoodRule mRavenwood = new RavenwoodRule();
private static final int DEMO_USER_ID = 5;
diff --git a/core/tests/utiltests/src/com/android/internal/util/MessageUtilsTest.java b/core/tests/utiltests/src/com/android/internal/util/MessageUtilsTest.java
index 32b969a..36f238e 100644
--- a/core/tests/utiltests/src/com/android/internal/util/MessageUtilsTest.java
+++ b/core/tests/utiltests/src/com/android/internal/util/MessageUtilsTest.java
@@ -19,10 +19,13 @@
import static org.junit.Assert.*;
import com.android.internal.util.MessageUtils;
-import android.test.suitebuilder.annotation.SmallTest;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
import android.util.SparseArray;
import org.junit.Test;
+import org.junit.runner.RunWith;
class A {
@@ -48,6 +51,7 @@
* Unit tests for {@link com.android.util.MessageUtils}.
*/
@SmallTest
+@RunWith(AndroidJUnit4.class)
public class MessageUtilsTest {
private static final Class[] CLASSES = { A.class, B.class };
diff --git a/core/tests/utiltests/src/com/android/internal/util/MimeIconUtilsTest.java b/core/tests/utiltests/src/com/android/internal/util/MimeIconUtilsTest.java
index 4412c2c..6c34797 100644
--- a/core/tests/utiltests/src/com/android/internal/util/MimeIconUtilsTest.java
+++ b/core/tests/utiltests/src/com/android/internal/util/MimeIconUtilsTest.java
@@ -16,12 +16,27 @@
package com.android.internal.util;
-import junit.framework.TestCase;
+import static org.junit.Assert.assertEquals;
+
+import android.platform.test.annotations.IgnoreUnderRavenwood;
+import android.platform.test.ravenwood.RavenwoodRule;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
/**
* Tests for {@link MimeIconUtils}.
*/
-public class MimeIconUtilsTest extends TestCase {
+@RunWith(AndroidJUnit4.class)
+@IgnoreUnderRavenwood(blockedBy = MimeIconUtils.class)
+public class MimeIconUtilsTest {
+ @Rule
+ public final RavenwoodRule mRavenwood = new RavenwoodRule();
+
+ @Test
public void testSimple() throws Exception {
assertEquals("PNG image",
MimeIconUtils.getTypeInfo("image/png").getLabel());
diff --git a/core/tests/utiltests/src/com/android/internal/util/ObjectUtilsTest.java b/core/tests/utiltests/src/com/android/internal/util/ObjectUtilsTest.java
index 443183e..4eaacff 100644
--- a/core/tests/utiltests/src/com/android/internal/util/ObjectUtilsTest.java
+++ b/core/tests/utiltests/src/com/android/internal/util/ObjectUtilsTest.java
@@ -15,11 +15,18 @@
*/
package com.android.internal.util;
-import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.SmallTest;
+import static org.junit.Assert.assertEquals;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
@SmallTest
-public class ObjectUtilsTest extends AndroidTestCase {
+@RunWith(AndroidJUnit4.class)
+public class ObjectUtilsTest {
+ @Test
public void testCompare() {
assertEquals(0, ObjectUtils.compare(null, null));
assertEquals(1, ObjectUtils.compare("a", null));
diff --git a/core/tests/utiltests/src/com/android/internal/util/ObservableServiceConnectionTest.java b/core/tests/utiltests/src/com/android/internal/util/ObservableServiceConnectionTest.java
index d124ad9..c852e9f 100644
--- a/core/tests/utiltests/src/com/android/internal/util/ObservableServiceConnectionTest.java
+++ b/core/tests/utiltests/src/com/android/internal/util/ObservableServiceConnectionTest.java
@@ -29,14 +29,19 @@
import android.content.Context;
import android.content.Intent;
import android.os.IBinder;
+import android.platform.test.annotations.IgnoreUnderRavenwood;
+import android.platform.test.ravenwood.RavenwoodRule;
import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
import com.android.internal.util.ObservableServiceConnection.ServiceTransformer;
import org.junit.After;
import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
+import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
@@ -46,7 +51,12 @@
import java.util.concurrent.Executor;
@SmallTest
+@RunWith(AndroidJUnit4.class)
+@IgnoreUnderRavenwood(blockedBy = ObservableServiceConnection.class)
public class ObservableServiceConnectionTest {
+ @Rule
+ public final RavenwoodRule mRavenwood = new RavenwoodRule();
+
private static final ComponentName COMPONENT_NAME =
new ComponentName("test.package", "component");
diff --git a/core/tests/utiltests/src/com/android/internal/util/PersistentServiceConnectionTest.java b/core/tests/utiltests/src/com/android/internal/util/PersistentServiceConnectionTest.java
index fee4654..096f303 100644
--- a/core/tests/utiltests/src/com/android/internal/util/PersistentServiceConnectionTest.java
+++ b/core/tests/utiltests/src/com/android/internal/util/PersistentServiceConnectionTest.java
@@ -30,6 +30,10 @@
import android.content.Context;
import android.content.Intent;
import android.os.IBinder;
+import android.platform.test.annotations.IgnoreUnderRavenwood;
+import android.platform.test.ravenwood.RavenwoodRule;
+
+import androidx.test.runner.AndroidJUnit4;
import com.android.internal.util.ObservableServiceConnection.ServiceTransformer;
import com.android.server.testutils.OffsettableClock;
@@ -37,7 +41,9 @@
import org.junit.After;
import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
+import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
@@ -45,7 +51,12 @@
import java.util.Queue;
import java.util.concurrent.Executor;
+@RunWith(AndroidJUnit4.class)
+@IgnoreUnderRavenwood(blockedBy = PersistentServiceConnection.class)
public class PersistentServiceConnectionTest {
+ @Rule
+ public final RavenwoodRule mRavenwood = new RavenwoodRule();
+
private static final ComponentName COMPONENT_NAME =
new ComponentName("test.package", "component");
private static final int MAX_RETRIES = 2;
diff --git a/core/tests/utiltests/src/com/android/internal/util/ProcFileReaderTest.java b/core/tests/utiltests/src/com/android/internal/util/ProcFileReaderTest.java
index b932760..4c00c16 100644
--- a/core/tests/utiltests/src/com/android/internal/util/ProcFileReaderTest.java
+++ b/core/tests/utiltests/src/com/android/internal/util/ProcFileReaderTest.java
@@ -16,7 +16,15 @@
package com.android.internal.util;
-import android.test.AndroidTestCase;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
import java.io.ByteArrayInputStream;
import java.io.File;
@@ -28,8 +36,10 @@
/**
* Tests for {@link ProcFileReader}.
*/
-public class ProcFileReaderTest extends AndroidTestCase {
+@RunWith(AndroidJUnit4.class)
+public class ProcFileReaderTest {
+ @Test
public void testEmpty() throws Exception {
final ProcFileReader reader = buildReader("");
@@ -43,6 +53,7 @@
assertFalse(reader.hasMoreData());
}
+ @Test
public void testSingleString() throws Exception {
final ProcFileReader reader = buildReader("a\nb\nc\n");
@@ -59,6 +70,7 @@
assertFalse(reader.hasMoreData());
}
+ @Test
public void testMixedNumbersSkip() throws Exception {
final ProcFileReader reader = buildReader("1 2 3\n4 abc_def 5 6 7 8 9\n10\n");
@@ -79,6 +91,7 @@
assertFalse(reader.hasMoreData());
}
+ @Test
public void testBufferSize() throws Exception {
// read numbers using very small buffer size, exercising fillBuf()
final ProcFileReader reader = buildReader("1 21 3 41 5 61 7 81 9 10\n", 3);
@@ -97,6 +110,7 @@
assertFalse(reader.hasMoreData());
}
+ @Test
public void testBlankLines() throws Exception {
final ProcFileReader reader = buildReader("1\n\n2\n\n3\n");
@@ -117,6 +131,7 @@
assertFalse(reader.hasMoreData());
}
+ @Test
public void testMinMax() throws Exception {
final ProcFileReader reader = buildReader(
"1 -1024 9223372036854775807 -9223372036854775808\n");
@@ -129,6 +144,7 @@
assertFalse(reader.hasMoreData());
}
+ @Test
public void testDelimiterNeverFound() throws Exception {
final ProcFileReader reader = buildReader("teststringwithoutdelimiters");
@@ -141,6 +157,7 @@
}
}
+ @Test
public void testLargerThanBuffer() throws Exception {
// try finishing line larger than buffer
final ProcFileReader reader = buildReader("1 teststringlongerthanbuffer\n", 4);
@@ -155,6 +172,7 @@
}
}
+ @Test
public void testOptionalLongs() throws Exception {
final ProcFileReader reader = buildReader("123 456\n789\n");
@@ -169,6 +187,7 @@
assertEquals(-1L, reader.nextOptionalLong(-1L));
}
+ @Test
public void testInvalidLongs() throws Exception {
final ProcFileReader reader = buildReader("12: 34\n56 78@#\n");
@@ -183,6 +202,7 @@
assertFalse(reader.hasMoreData());
}
+ @Test
public void testConsecutiveDelimiters() throws Exception {
final ProcFileReader reader = buildReader("1 2 3 4 5\n");
@@ -195,6 +215,7 @@
assertFalse(reader.hasMoreData());
}
+ @Test
public void testIgnore() throws Exception {
final ProcFileReader reader = buildReader("a b c\n");
@@ -209,6 +230,7 @@
assertFalse(reader.hasMoreData());
}
+ @Test
public void testRewind() throws Exception {
final ProcFileReader reader = buildReader("abc\n");
@@ -224,7 +246,7 @@
assertFalse(reader.hasMoreData());
}
-
+ @Test
public void testRewindFileInputStream() throws Exception {
File tempFile = File.createTempFile("procfile", null, null);
Files.write(tempFile.toPath(), "abc\n".getBytes(StandardCharsets.US_ASCII));
diff --git a/core/tests/utiltests/src/com/android/internal/util/QuickSelectTest.java b/core/tests/utiltests/src/com/android/internal/util/QuickSelectTest.java
index 1b9d2ef..1eb5e3ab 100644
--- a/core/tests/utiltests/src/com/android/internal/util/QuickSelectTest.java
+++ b/core/tests/utiltests/src/com/android/internal/util/QuickSelectTest.java
@@ -16,7 +16,12 @@
package com.android.internal.util;
-import junit.framework.TestCase;
+import static org.junit.Assert.assertEquals;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
import java.util.Arrays;
import java.util.List;
@@ -24,8 +29,10 @@
/**
* Tests for {@link QuickSelect}.
*/
-public final class QuickSelectTest extends TestCase {
+@RunWith(AndroidJUnit4.class)
+public class QuickSelectTest {
+ @Test
public void testQuickSelect() throws Exception {
test((List<Integer>) null, 0, null);
test(Arrays.asList(), -1, null);
diff --git a/core/tests/utiltests/src/com/android/internal/util/StringPoolTest.java b/core/tests/utiltests/src/com/android/internal/util/StringPoolTest.java
index f67fd51..6523ed7 100644
--- a/core/tests/utiltests/src/com/android/internal/util/StringPoolTest.java
+++ b/core/tests/utiltests/src/com/android/internal/util/StringPoolTest.java
@@ -16,12 +16,21 @@
package com.android.internal.util;
-import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.SmallTest;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotSame;
+import static org.junit.Assert.assertSame;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
@SmallTest
-public final class StringPoolTest extends AndroidTestCase {
+@RunWith(AndroidJUnit4.class)
+public final class StringPoolTest {
+ @Test
public void testStringPool() {
StringPool stringPool = new StringPool();
String bcd = stringPool.get(new char[] { 'a', 'b', 'c', 'd', 'e' }, 1, 3);
@@ -29,6 +38,7 @@
assertSame(bcd, stringPool.get(new char[] { 'a', 'b', 'c', 'd', 'e' }, 1, 3));
}
+ @Test
public void testHashCollision() {
StringPool stringPool = new StringPool();
char[] a = { (char) 1, (char) 0 };
diff --git a/core/tests/utiltests/src/com/android/internal/util/WakeupMessageTest.java b/core/tests/utiltests/src/com/android/internal/util/WakeupMessageTest.java
index 734ebef..b0db8a1 100644
--- a/core/tests/utiltests/src/com/android/internal/util/WakeupMessageTest.java
+++ b/core/tests/utiltests/src/com/android/internal/util/WakeupMessageTest.java
@@ -24,11 +24,17 @@
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
-import android.test.suitebuilder.annotation.SmallTest;
+import android.platform.test.annotations.IgnoreUnderRavenwood;
+import android.platform.test.ravenwood.RavenwoodRule;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
import org.junit.After;
import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
+import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
@@ -40,6 +46,8 @@
* Unit tests for {@link com.android.internal.util.WakeupMessage}.
*/
@SmallTest
+@RunWith(AndroidJUnit4.class)
+@IgnoreUnderRavenwood(blockedBy = WakeupMessage.class)
public class WakeupMessageTest {
private static final String TEST_CMD_NAME = "TEST cmd Name";
private static final int TEST_CMD = 18;
@@ -47,11 +55,16 @@
private static final int TEST_ARG2 = 182;
private static final Object TEST_OBJ = "hello";
+ @Rule
+ public final RavenwoodRule mRavenwood = new RavenwoodRule.Builder()
+ .setProvideMainThread(true)
+ .build();
+
@Mock Context mContext;
@Mock AlarmManager mAlarmManager;
WakeupMessage mMessage;
// Make a spy so that we can verify calls to it
- @Spy MessageCapturingHandler mHandler = new MessageCapturingHandler();
+ @Spy MessageCapturingHandler mHandler;
ArgumentCaptor<AlarmManager.OnAlarmListener> mListenerCaptor =
ArgumentCaptor.forClass(AlarmManager.OnAlarmListener.class);
@@ -85,6 +98,8 @@
*/
@Before
public void setUp() {
+ mHandler = new MessageCapturingHandler();
+
MockitoAnnotations.initMocks(this);
when(mContext.getSystemService(Context.ALARM_SERVICE)).thenReturn(mAlarmManager);
diff --git a/core/tests/utiltests/src/com/android/internal/util/XmlUtilsTest.java b/core/tests/utiltests/src/com/android/internal/util/XmlUtilsTest.java
index 0484068..24eb213 100644
--- a/core/tests/utiltests/src/com/android/internal/util/XmlUtilsTest.java
+++ b/core/tests/utiltests/src/com/android/internal/util/XmlUtilsTest.java
@@ -17,13 +17,17 @@
package com.android.internal.util;
import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
import android.util.Xml;
+import androidx.test.runner.AndroidJUnit4;
+
import com.android.modules.utils.TypedXmlPullParser;
import com.android.modules.utils.TypedXmlSerializer;
-import junit.framework.TestCase;
+import org.junit.Test;
+import org.junit.runner.RunWith;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
@@ -32,9 +36,11 @@
import java.util.HashMap;
import java.util.Map;
-public class XmlUtilsTest extends TestCase {
+@RunWith(AndroidJUnit4.class)
+public class XmlUtilsTest {
// https://code.google.com/p/android/issues/detail?id=63717
+ @Test
public void testMapWithNullKeys() throws Exception {
ByteArrayOutputStream baos = new ByteArrayOutputStream(1024);
Map<String, Object> map = new HashMap<String, Object>();
@@ -48,6 +54,7 @@
assertEquals("fooValue", deserialized.get("foo"));
}
+ @Test
public void testreadWriteXmlByteArrayValue() throws Exception {
byte[] testByteArray = {0x1 , 0xa, 0xb, 0x9, 0x34, (byte) 0xaa, (byte) 0xba, (byte) 0x99};
diff --git a/core/tests/utiltests/src/com/android/internal/util/test/FakeSettingsProviderTest.java b/core/tests/utiltests/src/com/android/internal/util/test/FakeSettingsProviderTest.java
index f2be109..502d6b6 100644
--- a/core/tests/utiltests/src/com/android/internal/util/test/FakeSettingsProviderTest.java
+++ b/core/tests/utiltests/src/com/android/internal/util/test/FakeSettingsProviderTest.java
@@ -16,33 +16,41 @@
package com.android.internal.util.test;
-import android.content.ContentResolver;
-import android.database.ContentObserver;
-import android.net.Uri;
-import android.provider.Settings;
-import android.test.AndroidTestCase;
-import android.test.mock.MockContentResolver;
-import android.test.mock.MockContext;
-import android.test.suitebuilder.annotation.SmallTest;
-import android.test.suitebuilder.annotation.Suppress;
-import android.util.Log;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
+import android.content.ContentProvider;
+import android.platform.test.annotations.IgnoreUnderRavenwood;
+import android.platform.test.ravenwood.RavenwoodRule;
+import android.provider.Settings;
+import android.test.mock.MockContentResolver;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
/**
* Unit tests for FakeSettingsProvider.
*/
-public class FakeSettingsProviderTest extends AndroidTestCase {
+@RunWith(AndroidJUnit4.class)
+@IgnoreUnderRavenwood(blockedBy = ContentProvider.class)
+public class FakeSettingsProviderTest {
+ @Rule
+ public final RavenwoodRule mRavenwood = new RavenwoodRule();
private MockContentResolver mCr;
- @Override
+ @Before
public void setUp() throws Exception {
mCr = new MockContentResolver();
mCr.addProvider(Settings.AUTHORITY, new FakeSettingsProvider());
}
+ @Test
@SmallTest
public void testBasicOperation() throws Exception {
String settingName = Settings.System.SCREEN_BRIGHTNESS;
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index 3cf28c9..69a6e6d 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -535,6 +535,8 @@
<!-- Permission required for CTS test IntentRedirectionTest -->
<permission name="android.permission.QUERY_CLONED_APPS"/>
<permission name="android.permission.GET_BINDING_UID_IMPORTANCE"/>
+ <!-- Permission required for CTS test NotificationManagerZenTest -->
+ <permission name="android.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS" />
</privapp-permissions>
<privapp-permissions package="com.android.statementservice">
diff --git a/data/etc/services.core.protolog.json b/data/etc/services.core.protolog.json
index 1912821..2237ba1 100644
--- a/data/etc/services.core.protolog.json
+++ b/data/etc/services.core.protolog.json
@@ -595,12 +595,6 @@
"group": "WM_ERROR",
"at": "com\/android\/server\/wm\/WindowManagerService.java"
},
- "-1518132958": {
- "message": "fractionRendered boundsOverSource=%f",
- "level": "VERBOSE",
- "group": "WM_DEBUG_TPL",
- "at": "com\/android\/server\/wm\/TrustedPresentationListenerController.java"
- },
"-1517908912": {
"message": "requestScrollCapture: caught exception dispatching to window.token=%s",
"level": "WARN",
@@ -967,12 +961,6 @@
"group": "WM_DEBUG_CONTENT_RECORDING",
"at": "com\/android\/server\/wm\/ContentRecorder.java"
},
- "-1209762265": {
- "message": "Registering listener=%s with id=%d for window=%s with %s",
- "level": "DEBUG",
- "group": "WM_DEBUG_TPL",
- "at": "com\/android\/server\/wm\/TrustedPresentationListenerController.java"
- },
"-1209252064": {
"message": "Clear animatingExit: reason=clearAnimatingFlags win=%s",
"level": "DEBUG",
@@ -1345,12 +1333,6 @@
"group": "WM_DEBUG_WINDOW_TRANSITIONS",
"at": "com\/android\/server\/wm\/Transition.java"
},
- "-888703350": {
- "message": "Skipping %s",
- "level": "VERBOSE",
- "group": "WM_DEBUG_TPL",
- "at": "com\/android\/server\/wm\/TrustedPresentationListenerController.java"
- },
"-883738232": {
"message": "Adding more than one toast window for UID at a time.",
"level": "WARN",
@@ -2821,12 +2803,6 @@
"group": "WM_DEBUG_ORIENTATION",
"at": "com\/android\/server\/wm\/WindowManagerService.java"
},
- "360319850": {
- "message": "fractionRendered scale=%f",
- "level": "VERBOSE",
- "group": "WM_DEBUG_TPL",
- "at": "com\/android\/server\/wm\/TrustedPresentationListenerController.java"
- },
"364992694": {
"message": "freezeDisplayRotation: current rotation=%d, new rotation=%d, caller=%s",
"level": "VERBOSE",
@@ -3007,12 +2983,6 @@
"group": "WM_DEBUG_BACK_PREVIEW",
"at": "com\/android\/server\/wm\/BackNavigationController.java"
},
- "532771960": {
- "message": "Adding untrusted state listener=%s with id=%d",
- "level": "DEBUG",
- "group": "WM_DEBUG_TPL",
- "at": "com\/android\/server\/wm\/TrustedPresentationListenerController.java"
- },
"535103992": {
"message": "Wallpaper may change! Adjusting",
"level": "VERBOSE",
@@ -3091,12 +3061,6 @@
"group": "WM_DEBUG_DREAM",
"at": "com\/android\/server\/wm\/ActivityTaskManagerService.java"
},
- "605179032": {
- "message": "checkIfInThreshold fractionRendered=%f alpha=%f currTimeMs=%d",
- "level": "VERBOSE",
- "group": "WM_DEBUG_TPL",
- "at": "com\/android\/server\/wm\/TrustedPresentationListenerController.java"
- },
"608694300": {
"message": " NEW SURFACE SESSION %s",
"level": "INFO",
@@ -3325,12 +3289,6 @@
"group": "WM_SHOW_TRANSACTIONS",
"at": "com\/android\/server\/wm\/WindowState.java"
},
- "824532141": {
- "message": "lastState=%s newState=%s alpha=%f minAlpha=%f fractionRendered=%f minFractionRendered=%f",
- "level": "VERBOSE",
- "group": "WM_DEBUG_TPL",
- "at": "com\/android\/server\/wm\/TrustedPresentationListenerController.java"
- },
"829434921": {
"message": "Draw state now committed in %s",
"level": "VERBOSE",
@@ -3625,12 +3583,6 @@
"group": "WM_SHOW_SURFACE_ALLOC",
"at": "com\/android\/server\/wm\/ScreenRotationAnimation.java"
},
- "1090378847": {
- "message": "Checking %d windows",
- "level": "VERBOSE",
- "group": "WM_DEBUG_TPL",
- "at": "com\/android\/server\/wm\/TrustedPresentationListenerController.java"
- },
"1100065297": {
"message": "Attempted to get IME policy of a display that does not exist: %d",
"level": "WARN",
@@ -3763,12 +3715,6 @@
"group": "WM_DEBUG_FOCUS",
"at": "com\/android\/server\/wm\/ActivityRecord.java"
},
- "1251721200": {
- "message": "unregister failed, couldn't find deathRecipient for %s with id=%d",
- "level": "ERROR",
- "group": "WM_DEBUG_TPL",
- "at": "com\/android\/server\/wm\/TrustedPresentationListenerController.java"
- },
"1252594551": {
"message": "Window types in WindowContext and LayoutParams.type should match! Type from LayoutParams is %d, but type from WindowContext is %d",
"level": "WARN",
@@ -3907,12 +3853,6 @@
"group": "WM_DEBUG_ORIENTATION",
"at": "com\/android\/server\/wm\/TaskDisplayArea.java"
},
- "1382634842": {
- "message": "Unregistering listener=%s with id=%d",
- "level": "DEBUG",
- "group": "WM_DEBUG_TPL",
- "at": "com\/android\/server\/wm\/TrustedPresentationListenerController.java"
- },
"1393721079": {
"message": "Starting remote display change: from [rot = %d], to [%dx%d, rot = %d]",
"level": "VERBOSE",
@@ -3961,12 +3901,6 @@
"group": "WM_ERROR",
"at": "com\/android\/server\/wm\/WindowManagerService.java"
},
- "1445704347": {
- "message": "coveredRegionsAbove updated with %s frame:%s region:%s",
- "level": "VERBOSE",
- "group": "WM_DEBUG_TPL",
- "at": "com\/android\/server\/wm\/TrustedPresentationListenerController.java"
- },
"1448683958": {
"message": "Override pending remote transitionSet=%b adapter=%s",
"level": "INFO",
@@ -4267,12 +4201,6 @@
"group": "WM_DEBUG_RECENTS_ANIMATIONS",
"at": "com\/android\/server\/wm\/RecentsAnimation.java"
},
- "1786463281": {
- "message": "Adding trusted state listener=%s with id=%d",
- "level": "DEBUG",
- "group": "WM_DEBUG_TPL",
- "at": "com\/android\/server\/wm\/TrustedPresentationListenerController.java"
- },
"1789321832": {
"message": "Then token:%s is invalid. It might be removed",
"level": "WARN",
@@ -4447,12 +4375,6 @@
"group": "WM_DEBUG_TASKS",
"at": "com\/android\/server\/wm\/RootWindowContainer.java"
},
- "1955470028": {
- "message": "computeFractionRendered: visibleRegion=%s screenBounds=%s contentSize=%s scale=%f,%f",
- "level": "VERBOSE",
- "group": "WM_DEBUG_TPL",
- "at": "com\/android\/server\/wm\/TrustedPresentationListenerController.java"
- },
"1964565370": {
"message": "Starting remote animation",
"level": "INFO",
@@ -4737,9 +4659,6 @@
"WM_DEBUG_TASKS": {
"tag": "WindowManager"
},
- "WM_DEBUG_TPL": {
- "tag": "WindowManager"
- },
"WM_DEBUG_WALLPAPER": {
"tag": "WindowManager"
},
diff --git a/libs/WindowManager/Shell/res/drawable/desktop_mode_decor_title.xml b/libs/WindowManager/Shell/res/drawable/desktop_mode_decor_title.xml
deleted file mode 100644
index ef30060..0000000
--- a/libs/WindowManager/Shell/res/drawable/desktop_mode_decor_title.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ Copyright (C) 2022 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-<shape android:shape="rectangle"
- android:tintMode="multiply"
- android:tint="@color/decor_title_color"
- xmlns:android="http://schemas.android.com/apk/res/android">
- <solid android:color="@android:color/white" />
-</shape>
diff --git a/libs/WindowManager/Shell/res/layout/desktop_mode_app_controls_window_decor.xml b/libs/WindowManager/Shell/res/layout/desktop_mode_app_controls_window_decor.xml
index c525a29..85bf2c1 100644
--- a/libs/WindowManager/Shell/res/layout/desktop_mode_app_controls_window_decor.xml
+++ b/libs/WindowManager/Shell/res/layout/desktop_mode_app_controls_window_decor.xml
@@ -21,8 +21,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_horizontal"
- android:orientation="horizontal"
- android:background="@drawable/desktop_mode_decor_title">
+ android:orientation="horizontal">
<LinearLayout
android:id="@+id/open_menu_button"
@@ -45,7 +44,6 @@
android:layout_width="0dp"
android:layout_height="20dp"
android:minWidth="80dp"
- android:textColor="@color/desktop_mode_caption_app_name_dark"
android:textAppearance="@android:style/TextAppearance.Material.Title"
android:textSize="14sp"
android:textFontWeight="500"
@@ -62,7 +60,6 @@
android:layout_height="16dp"
android:contentDescription="@string/expand_menu_text"
android:src="@drawable/ic_baseline_expand_more_24"
- android:tint="@color/desktop_mode_caption_expand_button_dark"
android:background="@null"
android:scaleType="fitCenter"
android:clickable="false"
@@ -87,8 +84,7 @@
android:src="@drawable/decor_desktop_mode_maximize_button_dark"
android:scaleType="fitCenter"
android:gravity="end"
- android:background="@null"
- android:tint="@color/desktop_mode_caption_maximize_button_dark"/>
+ android:background="@null"/>
<ImageButton
android:id="@+id/close_window"
@@ -100,6 +96,5 @@
android:src="@drawable/decor_close_button_dark"
android:scaleType="fitCenter"
android:gravity="end"
- android:background="@null"
- android:tint="@color/desktop_mode_caption_close_button_dark"/>
+ android:background="@null"/>
</com.android.wm.shell.windowdecor.WindowDecorLinearLayout>
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/res/layout/desktop_mode_focused_window_decor.xml b/libs/WindowManager/Shell/res/layout/desktop_mode_focused_window_decor.xml
index 7638132..cec7ee2 100644
--- a/libs/WindowManager/Shell/res/layout/desktop_mode_focused_window_decor.xml
+++ b/libs/WindowManager/Shell/res/layout/desktop_mode_focused_window_decor.xml
@@ -20,8 +20,7 @@
android:id="@+id/desktop_mode_caption"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:gravity="center_horizontal"
- android:background="@drawable/desktop_mode_decor_title">
+ android:gravity="center_horizontal">
<ImageButton
android:id="@+id/caption_handle"
@@ -33,5 +32,4 @@
tools:tint="@color/desktop_mode_caption_handle_bar_dark"
android:scaleType="fitXY"
android:background="?android:selectableItemBackground"/>
-
</com.android.wm.shell.windowdecor.WindowDecorLinearLayout>
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/res/values/colors.xml b/libs/WindowManager/Shell/res/values/colors.xml
index 9bfd1b4..fae71ef 100644
--- a/libs/WindowManager/Shell/res/values/colors.xml
+++ b/libs/WindowManager/Shell/res/values/colors.xml
@@ -60,14 +60,6 @@
<!-- Desktop Mode -->
<color name="desktop_mode_caption_handle_bar_light">#EFF1F2</color>
<color name="desktop_mode_caption_handle_bar_dark">#1C1C17</color>
- <color name="desktop_mode_caption_expand_button_light">#EFF1F2</color>
- <color name="desktop_mode_caption_expand_button_dark">#48473A</color>
- <color name="desktop_mode_caption_close_button_light">#EFF1F2</color>
- <color name="desktop_mode_caption_close_button_dark">#1C1C17</color>
- <color name="desktop_mode_caption_maximize_button_light">#EFF1F2</color>
- <color name="desktop_mode_caption_maximize_button_dark">#1C1C17</color>
- <color name="desktop_mode_caption_app_name_light">#EFF1F2</color>
- <color name="desktop_mode_caption_app_name_dark">#1C1C17</color>
<color name="desktop_mode_resize_veil_light">#EFF1F2</color>
<color name="desktop_mode_resize_veil_dark">#1C1C17</color>
<color name="desktop_mode_maximize_menu_button">#DDDACD</color>
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
index e74e578d..249f52b 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
@@ -1280,7 +1280,14 @@
* Dismiss bubble if it exists and remove it from the stack
*/
public void dismissBubble(Bubble bubble, @Bubbles.DismissReason int reason) {
- mBubbleData.dismissBubbleWithKey(bubble.getKey(), reason);
+ dismissBubble(bubble.getKey(), reason);
+ }
+
+ /**
+ * Dismiss bubble with given key if it exists and remove it from the stack
+ */
+ public void dismissBubble(String key, @Bubbles.DismissReason int reason) {
+ mBubbleData.dismissBubbleWithKey(key, reason);
}
/**
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java
index 5d16196..662a5c4 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java
@@ -242,6 +242,18 @@
return mDeviceConfig.isLandscape();
}
+ /**
+ * On large screen (not small tablet), while in portrait, expanded bubbles are aligned to
+ * the bottom of the screen.
+ *
+ * @return whether bubbles are bottom aligned while expanded
+ */
+ public boolean areBubblesBottomAligned() {
+ return isLargeScreen()
+ && !mDeviceConfig.isSmallTablet()
+ && !isLandscape();
+ }
+
/** @return whether the screen is considered large. */
public boolean isLargeScreen() {
return mDeviceConfig.isLargeScreen();
@@ -417,7 +429,10 @@
- bottomPadding;
}
- private int getExpandedViewHeightForLargeScreen() {
+ /**
+ * Returns the height to use for the expanded view when showing on a large screen.
+ */
+ public int getExpandedViewHeightForLargeScreen() {
// the expanded view height on large tablets is calculated based on the shortest screen
// size and is the same in both portrait and landscape
int maxVerticalInset = Math.max(mInsets.top, mInsets.bottom);
@@ -460,13 +475,21 @@
boolean isOverflow = bubble == null || BubbleOverflow.KEY.equals(bubble.getKey());
float expandedViewHeight = getExpandedViewHeight(bubble);
float topAlignment = getExpandedViewYTopAligned();
+ int manageButtonHeight =
+ isOverflow ? mExpandedViewPadding : mManageButtonHeightIncludingMargins;
+
+ // On largescreen portrait bubbles are bottom aligned.
+ if (areBubblesBottomAligned() && expandedViewHeight == MAX_HEIGHT) {
+ return mPositionRect.bottom - manageButtonHeight
+ - getExpandedViewHeightForLargeScreen() - mPointerWidth;
+ }
+
if (!showBubblesVertically() || expandedViewHeight == MAX_HEIGHT) {
// Top-align when bubbles are shown at the top or are max size.
return topAlignment;
}
+
// If we're here, we're showing vertically & developer has made height less than maximum.
- int manageButtonHeight =
- isOverflow ? mExpandedViewPadding : mManageButtonHeightIncludingMargins;
float pointerPosition = getPointerPosition(bubblePosition);
float bottomIfCentered = pointerPosition + (expandedViewHeight / 2) + manageButtonHeight;
float topIfCentered = pointerPosition - (expandedViewHeight / 2);
@@ -524,14 +547,8 @@
// Last bubble has screen index 0 and first bubble has max screen index value.
onScreenIndex = state.numberOfBubbles - 1 - index;
}
-
final float positionInRow = onScreenIndex * (mBubbleSize + mSpacingBetweenBubbles);
- final float expandedStackSize = getExpandedStackSize(state.numberOfBubbles);
- final float centerPosition = showBubblesVertically
- ? mPositionRect.centerY()
- : mPositionRect.centerX();
- // alignment - centered on the edge
- final float rowStart = centerPosition - (expandedStackSize / 2f);
+ final float rowStart = getBubbleRowStart(state);
float x;
float y;
if (showBubblesVertically) {
@@ -557,6 +574,25 @@
return new PointF(x, y);
}
+ private float getBubbleRowStart(BubbleStackView.StackViewState state) {
+ final float expandedStackSize = getExpandedStackSize(state.numberOfBubbles);
+ final float rowStart;
+ if (areBubblesBottomAligned()) {
+ final float expandedViewHeight = getExpandedViewHeightForLargeScreen();
+ final float expandedViewBottom = mScreenRect.bottom
+ - Math.max(mInsets.bottom, mInsets.top)
+ - mManageButtonHeight - mPointerWidth;
+ final float expandedViewCenter = expandedViewBottom - (expandedViewHeight / 2f);
+ rowStart = expandedViewCenter - (expandedStackSize / 2f);
+ } else {
+ final float centerPosition = showBubblesVertically()
+ ? mPositionRect.centerY()
+ : mPositionRect.centerX();
+ rowStart = centerPosition - (expandedStackSize / 2f);
+ }
+ return rowStart;
+ }
+
/**
* Returns the position of the bubble on-screen when the stack is expanded and the IME
* is showing.
@@ -577,9 +613,8 @@
final float bottomHeight = getImeHeight() + mInsets.bottom + (mSpacingBetweenBubbles * 2);
final float bottomInset = mScreenRect.bottom - bottomHeight;
final float expandedStackSize = getExpandedStackSize(state.numberOfBubbles);
- final float centerPosition = mPositionRect.centerY();
- final float rowBottom = centerPosition + (expandedStackSize / 2f);
- final float rowTop = centerPosition - (expandedStackSize / 2f);
+ final float rowTop = getBubbleRowStart(state);
+ final float rowBottom = rowTop + expandedStackSize;
float rowTopForIme = rowTop;
if (rowBottom > bottomInset) {
// We overlap with IME, must shift the bubbles
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java
index 65db69a..b7f749e 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java
@@ -2462,6 +2462,7 @@
final Runnable collapseBackToStack = () ->
mExpandedAnimationController.collapseBackToStack(
mStackAnimationController.getStackPositionAlongNearestHorizontalEdge(),
+ /* fadeBubblesDuringCollapse= */ mRemovingLastBubbleWhileExpanded,
() -> {
mBubbleContainer.setActiveController(mStackAnimationController);
updateOverflowVisibility();
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/ExpandedAnimationController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/ExpandedAnimationController.java
index 79f306e..5b0239f 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/ExpandedAnimationController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/ExpandedAnimationController.java
@@ -107,6 +107,7 @@
private Runnable mAfterExpand;
private Runnable mAfterCollapse;
private PointF mCollapsePoint;
+ private boolean mFadeBubblesDuringCollapse = false;
/**
* Whether the dragged out bubble is springing towards the touch point, rather than using the
@@ -201,12 +202,14 @@
}
/** Animate collapsing the bubbles back to their stacked position. */
- public void collapseBackToStack(PointF collapsePoint, Runnable after) {
+ public void collapseBackToStack(PointF collapsePoint, boolean fadeBubblesDuringCollapse,
+ Runnable after) {
mAnimatingExpand = false;
mPreparingToCollapse = false;
mAnimatingCollapse = true;
mAfterCollapse = after;
mCollapsePoint = collapsePoint;
+ mFadeBubblesDuringCollapse = fadeBubblesDuringCollapse;
startOrUpdatePathAnimation(false /* expanding */);
}
@@ -253,6 +256,7 @@
}
mAfterCollapse = null;
+ mFadeBubblesDuringCollapse = false;
};
}
@@ -262,7 +266,7 @@
== LAYOUT_DIRECTION_RTL;
// Animate each bubble individually, since each path will end in a different spot.
- animationsForChildrenFromIndex(0, (index, animation) -> {
+ animationsForChildrenFromIndex(0, mFadeBubblesDuringCollapse, (index, animation) -> {
final View bubble = mLayout.getChildAt(index);
// Start a path at the bubble's current position.
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/PhysicsAnimationLayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/PhysicsAnimationLayout.java
index f3cc514..ed00da8 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/PhysicsAnimationLayout.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/PhysicsAnimationLayout.java
@@ -204,6 +204,13 @@
return animationForChild(mLayout.getChildAt(index));
}
+
+ protected MultiAnimationStarter animationsForChildrenFromIndex(
+ int startIndex, ChildAnimationConfigurator configurator) {
+ return animationsForChildrenFromIndex(startIndex, /* fadeChildren= */ false,
+ configurator);
+ }
+
/**
* Returns a {@link MultiAnimationStarter} whose startAll method will start the physics
* animations for all children from startIndex onward. The provided configurator will be
@@ -211,14 +218,16 @@
* animation appropriately.
*/
protected MultiAnimationStarter animationsForChildrenFromIndex(
- int startIndex, ChildAnimationConfigurator configurator) {
+ int startIndex, boolean fadeChildren, ChildAnimationConfigurator configurator) {
final Set<DynamicAnimation.ViewProperty> allAnimatedProperties = new HashSet<>();
final List<PhysicsPropertyAnimator> allChildAnims = new ArrayList<>();
// Retrieve the animator for each child, ask the configurator to configure it, then save
// it and the properties it chose to animate.
for (int i = startIndex; i < mLayout.getChildCount(); i++) {
- final PhysicsPropertyAnimator anim = animationForChildAtIndex(i);
+ final PhysicsPropertyAnimator anim = fadeChildren
+ ? animationForChildAtIndex(i).alpha(0)
+ : animationForChildAtIndex(i);
configurator.configureAnimationForChildAtIndex(i, anim);
allAnimatedProperties.addAll(anim.getAnimatedProperties());
allChildAnims.add(anim);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarExpandedView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarExpandedView.java
index 50e1f73..d073f1d 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarExpandedView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarExpandedView.java
@@ -67,7 +67,6 @@
private boolean mIsOverflow;
private BubbleTaskViewHelper mBubbleTaskViewHelper;
private BubbleBarMenuViewController mMenuViewController;
- private BubbleBarExpandedViewDragController mDragController;
private @Nullable Supplier<Rect> mLayerBoundsSupplier;
private @Nullable Listener mListener;
@@ -181,8 +180,6 @@
mHandleView.setOnClickListener(view -> {
mMenuViewController.showMenu(true /* animated */);
});
-
- mDragController = new BubbleBarExpandedViewDragController(this);
}
public BubbleBarHandleView getHandleView() {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarExpandedViewDragController.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarExpandedViewDragController.kt
index 933794b..4ea18f7 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarExpandedViewDragController.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarExpandedViewDragController.kt
@@ -19,29 +19,47 @@
import android.animation.Animator
import android.animation.AnimatorListenerAdapter
import android.graphics.PointF
+import android.graphics.Rect
import android.view.MotionEvent
import android.view.View
import com.android.wm.shell.animation.Interpolators
+import com.android.wm.shell.common.bubbles.DismissView
import com.android.wm.shell.common.bubbles.RelativeTouchListener
/** Controller for handling drag interactions with [BubbleBarExpandedView] */
-class BubbleBarExpandedViewDragController(private val expandedView: BubbleBarExpandedView) {
+class BubbleBarExpandedViewDragController(
+ private val expandedView: BubbleBarExpandedView,
+ private val dismissView: DismissView,
+ private val onDismissed: () -> Unit
+) {
init {
expandedView.handleView.setOnTouchListener(HandleDragListener())
}
- private fun resetExpandedViewPosition(initialX: Float, initialY: Float) {
- val listener = object : AnimatorListenerAdapter() {
- override fun onAnimationStart(animation: Animator) {
- expandedView.isAnimating = true
- }
-
- override fun onAnimationEnd(animation: Animator) {
- expandedView.isAnimating = false
- }
+ private fun finishDrag(x: Float, y: Float, viewInitialX: Float, viewInitialY: Float) {
+ val dismissCircleBounds = Rect().apply { dismissView.circle.getBoundsOnScreen(this) }
+ if (dismissCircleBounds.contains(x.toInt(), y.toInt())) {
+ onDismissed()
+ } else {
+ resetExpandedViewPosition(viewInitialX, viewInitialY)
}
- expandedView.animate()
+ dismissView.hide()
+ }
+
+ private fun resetExpandedViewPosition(initialX: Float, initialY: Float) {
+ val listener =
+ object : AnimatorListenerAdapter() {
+ override fun onAnimationStart(animation: Animator) {
+ expandedView.isAnimating = true
+ }
+
+ override fun onAnimationEnd(animation: Animator) {
+ expandedView.isAnimating = false
+ }
+ }
+ expandedView
+ .animate()
.translationX(initialX)
.translationY(initialY)
.setDuration(RESET_POSITION_ANIM_DURATION)
@@ -74,6 +92,7 @@
) {
expandedView.translationX = expandedViewRestPosition.x + dx
expandedView.translationY = expandedViewRestPosition.y + dy
+ dismissView.show()
}
override fun onUp(
@@ -86,11 +105,12 @@
velX: Float,
velY: Float
) {
- resetExpandedViewPosition(expandedViewRestPosition.x, expandedViewRestPosition.y)
+ finishDrag(ev.rawX, ev.rawY, expandedViewRestPosition.x, expandedViewRestPosition.y)
}
override fun onCancel(v: View, ev: MotionEvent, viewInitialX: Float, viewInitialY: Float) {
resetExpandedViewPosition(expandedViewRestPosition.x, expandedViewRestPosition.y)
+ dismissView.hide()
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarLayerView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarLayerView.java
index 92cb436..bdb0e20 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarLayerView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarLayerView.java
@@ -31,17 +31,21 @@
import android.view.WindowManager;
import android.widget.FrameLayout;
+import com.android.wm.shell.R;
import com.android.wm.shell.bubbles.BubbleController;
import com.android.wm.shell.bubbles.BubbleOverflow;
import com.android.wm.shell.bubbles.BubblePositioner;
import com.android.wm.shell.bubbles.BubbleViewProvider;
+import com.android.wm.shell.bubbles.Bubbles;
import com.android.wm.shell.bubbles.DeviceConfig;
+import com.android.wm.shell.bubbles.DismissViewUtils;
+import com.android.wm.shell.common.bubbles.DismissView;
+
+import kotlin.Unit;
import java.util.Objects;
import java.util.function.Consumer;
-import kotlin.Unit;
-
/**
* Similar to {@link com.android.wm.shell.bubbles.BubbleStackView}, this view is added to window
* manager to display bubbles. However, it is only used when bubbles are being displayed in
@@ -63,7 +67,11 @@
@Nullable
private BubbleViewProvider mExpandedBubble;
+ @Nullable
private BubbleBarExpandedView mExpandedView;
+ @Nullable
+ private BubbleBarExpandedViewDragController mDragController;
+ private DismissView mDismissView;
private @Nullable Consumer<String> mUnBubbleConversationCallback;
// TODO(b/273310265) - currently the view is always on the right, need to update for RTL.
@@ -101,6 +109,8 @@
mScrimView.setBackgroundDrawable(new ColorDrawable(
getResources().getColor(android.R.color.system_neutral1_1000)));
+ setUpDismissView();
+
setOnClickListener(view -> hideMenuOrCollapse());
}
@@ -196,6 +206,13 @@
}
});
+ mDragController = new BubbleBarExpandedViewDragController(mExpandedView, mDismissView,
+ () -> {
+ mBubbleController.dismissBubble(mExpandedBubble.getKey(),
+ Bubbles.DISMISS_USER_GESTURE);
+ return Unit.INSTANCE;
+ });
+
addView(mExpandedView, new FrameLayout.LayoutParams(width, height));
}
@@ -227,6 +244,7 @@
mAnimationHelper.animateCollapse(() -> removeView(viewToRemove));
mBubbleController.getSysuiProxy().onStackExpandChanged(false);
mExpandedView = null;
+ mDragController = null;
setTouchDelegate(null);
showScrim(false);
}
@@ -252,6 +270,18 @@
mUnBubbleConversationCallback = unBubbleConversationCallback;
}
+ private void setUpDismissView() {
+ if (mDismissView != null) {
+ removeView(mDismissView);
+ }
+ mDismissView = new DismissView(getContext());
+ DismissViewUtils.setup(mDismissView);
+ int elevation = getResources().getDimensionPixelSize(R.dimen.bubble_elevation);
+
+ addView(mDismissView);
+ mDismissView.setElevation(elevation);
+ }
+
/** Hides the current modal education/menu view, expanded view or collapses the bubble stack */
private void hideMenuOrCollapse() {
if (mEducationViewController.isEducationVisible()) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitScreenConstants.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitScreenConstants.java
index e734300..49db8d9 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitScreenConstants.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitScreenConstants.java
@@ -26,11 +26,12 @@
/** Helper utility class of methods and constants that are available to be imported in Launcher. */
public class SplitScreenConstants {
- /**
- * Duration used for every split fade-in or fade-out.
- */
+ /** Duration used for every split fade-in or fade-out. */
public static final int FADE_DURATION = 133;
+ /** Key for passing in widget intents when invoking split from launcher workspace. */
+ public static final String KEY_EXTRA_WIDGET_INTENT = "key_extra_widget_intent";
+
///////////////
// IMPORTANT for the following SPLIT_POSITION and SNAP_TO constants:
// These int values must not be changed -- they are persisted to user-defined app pairs, and
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropPolicy.java b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropPolicy.java
index 162ce19..a31a773 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropPolicy.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropPolicy.java
@@ -40,6 +40,7 @@
import static com.android.wm.shell.draganddrop.DragAndDropPolicy.Target.TYPE_SPLIT_RIGHT;
import static com.android.wm.shell.draganddrop.DragAndDropPolicy.Target.TYPE_SPLIT_TOP;
+import android.app.ActivityOptions;
import android.app.ActivityTaskManager;
import android.app.PendingIntent;
import android.content.ActivityNotFoundException;
@@ -246,8 +247,15 @@
@SplitPosition int position) {
final boolean isTask = description.hasMimeType(MIMETYPE_APPLICATION_TASK);
final boolean isShortcut = description.hasMimeType(MIMETYPE_APPLICATION_SHORTCUT);
- final Bundle opts = intent.hasExtra(EXTRA_ACTIVITY_OPTIONS)
- ? intent.getBundleExtra(EXTRA_ACTIVITY_OPTIONS) : new Bundle();
+ final ActivityOptions baseActivityOpts = ActivityOptions.makeBasic();
+ baseActivityOpts.setDisallowEnterPictureInPictureWhileLaunching(true);
+ final Bundle opts = baseActivityOpts.toBundle();
+ if (intent.hasExtra(EXTRA_ACTIVITY_OPTIONS)) {
+ opts.putAll(intent.getBundleExtra(EXTRA_ACTIVITY_OPTIONS));
+ }
+ // Put BAL flags to avoid activity start aborted.
+ opts.putBoolean(KEY_PENDING_INTENT_BACKGROUND_ACTIVITY_ALLOWED, true);
+ opts.putBoolean(KEY_PENDING_INTENT_BACKGROUND_ACTIVITY_ALLOWED_BY_PERMISSION, true);
final UserHandle user = intent.getParcelableExtra(EXTRA_USER);
if (isTask) {
@@ -259,9 +267,6 @@
mStarter.startShortcut(packageName, id, position, opts, user);
} else {
final PendingIntent launchIntent = intent.getParcelableExtra(EXTRA_PENDING_INTENT);
- // Put BAL flags to avoid activity start aborted.
- opts.putBoolean(KEY_PENDING_INTENT_BACKGROUND_ACTIVITY_ALLOWED, true);
- opts.putBoolean(KEY_PENDING_INTENT_BACKGROUND_ACTIVITY_ALLOWED_BY_PERMISSION, true);
mStarter.startIntent(launchIntent, user.getIdentifier(), null /* fillIntent */,
position, opts);
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java
index d5fab44..fe4980a 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java
@@ -554,6 +554,11 @@
}
}
}
+ // if overlay is present remove it immediately, as exit transition came before it faded out
+ if (mPipOrganizer.mSwipePipToHomeOverlay != null) {
+ startTransaction.remove(mPipOrganizer.mSwipePipToHomeOverlay);
+ clearSwipePipToHomeOverlay();
+ }
if (pipChange == null) {
ProtoLog.w(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
"%s: No window of exiting PIP is found. Can't play expand animation", TAG);
@@ -1007,7 +1012,6 @@
// the overlay to the final PIP task.
startTransaction.reparent(swipePipToHomeOverlay, leash)
.setLayer(swipePipToHomeOverlay, Integer.MAX_VALUE);
- mPipOrganizer.mSwipePipToHomeOverlay = null;
}
final Rect sourceBounds = pipTaskInfo.configuration.windowConfiguration.getBounds();
@@ -1029,7 +1033,7 @@
sendOnPipTransitionFinished(TRANSITION_DIRECTION_TO_PIP);
if (swipePipToHomeOverlay != null) {
mPipOrganizer.fadeOutAndRemoveOverlay(swipePipToHomeOverlay,
- null /* callback */, false /* withStartDelay */);
+ this::clearSwipePipToHomeOverlay /* callback */, false /* withStartDelay */);
}
mPipTransitionState.setInSwipePipToHomeTransition(false);
}
@@ -1173,6 +1177,10 @@
mPipMenuController.updateMenuBounds(destinationBounds);
}
+ private void clearSwipePipToHomeOverlay() {
+ mPipOrganizer.mSwipePipToHomeOverlay = null;
+ }
+
@Override
public void dump(PrintWriter pw, String prefix) {
final String innerPrefix = prefix + " ";
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
index 37b24e5..56f1c78 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
@@ -25,6 +25,7 @@
import static android.view.RemoteAnimationTarget.MODE_OPENING;
import static com.android.wm.shell.common.ExecutorUtils.executeRemoteCallWithTaskPermission;
+import static com.android.wm.shell.common.split.SplitScreenConstants.KEY_EXTRA_WIDGET_INTENT;
import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT;
import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_TOP_OR_LEFT;
import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_UNDEFINED;
@@ -719,10 +720,10 @@
// recents that hasn't launched and is not being organized
final String packageName2 = SplitScreenUtils.getPackageName(taskId, mTaskOrganizer);
final int userId2 = SplitScreenUtils.getUserId(taskId, mTaskOrganizer);
+ boolean setSecondIntentMultipleTask = false;
if (samePackage(packageName1, packageName2, userId1, userId2)) {
if (supportMultiInstancesSplit(packageName1)) {
- fillInIntent = new Intent();
- fillInIntent.addFlags(FLAG_ACTIVITY_MULTIPLE_TASK);
+ setSecondIntentMultipleTask = true;
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_SPLIT_SCREEN, "Adding MULTIPLE_TASK");
} else {
if (mRecentTasksOptional.isPresent()) {
@@ -737,6 +738,10 @@
Toast.LENGTH_SHORT).show();
}
}
+ if (options2 != null) {
+ Intent widgetIntent = options2.getParcelable(KEY_EXTRA_WIDGET_INTENT, Intent.class);
+ fillInIntent = resolveWidgetFillinIntent(widgetIntent, setSecondIntentMultipleTask);
+ }
mStageCoordinator.startIntentAndTask(pendingIntent, fillInIntent, options1, taskId,
options2, splitPosition, snapPosition, remoteTransition, instanceId);
}
@@ -787,12 +792,12 @@
? ActivityOptions.fromBundle(options1) : ActivityOptions.makeBasic();
final ActivityOptions activityOptions2 = options2 != null
? ActivityOptions.fromBundle(options2) : ActivityOptions.makeBasic();
+ boolean setSecondIntentMultipleTask = false;
if (samePackage(packageName1, packageName2, userId1, userId2)) {
if (supportMultiInstancesSplit(packageName1)) {
fillInIntent1 = new Intent();
fillInIntent1.addFlags(FLAG_ACTIVITY_MULTIPLE_TASK);
- fillInIntent2 = new Intent();
- fillInIntent2.addFlags(FLAG_ACTIVITY_MULTIPLE_TASK);
+ setSecondIntentMultipleTask = true;
if (shortcutInfo1 != null) {
activityOptions1.setApplyMultipleTaskFlagForShortcut(true);
@@ -811,6 +816,10 @@
Toast.LENGTH_SHORT).show();
}
}
+ if (options2 != null) {
+ Intent widgetIntent = options2.getParcelable(KEY_EXTRA_WIDGET_INTENT, Intent.class);
+ fillInIntent2 = resolveWidgetFillinIntent(widgetIntent, setSecondIntentMultipleTask);
+ }
mStageCoordinator.startIntents(pendingIntent1, fillInIntent1, shortcutInfo1,
activityOptions1.toBundle(), pendingIntent2, fillInIntent2, shortcutInfo2,
activityOptions2.toBundle(), splitPosition, snapPosition, remoteTransition,
@@ -916,6 +925,34 @@
return false;
}
+ /**
+ * Determines whether the widgetIntent needs to be modified if multiple tasks of its
+ * corresponding package/app are supported. There are 4 possible paths:
+ * <li> We select a widget for second app which is the same as the first app </li>
+ * <li> We select a widget for second app which is different from the first app </li>
+ * <li> No widgets involved, we select a second app that is the same as first app </li>
+ * <li> No widgets involved, we select a second app that is different from the first app
+ * (returns null) </li>
+ *
+ * @return an {@link Intent} with the appropriate {@link Intent#FLAG_ACTIVITY_MULTIPLE_TASK}
+ * added on or not depending on {@param launchMultipleTasks}.
+ */
+ @Nullable
+ private Intent resolveWidgetFillinIntent(@Nullable Intent widgetIntent,
+ boolean launchMultipleTasks) {
+ Intent fillInIntent2 = null;
+ if (launchMultipleTasks && widgetIntent != null) {
+ fillInIntent2 = widgetIntent;
+ fillInIntent2.addFlags(FLAG_ACTIVITY_MULTIPLE_TASK);
+ } else if (widgetIntent != null) {
+ fillInIntent2 = widgetIntent;
+ } else if (launchMultipleTasks) {
+ fillInIntent2 = new Intent();
+ fillInIntent2.addFlags(FLAG_ACTIVITY_MULTIPLE_TASK);
+ }
+ return fillInIntent2;
+ }
+
RemoteAnimationTarget[] onGoingToRecentsLegacy(RemoteAnimationTarget[] apps) {
if (ENABLE_SHELL_TRANSITIONS) return null;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/HomeTransitionObserver.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/HomeTransitionObserver.java
index 5c02dbc..473deba 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/HomeTransitionObserver.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/HomeTransitionObserver.java
@@ -57,7 +57,9 @@
@NonNull SurfaceControl.Transaction finishTransaction) {
for (TransitionInfo.Change change : info.getChanges()) {
final ActivityManager.RunningTaskInfo taskInfo = change.getTaskInfo();
- if (taskInfo == null || taskInfo.taskId == -1) {
+ if (taskInfo == null
+ || taskInfo.taskId == -1
+ || !taskInfo.isRunning) {
continue;
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewholder/DesktopModeAppControlsWindowDecorationViewHolder.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewholder/DesktopModeAppControlsWindowDecorationViewHolder.kt
index b739ad3..589a813 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewholder/DesktopModeAppControlsWindowDecorationViewHolder.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewholder/DesktopModeAppControlsWindowDecorationViewHolder.kt
@@ -1,14 +1,23 @@
package com.android.wm.shell.windowdecor.viewholder
+import android.annotation.ColorInt
import android.app.ActivityManager.RunningTaskInfo
import android.content.res.ColorStateList
+import android.content.res.Configuration
import android.graphics.Bitmap
-import android.graphics.drawable.GradientDrawable
+import android.graphics.Color
import android.view.View
import android.view.View.OnLongClickListener
import android.widget.ImageButton
import android.widget.ImageView
import android.widget.TextView
+import androidx.core.content.withStyledAttributes
+import com.android.internal.R.attr.materialColorOnSecondaryContainer
+import com.android.internal.R.attr.materialColorOnSurface
+import com.android.internal.R.attr.materialColorSecondaryContainer
+import com.android.internal.R.attr.materialColorSurfaceContainerHigh
+import com.android.internal.R.attr.materialColorSurfaceContainerLow
+import com.android.internal.R.attr.materialColorSurfaceDim
import com.android.wm.shell.R
/**
@@ -49,57 +58,82 @@
}
override fun bindData(taskInfo: RunningTaskInfo) {
- val captionDrawable = captionView.background as GradientDrawable
- taskInfo.taskDescription?.statusBarColor?.let {
- captionDrawable.setColor(it)
- }
-
- closeWindowButton.imageTintList = ColorStateList.valueOf(
- getCaptionCloseButtonColor(taskInfo))
- maximizeWindowButton.imageTintList = ColorStateList.valueOf(
- getCaptionMaximizeButtonColor(taskInfo))
- expandMenuButton.imageTintList = ColorStateList.valueOf(
- getCaptionExpandButtonColor(taskInfo))
- appNameTextView.setTextColor(getCaptionAppNameTextColor(taskInfo))
+ captionView.setBackgroundColor(getCaptionBackgroundColor(taskInfo))
+ val color = getAppNameAndButtonColor(taskInfo)
+ val alpha = Color.alpha(color)
+ closeWindowButton.imageTintList = ColorStateList.valueOf(color)
+ maximizeWindowButton.imageTintList = ColorStateList.valueOf(color)
+ expandMenuButton.imageTintList = ColorStateList.valueOf(color)
+ appNameTextView.setTextColor(color)
+ appIconImageView.imageAlpha = alpha
+ maximizeWindowButton.imageAlpha = alpha
+ closeWindowButton.imageAlpha = alpha
+ expandMenuButton.imageAlpha = alpha
}
override fun onHandleMenuOpened() {}
override fun onHandleMenuClosed() {}
- private fun getCaptionAppNameTextColor(taskInfo: RunningTaskInfo): Int {
- return if (shouldUseLightCaptionColors(taskInfo)) {
- context.getColor(R.color.desktop_mode_caption_app_name_light)
- } else {
- context.getColor(R.color.desktop_mode_caption_app_name_dark)
+ @ColorInt
+ private fun getCaptionBackgroundColor(taskInfo: RunningTaskInfo): Int {
+ val materialColorAttr: Int =
+ if (isDarkMode()) {
+ if (!taskInfo.isFocused) {
+ materialColorSurfaceContainerHigh
+ } else {
+ materialColorSurfaceDim
+ }
+ } else {
+ if (!taskInfo.isFocused) {
+ materialColorSurfaceContainerLow
+ } else {
+ materialColorSecondaryContainer
+ }
}
+ context.withStyledAttributes(null, intArrayOf(materialColorAttr), 0, 0) {
+ return getColor(0, 0)
+ }
+ return 0
}
- private fun getCaptionCloseButtonColor(taskInfo: RunningTaskInfo): Int {
- return if (shouldUseLightCaptionColors(taskInfo)) {
- context.getColor(R.color.desktop_mode_caption_close_button_light)
- } else {
- context.getColor(R.color.desktop_mode_caption_close_button_dark)
+ @ColorInt
+ private fun getAppNameAndButtonColor(taskInfo: RunningTaskInfo): Int {
+ val materialColorAttr = when {
+ isDarkMode() -> materialColorOnSurface
+ else -> materialColorOnSecondaryContainer
}
+ val appDetailsOpacity = when {
+ isDarkMode() && !taskInfo.isFocused -> DARK_THEME_UNFOCUSED_OPACITY
+ !isDarkMode() && !taskInfo.isFocused -> LIGHT_THEME_UNFOCUSED_OPACITY
+ else -> FOCUSED_OPACITY
+ }
+ context.withStyledAttributes(null, intArrayOf(materialColorAttr), 0, 0) {
+ val color = getColor(0, 0)
+ return if (appDetailsOpacity == FOCUSED_OPACITY) {
+ color
+ } else {
+ Color.argb(
+ appDetailsOpacity,
+ Color.red(color),
+ Color.green(color),
+ Color.blue(color)
+ )
+ }
+ }
+ return 0
}
- private fun getCaptionMaximizeButtonColor(taskInfo: RunningTaskInfo): Int {
- return if (shouldUseLightCaptionColors(taskInfo)) {
- context.getColor(R.color.desktop_mode_caption_maximize_button_light)
- } else {
- context.getColor(R.color.desktop_mode_caption_maximize_button_dark)
- }
- }
-
- private fun getCaptionExpandButtonColor(taskInfo: RunningTaskInfo): Int {
- return if (shouldUseLightCaptionColors(taskInfo)) {
- context.getColor(R.color.desktop_mode_caption_expand_button_light)
- } else {
- context.getColor(R.color.desktop_mode_caption_expand_button_dark)
- }
+ private fun isDarkMode(): Boolean {
+ return context.resources.configuration.uiMode and
+ Configuration.UI_MODE_NIGHT_MASK ==
+ Configuration.UI_MODE_NIGHT_YES
}
companion object {
private const val TAG = "DesktopModeAppControlsWindowDecorationViewHolder"
+ private const val DARK_THEME_UNFOCUSED_OPACITY = 140 // 55%
+ private const val LIGHT_THEME_UNFOCUSED_OPACITY = 166 // 65%
+ private const val FOCUSED_OPACITY = 255
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewholder/DesktopModeFocusedWindowDecorationViewHolder.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewholder/DesktopModeFocusedWindowDecorationViewHolder.kt
index b1fb0f1..4930cb7 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewholder/DesktopModeFocusedWindowDecorationViewHolder.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewholder/DesktopModeFocusedWindowDecorationViewHolder.kt
@@ -2,9 +2,11 @@
import android.animation.ObjectAnimator
import android.app.ActivityManager.RunningTaskInfo
+import android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM
import android.content.res.ColorStateList
-import android.graphics.drawable.GradientDrawable
+import android.graphics.Color
import android.view.View
+import android.view.WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS
import android.widget.ImageButton
import com.android.wm.shell.R
import com.android.wm.shell.animation.Interpolators
@@ -34,10 +36,8 @@
override fun bindData(taskInfo: RunningTaskInfo) {
taskInfo.taskDescription?.statusBarColor?.let { captionColor ->
- val captionDrawable = captionView.background as GradientDrawable
- captionDrawable.setColor(captionColor)
+ captionView.setBackgroundColor(captionColor)
}
-
captionHandle.imageTintList = ColorStateList.valueOf(getCaptionHandleBarColor(taskInfo))
}
@@ -57,6 +57,22 @@
}
}
+ /**
+ * Whether the caption items should use the 'light' color variant so that there's good contrast
+ * with the caption background color.
+ */
+ private fun shouldUseLightCaptionColors(taskInfo: RunningTaskInfo): Boolean {
+ return taskInfo.taskDescription
+ ?.let { taskDescription ->
+ if (Color.alpha(taskDescription.statusBarColor) != 0 &&
+ taskInfo.windowingMode == WINDOWING_MODE_FREEFORM) {
+ Color.valueOf(taskDescription.statusBarColor).luminance() < 0.5
+ } else {
+ taskDescription.statusBarAppearance and APPEARANCE_LIGHT_STATUS_BARS == 0
+ }
+ } ?: false
+ }
+
/** Animate appearance/disappearance of caption handle as the handle menu is animated. */
private fun animateCaptionHandleAlpha(startValue: Float, endValue: Float) {
val animator =
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewholder/DesktopModeWindowDecorationViewHolder.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewholder/DesktopModeWindowDecorationViewHolder.kt
index 8b405f0..690b4e4 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewholder/DesktopModeWindowDecorationViewHolder.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewholder/DesktopModeWindowDecorationViewHolder.kt
@@ -1,11 +1,8 @@
package com.android.wm.shell.windowdecor.viewholder
import android.app.ActivityManager.RunningTaskInfo
-import android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM
import android.content.Context
-import android.graphics.Color
import android.view.View
-import android.view.WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS
/**
* Encapsulates the root [View] of a window decoration and its children to facilitate looking up
@@ -20,22 +17,6 @@
*/
abstract fun bindData(taskInfo: RunningTaskInfo)
- /**
- * Whether the caption items should use the 'light' color variant so that there's good contrast
- * with the caption background color.
- */
- protected fun shouldUseLightCaptionColors(taskInfo: RunningTaskInfo): Boolean {
- return taskInfo.taskDescription
- ?.let { taskDescription ->
- if (Color.alpha(taskDescription.statusBarColor) != 0 &&
- taskInfo.windowingMode == WINDOWING_MODE_FREEFORM) {
- Color.valueOf(taskDescription.statusBarColor).luminance() < 0.5
- } else {
- taskDescription.statusBarAppearance and APPEARANCE_LIGHT_STATUS_BARS == 0
- }
- } ?: false
- }
-
/** Callback when the handle menu is opened. */
abstract fun onHandleMenuOpened()
diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/EnterSplitScreenByDragFromAllApps.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/EnterSplitScreenByDragFromAllApps.kt
index d7b306c..03170a3 100644
--- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/EnterSplitScreenByDragFromAllApps.kt
+++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/EnterSplitScreenByDragFromAllApps.kt
@@ -57,10 +57,13 @@
tapl.setEnableRotation(true)
tapl.setExpectedRotation(rotation.value)
+
+ tapl.enableBlockTimeout(true)
}
@Test
open fun enterSplitScreenByDragFromAllApps() {
+ tapl.showTaskbarIfHidden()
tapl.launchedAppState.taskbar
.openAllApps()
.getAppIcon(secondaryApp.appName)
@@ -72,5 +75,6 @@
fun teardown() {
primaryApp.exit(wmHelper)
secondaryApp.exit(wmHelper)
+ tapl.enableBlockTimeout(false)
}
}
diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/EnterSplitScreenByDragFromShortcut.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/EnterSplitScreenByDragFromShortcut.kt
index 8134fdd..479d01d 100644
--- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/EnterSplitScreenByDragFromShortcut.kt
+++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/EnterSplitScreenByDragFromShortcut.kt
@@ -59,10 +59,13 @@
tapl.setEnableRotation(true)
tapl.setExpectedRotation(rotation.value)
+
+ tapl.enableBlockTimeout(true)
}
@Test
open fun enterSplitScreenByDragFromShortcut() {
+ tapl.showTaskbarIfHidden()
tapl.launchedAppState.taskbar
.getAppIcon(secondaryApp.appName)
.openDeepShortcutMenu()
@@ -83,6 +86,7 @@
fun teardwon() {
primaryApp.exit(wmHelper)
secondaryApp.exit(wmHelper)
+ tapl.enableBlockTimeout(false)
}
companion object {
diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/EnterSplitScreenByDragFromTaskbar.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/EnterSplitScreenByDragFromTaskbar.kt
index 3417744..625c56b 100644
--- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/EnterSplitScreenByDragFromTaskbar.kt
+++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/EnterSplitScreenByDragFromTaskbar.kt
@@ -54,6 +54,8 @@
tapl.setEnableRotation(true)
tapl.setExpectedRotation(rotation.value)
+ tapl.enableBlockTimeout(true)
+
tapl.goHome()
SplitScreenUtils.createShortcutOnHotseatIfNotExist(tapl, secondaryApp.appName)
primaryApp.launchViaIntent(wmHelper)
@@ -61,6 +63,7 @@
@Test
open fun enterSplitScreenByDragFromTaskbar() {
+ tapl.showTaskbarIfHidden()
tapl.launchedAppState.taskbar
.getAppIcon(secondaryApp.appName)
.dragToSplitscreen(secondaryApp.packageName, primaryApp.packageName)
@@ -71,6 +74,7 @@
fun teardown() {
primaryApp.exit(wmHelper)
secondaryApp.exit(wmHelper)
+ tapl.enableBlockTimeout(false)
}
companion object {
diff --git a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenByDragFromAllAppsBenchmark.kt b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenByDragFromAllAppsBenchmark.kt
index 394864a..5c43cbd 100644
--- a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenByDragFromAllAppsBenchmark.kt
+++ b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenByDragFromAllAppsBenchmark.kt
@@ -23,6 +23,7 @@
import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import androidx.test.filters.RequiresDevice
import com.android.wm.shell.flicker.utils.SplitScreenUtils
+import org.junit.After
import org.junit.Assume
import org.junit.Before
import org.junit.FixMethodOrder
@@ -42,8 +43,10 @@
setup {
tapl.goHome()
primaryApp.launchViaIntent(wmHelper)
+ tapl.enableBlockTimeout(true)
}
transitions {
+ tapl.showTaskbarIfHidden()
tapl.launchedAppState.taskbar
.openAllApps()
.getAppIcon(secondaryApp.appName)
@@ -57,6 +60,11 @@
Assume.assumeTrue(tapl.isTablet)
}
+ @After
+ fun after() {
+ tapl.enableBlockTimeout(false)
+ }
+
companion object {
@Parameterized.Parameters(name = "{0}")
@JvmStatic
diff --git a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenByDragFromShortcutBenchmark.kt b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenByDragFromShortcutBenchmark.kt
index 3b3be84..15ad0c1 100644
--- a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenByDragFromShortcutBenchmark.kt
+++ b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenByDragFromShortcutBenchmark.kt
@@ -23,6 +23,7 @@
import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import androidx.test.filters.RequiresDevice
import com.android.wm.shell.flicker.utils.SplitScreenUtils
+import org.junit.After
import org.junit.Assume
import org.junit.Before
import org.junit.FixMethodOrder
@@ -42,13 +43,20 @@
Assume.assumeTrue(tapl.isTablet)
}
+ @After
+ fun after() {
+ tapl.enableBlockTimeout(false)
+ }
+
protected val thisTransition: FlickerBuilder.() -> Unit = {
setup {
tapl.goHome()
SplitScreenUtils.createShortcutOnHotseatIfNotExist(tapl, secondaryApp.appName)
primaryApp.launchViaIntent(wmHelper)
+ tapl.enableBlockTimeout(true)
}
transitions {
+ tapl.showTaskbarIfHidden()
tapl.launchedAppState.taskbar
.getAppIcon(secondaryApp.appName)
.openDeepShortcutMenu()
diff --git a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenByDragFromTaskbarBenchmark.kt b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenByDragFromTaskbarBenchmark.kt
index eff3559..ca8adb1 100644
--- a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenByDragFromTaskbarBenchmark.kt
+++ b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenByDragFromTaskbarBenchmark.kt
@@ -23,6 +23,7 @@
import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import androidx.test.filters.RequiresDevice
import com.android.wm.shell.flicker.utils.SplitScreenUtils
+import org.junit.After
import org.junit.Assume
import org.junit.Before
import org.junit.FixMethodOrder
@@ -44,6 +45,7 @@
primaryApp.launchViaIntent(wmHelper)
}
transitions {
+ tapl.showTaskbarIfHidden()
tapl.launchedAppState.taskbar
.getAppIcon(secondaryApp.appName)
.dragToSplitscreen(secondaryApp.packageName, primaryApp.packageName)
@@ -54,6 +56,12 @@
@Before
fun before() {
Assume.assumeTrue(tapl.isTablet)
+ tapl.enableBlockTimeout(true)
+ }
+
+ @After
+ fun after() {
+ tapl.enableBlockTimeout(false)
}
companion object {
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubblePositionerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubblePositionerTest.java
index e5ae6e5..6ebee73 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubblePositionerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubblePositionerTest.java
@@ -332,6 +332,201 @@
.isWithin(0.1f).of(expectedHeight);
}
+ @Test
+ public void testAreBubblesBottomAligned_largeScreen_true() {
+ Insets insets = Insets.of(10, 20, 5, 15);
+ Rect screenBounds = new Rect(0, 0, 1800, 2600);
+
+ DeviceConfig deviceConfig = new ConfigBuilder()
+ .setLargeScreen()
+ .setInsets(insets)
+ .setScreenBounds(screenBounds)
+ .build();
+ mPositioner.update(deviceConfig);
+
+ assertThat(mPositioner.areBubblesBottomAligned()).isTrue();
+ }
+
+ @Test
+ public void testAreBubblesBottomAligned_largeScreen_false() {
+ Insets insets = Insets.of(10, 20, 5, 15);
+ Rect screenBounds = new Rect(0, 0, 1800, 2600);
+
+ DeviceConfig deviceConfig = new ConfigBuilder()
+ .setLargeScreen()
+ .setLandscape()
+ .setInsets(insets)
+ .setScreenBounds(screenBounds)
+ .build();
+ mPositioner.update(deviceConfig);
+
+ assertThat(mPositioner.areBubblesBottomAligned()).isFalse();
+ }
+
+ @Test
+ public void testAreBubblesBottomAligned_smallTablet_false() {
+ Insets insets = Insets.of(10, 20, 5, 15);
+ Rect screenBounds = new Rect(0, 0, 1800, 2600);
+
+ DeviceConfig deviceConfig = new ConfigBuilder()
+ .setLargeScreen()
+ .setSmallTablet()
+ .setInsets(insets)
+ .setScreenBounds(screenBounds)
+ .build();
+ mPositioner.update(deviceConfig);
+
+ assertThat(mPositioner.areBubblesBottomAligned()).isFalse();
+ }
+
+ @Test
+ public void testAreBubblesBottomAligned_phone_false() {
+ Insets insets = Insets.of(10, 20, 5, 15);
+ Rect screenBounds = new Rect(0, 0, 1800, 2600);
+
+ DeviceConfig deviceConfig = new ConfigBuilder()
+ .setInsets(insets)
+ .setScreenBounds(screenBounds)
+ .build();
+ mPositioner.update(deviceConfig);
+
+ assertThat(mPositioner.areBubblesBottomAligned()).isFalse();
+ }
+
+ @Test
+ public void testExpandedViewY_phoneLandscape() {
+ Insets insets = Insets.of(10, 20, 5, 15);
+ Rect screenBounds = new Rect(0, 0, 1800, 2600);
+
+ DeviceConfig deviceConfig = new ConfigBuilder()
+ .setLandscape()
+ .setInsets(insets)
+ .setScreenBounds(screenBounds)
+ .build();
+ mPositioner.update(deviceConfig);
+
+ Intent intent = new Intent(Intent.ACTION_VIEW).setPackage(mContext.getPackageName());
+ Bubble bubble = Bubble.createAppBubble(intent, new UserHandle(1), null, directExecutor());
+
+ // This bubble will have max height so it'll always be top aligned
+ assertThat(mPositioner.getExpandedViewY(bubble, 0f /* bubblePosition */))
+ .isEqualTo(mPositioner.getExpandedViewYTopAligned());
+ }
+
+ @Test
+ public void testExpandedViewY_phonePortrait() {
+ Insets insets = Insets.of(10, 20, 5, 15);
+ Rect screenBounds = new Rect(0, 0, 1800, 2600);
+
+ DeviceConfig deviceConfig = new ConfigBuilder()
+ .setInsets(insets)
+ .setScreenBounds(screenBounds)
+ .build();
+ mPositioner.update(deviceConfig);
+
+ Intent intent = new Intent(Intent.ACTION_VIEW).setPackage(mContext.getPackageName());
+ Bubble bubble = Bubble.createAppBubble(intent, new UserHandle(1), null, directExecutor());
+
+ // Always top aligned in phone portrait
+ assertThat(mPositioner.getExpandedViewY(bubble, 0f /* bubblePosition */))
+ .isEqualTo(mPositioner.getExpandedViewYTopAligned());
+ }
+
+ @Test
+ public void testExpandedViewY_smallTabletLandscape() {
+ Insets insets = Insets.of(10, 20, 5, 15);
+ Rect screenBounds = new Rect(0, 0, 1800, 2600);
+
+ DeviceConfig deviceConfig = new ConfigBuilder()
+ .setSmallTablet()
+ .setLandscape()
+ .setInsets(insets)
+ .setScreenBounds(screenBounds)
+ .build();
+ mPositioner.update(deviceConfig);
+
+ Intent intent = new Intent(Intent.ACTION_VIEW).setPackage(mContext.getPackageName());
+ Bubble bubble = Bubble.createAppBubble(intent, new UserHandle(1), null, directExecutor());
+
+ // This bubble will have max height which is always top aligned on small tablets
+ assertThat(mPositioner.getExpandedViewY(bubble, 0f /* bubblePosition */))
+ .isEqualTo(mPositioner.getExpandedViewYTopAligned());
+ }
+
+ @Test
+ public void testExpandedViewY_smallTabletPortrait() {
+ Insets insets = Insets.of(10, 20, 5, 15);
+ Rect screenBounds = new Rect(0, 0, 1800, 2600);
+
+ DeviceConfig deviceConfig = new ConfigBuilder()
+ .setSmallTablet()
+ .setInsets(insets)
+ .setScreenBounds(screenBounds)
+ .build();
+ mPositioner.update(deviceConfig);
+
+ Intent intent = new Intent(Intent.ACTION_VIEW).setPackage(mContext.getPackageName());
+ Bubble bubble = Bubble.createAppBubble(intent, new UserHandle(1), null, directExecutor());
+
+ // This bubble will have max height which is always top aligned on small tablets
+ assertThat(mPositioner.getExpandedViewY(bubble, 0f /* bubblePosition */))
+ .isEqualTo(mPositioner.getExpandedViewYTopAligned());
+ }
+
+ @Test
+ public void testExpandedViewY_largeScreenLandscape() {
+ Insets insets = Insets.of(10, 20, 5, 15);
+ Rect screenBounds = new Rect(0, 0, 1800, 2600);
+
+ DeviceConfig deviceConfig = new ConfigBuilder()
+ .setLargeScreen()
+ .setLandscape()
+ .setInsets(insets)
+ .setScreenBounds(screenBounds)
+ .build();
+ mPositioner.update(deviceConfig);
+
+ Intent intent = new Intent(Intent.ACTION_VIEW).setPackage(mContext.getPackageName());
+ Bubble bubble = Bubble.createAppBubble(intent, new UserHandle(1), null, directExecutor());
+
+ // This bubble will have max height which is always top aligned on landscape, large tablet
+ assertThat(mPositioner.getExpandedViewY(bubble, 0f /* bubblePosition */))
+ .isEqualTo(mPositioner.getExpandedViewYTopAligned());
+ }
+
+ @Test
+ public void testExpandedViewY_largeScreenPortrait() {
+ Insets insets = Insets.of(10, 20, 5, 15);
+ Rect screenBounds = new Rect(0, 0, 1800, 2600);
+
+ DeviceConfig deviceConfig = new ConfigBuilder()
+ .setLargeScreen()
+ .setInsets(insets)
+ .setScreenBounds(screenBounds)
+ .build();
+ mPositioner.update(deviceConfig);
+
+ Intent intent = new Intent(Intent.ACTION_VIEW).setPackage(mContext.getPackageName());
+ Bubble bubble = Bubble.createAppBubble(intent, new UserHandle(1), null, directExecutor());
+
+ int manageButtonHeight =
+ mContext.getResources().getDimensionPixelSize(R.dimen.bubble_manage_button_height);
+ int manageButtonPlusMargin = manageButtonHeight + 2
+ * mContext.getResources().getDimensionPixelSize(
+ R.dimen.bubble_manage_button_margin);
+ int pointerWidth = mContext.getResources().getDimensionPixelSize(
+ R.dimen.bubble_pointer_width);
+
+ final float expectedExpandedViewY = mPositioner.getAvailableRect().bottom
+ - manageButtonPlusMargin
+ - mPositioner.getExpandedViewHeightForLargeScreen()
+ - pointerWidth;
+
+ // Bubbles are bottom aligned on portrait, large tablet
+ assertThat(mPositioner.getExpandedViewY(bubble, 0f /* bubblePosition */))
+ .isEqualTo(expectedExpandedViewY);
+ }
+
/**
* Calculates the Y position bubbles should be placed based on the config. Based on
* the calculations in {@link BubblePositioner#getDefaultStartPosition()} and
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/animation/ExpandedAnimationControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/animation/ExpandedAnimationControllerTest.java
index 6403e79..c1ff260 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/animation/ExpandedAnimationControllerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/animation/ExpandedAnimationControllerTest.java
@@ -106,7 +106,7 @@
verify(afterExpand).run();
Runnable afterCollapse = mock(Runnable.class);
- mExpandedController.collapseBackToStack(mExpansionPoint, afterCollapse);
+ mExpandedController.collapseBackToStack(mExpansionPoint, false, afterCollapse);
waitForPropertyAnimations(DynamicAnimation.TRANSLATION_X, DynamicAnimation.TRANSLATION_Y);
testStackedAtPosition(mExpansionPoint.x, mExpansionPoint.y, -1);
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/HomeTransitionObserverTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/HomeTransitionObserverTest.java
index 421c445..50802c3 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/HomeTransitionObserverTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/HomeTransitionObserverTest.java
@@ -101,7 +101,7 @@
when(change.getTaskInfo()).thenReturn(taskInfo);
when(info.getChanges()).thenReturn(new ArrayList<>(List.of(change)));
- setupTransitionInfo(taskInfo, change, ACTIVITY_TYPE_HOME, TRANSIT_OPEN);
+ setupTransitionInfo(taskInfo, change, ACTIVITY_TYPE_HOME, TRANSIT_OPEN, true);
mHomeTransitionObserver.onTransitionReady(mock(IBinder.class),
info,
@@ -119,7 +119,7 @@
when(change.getTaskInfo()).thenReturn(taskInfo);
when(info.getChanges()).thenReturn(new ArrayList<>(List.of(change)));
- setupTransitionInfo(taskInfo, change, ACTIVITY_TYPE_HOME, TRANSIT_TO_BACK);
+ setupTransitionInfo(taskInfo, change, ACTIVITY_TYPE_HOME, TRANSIT_TO_BACK, true);
mHomeTransitionObserver.onTransitionReady(mock(IBinder.class),
info,
@@ -137,7 +137,25 @@
when(change.getTaskInfo()).thenReturn(taskInfo);
when(info.getChanges()).thenReturn(new ArrayList<>(List.of(change)));
- setupTransitionInfo(taskInfo, change, ACTIVITY_TYPE_UNDEFINED, TRANSIT_TO_BACK);
+ setupTransitionInfo(taskInfo, change, ACTIVITY_TYPE_UNDEFINED, TRANSIT_TO_BACK, true);
+
+ mHomeTransitionObserver.onTransitionReady(mock(IBinder.class),
+ info,
+ mock(SurfaceControl.Transaction.class),
+ mock(SurfaceControl.Transaction.class));
+
+ verify(mListener, times(0)).onHomeVisibilityChanged(anyBoolean());
+ }
+
+ @Test
+ public void testNonRunningHomeActivityDoesNotTriggerCallback() throws RemoteException {
+ TransitionInfo info = mock(TransitionInfo.class);
+ TransitionInfo.Change change = mock(TransitionInfo.Change.class);
+ ActivityManager.RunningTaskInfo taskInfo = mock(ActivityManager.RunningTaskInfo.class);
+ when(change.getTaskInfo()).thenReturn(taskInfo);
+ when(info.getChanges()).thenReturn(new ArrayList<>(List.of(change)));
+
+ setupTransitionInfo(taskInfo, change, ACTIVITY_TYPE_UNDEFINED, TRANSIT_TO_BACK, false);
mHomeTransitionObserver.onTransitionReady(mock(IBinder.class),
info,
@@ -156,7 +174,7 @@
when(info.getChanges()).thenReturn(new ArrayList<>(List.of(change)));
when(change.hasFlags(FLAG_BACK_GESTURE_ANIMATED)).thenReturn(true);
- setupTransitionInfo(taskInfo, change, ACTIVITY_TYPE_HOME, TRANSIT_CHANGE);
+ setupTransitionInfo(taskInfo, change, ACTIVITY_TYPE_HOME, TRANSIT_CHANGE, true);
mHomeTransitionObserver.onTransitionReady(mock(IBinder.class),
info,
@@ -166,16 +184,16 @@
verify(mListener, times(1)).onHomeVisibilityChanged(true);
}
-
/**
* Helper class to initialize variables for the rest.
*/
private void setupTransitionInfo(ActivityManager.RunningTaskInfo taskInfo,
TransitionInfo.Change change,
@ActivityType int activityType,
- @TransitionMode int mode) {
+ @TransitionMode int mode,
+ boolean isRunning) {
when(taskInfo.getActivityType()).thenReturn(activityType);
when(change.getMode()).thenReturn(mode);
+ taskInfo.isRunning = isRunning;
}
-
}
diff --git a/libs/androidfw/FileStream.cpp b/libs/androidfw/FileStream.cpp
index b86c9cb..e898949 100644
--- a/libs/androidfw/FileStream.cpp
+++ b/libs/androidfw/FileStream.cpp
@@ -22,6 +22,7 @@
#include "android-base/errors.h"
#include "android-base/file.h" // for O_BINARY
+#include "android-base/logging.h"
#include "android-base/macros.h"
#include "android-base/utf8.h"
@@ -37,9 +38,9 @@
namespace android {
FileInputStream::FileInputStream(const std::string& path, size_t buffer_capacity)
- : buffer_capacity_(buffer_capacity) {
+ : should_close_(true), buffer_capacity_(buffer_capacity) {
int mode = O_RDONLY | O_CLOEXEC | O_BINARY;
- fd_.reset(TEMP_FAILURE_RETRY(::android::base::utf8::open(path.c_str(), mode)));
+ fd_ = TEMP_FAILURE_RETRY(::android::base::utf8::open(path.c_str(), mode));
if (fd_ == -1) {
error_ = SystemErrorCodeToString(errno);
} else {
@@ -48,7 +49,7 @@
}
FileInputStream::FileInputStream(int fd, size_t buffer_capacity)
- : fd_(fd), buffer_capacity_(buffer_capacity) {
+ : fd_(fd), should_close_(true), buffer_capacity_(buffer_capacity) {
if (fd_ < 0) {
error_ = "Bad File Descriptor";
} else {
@@ -56,6 +57,17 @@
}
}
+FileInputStream::FileInputStream(android::base::borrowed_fd fd, size_t buffer_capacity)
+ : fd_(fd.get()), should_close_(false), buffer_capacity_(buffer_capacity) {
+
+ if (fd_ < 0) {
+ error_ = "Bad File Descriptor";
+ } else {
+ buffer_.reset(new uint8_t[buffer_capacity_]);
+ }
+}
+
+
bool FileInputStream::Next(const void** data, size_t* size) {
if (HadError()) {
return false;
@@ -73,7 +85,12 @@
ssize_t n = TEMP_FAILURE_RETRY(read(fd_, buffer_.get(), buffer_capacity_));
if (n < 0) {
error_ = SystemErrorCodeToString(errno);
- fd_.reset();
+ if (fd_ != -1) {
+ if (should_close_) {
+ close(fd_);
+ }
+ fd_ = -1;
+ }
buffer_.reset();
return false;
}
diff --git a/libs/androidfw/include/androidfw/BigBufferStream.h b/libs/androidfw/include/androidfw/BigBufferStream.h
index e55fe0d..c23194b 100644
--- a/libs/androidfw/include/androidfw/BigBufferStream.h
+++ b/libs/androidfw/include/androidfw/BigBufferStream.h
@@ -24,8 +24,13 @@
class BigBufferInputStream : public KnownSizeInputStream {
public:
inline explicit BigBufferInputStream(const BigBuffer* buffer)
- : buffer_(buffer), iter_(buffer->begin()) {
+ : owning_buffer_(0), buffer_(buffer), iter_(buffer->begin()) {
}
+
+ inline explicit BigBufferInputStream(android::BigBuffer&& buffer)
+ : owning_buffer_(std::move(buffer)), buffer_(&owning_buffer_), iter_(buffer_->begin()) {
+ }
+
virtual ~BigBufferInputStream() = default;
bool Next(const void** data, size_t* size) override;
@@ -47,6 +52,7 @@
private:
DISALLOW_COPY_AND_ASSIGN(BigBufferInputStream);
+ android::BigBuffer owning_buffer_;
const BigBuffer* buffer_;
BigBuffer::const_iterator iter_;
size_t offset_ = 0;
diff --git a/libs/androidfw/include/androidfw/FileStream.h b/libs/androidfw/include/androidfw/FileStream.h
index fb84a91..87c42d1 100644
--- a/libs/androidfw/include/androidfw/FileStream.h
+++ b/libs/androidfw/include/androidfw/FileStream.h
@@ -18,6 +18,7 @@
#include <memory>
#include <string>
+#include <unistd.h>
#include "Streams.h"
#include "android-base/macros.h"
@@ -35,6 +36,16 @@
// Take ownership of `fd`.
explicit FileInputStream(int fd, size_t buffer_capacity = kDefaultBufferCapacity);
+ // Take ownership of `fd`.
+ explicit FileInputStream(android::base::borrowed_fd fd,
+ size_t buffer_capacity = kDefaultBufferCapacity);
+
+ ~FileInputStream() {
+ if (should_close_ && (fd_ != -1)) {
+ close(fd_);
+ }
+ }
+
bool Next(const void** data, size_t* size) override;
void BackUp(size_t count) override;
@@ -50,8 +61,9 @@
private:
DISALLOW_COPY_AND_ASSIGN(FileInputStream);
- android::base::unique_fd fd_;
+ int fd_ = -1;
std::string error_;
+ bool should_close_;
std::unique_ptr<uint8_t[]> buffer_;
size_t buffer_capacity_ = 0u;
size_t buffer_offset_ = 0u;
diff --git a/libs/androidfw/include/androidfw/IDiagnostics.h b/libs/androidfw/include/androidfw/IDiagnostics.h
index 865a298..d1dda81 100644
--- a/libs/androidfw/include/androidfw/IDiagnostics.h
+++ b/libs/androidfw/include/androidfw/IDiagnostics.h
@@ -17,10 +17,15 @@
#ifndef _ANDROID_DIAGNOSTICS_H
#define _ANDROID_DIAGNOSTICS_H
+// on some systems ERROR is defined as 0 so android::base::ERROR becomes android::base::0
+// which doesn't compile. We undef it here to avoid that and because we don't ever need that def.
+#undef ERROR
+
#include <sstream>
#include <string>
#include "Source.h"
+#include "android-base/logging.h"
#include "android-base/macros.h"
#include "androidfw/StringPiece.h"
@@ -144,6 +149,36 @@
DISALLOW_COPY_AND_ASSIGN(NoOpDiagnostics);
};
+class AndroidLogDiagnostics : public IDiagnostics {
+ public:
+ AndroidLogDiagnostics() = default;
+
+ void Log(Level level, DiagMessageActual& actual_msg) override {
+ android::base::LogSeverity severity;
+ switch (level) {
+ case Level::Error:
+ severity = android::base::ERROR;
+ break;
+
+ case Level::Warn:
+ severity = android::base::WARNING;
+ break;
+
+ case Level::Note:
+ severity = android::base::INFO;
+ break;
+ }
+ if (!actual_msg.source.path.empty()) {
+ LOG(severity) << actual_msg.source << ": " + actual_msg.message;
+ } else {
+ LOG(severity) << actual_msg.message;
+ }
+ }
+
+ DISALLOW_COPY_AND_ASSIGN(AndroidLogDiagnostics);
+};
+
+
} // namespace android
#endif /* _ANDROID_DIAGNOSTICS_H */
diff --git a/libs/androidfw/include/androidfw/ResourceTypes.h b/libs/androidfw/include/androidfw/ResourceTypes.h
index fdb3551..c0514fd 100644
--- a/libs/androidfw/include/androidfw/ResourceTypes.h
+++ b/libs/androidfw/include/androidfw/ResourceTypes.h
@@ -1875,6 +1875,7 @@
off64_t binary_data_offset;
size_t binary_data_size;
std::string configuration;
+ bool nine_patch;
};
class AssetManager2;
diff --git a/libs/hwui/aconfig/hwui_flags.aconfig b/libs/hwui/aconfig/hwui_flags.aconfig
index 78a6479..ca11975 100644
--- a/libs/hwui/aconfig/hwui_flags.aconfig
+++ b/libs/hwui/aconfig/hwui_flags.aconfig
@@ -1,6 +1,13 @@
package: "com.android.graphics.hwui.flags"
flag {
+ name: "matrix_44"
+ namespace: "core_graphics"
+ description: "API for 4x4 matrix and related canvas functions"
+ bug: "280116960"
+}
+
+flag {
name: "limited_hdr"
namespace: "core_graphics"
description: "API to enable apps to restrict the amount of HDR headroom that is used"
@@ -41,3 +48,10 @@
description: "Enable r_8, r_16_uint, rg_1616_uint, and rgba_10101010 in the SDK"
bug: "292545615"
}
+
+flag {
+ name: "animate_hdr_transitions"
+ namespace: "core_graphics"
+ description: "Automatically animate all changes in HDR headroom"
+ bug: "314810174"
+}
diff --git a/media/java/android/media/IMediaRouterService.aidl b/media/java/android/media/IMediaRouterService.aidl
index 4a5b4f2..fa4d1a1 100644
--- a/media/java/android/media/IMediaRouterService.aidl
+++ b/media/java/android/media/IMediaRouterService.aidl
@@ -26,6 +26,7 @@
import android.media.RouteListingPreference;
import android.media.RoutingSessionInfo;
import android.os.Bundle;
+import android.os.UserHandle;
/**
* {@hide}
@@ -50,7 +51,6 @@
// MediaRouterService.java for readability.
// Methods for MediaRouter2
- boolean verifyPackageExists(String clientPackageName);
List<MediaRoute2Info> getSystemRoutes();
RoutingSessionInfo getSystemSessionInfo();
@@ -76,6 +76,7 @@
List<RoutingSessionInfo> getRemoteSessions(IMediaRouter2Manager manager);
RoutingSessionInfo getSystemSessionInfoForPackage(String packageName);
void registerManager(IMediaRouter2Manager manager, String packageName);
+ void registerProxyRouter(IMediaRouter2Manager manager, String callingPackageName, String targetPackageName, in UserHandle targetUser);
void unregisterManager(IMediaRouter2Manager manager);
void setRouteVolumeWithManager(IMediaRouter2Manager manager, int requestId,
in MediaRoute2Info route, int volume);
diff --git a/media/java/android/media/MediaRouter2.java b/media/java/android/media/MediaRouter2.java
index bde0c0c..ba26df9 100644
--- a/media/java/android/media/MediaRouter2.java
+++ b/media/java/android/media/MediaRouter2.java
@@ -18,6 +18,7 @@
import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage;
import static com.android.media.flags.Flags.FLAG_ENABLE_RLP_CALLBACKS_IN_MEDIA_ROUTER2;
+import static com.android.media.flags.Flags.FLAG_ENABLE_CROSS_USER_ROUTING_IN_MEDIA_ROUTER2;
import android.Manifest;
import android.annotation.CallbackExecutor;
@@ -32,8 +33,10 @@
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
+import android.os.Process;
import android.os.RemoteException;
import android.os.ServiceManager;
+import android.os.UserHandle;
import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.ArraySet;
@@ -78,8 +81,11 @@
// The manager request ID representing that no manager is involved.
private static final long MANAGER_REQUEST_ID_NONE = MediaRoute2ProviderService.REQUEST_ID_NONE;
+ private record PackageNameUserHandlePair(String packageName, UserHandle user) {}
+
@GuardedBy("sSystemRouterLock")
- private static final Map<String, MediaRouter2> sSystemMediaRouter2Map = new ArrayMap<>();
+ private static final Map<PackageNameUserHandlePair, MediaRouter2> sAppToProxyRouterMap =
+ new ArrayMap<>();
@GuardedBy("sRouterLock")
private static MediaRouter2 sInstance;
@@ -161,66 +167,121 @@
}
/**
- * Gets an instance of the system media router which controls the app's media routing. Returns
- * {@code null} if the given package name is invalid. There are several things to note when
- * using the media routers created with this method.
+ * Returns a proxy MediaRouter2 instance that allows you to control the routing of an app
+ * specified by {@code clientPackageName}. Returns {@code null} if the specified package name
+ * does not exist.
*
- * <p>First of all, the discovery preference passed to {@link #registerRouteCallback} will have
- * no effect. The callback will be called accordingly with the client app's discovery
- * preference. Therefore, it is recommended to pass {@link RouteDiscoveryPreference#EMPTY}
- * there.
- *
- * <p>Also, do not keep/compare the instances of the {@link RoutingController}, since they are
- * always newly created with the latest session information whenever below methods are called:
+ * <p>Proxy MediaRouter2 instances operate differently than regular MediaRouter2 instances:
*
* <ul>
- * <li>{@link #getControllers()}
- * <li>{@link #getController(String)}
- * <li>{@link TransferCallback#onTransfer(RoutingController, RoutingController)}
- * <li>{@link TransferCallback#onStop(RoutingController)}
- * <li>{@link ControllerCallback#onControllerUpdated(RoutingController)}
+ * <li>
+ * <p>{@link #registerRouteCallback} ignores any {@link RouteDiscoveryPreference discovery
+ * preference} passed by a proxy router. Use {@link RouteDiscoveryPreference#EMPTY} when
+ * setting a route callback.
+ * <li>
+ * <p>Methods returning non-system {@link RoutingController controllers} always return
+ * new instances with the latest data. Do not attempt to compare or store them. Instead,
+ * use {@link #getController(String)} or {@link #getControllers()} to query the most
+ * up-to-date state.
+ * <li>
+ * <p>Calls to {@link #setOnGetControllerHintsListener} are ignored.
* </ul>
*
- * Therefore, in order to track the current routing status, keep the controller's ID instead,
- * and use {@link #getController(String)} and {@link #getSystemController()} for getting
- * controllers.
- *
- * <p>Finally, it will have no effect to call {@link #setOnGetControllerHintsListener}.
- *
* @param clientPackageName the package name of the app to control
* @throws SecurityException if the caller doesn't have {@link
* Manifest.permission#MEDIA_CONTENT_CONTROL MEDIA_CONTENT_CONTROL} permission.
* @hide
*/
+ // TODO (b/311711420): Deprecate once #getInstance(Context, Looper, String, UserHandle)
+ // reaches public SDK.
@SystemApi
@RequiresPermission(Manifest.permission.MEDIA_CONTENT_CONTROL)
@Nullable
public static MediaRouter2 getInstance(
@NonNull Context context, @NonNull String clientPackageName) {
- Objects.requireNonNull(context, "context must not be null");
- Objects.requireNonNull(clientPackageName, "clientPackageName must not be null");
-
- // Note: Even though this check could be somehow bypassed, the other permission checks
- // in system server will not allow MediaRouter2Manager to be registered.
- IMediaRouterService serviceBinder =
- IMediaRouterService.Stub.asInterface(
- ServiceManager.getService(Context.MEDIA_ROUTER_SERVICE));
+ // Capturing the IAE here to not break nullability.
try {
- // verifyPackageExists throws SecurityException if the caller doesn't hold
- // MEDIA_CONTENT_CONTROL permission.
- if (!serviceBinder.verifyPackageExists(clientPackageName)) {
- Log.e(TAG, "Package " + clientPackageName + " not found. Ignoring.");
- return null;
- }
- } catch (RemoteException e) {
- e.rethrowFromSystemServer();
+ return findOrCreateProxyInstanceForCallingUser(
+ context, Looper.getMainLooper(), clientPackageName, context.getUser());
+ } catch (IllegalArgumentException ex) {
+ Log.e(TAG, "Package " + clientPackageName + " not found. Ignoring.");
+ return null;
+ }
+ }
+
+ /**
+ * Returns a proxy MediaRouter2 instance that allows you to control the routing of an app
+ * specified by {@code clientPackageName} and {@code user}.
+ *
+ * <p>You can specify any {@link Looper} of choice on which internal state updates will run.
+ *
+ * <p>Proxy MediaRouter2 instances operate differently than regular MediaRouter2 instances:
+ *
+ * <ul>
+ * <li>
+ * <p>{@link #registerRouteCallback} ignores any {@link RouteDiscoveryPreference discovery
+ * preference} passed by a proxy router. Use a {@link RouteDiscoveryPreference} with empty
+ * {@link RouteDiscoveryPreference.Builder#setPreferredFeatures(List) preferred features}
+ * when setting a route callback.
+ * <li>
+ * <p>Methods returning non-system {@link RoutingController controllers} always return
+ * new instances with the latest data. Do not attempt to compare or store them. Instead,
+ * use {@link #getController(String)} or {@link #getControllers()} to query the most
+ * up-to-date state.
+ * <li>
+ * <p>Calls to {@link #setOnGetControllerHintsListener} are ignored.
+ * </ul>
+ *
+ * @param context The {@link Context} of the caller.
+ * @param looper The {@link Looper} on which to process internal state changes.
+ * @param clientPackageName The package name of the app you want to control the routing of.
+ * @param user The {@link UserHandle} of the user running the app for which to get the proxy
+ * router instance. Must match {@link Process#myUserHandle()} if the caller doesn't hold
+ * {@code Manifest.permission#INTERACT_ACROSS_USERS_FULL}.
+ * @throws SecurityException if {@code user} does not match {@link Process#myUserHandle()} and
+ * the caller does not hold {@code Manifest.permission#INTERACT_ACROSS_USERS_FULL}.
+ * @throws IllegalArgumentException if {@code clientPackageName} does not exist in {@code user}.
+ */
+ @FlaggedApi(FLAG_ENABLE_CROSS_USER_ROUTING_IN_MEDIA_ROUTER2)
+ @RequiresPermission(
+ anyOf = {
+ Manifest.permission.MEDIA_CONTENT_CONTROL,
+ Manifest.permission.MEDIA_ROUTING_CONTROL
+ })
+ @NonNull
+ public static MediaRouter2 getInstance(
+ @NonNull Context context,
+ @NonNull Looper looper,
+ @NonNull String clientPackageName,
+ @NonNull UserHandle user) {
+ return findOrCreateProxyInstanceForCallingUser(context, looper, clientPackageName, user);
+ }
+
+ /**
+ * Returns the per-process singleton proxy router instance for the {@code clientPackageName} and
+ * {@code user} if it exists, or otherwise it creates the appropriate instance.
+ *
+ * <p>If no instance has been created previously, the method will create an instance via {@link
+ * #MediaRouter2(Context, Looper, String, UserHandle)}.
+ */
+ @NonNull
+ private static MediaRouter2 findOrCreateProxyInstanceForCallingUser(
+ Context context, Looper looper, String clientPackageName, UserHandle user) {
+ Objects.requireNonNull(context, "context must not be null");
+ Objects.requireNonNull(looper, "looper must not be null");
+ Objects.requireNonNull(user, "user must not be null");
+
+ if (TextUtils.isEmpty(clientPackageName)) {
+ throw new IllegalArgumentException("clientPackageName must not be null or empty");
}
+ PackageNameUserHandlePair key = new PackageNameUserHandlePair(clientPackageName, user);
+
synchronized (sSystemRouterLock) {
- MediaRouter2 instance = sSystemMediaRouter2Map.get(clientPackageName);
+ MediaRouter2 instance = sAppToProxyRouterMap.get(key);
if (instance == null) {
- instance = new MediaRouter2(context, clientPackageName);
- sSystemMediaRouter2Map.put(clientPackageName, instance);
+ instance = new MediaRouter2(context, looper, clientPackageName, user);
+ sAppToProxyRouterMap.put(key, instance);
}
return instance;
}
@@ -304,9 +365,10 @@
mSystemController = new SystemRoutingController(currentSystemSessionInfo);
}
- private MediaRouter2(Context context, String clientPackageName) {
+ private MediaRouter2(
+ Context context, Looper looper, String clientPackageName, UserHandle user) {
mContext = context;
- mHandler = new Handler(Looper.getMainLooper());
+ mHandler = new Handler(looper);
mMediaRouterService =
IMediaRouterService.Stub.asInterface(
ServiceManager.getService(Context.MEDIA_ROUTER_SERVICE));
@@ -315,7 +377,7 @@
new SystemRoutingController(
ProxyMediaRouter2Impl.getSystemSessionInfoImpl(
mMediaRouterService, clientPackageName));
- mImpl = new ProxyMediaRouter2Impl(context, clientPackageName);
+ mImpl = new ProxyMediaRouter2Impl(context, clientPackageName, user);
}
/**
@@ -2000,25 +2062,30 @@
*/
private class ProxyMediaRouter2Impl implements MediaRouter2Impl {
// Fields originating from MediaRouter2Manager.
- private final MediaRouter2Manager mManager;
private final IMediaRouter2Manager.Stub mClient;
private final CopyOnWriteArrayList<MediaRouter2Manager.TransferRequest>
mTransferRequests = new CopyOnWriteArrayList<>();
+ private final AtomicInteger mScanRequestCount = new AtomicInteger(/* initialValue= */ 0);
// Fields originating from MediaRouter2.
@NonNull private final String mClientPackageName;
-
- // TODO(b/281072508): Implement scan request counting when MediaRouter2Manager is removed.
+ @NonNull private final UserHandle mClientUser;
private final AtomicBoolean mIsScanning = new AtomicBoolean(/* initialValue= */ false);
- ProxyMediaRouter2Impl(@NonNull Context context, @NonNull String clientPackageName) {
- mManager = MediaRouter2Manager.getInstance(context.getApplicationContext());
+ ProxyMediaRouter2Impl(
+ @NonNull Context context,
+ @NonNull String clientPackageName,
+ @NonNull UserHandle user) {
+ mClientUser = user;
mClientPackageName = clientPackageName;
mClient = new Client();
try {
- mMediaRouterService.registerManager(
- mClient, context.getApplicationContext().getPackageName());
+ mMediaRouterService.registerProxyRouter(
+ mClient,
+ context.getApplicationContext().getPackageName(),
+ clientPackageName,
+ user);
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}
@@ -2029,14 +2096,35 @@
@Override
public void startScan() {
if (!mIsScanning.getAndSet(true)) {
- mManager.registerScanRequest();
+ if (mScanRequestCount.getAndIncrement() == 0) {
+ try {
+ mMediaRouterService.startScan(mClient);
+ } catch (RemoteException ex) {
+ throw ex.rethrowFromSystemServer();
+ }
+ }
}
}
@Override
public void stopScan() {
if (mIsScanning.getAndSet(false)) {
- mManager.unregisterScanRequest();
+ if (mScanRequestCount.updateAndGet(
+ count -> {
+ if (count == 0) {
+ throw new IllegalStateException(
+ "No active scan requests to unregister.");
+ } else {
+ return --count;
+ }
+ })
+ == 0) {
+ try {
+ mMediaRouterService.stopScan(mClient);
+ } catch (RemoteException ex) {
+ throw ex.rethrowFromSystemServer();
+ }
+ }
}
}
diff --git a/media/java/android/media/flags/media_better_together.aconfig b/media/java/android/media/flags/media_better_together.aconfig
index 283d61b..3c0b002 100644
--- a/media/java/android/media/flags/media_better_together.aconfig
+++ b/media/java/android/media/flags/media_better_together.aconfig
@@ -55,3 +55,10 @@
description: "Allow access to privileged routing capabilities to MEDIA_ROUTING_CONTROL holders."
bug: "305919655"
}
+
+flag {
+ name: "enable_cross_user_routing_in_media_router2"
+ namespace: "media_solutions"
+ description: "Allows clients of privileged MediaRouter2 that hold INTERACT_ACROSS_USERS_FULL to control routing across users."
+ bug: "288580225"
+}
diff --git a/packages/CompanionDeviceManager/res/drawable-night/ic_permission_media_routing_control.xml b/packages/CompanionDeviceManager/res/drawable-night/ic_permission_media_routing_control.xml
new file mode 100644
index 0000000..a0426a3
--- /dev/null
+++ b/packages/CompanionDeviceManager/res/drawable-night/ic_permission_media_routing_control.xml
@@ -0,0 +1,25 @@
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="960"
+ android:viewportHeight="960"
+ android:tint="@android:color/system_accent1_200">
+ <path android:fillColor="@android:color/system_accent1_200"
+ android:pathData="M360,840L200,840Q167,840 143.5,816.5Q120,793 120,760L120,480Q120,405 148.5,339.5Q177,274 225.5,225.5Q274,177 339.5,148.5Q405,120 480,120Q555,120 620.5,148.5Q686,177 734.5,225.5Q783,274 811.5,339.5Q840,405 840,480L840,760Q840,793 816.5,816.5Q793,840 760,840L600,840L600,520L760,520L760,480Q760,363 678.5,281.5Q597,200 480,200Q363,200 281.5,281.5Q200,363 200,480L200,520L360,520L360,840ZM280,600L200,600L200,760Q200,760 200,760Q200,760 200,760L280,760L280,600ZM680,600L680,760L760,760Q760,760 760,760Q760,760 760,760L760,600L680,600ZM280,600L280,600L200,600Q200,600 200,600Q200,600 200,600L200,600L280,600ZM680,600L760,600L760,600Q760,600 760,600Q760,600 760,600L680,600L680,600Z"/>
+</vector>
\ No newline at end of file
diff --git a/packages/CompanionDeviceManager/res/drawable/ic_permission_media_routing_control.xml b/packages/CompanionDeviceManager/res/drawable/ic_permission_media_routing_control.xml
new file mode 100644
index 0000000..9a7525b
--- /dev/null
+++ b/packages/CompanionDeviceManager/res/drawable/ic_permission_media_routing_control.xml
@@ -0,0 +1,25 @@
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="960"
+ android:viewportHeight="960"
+ android:tint="?attr/colorControlNormal">
+ <path android:fillColor="@android:color/system_accent1_600"
+ android:pathData="M360,840L200,840Q167,840 143.5,816.5Q120,793 120,760L120,480Q120,405 148.5,339.5Q177,274 225.5,225.5Q274,177 339.5,148.5Q405,120 480,120Q555,120 620.5,148.5Q686,177 734.5,225.5Q783,274 811.5,339.5Q840,405 840,480L840,760Q840,793 816.5,816.5Q793,840 760,840L600,840L600,520L760,520L760,480Q760,363 678.5,281.5Q597,200 480,200Q363,200 281.5,281.5Q200,363 200,480L200,520L360,520L360,840ZM280,600L200,600L200,760Q200,760 200,760Q200,760 200,760L280,760L280,600ZM680,600L680,760L760,760Q760,760 760,760Q760,760 760,760L760,600L680,600ZM280,600L280,600L200,600Q200,600 200,600Q200,600 200,600L200,600L280,600ZM680,600L760,600L760,600Q760,600 760,600Q760,600 760,600L680,600L680,600Z"/>
+</vector>
\ No newline at end of file
diff --git a/packages/CompanionDeviceManager/res/values/strings.xml b/packages/CompanionDeviceManager/res/values/strings.xml
index 7a6fad4..281eba6 100644
--- a/packages/CompanionDeviceManager/res/values/strings.xml
+++ b/packages/CompanionDeviceManager/res/values/strings.xml
@@ -149,6 +149,9 @@
<!-- Nearby devices' permission will be granted of corresponding profile [CHAR LIMIT=30] -->
<string name="permission_nearby_devices">Nearby devices</string>
+ <!-- Change media output permission will be granted to the corresponding profile [CHAR LIMIT=30] -->
+ <string name="permission_media_routing_control">Change media output</string>
+
<!-- Storage permission will be granted of corresponding profile [CHAR LIMIT=30] -->
<string name="permission_storage">Photos and media</string>
@@ -194,6 +197,9 @@
<!-- Description of nearby_device_streaming permission of corresponding profile [CHAR LIMIT=NONE] -->
<string name="permission_nearby_device_streaming_summary">Stream apps and other system features from your phone</string>
+ <!-- Description of change media output permission to be granted to the corresponding profile [CHAR LIMIT=NONE] -->
+ <string name="permission_media_routing_control_summary">Access a list of available devices and control which one streams or casts audio or video from other apps</string>
+
<!-- The type of the device for phone [CHAR LIMIT=30] -->
<string name="device_type" product="default">phone</string>
diff --git a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceResources.java b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceResources.java
index 060c032..551e975 100644
--- a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceResources.java
+++ b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceResources.java
@@ -26,6 +26,7 @@
import static com.android.companiondevicemanager.PermissionListAdapter.PERMISSION_APP_STREAMING;
import static com.android.companiondevicemanager.PermissionListAdapter.PERMISSION_CALENDAR;
import static com.android.companiondevicemanager.PermissionListAdapter.PERMISSION_CALL_LOGS;
+import static com.android.companiondevicemanager.PermissionListAdapter.PERMISSION_CHANGE_MEDIA_OUTPUT;
import static com.android.companiondevicemanager.PermissionListAdapter.PERMISSION_CONTACTS;
import static com.android.companiondevicemanager.PermissionListAdapter.PERMISSION_MICROPHONE;
import static com.android.companiondevicemanager.PermissionListAdapter.PERMISSION_NEARBY_DEVICES;
@@ -41,6 +42,8 @@
import android.util.ArrayMap;
import android.util.ArraySet;
+import com.android.media.flags.Flags;
+
import java.util.Arrays;
import java.util.List;
import java.util.Map;
@@ -73,9 +76,15 @@
PERMISSION_NOTIFICATION, PERMISSION_STORAGE));
map.put(DEVICE_PROFILE_NEARBY_DEVICE_STREAMING,
Arrays.asList(PERMISSION_NEARBY_DEVICE_STREAMING));
- map.put(DEVICE_PROFILE_WATCH, Arrays.asList(PERMISSION_NOTIFICATION, PERMISSION_PHONE,
- PERMISSION_CALL_LOGS, PERMISSION_SMS, PERMISSION_CONTACTS, PERMISSION_CALENDAR,
- PERMISSION_NEARBY_DEVICES));
+ if (!Flags.enablePrivilegedRoutingForMediaRoutingControl()) {
+ map.put(DEVICE_PROFILE_WATCH, Arrays.asList(PERMISSION_NOTIFICATION, PERMISSION_PHONE,
+ PERMISSION_CALL_LOGS, PERMISSION_SMS, PERMISSION_CONTACTS, PERMISSION_CALENDAR,
+ PERMISSION_NEARBY_DEVICES));
+ } else {
+ map.put(DEVICE_PROFILE_WATCH, Arrays.asList(PERMISSION_NOTIFICATION, PERMISSION_PHONE,
+ PERMISSION_CALL_LOGS, PERMISSION_SMS, PERMISSION_CONTACTS, PERMISSION_CALENDAR,
+ PERMISSION_NEARBY_DEVICES, PERMISSION_CHANGE_MEDIA_OUTPUT));
+ }
map.put(DEVICE_PROFILE_GLASSES, Arrays.asList(PERMISSION_NOTIFICATION, PERMISSION_PHONE,
PERMISSION_SMS, PERMISSION_CONTACTS, PERMISSION_MICROPHONE,
PERMISSION_NEARBY_DEVICES));
diff --git a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/PermissionListAdapter.java b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/PermissionListAdapter.java
index 7ed1816..e21aee3 100644
--- a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/PermissionListAdapter.java
+++ b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/PermissionListAdapter.java
@@ -54,6 +54,7 @@
static final int PERMISSION_NEARBY_DEVICE_STREAMING = 8;
static final int PERMISSION_MICROPHONE = 9;
static final int PERMISSION_CALL_LOGS = 10;
+ static final int PERMISSION_CHANGE_MEDIA_OUTPUT = 11;
private static final Map<Integer, Integer> sTitleMap;
static {
@@ -69,6 +70,7 @@
map.put(PERMISSION_NEARBY_DEVICE_STREAMING, R.string.permission_nearby_device_streaming);
map.put(PERMISSION_MICROPHONE, R.string.permission_microphone);
map.put(PERMISSION_CALL_LOGS, R.string.permission_call_logs);
+ map.put(PERMISSION_CHANGE_MEDIA_OUTPUT, R.string.permission_media_routing_control);
sTitleMap = unmodifiableMap(map);
}
@@ -87,6 +89,7 @@
R.string.permission_nearby_device_streaming_summary);
map.put(PERMISSION_MICROPHONE, R.string.permission_microphone_summary);
map.put(PERMISSION_CALL_LOGS, R.string.permission_call_logs_summary);
+ map.put(PERMISSION_CHANGE_MEDIA_OUTPUT, R.string.permission_media_routing_control_summary);
sSummaryMap = unmodifiableMap(map);
}
@@ -105,6 +108,7 @@
R.drawable.ic_permission_nearby_device_streaming);
map.put(PERMISSION_MICROPHONE, R.drawable.ic_permission_microphone);
map.put(PERMISSION_CALL_LOGS, R.drawable.ic_permission_call_logs);
+ map.put(PERMISSION_CHANGE_MEDIA_OUTPUT, R.drawable.ic_permission_media_routing_control);
sIconMap = unmodifiableMap(map);
}
diff --git a/packages/CredentialManager/res/values-el/strings.xml b/packages/CredentialManager/res/values-el/strings.xml
index 8d06765..089f898 100644
--- a/packages/CredentialManager/res/values-el/strings.xml
+++ b/packages/CredentialManager/res/values-el/strings.xml
@@ -33,7 +33,7 @@
<string name="passwordless_technology_detail" msgid="6853928846532955882">"Τα κλειδιά πρόσβασης σάς επιτρέπουν να συνδέεστε χωρίς να εξαρτάστε από κωδικούς πρόσβασης. Χρειάζεται μόνο να χρησιμοποιήσετε το δακτυλικό αποτύπωμά σας, την αναγνώριση προσώπου, ένα PIN ή ένα μοτίβο σάρωσης για να επαληθεύσετε την ταυτότητά σας και να δημιουργήσετε ένα κλειδί πρόσβασης."</string>
<string name="public_key_cryptography_title" msgid="6751970819265298039">"Κρυπτογραφία δημόσιου κλειδιού"</string>
<string name="public_key_cryptography_detail" msgid="6937631710280562213">"Βάσει του FIDO Alliance (συμμετ. οι Google, Apple, Microsoft κ.ά.) και προτύπων W3C, τα κλειδιά πρόσβ. χρησιμ. συζεύξεις κλειδιών κρυπτογρ. Σε αντίθεση με το όνομα χρήστη και τη συμβολοσειρά χαρακτ. για κωδ. πρόσβ., δημιουργείται μια σύζευξη ιδιωτικού-δημόσιου κλειδ. για εφαρμ./ιστοτόπους. Το ιδιωτ. κλειδί αποθηκεύεται με ασφάλεια στη συσκευή ή στον διαχειρ. κωδ. πρόσβ. και επιβεβαιώνει την ταυτότητά σας. Το δημόσιο κλειδί κοινοπ. στον διακομιστή εφαρμ./ιστοτόπου. Τα αντίστοιχα κλειδιά επιτρέπουν άμεση εγγραφή και σύνδεση."</string>
- <string name="improved_account_security_title" msgid="1069841917893513424">"Βελτιωμένη ασφάλεια λογαριασμού"</string>
+ <string name="improved_account_security_title" msgid="1069841917893513424">"Βελτιωμένη προστασία λογαριασμού"</string>
<string name="improved_account_security_detail" msgid="9123750251551844860">"Κάθε κλειδί συνδέεται αποκλειστικά με την εφαρμογή ή τον ιστότοπο για τον οποίο δημιουργήθηκε ώστε να μην συνδέεστε ποτέ κατά λάθος σε μη νόμιμες εφαρμογές ή ιστοτόπους. Επιπλέον, οι παραβιάσεις είναι πολύ πιο δύσκολες, επειδή οι διακομιστές διατηρούν μόνο δημόσια κλειδιά."</string>
<string name="seamless_transition_title" msgid="5335622196351371961">"Απρόσκοπτη μετάβαση"</string>
<string name="seamless_transition_detail" msgid="4475509237171739843">"Καθώς κινούμαστε προς ένα μέλλον χωρίς κωδικούς πρόσβασης, οι κωδικοί πρόσβασης θα εξακολουθούν να είναι διαθέσιμοι μαζί με τα κλειδιά πρόσβασης."</string>
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/common/ui/BottomSheet.kt b/packages/CredentialManager/src/com/android/credentialmanager/common/ui/BottomSheet.kt
index a5998faa..db69b8b 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/common/ui/BottomSheet.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/common/ui/BottomSheet.kt
@@ -60,14 +60,15 @@
sheetContent = sheetContent,
sheetShape = EntryShape.TopRoundedCorner,
) {}
- LaunchedEffect(state.currentValue) {
+ LaunchedEffect(state.currentValue, state.targetValue) {
if (state.currentValue == ModalBottomSheetValue.Hidden) {
if (isInitialRender) {
onInitialRenderComplete()
scope.launch { state.show() }
- } else {
+ } else if (state.targetValue == ModalBottomSheetValue.Hidden) {
+ // Only dismiss ui when the motion is downwards
onDismiss()
}
}
}
-}
\ No newline at end of file
+}
diff --git a/packages/PackageInstaller/res/values-af/strings.xml b/packages/PackageInstaller/res/values-af/strings.xml
index a3496ca..cb76a28 100644
--- a/packages/PackageInstaller/res/values-af/strings.xml
+++ b/packages/PackageInstaller/res/values-af/strings.xml
@@ -66,6 +66,7 @@
<string name="uninstall_keep_data" msgid="7002379587465487550">"Hou <xliff:g id="SIZE">%1$s</xliff:g> se programdata."</string>
<string name="uninstall_application_text_current_user_clone_profile" msgid="835170400160011636">"Wil jy hierdie app uitvee?"</string>
<string name="uninstall_application_text_with_clone_instance" msgid="6944473334273349036">"Wil jy hierdie app deïnstalleer? <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g>-kloon sal ook uitgevee word."</string>
+ <string name="uninstall_application_text_current_user_private_profile" msgid="867004464945674674">"Wil jy hierdie app van jou private ruimte deïnstalleer?"</string>
<string name="uninstalling_notification_channel" msgid="840153394325714653">"Voer tans deïnstallerings uit"</string>
<string name="uninstall_failure_notification_channel" msgid="1136405866767576588">"Mislukte deïnstallerings"</string>
<string name="uninstalling" msgid="8709566347688966845">"Deïnstalleer tans …"</string>
@@ -106,4 +107,21 @@
<string name="unarchive_application_title" msgid="7958278328280721421">"Stel <xliff:g id="APPNAME">%1$s</xliff:g> terug vanaf <xliff:g id="INSTALLERNAME">%1$s</xliff:g>?"</string>
<string name="unarchive_body_text" msgid="8244155079861708964">"Hierdie app sal in die agtergrond begin aflaai"</string>
<string name="restore" msgid="8460854736328970444">"Stel terug"</string>
+ <string name="unarchive_error_offline_title" msgid="4021785324565678605">"Jy is vanlyn"</string>
+ <string name="unarchive_error_offline_body" msgid="255717000519772755">"Hierdie app sal outomaties teruggestel word wanneer jy aan die internet gekoppel is"</string>
+ <string name="unarchive_error_generic_title" msgid="7123457671482449992">"Iets het skeefgeloop"</string>
+ <string name="unarchive_error_generic_body" msgid="4486803312463813079">"Kon nie hierdie app terugstel nie"</string>
+ <string name="unarchive_error_storage_title" msgid="5080723357273852630">"Te min berging"</string>
+ <string name="unarchive_error_storage_body" msgid="6879544407568780524">"Jy kan spasie op hierdie toestel beskikbaar maak om hierdie app terug te stel. Berging benodig: <xliff:g id="BYTES">%1$s</xliff:g>"</string>
+ <string name="unarchive_action_required_title" msgid="4971245740162604619">"Optrede vereis"</string>
+ <string name="unarchive_action_required_body" msgid="1679431572983989231">"Volg die volgende stappe om hierdie app terug te stel"</string>
+ <string name="unarchive_error_installer_disabled_title" msgid="4815715617014985605">"<xliff:g id="INSTALLERNAME">%1$s</xliff:g> is gedeaktiveer"</string>
+ <!-- no translation found for unarchive_error_installer_disabled_body (4820821285907011729) -->
+ <skip />
+ <string name="unarchive_error_installer_uninstalled_title" msgid="3748354109176326489">"<xliff:g id="INSTALLERNAME">%1$s</xliff:g> is gedeïnstalleer"</string>
+ <string name="unarchive_error_installer_uninstalled_body" msgid="944733542444183204">"Jy sal <xliff:g id="INSTALLERNAME">%1$s</xliff:g> moet installeer om hierdie app terug te stel"</string>
+ <string name="unarchive_action_required_continue" msgid="5711202111224184257">"Gaan voort"</string>
+ <string name="unarchive_clear_storage_button" msgid="1549537154535608744">"Vee berging uit"</string>
+ <string name="unarchive_settings_button" msgid="3504171760009177425">"Instellings"</string>
+ <string name="close" msgid="5214897374055647996">"Maak toe"</string>
</resources>
diff --git a/packages/PackageInstaller/res/values-am/strings.xml b/packages/PackageInstaller/res/values-am/strings.xml
index 9d0fd53..e58eafea 100644
--- a/packages/PackageInstaller/res/values-am/strings.xml
+++ b/packages/PackageInstaller/res/values-am/strings.xml
@@ -66,6 +66,7 @@
<string name="uninstall_keep_data" msgid="7002379587465487550">"ከመተግበሪያ ውሂብ <xliff:g id="SIZE">%1$s</xliff:g> አቆይ።"</string>
<string name="uninstall_application_text_current_user_clone_profile" msgid="835170400160011636">"ይህን መተግበሪያ መሰረዝ ይፈልጋሉ?"</string>
<string name="uninstall_application_text_with_clone_instance" msgid="6944473334273349036">"ይህን መተግበሪያ ማራገፍ ይፈልጋሉ? የተባዛውም <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g> ይሰረዛል።"</string>
+ <string name="uninstall_application_text_current_user_private_profile" msgid="867004464945674674">"ይህን መተግበሪያ ከግል ቦታዎ ማራገፍ ይፈልጋሉ?"</string>
<string name="uninstalling_notification_channel" msgid="840153394325714653">"በማሄድ ላይ ያሉ ማራገፎች"</string>
<string name="uninstall_failure_notification_channel" msgid="1136405866767576588">"ያልተሳኩ ማራገፎች"</string>
<string name="uninstalling" msgid="8709566347688966845">"በማራገፍ ላይ…"</string>
@@ -106,4 +107,21 @@
<string name="unarchive_application_title" msgid="7958278328280721421">"ከ <xliff:g id="INSTALLERNAME">%1$s</xliff:g> ወደነበረበት <xliff:g id="APPNAME">%1$s</xliff:g> መልስ?"</string>
<string name="unarchive_body_text" msgid="8244155079861708964">"ይህ መተግበሪያ በዳራ ማውረድ ይጀምራል።"</string>
<string name="restore" msgid="8460854736328970444">"ወደነበረበት መልስ"</string>
+ <string name="unarchive_error_offline_title" msgid="4021785324565678605">"ከመስመር ውጭ ነዎት"</string>
+ <string name="unarchive_error_offline_body" msgid="255717000519772755">"እርስዎ ከበይነመረቡ ጋር ሲገናኙ ይህ መተግበሪያ በራስ-ሰር ወደነበረበት ይመለሳል"</string>
+ <string name="unarchive_error_generic_title" msgid="7123457671482449992">"የሆነ ስህተት ተከስቷል"</string>
+ <string name="unarchive_error_generic_body" msgid="4486803312463813079">"ይህን መተግበሪያ ወደነበረበት ለመመለስ እየተሞከረ ሳለ አንድ ችግር ነበር"</string>
+ <string name="unarchive_error_storage_title" msgid="5080723357273852630">"በቂ ማከማቻ የለም"</string>
+ <string name="unarchive_error_storage_body" msgid="6879544407568780524">"ይህን መተግበሪያ ወደነበረበት ለመመለስ፣ በዚህ መሳሪያ ላይ ቦታን ማስለቀቅ ይችላሉ። ማከማቻ ያስፈልጋል፦ <xliff:g id="BYTES">%1$s</xliff:g>"</string>
+ <string name="unarchive_action_required_title" msgid="4971245740162604619">"የሚያስፈልግ እርምጃ"</string>
+ <string name="unarchive_action_required_body" msgid="1679431572983989231">"ይህን መተግበሪያ ወደነበረበት ለመመለስ ቀጣዮቹን ደረጃዎች ይከተሉ"</string>
+ <string name="unarchive_error_installer_disabled_title" msgid="4815715617014985605">"<xliff:g id="INSTALLERNAME">%1$s</xliff:g> ተሰናክሏል"</string>
+ <!-- no translation found for unarchive_error_installer_disabled_body (4820821285907011729) -->
+ <skip />
+ <string name="unarchive_error_installer_uninstalled_title" msgid="3748354109176326489">"<xliff:g id="INSTALLERNAME">%1$s</xliff:g> ተራግፏል"</string>
+ <string name="unarchive_error_installer_uninstalled_body" msgid="944733542444183204">"ይህን መተግበሪያ ወደነበረበት ለመመለስ፣ <xliff:g id="INSTALLERNAME">%1$s</xliff:g>ን መጫን አለብዎት"</string>
+ <string name="unarchive_action_required_continue" msgid="5711202111224184257">"ቀጥል"</string>
+ <string name="unarchive_clear_storage_button" msgid="1549537154535608744">"ማከማቻን አጽዳ"</string>
+ <string name="unarchive_settings_button" msgid="3504171760009177425">"ቅንብሮች"</string>
+ <string name="close" msgid="5214897374055647996">"ዝጋ"</string>
</resources>
diff --git a/packages/PackageInstaller/res/values-ar/strings.xml b/packages/PackageInstaller/res/values-ar/strings.xml
index f4c9581..1edd9b1 100644
--- a/packages/PackageInstaller/res/values-ar/strings.xml
+++ b/packages/PackageInstaller/res/values-ar/strings.xml
@@ -66,6 +66,7 @@
<string name="uninstall_keep_data" msgid="7002379587465487550">"الاحتفاظ بـ <xliff:g id="SIZE">%1$s</xliff:g> من بيانات التطبيق."</string>
<string name="uninstall_application_text_current_user_clone_profile" msgid="835170400160011636">"هل تريد حذف هذا التطبيق؟"</string>
<string name="uninstall_application_text_with_clone_instance" msgid="6944473334273349036">"هل تريد إلغاء تثبيت هذا التطبيق؟ سيتم أيضًا حذف نسخة \"<xliff:g id="PACKAGE_LABEL">%1$s</xliff:g>\" الطبق الأصل."</string>
+ <string name="uninstall_application_text_current_user_private_profile" msgid="867004464945674674">"هل تريد إلغاء تثبيت هذا التطبيق من المساحة الخاصة؟"</string>
<string name="uninstalling_notification_channel" msgid="840153394325714653">"عمليات إلغاء التثبيت الجارية"</string>
<string name="uninstall_failure_notification_channel" msgid="1136405866767576588">"عمليات إلغاء التثبيت غير الناجحة"</string>
<string name="uninstalling" msgid="8709566347688966845">"جارٍ إلغاء التثبيت…"</string>
@@ -106,4 +107,21 @@
<string name="unarchive_application_title" msgid="7958278328280721421">"هل تريد استعادة التطبيق \"<xliff:g id="APPNAME">%1$s</xliff:g>\" من \"<xliff:g id="INSTALLERNAME">%1$s</xliff:g>\"؟"</string>
<string name="unarchive_body_text" msgid="8244155079861708964">"سيبدأ تنزيل هذا التطبيق في الخلفية."</string>
<string name="restore" msgid="8460854736328970444">"استعادة"</string>
+ <string name="unarchive_error_offline_title" msgid="4021785324565678605">"لا يتوفر اتصال بالإنترنت"</string>
+ <string name="unarchive_error_offline_body" msgid="255717000519772755">"ستتم استعادة هذا التطبيق تلقائيًا بمجرد اتصالك بالإنترنت."</string>
+ <string name="unarchive_error_generic_title" msgid="7123457671482449992">"حدث خطأ"</string>
+ <string name="unarchive_error_generic_body" msgid="4486803312463813079">"حدثت مشكلة أثناء محاولة استعادة هذا التطبيق."</string>
+ <string name="unarchive_error_storage_title" msgid="5080723357273852630">"مساحة التخزين غير كافية"</string>
+ <string name="unarchive_error_storage_body" msgid="6879544407568780524">"لاستعادة هذا التطبيق، يجب إخلاء بعض المساحة على هذا الجهاز. مساحة التخزين المطلوبة: <xliff:g id="BYTES">%1$s</xliff:g>"</string>
+ <string name="unarchive_action_required_title" msgid="4971245740162604619">"مطلوب اتخاذ إجراء"</string>
+ <string name="unarchive_action_required_body" msgid="1679431572983989231">"يُرجى اتّباع الخطوات التالية لاستعادة هذا التطبيق."</string>
+ <string name="unarchive_error_installer_disabled_title" msgid="4815715617014985605">"<xliff:g id="INSTALLERNAME">%1$s</xliff:g> غير مفعّل"</string>
+ <!-- no translation found for unarchive_error_installer_disabled_body (4820821285907011729) -->
+ <skip />
+ <string name="unarchive_error_installer_uninstalled_title" msgid="3748354109176326489">"<xliff:g id="INSTALLERNAME">%1$s</xliff:g> غير مثبَّت"</string>
+ <string name="unarchive_error_installer_uninstalled_body" msgid="944733542444183204">"لاستعادة هذا التطبيق، يجب تثبيت <xliff:g id="INSTALLERNAME">%1$s</xliff:g>."</string>
+ <string name="unarchive_action_required_continue" msgid="5711202111224184257">"متابعة"</string>
+ <string name="unarchive_clear_storage_button" msgid="1549537154535608744">"محو مساحة التخزين"</string>
+ <string name="unarchive_settings_button" msgid="3504171760009177425">"الإعدادات"</string>
+ <string name="close" msgid="5214897374055647996">"إغلاق"</string>
</resources>
diff --git a/packages/PackageInstaller/res/values-as/strings.xml b/packages/PackageInstaller/res/values-as/strings.xml
index 4d264c6..9bf9cb0 100644
--- a/packages/PackageInstaller/res/values-as/strings.xml
+++ b/packages/PackageInstaller/res/values-as/strings.xml
@@ -66,6 +66,7 @@
<string name="uninstall_keep_data" msgid="7002379587465487550">"এপৰ ডেটাৰ <xliff:g id="SIZE">%1$s</xliff:g> ৰাখক"</string>
<string name="uninstall_application_text_current_user_clone_profile" msgid="835170400160011636">"আপুনি এই এপ্টো মচিব বিচাৰেনে?"</string>
<string name="uninstall_application_text_with_clone_instance" msgid="6944473334273349036">"আপুনি এই এপ্টো আনইনষ্টল কৰিব বিচাৰেনে? <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g>ৰ ক্ল’নো মচা হ’ব।"</string>
+ <string name="uninstall_application_text_current_user_private_profile" msgid="867004464945674674">"আপুনি আপোনাৰ ব্যক্তিগত স্পেচৰ পৰা এই এপ্টো আনইনষ্টল কৰিব বিচাৰেনে?"</string>
<string name="uninstalling_notification_channel" msgid="840153394325714653">"আনইনষ্টল কৰি থকা হৈছে"</string>
<string name="uninstall_failure_notification_channel" msgid="1136405866767576588">"যিবোৰ আনইনষ্টল পৰা নগ\'ল"</string>
<string name="uninstalling" msgid="8709566347688966845">"আনইনষ্টল কৰি থকা হৈছে…"</string>
@@ -106,4 +107,21 @@
<string name="unarchive_application_title" msgid="7958278328280721421">"<xliff:g id="INSTALLERNAME">%1$s</xliff:g>ৰ পৰা <xliff:g id="APPNAME">%1$s</xliff:g> পুনঃস্থাপন কৰিবনে?"</string>
<string name="unarchive_body_text" msgid="8244155079861708964">"এই এপ্টোৱে নেপথ্যত ডাউনল’ড কৰিবলৈ আৰম্ভ কৰিব"</string>
<string name="restore" msgid="8460854736328970444">"পুনঃস্থাপন কৰক"</string>
+ <string name="unarchive_error_offline_title" msgid="4021785324565678605">"আপুনি অফলাইন হৈ আছে"</string>
+ <string name="unarchive_error_offline_body" msgid="255717000519772755">"আপুনি ইণ্টাৰনেটৰ সৈতে সংযুক্ত হ’লে এই এপ্টো স্বয়ংক্ৰিয়ভাৱে পুনঃস্থাপন কৰা হ’ব"</string>
+ <string name="unarchive_error_generic_title" msgid="7123457671482449992">"কিবা ভুল হ’ল"</string>
+ <string name="unarchive_error_generic_body" msgid="4486803312463813079">"এই এপ্টো পুনঃস্থাপন কৰাত কিবা অসুবিধা হৈছিল"</string>
+ <string name="unarchive_error_storage_title" msgid="5080723357273852630">"ষ্ট’ৰেজত পৰ্যাপ্ত ঠাই নাই"</string>
+ <string name="unarchive_error_storage_body" msgid="6879544407568780524">"এই এপ্টো পুনঃস্থাপন কৰিবলৈ, আপুনি এই ডিভাইচটোত ঠাই খালী কৰিব পাৰে। আৱশ্যকীয় ষ্ট’ৰেজ: <xliff:g id="BYTES">%1$s</xliff:g>"</string>
+ <string name="unarchive_action_required_title" msgid="4971245740162604619">"কাৰ্যব্যৱস্থা লোৱাৰ প্ৰয়োজন"</string>
+ <string name="unarchive_action_required_body" msgid="1679431572983989231">"এই এপ্টো পুনঃস্থাপন কৰিবলৈ পৰৱৰ্তী পদক্ষেপসমূহ অনুসৰণ কৰক"</string>
+ <string name="unarchive_error_installer_disabled_title" msgid="4815715617014985605">"<xliff:g id="INSTALLERNAME">%1$s</xliff:g> অক্ষম কৰা আছে"</string>
+ <!-- no translation found for unarchive_error_installer_disabled_body (4820821285907011729) -->
+ <skip />
+ <string name="unarchive_error_installer_uninstalled_title" msgid="3748354109176326489">"<xliff:g id="INSTALLERNAME">%1$s</xliff:g> আনইনষ্টল কৰা হৈছে"</string>
+ <string name="unarchive_error_installer_uninstalled_body" msgid="944733542444183204">"এই এপ্টো পুনঃস্থাপন কৰিবলৈ, আপুনি <xliff:g id="INSTALLERNAME">%1$s</xliff:g> ইনষ্টল কৰিব লাগিব"</string>
+ <string name="unarchive_action_required_continue" msgid="5711202111224184257">"অব্যাহত ৰাখক"</string>
+ <string name="unarchive_clear_storage_button" msgid="1549537154535608744">"ষ্ট’ৰেজ মচক"</string>
+ <string name="unarchive_settings_button" msgid="3504171760009177425">"ছেটিং"</string>
+ <string name="close" msgid="5214897374055647996">"বন্ধ কৰক"</string>
</resources>
diff --git a/packages/PackageInstaller/res/values-az/strings.xml b/packages/PackageInstaller/res/values-az/strings.xml
index 0807ef7..64004e9 100644
--- a/packages/PackageInstaller/res/values-az/strings.xml
+++ b/packages/PackageInstaller/res/values-az/strings.xml
@@ -66,6 +66,7 @@
<string name="uninstall_keep_data" msgid="7002379587465487550">"Tətbiq datasının <xliff:g id="SIZE">%1$s</xliff:g> hissəsini saxlayın."</string>
<string name="uninstall_application_text_current_user_clone_profile" msgid="835170400160011636">"Bu tətbiq silinsin?"</string>
<string name="uninstall_application_text_with_clone_instance" msgid="6944473334273349036">"Bu tətbiqi sistemdən silmək istəyirsiniz? <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g> kopya da silinəcək."</string>
+ <string name="uninstall_application_text_current_user_private_profile" msgid="867004464945674674">"Bu tətbiqi şəxsi məkandan silmək istəyirsiniz?"</string>
<string name="uninstalling_notification_channel" msgid="840153394325714653">"İşləyən sistemlər silinmələr"</string>
<string name="uninstall_failure_notification_channel" msgid="1136405866767576588">"Uğursuz olan sistemlər silinmələr"</string>
<string name="uninstalling" msgid="8709566347688966845">"Sistemdən silinir..."</string>
@@ -106,4 +107,21 @@
<string name="unarchive_application_title" msgid="7958278328280721421">"<xliff:g id="APPNAME">%1$s</xliff:g> <xliff:g id="INSTALLERNAME">%1$s</xliff:g> ünvanından bərpa edilsin?"</string>
<string name="unarchive_body_text" msgid="8244155079861708964">"Bu tətbiq arxa fonda endirilməyə başlayacaq"</string>
<string name="restore" msgid="8460854736328970444">"Bərpa edin"</string>
+ <string name="unarchive_error_offline_title" msgid="4021785324565678605">"Oflaynsınız"</string>
+ <string name="unarchive_error_offline_body" msgid="255717000519772755">"İnternetə qoşulanda bu tətbiq avtomatik bərpa ediləcək"</string>
+ <string name="unarchive_error_generic_title" msgid="7123457671482449992">"Xəta oldu"</string>
+ <string name="unarchive_error_generic_body" msgid="4486803312463813079">"Bu tətbiqi bərpa edərkən problem oldu"</string>
+ <string name="unarchive_error_storage_title" msgid="5080723357273852630">"Kifayət qədər yaddaş yoxdur"</string>
+ <string name="unarchive_error_storage_body" msgid="6879544407568780524">"Bu tətbiqi bərpa etmək üçün bu cihazda yer boşalda bilərsiniz. Lazımi yaddaş: <xliff:g id="BYTES">%1$s</xliff:g>"</string>
+ <string name="unarchive_action_required_title" msgid="4971245740162604619">"Tədbir görmək tələb edilir"</string>
+ <string name="unarchive_action_required_body" msgid="1679431572983989231">"Bu tətbiqi bərpa etmək üçün növbəti addımları izləyin"</string>
+ <string name="unarchive_error_installer_disabled_title" msgid="4815715617014985605">"<xliff:g id="INSTALLERNAME">%1$s</xliff:g> deaktiv edilib"</string>
+ <!-- no translation found for unarchive_error_installer_disabled_body (4820821285907011729) -->
+ <skip />
+ <string name="unarchive_error_installer_uninstalled_title" msgid="3748354109176326489">"<xliff:g id="INSTALLERNAME">%1$s</xliff:g> sistemdən silinib"</string>
+ <string name="unarchive_error_installer_uninstalled_body" msgid="944733542444183204">"Bu tətbiqi bərpa etmək üçün <xliff:g id="INSTALLERNAME">%1$s</xliff:g> quraşdırılmalıdır"</string>
+ <string name="unarchive_action_required_continue" msgid="5711202111224184257">"Davam edin"</string>
+ <string name="unarchive_clear_storage_button" msgid="1549537154535608744">"Yaddaşı təmizləyin"</string>
+ <string name="unarchive_settings_button" msgid="3504171760009177425">"Ayarlar"</string>
+ <string name="close" msgid="5214897374055647996">"Bağlayın"</string>
</resources>
diff --git a/packages/PackageInstaller/res/values-b+sr+Latn/strings.xml b/packages/PackageInstaller/res/values-b+sr+Latn/strings.xml
index 6b9cd04..464b120 100644
--- a/packages/PackageInstaller/res/values-b+sr+Latn/strings.xml
+++ b/packages/PackageInstaller/res/values-b+sr+Latn/strings.xml
@@ -66,6 +66,7 @@
<string name="uninstall_keep_data" msgid="7002379587465487550">"Zadrži <xliff:g id="SIZE">%1$s</xliff:g> podataka aplikacije."</string>
<string name="uninstall_application_text_current_user_clone_profile" msgid="835170400160011636">"Želite da izbrišete ovu aplikaciju?"</string>
<string name="uninstall_application_text_with_clone_instance" msgid="6944473334273349036">"Želite da deinstalirate ovu aplikaciju? Klon aplikacije <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g> će takođe biti izbrisan."</string>
+ <string name="uninstall_application_text_current_user_private_profile" msgid="867004464945674674">"Želite da deinstalirate ovu aplikaciju iz privatnog prostora?"</string>
<string name="uninstalling_notification_channel" msgid="840153394325714653">"Aktivna deinstaliranja"</string>
<string name="uninstall_failure_notification_channel" msgid="1136405866767576588">"Neuspela deinstaliranja"</string>
<string name="uninstalling" msgid="8709566347688966845">"Deinstalira se…"</string>
@@ -106,4 +107,21 @@
<string name="unarchive_application_title" msgid="7958278328280721421">"Želite da vratite <xliff:g id="APPNAME">%1$s</xliff:g> iz <xliff:g id="INSTALLERNAME">%1$s</xliff:g>?"</string>
<string name="unarchive_body_text" msgid="8244155079861708964">"Aplikacija će započeti preuzimanje u pozadini."</string>
<string name="restore" msgid="8460854736328970444">"Vrati"</string>
+ <string name="unarchive_error_offline_title" msgid="4021785324565678605">"Oflajn ste"</string>
+ <string name="unarchive_error_offline_body" msgid="255717000519772755">"Ova aplikacija će biti vraćena automatski kada se povežete na internet"</string>
+ <string name="unarchive_error_generic_title" msgid="7123457671482449992">"Došlo je do greške"</string>
+ <string name="unarchive_error_generic_body" msgid="4486803312463813079">"Došlo je do problema pri vraćanju ove aplikacije"</string>
+ <string name="unarchive_error_storage_title" msgid="5080723357273852630">"Nema dovoljno memorijskog prostora"</string>
+ <string name="unarchive_error_storage_body" msgid="6879544407568780524">"Možete da oslobodite prostor na ovom uređaju da biste vratili ovu aplikaciju. Potreban memorijski prostor: <xliff:g id="BYTES">%1$s</xliff:g>"</string>
+ <string name="unarchive_action_required_title" msgid="4971245740162604619">"Treba da reagujete"</string>
+ <string name="unarchive_action_required_body" msgid="1679431572983989231">"Pratite dalja uputstva da biste vratili ovu aplikaciju"</string>
+ <string name="unarchive_error_installer_disabled_title" msgid="4815715617014985605">"Onemogućen <xliff:g id="INSTALLERNAME">%1$s</xliff:g>"</string>
+ <!-- no translation found for unarchive_error_installer_disabled_body (4820821285907011729) -->
+ <skip />
+ <string name="unarchive_error_installer_uninstalled_title" msgid="3748354109176326489">"Deinstaliran <xliff:g id="INSTALLERNAME">%1$s</xliff:g>"</string>
+ <string name="unarchive_error_installer_uninstalled_body" msgid="944733542444183204">"Da biste vratili ovu aplikaciju, treba da instalirate <xliff:g id="INSTALLERNAME">%1$s</xliff:g>"</string>
+ <string name="unarchive_action_required_continue" msgid="5711202111224184257">"Nastavi"</string>
+ <string name="unarchive_clear_storage_button" msgid="1549537154535608744">"Obriši memorijski prostor"</string>
+ <string name="unarchive_settings_button" msgid="3504171760009177425">"Podešavanja"</string>
+ <string name="close" msgid="5214897374055647996">"Zatvori"</string>
</resources>
diff --git a/packages/PackageInstaller/res/values-be/strings.xml b/packages/PackageInstaller/res/values-be/strings.xml
index 9e6e6fd..3977f22 100644
--- a/packages/PackageInstaller/res/values-be/strings.xml
+++ b/packages/PackageInstaller/res/values-be/strings.xml
@@ -66,6 +66,7 @@
<string name="uninstall_keep_data" msgid="7002379587465487550">"Захаваць даныя праграмы (<xliff:g id="SIZE">%1$s</xliff:g>)."</string>
<string name="uninstall_application_text_current_user_clone_profile" msgid="835170400160011636">"Выдаліць гэту праграму?"</string>
<string name="uninstall_application_text_with_clone_instance" msgid="6944473334273349036">"Выдаліць гэту праграму? Таксама будзе выдалены клон \"<xliff:g id="PACKAGE_LABEL">%1$s</xliff:g>\"."</string>
+ <string name="uninstall_application_text_current_user_private_profile" msgid="867004464945674674">"Выдаліць гэту праграму з прыватнай аўдыторыі?"</string>
<string name="uninstalling_notification_channel" msgid="840153394325714653">"Актыўныя выдаленні"</string>
<string name="uninstall_failure_notification_channel" msgid="1136405866767576588">"Нявыкананыя выдаленні"</string>
<string name="uninstalling" msgid="8709566347688966845">"Ідзе выдаленне…"</string>
@@ -106,4 +107,21 @@
<string name="unarchive_application_title" msgid="7958278328280721421">"Аднавіць праграму \"<xliff:g id="APPNAME">%1$s</xliff:g>\" адсюль: <xliff:g id="INSTALLERNAME">%1$s</xliff:g>?"</string>
<string name="unarchive_body_text" msgid="8244155079861708964">"Праграма пачне спампоўвацца ў фонавым рэжыме"</string>
<string name="restore" msgid="8460854736328970444">"Аднавіць"</string>
+ <string name="unarchive_error_offline_title" msgid="4021785324565678605">"Вы па-за сеткай"</string>
+ <string name="unarchive_error_offline_body" msgid="255717000519772755">"Гэта праграма будзе аўтаматычна адноўлена, калі прылада падключыцца да інтэрнэту"</string>
+ <string name="unarchive_error_generic_title" msgid="7123457671482449992">"Адбылася памылка"</string>
+ <string name="unarchive_error_generic_body" msgid="4486803312463813079">"Пры аднаўленні праграмы ўзнікла праблема"</string>
+ <string name="unarchive_error_storage_title" msgid="5080723357273852630">"Не хапае месца ў сховішчы"</string>
+ <string name="unarchive_error_storage_body" msgid="6879544407568780524">"Каб аднавіць гэту праграму, вызваліце месца на прыладзе. Неабходны аб\'ём месца ў сховішчы: <xliff:g id="BYTES">%1$s</xliff:g>."</string>
+ <string name="unarchive_action_required_title" msgid="4971245740162604619">"Патрабуецца дзеянне"</string>
+ <string name="unarchive_action_required_body" msgid="1679431572983989231">"Каб аднавіць гэту праграму, выканайце далейшыя інструкцыі"</string>
+ <string name="unarchive_error_installer_disabled_title" msgid="4815715617014985605">"Усталёўшчык \"<xliff:g id="INSTALLERNAME">%1$s</xliff:g>\" адключаны"</string>
+ <!-- no translation found for unarchive_error_installer_disabled_body (4820821285907011729) -->
+ <skip />
+ <string name="unarchive_error_installer_uninstalled_title" msgid="3748354109176326489">"Усталёўшчык \"<xliff:g id="INSTALLERNAME">%1$s</xliff:g>\" выдалены"</string>
+ <string name="unarchive_error_installer_uninstalled_body" msgid="944733542444183204">"Каб аднавіць гэту праграму, усталюйце праграму \"<xliff:g id="INSTALLERNAME">%1$s</xliff:g>\""</string>
+ <string name="unarchive_action_required_continue" msgid="5711202111224184257">"Працягнуць"</string>
+ <string name="unarchive_clear_storage_button" msgid="1549537154535608744">"Ачысціць сховішча"</string>
+ <string name="unarchive_settings_button" msgid="3504171760009177425">"Налады"</string>
+ <string name="close" msgid="5214897374055647996">"Закрыць"</string>
</resources>
diff --git a/packages/PackageInstaller/res/values-bg/strings.xml b/packages/PackageInstaller/res/values-bg/strings.xml
index 1c91874..a5f34a7 100644
--- a/packages/PackageInstaller/res/values-bg/strings.xml
+++ b/packages/PackageInstaller/res/values-bg/strings.xml
@@ -66,6 +66,7 @@
<string name="uninstall_keep_data" msgid="7002379587465487550">"Запазване на <xliff:g id="SIZE">%1$s</xliff:g> данни от приложението."</string>
<string name="uninstall_application_text_current_user_clone_profile" msgid="835170400160011636">"Искате ли да изтриете това приложение?"</string>
<string name="uninstall_application_text_with_clone_instance" msgid="6944473334273349036">"Искате ли да деинсталирате това приложение? Копието на <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g> също ще бъде изтрито."</string>
+ <string name="uninstall_application_text_current_user_private_profile" msgid="867004464945674674">"Искате ли да деинсталирате това приложение от личното си пространство?"</string>
<string name="uninstalling_notification_channel" msgid="840153394325714653">"Активни деинсталирания"</string>
<string name="uninstall_failure_notification_channel" msgid="1136405866767576588">"Неуспешни деинсталирания"</string>
<string name="uninstalling" msgid="8709566347688966845">"Деинсталира се..."</string>
@@ -106,4 +107,21 @@
<string name="unarchive_application_title" msgid="7958278328280721421">"Да се възстанови ли <xliff:g id="APPNAME">%1$s</xliff:g> от <xliff:g id="INSTALLERNAME">%1$s</xliff:g>?"</string>
<string name="unarchive_body_text" msgid="8244155079861708964">"Това приложение ще започне да се изтегля на заден план"</string>
<string name="restore" msgid="8460854736328970444">"Възстановяване"</string>
+ <string name="unarchive_error_offline_title" msgid="4021785324565678605">"Офлайн сте"</string>
+ <string name="unarchive_error_offline_body" msgid="255717000519772755">"Това приложение ще бъде възстановено автоматично, когато имате връзка с интернет"</string>
+ <string name="unarchive_error_generic_title" msgid="7123457671482449992">"Нещо се обърка"</string>
+ <string name="unarchive_error_generic_body" msgid="4486803312463813079">"При опита за възстановяване на това приложение възникна проблем"</string>
+ <string name="unarchive_error_storage_title" msgid="5080723357273852630">"Няма достатъчно място в хранилището"</string>
+ <string name="unarchive_error_storage_body" msgid="6879544407568780524">"За да възстановите това приложение, ще трябва да освободите място на устройството. Необходимо място в хранилището: <xliff:g id="BYTES">%1$s</xliff:g>"</string>
+ <string name="unarchive_action_required_title" msgid="4971245740162604619">"Изисква се действие"</string>
+ <string name="unarchive_action_required_body" msgid="1679431572983989231">"Изпълнете следващите стъпки, за да възстановите това приложение"</string>
+ <string name="unarchive_error_installer_disabled_title" msgid="4815715617014985605">"<xliff:g id="INSTALLERNAME">%1$s</xliff:g> е деактивирано"</string>
+ <!-- no translation found for unarchive_error_installer_disabled_body (4820821285907011729) -->
+ <skip />
+ <string name="unarchive_error_installer_uninstalled_title" msgid="3748354109176326489">"<xliff:g id="INSTALLERNAME">%1$s</xliff:g> е деинсталирано"</string>
+ <string name="unarchive_error_installer_uninstalled_body" msgid="944733542444183204">"За да възстановите това приложение, ще трябва да инсталирате <xliff:g id="INSTALLERNAME">%1$s</xliff:g>"</string>
+ <string name="unarchive_action_required_continue" msgid="5711202111224184257">"Напред"</string>
+ <string name="unarchive_clear_storage_button" msgid="1549537154535608744">"Изчистване на данните"</string>
+ <string name="unarchive_settings_button" msgid="3504171760009177425">"Настройки"</string>
+ <string name="close" msgid="5214897374055647996">"Затваряне"</string>
</resources>
diff --git a/packages/PackageInstaller/res/values-bn/strings.xml b/packages/PackageInstaller/res/values-bn/strings.xml
index 5a78f37..eef339a 100644
--- a/packages/PackageInstaller/res/values-bn/strings.xml
+++ b/packages/PackageInstaller/res/values-bn/strings.xml
@@ -66,6 +66,7 @@
<string name="uninstall_keep_data" msgid="7002379587465487550">"অ্যাপ ডেটার মধ্যে <xliff:g id="SIZE">%1$s</xliff:g> রেখে দিন।"</string>
<string name="uninstall_application_text_current_user_clone_profile" msgid="835170400160011636">"আপনি এই অ্যাপ মুছে ফেলতে চান?"</string>
<string name="uninstall_application_text_with_clone_instance" msgid="6944473334273349036">"আপনি এই অ্যাপ আনইনস্টল করতে চান? <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g> ক্লোনও মুছে ফেলা হবে।"</string>
+ <string name="uninstall_application_text_current_user_private_profile" msgid="867004464945674674">"আপনার ব্যক্তিগত স্পেস থেকে এই অ্যাপ আনইনস্টল করতে চান?"</string>
<string name="uninstalling_notification_channel" msgid="840153394325714653">"আনইনস্টল করা হচ্ছে"</string>
<string name="uninstall_failure_notification_channel" msgid="1136405866767576588">"আনইনস্টল করা যায়নি"</string>
<string name="uninstalling" msgid="8709566347688966845">"আনইনস্টল করা হচ্ছে…"</string>
@@ -106,4 +107,21 @@
<string name="unarchive_application_title" msgid="7958278328280721421">"<xliff:g id="INSTALLERNAME">%1$s</xliff:g> থেকে <xliff:g id="APPNAME">%1$s</xliff:g> ফিরিয়ে আনবেন?"</string>
<string name="unarchive_body_text" msgid="8244155079861708964">"এই অ্যাপটি ব্যাকগ্রাউন্ডে ডাউনলোড হওয়া শুরু হবে"</string>
<string name="restore" msgid="8460854736328970444">"ফিরিয়ে আনুন"</string>
+ <string name="unarchive_error_offline_title" msgid="4021785324565678605">"আপনি অফলাইন আছেন"</string>
+ <string name="unarchive_error_offline_body" msgid="255717000519772755">"আপনি ইন্টারনেটের সাথে কানেক্ট থাকাকালীন এই অ্যাপ অটোমেটিক ফিরিয়ে আনা হবে"</string>
+ <string name="unarchive_error_generic_title" msgid="7123457671482449992">"কোনও সমস্যা হয়েছে"</string>
+ <string name="unarchive_error_generic_body" msgid="4486803312463813079">"এই অ্যাপ ফিরিয়ে আনতে চেষ্টা করার সময় সমস্যা হয়েছে"</string>
+ <string name="unarchive_error_storage_title" msgid="5080723357273852630">"পর্যাপ্ত স্টোরেজ নেই"</string>
+ <string name="unarchive_error_storage_body" msgid="6879544407568780524">"এই অ্যাপ ফিরিয়ে আনতে, এই ডিভাইসের স্পেস খালি করতে পারেন। স্টোরেজ প্রয়োজন: <xliff:g id="BYTES">%1$s</xliff:g>"</string>
+ <string name="unarchive_action_required_title" msgid="4971245740162604619">"ব্যবস্থা নিতে হবে"</string>
+ <string name="unarchive_action_required_body" msgid="1679431572983989231">"এই অ্যাপ ফিরিয়ে আনতে পরবর্তী ধাপগুলি ফলো করুন"</string>
+ <string name="unarchive_error_installer_disabled_title" msgid="4815715617014985605">"<xliff:g id="INSTALLERNAME">%1$s</xliff:g> বন্ধ করা হয়েছে"</string>
+ <!-- no translation found for unarchive_error_installer_disabled_body (4820821285907011729) -->
+ <skip />
+ <string name="unarchive_error_installer_uninstalled_title" msgid="3748354109176326489">"<xliff:g id="INSTALLERNAME">%1$s</xliff:g> আনইনস্টল করা হয়েছে"</string>
+ <string name="unarchive_error_installer_uninstalled_body" msgid="944733542444183204">"এই অ্যাপ ফিরিয়ে আনতে, আপনাকে <xliff:g id="INSTALLERNAME">%1$s</xliff:g> ইনস্টল করতে হবে"</string>
+ <string name="unarchive_action_required_continue" msgid="5711202111224184257">"চালিয়ে যান"</string>
+ <string name="unarchive_clear_storage_button" msgid="1549537154535608744">"স্টোরেজ মুছুন"</string>
+ <string name="unarchive_settings_button" msgid="3504171760009177425">"সেটিংস"</string>
+ <string name="close" msgid="5214897374055647996">"বন্ধ করুন"</string>
</resources>
diff --git a/packages/PackageInstaller/res/values-bs/strings.xml b/packages/PackageInstaller/res/values-bs/strings.xml
index aed2d22..7838843 100644
--- a/packages/PackageInstaller/res/values-bs/strings.xml
+++ b/packages/PackageInstaller/res/values-bs/strings.xml
@@ -66,6 +66,7 @@
<string name="uninstall_keep_data" msgid="7002379587465487550">"Zadržati <xliff:g id="SIZE">%1$s</xliff:g> podataka aplikacije."</string>
<string name="uninstall_application_text_current_user_clone_profile" msgid="835170400160011636">"Želite li izbrisati ovu aplikaciju?"</string>
<string name="uninstall_application_text_with_clone_instance" msgid="6944473334273349036">"Želite li deinstalirati ovu aplikaciju? Izbrisat će se i klon aplikacije <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g>."</string>
+ <string name="uninstall_application_text_current_user_private_profile" msgid="867004464945674674">"Želite li deinstalirati ovu aplikaciju iz privatnog prostora?"</string>
<string name="uninstalling_notification_channel" msgid="840153394325714653">"Tekuća deinstaliranja"</string>
<string name="uninstall_failure_notification_channel" msgid="1136405866767576588">"Neuspjela deinstaliranja"</string>
<string name="uninstalling" msgid="8709566347688966845">"Deinstaliranje..."</string>
@@ -106,4 +107,21 @@
<string name="unarchive_application_title" msgid="7958278328280721421">"Vratiti aplikaciju <xliff:g id="APPNAME">%1$s</xliff:g> s usluge <xliff:g id="INSTALLERNAME">%1$s</xliff:g>?"</string>
<string name="unarchive_body_text" msgid="8244155079861708964">"Preuzimanje aplikacije će započeti u pozadini"</string>
<string name="restore" msgid="8460854736328970444">"Vrati"</string>
+ <string name="unarchive_error_offline_title" msgid="4021785324565678605">"Offline ste"</string>
+ <string name="unarchive_error_offline_body" msgid="255717000519772755">"Aplikacija će se automatski vratiti kada se povežete s internetom"</string>
+ <string name="unarchive_error_generic_title" msgid="7123457671482449992">"Nešto nije uredu"</string>
+ <string name="unarchive_error_generic_body" msgid="4486803312463813079">"Došlo je do problema prilikom pokušaja vraćanja aplikacije"</string>
+ <string name="unarchive_error_storage_title" msgid="5080723357273852630">"Nema dovoljno prostora za pohranu"</string>
+ <string name="unarchive_error_storage_body" msgid="6879544407568780524">"Da vratite aplikaciju, možete osloboditi prostor na uređaju. Potrebna pohrana: <xliff:g id="BYTES">%1$s</xliff:g>"</string>
+ <string name="unarchive_action_required_title" msgid="4971245740162604619">"Potrebna je radnja"</string>
+ <string name="unarchive_action_required_body" msgid="1679431572983989231">"Pratite sljedeće korake da vratite ovu aplikaciju"</string>
+ <string name="unarchive_error_installer_disabled_title" msgid="4815715617014985605">"Program za instaliranje <xliff:g id="INSTALLERNAME">%1$s</xliff:g> je onemogućen"</string>
+ <!-- no translation found for unarchive_error_installer_disabled_body (4820821285907011729) -->
+ <skip />
+ <string name="unarchive_error_installer_uninstalled_title" msgid="3748354109176326489">"Program za instaliranje <xliff:g id="INSTALLERNAME">%1$s</xliff:g> je deinstaliran"</string>
+ <string name="unarchive_error_installer_uninstalled_body" msgid="944733542444183204">"Da vratite aplikaciju, trebat ćete instalirati program za instaliranje <xliff:g id="INSTALLERNAME">%1$s</xliff:g>"</string>
+ <string name="unarchive_action_required_continue" msgid="5711202111224184257">"Nastavi"</string>
+ <string name="unarchive_clear_storage_button" msgid="1549537154535608744">"Obriši pohranu"</string>
+ <string name="unarchive_settings_button" msgid="3504171760009177425">"Postavke"</string>
+ <string name="close" msgid="5214897374055647996">"Zatvori"</string>
</resources>
diff --git a/packages/PackageInstaller/res/values-ca/strings.xml b/packages/PackageInstaller/res/values-ca/strings.xml
index 85e5110..bf28e81 100644
--- a/packages/PackageInstaller/res/values-ca/strings.xml
+++ b/packages/PackageInstaller/res/values-ca/strings.xml
@@ -66,6 +66,7 @@
<string name="uninstall_keep_data" msgid="7002379587465487550">"Conserva <xliff:g id="SIZE">%1$s</xliff:g> de dades de l\'aplicació."</string>
<string name="uninstall_application_text_current_user_clone_profile" msgid="835170400160011636">"Vols suprimir aquesta aplicació?"</string>
<string name="uninstall_application_text_with_clone_instance" msgid="6944473334273349036">"Vols desinstal·lar aquesta aplicació? El clon de <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g> també se suprimirà."</string>
+ <string name="uninstall_application_text_current_user_private_profile" msgid="867004464945674674">"Vols desinstal·lar aquesta aplicació del teu espai privat?"</string>
<string name="uninstalling_notification_channel" msgid="840153394325714653">"Desinstal·lacions en curs"</string>
<string name="uninstall_failure_notification_channel" msgid="1136405866767576588">"Desinstal·lacions fallides"</string>
<string name="uninstalling" msgid="8709566347688966845">"S\'està desinstal·lant…"</string>
@@ -106,4 +107,21 @@
<string name="unarchive_application_title" msgid="7958278328280721421">"Vols restaurar <xliff:g id="APPNAME">%1$s</xliff:g> des de <xliff:g id="INSTALLERNAME">%1$s</xliff:g>?"</string>
<string name="unarchive_body_text" msgid="8244155079861708964">"Aquesta aplicació començarà a baixar-se en segon pla"</string>
<string name="restore" msgid="8460854736328970444">"Restaura"</string>
+ <string name="unarchive_error_offline_title" msgid="4021785324565678605">"No tens connexió"</string>
+ <string name="unarchive_error_offline_body" msgid="255717000519772755">"L\'aplicació es restaurarà automàticament quan tinguis connexió a Internet"</string>
+ <string name="unarchive_error_generic_title" msgid="7123457671482449992">"S\'ha produït un error"</string>
+ <string name="unarchive_error_generic_body" msgid="4486803312463813079">"Hi ha hagut un problema en intentar restaurar aquesta aplicació"</string>
+ <string name="unarchive_error_storage_title" msgid="5080723357273852630">"No hi ha prou emmagatzematge"</string>
+ <string name="unarchive_error_storage_body" msgid="6879544407568780524">"Per restaurar l\'aplicació, allibera espai en aquest dispositiu. Emmagatzematge necessari: <xliff:g id="BYTES">%1$s</xliff:g>"</string>
+ <string name="unarchive_action_required_title" msgid="4971245740162604619">"Acció necessària"</string>
+ <string name="unarchive_action_required_body" msgid="1679431572983989231">"Segueix els passos que hi ha continuació per restaurar l\'aplicació"</string>
+ <string name="unarchive_error_installer_disabled_title" msgid="4815715617014985605">"<xliff:g id="INSTALLERNAME">%1$s</xliff:g> està desactivat"</string>
+ <!-- no translation found for unarchive_error_installer_disabled_body (4820821285907011729) -->
+ <skip />
+ <string name="unarchive_error_installer_uninstalled_title" msgid="3748354109176326489">"<xliff:g id="INSTALLERNAME">%1$s</xliff:g> no està instal·lat"</string>
+ <string name="unarchive_error_installer_uninstalled_body" msgid="944733542444183204">"Per restaurar l\'aplicació, cal que instal·lis <xliff:g id="INSTALLERNAME">%1$s</xliff:g>"</string>
+ <string name="unarchive_action_required_continue" msgid="5711202111224184257">"Continua"</string>
+ <string name="unarchive_clear_storage_button" msgid="1549537154535608744">"Esborra emmagatzematge"</string>
+ <string name="unarchive_settings_button" msgid="3504171760009177425">"Configuració"</string>
+ <string name="close" msgid="5214897374055647996">"Tanca"</string>
</resources>
diff --git a/packages/PackageInstaller/res/values-cs/strings.xml b/packages/PackageInstaller/res/values-cs/strings.xml
index fc85bca..5c0ff24 100644
--- a/packages/PackageInstaller/res/values-cs/strings.xml
+++ b/packages/PackageInstaller/res/values-cs/strings.xml
@@ -66,6 +66,7 @@
<string name="uninstall_keep_data" msgid="7002379587465487550">"Ponechat data aplikace o velikosti <xliff:g id="SIZE">%1$s</xliff:g>."</string>
<string name="uninstall_application_text_current_user_clone_profile" msgid="835170400160011636">"Chcete tuto aplikaci smazat?"</string>
<string name="uninstall_application_text_with_clone_instance" msgid="6944473334273349036">"Chcete tuto aplikaci odinstalovat? Smazán bude také klon <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g>."</string>
+ <string name="uninstall_application_text_current_user_private_profile" msgid="867004464945674674">"Chcete tuto aplikaci odinstalovat ze soukromého prostoru?"</string>
<string name="uninstalling_notification_channel" msgid="840153394325714653">"Probíhající odinstalace"</string>
<string name="uninstall_failure_notification_channel" msgid="1136405866767576588">"Neúspěšné odinstalace"</string>
<string name="uninstalling" msgid="8709566347688966845">"Odinstalace…"</string>
@@ -106,4 +107,21 @@
<string name="unarchive_application_title" msgid="7958278328280721421">"Obnovit aplikaci <xliff:g id="APPNAME">%1$s</xliff:g> z aplikace <xliff:g id="INSTALLERNAME">%1$s</xliff:g>?"</string>
<string name="unarchive_body_text" msgid="8244155079861708964">"Aplikace se začne stahovat na pozadí"</string>
<string name="restore" msgid="8460854736328970444">"Obnovit"</string>
+ <string name="unarchive_error_offline_title" msgid="4021785324565678605">"Nejste připojeni k internetu"</string>
+ <string name="unarchive_error_offline_body" msgid="255717000519772755">"Tato aplikace se automaticky obnoví, až budete připojeni k internetu"</string>
+ <string name="unarchive_error_generic_title" msgid="7123457671482449992">"Něco se pokazilo"</string>
+ <string name="unarchive_error_generic_body" msgid="4486803312463813079">"Při pokusu o obnovení této aplikace došlo k problému"</string>
+ <string name="unarchive_error_storage_title" msgid="5080723357273852630">"Nedostatek úložného prostoru"</string>
+ <string name="unarchive_error_storage_body" msgid="6879544407568780524">"Pokud tuto aplikaci chcete obnovit, uvolněte na zařízení místo. Požadované úložiště: <xliff:g id="BYTES">%1$s</xliff:g>"</string>
+ <string name="unarchive_action_required_title" msgid="4971245740162604619">"Vyžadovaná akce"</string>
+ <string name="unarchive_action_required_body" msgid="1679431572983989231">"Pokud tuto aplikaci chcete obnovit, postupujte podle následujících pokynů"</string>
+ <string name="unarchive_error_installer_disabled_title" msgid="4815715617014985605">"<xliff:g id="INSTALLERNAME">%1$s</xliff:g> je zakázán"</string>
+ <!-- no translation found for unarchive_error_installer_disabled_body (4820821285907011729) -->
+ <skip />
+ <string name="unarchive_error_installer_uninstalled_title" msgid="3748354109176326489">"<xliff:g id="INSTALLERNAME">%1$s</xliff:g> je odinstalován"</string>
+ <string name="unarchive_error_installer_uninstalled_body" msgid="944733542444183204">"Pokud tuto aplikaci chcete obnovit, bude potřeba nainstalovat <xliff:g id="INSTALLERNAME">%1$s</xliff:g>"</string>
+ <string name="unarchive_action_required_continue" msgid="5711202111224184257">"Pokračovat"</string>
+ <string name="unarchive_clear_storage_button" msgid="1549537154535608744">"Vymazat úložiště"</string>
+ <string name="unarchive_settings_button" msgid="3504171760009177425">"Nastavení"</string>
+ <string name="close" msgid="5214897374055647996">"Zavřít"</string>
</resources>
diff --git a/packages/PackageInstaller/res/values-da/strings.xml b/packages/PackageInstaller/res/values-da/strings.xml
index aa6fe8f..acb888a 100644
--- a/packages/PackageInstaller/res/values-da/strings.xml
+++ b/packages/PackageInstaller/res/values-da/strings.xml
@@ -66,6 +66,7 @@
<string name="uninstall_keep_data" msgid="7002379587465487550">"Behold <xliff:g id="SIZE">%1$s</xliff:g> appdata."</string>
<string name="uninstall_application_text_current_user_clone_profile" msgid="835170400160011636">"Vil du slette denne app?"</string>
<string name="uninstall_application_text_with_clone_instance" msgid="6944473334273349036">"Vil du afinstallere denne app? Klonen af <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g> slettes også."</string>
+ <string name="uninstall_application_text_current_user_private_profile" msgid="867004464945674674">"Vil du afinstallere denne app fra dit private område?"</string>
<string name="uninstalling_notification_channel" msgid="840153394325714653">"Igangværende afinstallationer"</string>
<string name="uninstall_failure_notification_channel" msgid="1136405866767576588">"Mislykkede afinstallationer"</string>
<string name="uninstalling" msgid="8709566347688966845">"Afinstallerer…"</string>
@@ -106,4 +107,21 @@
<string name="unarchive_application_title" msgid="7958278328280721421">"Vil du gendanne <xliff:g id="APPNAME">%1$s</xliff:g> fra <xliff:g id="INSTALLERNAME">%1$s</xliff:g>?"</string>
<string name="unarchive_body_text" msgid="8244155079861708964">"Download af denne app startes i baggrunden"</string>
<string name="restore" msgid="8460854736328970444">"Gendan"</string>
+ <string name="unarchive_error_offline_title" msgid="4021785324565678605">"Du er offline"</string>
+ <string name="unarchive_error_offline_body" msgid="255717000519772755">"Denne app gendannes automatisk, når du har forbindelse til internettet"</string>
+ <string name="unarchive_error_generic_title" msgid="7123457671482449992">"Noget gik galt"</string>
+ <string name="unarchive_error_generic_body" msgid="4486803312463813079">"Der opstod et problem under gendannelsen af denne app"</string>
+ <string name="unarchive_error_storage_title" msgid="5080723357273852630">"Ikke nok lagerplads"</string>
+ <string name="unarchive_error_storage_body" msgid="6879544407568780524">"Hvis du vil gendanne denne app, skal du frigøre plads på enheden. Påkrævet lagerplads: <xliff:g id="BYTES">%1$s</xliff:g>"</string>
+ <string name="unarchive_action_required_title" msgid="4971245740162604619">"Handling påkrævet"</string>
+ <string name="unarchive_action_required_body" msgid="1679431572983989231">"Følg de næste trin for at gendanne denne app"</string>
+ <string name="unarchive_error_installer_disabled_title" msgid="4815715617014985605">"<xliff:g id="INSTALLERNAME">%1$s</xliff:g> er deaktiveret"</string>
+ <!-- no translation found for unarchive_error_installer_disabled_body (4820821285907011729) -->
+ <skip />
+ <string name="unarchive_error_installer_uninstalled_title" msgid="3748354109176326489">"<xliff:g id="INSTALLERNAME">%1$s</xliff:g> er afinstalleret"</string>
+ <string name="unarchive_error_installer_uninstalled_body" msgid="944733542444183204">"Du skal installere <xliff:g id="INSTALLERNAME">%1$s</xliff:g> for at gendanne denne app"</string>
+ <string name="unarchive_action_required_continue" msgid="5711202111224184257">"Fortsæt"</string>
+ <string name="unarchive_clear_storage_button" msgid="1549537154535608744">"Ryd lagerplads"</string>
+ <string name="unarchive_settings_button" msgid="3504171760009177425">"Indstillinger"</string>
+ <string name="close" msgid="5214897374055647996">"Luk"</string>
</resources>
diff --git a/packages/PackageInstaller/res/values-de/strings.xml b/packages/PackageInstaller/res/values-de/strings.xml
index dc23696..faecc3e 100644
--- a/packages/PackageInstaller/res/values-de/strings.xml
+++ b/packages/PackageInstaller/res/values-de/strings.xml
@@ -66,6 +66,7 @@
<string name="uninstall_keep_data" msgid="7002379587465487550">"<xliff:g id="SIZE">%1$s</xliff:g> an App-Daten behalten."</string>
<string name="uninstall_application_text_current_user_clone_profile" msgid="835170400160011636">"Möchtest du diese App löschen?"</string>
<string name="uninstall_application_text_with_clone_instance" msgid="6944473334273349036">"Möchtest du diese App deinstallieren? Der <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g>-Klon wird ebenfalls gelöscht."</string>
+ <string name="uninstall_application_text_current_user_private_profile" msgid="867004464945674674">"Möchtest du diese App in deinem privaten Bereich deinstallieren?"</string>
<string name="uninstalling_notification_channel" msgid="840153394325714653">"Laufende Deinstallationen"</string>
<string name="uninstall_failure_notification_channel" msgid="1136405866767576588">"Fehlgeschlagene Deinstallationen"</string>
<string name="uninstalling" msgid="8709566347688966845">"Wird deinstalliert..."</string>
@@ -106,4 +107,21 @@
<string name="unarchive_application_title" msgid="7958278328280721421">"<xliff:g id="APPNAME">%1$s</xliff:g> von <xliff:g id="INSTALLERNAME">%1$s</xliff:g> wiederherstellen?"</string>
<string name="unarchive_body_text" msgid="8244155079861708964">"Diese App beginnt im Hintergrund mit dem Herunterladen"</string>
<string name="restore" msgid="8460854736328970444">"Wiederherstellen"</string>
+ <string name="unarchive_error_offline_title" msgid="4021785324565678605">"Du bist offline"</string>
+ <string name="unarchive_error_offline_body" msgid="255717000519772755">"Die App wird automatisch wiederhergestellt, sobald du mit dem Internet verbunden bist"</string>
+ <string name="unarchive_error_generic_title" msgid="7123457671482449992">"Ein Fehler ist aufgetreten"</string>
+ <string name="unarchive_error_generic_body" msgid="4486803312463813079">"Beim Wiederherstellen der App ist ein Fehler aufgetreten"</string>
+ <string name="unarchive_error_storage_title" msgid="5080723357273852630">"Nicht genügend Speicherplatz"</string>
+ <string name="unarchive_error_storage_body" msgid="6879544407568780524">"Um die App wiederherzustellen, musst du erst Speicherplatz auf diesem Gerät freigeben. Erforderlicher Speicherplatz: <xliff:g id="BYTES">%1$s</xliff:g>"</string>
+ <string name="unarchive_action_required_title" msgid="4971245740162604619">"Aktion erforderlich"</string>
+ <string name="unarchive_action_required_body" msgid="1679431572983989231">"Folge den nächsten Schritten, um die App wiederherzustellen"</string>
+ <string name="unarchive_error_installer_disabled_title" msgid="4815715617014985605">"<xliff:g id="INSTALLERNAME">%1$s</xliff:g> ist deaktiviert"</string>
+ <!-- no translation found for unarchive_error_installer_disabled_body (4820821285907011729) -->
+ <skip />
+ <string name="unarchive_error_installer_uninstalled_title" msgid="3748354109176326489">"<xliff:g id="INSTALLERNAME">%1$s</xliff:g> ist deinstalliert"</string>
+ <string name="unarchive_error_installer_uninstalled_body" msgid="944733542444183204">"Um die App wiederherzustellen, musst du den <xliff:g id="INSTALLERNAME">%1$s</xliff:g> installieren"</string>
+ <string name="unarchive_action_required_continue" msgid="5711202111224184257">"Weiter"</string>
+ <string name="unarchive_clear_storage_button" msgid="1549537154535608744">"Speicherinhalt löschen"</string>
+ <string name="unarchive_settings_button" msgid="3504171760009177425">"Einstellungen"</string>
+ <string name="close" msgid="5214897374055647996">"Schließen"</string>
</resources>
diff --git a/packages/PackageInstaller/res/values-el/strings.xml b/packages/PackageInstaller/res/values-el/strings.xml
index ea4eeb6..f5deac9 100644
--- a/packages/PackageInstaller/res/values-el/strings.xml
+++ b/packages/PackageInstaller/res/values-el/strings.xml
@@ -66,6 +66,7 @@
<string name="uninstall_keep_data" msgid="7002379587465487550">"Διατήρηση <xliff:g id="SIZE">%1$s</xliff:g> δεδομένων εφαρμογών."</string>
<string name="uninstall_application_text_current_user_clone_profile" msgid="835170400160011636">"Θέλετε να διαγράψετε αυτή την εφαρμογή;"</string>
<string name="uninstall_application_text_with_clone_instance" msgid="6944473334273349036">"Θέλετε να απεγκαταστήσετε αυτή την εφαρμογή; Θα διαγραφεί επίσης το διπλότυπο της εφαρμογής <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g>."</string>
+ <string name="uninstall_application_text_current_user_private_profile" msgid="867004464945674674">"Θέλετε να απεγκαταστήσετε αυτή την εφαρμογή από τον ιδιωτικό χώρο;"</string>
<string name="uninstalling_notification_channel" msgid="840153394325714653">"Απεγκαταστάσεις σε εξέλιξη"</string>
<string name="uninstall_failure_notification_channel" msgid="1136405866767576588">"Αποτυχημένες απεγκαταστάσεις"</string>
<string name="uninstalling" msgid="8709566347688966845">"Απεγκατάσταση…"</string>
@@ -106,4 +107,21 @@
<string name="unarchive_application_title" msgid="7958278328280721421">"Επαναφορά <xliff:g id="APPNAME">%1$s</xliff:g> από <xliff:g id="INSTALLERNAME">%1$s</xliff:g>;"</string>
<string name="unarchive_body_text" msgid="8244155079861708964">"Η λήψη της εφαρμογής θα ξεκινήσει στο παρασκήνιο"</string>
<string name="restore" msgid="8460854736328970444">"Επαναφορά"</string>
+ <string name="unarchive_error_offline_title" msgid="4021785324565678605">"Είστε εκτός σύνδεσης"</string>
+ <string name="unarchive_error_offline_body" msgid="255717000519772755">"Θα γίνει αυτόματη επαναφορά αυτής της εφαρμογής όταν είστε συνδεδεμένοι στο διαδίκτυο"</string>
+ <string name="unarchive_error_generic_title" msgid="7123457671482449992">"Κάτι πήγε στραβά"</string>
+ <string name="unarchive_error_generic_body" msgid="4486803312463813079">"Παρουσιάστηκε κάποιο πρόβλημα κατά την επαναφορά αυτής της εφαρμογής"</string>
+ <string name="unarchive_error_storage_title" msgid="5080723357273852630">"Δεν επαρκεί ο αποθηκευτικός χώρος"</string>
+ <string name="unarchive_error_storage_body" msgid="6879544407568780524">"Για να επαναφέρετε αυτή την εφαρμογή, μπορείτε να ελευθερώσετε χώρο στη συσκευή. Απαιτούμενος αποθηκευτικός χώρος: <xliff:g id="BYTES">%1$s</xliff:g>"</string>
+ <string name="unarchive_action_required_title" msgid="4971245740162604619">"Απαιτούμενη ενέργεια"</string>
+ <string name="unarchive_action_required_body" msgid="1679431572983989231">"Ακολουθήστε τα επόμενα βήματα για να επαναφέρετε αυτή την εφαρμογή"</string>
+ <string name="unarchive_error_installer_disabled_title" msgid="4815715617014985605">"Το <xliff:g id="INSTALLERNAME">%1$s</xliff:g> είναι απενεργοποιημένο"</string>
+ <!-- no translation found for unarchive_error_installer_disabled_body (4820821285907011729) -->
+ <skip />
+ <string name="unarchive_error_installer_uninstalled_title" msgid="3748354109176326489">"Το <xliff:g id="INSTALLERNAME">%1$s</xliff:g> έχει απεγκατασταθεί"</string>
+ <string name="unarchive_error_installer_uninstalled_body" msgid="944733542444183204">"Για να επαναφέρετε αυτή την εφαρμογή, πρέπει να εγκαταστήσετε το <xliff:g id="INSTALLERNAME">%1$s</xliff:g>"</string>
+ <string name="unarchive_action_required_continue" msgid="5711202111224184257">"Συνέχεια"</string>
+ <string name="unarchive_clear_storage_button" msgid="1549537154535608744">"Διαγραφή αποθηκευτικού χώρου"</string>
+ <string name="unarchive_settings_button" msgid="3504171760009177425">"Ρυθμίσεις"</string>
+ <string name="close" msgid="5214897374055647996">"Κλείσιμο"</string>
</resources>
diff --git a/packages/PackageInstaller/res/values-en-rAU/strings.xml b/packages/PackageInstaller/res/values-en-rAU/strings.xml
index 0187172..4ad4fa1 100644
--- a/packages/PackageInstaller/res/values-en-rAU/strings.xml
+++ b/packages/PackageInstaller/res/values-en-rAU/strings.xml
@@ -66,6 +66,7 @@
<string name="uninstall_keep_data" msgid="7002379587465487550">"Keep <xliff:g id="SIZE">%1$s</xliff:g> of app data."</string>
<string name="uninstall_application_text_current_user_clone_profile" msgid="835170400160011636">"Do you want to delete this app?"</string>
<string name="uninstall_application_text_with_clone_instance" msgid="6944473334273349036">"Do you want to uninstall this app? <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g> clone will also be deleted."</string>
+ <string name="uninstall_application_text_current_user_private_profile" msgid="867004464945674674">"Do you want to uninstall this app from your private space?"</string>
<string name="uninstalling_notification_channel" msgid="840153394325714653">"Running uninstallations"</string>
<string name="uninstall_failure_notification_channel" msgid="1136405866767576588">"Failed uninstallations"</string>
<string name="uninstalling" msgid="8709566347688966845">"Uninstalling…"</string>
@@ -106,4 +107,21 @@
<string name="unarchive_application_title" msgid="7958278328280721421">"Restore <xliff:g id="APPNAME">%1$s</xliff:g> from <xliff:g id="INSTALLERNAME">%1$s</xliff:g>?"</string>
<string name="unarchive_body_text" msgid="8244155079861708964">"This app will start downloading in the background"</string>
<string name="restore" msgid="8460854736328970444">"Restore"</string>
+ <string name="unarchive_error_offline_title" msgid="4021785324565678605">"You\'re offline"</string>
+ <string name="unarchive_error_offline_body" msgid="255717000519772755">"This app will automatically restore when you\'re connected to the Internet"</string>
+ <string name="unarchive_error_generic_title" msgid="7123457671482449992">"Something went wrong"</string>
+ <string name="unarchive_error_generic_body" msgid="4486803312463813079">"There was a problem trying to restore this app"</string>
+ <string name="unarchive_error_storage_title" msgid="5080723357273852630">"Not enough storage"</string>
+ <string name="unarchive_error_storage_body" msgid="6879544407568780524">"To restore this app, you can free up space on this device. Storage required: <xliff:g id="BYTES">%1$s</xliff:g>"</string>
+ <string name="unarchive_action_required_title" msgid="4971245740162604619">"Action required"</string>
+ <string name="unarchive_action_required_body" msgid="1679431572983989231">"Follow the next steps to restore this app"</string>
+ <string name="unarchive_error_installer_disabled_title" msgid="4815715617014985605">"<xliff:g id="INSTALLERNAME">%1$s</xliff:g> is disabled"</string>
+ <!-- no translation found for unarchive_error_installer_disabled_body (4820821285907011729) -->
+ <skip />
+ <string name="unarchive_error_installer_uninstalled_title" msgid="3748354109176326489">"<xliff:g id="INSTALLERNAME">%1$s</xliff:g> is uninstalled"</string>
+ <string name="unarchive_error_installer_uninstalled_body" msgid="944733542444183204">"To restore this app, you\'ll need to install <xliff:g id="INSTALLERNAME">%1$s</xliff:g>"</string>
+ <string name="unarchive_action_required_continue" msgid="5711202111224184257">"Continue"</string>
+ <string name="unarchive_clear_storage_button" msgid="1549537154535608744">"Clear storage"</string>
+ <string name="unarchive_settings_button" msgid="3504171760009177425">"Settings"</string>
+ <string name="close" msgid="5214897374055647996">"Close"</string>
</resources>
diff --git a/packages/PackageInstaller/res/values-en-rCA/strings.xml b/packages/PackageInstaller/res/values-en-rCA/strings.xml
index 9b31f27..831ee1b 100644
--- a/packages/PackageInstaller/res/values-en-rCA/strings.xml
+++ b/packages/PackageInstaller/res/values-en-rCA/strings.xml
@@ -66,6 +66,7 @@
<string name="uninstall_keep_data" msgid="7002379587465487550">"Keep <xliff:g id="SIZE">%1$s</xliff:g> of app data."</string>
<string name="uninstall_application_text_current_user_clone_profile" msgid="835170400160011636">"Do you want to delete this app?"</string>
<string name="uninstall_application_text_with_clone_instance" msgid="6944473334273349036">"Do you want to uninstall this app? <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g> clone will also be deleted."</string>
+ <string name="uninstall_application_text_current_user_private_profile" msgid="867004464945674674">"Do you want to uninstall this app from your private space?"</string>
<string name="uninstalling_notification_channel" msgid="840153394325714653">"Running uninstalls"</string>
<string name="uninstall_failure_notification_channel" msgid="1136405866767576588">"Failed uninstalls"</string>
<string name="uninstalling" msgid="8709566347688966845">"Uninstalling…"</string>
@@ -106,4 +107,21 @@
<string name="unarchive_application_title" msgid="7958278328280721421">"Restore <xliff:g id="APPNAME">%1$s</xliff:g> from <xliff:g id="INSTALLERNAME">%1$s</xliff:g>?"</string>
<string name="unarchive_body_text" msgid="8244155079861708964">"This app will begin to download in the background"</string>
<string name="restore" msgid="8460854736328970444">"Restore"</string>
+ <string name="unarchive_error_offline_title" msgid="4021785324565678605">"You\'re offline"</string>
+ <string name="unarchive_error_offline_body" msgid="255717000519772755">"This app will automatically restore when you\'re connected to the internet"</string>
+ <string name="unarchive_error_generic_title" msgid="7123457671482449992">"Something went wrong"</string>
+ <string name="unarchive_error_generic_body" msgid="4486803312463813079">"There was a problem trying to restore this app"</string>
+ <string name="unarchive_error_storage_title" msgid="5080723357273852630">"Not enough storage"</string>
+ <string name="unarchive_error_storage_body" msgid="6879544407568780524">"To restore this app, you can free up space on this device. Storage required: <xliff:g id="BYTES">%1$s</xliff:g>"</string>
+ <string name="unarchive_action_required_title" msgid="4971245740162604619">"Action required"</string>
+ <string name="unarchive_action_required_body" msgid="1679431572983989231">"Follow the next steps to restore this app"</string>
+ <string name="unarchive_error_installer_disabled_title" msgid="4815715617014985605">"<xliff:g id="INSTALLERNAME">%1$s</xliff:g> is disabled"</string>
+ <!-- no translation found for unarchive_error_installer_disabled_body (4820821285907011729) -->
+ <skip />
+ <string name="unarchive_error_installer_uninstalled_title" msgid="3748354109176326489">"<xliff:g id="INSTALLERNAME">%1$s</xliff:g> is uninstalled"</string>
+ <string name="unarchive_error_installer_uninstalled_body" msgid="944733542444183204">"To restore this app, you\'ll need to install <xliff:g id="INSTALLERNAME">%1$s</xliff:g>"</string>
+ <string name="unarchive_action_required_continue" msgid="5711202111224184257">"Continue"</string>
+ <string name="unarchive_clear_storage_button" msgid="1549537154535608744">"Clear storage"</string>
+ <string name="unarchive_settings_button" msgid="3504171760009177425">"Settings"</string>
+ <string name="close" msgid="5214897374055647996">"Close"</string>
</resources>
diff --git a/packages/PackageInstaller/res/values-en-rGB/strings.xml b/packages/PackageInstaller/res/values-en-rGB/strings.xml
index 0187172..4ad4fa1 100644
--- a/packages/PackageInstaller/res/values-en-rGB/strings.xml
+++ b/packages/PackageInstaller/res/values-en-rGB/strings.xml
@@ -66,6 +66,7 @@
<string name="uninstall_keep_data" msgid="7002379587465487550">"Keep <xliff:g id="SIZE">%1$s</xliff:g> of app data."</string>
<string name="uninstall_application_text_current_user_clone_profile" msgid="835170400160011636">"Do you want to delete this app?"</string>
<string name="uninstall_application_text_with_clone_instance" msgid="6944473334273349036">"Do you want to uninstall this app? <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g> clone will also be deleted."</string>
+ <string name="uninstall_application_text_current_user_private_profile" msgid="867004464945674674">"Do you want to uninstall this app from your private space?"</string>
<string name="uninstalling_notification_channel" msgid="840153394325714653">"Running uninstallations"</string>
<string name="uninstall_failure_notification_channel" msgid="1136405866767576588">"Failed uninstallations"</string>
<string name="uninstalling" msgid="8709566347688966845">"Uninstalling…"</string>
@@ -106,4 +107,21 @@
<string name="unarchive_application_title" msgid="7958278328280721421">"Restore <xliff:g id="APPNAME">%1$s</xliff:g> from <xliff:g id="INSTALLERNAME">%1$s</xliff:g>?"</string>
<string name="unarchive_body_text" msgid="8244155079861708964">"This app will start downloading in the background"</string>
<string name="restore" msgid="8460854736328970444">"Restore"</string>
+ <string name="unarchive_error_offline_title" msgid="4021785324565678605">"You\'re offline"</string>
+ <string name="unarchive_error_offline_body" msgid="255717000519772755">"This app will automatically restore when you\'re connected to the Internet"</string>
+ <string name="unarchive_error_generic_title" msgid="7123457671482449992">"Something went wrong"</string>
+ <string name="unarchive_error_generic_body" msgid="4486803312463813079">"There was a problem trying to restore this app"</string>
+ <string name="unarchive_error_storage_title" msgid="5080723357273852630">"Not enough storage"</string>
+ <string name="unarchive_error_storage_body" msgid="6879544407568780524">"To restore this app, you can free up space on this device. Storage required: <xliff:g id="BYTES">%1$s</xliff:g>"</string>
+ <string name="unarchive_action_required_title" msgid="4971245740162604619">"Action required"</string>
+ <string name="unarchive_action_required_body" msgid="1679431572983989231">"Follow the next steps to restore this app"</string>
+ <string name="unarchive_error_installer_disabled_title" msgid="4815715617014985605">"<xliff:g id="INSTALLERNAME">%1$s</xliff:g> is disabled"</string>
+ <!-- no translation found for unarchive_error_installer_disabled_body (4820821285907011729) -->
+ <skip />
+ <string name="unarchive_error_installer_uninstalled_title" msgid="3748354109176326489">"<xliff:g id="INSTALLERNAME">%1$s</xliff:g> is uninstalled"</string>
+ <string name="unarchive_error_installer_uninstalled_body" msgid="944733542444183204">"To restore this app, you\'ll need to install <xliff:g id="INSTALLERNAME">%1$s</xliff:g>"</string>
+ <string name="unarchive_action_required_continue" msgid="5711202111224184257">"Continue"</string>
+ <string name="unarchive_clear_storage_button" msgid="1549537154535608744">"Clear storage"</string>
+ <string name="unarchive_settings_button" msgid="3504171760009177425">"Settings"</string>
+ <string name="close" msgid="5214897374055647996">"Close"</string>
</resources>
diff --git a/packages/PackageInstaller/res/values-en-rIN/strings.xml b/packages/PackageInstaller/res/values-en-rIN/strings.xml
index 0187172..4ad4fa1 100644
--- a/packages/PackageInstaller/res/values-en-rIN/strings.xml
+++ b/packages/PackageInstaller/res/values-en-rIN/strings.xml
@@ -66,6 +66,7 @@
<string name="uninstall_keep_data" msgid="7002379587465487550">"Keep <xliff:g id="SIZE">%1$s</xliff:g> of app data."</string>
<string name="uninstall_application_text_current_user_clone_profile" msgid="835170400160011636">"Do you want to delete this app?"</string>
<string name="uninstall_application_text_with_clone_instance" msgid="6944473334273349036">"Do you want to uninstall this app? <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g> clone will also be deleted."</string>
+ <string name="uninstall_application_text_current_user_private_profile" msgid="867004464945674674">"Do you want to uninstall this app from your private space?"</string>
<string name="uninstalling_notification_channel" msgid="840153394325714653">"Running uninstallations"</string>
<string name="uninstall_failure_notification_channel" msgid="1136405866767576588">"Failed uninstallations"</string>
<string name="uninstalling" msgid="8709566347688966845">"Uninstalling…"</string>
@@ -106,4 +107,21 @@
<string name="unarchive_application_title" msgid="7958278328280721421">"Restore <xliff:g id="APPNAME">%1$s</xliff:g> from <xliff:g id="INSTALLERNAME">%1$s</xliff:g>?"</string>
<string name="unarchive_body_text" msgid="8244155079861708964">"This app will start downloading in the background"</string>
<string name="restore" msgid="8460854736328970444">"Restore"</string>
+ <string name="unarchive_error_offline_title" msgid="4021785324565678605">"You\'re offline"</string>
+ <string name="unarchive_error_offline_body" msgid="255717000519772755">"This app will automatically restore when you\'re connected to the Internet"</string>
+ <string name="unarchive_error_generic_title" msgid="7123457671482449992">"Something went wrong"</string>
+ <string name="unarchive_error_generic_body" msgid="4486803312463813079">"There was a problem trying to restore this app"</string>
+ <string name="unarchive_error_storage_title" msgid="5080723357273852630">"Not enough storage"</string>
+ <string name="unarchive_error_storage_body" msgid="6879544407568780524">"To restore this app, you can free up space on this device. Storage required: <xliff:g id="BYTES">%1$s</xliff:g>"</string>
+ <string name="unarchive_action_required_title" msgid="4971245740162604619">"Action required"</string>
+ <string name="unarchive_action_required_body" msgid="1679431572983989231">"Follow the next steps to restore this app"</string>
+ <string name="unarchive_error_installer_disabled_title" msgid="4815715617014985605">"<xliff:g id="INSTALLERNAME">%1$s</xliff:g> is disabled"</string>
+ <!-- no translation found for unarchive_error_installer_disabled_body (4820821285907011729) -->
+ <skip />
+ <string name="unarchive_error_installer_uninstalled_title" msgid="3748354109176326489">"<xliff:g id="INSTALLERNAME">%1$s</xliff:g> is uninstalled"</string>
+ <string name="unarchive_error_installer_uninstalled_body" msgid="944733542444183204">"To restore this app, you\'ll need to install <xliff:g id="INSTALLERNAME">%1$s</xliff:g>"</string>
+ <string name="unarchive_action_required_continue" msgid="5711202111224184257">"Continue"</string>
+ <string name="unarchive_clear_storage_button" msgid="1549537154535608744">"Clear storage"</string>
+ <string name="unarchive_settings_button" msgid="3504171760009177425">"Settings"</string>
+ <string name="close" msgid="5214897374055647996">"Close"</string>
</resources>
diff --git a/packages/PackageInstaller/res/values-en-rXC/strings.xml b/packages/PackageInstaller/res/values-en-rXC/strings.xml
index 67ffce5..9ed871eb 100644
--- a/packages/PackageInstaller/res/values-en-rXC/strings.xml
+++ b/packages/PackageInstaller/res/values-en-rXC/strings.xml
@@ -66,6 +66,7 @@
<string name="uninstall_keep_data" msgid="7002379587465487550">"Keep <xliff:g id="SIZE">%1$s</xliff:g> of app data."</string>
<string name="uninstall_application_text_current_user_clone_profile" msgid="835170400160011636">"Do you want to delete this app?"</string>
<string name="uninstall_application_text_with_clone_instance" msgid="6944473334273349036">"Do you want to uninstall this app? <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g> clone will also be deleted."</string>
+ <string name="uninstall_application_text_current_user_private_profile" msgid="867004464945674674">"Do you want to uninstall this app from your private space?"</string>
<string name="uninstalling_notification_channel" msgid="840153394325714653">"Running uninstalls"</string>
<string name="uninstall_failure_notification_channel" msgid="1136405866767576588">"Failed uninstalls"</string>
<string name="uninstalling" msgid="8709566347688966845">"Uninstalling…"</string>
@@ -106,4 +107,21 @@
<string name="unarchive_application_title" msgid="7958278328280721421">"Restore <xliff:g id="APPNAME">%1$s</xliff:g> from <xliff:g id="INSTALLERNAME">%1$s</xliff:g>?"</string>
<string name="unarchive_body_text" msgid="8244155079861708964">"This app will begin to download in the background"</string>
<string name="restore" msgid="8460854736328970444">"Restore"</string>
+ <string name="unarchive_error_offline_title" msgid="4021785324565678605">"You\'re offline"</string>
+ <string name="unarchive_error_offline_body" msgid="255717000519772755">"This app will automatically restore when you\'re connected to the internet"</string>
+ <string name="unarchive_error_generic_title" msgid="7123457671482449992">"Something went wrong"</string>
+ <string name="unarchive_error_generic_body" msgid="4486803312463813079">"There was a problem trying to restore this app"</string>
+ <string name="unarchive_error_storage_title" msgid="5080723357273852630">"Not enough storage"</string>
+ <string name="unarchive_error_storage_body" msgid="6879544407568780524">"To restore this app, you can free up space on this device. Storage required: <xliff:g id="BYTES">%1$s</xliff:g>"</string>
+ <string name="unarchive_action_required_title" msgid="4971245740162604619">"Action required"</string>
+ <string name="unarchive_action_required_body" msgid="1679431572983989231">"Follow the next steps to restore this app"</string>
+ <string name="unarchive_error_installer_disabled_title" msgid="4815715617014985605">"<xliff:g id="INSTALLERNAME">%1$s</xliff:g> is disabled"</string>
+ <!-- no translation found for unarchive_error_installer_disabled_body (4820821285907011729) -->
+ <skip />
+ <string name="unarchive_error_installer_uninstalled_title" msgid="3748354109176326489">"<xliff:g id="INSTALLERNAME">%1$s</xliff:g> is uninstalled"</string>
+ <string name="unarchive_error_installer_uninstalled_body" msgid="944733542444183204">"To restore this app, you\'ll need to install <xliff:g id="INSTALLERNAME">%1$s</xliff:g>"</string>
+ <string name="unarchive_action_required_continue" msgid="5711202111224184257">"Continue"</string>
+ <string name="unarchive_clear_storage_button" msgid="1549537154535608744">"Clear storage"</string>
+ <string name="unarchive_settings_button" msgid="3504171760009177425">"Settings"</string>
+ <string name="close" msgid="5214897374055647996">"Close"</string>
</resources>
diff --git a/packages/PackageInstaller/res/values-es-rUS/strings.xml b/packages/PackageInstaller/res/values-es-rUS/strings.xml
index 2a8559a..631875e 100644
--- a/packages/PackageInstaller/res/values-es-rUS/strings.xml
+++ b/packages/PackageInstaller/res/values-es-rUS/strings.xml
@@ -66,6 +66,7 @@
<string name="uninstall_keep_data" msgid="7002379587465487550">"Guardar <xliff:g id="SIZE">%1$s</xliff:g> en datos de apps"</string>
<string name="uninstall_application_text_current_user_clone_profile" msgid="835170400160011636">"¿Quieres borrar esta app?"</string>
<string name="uninstall_application_text_with_clone_instance" msgid="6944473334273349036">"¿Quieres desinstalar esta app? También se borrará el clon de <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g>."</string>
+ <string name="uninstall_application_text_current_user_private_profile" msgid="867004464945674674">"¿Quieres desinstalar esta app de tu espacio privado?"</string>
<string name="uninstalling_notification_channel" msgid="840153394325714653">"Desinstalaciones activas"</string>
<string name="uninstall_failure_notification_channel" msgid="1136405866767576588">"Desinstalaciones con errores"</string>
<string name="uninstalling" msgid="8709566347688966845">"Desinstalando…"</string>
@@ -106,4 +107,21 @@
<string name="unarchive_application_title" msgid="7958278328280721421">"¿Quieres restablecer <xliff:g id="APPNAME">%1$s</xliff:g> desde <xliff:g id="INSTALLERNAME">%1$s</xliff:g>?"</string>
<string name="unarchive_body_text" msgid="8244155079861708964">"Esta app comenzará la descarga en segundo plano"</string>
<string name="restore" msgid="8460854736328970444">"Restablecer"</string>
+ <string name="unarchive_error_offline_title" msgid="4021785324565678605">"No tienes conexión"</string>
+ <string name="unarchive_error_offline_body" msgid="255717000519772755">"Se restablecerá automáticamente esta app cuando te conectes a Internet"</string>
+ <string name="unarchive_error_generic_title" msgid="7123457671482449992">"Se produjo un error"</string>
+ <string name="unarchive_error_generic_body" msgid="4486803312463813079">"Hubo un problema al intentar restablecer esta app"</string>
+ <string name="unarchive_error_storage_title" msgid="5080723357273852630">"No hay suficiente espacio de almacenamiento"</string>
+ <string name="unarchive_error_storage_body" msgid="6879544407568780524">"Para restablecer la app, deberás liberar espacio en este dispositivo. Almacenamiento requerido: <xliff:g id="BYTES">%1$s</xliff:g>"</string>
+ <string name="unarchive_action_required_title" msgid="4971245740162604619">"Acción obligatoria"</string>
+ <string name="unarchive_action_required_body" msgid="1679431572983989231">"Sigue los próximos pasos para restablecer esta app"</string>
+ <string name="unarchive_error_installer_disabled_title" msgid="4815715617014985605">"Se inhabilitó <xliff:g id="INSTALLERNAME">%1$s</xliff:g>"</string>
+ <!-- no translation found for unarchive_error_installer_disabled_body (4820821285907011729) -->
+ <skip />
+ <string name="unarchive_error_installer_uninstalled_title" msgid="3748354109176326489">"No se instaló <xliff:g id="INSTALLERNAME">%1$s</xliff:g>"</string>
+ <string name="unarchive_error_installer_uninstalled_body" msgid="944733542444183204">"Para restablecer esta app, deberás instalar <xliff:g id="INSTALLERNAME">%1$s</xliff:g>"</string>
+ <string name="unarchive_action_required_continue" msgid="5711202111224184257">"Continuar"</string>
+ <string name="unarchive_clear_storage_button" msgid="1549537154535608744">"Liberar almacenamiento"</string>
+ <string name="unarchive_settings_button" msgid="3504171760009177425">"Configuración"</string>
+ <string name="close" msgid="5214897374055647996">"Cerrar"</string>
</resources>
diff --git a/packages/PackageInstaller/res/values-es/strings.xml b/packages/PackageInstaller/res/values-es/strings.xml
index 5e1022b..bf85728 100644
--- a/packages/PackageInstaller/res/values-es/strings.xml
+++ b/packages/PackageInstaller/res/values-es/strings.xml
@@ -66,6 +66,7 @@
<string name="uninstall_keep_data" msgid="7002379587465487550">"Mantener <xliff:g id="SIZE">%1$s</xliff:g> de datos de aplicaciones."</string>
<string name="uninstall_application_text_current_user_clone_profile" msgid="835170400160011636">"¿Quieres eliminar esta aplicación?"</string>
<string name="uninstall_application_text_with_clone_instance" msgid="6944473334273349036">"¿Quieres desinstalar esta aplicación? El clon de <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g> también se eliminará."</string>
+ <string name="uninstall_application_text_current_user_private_profile" msgid="867004464945674674">"¿Quieres desinstalar esta aplicación de tu espacio privado?"</string>
<string name="uninstalling_notification_channel" msgid="840153394325714653">"Desinstalaciones en curso"</string>
<string name="uninstall_failure_notification_channel" msgid="1136405866767576588">"Desinstalaciones fallidas"</string>
<string name="uninstalling" msgid="8709566347688966845">"Desinstalando…"</string>
@@ -106,4 +107,21 @@
<string name="unarchive_application_title" msgid="7958278328280721421">"¿Restaurar <xliff:g id="APPNAME">%1$s</xliff:g> de <xliff:g id="INSTALLERNAME">%1$s</xliff:g>?"</string>
<string name="unarchive_body_text" msgid="8244155079861708964">"Esta aplicación comenzará a descargarse en segundo plano"</string>
<string name="restore" msgid="8460854736328970444">"Restaurar"</string>
+ <string name="unarchive_error_offline_title" msgid="4021785324565678605">"No tienes conexión a Internet"</string>
+ <string name="unarchive_error_offline_body" msgid="255717000519772755">"Esta aplicación se restaurará automáticamente cuando tengas conexión a Internet"</string>
+ <string name="unarchive_error_generic_title" msgid="7123457671482449992">"Se ha producido un error"</string>
+ <string name="unarchive_error_generic_body" msgid="4486803312463813079">"No se ha podido restaurar esta aplicación"</string>
+ <string name="unarchive_error_storage_title" msgid="5080723357273852630">"No hay suficiente espacio"</string>
+ <string name="unarchive_error_storage_body" msgid="6879544407568780524">"Para restaurar esta aplicación, libera espacio del dispositivo. Almacenamiento necesario: <xliff:g id="BYTES">%1$s</xliff:g>"</string>
+ <string name="unarchive_action_required_title" msgid="4971245740162604619">"Acción necesaria"</string>
+ <string name="unarchive_action_required_body" msgid="1679431572983989231">"Sigue los pasos que se indican a continuación para restaurar esta aplicación"</string>
+ <string name="unarchive_error_installer_disabled_title" msgid="4815715617014985605">"<xliff:g id="INSTALLERNAME">%1$s</xliff:g> está inhabilitada"</string>
+ <!-- no translation found for unarchive_error_installer_disabled_body (4820821285907011729) -->
+ <skip />
+ <string name="unarchive_error_installer_uninstalled_title" msgid="3748354109176326489">"<xliff:g id="INSTALLERNAME">%1$s</xliff:g> está desinstalada"</string>
+ <string name="unarchive_error_installer_uninstalled_body" msgid="944733542444183204">"Para restaurar esta aplicación, tendrás que instalar <xliff:g id="INSTALLERNAME">%1$s</xliff:g>"</string>
+ <string name="unarchive_action_required_continue" msgid="5711202111224184257">"Continuar"</string>
+ <string name="unarchive_clear_storage_button" msgid="1549537154535608744">"Borrar almacenamiento"</string>
+ <string name="unarchive_settings_button" msgid="3504171760009177425">"Ajustes"</string>
+ <string name="close" msgid="5214897374055647996">"Cerrar"</string>
</resources>
diff --git a/packages/PackageInstaller/res/values-et/strings.xml b/packages/PackageInstaller/res/values-et/strings.xml
index 2bd2c04..db3c7dc 100644
--- a/packages/PackageInstaller/res/values-et/strings.xml
+++ b/packages/PackageInstaller/res/values-et/strings.xml
@@ -66,6 +66,7 @@
<string name="uninstall_keep_data" msgid="7002379587465487550">"Säilita rakenduse andmete hulk <xliff:g id="SIZE">%1$s</xliff:g>."</string>
<string name="uninstall_application_text_current_user_clone_profile" msgid="835170400160011636">"Kas soovite selle rakenduse kustutada?"</string>
<string name="uninstall_application_text_with_clone_instance" msgid="6944473334273349036">"Kas soovite selle rakenduse desinstallida? Rakenduse <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g> kloon kustutatakse samuti."</string>
+ <string name="uninstall_application_text_current_user_private_profile" msgid="867004464945674674">"Kas soovite selle rakenduse oma privaatsest ruumist desinstallida?"</string>
<string name="uninstalling_notification_channel" msgid="840153394325714653">"Käimasolevad desinstallimised"</string>
<string name="uninstall_failure_notification_channel" msgid="1136405866767576588">"Ebaõnnestunud desinstallimised"</string>
<string name="uninstalling" msgid="8709566347688966845">"Desinstallimine …"</string>
@@ -106,4 +107,21 @@
<string name="unarchive_application_title" msgid="7958278328280721421">"Kas taastada rakendus <xliff:g id="APPNAME">%1$s</xliff:g> rakenduse <xliff:g id="INSTALLERNAME">%1$s</xliff:g> kaudu?"</string>
<string name="unarchive_body_text" msgid="8244155079861708964">"Selle rakenduse allalaadimine algab taustal"</string>
<string name="restore" msgid="8460854736328970444">"Taasta"</string>
+ <string name="unarchive_error_offline_title" msgid="4021785324565678605">"Võrguühendus puudub"</string>
+ <string name="unarchive_error_offline_body" msgid="255717000519772755">"See rakendus taastatakse automaatselt, kui olete Internetiga ühendatud"</string>
+ <string name="unarchive_error_generic_title" msgid="7123457671482449992">"Midagi läks valesti"</string>
+ <string name="unarchive_error_generic_body" msgid="4486803312463813079">"Selle rakenduse taastamisel ilmnes probleem"</string>
+ <string name="unarchive_error_storage_title" msgid="5080723357273852630">"Pole piisavalt salvestusruumi"</string>
+ <string name="unarchive_error_storage_body" msgid="6879544407568780524">"Selle rakenduse taastamiseks saate selles seadmes ruumi vabastada. Vajalik salvestusruum: <xliff:g id="BYTES">%1$s</xliff:g>"</string>
+ <string name="unarchive_action_required_title" msgid="4971245740162604619">"Toiming on vajalik"</string>
+ <string name="unarchive_action_required_body" msgid="1679431572983989231">"Selle rakenduse taastamiseks järgige järgmisi samme"</string>
+ <string name="unarchive_error_installer_disabled_title" msgid="4815715617014985605">"<xliff:g id="INSTALLERNAME">%1$s</xliff:g> on keelatud"</string>
+ <!-- no translation found for unarchive_error_installer_disabled_body (4820821285907011729) -->
+ <skip />
+ <string name="unarchive_error_installer_uninstalled_title" msgid="3748354109176326489">"<xliff:g id="INSTALLERNAME">%1$s</xliff:g> on desinstallitud"</string>
+ <string name="unarchive_error_installer_uninstalled_body" msgid="944733542444183204">"Selle rakenduse taastamiseks peate installima: <xliff:g id="INSTALLERNAME">%1$s</xliff:g>"</string>
+ <string name="unarchive_action_required_continue" msgid="5711202111224184257">"Jätka"</string>
+ <string name="unarchive_clear_storage_button" msgid="1549537154535608744">"Tühjenda salvestusruum"</string>
+ <string name="unarchive_settings_button" msgid="3504171760009177425">"Seaded"</string>
+ <string name="close" msgid="5214897374055647996">"Sule"</string>
</resources>
diff --git a/packages/PackageInstaller/res/values-eu/strings.xml b/packages/PackageInstaller/res/values-eu/strings.xml
index 574d4ab..e6fe660 100644
--- a/packages/PackageInstaller/res/values-eu/strings.xml
+++ b/packages/PackageInstaller/res/values-eu/strings.xml
@@ -66,6 +66,7 @@
<string name="uninstall_keep_data" msgid="7002379587465487550">"Mantendu aplikazioetako datuen <xliff:g id="SIZE">%1$s</xliff:g>."</string>
<string name="uninstall_application_text_current_user_clone_profile" msgid="835170400160011636">"Aplikazioa ezabatu nahi duzu?"</string>
<string name="uninstall_application_text_with_clone_instance" msgid="6944473334273349036">"Aplikazioa desinstalatu nahi duzu? <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g> aplikazioaren klona ere ezabatuko da."</string>
+ <string name="uninstall_application_text_current_user_private_profile" msgid="867004464945674674">"Aplikazioa eremu pribatutik desinstalatu nahi duzu?"</string>
<string name="uninstalling_notification_channel" msgid="840153394325714653">"Abian diren desinstalatze-eragiketak"</string>
<string name="uninstall_failure_notification_channel" msgid="1136405866767576588">"Desinstalatu ezin izan direnak"</string>
<string name="uninstalling" msgid="8709566347688966845">"Desinstalatzen…"</string>
@@ -106,4 +107,21 @@
<string name="unarchive_application_title" msgid="7958278328280721421">"<xliff:g id="INSTALLERNAME">%1$s</xliff:g> aplikaziotik leheneratu nahi duzu <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
<string name="unarchive_body_text" msgid="8244155079861708964">"Atzeko planoan deskargatuko da aplikazioa"</string>
<string name="restore" msgid="8460854736328970444">"Leheneratu"</string>
+ <string name="unarchive_error_offline_title" msgid="4021785324565678605">"Ez zaude konektatuta Internetera"</string>
+ <string name="unarchive_error_offline_body" msgid="255717000519772755">"Aplikazioa automatikoki leheneratuko da Internetera konektatzen zarenean"</string>
+ <string name="unarchive_error_generic_title" msgid="7123457671482449992">"Arazoren bat izan da"</string>
+ <string name="unarchive_error_generic_body" msgid="4486803312463813079">"Arazo bat izan da aplikazioa leheneratzean"</string>
+ <string name="unarchive_error_storage_title" msgid="5080723357273852630">"Ez dago behar adina toki"</string>
+ <string name="unarchive_error_storage_body" msgid="6879544407568780524">"Aplikazioa leheneratzeko, egin tokia gailuan. Behar den tokia: <xliff:g id="BYTES">%1$s</xliff:g>."</string>
+ <string name="unarchive_action_required_title" msgid="4971245740162604619">"Zerbait egin behar duzu"</string>
+ <string name="unarchive_action_required_body" msgid="1679431572983989231">"Aplikazioa leheneratzeko, egin hurrengo urratsak"</string>
+ <string name="unarchive_error_installer_disabled_title" msgid="4815715617014985605">"<xliff:g id="INSTALLERNAME">%1$s</xliff:g> desgaituta dago"</string>
+ <!-- no translation found for unarchive_error_installer_disabled_body (4820821285907011729) -->
+ <skip />
+ <string name="unarchive_error_installer_uninstalled_title" msgid="3748354109176326489">"<xliff:g id="INSTALLERNAME">%1$s</xliff:g> ez dago instalatuta"</string>
+ <string name="unarchive_error_installer_uninstalled_body" msgid="944733542444183204">"Aplikazioa leheneratzeko, <xliff:g id="INSTALLERNAME">%1$s</xliff:g> instalatu beharko duzu"</string>
+ <string name="unarchive_action_required_continue" msgid="5711202111224184257">"Egin aurrera"</string>
+ <string name="unarchive_clear_storage_button" msgid="1549537154535608744">"Egin tokia"</string>
+ <string name="unarchive_settings_button" msgid="3504171760009177425">"Ezarpenak"</string>
+ <string name="close" msgid="5214897374055647996">"Itxi"</string>
</resources>
diff --git a/packages/PackageInstaller/res/values-fa/strings.xml b/packages/PackageInstaller/res/values-fa/strings.xml
index 1869cb6..014dd93 100644
--- a/packages/PackageInstaller/res/values-fa/strings.xml
+++ b/packages/PackageInstaller/res/values-fa/strings.xml
@@ -66,6 +66,7 @@
<string name="uninstall_keep_data" msgid="7002379587465487550">"<xliff:g id="SIZE">%1$s</xliff:g> از دادههای برنامه را نگهدارید."</string>
<string name="uninstall_application_text_current_user_clone_profile" msgid="835170400160011636">"میخواهید این برنامه را حذف کنید؟"</string>
<string name="uninstall_application_text_with_clone_instance" msgid="6944473334273349036">"میخواهید این برنامه را حذف نصب کنید؟ همسانه <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g> هم حذف خواهد شد."</string>
+ <string name="uninstall_application_text_current_user_private_profile" msgid="867004464945674674">"میخواهید این برنامه از فضای خصوصی حذف نصب شود؟"</string>
<string name="uninstalling_notification_channel" msgid="840153394325714653">"حذفنصبهای درحال انجام"</string>
<string name="uninstall_failure_notification_channel" msgid="1136405866767576588">"حذفنصبهای ناموفق"</string>
<string name="uninstalling" msgid="8709566347688966845">"درحال حذف نصب..."</string>
@@ -106,4 +107,21 @@
<string name="unarchive_application_title" msgid="7958278328280721421">"<xliff:g id="APPNAME">%1$s</xliff:g> از <xliff:g id="INSTALLERNAME">%1$s</xliff:g> بازیابی شود؟"</string>
<string name="unarchive_body_text" msgid="8244155079861708964">"این برنامه در پسزمینه شروع به بارگیری میکند"</string>
<string name="restore" msgid="8460854736328970444">"بازیابی"</string>
+ <string name="unarchive_error_offline_title" msgid="4021785324565678605">"آفلاین هستید"</string>
+ <string name="unarchive_error_offline_body" msgid="255717000519772755">"وقتی به اینترنت متصل شوید، این برنامه بهطور خودکار بازیابی خواهد شد"</string>
+ <string name="unarchive_error_generic_title" msgid="7123457671482449992">"مشکلی پیش آمد"</string>
+ <string name="unarchive_error_generic_body" msgid="4486803312463813079">"هنگام بازیابی این برنامه مشکلی پیش آمد"</string>
+ <string name="unarchive_error_storage_title" msgid="5080723357273852630">"فضای ذخیرهسازی کافی نیست"</string>
+ <string name="unarchive_error_storage_body" msgid="6879544407568780524">"برای بازیابی این برنامه، میتوانید فضای این دستگاه را آزاد کنید. فضای ذخیرهسازی لازم: <xliff:g id="BYTES">%1$s</xliff:g>"</string>
+ <string name="unarchive_action_required_title" msgid="4971245740162604619">"اقدام لازم است"</string>
+ <string name="unarchive_action_required_body" msgid="1679431572983989231">"برای بازیابی این برنامه، مراحل بعدی را دنبال کنید"</string>
+ <string name="unarchive_error_installer_disabled_title" msgid="4815715617014985605">"<xliff:g id="INSTALLERNAME">%1$s</xliff:g> غیرفعال است"</string>
+ <!-- no translation found for unarchive_error_installer_disabled_body (4820821285907011729) -->
+ <skip />
+ <string name="unarchive_error_installer_uninstalled_title" msgid="3748354109176326489">"<xliff:g id="INSTALLERNAME">%1$s</xliff:g> حذف نصب شده است"</string>
+ <string name="unarchive_error_installer_uninstalled_body" msgid="944733542444183204">"برای بازیابی این برنامه، باید <xliff:g id="INSTALLERNAME">%1$s</xliff:g> را نصب کنید"</string>
+ <string name="unarchive_action_required_continue" msgid="5711202111224184257">"ادامه دادن"</string>
+ <string name="unarchive_clear_storage_button" msgid="1549537154535608744">"پاک کردن فضای ذخیرهسازی"</string>
+ <string name="unarchive_settings_button" msgid="3504171760009177425">"تنظیمات"</string>
+ <string name="close" msgid="5214897374055647996">"بستن"</string>
</resources>
diff --git a/packages/PackageInstaller/res/values-fi/strings.xml b/packages/PackageInstaller/res/values-fi/strings.xml
index 8f960ea..78e4067 100644
--- a/packages/PackageInstaller/res/values-fi/strings.xml
+++ b/packages/PackageInstaller/res/values-fi/strings.xml
@@ -66,6 +66,7 @@
<string name="uninstall_keep_data" msgid="7002379587465487550">"Säilytä <xliff:g id="SIZE">%1$s</xliff:g> sovellusdataa"</string>
<string name="uninstall_application_text_current_user_clone_profile" msgid="835170400160011636">"Haluatko poistaa tämän sovelluksen?"</string>
<string name="uninstall_application_text_with_clone_instance" msgid="6944473334273349036">"Haluatko poistaa tämän sovelluksen? Myös klooni (<xliff:g id="PACKAGE_LABEL">%1$s</xliff:g>) poistetaan."</string>
+ <string name="uninstall_application_text_current_user_private_profile" msgid="867004464945674674">"Haluatko poistaa tämän sovelluksen yksityisestä tilasta?"</string>
<string name="uninstalling_notification_channel" msgid="840153394325714653">"Käynnissä olevat poistot"</string>
<string name="uninstall_failure_notification_channel" msgid="1136405866767576588">"Epäonnistuneet poistot"</string>
<string name="uninstalling" msgid="8709566347688966845">"Poistetaan…"</string>
@@ -106,4 +107,21 @@
<string name="unarchive_application_title" msgid="7958278328280721421">"Palautetaanko <xliff:g id="APPNAME">%1$s</xliff:g> sovelluksella <xliff:g id="INSTALLERNAME">%1$s</xliff:g>?"</string>
<string name="unarchive_body_text" msgid="8244155079861708964">"Sovelluksen lataus aloitetaan taustalla"</string>
<string name="restore" msgid="8460854736328970444">"Palauta"</string>
+ <string name="unarchive_error_offline_title" msgid="4021785324565678605">"Olet offline-tilassa"</string>
+ <string name="unarchive_error_offline_body" msgid="255717000519772755">"Sovellus palautuu automaattiseti, kun olet yhteydessä internetiin"</string>
+ <string name="unarchive_error_generic_title" msgid="7123457671482449992">"Jotain meni pieleen"</string>
+ <string name="unarchive_error_generic_body" msgid="4486803312463813079">"Sovelluksen palauttamisessa oli ongelma"</string>
+ <string name="unarchive_error_storage_title" msgid="5080723357273852630">"Tallennustila ei riitä"</string>
+ <string name="unarchive_error_storage_body" msgid="6879544407568780524">"Voit palauttaa sovelluksen vapauttamalla tilaa laitteella. Vaadittu tallennustila: <xliff:g id="BYTES">%1$s</xliff:g>"</string>
+ <string name="unarchive_action_required_title" msgid="4971245740162604619">"Toimi nyt"</string>
+ <string name="unarchive_action_required_body" msgid="1679431572983989231">"Seuraa vaiheita sovelluksen palauttamiseen"</string>
+ <string name="unarchive_error_installer_disabled_title" msgid="4815715617014985605">"<xliff:g id="INSTALLERNAME">%1$s</xliff:g> on poistettu käytöstä"</string>
+ <!-- no translation found for unarchive_error_installer_disabled_body (4820821285907011729) -->
+ <skip />
+ <string name="unarchive_error_installer_uninstalled_title" msgid="3748354109176326489">"Asennus on poistettu (<xliff:g id="INSTALLERNAME">%1$s</xliff:g>)"</string>
+ <string name="unarchive_error_installer_uninstalled_body" msgid="944733542444183204">"Asenna <xliff:g id="INSTALLERNAME">%1$s</xliff:g>, jotta voit palauttaa sovelluksen"</string>
+ <string name="unarchive_action_required_continue" msgid="5711202111224184257">"Jatka"</string>
+ <string name="unarchive_clear_storage_button" msgid="1549537154535608744">"Tyhjennä tallennustila"</string>
+ <string name="unarchive_settings_button" msgid="3504171760009177425">"Asetukset"</string>
+ <string name="close" msgid="5214897374055647996">"Sulje"</string>
</resources>
diff --git a/packages/PackageInstaller/res/values-fr-rCA/strings.xml b/packages/PackageInstaller/res/values-fr-rCA/strings.xml
index 647a7b5..8415b51 100644
--- a/packages/PackageInstaller/res/values-fr-rCA/strings.xml
+++ b/packages/PackageInstaller/res/values-fr-rCA/strings.xml
@@ -66,6 +66,7 @@
<string name="uninstall_keep_data" msgid="7002379587465487550">"Garder <xliff:g id="SIZE">%1$s</xliff:g> de données d\'application."</string>
<string name="uninstall_application_text_current_user_clone_profile" msgid="835170400160011636">"Voulez-vous supprimer cette application?"</string>
<string name="uninstall_application_text_with_clone_instance" msgid="6944473334273349036">"Voulez-vous désinstaller cette application? Le clone de <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g> sera aussi supprimé."</string>
+ <string name="uninstall_application_text_current_user_private_profile" msgid="867004464945674674">"Voulez-vous désinstaller cette application de votre Espace privé?"</string>
<string name="uninstalling_notification_channel" msgid="840153394325714653">"Désinstallations en cours…"</string>
<string name="uninstall_failure_notification_channel" msgid="1136405866767576588">"Désinstallations échouées"</string>
<string name="uninstalling" msgid="8709566347688966845">"Désinstallation en cours…"</string>
@@ -106,4 +107,21 @@
<string name="unarchive_application_title" msgid="7958278328280721421">"Restaurer <xliff:g id="APPNAME">%1$s</xliff:g> à partir de <xliff:g id="INSTALLERNAME">%1$s</xliff:g>?"</string>
<string name="unarchive_body_text" msgid="8244155079861708964">"Le téléchargement de cette application commencera en arrière-plan"</string>
<string name="restore" msgid="8460854736328970444">"Restaurer"</string>
+ <string name="unarchive_error_offline_title" msgid="4021785324565678605">"Vous êtes hors ligne"</string>
+ <string name="unarchive_error_offline_body" msgid="255717000519772755">"Cette application sera automatiquement restaurée lorsque vous serez connecté à Internet"</string>
+ <string name="unarchive_error_generic_title" msgid="7123457671482449992">"Un problème est survenu"</string>
+ <string name="unarchive_error_generic_body" msgid="4486803312463813079">"Un problème est survenu lors de la restauration de cette application"</string>
+ <string name="unarchive_error_storage_title" msgid="5080723357273852630">"Espace de stockage insuffisant"</string>
+ <string name="unarchive_error_storage_body" msgid="6879544407568780524">"Pour restaurer cette application, vous devez libérer de l\'espace de stockage sur cet appareil. Espace de stockage requis : <xliff:g id="BYTES">%1$s</xliff:g>"</string>
+ <string name="unarchive_action_required_title" msgid="4971245740162604619">"Action requise"</string>
+ <string name="unarchive_action_required_body" msgid="1679431572983989231">"Suivez les étapes suivantes pour restaurer cette application"</string>
+ <string name="unarchive_error_installer_disabled_title" msgid="4815715617014985605">"<xliff:g id="INSTALLERNAME">%1$s</xliff:g> est désactivé"</string>
+ <!-- no translation found for unarchive_error_installer_disabled_body (4820821285907011729) -->
+ <skip />
+ <string name="unarchive_error_installer_uninstalled_title" msgid="3748354109176326489">"<xliff:g id="INSTALLERNAME">%1$s</xliff:g> est désinstallé"</string>
+ <string name="unarchive_error_installer_uninstalled_body" msgid="944733542444183204">"Pour restaurer cette application, vous devrez installer <xliff:g id="INSTALLERNAME">%1$s</xliff:g>"</string>
+ <string name="unarchive_action_required_continue" msgid="5711202111224184257">"Continuer"</string>
+ <string name="unarchive_clear_storage_button" msgid="1549537154535608744">"Effacer le stockage"</string>
+ <string name="unarchive_settings_button" msgid="3504171760009177425">"Paramètres"</string>
+ <string name="close" msgid="5214897374055647996">"Fermer"</string>
</resources>
diff --git a/packages/PackageInstaller/res/values-fr/strings.xml b/packages/PackageInstaller/res/values-fr/strings.xml
index 3cf043b..a90fdce 100644
--- a/packages/PackageInstaller/res/values-fr/strings.xml
+++ b/packages/PackageInstaller/res/values-fr/strings.xml
@@ -66,6 +66,7 @@
<string name="uninstall_keep_data" msgid="7002379587465487550">"Conserver <xliff:g id="SIZE">%1$s</xliff:g> de données d\'application."</string>
<string name="uninstall_application_text_current_user_clone_profile" msgid="835170400160011636">"Voulez-vous supprimer cette appli ?"</string>
<string name="uninstall_application_text_with_clone_instance" msgid="6944473334273349036">"Voulez-vous désinstaller cette appli ? Le clone de <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g> sera supprimé aussi."</string>
+ <string name="uninstall_application_text_current_user_private_profile" msgid="867004464945674674">"Souhaitez-vous désinstaller cette application de votre Espace privé ?"</string>
<string name="uninstalling_notification_channel" msgid="840153394325714653">"Désinstallations en cours"</string>
<string name="uninstall_failure_notification_channel" msgid="1136405866767576588">"Échec des désinstallations"</string>
<string name="uninstalling" msgid="8709566347688966845">"Désinstallation…"</string>
@@ -106,4 +107,21 @@
<string name="unarchive_application_title" msgid="7958278328280721421">"Restaurer <xliff:g id="APPNAME">%1$s</xliff:g> depuis <xliff:g id="INSTALLERNAME">%1$s</xliff:g> ?"</string>
<string name="unarchive_body_text" msgid="8244155079861708964">"Cette application commencera à se télécharger en arrière-plan"</string>
<string name="restore" msgid="8460854736328970444">"Restaurer"</string>
+ <string name="unarchive_error_offline_title" msgid="4021785324565678605">"Vous n\'êtes pas connecté"</string>
+ <string name="unarchive_error_offline_body" msgid="255717000519772755">"L\'application sera automatiquement restaurée lorsque vous serez connecté à Internet"</string>
+ <string name="unarchive_error_generic_title" msgid="7123457671482449992">"Un problème est survenu"</string>
+ <string name="unarchive_error_generic_body" msgid="4486803312463813079">"Un problème est survenu lors de la restauration de cette application"</string>
+ <string name="unarchive_error_storage_title" msgid="5080723357273852630">"Espace de stockage insuffisant"</string>
+ <string name="unarchive_error_storage_body" msgid="6879544407568780524">"Pour restaurer cette application, vous pouvez libérer de l\'espace sur cet appareil. Espace de stockage requis : <xliff:g id="BYTES">%1$s</xliff:g>"</string>
+ <string name="unarchive_action_required_title" msgid="4971245740162604619">"Action requise"</string>
+ <string name="unarchive_action_required_body" msgid="1679431572983989231">"Suivre la procédure ci-dessous pour restaurer cette application"</string>
+ <string name="unarchive_error_installer_disabled_title" msgid="4815715617014985605">"<xliff:g id="INSTALLERNAME">%1$s</xliff:g> est désactivé"</string>
+ <!-- no translation found for unarchive_error_installer_disabled_body (4820821285907011729) -->
+ <skip />
+ <string name="unarchive_error_installer_uninstalled_title" msgid="3748354109176326489">"<xliff:g id="INSTALLERNAME">%1$s</xliff:g> n\'est pas installé"</string>
+ <string name="unarchive_error_installer_uninstalled_body" msgid="944733542444183204">"Pour restaurer cette application, vous devrez installer <xliff:g id="INSTALLERNAME">%1$s</xliff:g>"</string>
+ <string name="unarchive_action_required_continue" msgid="5711202111224184257">"Continuer"</string>
+ <string name="unarchive_clear_storage_button" msgid="1549537154535608744">"Vider l\'espace de stockage"</string>
+ <string name="unarchive_settings_button" msgid="3504171760009177425">"Paramètres"</string>
+ <string name="close" msgid="5214897374055647996">"Fermer"</string>
</resources>
diff --git a/packages/PackageInstaller/res/values-gl/strings.xml b/packages/PackageInstaller/res/values-gl/strings.xml
index eeb1f95..a758e32 100644
--- a/packages/PackageInstaller/res/values-gl/strings.xml
+++ b/packages/PackageInstaller/res/values-gl/strings.xml
@@ -66,6 +66,7 @@
<string name="uninstall_keep_data" msgid="7002379587465487550">"Conservar os datos da aplicación, que ocupan <xliff:g id="SIZE">%1$s</xliff:g>."</string>
<string name="uninstall_application_text_current_user_clone_profile" msgid="835170400160011636">"Queres eliminar esta aplicación?"</string>
<string name="uninstall_application_text_with_clone_instance" msgid="6944473334273349036">"Queres desinstalar esta aplicación? Tamén se eliminará o clon de <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g>."</string>
+ <string name="uninstall_application_text_current_user_private_profile" msgid="867004464945674674">"Queres desinstalar esta aplicación do teu espazo privado?"</string>
<string name="uninstalling_notification_channel" msgid="840153394325714653">"Desinstalacións en curso"</string>
<string name="uninstall_failure_notification_channel" msgid="1136405866767576588">"Erros nas desinstalacións"</string>
<string name="uninstalling" msgid="8709566347688966845">"Desinstalando…"</string>
@@ -106,4 +107,21 @@
<string name="unarchive_application_title" msgid="7958278328280721421">"Queres restaurar <xliff:g id="APPNAME">%1$s</xliff:g> desde <xliff:g id="INSTALLERNAME">%1$s</xliff:g>?"</string>
<string name="unarchive_body_text" msgid="8244155079861708964">"Esta aplicación comezará a descargarse en segundo plano"</string>
<string name="restore" msgid="8460854736328970444">"Restaurar"</string>
+ <string name="unarchive_error_offline_title" msgid="4021785324565678605">"Estás sen conexión"</string>
+ <string name="unarchive_error_offline_body" msgid="255717000519772755">"Esta aplicación restaurarase automaticamente cando te conectes a Internet"</string>
+ <string name="unarchive_error_generic_title" msgid="7123457671482449992">"Produciuse un erro"</string>
+ <string name="unarchive_error_generic_body" msgid="4486803312463813079">"Produciuse un problema ao restaurar esta aplicación"</string>
+ <string name="unarchive_error_storage_title" msgid="5080723357273852630">"Non hai almacenamento suficiente"</string>
+ <string name="unarchive_error_storage_body" msgid="6879544407568780524">"Para restaurar esta aplicación, podes liberar espazo neste dispositivo. Espazo de almacenamento necesario: <xliff:g id="BYTES">%1$s</xliff:g>"</string>
+ <string name="unarchive_action_required_title" msgid="4971245740162604619">"Acción necesaria"</string>
+ <string name="unarchive_action_required_body" msgid="1679431572983989231">"Completa os pasos seguintes para restaurar esta aplicación"</string>
+ <string name="unarchive_error_installer_disabled_title" msgid="4815715617014985605">"Desactivouse <xliff:g id="INSTALLERNAME">%1$s</xliff:g>"</string>
+ <!-- no translation found for unarchive_error_installer_disabled_body (4820821285907011729) -->
+ <skip />
+ <string name="unarchive_error_installer_uninstalled_title" msgid="3748354109176326489">"Desinstalouse <xliff:g id="INSTALLERNAME">%1$s</xliff:g>"</string>
+ <string name="unarchive_error_installer_uninstalled_body" msgid="944733542444183204">"Para restaurar esta aplicación, tes que instalar <xliff:g id="INSTALLERNAME">%1$s</xliff:g>"</string>
+ <string name="unarchive_action_required_continue" msgid="5711202111224184257">"Continuar"</string>
+ <string name="unarchive_clear_storage_button" msgid="1549537154535608744">"Liberar almacenamento"</string>
+ <string name="unarchive_settings_button" msgid="3504171760009177425">"Configuración"</string>
+ <string name="close" msgid="5214897374055647996">"Pechar"</string>
</resources>
diff --git a/packages/PackageInstaller/res/values-gu/strings.xml b/packages/PackageInstaller/res/values-gu/strings.xml
index e1f1887..4873303 100644
--- a/packages/PackageInstaller/res/values-gu/strings.xml
+++ b/packages/PackageInstaller/res/values-gu/strings.xml
@@ -66,6 +66,7 @@
<string name="uninstall_keep_data" msgid="7002379587465487550">"<xliff:g id="SIZE">%1$s</xliff:g>નો ઍપ ડેટા રાખો."</string>
<string name="uninstall_application_text_current_user_clone_profile" msgid="835170400160011636">"શું તમે આ ઍપ ડિલીટ કરવા માગો છો?"</string>
<string name="uninstall_application_text_with_clone_instance" msgid="6944473334273349036">"શું તમે આ ઍપને અનઇન્સ્ટૉલ કરવા માગો છો? <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g>ની ક્લોન પણ ડિલીટ કરવામાં આવશે."</string>
+ <string name="uninstall_application_text_current_user_private_profile" msgid="867004464945674674">"શું તમે તમારી ખાનગી સ્પેસમાંથી આ ઍપ અનઇન્સ્ટૉલ કરવા માગો છો?"</string>
<string name="uninstalling_notification_channel" msgid="840153394325714653">"ચાલી રહેલા અનઇન્સ્ટૉલ"</string>
<string name="uninstall_failure_notification_channel" msgid="1136405866767576588">"નિષ્ફળ થયેલા અનઇન્સ્ટૉલ"</string>
<string name="uninstalling" msgid="8709566347688966845">"અનઇન્સ્ટૉલ કરી રહ્યાં છીએ…"</string>
@@ -106,4 +107,21 @@
<string name="unarchive_application_title" msgid="7958278328280721421">"<xliff:g id="INSTALLERNAME">%1$s</xliff:g>માંથી <xliff:g id="APPNAME">%1$s</xliff:g> રિસ્ટોર કરીએ?"</string>
<string name="unarchive_body_text" msgid="8244155079861708964">"બૅકગ્રાઉન્ડમાં આ ઍપ ડાઉનલોડ થવાનું શરૂ થશે"</string>
<string name="restore" msgid="8460854736328970444">"રિસ્ટોર કરો"</string>
+ <string name="unarchive_error_offline_title" msgid="4021785324565678605">"તમે ઑફલાઇન છો"</string>
+ <string name="unarchive_error_offline_body" msgid="255717000519772755">"જ્યારે તમે ઇન્ટરનેટ સાથે કનેક્ટેડ થશો, ત્યારે આ ઍપ ઑટોમૅટિક રીતે રિસ્ટોર થશે"</string>
+ <string name="unarchive_error_generic_title" msgid="7123457671482449992">"કંઈક ખોટું થયું"</string>
+ <string name="unarchive_error_generic_body" msgid="4486803312463813079">"આ ઍપને રિસ્ટોર કરવામાં કોઈ સમસ્યા આવી હતી"</string>
+ <string name="unarchive_error_storage_title" msgid="5080723357273852630">"પર્યાપ્ત સ્ટોરેજ નથી"</string>
+ <string name="unarchive_error_storage_body" msgid="6879544407568780524">"આ ઍપને રિસ્ટોર કરવા માટે, તમે આ ડિવાઇસ પર સ્પેસ ખાલી કરી શકો છો. આવશ્યક સ્ટોરેજ: <xliff:g id="BYTES">%1$s</xliff:g>"</string>
+ <string name="unarchive_action_required_title" msgid="4971245740162604619">"પગલું આવશ્યક છે"</string>
+ <string name="unarchive_action_required_body" msgid="1679431572983989231">"આ ઍપને રિસ્ટોર કરવા માટે આગળના પગલાં અનુસરો"</string>
+ <string name="unarchive_error_installer_disabled_title" msgid="4815715617014985605">"<xliff:g id="INSTALLERNAME">%1$s</xliff:g> બંધ છે"</string>
+ <!-- no translation found for unarchive_error_installer_disabled_body (4820821285907011729) -->
+ <skip />
+ <string name="unarchive_error_installer_uninstalled_title" msgid="3748354109176326489">"<xliff:g id="INSTALLERNAME">%1$s</xliff:g> અનઇન્સ્ટૉલ કર્યું છે"</string>
+ <string name="unarchive_error_installer_uninstalled_body" msgid="944733542444183204">"આ ઍપને રિસ્ટોર કરવા માટે, તમારે <xliff:g id="INSTALLERNAME">%1$s</xliff:g> ઇન્સ્ટૉલ કરવું જરૂરી છે"</string>
+ <string name="unarchive_action_required_continue" msgid="5711202111224184257">"આગળ વધો"</string>
+ <string name="unarchive_clear_storage_button" msgid="1549537154535608744">"સ્ટોરેજ સાફ કરો"</string>
+ <string name="unarchive_settings_button" msgid="3504171760009177425">"સેટિંગ"</string>
+ <string name="close" msgid="5214897374055647996">"બંધ કરો"</string>
</resources>
diff --git a/packages/PackageInstaller/res/values-hi/strings.xml b/packages/PackageInstaller/res/values-hi/strings.xml
index 642bbd9..1e2dea2 100644
--- a/packages/PackageInstaller/res/values-hi/strings.xml
+++ b/packages/PackageInstaller/res/values-hi/strings.xml
@@ -66,6 +66,7 @@
<string name="uninstall_keep_data" msgid="7002379587465487550">"<xliff:g id="SIZE">%1$s</xliff:g> ऐप्लिकेशन डेटा रखें."</string>
<string name="uninstall_application_text_current_user_clone_profile" msgid="835170400160011636">"क्या आपको यह ऐप्लिकेशन मिटाना है?"</string>
<string name="uninstall_application_text_with_clone_instance" msgid="6944473334273349036">"क्या आपको यह ऐप्लिकेशन अनइंस्टॉल करना है? इससे <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g> का क्लोन भी मिट जाएगा."</string>
+ <string name="uninstall_application_text_current_user_private_profile" msgid="867004464945674674">"क्या आपको अपने प्राइवेट स्पेस से यह ऐप्लिकेशन अनइंस्टॉल करना है?"</string>
<string name="uninstalling_notification_channel" msgid="840153394325714653">"वे अनइंस्टॉल जो चल रहे हैं"</string>
<string name="uninstall_failure_notification_channel" msgid="1136405866767576588">"वे अनइंस्टॉल जो सफल नहीं रहे"</string>
<string name="uninstalling" msgid="8709566347688966845">"अनइंस्टॉल हो रहा है…"</string>
@@ -106,4 +107,21 @@
<string name="unarchive_application_title" msgid="7958278328280721421">"<xliff:g id="APPNAME">%1$s</xliff:g> को <xliff:g id="INSTALLERNAME">%1$s</xliff:g> से वापस लाएं?"</string>
<string name="unarchive_body_text" msgid="8244155079861708964">"यह ऐप्लिकेशन, बैकग्राउंड में डाउनलोड होना शुरू हो जाएगा"</string>
<string name="restore" msgid="8460854736328970444">"वापस लाएं"</string>
+ <string name="unarchive_error_offline_title" msgid="4021785324565678605">"आप ऑफ़लाइन हैं"</string>
+ <string name="unarchive_error_offline_body" msgid="255717000519772755">"इंटरनेट कनेक्शन होने पर, यह ऐप्लिकेशन अपने-आप वापस आ जाएगा"</string>
+ <string name="unarchive_error_generic_title" msgid="7123457671482449992">"कोई गड़बड़ी हुई"</string>
+ <string name="unarchive_error_generic_body" msgid="4486803312463813079">"इस ऐप्लिकेशन को वापस लाने में समस्या हुई"</string>
+ <string name="unarchive_error_storage_title" msgid="5080723357273852630">"डिवाइस का स्टोरेज ज़रूरत से कम है"</string>
+ <string name="unarchive_error_storage_body" msgid="6879544407568780524">"इस ऐप्लिकेशन को वापस लाने के लिए, इस डिवाइस में स्टोरेज खाली करें. इतने स्टोरेज की ज़रूरत है: <xliff:g id="BYTES">%1$s</xliff:g>"</string>
+ <string name="unarchive_action_required_title" msgid="4971245740162604619">"कार्रवाई ज़रूरी है"</string>
+ <string name="unarchive_action_required_body" msgid="1679431572983989231">"इस ऐप्लिकेशन को वापस लाने के लिए, दिया गया तरीका अपनाएं"</string>
+ <string name="unarchive_error_installer_disabled_title" msgid="4815715617014985605">"<xliff:g id="INSTALLERNAME">%1$s</xliff:g> बंद है"</string>
+ <!-- no translation found for unarchive_error_installer_disabled_body (4820821285907011729) -->
+ <skip />
+ <string name="unarchive_error_installer_uninstalled_title" msgid="3748354109176326489">"<xliff:g id="INSTALLERNAME">%1$s</xliff:g> अनइंस्टॉल है"</string>
+ <string name="unarchive_error_installer_uninstalled_body" msgid="944733542444183204">"इस ऐप्लिकेशन को वापस लाने के लिए, आपको <xliff:g id="INSTALLERNAME">%1$s</xliff:g> इंस्टॉल करना होगा"</string>
+ <string name="unarchive_action_required_continue" msgid="5711202111224184257">"जारी रखें"</string>
+ <string name="unarchive_clear_storage_button" msgid="1549537154535608744">"स्टोरेज खाली करें"</string>
+ <string name="unarchive_settings_button" msgid="3504171760009177425">"Settings"</string>
+ <string name="close" msgid="5214897374055647996">"बंद करें"</string>
</resources>
diff --git a/packages/PackageInstaller/res/values-hr/strings.xml b/packages/PackageInstaller/res/values-hr/strings.xml
index 69ce3f1..34901a4 100644
--- a/packages/PackageInstaller/res/values-hr/strings.xml
+++ b/packages/PackageInstaller/res/values-hr/strings.xml
@@ -66,6 +66,7 @@
<string name="uninstall_keep_data" msgid="7002379587465487550">"Zadrži <xliff:g id="SIZE">%1$s</xliff:g> podataka aplikacije."</string>
<string name="uninstall_application_text_current_user_clone_profile" msgid="835170400160011636">"Želite li izbrisati ovu aplikaciju?"</string>
<string name="uninstall_application_text_with_clone_instance" msgid="6944473334273349036">"Želite li deinstalirati ovu aplikaciju? Klon za <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g> također će se izbrisati."</string>
+ <string name="uninstall_application_text_current_user_private_profile" msgid="867004464945674674">"Želite li deinstalirati ovu aplikaciju iz svojeg privatnog prostora?"</string>
<string name="uninstalling_notification_channel" msgid="840153394325714653">"Deinstaliranja u tijeku"</string>
<string name="uninstall_failure_notification_channel" msgid="1136405866767576588">"Neuspjela deinstaliranja"</string>
<string name="uninstalling" msgid="8709566347688966845">"Deinstaliranje…"</string>
@@ -106,4 +107,21 @@
<string name="unarchive_application_title" msgid="7958278328280721421">"Želite li vratiti aplikaciju <xliff:g id="APPNAME">%1$s</xliff:g> putem aplikacije <xliff:g id="INSTALLERNAME">%1$s</xliff:g>?"</string>
<string name="unarchive_body_text" msgid="8244155079861708964">"Ova aplikacija počet će se preuzimati u pozadini"</string>
<string name="restore" msgid="8460854736328970444">"Vrati"</string>
+ <string name="unarchive_error_offline_title" msgid="4021785324565678605">"Niste povezani s internetom"</string>
+ <string name="unarchive_error_offline_body" msgid="255717000519772755">"Aplikacija će se automatski vratiti kad se povežete s internetom"</string>
+ <string name="unarchive_error_generic_title" msgid="7123457671482449992">"Nešto nije u redu"</string>
+ <string name="unarchive_error_generic_body" msgid="4486803312463813079">"Došlo je do problema s vraćanjem aplikacije"</string>
+ <string name="unarchive_error_storage_title" msgid="5080723357273852630">"Nema dovoljno prostora za pohranu"</string>
+ <string name="unarchive_error_storage_body" msgid="6879544407568780524">"Da biste vratili aplikaciju, možete osloboditi prostor za pohranu na ovom uređaju. Potreban prostor za pohranu: <xliff:g id="BYTES">%1$s</xliff:g>"</string>
+ <string name="unarchive_action_required_title" msgid="4971245740162604619">"Potrebna je radnja"</string>
+ <string name="unarchive_action_required_body" msgid="1679431572983989231">"Da biste vratili aplikaciju, slijedite upute u nastavku"</string>
+ <string name="unarchive_error_installer_disabled_title" msgid="4815715617014985605">"<xliff:g id="INSTALLERNAME">%1$s</xliff:g> – onemogućeno"</string>
+ <!-- no translation found for unarchive_error_installer_disabled_body (4820821285907011729) -->
+ <skip />
+ <string name="unarchive_error_installer_uninstalled_title" msgid="3748354109176326489">"<xliff:g id="INSTALLERNAME">%1$s</xliff:g> – deinstalirano"</string>
+ <string name="unarchive_error_installer_uninstalled_body" msgid="944733542444183204">"Da biste vratili aplikaciju, instalirajte sljedeće: <xliff:g id="INSTALLERNAME">%1$s</xliff:g>"</string>
+ <string name="unarchive_action_required_continue" msgid="5711202111224184257">"Nastavi"</string>
+ <string name="unarchive_clear_storage_button" msgid="1549537154535608744">"Izbriši pohranu"</string>
+ <string name="unarchive_settings_button" msgid="3504171760009177425">"Postavke"</string>
+ <string name="close" msgid="5214897374055647996">"Zatvori"</string>
</resources>
diff --git a/packages/PackageInstaller/res/values-hu/strings.xml b/packages/PackageInstaller/res/values-hu/strings.xml
index ea8cfc7..e873526 100644
--- a/packages/PackageInstaller/res/values-hu/strings.xml
+++ b/packages/PackageInstaller/res/values-hu/strings.xml
@@ -66,6 +66,7 @@
<string name="uninstall_keep_data" msgid="7002379587465487550">"<xliff:g id="SIZE">%1$s</xliff:g> alkalmazásadat megtartása."</string>
<string name="uninstall_application_text_current_user_clone_profile" msgid="835170400160011636">"Szeretné törölni ezt az alkalmazást?"</string>
<string name="uninstall_application_text_with_clone_instance" msgid="6944473334273349036">"Eltávolítja ezt az alkalmazást? A klónozott <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g> is törlésre kerül."</string>
+ <string name="uninstall_application_text_current_user_private_profile" msgid="867004464945674674">"Eltávolítja ezt az alkalmazást a privát területről?"</string>
<string name="uninstalling_notification_channel" msgid="840153394325714653">"Futó eltávolítások"</string>
<string name="uninstall_failure_notification_channel" msgid="1136405866767576588">"Sikertelen telepítések"</string>
<string name="uninstalling" msgid="8709566347688966845">"Eltávolítás…"</string>
@@ -106,4 +107,21 @@
<string name="unarchive_application_title" msgid="7958278328280721421">"Visszaállítja a(z) <xliff:g id="APPNAME">%1$s</xliff:g> appot innen: <xliff:g id="INSTALLERNAME">%1$s</xliff:g>?"</string>
<string name="unarchive_body_text" msgid="8244155079861708964">"A háttérben megkezdődik az app letöltése"</string>
<string name="restore" msgid="8460854736328970444">"Visszaállítás"</string>
+ <string name="unarchive_error_offline_title" msgid="4021785324565678605">"Az eszköz offline állapotban van"</string>
+ <string name="unarchive_error_offline_body" msgid="255717000519772755">"Automatikusan megtörténik az alkalmazás visszaállítása, amikor Ön csatlakozik az internethez."</string>
+ <string name="unarchive_error_generic_title" msgid="7123457671482449992">"Hiba történt"</string>
+ <string name="unarchive_error_generic_body" msgid="4486803312463813079">"Hiba történt az alkalmazás visszaállítása során."</string>
+ <string name="unarchive_error_storage_title" msgid="5080723357273852630">"Nincs elegendő tárhely"</string>
+ <string name="unarchive_error_storage_body" msgid="6879544407568780524">"Az alkalmazás visszaállításához szabadítson fel tárhelyet ezen az eszközön. Szükséges tárhely: <xliff:g id="BYTES">%1$s</xliff:g>."</string>
+ <string name="unarchive_action_required_title" msgid="4971245740162604619">"Fontos teendő"</string>
+ <string name="unarchive_action_required_body" msgid="1679431572983989231">"Az alkalmazás visszaállításához kövesse a következő lépéseket."</string>
+ <string name="unarchive_error_installer_disabled_title" msgid="4815715617014985605">"A(z) <xliff:g id="INSTALLERNAME">%1$s</xliff:g> le van tiltva"</string>
+ <!-- no translation found for unarchive_error_installer_disabled_body (4820821285907011729) -->
+ <skip />
+ <string name="unarchive_error_installer_uninstalled_title" msgid="3748354109176326489">"A(z) <xliff:g id="INSTALLERNAME">%1$s</xliff:g> nincs telepítve"</string>
+ <string name="unarchive_error_installer_uninstalled_body" msgid="944733542444183204">"Az alkalmazás app visszaállításához telepítse a következőt: <xliff:g id="INSTALLERNAME">%1$s</xliff:g>."</string>
+ <string name="unarchive_action_required_continue" msgid="5711202111224184257">"Tovább"</string>
+ <string name="unarchive_clear_storage_button" msgid="1549537154535608744">"Tárhely ürítése"</string>
+ <string name="unarchive_settings_button" msgid="3504171760009177425">"Beállítások"</string>
+ <string name="close" msgid="5214897374055647996">"Bezárás"</string>
</resources>
diff --git a/packages/PackageInstaller/res/values-hy/strings.xml b/packages/PackageInstaller/res/values-hy/strings.xml
index a447371..cccf6b6 100644
--- a/packages/PackageInstaller/res/values-hy/strings.xml
+++ b/packages/PackageInstaller/res/values-hy/strings.xml
@@ -66,6 +66,7 @@
<string name="uninstall_keep_data" msgid="7002379587465487550">"Չհեռացնել հավելվածների տվյալները (<xliff:g id="SIZE">%1$s</xliff:g>):"</string>
<string name="uninstall_application_text_current_user_clone_profile" msgid="835170400160011636">"Ջնջե՞լ այս հավելվածը"</string>
<string name="uninstall_application_text_with_clone_instance" msgid="6944473334273349036">"Ապատեղադրե՞լ այս հավելվածը։ <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g>-ի կլոնը նույնպես կջնջվի։"</string>
+ <string name="uninstall_application_text_current_user_private_profile" msgid="867004464945674674">"Ապատեղադրե՞լ այս հավելվածը ձեր անձնական տարածքից"</string>
<string name="uninstalling_notification_channel" msgid="840153394325714653">"Ընթացիկ ապատեղադրումներ"</string>
<string name="uninstall_failure_notification_channel" msgid="1136405866767576588">"Ձախողված ապատեղադրումներ"</string>
<string name="uninstalling" msgid="8709566347688966845">"Ապատեղադրվում է…"</string>
@@ -106,4 +107,21 @@
<string name="unarchive_application_title" msgid="7958278328280721421">"Վերականգնե՞լ <xliff:g id="APPNAME">%1$s</xliff:g> հավելվածը <xliff:g id="INSTALLERNAME">%1$s</xliff:g>-ից"</string>
<string name="unarchive_body_text" msgid="8244155079861708964">"Այս հավելվածը կներբեռնվի ֆոնային ռեժիմում"</string>
<string name="restore" msgid="8460854736328970444">"Վերականգնել"</string>
+ <string name="unarchive_error_offline_title" msgid="4021785324565678605">"Կապ չկա"</string>
+ <string name="unarchive_error_offline_body" msgid="255717000519772755">"Այս հավելվածն ավտոմատ կվերականգնվի, երբ միանաք ինտերնետին"</string>
+ <string name="unarchive_error_generic_title" msgid="7123457671482449992">"Սխալ առաջացավ"</string>
+ <string name="unarchive_error_generic_body" msgid="4486803312463813079">"Չհաջողվեց վերականգնել այս հավելվածը"</string>
+ <string name="unarchive_error_storage_title" msgid="5080723357273852630">"Բավարար տարածք չկա"</string>
+ <string name="unarchive_error_storage_body" msgid="6879544407568780524">"Հավելվածը վերականգնելու համար տարածք ազատեք սարքում։ Պահանջվում է <xliff:g id="BYTES">%1$s</xliff:g>։"</string>
+ <string name="unarchive_action_required_title" msgid="4971245740162604619">"Պահանջվում է գործողություն"</string>
+ <string name="unarchive_action_required_body" msgid="1679431572983989231">"Այս հավելվածը վերականգնելու համար կատարեք հաջորդ քայլերը"</string>
+ <string name="unarchive_error_installer_disabled_title" msgid="4815715617014985605">"<xliff:g id="INSTALLERNAME">%1$s</xliff:g> հավելվածն անջատված է"</string>
+ <!-- no translation found for unarchive_error_installer_disabled_body (4820821285907011729) -->
+ <skip />
+ <string name="unarchive_error_installer_uninstalled_title" msgid="3748354109176326489">"<xliff:g id="INSTALLERNAME">%1$s</xliff:g> հավելվածն ապատեղադրված է"</string>
+ <string name="unarchive_error_installer_uninstalled_body" msgid="944733542444183204">"Այս հավելվածը վերականգնելու համար տեղադրեք <xliff:g id="INSTALLERNAME">%1$s</xliff:g> հավելվածը"</string>
+ <string name="unarchive_action_required_continue" msgid="5711202111224184257">"Շարունակել"</string>
+ <string name="unarchive_clear_storage_button" msgid="1549537154535608744">"Մաքրել պահոցը"</string>
+ <string name="unarchive_settings_button" msgid="3504171760009177425">"Կարգավորումներ"</string>
+ <string name="close" msgid="5214897374055647996">"Փակել"</string>
</resources>
diff --git a/packages/PackageInstaller/res/values-in/strings.xml b/packages/PackageInstaller/res/values-in/strings.xml
index 9e24424..5ab5649 100644
--- a/packages/PackageInstaller/res/values-in/strings.xml
+++ b/packages/PackageInstaller/res/values-in/strings.xml
@@ -66,6 +66,7 @@
<string name="uninstall_keep_data" msgid="7002379587465487550">"Pertahankan data aplikasi sebesar <xliff:g id="SIZE">%1$s</xliff:g>."</string>
<string name="uninstall_application_text_current_user_clone_profile" msgid="835170400160011636">"Ingin menghapus aplikasi ini?"</string>
<string name="uninstall_application_text_with_clone_instance" msgid="6944473334273349036">"Ingin meng-uninstal aplikasi ini? Clone <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g> juga akan dihapus."</string>
+ <string name="uninstall_application_text_current_user_private_profile" msgid="867004464945674674">"Ingin meng-uninstal aplikasi ini dari ruang pribadi?"</string>
<string name="uninstalling_notification_channel" msgid="840153394325714653">"Menjalankan proses uninstal"</string>
<string name="uninstall_failure_notification_channel" msgid="1136405866767576588">"Proses uninstal yang gagal"</string>
<string name="uninstalling" msgid="8709566347688966845">"Meng-uninstal..."</string>
@@ -106,4 +107,21 @@
<string name="unarchive_application_title" msgid="7958278328280721421">"Pulihkan <xliff:g id="APPNAME">%1$s</xliff:g> dari <xliff:g id="INSTALLERNAME">%1$s</xliff:g>?"</string>
<string name="unarchive_body_text" msgid="8244155079861708964">"Aplikasi ini akan mulai didownload di latar belakang"</string>
<string name="restore" msgid="8460854736328970444">"Pulihkan"</string>
+ <string name="unarchive_error_offline_title" msgid="4021785324565678605">"Anda offline"</string>
+ <string name="unarchive_error_offline_body" msgid="255717000519772755">"Aplikasi ini akan otomatis dipulihkan saat Anda terhubung ke internet"</string>
+ <string name="unarchive_error_generic_title" msgid="7123457671482449992">"Terjadi error"</string>
+ <string name="unarchive_error_generic_body" msgid="4486803312463813079">"Terjadi error saat mencoba memulihkan aplikasi ini"</string>
+ <string name="unarchive_error_storage_title" msgid="5080723357273852630">"Penyimpanan tidak cukup"</string>
+ <string name="unarchive_error_storage_body" msgid="6879544407568780524">"Untuk memulihkan aplikasi ini, Anda perlu mengosongkan ruang penyimpanan di perangkat ini. Penyimpanan yang diperlukan: <xliff:g id="BYTES">%1$s</xliff:g>"</string>
+ <string name="unarchive_action_required_title" msgid="4971245740162604619">"Tindakan diperlukan"</string>
+ <string name="unarchive_action_required_body" msgid="1679431572983989231">"Ikuti langkah berikutnya untuk memulihkan aplikasi ini"</string>
+ <string name="unarchive_error_installer_disabled_title" msgid="4815715617014985605">"<xliff:g id="INSTALLERNAME">%1$s</xliff:g> dinonaktifkan"</string>
+ <!-- no translation found for unarchive_error_installer_disabled_body (4820821285907011729) -->
+ <skip />
+ <string name="unarchive_error_installer_uninstalled_title" msgid="3748354109176326489">"<xliff:g id="INSTALLERNAME">%1$s</xliff:g> diuninstal"</string>
+ <string name="unarchive_error_installer_uninstalled_body" msgid="944733542444183204">"Untuk memulihkan aplikasi ini, Anda harus menginstal <xliff:g id="INSTALLERNAME">%1$s</xliff:g>"</string>
+ <string name="unarchive_action_required_continue" msgid="5711202111224184257">"Lanjutkan"</string>
+ <string name="unarchive_clear_storage_button" msgid="1549537154535608744">"Hapus penyimpanan"</string>
+ <string name="unarchive_settings_button" msgid="3504171760009177425">"Setelan"</string>
+ <string name="close" msgid="5214897374055647996">"Tutup"</string>
</resources>
diff --git a/packages/PackageInstaller/res/values-is/strings.xml b/packages/PackageInstaller/res/values-is/strings.xml
index c24f284..3822994 100644
--- a/packages/PackageInstaller/res/values-is/strings.xml
+++ b/packages/PackageInstaller/res/values-is/strings.xml
@@ -66,6 +66,7 @@
<string name="uninstall_keep_data" msgid="7002379587465487550">"Halda <xliff:g id="SIZE">%1$s</xliff:g> af forritagögnum."</string>
<string name="uninstall_application_text_current_user_clone_profile" msgid="835170400160011636">"Viltu eyða þessu forriti?"</string>
<string name="uninstall_application_text_with_clone_instance" msgid="6944473334273349036">"Viltu fjarlægja þetta forrit? Afriti af <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g> verður einnig eytt."</string>
+ <string name="uninstall_application_text_current_user_private_profile" msgid="867004464945674674">"Viltu fjarlægja þetta forrit úr einkarýminu?"</string>
<string name="uninstalling_notification_channel" msgid="840153394325714653">"Fjarlægingar í gangi"</string>
<string name="uninstall_failure_notification_channel" msgid="1136405866767576588">"Fjarlægingar sem mistókust"</string>
<string name="uninstalling" msgid="8709566347688966845">"Fjarlægir…"</string>
@@ -106,4 +107,21 @@
<string name="unarchive_application_title" msgid="7958278328280721421">"Endurheimta <xliff:g id="APPNAME">%1$s</xliff:g> úr <xliff:g id="INSTALLERNAME">%1$s</xliff:g>?"</string>
<string name="unarchive_body_text" msgid="8244155079861708964">"Forritið verður sótt í bakgrunni"</string>
<string name="restore" msgid="8460854736328970444">"Endurheimta"</string>
+ <string name="unarchive_error_offline_title" msgid="4021785324565678605">"Þú ert ekki á netinu"</string>
+ <string name="unarchive_error_offline_body" msgid="255717000519772755">"Þetta forrit verður endurheimt sjálfkrafa þegar þú tengist netinu"</string>
+ <string name="unarchive_error_generic_title" msgid="7123457671482449992">"Eitthvað fór úrskeiðis"</string>
+ <string name="unarchive_error_generic_body" msgid="4486803312463813079">"Vandamál kom upp við að endurheimta þetta forrit"</string>
+ <string name="unarchive_error_storage_title" msgid="5080723357273852630">"Ekki nógu mikið geymslurými"</string>
+ <string name="unarchive_error_storage_body" msgid="6879544407568780524">"Til að endurheimta þetta forrit geturðu losað um pláss í þessu tæki. Geymslurýmið sem þarf: <xliff:g id="BYTES">%1$s</xliff:g>"</string>
+ <string name="unarchive_action_required_title" msgid="4971245740162604619">"Aðgerðar krafist"</string>
+ <string name="unarchive_action_required_body" msgid="1679431572983989231">"Fylgdu næstu skrefum til að endurheimta þetta forrit"</string>
+ <string name="unarchive_error_installer_disabled_title" msgid="4815715617014985605">"Slökkt er á <xliff:g id="INSTALLERNAME">%1$s</xliff:g>"</string>
+ <!-- no translation found for unarchive_error_installer_disabled_body (4820821285907011729) -->
+ <skip />
+ <string name="unarchive_error_installer_uninstalled_title" msgid="3748354109176326489">"Búið er að fjarlægja <xliff:g id="INSTALLERNAME">%1$s</xliff:g>"</string>
+ <string name="unarchive_error_installer_uninstalled_body" msgid="944733542444183204">"Þú þarft að setja upp <xliff:g id="INSTALLERNAME">%1$s</xliff:g> til að endurheimta þetta forrit"</string>
+ <string name="unarchive_action_required_continue" msgid="5711202111224184257">"Halda áfram"</string>
+ <string name="unarchive_clear_storage_button" msgid="1549537154535608744">"Hreinsa geymslu"</string>
+ <string name="unarchive_settings_button" msgid="3504171760009177425">"Stillingar"</string>
+ <string name="close" msgid="5214897374055647996">"Loka"</string>
</resources>
diff --git a/packages/PackageInstaller/res/values-it/strings.xml b/packages/PackageInstaller/res/values-it/strings.xml
index 604d88a..669a8db 100644
--- a/packages/PackageInstaller/res/values-it/strings.xml
+++ b/packages/PackageInstaller/res/values-it/strings.xml
@@ -66,6 +66,7 @@
<string name="uninstall_keep_data" msgid="7002379587465487550">"Mantieni <xliff:g id="SIZE">%1$s</xliff:g> di dati delle app."</string>
<string name="uninstall_application_text_current_user_clone_profile" msgid="835170400160011636">"Vuoi eliminare questa app?"</string>
<string name="uninstall_application_text_with_clone_instance" msgid="6944473334273349036">"Vuoi disinstallare questa app? Verrà eliminato anche il clone di <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g>."</string>
+ <string name="uninstall_application_text_current_user_private_profile" msgid="867004464945674674">"Vuoi disinstallare questa app dal tuo spazio privato?"</string>
<string name="uninstalling_notification_channel" msgid="840153394325714653">"Disinstallazioni in esecuzione"</string>
<string name="uninstall_failure_notification_channel" msgid="1136405866767576588">"Disinstallazioni non riuscite"</string>
<string name="uninstalling" msgid="8709566347688966845">"Disinstallazione…"</string>
@@ -106,4 +107,21 @@
<string name="unarchive_application_title" msgid="7958278328280721421">"Ripristinare <xliff:g id="APPNAME">%1$s</xliff:g> da <xliff:g id="INSTALLERNAME">%1$s</xliff:g>?"</string>
<string name="unarchive_body_text" msgid="8244155079861708964">"Il download di quest\'app inizierà in background"</string>
<string name="restore" msgid="8460854736328970444">"Ripristina"</string>
+ <string name="unarchive_error_offline_title" msgid="4021785324565678605">"Sei offline"</string>
+ <string name="unarchive_error_offline_body" msgid="255717000519772755">"Quest\'app verrà ripristinata automaticamente quando il dispositivo è connesso a internet"</string>
+ <string name="unarchive_error_generic_title" msgid="7123457671482449992">"Si è verificato un problema"</string>
+ <string name="unarchive_error_generic_body" msgid="4486803312463813079">"Si è verificato un problema durante il ripristino di questa app"</string>
+ <string name="unarchive_error_storage_title" msgid="5080723357273852630">"Spazio di archiviazione insufficiente"</string>
+ <string name="unarchive_error_storage_body" msgid="6879544407568780524">"Per ripristinare quest\'app, puoi liberare spazio sul dispositivo. Spazio di archiviazione necessario: <xliff:g id="BYTES">%1$s</xliff:g>"</string>
+ <string name="unarchive_action_required_title" msgid="4971245740162604619">"Azione richiesta"</string>
+ <string name="unarchive_action_required_body" msgid="1679431572983989231">"Segui i passaggi successivi per ripristinare quest\'app"</string>
+ <string name="unarchive_error_installer_disabled_title" msgid="4815715617014985605">"<xliff:g id="INSTALLERNAME">%1$s</xliff:g> non è attivo"</string>
+ <!-- no translation found for unarchive_error_installer_disabled_body (4820821285907011729) -->
+ <skip />
+ <string name="unarchive_error_installer_uninstalled_title" msgid="3748354109176326489">"<xliff:g id="INSTALLERNAME">%1$s</xliff:g> è stato disinstallato"</string>
+ <string name="unarchive_error_installer_uninstalled_body" msgid="944733542444183204">"Per ripristinare quest\'app, dovrai installare <xliff:g id="INSTALLERNAME">%1$s</xliff:g>"</string>
+ <string name="unarchive_action_required_continue" msgid="5711202111224184257">"Continua"</string>
+ <string name="unarchive_clear_storage_button" msgid="1549537154535608744">"Libera spazio di archiviazione"</string>
+ <string name="unarchive_settings_button" msgid="3504171760009177425">"Impostazioni"</string>
+ <string name="close" msgid="5214897374055647996">"Chiudi"</string>
</resources>
diff --git a/packages/PackageInstaller/res/values-iw/strings.xml b/packages/PackageInstaller/res/values-iw/strings.xml
index 0e37b2e..1030e03 100644
--- a/packages/PackageInstaller/res/values-iw/strings.xml
+++ b/packages/PackageInstaller/res/values-iw/strings.xml
@@ -66,6 +66,7 @@
<string name="uninstall_keep_data" msgid="7002379587465487550">"שמירת <xliff:g id="SIZE">%1$s</xliff:g> מנתוני האפליקציה."</string>
<string name="uninstall_application_text_current_user_clone_profile" msgid="835170400160011636">"למחוק את האפליקציה הזו?"</string>
<string name="uninstall_application_text_with_clone_instance" msgid="6944473334273349036">"להסיר את ההתקנה של האפליקציה הזו? השכפול של <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g> גם יימחק."</string>
+ <string name="uninstall_application_text_current_user_private_profile" msgid="867004464945674674">"להסיר את ההתקנה של האפליקציה הזו מהמרחב הפרטי?"</string>
<string name="uninstalling_notification_channel" msgid="840153394325714653">"התקנות בתהליכי הסרה"</string>
<string name="uninstall_failure_notification_channel" msgid="1136405866767576588">"הסרות התקנה שנכשלו"</string>
<string name="uninstalling" msgid="8709566347688966845">"בתהליך הסרת התקנה..."</string>
@@ -106,4 +107,21 @@
<string name="unarchive_application_title" msgid="7958278328280721421">"לשחזר את <xliff:g id="APPNAME">%1$s</xliff:g> מ-<xliff:g id="INSTALLERNAME">%1$s</xliff:g>?"</string>
<string name="unarchive_body_text" msgid="8244155079861708964">"תהליך ההורדה של האפליקציה יתחיל ברקע"</string>
<string name="restore" msgid="8460854736328970444">"שחזור"</string>
+ <string name="unarchive_error_offline_title" msgid="4021785324565678605">"אין חיבור לאינטרנט"</string>
+ <string name="unarchive_error_offline_body" msgid="255717000519772755">"שחזור האפליקציה יתחיל אוטומטית כשהמכשיר יחובר לאינטרנט"</string>
+ <string name="unarchive_error_generic_title" msgid="7123457671482449992">"משהו השתבש"</string>
+ <string name="unarchive_error_generic_body" msgid="4486803312463813079">"הייתה בעיה בניסיון לשחזר את האפליקציה הזו"</string>
+ <string name="unarchive_error_storage_title" msgid="5080723357273852630">"אין מספיק נפח אחסון פנוי"</string>
+ <string name="unarchive_error_storage_body" msgid="6879544407568780524">"כדי לשחזר את האפליקציה הזו צריך לפנות מקום במכשיר. נפח האחסון הנדרש: <xliff:g id="BYTES">%1$s</xliff:g>"</string>
+ <string name="unarchive_action_required_title" msgid="4971245740162604619">"נדרשת פעולה"</string>
+ <string name="unarchive_action_required_body" msgid="1679431572983989231">"כדי לשחזר את האפליקציה הזו יש לפעול לפי השלבים הבאים"</string>
+ <string name="unarchive_error_installer_disabled_title" msgid="4815715617014985605">"<xliff:g id="INSTALLERNAME">%1$s</xliff:g> במצב מושבת"</string>
+ <!-- no translation found for unarchive_error_installer_disabled_body (4820821285907011729) -->
+ <skip />
+ <string name="unarchive_error_installer_uninstalled_title" msgid="3748354109176326489">"ההתקנה של <xliff:g id="INSTALLERNAME">%1$s</xliff:g> הוסרה"</string>
+ <string name="unarchive_error_installer_uninstalled_body" msgid="944733542444183204">"כדי לשחזר את האפליקציה הזו, צריך להתקין את <xliff:g id="INSTALLERNAME">%1$s</xliff:g>"</string>
+ <string name="unarchive_action_required_continue" msgid="5711202111224184257">"המשך"</string>
+ <string name="unarchive_clear_storage_button" msgid="1549537154535608744">"צריך לפנות נפח אחסון"</string>
+ <string name="unarchive_settings_button" msgid="3504171760009177425">"הגדרות"</string>
+ <string name="close" msgid="5214897374055647996">"סגירה"</string>
</resources>
diff --git a/packages/PackageInstaller/res/values-ja/strings.xml b/packages/PackageInstaller/res/values-ja/strings.xml
index 58e46a6..80b60ff 100644
--- a/packages/PackageInstaller/res/values-ja/strings.xml
+++ b/packages/PackageInstaller/res/values-ja/strings.xml
@@ -66,6 +66,7 @@
<string name="uninstall_keep_data" msgid="7002379587465487550">"アプリのデータ(<xliff:g id="SIZE">%1$s</xliff:g>)を保持"</string>
<string name="uninstall_application_text_current_user_clone_profile" msgid="835170400160011636">"このアプリを削除しますか?"</string>
<string name="uninstall_application_text_with_clone_instance" msgid="6944473334273349036">"このアプリをアンインストールしますか?<xliff:g id="PACKAGE_LABEL">%1$s</xliff:g> のクローンも削除されます。"</string>
+ <string name="uninstall_application_text_current_user_private_profile" msgid="867004464945674674">"このアプリをプライベート スペースからアンインストールしますか?"</string>
<string name="uninstalling_notification_channel" msgid="840153394325714653">"アンインストールを実行しています"</string>
<string name="uninstall_failure_notification_channel" msgid="1136405866767576588">"エラーになったアンインストール"</string>
<string name="uninstalling" msgid="8709566347688966845">"アンインストールしています…"</string>
@@ -106,4 +107,21 @@
<string name="unarchive_application_title" msgid="7958278328280721421">"<xliff:g id="INSTALLERNAME">%1$s</xliff:g> から <xliff:g id="APPNAME">%1$s</xliff:g> を復元しますか?"</string>
<string name="unarchive_body_text" msgid="8244155079861708964">"このアプリのダウンロードをバックグラウンドで開始します"</string>
<string name="restore" msgid="8460854736328970444">"復元する"</string>
+ <string name="unarchive_error_offline_title" msgid="4021785324565678605">"オフラインです"</string>
+ <string name="unarchive_error_offline_body" msgid="255717000519772755">"インターネットに接続すると、このアプリは自動的に復元されます"</string>
+ <string name="unarchive_error_generic_title" msgid="7123457671482449992">"エラーが発生しました"</string>
+ <string name="unarchive_error_generic_body" msgid="4486803312463813079">"このアプリを復元しようとしたときに問題が発生しました"</string>
+ <string name="unarchive_error_storage_title" msgid="5080723357273852630">"空き容量が不足しています"</string>
+ <string name="unarchive_error_storage_body" msgid="6879544407568780524">"このアプリを復元するには、このデバイスの空き容量を増やしてください。必要なストレージ: <xliff:g id="BYTES">%1$s</xliff:g>"</string>
+ <string name="unarchive_action_required_title" msgid="4971245740162604619">"必要な対応"</string>
+ <string name="unarchive_action_required_body" msgid="1679431572983989231">"このアプリを復元するには、次の手順を行います"</string>
+ <string name="unarchive_error_installer_disabled_title" msgid="4815715617014985605">"<xliff:g id="INSTALLERNAME">%1$s</xliff:g> は無効です"</string>
+ <!-- no translation found for unarchive_error_installer_disabled_body (4820821285907011729) -->
+ <skip />
+ <string name="unarchive_error_installer_uninstalled_title" msgid="3748354109176326489">"<xliff:g id="INSTALLERNAME">%1$s</xliff:g> はアンインストールされています"</string>
+ <string name="unarchive_error_installer_uninstalled_body" msgid="944733542444183204">"このアプリを復元するには、<xliff:g id="INSTALLERNAME">%1$s</xliff:g> をインストールする必要があります"</string>
+ <string name="unarchive_action_required_continue" msgid="5711202111224184257">"続行"</string>
+ <string name="unarchive_clear_storage_button" msgid="1549537154535608744">"ストレージの消去"</string>
+ <string name="unarchive_settings_button" msgid="3504171760009177425">"設定"</string>
+ <string name="close" msgid="5214897374055647996">"閉じる"</string>
</resources>
diff --git a/packages/PackageInstaller/res/values-ka/strings.xml b/packages/PackageInstaller/res/values-ka/strings.xml
index bbd63d1..cfe9050 100644
--- a/packages/PackageInstaller/res/values-ka/strings.xml
+++ b/packages/PackageInstaller/res/values-ka/strings.xml
@@ -66,6 +66,7 @@
<string name="uninstall_keep_data" msgid="7002379587465487550">"შენარჩუნდეს აპების მონაცემების <xliff:g id="SIZE">%1$s</xliff:g>."</string>
<string name="uninstall_application_text_current_user_clone_profile" msgid="835170400160011636">"გსურთ ამ აპის წაშლა?"</string>
<string name="uninstall_application_text_with_clone_instance" msgid="6944473334273349036">"გსურთ ამ აპის დეინსტალაცია? <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g> კლონი ასევე წაიშლება."</string>
+ <string name="uninstall_application_text_current_user_private_profile" msgid="867004464945674674">"გსურთ ამ აპის დეინსტალაცია თქვენი პირადი სივრციდან?"</string>
<string name="uninstalling_notification_channel" msgid="840153394325714653">"გაშვებული დეინსტალაციები"</string>
<string name="uninstall_failure_notification_channel" msgid="1136405866767576588">"შეუსრულებელი დეინსტალაციები"</string>
<string name="uninstalling" msgid="8709566347688966845">"მიმდინარეობს დეინსტალაცია…"</string>
@@ -106,4 +107,21 @@
<string name="unarchive_application_title" msgid="7958278328280721421">"აღვადგინოთ <xliff:g id="APPNAME">%1$s</xliff:g> <xliff:g id="INSTALLERNAME">%1$s</xliff:g>-დან?"</string>
<string name="unarchive_body_text" msgid="8244155079861708964">"ამ აპის ჩამოტვირთვა ფონურ რეჟიმში დაიწყება"</string>
<string name="restore" msgid="8460854736328970444">"აღდგენა"</string>
+ <string name="unarchive_error_offline_title" msgid="4021785324565678605">"თქვენ ხაზგარეშე რეჟიმში ხართ"</string>
+ <string name="unarchive_error_offline_body" msgid="255717000519772755">"ეს აპი ავტომატურად აღდგება, როცა დაუკავშირდებით ინტერნეტს"</string>
+ <string name="unarchive_error_generic_title" msgid="7123457671482449992">"წარმოიქმნა შეფერხება"</string>
+ <string name="unarchive_error_generic_body" msgid="4486803312463813079">"ამ აპის აღდგენისას წარმოიქმნა პრობლემა"</string>
+ <string name="unarchive_error_storage_title" msgid="5080723357273852630">"მეხსიერება საკმარისი არ არის"</string>
+ <string name="unarchive_error_storage_body" msgid="6879544407568780524">"ამ აპის აღსადგენად შეგიძლიათ, გამოათავისუფლოთ მეხსიერება ამ მოწყობილობაზე. საჭიროა მეხსიერება: <xliff:g id="BYTES">%1$s</xliff:g>"</string>
+ <string name="unarchive_action_required_title" msgid="4971245740162604619">"საჭიროა მოქმედება"</string>
+ <string name="unarchive_action_required_body" msgid="1679431572983989231">"ამ აპის აღსადგენად მიჰყევით შემდეგ ნაბიჯებს"</string>
+ <string name="unarchive_error_installer_disabled_title" msgid="4815715617014985605">"<xliff:g id="INSTALLERNAME">%1$s</xliff:g> გამორთულია"</string>
+ <!-- no translation found for unarchive_error_installer_disabled_body (4820821285907011729) -->
+ <skip />
+ <string name="unarchive_error_installer_uninstalled_title" msgid="3748354109176326489">"<xliff:g id="INSTALLERNAME">%1$s</xliff:g> დეინსტალირებულია"</string>
+ <string name="unarchive_error_installer_uninstalled_body" msgid="944733542444183204">"ამ აპის აღსადგენად უნდა დააინსტალიროთ <xliff:g id="INSTALLERNAME">%1$s</xliff:g>"</string>
+ <string name="unarchive_action_required_continue" msgid="5711202111224184257">"გაგრძელება"</string>
+ <string name="unarchive_clear_storage_button" msgid="1549537154535608744">"მეხსიერების გასუფთავება"</string>
+ <string name="unarchive_settings_button" msgid="3504171760009177425">"პარამეტრები"</string>
+ <string name="close" msgid="5214897374055647996">"დახურვა"</string>
</resources>
diff --git a/packages/PackageInstaller/res/values-kk/strings.xml b/packages/PackageInstaller/res/values-kk/strings.xml
index 02843b8..60f3e66 100644
--- a/packages/PackageInstaller/res/values-kk/strings.xml
+++ b/packages/PackageInstaller/res/values-kk/strings.xml
@@ -66,6 +66,7 @@
<string name="uninstall_keep_data" msgid="7002379587465487550">"Қолданба деректерін (<xliff:g id="SIZE">%1$s</xliff:g>) сақтау."</string>
<string name="uninstall_application_text_current_user_clone_profile" msgid="835170400160011636">"Осы қолданба жойылсын ба?"</string>
<string name="uninstall_application_text_with_clone_instance" msgid="6944473334273349036">"Осы қолданба жойылсын ба? <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g> клоны да жойылады."</string>
+ <string name="uninstall_application_text_current_user_private_profile" msgid="867004464945674674">"Осы құрылғыны жеке бөлмеңізден жойғыңыз келе ме?"</string>
<string name="uninstalling_notification_channel" msgid="840153394325714653">"Орындалып жатқан жою процестері"</string>
<string name="uninstall_failure_notification_channel" msgid="1136405866767576588">"Сәтсіз жою әрекеттері"</string>
<string name="uninstalling" msgid="8709566347688966845">"Жойылуда…"</string>
@@ -106,4 +107,21 @@
<string name="unarchive_application_title" msgid="7958278328280721421">"<xliff:g id="APPNAME">%1$s</xliff:g> қолданбасын <xliff:g id="INSTALLERNAME">%1$s</xliff:g> арқылы қалпына келтіру керек пе?"</string>
<string name="unarchive_body_text" msgid="8244155079861708964">"Бұл қолданба фондық режимде жүктеп алына бастайды."</string>
<string name="restore" msgid="8460854736328970444">"Қалпына келтіру"</string>
+ <string name="unarchive_error_offline_title" msgid="4021785324565678605">"Құрылғыңыз офлайн режимде"</string>
+ <string name="unarchive_error_offline_body" msgid="255717000519772755">"Бұл қолданба құрылғыңыз интернетке қосылғанда автоматты түрде қалпына келеді."</string>
+ <string name="unarchive_error_generic_title" msgid="7123457671482449992">"Бірдеңе дұрыс болмады"</string>
+ <string name="unarchive_error_generic_body" msgid="4486803312463813079">"Бұл құрылғыны қалпына келтіру үшін әрекет жасалғанда мәселе туындады."</string>
+ <string name="unarchive_error_storage_title" msgid="5080723357273852630">"Жадта орын жеткіліксіз"</string>
+ <string name="unarchive_error_storage_body" msgid="6879544407568780524">"Бұл қолданбаны қалпына келтіргіңіз келсе, осы құрылғыда орын босатуға болады. Қажетті жад көлемі: <xliff:g id="BYTES">%1$s</xliff:g>."</string>
+ <string name="unarchive_action_required_title" msgid="4971245740162604619">"Әрекет қажет"</string>
+ <string name="unarchive_action_required_body" msgid="1679431572983989231">"Бұл қолданбаны қалпына келтіру үшін келесі қадамдарды орындаңыз."</string>
+ <string name="unarchive_error_installer_disabled_title" msgid="4815715617014985605">"<xliff:g id="INSTALLERNAME">%1$s</xliff:g> өшірілген"</string>
+ <!-- no translation found for unarchive_error_installer_disabled_body (4820821285907011729) -->
+ <skip />
+ <string name="unarchive_error_installer_uninstalled_title" msgid="3748354109176326489">"<xliff:g id="INSTALLERNAME">%1$s</xliff:g> жойылған"</string>
+ <string name="unarchive_error_installer_uninstalled_body" msgid="944733542444183204">"Бұл қолданбаны қалпына келтіру үшін орнатқышты (<xliff:g id="INSTALLERNAME">%1$s</xliff:g>) орнатуыңыз керек."</string>
+ <string name="unarchive_action_required_continue" msgid="5711202111224184257">"Жалғастыру"</string>
+ <string name="unarchive_clear_storage_button" msgid="1549537154535608744">"Жадты тазалау"</string>
+ <string name="unarchive_settings_button" msgid="3504171760009177425">"Параметрлер"</string>
+ <string name="close" msgid="5214897374055647996">"Жабу"</string>
</resources>
diff --git a/packages/PackageInstaller/res/values-km/strings.xml b/packages/PackageInstaller/res/values-km/strings.xml
index bb84976..c7a2b87 100644
--- a/packages/PackageInstaller/res/values-km/strings.xml
+++ b/packages/PackageInstaller/res/values-km/strings.xml
@@ -66,6 +66,7 @@
<string name="uninstall_keep_data" msgid="7002379587465487550">"រក្សាទុកទិន្នន័យកម្មវិធីទំហំ <xliff:g id="SIZE">%1$s</xliff:g>។"</string>
<string name="uninstall_application_text_current_user_clone_profile" msgid="835170400160011636">"តើអ្នកចង់លុបកម្មវិធីនេះដែរឬទេ?"</string>
<string name="uninstall_application_text_with_clone_instance" msgid="6944473334273349036">"តើអ្នកចង់លុបកម្មវិធីនេះដែរឬទេ? ក្លូន <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g> ក៏នឹងត្រូវបានលុបផងដែរ។"</string>
+ <string name="uninstall_application_text_current_user_private_profile" msgid="867004464945674674">"តើអ្នកចង់លុបកម្មវិធីនេះចេញពី private space របស់អ្នកដែរទេ?"</string>
<string name="uninstalling_notification_channel" msgid="840153394325714653">"កំពុងដំណើរការការលុប"</string>
<string name="uninstall_failure_notification_channel" msgid="1136405866767576588">"ការលុបដែលបរាជ័យ"</string>
<string name="uninstalling" msgid="8709566347688966845">"កំពុងលុប…"</string>
@@ -106,4 +107,21 @@
<string name="unarchive_application_title" msgid="7958278328280721421">"ស្ដារ <xliff:g id="APPNAME">%1$s</xliff:g> ពី <xliff:g id="INSTALLERNAME">%1$s</xliff:g> ឬ?"</string>
<string name="unarchive_body_text" msgid="8244155079861708964">"កម្មវិធីនេះនឹងចាប់ផ្ដើមទាញយកនៅផ្ទៃខាងក្រោយ"</string>
<string name="restore" msgid="8460854736328970444">"ស្ដារ"</string>
+ <string name="unarchive_error_offline_title" msgid="4021785324565678605">"អ្នកគ្មានអ៊ីនធឺណិតទេ"</string>
+ <string name="unarchive_error_offline_body" msgid="255717000519772755">"កម្មវិធីនេះនឹងស្ដារដោយស្វ័យប្រវត្តិ នៅពេលអ្នកភ្ជាប់អ៊ីនធឺណិត"</string>
+ <string name="unarchive_error_generic_title" msgid="7123457671482449992">"មានអ្វីមួយខុសប្រក្រតី"</string>
+ <string name="unarchive_error_generic_body" msgid="4486803312463813079">"មានបញ្ហាក្នុងការព្យាយាមស្ដារកម្មវិធីនេះ"</string>
+ <string name="unarchive_error_storage_title" msgid="5080723357273852630">"ទំហំផ្ទុកមិនគ្រប់គ្រាន់"</string>
+ <string name="unarchive_error_storage_body" msgid="6879544407568780524">"ដើម្បីស្ដារកម្មវិធីនេះ អ្នកត្រូវបង្កើនទំហំផ្ទុកទំនេរនៅលើឧបករណ៍នេះ។ តម្រូវឱ្យមានទំហំផ្ទុក៖ <xliff:g id="BYTES">%1$s</xliff:g>"</string>
+ <string name="unarchive_action_required_title" msgid="4971245740162604619">"សកម្មភាពដែលតម្រូវឱ្យធ្វើ"</string>
+ <string name="unarchive_action_required_body" msgid="1679431572983989231">"អនុវត្តតាមជំហានបន្ទាប់ ដើម្បីស្ដារកម្មវិធីនេះ"</string>
+ <string name="unarchive_error_installer_disabled_title" msgid="4815715617014985605">"<xliff:g id="INSTALLERNAME">%1$s</xliff:g> ត្រូវបានបិទ"</string>
+ <!-- no translation found for unarchive_error_installer_disabled_body (4820821285907011729) -->
+ <skip />
+ <string name="unarchive_error_installer_uninstalled_title" msgid="3748354109176326489">"<xliff:g id="INSTALLERNAME">%1$s</xliff:g> ត្រូវបានលុប"</string>
+ <string name="unarchive_error_installer_uninstalled_body" msgid="944733542444183204">"ដើម្បីស្ដារកម្មវិធីនេះ អ្នកនឹងត្រូវដំឡើង <xliff:g id="INSTALLERNAME">%1$s</xliff:g>"</string>
+ <string name="unarchive_action_required_continue" msgid="5711202111224184257">"បន្ត"</string>
+ <string name="unarchive_clear_storage_button" msgid="1549537154535608744">"សម្អាតទំហំផ្ទុក"</string>
+ <string name="unarchive_settings_button" msgid="3504171760009177425">"ការកំណត់"</string>
+ <string name="close" msgid="5214897374055647996">"បិទ"</string>
</resources>
diff --git a/packages/PackageInstaller/res/values-kn/strings.xml b/packages/PackageInstaller/res/values-kn/strings.xml
index 476b45d..200edf0 100644
--- a/packages/PackageInstaller/res/values-kn/strings.xml
+++ b/packages/PackageInstaller/res/values-kn/strings.xml
@@ -66,6 +66,7 @@
<string name="uninstall_keep_data" msgid="7002379587465487550">"ಆ್ಯಪ್ ಡೇಟಾದಲ್ಲಿ <xliff:g id="SIZE">%1$s</xliff:g> ಇರಿಸಿಕೊಳ್ಳಿ."</string>
<string name="uninstall_application_text_current_user_clone_profile" msgid="835170400160011636">"ನೀವು ಈ ಆ್ಯಪ್ ಅನ್ನು ಅಳಿಸಲು ಬಯಸುತ್ತೀರಾ?"</string>
<string name="uninstall_application_text_with_clone_instance" msgid="6944473334273349036">"ನೀವು ಈ ಆ್ಯಪ್ ಅನ್ನು ಅನ್ಇನ್ಸ್ಟಾಲ್ ಮಾಡಲು ಬಯಸುತ್ತೀರಾ? <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g> ಕ್ಲೋನ್ ಅನ್ನು ಸಹ ಅಳಿಸಲಾಗುತ್ತದೆ."</string>
+ <string name="uninstall_application_text_current_user_private_profile" msgid="867004464945674674">"ನಿಮ್ಮ ಖಾಸಗಿ ಸ್ಪೇಸ್ನಿಂದ ಈ ಆ್ಯಪ್ ಅನ್ನು ಅನ್ಇನ್ಸ್ಟಾಲ್ ಮಾಡಲು ನೀವು ಬಯಸುತ್ತೀರಾ?"</string>
<string name="uninstalling_notification_channel" msgid="840153394325714653">"ಚಾಲನೆಯಲ್ಲಿರುವ ಅನ್ಇನ್ಸ್ಟಾಲ್ಗಳು"</string>
<string name="uninstall_failure_notification_channel" msgid="1136405866767576588">"ವಿಫಲಗೊಂಡ ಅನ್ಇನ್ಸ್ಟಾಲ್ಗಳು"</string>
<string name="uninstalling" msgid="8709566347688966845">"ಅನ್ಇನ್ಸ್ಟಾಲ್ ಮಾಡಲಾಗುತ್ತಿದೆ..."</string>
@@ -106,4 +107,21 @@
<string name="unarchive_application_title" msgid="7958278328280721421">"<xliff:g id="INSTALLERNAME">%1$s</xliff:g> ನಿಂದ <xliff:g id="APPNAME">%1$s</xliff:g> ಅನ್ನು ಮರುಸ್ಥಾಪಿಸಬೇಕೆ?"</string>
<string name="unarchive_body_text" msgid="8244155079861708964">"ಹಿನ್ನೆಲೆಯಲ್ಲಿ ಡೌನ್ಲೋಡ್ ಆಗಲು ಈ ಆ್ಯಪ್ ಪ್ರಾರಂಭವಾಗುತ್ತದೆ"</string>
<string name="restore" msgid="8460854736328970444">"ಮರುಸ್ಥಾಪಿಸಿ"</string>
+ <string name="unarchive_error_offline_title" msgid="4021785324565678605">"ನೀವು ಆಫ್ಲೈನ್ನಲ್ಲಿರುವಿರಿ"</string>
+ <string name="unarchive_error_offline_body" msgid="255717000519772755">"ನೀವು ಇಂಟರ್ನೆಟ್ಗೆ ಕನೆಕ್ಟ್ ಮಾಡಿದಾಗ, ಈ ಆ್ಯಪ್ ಸ್ವಯಂಚಾಲಿತವಾಗಿ ಮರುಸ್ಥಾಪನೆಯಾಗುತ್ತದೆ"</string>
+ <string name="unarchive_error_generic_title" msgid="7123457671482449992">"ಏನೋ ತಪ್ಪಾಗಿದೆ"</string>
+ <string name="unarchive_error_generic_body" msgid="4486803312463813079">"ಈ ಆ್ಯಪ್ ಅನ್ನು ಮರುಸ್ಥಾಪಿಸಲು ಪ್ರಯತ್ನಿಸುವಾಗ ಸಮಸ್ಯೆ ಕಂಡುಬಂದಿದೆ"</string>
+ <string name="unarchive_error_storage_title" msgid="5080723357273852630">"ಸಾಕಷ್ಟು ಸಂಗ್ರಹಣೆ ಇಲ್ಲ"</string>
+ <string name="unarchive_error_storage_body" msgid="6879544407568780524">"ಈ ಆ್ಯಪ್ ಅನ್ನು ಮರುಸ್ಥಾಪಿಸಲು, ನೀವು ಈ ಸಾಧನದಲ್ಲಿ ಸ್ಥಳಾವಕಾಶವನ್ನು ತೆರವುಗೊಳಿಸಬಹುದು. ಅಗತ್ಯವಿರುವ ಸಂಗ್ರಹಣೆ: <xliff:g id="BYTES">%1$s</xliff:g>"</string>
+ <string name="unarchive_action_required_title" msgid="4971245740162604619">"ಕ್ರಮದ ಅಗತ್ಯವಿದೆ"</string>
+ <string name="unarchive_action_required_body" msgid="1679431572983989231">"ಈ ಆ್ಯಪ್ ಅನ್ನು ಮರುಸ್ಥಾಪಿಸಲು ಮುಂದಿನ ಹಂತಗಳನ್ನು ಅನುಸರಿಸಿ"</string>
+ <string name="unarchive_error_installer_disabled_title" msgid="4815715617014985605">"<xliff:g id="INSTALLERNAME">%1$s</xliff:g> ಅನ್ನು ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಲಾಗಿದೆ"</string>
+ <!-- no translation found for unarchive_error_installer_disabled_body (4820821285907011729) -->
+ <skip />
+ <string name="unarchive_error_installer_uninstalled_title" msgid="3748354109176326489">"<xliff:g id="INSTALLERNAME">%1$s</xliff:g> ಅನ್ನು ಅನ್ಇನ್ಸ್ಟಾಲ್ ಮಾಡಲಾಗಿದೆ"</string>
+ <string name="unarchive_error_installer_uninstalled_body" msgid="944733542444183204">"ಈ ಆ್ಯಪ್ ಅನ್ನು ಮರುಸ್ಥಾಪಿಸಲು, ನೀವು <xliff:g id="INSTALLERNAME">%1$s</xliff:g> ಅನ್ನು ಇನ್ಸ್ಟಾಲ್ ಮಾಡುವ ಅಗತ್ಯವಿದೆ"</string>
+ <string name="unarchive_action_required_continue" msgid="5711202111224184257">"ಮುಂದುವರಿಸಿ"</string>
+ <string name="unarchive_clear_storage_button" msgid="1549537154535608744">"ಸಂಗ್ರಹಣೆಯನ್ನು ತೆರವುಗೊಳಿಸಿ"</string>
+ <string name="unarchive_settings_button" msgid="3504171760009177425">"ಸೆಟ್ಟಿಂಗ್ಗಳು"</string>
+ <string name="close" msgid="5214897374055647996">"ಮುಚ್ಚಿರಿ"</string>
</resources>
diff --git a/packages/PackageInstaller/res/values-ko/strings.xml b/packages/PackageInstaller/res/values-ko/strings.xml
index 7ae19ac..d449090 100644
--- a/packages/PackageInstaller/res/values-ko/strings.xml
+++ b/packages/PackageInstaller/res/values-ko/strings.xml
@@ -66,6 +66,7 @@
<string name="uninstall_keep_data" msgid="7002379587465487550">"앱 데이터 크기를 <xliff:g id="SIZE">%1$s</xliff:g>로 유지합니다."</string>
<string name="uninstall_application_text_current_user_clone_profile" msgid="835170400160011636">"이 앱을 삭제하시겠습니까?"</string>
<string name="uninstall_application_text_with_clone_instance" msgid="6944473334273349036">"이 앱을 제거하시겠습니까? <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g> 클론도 삭제됩니다."</string>
+ <string name="uninstall_application_text_current_user_private_profile" msgid="867004464945674674">"비공개 스페이스에서 이 앱을 제거하시겠습니까?"</string>
<string name="uninstalling_notification_channel" msgid="840153394325714653">"실행 중인 제거 작업"</string>
<string name="uninstall_failure_notification_channel" msgid="1136405866767576588">"실패한 제거 작업"</string>
<string name="uninstalling" msgid="8709566347688966845">"제거 중..."</string>
@@ -106,4 +107,21 @@
<string name="unarchive_application_title" msgid="7958278328280721421">"<xliff:g id="INSTALLERNAME">%1$s</xliff:g>에서 <xliff:g id="APPNAME">%1$s</xliff:g> 앱을 복원하시겠습니까?"</string>
<string name="unarchive_body_text" msgid="8244155079861708964">"백그라운드에서 앱이 다운로드되기 시작합니다"</string>
<string name="restore" msgid="8460854736328970444">"복원"</string>
+ <string name="unarchive_error_offline_title" msgid="4021785324565678605">"오프라인 상태"</string>
+ <string name="unarchive_error_offline_body" msgid="255717000519772755">"인터넷에 연결되면 이 앱은 자동으로 복원됩니다"</string>
+ <string name="unarchive_error_generic_title" msgid="7123457671482449992">"문제가 발생했습니다"</string>
+ <string name="unarchive_error_generic_body" msgid="4486803312463813079">"이 앱을 복원하려고 시도하던 중 문제가 발생했습니다"</string>
+ <string name="unarchive_error_storage_title" msgid="5080723357273852630">"저장용량 부족"</string>
+ <string name="unarchive_error_storage_body" msgid="6879544407568780524">"이 앱을 사용하려면 이 기기의 여유 공간을 확보해야 합니다 필요한 저장용량: <xliff:g id="BYTES">%1$s</xliff:g>"</string>
+ <string name="unarchive_action_required_title" msgid="4971245740162604619">"조치 필요"</string>
+ <string name="unarchive_action_required_body" msgid="1679431572983989231">"이 앱을 복원하려면 다음 단계를 따르세요"</string>
+ <string name="unarchive_error_installer_disabled_title" msgid="4815715617014985605">"<xliff:g id="INSTALLERNAME">%1$s</xliff:g> 사용 중지됨"</string>
+ <!-- no translation found for unarchive_error_installer_disabled_body (4820821285907011729) -->
+ <skip />
+ <string name="unarchive_error_installer_uninstalled_title" msgid="3748354109176326489">"<xliff:g id="INSTALLERNAME">%1$s</xliff:g> 제거됨"</string>
+ <string name="unarchive_error_installer_uninstalled_body" msgid="944733542444183204">"이 앱을 복원하려면 <xliff:g id="INSTALLERNAME">%1$s</xliff:g>를 설치해야 합니다"</string>
+ <string name="unarchive_action_required_continue" msgid="5711202111224184257">"계속"</string>
+ <string name="unarchive_clear_storage_button" msgid="1549537154535608744">"저장용량 비우기"</string>
+ <string name="unarchive_settings_button" msgid="3504171760009177425">"설정"</string>
+ <string name="close" msgid="5214897374055647996">"닫기"</string>
</resources>
diff --git a/packages/PackageInstaller/res/values-ky/strings.xml b/packages/PackageInstaller/res/values-ky/strings.xml
index faf3df2..952e617 100644
--- a/packages/PackageInstaller/res/values-ky/strings.xml
+++ b/packages/PackageInstaller/res/values-ky/strings.xml
@@ -66,6 +66,7 @@
<string name="uninstall_keep_data" msgid="7002379587465487550">"Колдонмонун <xliff:g id="SIZE">%1$s</xliff:g> дайындарын сактоо."</string>
<string name="uninstall_application_text_current_user_clone_profile" msgid="835170400160011636">"Бул колдонмону өчүрөсүзбү?"</string>
<string name="uninstall_application_text_with_clone_instance" msgid="6944473334273349036">"Бул колдонмону чыгарып саласызбы? <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g> клону да өчүрүлөт."</string>
+ <string name="uninstall_application_text_current_user_private_profile" msgid="867004464945674674">"Бул колдонмону жеке чөйрөдөн чыгарып саласызбы?"</string>
<string name="uninstalling_notification_channel" msgid="840153394325714653">"Чыгарылып салынууда"</string>
<string name="uninstall_failure_notification_channel" msgid="1136405866767576588">"Чыгарылып салынбай калгандар"</string>
<string name="uninstalling" msgid="8709566347688966845">"Чыгарылып салынууда…"</string>
@@ -106,4 +107,21 @@
<string name="unarchive_application_title" msgid="7958278328280721421">"<xliff:g id="APPNAME">%1$s</xliff:g> <xliff:g id="INSTALLERNAME">%1$s</xliff:g> платформасынан калыбына келтирилсинби?"</string>
<string name="unarchive_body_text" msgid="8244155079861708964">"Бул колдонмо фондо жүктөлүп алына баштайт"</string>
<string name="restore" msgid="8460854736328970444">"Калыбына келтирүү"</string>
+ <string name="unarchive_error_offline_title" msgid="4021785324565678605">"Интернет байланышыңыз жок"</string>
+ <string name="unarchive_error_offline_body" msgid="255717000519772755">"Интернетке туташканыңызда бул колдонмо автоматтык түрдө калыбына келтирилет"</string>
+ <string name="unarchive_error_generic_title" msgid="7123457671482449992">"Бир жерден ката кетти"</string>
+ <string name="unarchive_error_generic_body" msgid="4486803312463813079">"Бул колдонмону калыбына келтирүүдө маселе келип чыкты"</string>
+ <string name="unarchive_error_storage_title" msgid="5080723357273852630">"Сактагычта орун жетишсиз"</string>
+ <string name="unarchive_error_storage_body" msgid="6879544407568780524">"Бул колдонмону калыбына келтирүү үчүн түзмөктө орун бошотуңуз. Сактагыч талап кылынат: <xliff:g id="BYTES">%1$s</xliff:g>"</string>
+ <string name="unarchive_action_required_title" msgid="4971245740162604619">"Аракет талап кылынат"</string>
+ <string name="unarchive_action_required_body" msgid="1679431572983989231">"Бул колдонмону калыбына келтирүү үчүн кийинки кадамдарды аткарыңыз"</string>
+ <string name="unarchive_error_installer_disabled_title" msgid="4815715617014985605">"<xliff:g id="INSTALLERNAME">%1$s</xliff:g> өчүрүлгөн"</string>
+ <!-- no translation found for unarchive_error_installer_disabled_body (4820821285907011729) -->
+ <skip />
+ <string name="unarchive_error_installer_uninstalled_title" msgid="3748354109176326489">"<xliff:g id="INSTALLERNAME">%1$s</xliff:g> орнотулду"</string>
+ <string name="unarchive_error_installer_uninstalled_body" msgid="944733542444183204">"Бул колдонмону калыбына келтирүү үчүн <xliff:g id="INSTALLERNAME">%1$s</xliff:g> кызматын орнотуп алышыңыз керек"</string>
+ <string name="unarchive_action_required_continue" msgid="5711202111224184257">"Улантуу"</string>
+ <string name="unarchive_clear_storage_button" msgid="1549537154535608744">"Сактагычты тазалоо"</string>
+ <string name="unarchive_settings_button" msgid="3504171760009177425">"Параметрлер"</string>
+ <string name="close" msgid="5214897374055647996">"Жабуу"</string>
</resources>
diff --git a/packages/PackageInstaller/res/values-lo/strings.xml b/packages/PackageInstaller/res/values-lo/strings.xml
index e9b3e8e..55c10d4 100644
--- a/packages/PackageInstaller/res/values-lo/strings.xml
+++ b/packages/PackageInstaller/res/values-lo/strings.xml
@@ -66,6 +66,7 @@
<string name="uninstall_keep_data" msgid="7002379587465487550">"ຮັກສາຂະໜາດຂໍ້ມູນແອັບ <xliff:g id="SIZE">%1$s</xliff:g> ໄວ້."</string>
<string name="uninstall_application_text_current_user_clone_profile" msgid="835170400160011636">"ທ່ານຕ້ອງການລຶບແອັບນີ້ບໍ?"</string>
<string name="uninstall_application_text_with_clone_instance" msgid="6944473334273349036">"ທ່ານຕ້ອງການຖອນການຕິດຕັ້ງແອັບນີ້ບໍ່? <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g> ໂຄລນຈະຖືກລຶບນຳ."</string>
+ <string name="uninstall_application_text_current_user_private_profile" msgid="867004464945674674">"ທ່ານຕ້ອງການຖອນການຕິດຕັ້ງແອັບນີ້ຈາກພື້ນທີ່ສ່ວນຕົວຂອງທ່ານບໍ?"</string>
<string name="uninstalling_notification_channel" msgid="840153394325714653">"ກຳລັງຖອນການຕິດຕັ້ງ"</string>
<string name="uninstall_failure_notification_channel" msgid="1136405866767576588">"ຖອນການຕິດຕັ້ງບໍ່ສຳເລັດ"</string>
<string name="uninstalling" msgid="8709566347688966845">"ກຳລັງຖອນການຕິດຕັ້ງ..."</string>
@@ -106,4 +107,21 @@
<string name="unarchive_application_title" msgid="7958278328280721421">"ກູ້ຄືນ <xliff:g id="APPNAME">%1$s</xliff:g> ຈາກ <xliff:g id="INSTALLERNAME">%1$s</xliff:g> ບໍ?"</string>
<string name="unarchive_body_text" msgid="8244155079861708964">"ແອັບນີ້ຈະເລີ່ມດາວໂຫຼດໃນພື້ນຫຼັງ"</string>
<string name="restore" msgid="8460854736328970444">"ກູ້ຄືນ"</string>
+ <string name="unarchive_error_offline_title" msgid="4021785324565678605">"ທ່ານອອບລາຍຢູ່"</string>
+ <string name="unarchive_error_offline_body" msgid="255717000519772755">"ແອັບນີ້ຈະກູ້ຄືນໂດຍອັດຕະໂນມັດເມື່ອທ່ານເຊື່ອມຕໍ່ກັບອິນເຕີເນັດ"</string>
+ <string name="unarchive_error_generic_title" msgid="7123457671482449992">"ມີບາງຢ່າງຜິດພາດເກີດຂຶ້ນ"</string>
+ <string name="unarchive_error_generic_body" msgid="4486803312463813079">"ເກີດບັນຫາໃນລະຫວ່າງທີ່ພະຍາຍາມກູ້ຄືນແອັບນີ້"</string>
+ <string name="unarchive_error_storage_title" msgid="5080723357273852630">"ບ່ອນຈັດເກັບຂໍ້ມູນບໍ່ພຽງພໍ"</string>
+ <string name="unarchive_error_storage_body" msgid="6879544407568780524">"ເພື່ອກູ້ຄືນແອັບນີ້, ທ່ານສາມາດເພີ່ມພື້ນທີ່ຫວ່າງໃນອຸປະກອນນີ້ໄດ້. ໂດຍຈະຕ້ອງໃຊ້ບ່ອນຈັດເກັບຂໍ້ມູນ: <xliff:g id="BYTES">%1$s</xliff:g>"</string>
+ <string name="unarchive_action_required_title" msgid="4971245740162604619">"ຕ້ອງດຳເນີນການ"</string>
+ <string name="unarchive_action_required_body" msgid="1679431572983989231">"ປະຕິບັດຕາມຂັ້ນຕອນຕໍ່ໄປເພື່ອກູ້ຄືນແອັບນີ້"</string>
+ <string name="unarchive_error_installer_disabled_title" msgid="4815715617014985605">"<xliff:g id="INSTALLERNAME">%1$s</xliff:g> ຖືກປິດການນຳໃຊ້"</string>
+ <!-- no translation found for unarchive_error_installer_disabled_body (4820821285907011729) -->
+ <skip />
+ <string name="unarchive_error_installer_uninstalled_title" msgid="3748354109176326489">"<xliff:g id="INSTALLERNAME">%1$s</xliff:g> ຖືກຖອນການຕິດຕັ້ງ"</string>
+ <string name="unarchive_error_installer_uninstalled_body" msgid="944733542444183204">"ເພື່ອກູ້ຄືນແອັບນີ້, ທ່ານຈະຕ້ອງຕິດຕັ້ງ <xliff:g id="INSTALLERNAME">%1$s</xliff:g>"</string>
+ <string name="unarchive_action_required_continue" msgid="5711202111224184257">"ສືບຕໍ່"</string>
+ <string name="unarchive_clear_storage_button" msgid="1549537154535608744">"ລຶບລ້າງບ່ອນຈັດເກັບຂໍ້ມູນ"</string>
+ <string name="unarchive_settings_button" msgid="3504171760009177425">"ການຕັ້ງຄ່າ"</string>
+ <string name="close" msgid="5214897374055647996">"ປິດ"</string>
</resources>
diff --git a/packages/PackageInstaller/res/values-lt/strings.xml b/packages/PackageInstaller/res/values-lt/strings.xml
index 654dee0..1184bab 100644
--- a/packages/PackageInstaller/res/values-lt/strings.xml
+++ b/packages/PackageInstaller/res/values-lt/strings.xml
@@ -66,6 +66,7 @@
<string name="uninstall_keep_data" msgid="7002379587465487550">"Palikti <xliff:g id="SIZE">%1$s</xliff:g> programų duomenų."</string>
<string name="uninstall_application_text_current_user_clone_profile" msgid="835170400160011636">"Ar norite ištrinti šią programą?"</string>
<string name="uninstall_application_text_with_clone_instance" msgid="6944473334273349036">"Ar norite pašalinti šią programą? „<xliff:g id="PACKAGE_LABEL">%1$s</xliff:g>“ kopija taip pat bus ištrinta."</string>
+ <string name="uninstall_application_text_current_user_private_profile" msgid="867004464945674674">"Ar norite pašalinti šią programą iš privačios erdvės?"</string>
<string name="uninstalling_notification_channel" msgid="840153394325714653">"Vykdomi pašalinimai"</string>
<string name="uninstall_failure_notification_channel" msgid="1136405866767576588">"Nepavykę pašalinimai"</string>
<string name="uninstalling" msgid="8709566347688966845">"Pašalinama…"</string>
@@ -106,4 +107,21 @@
<string name="unarchive_application_title" msgid="7958278328280721421">"Atkurti „<xliff:g id="APPNAME">%1$s</xliff:g>“ iš „<xliff:g id="INSTALLERNAME">%1$s</xliff:g>“?"</string>
<string name="unarchive_body_text" msgid="8244155079861708964">"Šios programos atsisiuntimas bus pradėtas fone"</string>
<string name="restore" msgid="8460854736328970444">"Atkurti"</string>
+ <string name="unarchive_error_offline_title" msgid="4021785324565678605">"Esate neprisijungę"</string>
+ <string name="unarchive_error_offline_body" msgid="255717000519772755">"Ši programa bus automatiškai atkurta, kai prisijungsite prie interneto"</string>
+ <string name="unarchive_error_generic_title" msgid="7123457671482449992">"Kažkas nepavyko"</string>
+ <string name="unarchive_error_generic_body" msgid="4486803312463813079">"Bandant atkurti šią programą iškilo problema"</string>
+ <string name="unarchive_error_storage_title" msgid="5080723357273852630">"Trūksta saugyklos vietos"</string>
+ <string name="unarchive_error_storage_body" msgid="6879544407568780524">"Kad atkurtumėte šią programą, galite atlaisvinti vietos šiame įrenginyje. Reikia saugyklos vietos: <xliff:g id="BYTES">%1$s</xliff:g>"</string>
+ <string name="unarchive_action_required_title" msgid="4971245740162604619">"Būtina imtis veiksmų"</string>
+ <string name="unarchive_action_required_body" msgid="1679431572983989231">"Atlikite toliau nurodytus veiksmus, kad atkurtumėte šią programą"</string>
+ <string name="unarchive_error_installer_disabled_title" msgid="4815715617014985605">"„<xliff:g id="INSTALLERNAME">%1$s</xliff:g>“ išjungta"</string>
+ <!-- no translation found for unarchive_error_installer_disabled_body (4820821285907011729) -->
+ <skip />
+ <string name="unarchive_error_installer_uninstalled_title" msgid="3748354109176326489">"„<xliff:g id="INSTALLERNAME">%1$s</xliff:g>“ pašalinta"</string>
+ <string name="unarchive_error_installer_uninstalled_body" msgid="944733542444183204">"Kad atkurtumėte šią programą, turėsite įdiegti „<xliff:g id="INSTALLERNAME">%1$s</xliff:g>“"</string>
+ <string name="unarchive_action_required_continue" msgid="5711202111224184257">"Tęsti"</string>
+ <string name="unarchive_clear_storage_button" msgid="1549537154535608744">"Išvalyti saugyklą"</string>
+ <string name="unarchive_settings_button" msgid="3504171760009177425">"Nustatymai"</string>
+ <string name="close" msgid="5214897374055647996">"Uždaryti"</string>
</resources>
diff --git a/packages/PackageInstaller/res/values-lv/strings.xml b/packages/PackageInstaller/res/values-lv/strings.xml
index 2d319fc..71d25d4 100644
--- a/packages/PackageInstaller/res/values-lv/strings.xml
+++ b/packages/PackageInstaller/res/values-lv/strings.xml
@@ -66,6 +66,7 @@
<string name="uninstall_keep_data" msgid="7002379587465487550">"Iegūstiet <xliff:g id="SIZE">%1$s</xliff:g> (lietotnes dati)."</string>
<string name="uninstall_application_text_current_user_clone_profile" msgid="835170400160011636">"Vai vēlaties izdzēst šo lietotni?"</string>
<string name="uninstall_application_text_with_clone_instance" msgid="6944473334273349036">"Vai vēlaties atinstalēt šo lietotni? Tiks izdzēsts arī lietotnes <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g> klons."</string>
+ <string name="uninstall_application_text_current_user_private_profile" msgid="867004464945674674">"Vai vēlaties atinstalēt šo lietotni no savas privātās mapes?"</string>
<string name="uninstalling_notification_channel" msgid="840153394325714653">"Pašreizējās atinstalēšanas operācijas"</string>
<string name="uninstall_failure_notification_channel" msgid="1136405866767576588">"Nesekmīgi atinstalēšanas mēģinājumi"</string>
<string name="uninstalling" msgid="8709566347688966845">"Notiek atinstalēšana…"</string>
@@ -106,4 +107,21 @@
<string name="unarchive_application_title" msgid="7958278328280721421">"Vai atjaunot lietotni <xliff:g id="APPNAME">%1$s</xliff:g> no <xliff:g id="INSTALLERNAME">%1$s</xliff:g>?"</string>
<string name="unarchive_body_text" msgid="8244155079861708964">"Fonā tiks sākta šīs lietotnes lejupielāde."</string>
<string name="restore" msgid="8460854736328970444">"Atjaunot"</string>
+ <string name="unarchive_error_offline_title" msgid="4021785324565678605">"Jūs esat bezsaistē"</string>
+ <string name="unarchive_error_offline_body" msgid="255717000519772755">"Šī lietotne tiks automātiski atjaunota, kad izveidosiet savienojumu ar internetu."</string>
+ <string name="unarchive_error_generic_title" msgid="7123457671482449992">"Radās problēma"</string>
+ <string name="unarchive_error_generic_body" msgid="4486803312463813079">"Mēģinot atjaunot šo lietotni, radās problēma."</string>
+ <string name="unarchive_error_storage_title" msgid="5080723357273852630">"Krātuvē nepietiek vietas"</string>
+ <string name="unarchive_error_storage_body" msgid="6879544407568780524">"Lai atjaunotu šo lietotni, jums ir jāatbrīvo vieta ierīces krātuvē. Nepieciešamā vieta: <xliff:g id="BYTES">%1$s</xliff:g>."</string>
+ <string name="unarchive_action_required_title" msgid="4971245740162604619">"Nepieciešamā darbība"</string>
+ <string name="unarchive_action_required_body" msgid="1679431572983989231">"Veiciet tālāk minētās darbības, lai atjaunotu šo lietotni."</string>
+ <string name="unarchive_error_installer_disabled_title" msgid="4815715617014985605">"Programma <xliff:g id="INSTALLERNAME">%1$s</xliff:g> ir atspējota"</string>
+ <!-- no translation found for unarchive_error_installer_disabled_body (4820821285907011729) -->
+ <skip />
+ <string name="unarchive_error_installer_uninstalled_title" msgid="3748354109176326489">"Programma <xliff:g id="INSTALLERNAME">%1$s</xliff:g> ir atinstalēta"</string>
+ <string name="unarchive_error_installer_uninstalled_body" msgid="944733542444183204">"Lai atjaunotu šo lietotni, jums ir jāinstalē programma <xliff:g id="INSTALLERNAME">%1$s</xliff:g>."</string>
+ <string name="unarchive_action_required_continue" msgid="5711202111224184257">"Turpināt"</string>
+ <string name="unarchive_clear_storage_button" msgid="1549537154535608744">"Notīrīt krātuvi"</string>
+ <string name="unarchive_settings_button" msgid="3504171760009177425">"Iestatījumi"</string>
+ <string name="close" msgid="5214897374055647996">"Aizvērt"</string>
</resources>
diff --git a/packages/PackageInstaller/res/values-mk/strings.xml b/packages/PackageInstaller/res/values-mk/strings.xml
index e02c3c5..e68fe06 100644
--- a/packages/PackageInstaller/res/values-mk/strings.xml
+++ b/packages/PackageInstaller/res/values-mk/strings.xml
@@ -66,6 +66,7 @@
<string name="uninstall_keep_data" msgid="7002379587465487550">"Задржи <xliff:g id="SIZE">%1$s</xliff:g> податоци на апликацијата."</string>
<string name="uninstall_application_text_current_user_clone_profile" msgid="835170400160011636">"Дали сакате да ја избришете оваа апликација?"</string>
<string name="uninstall_application_text_with_clone_instance" msgid="6944473334273349036">"Дали сакате да ја деинсталирате оваа апликација? Ќе се избрише и клонот на <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g>."</string>
+ <string name="uninstall_application_text_current_user_private_profile" msgid="867004464945674674">"Дали сакате да ја деинсталирате апликацијава од вашиот „Приватен простор“?"</string>
<string name="uninstalling_notification_channel" msgid="840153394325714653">"Деинсталации во тек"</string>
<string name="uninstall_failure_notification_channel" msgid="1136405866767576588">"Неуспешни деинсталации"</string>
<string name="uninstalling" msgid="8709566347688966845">"Се деинсталира…"</string>
@@ -106,4 +107,21 @@
<string name="unarchive_application_title" msgid="7958278328280721421">"Да се врати <xliff:g id="APPNAME">%1$s</xliff:g> од <xliff:g id="INSTALLERNAME">%1$s</xliff:g>?"</string>
<string name="unarchive_body_text" msgid="8244155079861708964">"Апликацијава ќе почне да се презема во заднина"</string>
<string name="restore" msgid="8460854736328970444">"Враќање"</string>
+ <string name="unarchive_error_offline_title" msgid="4021785324565678605">"Офлајн сте"</string>
+ <string name="unarchive_error_offline_body" msgid="255717000519772755">"Апликацијава ќе се врати автоматски кога ќе се поврзете на интернет"</string>
+ <string name="unarchive_error_generic_title" msgid="7123457671482449992">"Нешто тргна наопаку"</string>
+ <string name="unarchive_error_generic_body" msgid="4486803312463813079">"Се јави проблем при обидот за враќање на апликацијава"</string>
+ <string name="unarchive_error_storage_title" msgid="5080723357273852630">"Нема доволно простор"</string>
+ <string name="unarchive_error_storage_body" msgid="6879544407568780524">"За да ја вратите апликацијава, може да ослободите простор на уредов. Потребен простор: <xliff:g id="BYTES">%1$s</xliff:g>"</string>
+ <string name="unarchive_action_required_title" msgid="4971245740162604619">"Потребно е дејство"</string>
+ <string name="unarchive_action_required_body" msgid="1679431572983989231">"Следете ги следниве чекори за да ја вратите апликацијава"</string>
+ <string name="unarchive_error_installer_disabled_title" msgid="4815715617014985605">"Оневозможено: <xliff:g id="INSTALLERNAME">%1$s</xliff:g>"</string>
+ <!-- no translation found for unarchive_error_installer_disabled_body (4820821285907011729) -->
+ <skip />
+ <string name="unarchive_error_installer_uninstalled_title" msgid="3748354109176326489">"Деинсталирано: <xliff:g id="INSTALLERNAME">%1$s</xliff:g>"</string>
+ <string name="unarchive_error_installer_uninstalled_body" msgid="944733542444183204">"За да ја вратите апликацијава, треба да инсталирате <xliff:g id="INSTALLERNAME">%1$s</xliff:g>"</string>
+ <string name="unarchive_action_required_continue" msgid="5711202111224184257">"Продолжете"</string>
+ <string name="unarchive_clear_storage_button" msgid="1549537154535608744">"Ослободете простор"</string>
+ <string name="unarchive_settings_button" msgid="3504171760009177425">"Поставки"</string>
+ <string name="close" msgid="5214897374055647996">"Затворете"</string>
</resources>
diff --git a/packages/PackageInstaller/res/values-ml/strings.xml b/packages/PackageInstaller/res/values-ml/strings.xml
index 2e5dcfb..0b4b81a 100644
--- a/packages/PackageInstaller/res/values-ml/strings.xml
+++ b/packages/PackageInstaller/res/values-ml/strings.xml
@@ -66,6 +66,7 @@
<string name="uninstall_keep_data" msgid="7002379587465487550">"<xliff:g id="SIZE">%1$s</xliff:g> ആപ്പ് ഡാറ്റ വയ്ക്കുക."</string>
<string name="uninstall_application_text_current_user_clone_profile" msgid="835170400160011636">"ഈ ആപ്പ് ഇല്ലാതാക്കണോ?"</string>
<string name="uninstall_application_text_with_clone_instance" msgid="6944473334273349036">"ഈ ആപ്പ് അൺഇൻസ്റ്റാൾ ചെയ്യണോ? <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g> ക്ലോൺ ചെയ്യലും ഇല്ലാതാക്കും."</string>
+ <string name="uninstall_application_text_current_user_private_profile" msgid="867004464945674674">"നിങ്ങളുടെ സ്വകാര്യ സ്പെയ്സിൽ നിന്ന് ഈ ആപ്പ് അൺഇൻസ്റ്റാൾ ചെയ്യണോ?"</string>
<string name="uninstalling_notification_channel" msgid="840153394325714653">"നിലവിൽ അൺഇൻസ്റ്റാൾ ചെയ്യുന്നവ"</string>
<string name="uninstall_failure_notification_channel" msgid="1136405866767576588">"അൺ ഇൻസ്റ്റാൾ ചെയ്യാൻ കഴിയാഞ്ഞവ"</string>
<string name="uninstalling" msgid="8709566347688966845">"അണ് ഇൻസ്റ്റാൾ ചെയ്യുന്നു..."</string>
@@ -106,4 +107,21 @@
<string name="unarchive_application_title" msgid="7958278328280721421">"<xliff:g id="INSTALLERNAME">%1$s</xliff:g> എന്നതിൽ നിന്ന് <xliff:g id="APPNAME">%1$s</xliff:g> പുനഃസ്ഥാപിക്കണോ?"</string>
<string name="unarchive_body_text" msgid="8244155079861708964">"പശ്ചാത്തലത്തിൽ ഈ ആപ്പ് ഡൗൺലോഡ് ചെയ്ത് തുടങ്ങും"</string>
<string name="restore" msgid="8460854736328970444">"പുനഃസ്ഥാപിക്കുക"</string>
+ <string name="unarchive_error_offline_title" msgid="4021785324565678605">"നിങ്ങൾ ഓഫ്ലൈനാണ്"</string>
+ <string name="unarchive_error_offline_body" msgid="255717000519772755">"നിങ്ങൾ ഇന്റർനെറ്റിലേക്ക് കണക്റ്റ് ചെയ്തിരിക്കുമ്പോൾ, ഈ ആപ്പ് സ്വയമേവ പുനഃസ്ഥാപിക്കും"</string>
+ <string name="unarchive_error_generic_title" msgid="7123457671482449992">"എന്തോ കുഴപ്പമുണ്ടായി"</string>
+ <string name="unarchive_error_generic_body" msgid="4486803312463813079">"ഈ ആപ്പ് പുനഃസ്ഥാപിക്കുന്നതിൽ ഒരു പ്രശ്നമുണ്ടായി"</string>
+ <string name="unarchive_error_storage_title" msgid="5080723357273852630">"മതിയായ സ്റ്റോറേജ് ഇല്ല"</string>
+ <string name="unarchive_error_storage_body" msgid="6879544407568780524">"ഈ ആപ്പ് പുനഃസ്ഥാപിക്കുന്നതിന്, ഈ ഉപകരണത്തിൽ ഇടം സൃഷ്ടിക്കാം. ആവശ്യമായ സ്റ്റോറേജ്: <xliff:g id="BYTES">%1$s</xliff:g>"</string>
+ <string name="unarchive_action_required_title" msgid="4971245740162604619">"നടപടി ആവശ്യമാണ്"</string>
+ <string name="unarchive_action_required_body" msgid="1679431572983989231">"ഈ ആപ്പ് പുനഃസ്ഥാപിക്കാൻ തുടർന്നുള്ള ഘട്ടങ്ങൾ പാലിക്കുക"</string>
+ <string name="unarchive_error_installer_disabled_title" msgid="4815715617014985605">"<xliff:g id="INSTALLERNAME">%1$s</xliff:g> പ്രവർത്തനരഹിതമാക്കി"</string>
+ <!-- no translation found for unarchive_error_installer_disabled_body (4820821285907011729) -->
+ <skip />
+ <string name="unarchive_error_installer_uninstalled_title" msgid="3748354109176326489">"<xliff:g id="INSTALLERNAME">%1$s</xliff:g> അൺഇൻസ്റ്റാൾ ചെയ്തു"</string>
+ <string name="unarchive_error_installer_uninstalled_body" msgid="944733542444183204">"ഈ ആപ്പ് പുനഃസ്ഥാപിക്കുന്നതിന്, നിങ്ങൾ <xliff:g id="INSTALLERNAME">%1$s</xliff:g> ഇൻസ്റ്റാൾ ചെയ്യേണ്ടതുണ്ട്"</string>
+ <string name="unarchive_action_required_continue" msgid="5711202111224184257">"തുടരുക"</string>
+ <string name="unarchive_clear_storage_button" msgid="1549537154535608744">"സ്റ്റോറേജ് മായ്ക്കുക"</string>
+ <string name="unarchive_settings_button" msgid="3504171760009177425">"ക്രമീകരണം"</string>
+ <string name="close" msgid="5214897374055647996">"അടയ്ക്കുക"</string>
</resources>
diff --git a/packages/PackageInstaller/res/values-mn/strings.xml b/packages/PackageInstaller/res/values-mn/strings.xml
index 5deda94..32952ae 100644
--- a/packages/PackageInstaller/res/values-mn/strings.xml
+++ b/packages/PackageInstaller/res/values-mn/strings.xml
@@ -66,6 +66,7 @@
<string name="uninstall_keep_data" msgid="7002379587465487550">"Аппын өгөгдлийн <xliff:g id="SIZE">%1$s</xliff:g>-г үлдээнэ үү."</string>
<string name="uninstall_application_text_current_user_clone_profile" msgid="835170400160011636">"Та энэ аппыг устгахыг хүсэж байна уу?"</string>
<string name="uninstall_application_text_with_clone_instance" msgid="6944473334273349036">"Та энэ аппыг устгахыг хүсэж байна уу? <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g>-н хувилалыг мөн устгана."</string>
+ <string name="uninstall_application_text_current_user_private_profile" msgid="867004464945674674">"Та энэ аппыг хувийн орон зайнаасаа устгахдаа итгэлтэй байна уу?"</string>
<string name="uninstalling_notification_channel" msgid="840153394325714653">"Устгаж байна"</string>
<string name="uninstall_failure_notification_channel" msgid="1136405866767576588">"Устгаж чадсангүй"</string>
<string name="uninstalling" msgid="8709566347688966845">"Устгаж байна…"</string>
@@ -106,4 +107,21 @@
<string name="unarchive_application_title" msgid="7958278328280721421">"<xliff:g id="APPNAME">%1$s</xliff:g>-г <xliff:g id="INSTALLERNAME">%1$s</xliff:g>-с сэргээх үү?"</string>
<string name="unarchive_body_text" msgid="8244155079861708964">"Энэ аппыг дэвсгэрт татаж эхэлнэ"</string>
<string name="restore" msgid="8460854736328970444">"Сэргээх"</string>
+ <string name="unarchive_error_offline_title" msgid="4021785324565678605">"Та офлайн байна"</string>
+ <string name="unarchive_error_offline_body" msgid="255717000519772755">"Таныг интернэтэд холбогдсон үед энэ аппыг автоматаар сэргээнэ"</string>
+ <string name="unarchive_error_generic_title" msgid="7123457671482449992">"Ямар нэг алдаа гарлаа"</string>
+ <string name="unarchive_error_generic_body" msgid="4486803312463813079">"Энэ аппыг сэргээхээр оролдоход асуудал гарлаа"</string>
+ <string name="unarchive_error_storage_title" msgid="5080723357273852630">"Хангалттай хадгалах сан байхгүй"</string>
+ <string name="unarchive_error_storage_body" msgid="6879544407568780524">"Энэ аппыг сэргээхийн тулд та энэ төхөөрөмжид сул зай гаргах боломжтой. Шаардлагатай хадгалах сан: <xliff:g id="BYTES">%1$s</xliff:g>"</string>
+ <string name="unarchive_action_required_title" msgid="4971245740162604619">"Арга хэмжээ авах шаардлагатай"</string>
+ <string name="unarchive_action_required_body" msgid="1679431572983989231">"Энэ аппыг сэргээхийн тулд дараах алхмуудыг дагана уу"</string>
+ <string name="unarchive_error_installer_disabled_title" msgid="4815715617014985605">"<xliff:g id="INSTALLERNAME">%1$s</xliff:g>-г идэвхгүй болгосон"</string>
+ <!-- no translation found for unarchive_error_installer_disabled_body (4820821285907011729) -->
+ <skip />
+ <string name="unarchive_error_installer_uninstalled_title" msgid="3748354109176326489">"<xliff:g id="INSTALLERNAME">%1$s</xliff:g>-г устгасан"</string>
+ <string name="unarchive_error_installer_uninstalled_body" msgid="944733542444183204">"Энэ аппыг сэргээхийн тулд та <xliff:g id="INSTALLERNAME">%1$s</xliff:g>-г суулгах шаардлагатай"</string>
+ <string name="unarchive_action_required_continue" msgid="5711202111224184257">"Үргэлжлүүлэх"</string>
+ <string name="unarchive_clear_storage_button" msgid="1549537154535608744">"Хадгалах санг цэвэрлэх"</string>
+ <string name="unarchive_settings_button" msgid="3504171760009177425">"Тохиргоо"</string>
+ <string name="close" msgid="5214897374055647996">"Хаах"</string>
</resources>
diff --git a/packages/PackageInstaller/res/values-mr/strings.xml b/packages/PackageInstaller/res/values-mr/strings.xml
index 53ca403..77a5b9b 100644
--- a/packages/PackageInstaller/res/values-mr/strings.xml
+++ b/packages/PackageInstaller/res/values-mr/strings.xml
@@ -66,6 +66,7 @@
<string name="uninstall_keep_data" msgid="7002379587465487550">"ॲप डेटा पैकी <xliff:g id="SIZE">%1$s</xliff:g> ठेवा."</string>
<string name="uninstall_application_text_current_user_clone_profile" msgid="835170400160011636">"तुम्हाला हे अॅप हटवायचे आहे का?"</string>
<string name="uninstall_application_text_with_clone_instance" msgid="6944473334273349036">"तुम्हाला हे अॅप अनइंस्टॉल करायचे आहे का? <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g> क्लोनदेखील हटवले जाईल."</string>
+ <string name="uninstall_application_text_current_user_private_profile" msgid="867004464945674674">"तुम्हाला तुमच्या खाजगी स्पेसमधून हे अॅप काढून टाकायचे आहे का?"</string>
<string name="uninstalling_notification_channel" msgid="840153394325714653">"अनइंस्टॉल रन होत आहेत"</string>
<string name="uninstall_failure_notification_channel" msgid="1136405866767576588">"अनइंस्टॉल करता आले नाही"</string>
<string name="uninstalling" msgid="8709566347688966845">"अनइंस्टॉल करत आहे…"</string>
@@ -106,4 +107,21 @@
<string name="unarchive_application_title" msgid="7958278328280721421">"<xliff:g id="INSTALLERNAME">%1$s</xliff:g> मधून <xliff:g id="APPNAME">%1$s</xliff:g> रिस्टोअर करायचे आहे का?"</string>
<string name="unarchive_body_text" msgid="8244155079861708964">"हे ॲप बॅकग्राउंडमध्ये डाउनलोड होण्यास सुरुवात होईल"</string>
<string name="restore" msgid="8460854736328970444">"रिस्टोअर करा"</string>
+ <string name="unarchive_error_offline_title" msgid="4021785324565678605">"तुम्ही ऑफलाइन आहात"</string>
+ <string name="unarchive_error_offline_body" msgid="255717000519772755">"तुम्ही इंटरनेटशी कनेक्ट केले असेल, तेव्हा हे अॅप आपोआप रिस्टोअर होईल"</string>
+ <string name="unarchive_error_generic_title" msgid="7123457671482449992">"काहीतरी चुकले"</string>
+ <string name="unarchive_error_generic_body" msgid="4486803312463813079">"हे अॅप रिस्टोअर करताना समस्या आली होती"</string>
+ <string name="unarchive_error_storage_title" msgid="5080723357273852630">"पुरेसे स्टोरेज नाही"</string>
+ <string name="unarchive_error_storage_body" msgid="6879544407568780524">"हे अॅप रिस्टोअर करण्यासाठी, तुम्ही या डिव्हाइसवरील जागा मोकळी करू शकता. स्टोरेज आवश्यक आहे: <xliff:g id="BYTES">%1$s</xliff:g>"</string>
+ <string name="unarchive_action_required_title" msgid="4971245740162604619">"कृती आवश्यक आहे"</string>
+ <string name="unarchive_action_required_body" msgid="1679431572983989231">"हे अॅप रिस्टोअर करण्यासाठी पुढील पायऱ्या फॉलो करा"</string>
+ <string name="unarchive_error_installer_disabled_title" msgid="4815715617014985605">"<xliff:g id="INSTALLERNAME">%1$s</xliff:g> बंद केले आहे"</string>
+ <!-- no translation found for unarchive_error_installer_disabled_body (4820821285907011729) -->
+ <skip />
+ <string name="unarchive_error_installer_uninstalled_title" msgid="3748354109176326489">"<xliff:g id="INSTALLERNAME">%1$s</xliff:g> अनइंस्टॉल केले आहे"</string>
+ <string name="unarchive_error_installer_uninstalled_body" msgid="944733542444183204">"हे अॅप रिस्टोअर करण्यासाठी, तुम्हाला <xliff:g id="INSTALLERNAME">%1$s</xliff:g> इंस्टॉल करावे लागेल"</string>
+ <string name="unarchive_action_required_continue" msgid="5711202111224184257">"पुढे सुरू ठेवा"</string>
+ <string name="unarchive_clear_storage_button" msgid="1549537154535608744">"स्टोरेज साफ करा"</string>
+ <string name="unarchive_settings_button" msgid="3504171760009177425">"सेटिंग्ज"</string>
+ <string name="close" msgid="5214897374055647996">"बंद करा"</string>
</resources>
diff --git a/packages/PackageInstaller/res/values-ms/strings.xml b/packages/PackageInstaller/res/values-ms/strings.xml
index 4b0b560..7a85370 100644
--- a/packages/PackageInstaller/res/values-ms/strings.xml
+++ b/packages/PackageInstaller/res/values-ms/strings.xml
@@ -66,6 +66,7 @@
<string name="uninstall_keep_data" msgid="7002379587465487550">"Simpan <xliff:g id="SIZE">%1$s</xliff:g> data apl."</string>
<string name="uninstall_application_text_current_user_clone_profile" msgid="835170400160011636">"Adakah anda mahu memadamkan apl ini?"</string>
<string name="uninstall_application_text_with_clone_instance" msgid="6944473334273349036">"Adakah anda mahu menyahpasang apl ini? Klon <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g> juga akan dipadamkan."</string>
+ <string name="uninstall_application_text_current_user_private_profile" msgid="867004464945674674">"Adakah anda mahu menyahpasang apl ini daripada ruang peribadi anda?"</string>
<string name="uninstalling_notification_channel" msgid="840153394325714653">"Penyahpasangan yang sedang berjalan"</string>
<string name="uninstall_failure_notification_channel" msgid="1136405866767576588">"Penyahpasangan yang gagal"</string>
<string name="uninstalling" msgid="8709566347688966845">"Menyahpasang…"</string>
@@ -106,4 +107,21 @@
<string name="unarchive_application_title" msgid="7958278328280721421">"Pulihkan <xliff:g id="APPNAME">%1$s</xliff:g> daripada <xliff:g id="INSTALLERNAME">%1$s</xliff:g>?"</string>
<string name="unarchive_body_text" msgid="8244155079861708964">"Apl ini akan mula dimuat turun dalam latar"</string>
<string name="restore" msgid="8460854736328970444">"Pulihkan"</string>
+ <string name="unarchive_error_offline_title" msgid="4021785324565678605">"Anda berstatus luar talian"</string>
+ <string name="unarchive_error_offline_body" msgid="255717000519772755">"Apl ini akan dipulihkan secara automatik apabila anda disambungkan kepada Internet"</string>
+ <string name="unarchive_error_generic_title" msgid="7123457671482449992">"Ada yang tidak kena"</string>
+ <string name="unarchive_error_generic_body" msgid="4486803312463813079">"Terdapat masalah semasa memuatkan apl ini"</string>
+ <string name="unarchive_error_storage_title" msgid="5080723357273852630">"Storan tidak mencukupi"</string>
+ <string name="unarchive_error_storage_body" msgid="6879544407568780524">"Untuk memulihkan apl ini, anda boleh mengosongkan ruang storan pada peranti ini. Storan diperlukan: <xliff:g id="BYTES">%1$s</xliff:g>"</string>
+ <string name="unarchive_action_required_title" msgid="4971245740162604619">"Tindakan diperlukan"</string>
+ <string name="unarchive_action_required_body" msgid="1679431572983989231">"Ikut langkah seterusnya untuk memulihkan apl ini"</string>
+ <string name="unarchive_error_installer_disabled_title" msgid="4815715617014985605">"<xliff:g id="INSTALLERNAME">%1$s</xliff:g> dilumpuhkan"</string>
+ <!-- no translation found for unarchive_error_installer_disabled_body (4820821285907011729) -->
+ <skip />
+ <string name="unarchive_error_installer_uninstalled_title" msgid="3748354109176326489">"<xliff:g id="INSTALLERNAME">%1$s</xliff:g> dinyahpasang"</string>
+ <string name="unarchive_error_installer_uninstalled_body" msgid="944733542444183204">"Untuk memulihkan apl ini, anda perlu memasang <xliff:g id="INSTALLERNAME">%1$s</xliff:g>"</string>
+ <string name="unarchive_action_required_continue" msgid="5711202111224184257">"Teruskan"</string>
+ <string name="unarchive_clear_storage_button" msgid="1549537154535608744">"Kosongkan storan"</string>
+ <string name="unarchive_settings_button" msgid="3504171760009177425">"Tetapan"</string>
+ <string name="close" msgid="5214897374055647996">"Tutup"</string>
</resources>
diff --git a/packages/PackageInstaller/res/values-my/strings.xml b/packages/PackageInstaller/res/values-my/strings.xml
index 302c2c3..21c223c 100644
--- a/packages/PackageInstaller/res/values-my/strings.xml
+++ b/packages/PackageInstaller/res/values-my/strings.xml
@@ -66,6 +66,7 @@
<string name="uninstall_keep_data" msgid="7002379587465487550">"အက်ပ်ဒေတာများ၏ <xliff:g id="SIZE">%1$s</xliff:g> ကို ထားရှိရန်။"</string>
<string name="uninstall_application_text_current_user_clone_profile" msgid="835170400160011636">"ဤအက်ပ်ကို ဖျက်လိုသလား။"</string>
<string name="uninstall_application_text_with_clone_instance" msgid="6944473334273349036">"ဤအက်ပ်ကို ဖယ်ရှားလိုသလား။ <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g> ပုံတူပွားကိုလည်း ဖျက်လိုက်မည်။"</string>
+ <string name="uninstall_application_text_current_user_private_profile" msgid="867004464945674674">"ဤအက်ပ်ကို သင့်သီးသန့်နေရာမှ ဖယ်ရှားလိုသလား။"</string>
<string name="uninstalling_notification_channel" msgid="840153394325714653">"ပရိုဂရမ်ကို ဖယ်ရှားနေပါသည်"</string>
<string name="uninstall_failure_notification_channel" msgid="1136405866767576588">"ပရိုဂရမ်ကို ဖယ်ရှား၍မရပါ"</string>
<string name="uninstalling" msgid="8709566347688966845">"ပရိုဂရမ်ကို ဖယ်ရှားနေသည်..."</string>
@@ -106,4 +107,21 @@
<string name="unarchive_application_title" msgid="7958278328280721421">"<xliff:g id="INSTALLERNAME">%1$s</xliff:g> မှ <xliff:g id="APPNAME">%1$s</xliff:g> ကို ပြန်ယူမလား။"</string>
<string name="unarchive_body_text" msgid="8244155079861708964">"ဤအက်ပ်ကို နောက်ခံတွင် စတင်ဒေါင်းလုဒ်လုပ်ပါမည်"</string>
<string name="restore" msgid="8460854736328970444">"ပြန်ယူရန်"</string>
+ <string name="unarchive_error_offline_title" msgid="4021785324565678605">"သင်အော့ဖ်လိုင်း ဖြစ်နေသည်"</string>
+ <string name="unarchive_error_offline_body" msgid="255717000519772755">"အင်တာနက် ချိတ်ဆက်ထားသည့်အခါ ဤအက်ပ်ကို အလိုအလျောက် ပြန်ယူပါမည်"</string>
+ <string name="unarchive_error_generic_title" msgid="7123457671482449992">"တစ်ခုခုမှားသွားသည်"</string>
+ <string name="unarchive_error_generic_body" msgid="4486803312463813079">"ဤအက်ပ်ကို ပြန်ယူရန် ကြိုးပမ်းရာတွင် ပြဿနာရှိသည်"</string>
+ <string name="unarchive_error_storage_title" msgid="5080723357273852630">"သိုလှောင်ခန်း မလုံလောက်ပါ"</string>
+ <string name="unarchive_error_storage_body" msgid="6879544407568780524">"ဤအက်ပ်ကို ပြန်ယူရန် ဤစက်တွင် နေရာလွတ်ပြုလုပ်နိုင်သည်။ သိုလှောင်ခန်း လိုအပ်သည်- <xliff:g id="BYTES">%1$s</xliff:g>"</string>
+ <string name="unarchive_action_required_title" msgid="4971245740162604619">"လုပ်ဆောင်ချက် လိုအပ်သည်"</string>
+ <string name="unarchive_action_required_body" msgid="1679431572983989231">"ဤအက်ပ်ကို ပြန်ယူရန် နောက်အဆင့်များအတိုင်း လုပ်ဆောင်ပါ"</string>
+ <string name="unarchive_error_installer_disabled_title" msgid="4815715617014985605">"<xliff:g id="INSTALLERNAME">%1$s</xliff:g> ကို ပိတ်ထားသည်"</string>
+ <!-- no translation found for unarchive_error_installer_disabled_body (4820821285907011729) -->
+ <skip />
+ <string name="unarchive_error_installer_uninstalled_title" msgid="3748354109176326489">"<xliff:g id="INSTALLERNAME">%1$s</xliff:g> ကို ဖယ်ရှားထားသည်"</string>
+ <string name="unarchive_error_installer_uninstalled_body" msgid="944733542444183204">"ဤအက်ပ်ကို ပြန်ယူရန် <xliff:g id="INSTALLERNAME">%1$s</xliff:g> ကို ထည့်သွင်းရမည်"</string>
+ <string name="unarchive_action_required_continue" msgid="5711202111224184257">"ရှေ့ဆက်ရန်"</string>
+ <string name="unarchive_clear_storage_button" msgid="1549537154535608744">"သိုလှောင်ခန်း ရှင်းလင်းရန်"</string>
+ <string name="unarchive_settings_button" msgid="3504171760009177425">"ဆက်တင်များ"</string>
+ <string name="close" msgid="5214897374055647996">"ပိတ်ရန်"</string>
</resources>
diff --git a/packages/PackageInstaller/res/values-nb/strings.xml b/packages/PackageInstaller/res/values-nb/strings.xml
index 65c0cb8..86442e1 100644
--- a/packages/PackageInstaller/res/values-nb/strings.xml
+++ b/packages/PackageInstaller/res/values-nb/strings.xml
@@ -66,6 +66,7 @@
<string name="uninstall_keep_data" msgid="7002379587465487550">"Behold <xliff:g id="SIZE">%1$s</xliff:g> med appdata."</string>
<string name="uninstall_application_text_current_user_clone_profile" msgid="835170400160011636">"Vil du slette denne appen?"</string>
<string name="uninstall_application_text_with_clone_instance" msgid="6944473334273349036">"Vil du avinstallere denne appen? <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g>-klonen slettes også."</string>
+ <string name="uninstall_application_text_current_user_private_profile" msgid="867004464945674674">"Vil du avinstallere denne appen fra det private området ditt?"</string>
<string name="uninstalling_notification_channel" msgid="840153394325714653">"Avinstalleringer som er i gang"</string>
<string name="uninstall_failure_notification_channel" msgid="1136405866767576588">"Mislykkede avinstalleringer"</string>
<string name="uninstalling" msgid="8709566347688966845">"Avinstallerer …"</string>
@@ -106,4 +107,21 @@
<string name="unarchive_application_title" msgid="7958278328280721421">"Vil du gjenopprette <xliff:g id="APPNAME">%1$s</xliff:g> fra <xliff:g id="INSTALLERNAME">%1$s</xliff:g>?"</string>
<string name="unarchive_body_text" msgid="8244155079861708964">"Denne appen begynner å laste ned i bakgrunnen"</string>
<string name="restore" msgid="8460854736328970444">"Gjenopprett"</string>
+ <string name="unarchive_error_offline_title" msgid="4021785324565678605">"Du er uten nett"</string>
+ <string name="unarchive_error_offline_body" msgid="255717000519772755">"Denne appen gjenopprettes automatisk når du er koblet til internett"</string>
+ <string name="unarchive_error_generic_title" msgid="7123457671482449992">"Noe gikk galt"</string>
+ <string name="unarchive_error_generic_body" msgid="4486803312463813079">"Det oppsto et problem med å gjenopprette denne appen"</string>
+ <string name="unarchive_error_storage_title" msgid="5080723357273852630">"Ikke nok lagringsplass"</string>
+ <string name="unarchive_error_storage_body" msgid="6879544407568780524">"For å gjenopprette denne appen kan du frigjøre plass på enheten. Nødvendig lagringsplass: <xliff:g id="BYTES">%1$s</xliff:g>"</string>
+ <string name="unarchive_action_required_title" msgid="4971245740162604619">"Handling påkrevd"</string>
+ <string name="unarchive_action_required_body" msgid="1679431572983989231">"Følg de neste trinnene for å gjenopprette denne appen"</string>
+ <string name="unarchive_error_installer_disabled_title" msgid="4815715617014985605">"<xliff:g id="INSTALLERNAME">%1$s</xliff:g> er deaktivert"</string>
+ <!-- no translation found for unarchive_error_installer_disabled_body (4820821285907011729) -->
+ <skip />
+ <string name="unarchive_error_installer_uninstalled_title" msgid="3748354109176326489">"<xliff:g id="INSTALLERNAME">%1$s</xliff:g> er avinstallert"</string>
+ <string name="unarchive_error_installer_uninstalled_body" msgid="944733542444183204">"For å gjenopprette denne appen må du installere <xliff:g id="INSTALLERNAME">%1$s</xliff:g>"</string>
+ <string name="unarchive_action_required_continue" msgid="5711202111224184257">"Fortsett"</string>
+ <string name="unarchive_clear_storage_button" msgid="1549537154535608744">"Frigjør lagringsplass"</string>
+ <string name="unarchive_settings_button" msgid="3504171760009177425">"Innstillinger"</string>
+ <string name="close" msgid="5214897374055647996">"Lukk"</string>
</resources>
diff --git a/packages/PackageInstaller/res/values-ne/strings.xml b/packages/PackageInstaller/res/values-ne/strings.xml
index b72218c..ee704d0 100644
--- a/packages/PackageInstaller/res/values-ne/strings.xml
+++ b/packages/PackageInstaller/res/values-ne/strings.xml
@@ -66,6 +66,7 @@
<string name="uninstall_keep_data" msgid="7002379587465487550">"<xliff:g id="SIZE">%1$s</xliff:g> एपको डेटा राख्नुहोस्।"</string>
<string name="uninstall_application_text_current_user_clone_profile" msgid="835170400160011636">"तपाईं यो एप मेटाउन चाहनुहुन्छ?"</string>
<string name="uninstall_application_text_with_clone_instance" msgid="6944473334273349036">"तपाईं यो एप अनइन्स्टल गर्न चाहनुहुन्छ? <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g> क्लोन पनि मेटाइने छ।"</string>
+ <string name="uninstall_application_text_current_user_private_profile" msgid="867004464945674674">"तपाईं आफ्नो निजी स्पेसबाट यो एप अनइन्स्टल गर्न चाहनुहुन्छ?"</string>
<string name="uninstalling_notification_channel" msgid="840153394325714653">"चलिरहेका स्थापना रद्द गर्ने कार्यहरू"</string>
<string name="uninstall_failure_notification_channel" msgid="1136405866767576588">"असफल भएका स्थापना रद्द गर्ने कार्यहरू"</string>
<string name="uninstalling" msgid="8709566347688966845">"स्थापना रद्द गर्दै…"</string>
@@ -106,4 +107,21 @@
<string name="unarchive_application_title" msgid="7958278328280721421">"<xliff:g id="INSTALLERNAME">%1$s</xliff:g> बाट <xliff:g id="APPNAME">%1$s</xliff:g> रिस्टोर गर्ने हो?"</string>
<string name="unarchive_body_text" msgid="8244155079861708964">"यो एप ब्याकग्राउन्डमा डाउनलोड हुन थाल्ने छ"</string>
<string name="restore" msgid="8460854736328970444">"रिस्टोर गर्नुहोस्"</string>
+ <string name="unarchive_error_offline_title" msgid="4021785324565678605">"तपाईंको डिभाइस अफलाइन छ"</string>
+ <string name="unarchive_error_offline_body" msgid="255717000519772755">"तपाईंको डिभाइस इन्टरनेटमा कनेक्ट भएपछि यो एप स्वतः रिस्टोर हुने छ"</string>
+ <string name="unarchive_error_generic_title" msgid="7123457671482449992">"कुनै समस्या आयो"</string>
+ <string name="unarchive_error_generic_body" msgid="4486803312463813079">"यो एप रिस्टोर गर्ने क्रममा कुनै समस्या आयो"</string>
+ <string name="unarchive_error_storage_title" msgid="5080723357273852630">"पर्याप्त खाली ठाउँ छैन"</string>
+ <string name="unarchive_error_storage_body" msgid="6879544407568780524">"यो एप रिस्टोर गर्न तपाईं यो डिभाइसमा ठाउँ खाली गर्न सक्नुहुन्छ। आवश्यक भण्डारण: <xliff:g id="BYTES">%1$s</xliff:g>"</string>
+ <string name="unarchive_action_required_title" msgid="4971245740162604619">"कारबाही गर्नु पर्ने हुन्छ"</string>
+ <string name="unarchive_action_required_body" msgid="1679431572983989231">"यो एप रिस्टोर गर्न आगामी चरणहरू पालना गर्नुहोस्"</string>
+ <string name="unarchive_error_installer_disabled_title" msgid="4815715617014985605">"<xliff:g id="INSTALLERNAME">%1$s</xliff:g> अफ गरिएको छ"</string>
+ <!-- no translation found for unarchive_error_installer_disabled_body (4820821285907011729) -->
+ <skip />
+ <string name="unarchive_error_installer_uninstalled_title" msgid="3748354109176326489">"<xliff:g id="INSTALLERNAME">%1$s</xliff:g> अनइन्स्टल गरिएको छ"</string>
+ <string name="unarchive_error_installer_uninstalled_body" msgid="944733542444183204">"यो एप रिस्टोर गर्न तपाईंले <xliff:g id="INSTALLERNAME">%1$s</xliff:g> इन्स्टल गर्नु पर्ने हुन्छ"</string>
+ <string name="unarchive_action_required_continue" msgid="5711202111224184257">"जारी राख्नुहोस्"</string>
+ <string name="unarchive_clear_storage_button" msgid="1549537154535608744">"भण्डारण खाली गर्नुहोस्"</string>
+ <string name="unarchive_settings_button" msgid="3504171760009177425">"सेटिङ"</string>
+ <string name="close" msgid="5214897374055647996">"बन्द गर्नुहोस्"</string>
</resources>
diff --git a/packages/PackageInstaller/res/values-nl/strings.xml b/packages/PackageInstaller/res/values-nl/strings.xml
index a1eb708..a63ff93 100644
--- a/packages/PackageInstaller/res/values-nl/strings.xml
+++ b/packages/PackageInstaller/res/values-nl/strings.xml
@@ -66,6 +66,7 @@
<string name="uninstall_keep_data" msgid="7002379587465487550">"<xliff:g id="SIZE">%1$s</xliff:g> aan app-gegevens behouden."</string>
<string name="uninstall_application_text_current_user_clone_profile" msgid="835170400160011636">"Wil je deze app verwijderen?"</string>
<string name="uninstall_application_text_with_clone_instance" msgid="6944473334273349036">"Wil je deze app verwijderen? <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g>-kloon wordt ook verwijderd."</string>
+ <string name="uninstall_application_text_current_user_private_profile" msgid="867004464945674674">"Wil je deze app verwijderen uit je privéruimte?"</string>
<string name="uninstalling_notification_channel" msgid="840153394325714653">"Actieve verwijderingen"</string>
<string name="uninstall_failure_notification_channel" msgid="1136405866767576588">"Mislukte verwijderingen"</string>
<string name="uninstalling" msgid="8709566347688966845">"Verwijderen…"</string>
@@ -106,4 +107,21 @@
<string name="unarchive_application_title" msgid="7958278328280721421">"<xliff:g id="APPNAME">%1$s</xliff:g> herstellen via <xliff:g id="INSTALLERNAME">%1$s</xliff:g>?"</string>
<string name="unarchive_body_text" msgid="8244155079861708964">"Deze app wordt gedownload op de achtergrond"</string>
<string name="restore" msgid="8460854736328970444">"Herstellen"</string>
+ <string name="unarchive_error_offline_title" msgid="4021785324565678605">"Je bent offline"</string>
+ <string name="unarchive_error_offline_body" msgid="255717000519772755">"Deze app wordt automatisch hersteld als je verbinding hebt met internet"</string>
+ <string name="unarchive_error_generic_title" msgid="7123457671482449992">"Er is iets misgegaan"</string>
+ <string name="unarchive_error_generic_body" msgid="4486803312463813079">"Er is iets misgegaan bij het herstellen van deze app"</string>
+ <string name="unarchive_error_storage_title" msgid="5080723357273852630">"Onvoldoende opslagruimte"</string>
+ <string name="unarchive_error_storage_body" msgid="6879544407568780524">"Je kunt ruimte op dit apparaat vrijmaken om deze app te herstellen. Vereiste opslagruimte: <xliff:g id="BYTES">%1$s</xliff:g>"</string>
+ <string name="unarchive_action_required_title" msgid="4971245740162604619">"Actie vereist"</string>
+ <string name="unarchive_action_required_body" msgid="1679431572983989231">"Voer de volgende stappen uit om deze app te herstellen"</string>
+ <string name="unarchive_error_installer_disabled_title" msgid="4815715617014985605">"<xliff:g id="INSTALLERNAME">%1$s</xliff:g> is uitgezet"</string>
+ <!-- no translation found for unarchive_error_installer_disabled_body (4820821285907011729) -->
+ <skip />
+ <string name="unarchive_error_installer_uninstalled_title" msgid="3748354109176326489">"<xliff:g id="INSTALLERNAME">%1$s</xliff:g> is verwijderd"</string>
+ <string name="unarchive_error_installer_uninstalled_body" msgid="944733542444183204">"Je moet <xliff:g id="INSTALLERNAME">%1$s</xliff:g> installeren om deze app te herstellen"</string>
+ <string name="unarchive_action_required_continue" msgid="5711202111224184257">"Doorgaan"</string>
+ <string name="unarchive_clear_storage_button" msgid="1549537154535608744">"Opslag wissen"</string>
+ <string name="unarchive_settings_button" msgid="3504171760009177425">"Instellingen"</string>
+ <string name="close" msgid="5214897374055647996">"Sluiten"</string>
</resources>
diff --git a/packages/PackageInstaller/res/values-or/strings.xml b/packages/PackageInstaller/res/values-or/strings.xml
index a1c685c..c9041d1 100644
--- a/packages/PackageInstaller/res/values-or/strings.xml
+++ b/packages/PackageInstaller/res/values-or/strings.xml
@@ -66,6 +66,7 @@
<string name="uninstall_keep_data" msgid="7002379587465487550">"<xliff:g id="SIZE">%1$s</xliff:g> ଆକାରର ଆପ୍ ଡାଟା ରଖନ୍ତୁୁ।"</string>
<string name="uninstall_application_text_current_user_clone_profile" msgid="835170400160011636">"ଆପଣ ଏହି ଆପକୁ ଡିଲିଟ କରିବାକୁ ଚାହୁଁଛନ୍ତି?"</string>
<string name="uninstall_application_text_with_clone_instance" msgid="6944473334273349036">"ଆପଣ ଏହି ଆପକୁ ଅନଇନଷ୍ଟଲ କରିବାକୁ ଚାହୁଁଛନ୍ତି? <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g> କ୍ଲୋନକୁ ମଧ୍ୟ ଡିଲିଟ କରାଯିବ।"</string>
+ <string name="uninstall_application_text_current_user_private_profile" msgid="867004464945674674">"ଆପଣ ଆପଣଙ୍କ ପ୍ରାଇଭେଟ ସ୍ପେସରୁ ଏହି ଆପକୁ ଅନଇନଷ୍ଟଲ କରିବାକୁ ଚାହାଁନ୍ତି?"</string>
<string name="uninstalling_notification_channel" msgid="840153394325714653">"ଅନଇନଷ୍ଟଲ୍ ଚାଲୁଛି"</string>
<string name="uninstall_failure_notification_channel" msgid="1136405866767576588">"ବିଫଳ ହୋଇଥିବା ଅନଇନଷ୍ଟଲ୍"</string>
<string name="uninstalling" msgid="8709566347688966845">"ଅନ୍ଇନଷ୍ଟଲ୍ କରାଯାଉଛି…"</string>
@@ -106,4 +107,21 @@
<string name="unarchive_application_title" msgid="7958278328280721421">"<xliff:g id="INSTALLERNAME">%1$s</xliff:g>ରୁ <xliff:g id="APPNAME">%1$s</xliff:g>କୁ ରିଷ୍ଟୋର କରିବେ?"</string>
<string name="unarchive_body_text" msgid="8244155079861708964">"ଏହି ଆପ ପୃଷ୍ଠପଟରେ ଡାଉନଲୋଡ ହେବା ଆରମ୍ଭ କରିବ"</string>
<string name="restore" msgid="8460854736328970444">"ରିଷ୍ଟୋର କରନ୍ତୁ"</string>
+ <string name="unarchive_error_offline_title" msgid="4021785324565678605">"ଆପଣ ଅଫଲାଇନ ଅଛନ୍ତି"</string>
+ <string name="unarchive_error_offline_body" msgid="255717000519772755">"ଆପଣ ଇଣ୍ଟରନେଟ ସହ କନେକ୍ଟ ହେଲେ ଏହି ଆପ ସ୍ୱତଃ ରିଷ୍ଟୋର ହେବ"</string>
+ <string name="unarchive_error_generic_title" msgid="7123457671482449992">"କିଛି ତ୍ରୁଟି ହୋଇଛି"</string>
+ <string name="unarchive_error_generic_body" msgid="4486803312463813079">"ଏହି ଆପ ରିଷ୍ଟୋର କରିବାକୁ ଚେଷ୍ଟା କରିବା ସମୟରେ ଏକ ସମସ୍ୟା ହୋଇଛି"</string>
+ <string name="unarchive_error_storage_title" msgid="5080723357273852630">"ଯଥେଷ୍ଟ ଷ୍ଟୋରେଜ ନାହିଁ"</string>
+ <string name="unarchive_error_storage_body" msgid="6879544407568780524">"ଏହି ଆପ ରିଷ୍ଟୋର କରିବା ପାଇଁ ଆପଣ ଏହି ଡିଭାଇସରେ ସ୍ପେସ ଖାଲି କରିପାରିବେ। ଷ୍ଟୋରେଜ ଆବଶ୍ୟକ: <xliff:g id="BYTES">%1$s</xliff:g>"</string>
+ <string name="unarchive_action_required_title" msgid="4971245740162604619">"ପଦକ୍ଷେପ ନେବା ଆବଶ୍ୟକ"</string>
+ <string name="unarchive_action_required_body" msgid="1679431572983989231">"ଏହି ଆପ ରିଷ୍ଟୋର କରିବାକୁ ପରବର୍ତ୍ତୀ ଷ୍ଟେପଗୁଡ଼ିକୁ ଫଲୋ କରନ୍ତୁ"</string>
+ <string name="unarchive_error_installer_disabled_title" msgid="4815715617014985605">"<xliff:g id="INSTALLERNAME">%1$s</xliff:g>କୁ ଅକ୍ଷମ କରାଯାଇଛି"</string>
+ <!-- no translation found for unarchive_error_installer_disabled_body (4820821285907011729) -->
+ <skip />
+ <string name="unarchive_error_installer_uninstalled_title" msgid="3748354109176326489">"<xliff:g id="INSTALLERNAME">%1$s</xliff:g>କୁ ଅନଇନଷ୍ଟଲ କରାଯାଇଛି"</string>
+ <string name="unarchive_error_installer_uninstalled_body" msgid="944733542444183204">"ଏହି ଆପ ରିଷ୍ଟୋର କରିବା ପାଇଁ ଆପଣଙ୍କୁ <xliff:g id="INSTALLERNAME">%1$s</xliff:g> ଇନଷ୍ଟଲ କରିବାକୁ ହେବ"</string>
+ <string name="unarchive_action_required_continue" msgid="5711202111224184257">"ଜାରି ରଖନ୍ତୁ"</string>
+ <string name="unarchive_clear_storage_button" msgid="1549537154535608744">"ଷ୍ଟୋରେଜ ଖାଲି କରନ୍ତୁ"</string>
+ <string name="unarchive_settings_button" msgid="3504171760009177425">"ସେଟିଂସ"</string>
+ <string name="close" msgid="5214897374055647996">"ବନ୍ଦ କରନ୍ତୁ"</string>
</resources>
diff --git a/packages/PackageInstaller/res/values-pa/strings.xml b/packages/PackageInstaller/res/values-pa/strings.xml
index 1c7fb862..d968672 100644
--- a/packages/PackageInstaller/res/values-pa/strings.xml
+++ b/packages/PackageInstaller/res/values-pa/strings.xml
@@ -66,6 +66,7 @@
<string name="uninstall_keep_data" msgid="7002379587465487550">"<xliff:g id="SIZE">%1$s</xliff:g> ਐਪ ਡਾਟਾ ਰੱਖੋ।"</string>
<string name="uninstall_application_text_current_user_clone_profile" msgid="835170400160011636">"ਕੀ ਤੁਸੀਂ ਇਸ ਐਪ ਨੂੰ ਮਿਟਾਉਣਾ ਚਾਹੁੰਦੇ ਹੋ?"</string>
<string name="uninstall_application_text_with_clone_instance" msgid="6944473334273349036">"ਕੀ ਤੁਸੀਂ ਇਸ ਐਪ ਨੂੰ ਅਣਸਥਾਪਤ ਕਰਨਾ ਚਾਹੁੰਦੇ ਹੋ? <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g> ਦੇ ਕਲੋਨ ਨੂੰ ਵੀ ਮਿਟਾਇਆ ਜਾਵੇਗਾ।"</string>
+ <string name="uninstall_application_text_current_user_private_profile" msgid="867004464945674674">"ਕੀ ਤੁਸੀਂ ਇਸ ਐਪ ਨੂੰ ਆਪਣੇ ਨਿੱਜੀ ਸਪੇਸ ਤੋਂ ਅਣਸਥਾਪਤ ਕਰਨਾ ਚਾਹੁੰਦੇ ਹੋ?"</string>
<string name="uninstalling_notification_channel" msgid="840153394325714653">"ਚੱਲ ਰਹੀਆਂ ਅਣਸਥਾਪਨਾਵਾਂ"</string>
<string name="uninstall_failure_notification_channel" msgid="1136405866767576588">"ਅਸਫਲ ਅਣਸਥਾਪਨਾਵਾਂ"</string>
<string name="uninstalling" msgid="8709566347688966845">"ਅਣਸਥਾਪਤ ਕੀਤਾ ਜਾ ਰਿਹਾ ਹੈ…"</string>
@@ -106,4 +107,21 @@
<string name="unarchive_application_title" msgid="7958278328280721421">"ਕੀ <xliff:g id="APPNAME">%1$s</xliff:g> ਨੂੰ <xliff:g id="INSTALLERNAME">%1$s</xliff:g> ਤੋਂ ਮੁੜ-ਬਹਾਲ ਕਰਨਾ ਹੈ?"</string>
<string name="unarchive_body_text" msgid="8244155079861708964">"ਇਹ ਐਪ ਬੈਕਗ੍ਰਾਊਂਡ ਵਿੱਚ ਡਾਊਨਲੋਡ ਹੋਣੀ ਸ਼ੁਰੂ ਹੋ ਜਾਵੇਗੀ"</string>
<string name="restore" msgid="8460854736328970444">"ਮੁੜ-ਬਹਾਲ ਕਰੋ"</string>
+ <string name="unarchive_error_offline_title" msgid="4021785324565678605">"ਤੁਸੀਂ ਆਫ਼ਲਾਈਨ ਹੋ"</string>
+ <string name="unarchive_error_offline_body" msgid="255717000519772755">"ਜਦੋਂ ਤੁਸੀਂ ਇੰਟਰਨੈੱਟ ਨਾਲ ਕਨੈਕਟ ਹੁੰਦੇ ਹੋ, ਤਾਂ ਇਹ ਐਪ ਸਵੈਚਲਿਤ ਤੌਰ \'ਤੇ ਮੁੜ-ਬਹਾਲ ਹੋ ਜਾਵੇਗੀ"</string>
+ <string name="unarchive_error_generic_title" msgid="7123457671482449992">"ਕੋਈ ਗੜਬੜ ਹੋ ਗਈ"</string>
+ <string name="unarchive_error_generic_body" msgid="4486803312463813079">"ਇਸ ਐਪ ਨੂੰ ਮੁੜ-ਬਹਾਲ ਕਰਨ ਵੇਲੇ ਕੋਈ ਸਮੱਸਿਆ ਆਈ"</string>
+ <string name="unarchive_error_storage_title" msgid="5080723357273852630">"ਲੋੜੀਂਦੀ ਸਟੋਰੇਜ ਨਹੀਂ ਹੈ"</string>
+ <string name="unarchive_error_storage_body" msgid="6879544407568780524">"ਇਸ ਐਪ ਨੂੰ ਮੁੜ-ਬਹਾਲ ਕਰਨ ਲਈ, ਤੁਸੀਂ ਆਪਣੇ ਡੀਵਾਈਸ \'ਤੇ ਜਗ੍ਹਾ ਖਾਲੀ ਕਰ ਸਕਦੇ ਹੋ। ਲੋੜੀਂਦੀ ਸਟੋਰੇਜ: <xliff:g id="BYTES">%1$s</xliff:g>"</string>
+ <string name="unarchive_action_required_title" msgid="4971245740162604619">"ਕਾਰਵਾਈ ਦੀ ਲੋੜ"</string>
+ <string name="unarchive_action_required_body" msgid="1679431572983989231">"ਇਸ ਐਪ ਨੂੰ ਮੁੜ-ਬਹਾਲ ਕਰਨ ਲਈ ਅਗਲੇ ਪੜਾਵਾਂ ਦੀ ਪਾਲਣਾ ਕਰੋ"</string>
+ <string name="unarchive_error_installer_disabled_title" msgid="4815715617014985605">"<xliff:g id="INSTALLERNAME">%1$s</xliff:g> ਨੂੰ ਬੰਦ ਕੀਤਾ ਗਿਆ"</string>
+ <!-- no translation found for unarchive_error_installer_disabled_body (4820821285907011729) -->
+ <skip />
+ <string name="unarchive_error_installer_uninstalled_title" msgid="3748354109176326489">"<xliff:g id="INSTALLERNAME">%1$s</xliff:g> ਨੂੰ ਅਣਸਥਾਪਤ ਕੀਤਾ ਗਿਆ"</string>
+ <string name="unarchive_error_installer_uninstalled_body" msgid="944733542444183204">"ਇਸ ਐਪ ਨੂੰ ਮੁੜ-ਬਹਾਲ ਕਰਨ ਲਈ, ਤੁਹਾਨੂੰ <xliff:g id="INSTALLERNAME">%1$s</xliff:g> ਨੂੰ ਸਥਾਪਤ ਕਰਨ ਦੀ ਲੋੜ ਪਵੇਗੀ"</string>
+ <string name="unarchive_action_required_continue" msgid="5711202111224184257">"ਜਾਰੀ ਰੱਖੋ"</string>
+ <string name="unarchive_clear_storage_button" msgid="1549537154535608744">"ਸਟੋਰੇਜ ਕਲੀਅਰ ਕਰੋ"</string>
+ <string name="unarchive_settings_button" msgid="3504171760009177425">"ਸੈਟਿੰਗਾਂ"</string>
+ <string name="close" msgid="5214897374055647996">"ਬੰਦ ਕਰੋ"</string>
</resources>
diff --git a/packages/PackageInstaller/res/values-pl/strings.xml b/packages/PackageInstaller/res/values-pl/strings.xml
index 8fa11ed..6aa6aff 100644
--- a/packages/PackageInstaller/res/values-pl/strings.xml
+++ b/packages/PackageInstaller/res/values-pl/strings.xml
@@ -66,6 +66,7 @@
<string name="uninstall_keep_data" msgid="7002379587465487550">"Zachowaj <xliff:g id="SIZE">%1$s</xliff:g> danych aplikacji."</string>
<string name="uninstall_application_text_current_user_clone_profile" msgid="835170400160011636">"Chcesz usunąć tę aplikację?"</string>
<string name="uninstall_application_text_with_clone_instance" msgid="6944473334273349036">"Chcesz odinstalować tę aplikację? Klon aplikacji <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g> również zostanie usunięty."</string>
+ <string name="uninstall_application_text_current_user_private_profile" msgid="867004464945674674">"Chcesz odinstalować tę aplikację ze swojego obszaru prywatnego?"</string>
<string name="uninstalling_notification_channel" msgid="840153394325714653">"Aktywne odinstalowania"</string>
<string name="uninstall_failure_notification_channel" msgid="1136405866767576588">"Nieudane odinstalowania"</string>
<string name="uninstalling" msgid="8709566347688966845">"Odinstalowuję…"</string>
@@ -106,4 +107,21 @@
<string name="unarchive_application_title" msgid="7958278328280721421">"Przywrócić aplikację <xliff:g id="APPNAME">%1$s</xliff:g> z aplikacji <xliff:g id="INSTALLERNAME">%1$s</xliff:g>?"</string>
<string name="unarchive_body_text" msgid="8244155079861708964">"Ta aplikacja zacznie pobieranie w tle"</string>
<string name="restore" msgid="8460854736328970444">"Przywróć"</string>
+ <string name="unarchive_error_offline_title" msgid="4021785324565678605">"Jesteś offline"</string>
+ <string name="unarchive_error_offline_body" msgid="255717000519772755">"Ta aplikacja zostanie automatycznie przywrócona, gdy połączysz się z internetem"</string>
+ <string name="unarchive_error_generic_title" msgid="7123457671482449992">"Coś poszło nie tak"</string>
+ <string name="unarchive_error_generic_body" msgid="4486803312463813079">"Podczas przywracania tej aplikacji wystąpił błąd"</string>
+ <string name="unarchive_error_storage_title" msgid="5080723357273852630">"Za mało miejsca na dane"</string>
+ <string name="unarchive_error_storage_body" msgid="6879544407568780524">"Aby przywrócić tę aplikację, musisz zwolnić miejsce na urządzeniu. Wymagane miejsce na dane: <xliff:g id="BYTES">%1$s</xliff:g>"</string>
+ <string name="unarchive_action_required_title" msgid="4971245740162604619">"Wymagane działanie"</string>
+ <string name="unarchive_action_required_body" msgid="1679431572983989231">"Aby przywrócić tę aplikację, wykonaj następne czynności"</string>
+ <string name="unarchive_error_installer_disabled_title" msgid="4815715617014985605">"Aplikacja <xliff:g id="INSTALLERNAME">%1$s</xliff:g> jest wyłączona"</string>
+ <!-- no translation found for unarchive_error_installer_disabled_body (4820821285907011729) -->
+ <skip />
+ <string name="unarchive_error_installer_uninstalled_title" msgid="3748354109176326489">"Aplikacja <xliff:g id="INSTALLERNAME">%1$s</xliff:g> jest odinstalowana"</string>
+ <string name="unarchive_error_installer_uninstalled_body" msgid="944733542444183204">"Aby przywrócić tę aplikację, musisz zainstalować aplikację <xliff:g id="INSTALLERNAME">%1$s</xliff:g>"</string>
+ <string name="unarchive_action_required_continue" msgid="5711202111224184257">"Dalej"</string>
+ <string name="unarchive_clear_storage_button" msgid="1549537154535608744">"Wyczyść pamięć"</string>
+ <string name="unarchive_settings_button" msgid="3504171760009177425">"Ustawienia"</string>
+ <string name="close" msgid="5214897374055647996">"Zamknij"</string>
</resources>
diff --git a/packages/PackageInstaller/res/values-pt-rBR/strings.xml b/packages/PackageInstaller/res/values-pt-rBR/strings.xml
index 71ecb2b3..3f71c49 100644
--- a/packages/PackageInstaller/res/values-pt-rBR/strings.xml
+++ b/packages/PackageInstaller/res/values-pt-rBR/strings.xml
@@ -66,6 +66,7 @@
<string name="uninstall_keep_data" msgid="7002379587465487550">"Manter <xliff:g id="SIZE">%1$s</xliff:g> de dados do app."</string>
<string name="uninstall_application_text_current_user_clone_profile" msgid="835170400160011636">"Quer excluir este app?"</string>
<string name="uninstall_application_text_with_clone_instance" msgid="6944473334273349036">"Quer desinstalar este app? O clone <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g> também vai ser excluído."</string>
+ <string name="uninstall_application_text_current_user_private_profile" msgid="867004464945674674">"Você quer desinstalar esse app do seu espaço particular?"</string>
<string name="uninstalling_notification_channel" msgid="840153394325714653">"Executando desinstalações"</string>
<string name="uninstall_failure_notification_channel" msgid="1136405866767576588">"Falha nas desinstalações"</string>
<string name="uninstalling" msgid="8709566347688966845">"Desinstalando…"</string>
@@ -106,4 +107,21 @@
<string name="unarchive_application_title" msgid="7958278328280721421">"Restaurar <xliff:g id="APPNAME">%1$s</xliff:g> usando o app <xliff:g id="INSTALLERNAME">%1$s</xliff:g>?"</string>
<string name="unarchive_body_text" msgid="8244155079861708964">"O download desse app será feito em segundo plano"</string>
<string name="restore" msgid="8460854736328970444">"Restaurar"</string>
+ <string name="unarchive_error_offline_title" msgid="4021785324565678605">"Você está off-line"</string>
+ <string name="unarchive_error_offline_body" msgid="255717000519772755">"Este app será restaurado automaticamente quando você tiver uma conexão de Internet"</string>
+ <string name="unarchive_error_generic_title" msgid="7123457671482449992">"Algo deu errado"</string>
+ <string name="unarchive_error_generic_body" msgid="4486803312463813079">"Ocorreu um problema ao tentar restaurar este app"</string>
+ <string name="unarchive_error_storage_title" msgid="5080723357273852630">"Armazenamento insuficiente"</string>
+ <string name="unarchive_error_storage_body" msgid="6879544407568780524">"Para restaurar o app, libere espaço no dispositivo. Armazenamento necessário: <xliff:g id="BYTES">%1$s</xliff:g>"</string>
+ <string name="unarchive_action_required_title" msgid="4971245740162604619">"Ação necessária"</string>
+ <string name="unarchive_action_required_body" msgid="1679431572983989231">"Siga as próximas etapas para restaurar este app"</string>
+ <string name="unarchive_error_installer_disabled_title" msgid="4815715617014985605">"A <xliff:g id="INSTALLERNAME">%1$s</xliff:g> está desativada"</string>
+ <!-- no translation found for unarchive_error_installer_disabled_body (4820821285907011729) -->
+ <skip />
+ <string name="unarchive_error_installer_uninstalled_title" msgid="3748354109176326489">"A <xliff:g id="INSTALLERNAME">%1$s</xliff:g> não está instalada"</string>
+ <string name="unarchive_error_installer_uninstalled_body" msgid="944733542444183204">"Para restaurar o app, instale a <xliff:g id="INSTALLERNAME">%1$s</xliff:g>"</string>
+ <string name="unarchive_action_required_continue" msgid="5711202111224184257">"Continuar"</string>
+ <string name="unarchive_clear_storage_button" msgid="1549537154535608744">"Limpar armazenamento"</string>
+ <string name="unarchive_settings_button" msgid="3504171760009177425">"Configurações"</string>
+ <string name="close" msgid="5214897374055647996">"Fechar"</string>
</resources>
diff --git a/packages/PackageInstaller/res/values-pt-rPT/strings.xml b/packages/PackageInstaller/res/values-pt-rPT/strings.xml
index 1d5c1a2..9d47276 100644
--- a/packages/PackageInstaller/res/values-pt-rPT/strings.xml
+++ b/packages/PackageInstaller/res/values-pt-rPT/strings.xml
@@ -66,6 +66,7 @@
<string name="uninstall_keep_data" msgid="7002379587465487550">"Manter <xliff:g id="SIZE">%1$s</xliff:g> de dados da app."</string>
<string name="uninstall_application_text_current_user_clone_profile" msgid="835170400160011636">"Quer apagar esta app?"</string>
<string name="uninstall_application_text_with_clone_instance" msgid="6944473334273349036">"Quer desinstalar esta app? O clone de <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g> também vai ser apagado."</string>
+ <string name="uninstall_application_text_current_user_private_profile" msgid="867004464945674674">"Quer desinstalar esta app do seu espaço privado?"</string>
<string name="uninstalling_notification_channel" msgid="840153394325714653">"Desinstalações em execução"</string>
<string name="uninstall_failure_notification_channel" msgid="1136405866767576588">"Desinstalações com falha"</string>
<string name="uninstalling" msgid="8709566347688966845">"A desinstalar…"</string>
@@ -106,4 +107,21 @@
<string name="unarchive_application_title" msgid="7958278328280721421">"Restaurar <xliff:g id="APPNAME">%1$s</xliff:g> a partir da <xliff:g id="INSTALLERNAME">%1$s</xliff:g>?"</string>
<string name="unarchive_body_text" msgid="8244155079861708964">"Esta app vai começar a ser transferida em segundo plano"</string>
<string name="restore" msgid="8460854736328970444">"Restaurar"</string>
+ <string name="unarchive_error_offline_title" msgid="4021785324565678605">"Está offline"</string>
+ <string name="unarchive_error_offline_body" msgid="255717000519772755">"Esta app vai ser reposta automaticamente quando estabelecer ligação à Internet"</string>
+ <string name="unarchive_error_generic_title" msgid="7123457671482449992">"Algo correu mal"</string>
+ <string name="unarchive_error_generic_body" msgid="4486803312463813079">"Ocorreu um problema ao tentar repor esta app"</string>
+ <string name="unarchive_error_storage_title" msgid="5080723357273852630">"Sem armazenamento suficiente"</string>
+ <string name="unarchive_error_storage_body" msgid="6879544407568780524">"Para repor esta app, pode libertar espaço neste dispositivo. Armazenamento necessário: <xliff:g id="BYTES">%1$s</xliff:g>"</string>
+ <string name="unarchive_action_required_title" msgid="4971245740162604619">"Ação necessária"</string>
+ <string name="unarchive_action_required_body" msgid="1679431572983989231">"Siga os passos abaixo para repor esta app"</string>
+ <string name="unarchive_error_installer_disabled_title" msgid="4815715617014985605">"O instalador <xliff:g id="INSTALLERNAME">%1$s</xliff:g> está desativado"</string>
+ <!-- no translation found for unarchive_error_installer_disabled_body (4820821285907011729) -->
+ <skip />
+ <string name="unarchive_error_installer_uninstalled_title" msgid="3748354109176326489">"O instalador <xliff:g id="INSTALLERNAME">%1$s</xliff:g> está desinstalado"</string>
+ <string name="unarchive_error_installer_uninstalled_body" msgid="944733542444183204">"Para repor esta app, tem de instalar o instalador <xliff:g id="INSTALLERNAME">%1$s</xliff:g>"</string>
+ <string name="unarchive_action_required_continue" msgid="5711202111224184257">"Continuar"</string>
+ <string name="unarchive_clear_storage_button" msgid="1549537154535608744">"Limpar armazenamento"</string>
+ <string name="unarchive_settings_button" msgid="3504171760009177425">"Definições"</string>
+ <string name="close" msgid="5214897374055647996">"Fechar"</string>
</resources>
diff --git a/packages/PackageInstaller/res/values-pt/strings.xml b/packages/PackageInstaller/res/values-pt/strings.xml
index 71ecb2b3..3f71c49 100644
--- a/packages/PackageInstaller/res/values-pt/strings.xml
+++ b/packages/PackageInstaller/res/values-pt/strings.xml
@@ -66,6 +66,7 @@
<string name="uninstall_keep_data" msgid="7002379587465487550">"Manter <xliff:g id="SIZE">%1$s</xliff:g> de dados do app."</string>
<string name="uninstall_application_text_current_user_clone_profile" msgid="835170400160011636">"Quer excluir este app?"</string>
<string name="uninstall_application_text_with_clone_instance" msgid="6944473334273349036">"Quer desinstalar este app? O clone <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g> também vai ser excluído."</string>
+ <string name="uninstall_application_text_current_user_private_profile" msgid="867004464945674674">"Você quer desinstalar esse app do seu espaço particular?"</string>
<string name="uninstalling_notification_channel" msgid="840153394325714653">"Executando desinstalações"</string>
<string name="uninstall_failure_notification_channel" msgid="1136405866767576588">"Falha nas desinstalações"</string>
<string name="uninstalling" msgid="8709566347688966845">"Desinstalando…"</string>
@@ -106,4 +107,21 @@
<string name="unarchive_application_title" msgid="7958278328280721421">"Restaurar <xliff:g id="APPNAME">%1$s</xliff:g> usando o app <xliff:g id="INSTALLERNAME">%1$s</xliff:g>?"</string>
<string name="unarchive_body_text" msgid="8244155079861708964">"O download desse app será feito em segundo plano"</string>
<string name="restore" msgid="8460854736328970444">"Restaurar"</string>
+ <string name="unarchive_error_offline_title" msgid="4021785324565678605">"Você está off-line"</string>
+ <string name="unarchive_error_offline_body" msgid="255717000519772755">"Este app será restaurado automaticamente quando você tiver uma conexão de Internet"</string>
+ <string name="unarchive_error_generic_title" msgid="7123457671482449992">"Algo deu errado"</string>
+ <string name="unarchive_error_generic_body" msgid="4486803312463813079">"Ocorreu um problema ao tentar restaurar este app"</string>
+ <string name="unarchive_error_storage_title" msgid="5080723357273852630">"Armazenamento insuficiente"</string>
+ <string name="unarchive_error_storage_body" msgid="6879544407568780524">"Para restaurar o app, libere espaço no dispositivo. Armazenamento necessário: <xliff:g id="BYTES">%1$s</xliff:g>"</string>
+ <string name="unarchive_action_required_title" msgid="4971245740162604619">"Ação necessária"</string>
+ <string name="unarchive_action_required_body" msgid="1679431572983989231">"Siga as próximas etapas para restaurar este app"</string>
+ <string name="unarchive_error_installer_disabled_title" msgid="4815715617014985605">"A <xliff:g id="INSTALLERNAME">%1$s</xliff:g> está desativada"</string>
+ <!-- no translation found for unarchive_error_installer_disabled_body (4820821285907011729) -->
+ <skip />
+ <string name="unarchive_error_installer_uninstalled_title" msgid="3748354109176326489">"A <xliff:g id="INSTALLERNAME">%1$s</xliff:g> não está instalada"</string>
+ <string name="unarchive_error_installer_uninstalled_body" msgid="944733542444183204">"Para restaurar o app, instale a <xliff:g id="INSTALLERNAME">%1$s</xliff:g>"</string>
+ <string name="unarchive_action_required_continue" msgid="5711202111224184257">"Continuar"</string>
+ <string name="unarchive_clear_storage_button" msgid="1549537154535608744">"Limpar armazenamento"</string>
+ <string name="unarchive_settings_button" msgid="3504171760009177425">"Configurações"</string>
+ <string name="close" msgid="5214897374055647996">"Fechar"</string>
</resources>
diff --git a/packages/PackageInstaller/res/values-ro/strings.xml b/packages/PackageInstaller/res/values-ro/strings.xml
index 810f544..a48c9c5 100644
--- a/packages/PackageInstaller/res/values-ro/strings.xml
+++ b/packages/PackageInstaller/res/values-ro/strings.xml
@@ -66,6 +66,7 @@
<string name="uninstall_keep_data" msgid="7002379587465487550">"Păstrează <xliff:g id="SIZE">%1$s</xliff:g> din datele aplicației."</string>
<string name="uninstall_application_text_current_user_clone_profile" msgid="835170400160011636">"Vrei să ștergi această aplicație?"</string>
<string name="uninstall_application_text_with_clone_instance" msgid="6944473334273349036">"Dezinstalezi această aplicație? Se va șterge și clona <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g>."</string>
+ <string name="uninstall_application_text_current_user_private_profile" msgid="867004464945674674">"Dezinstalezi aplicația din spațiul privat?"</string>
<string name="uninstalling_notification_channel" msgid="840153394325714653">"Dezinstalări în curs"</string>
<string name="uninstall_failure_notification_channel" msgid="1136405866767576588">"Dezinstalări nereușite"</string>
<string name="uninstalling" msgid="8709566347688966845">"Se dezinstalează…"</string>
@@ -106,4 +107,21 @@
<string name="unarchive_application_title" msgid="7958278328280721421">"Restabilești <xliff:g id="APPNAME">%1$s</xliff:g> din <xliff:g id="INSTALLERNAME">%1$s</xliff:g>?"</string>
<string name="unarchive_body_text" msgid="8244155079861708964">"Descărcarea aplicației va începe în fundal"</string>
<string name="restore" msgid="8460854736328970444">"Restabilește"</string>
+ <string name="unarchive_error_offline_title" msgid="4021785324565678605">"Ești offline"</string>
+ <string name="unarchive_error_offline_body" msgid="255717000519772755">"Aplicația va fi restabilită automat după ce te conectezi la internet"</string>
+ <string name="unarchive_error_generic_title" msgid="7123457671482449992">"A apărut o eroare"</string>
+ <string name="unarchive_error_generic_body" msgid="4486803312463813079">"A apărut o problemă la restabilirea aplicației"</string>
+ <string name="unarchive_error_storage_title" msgid="5080723357273852630">"Nu există suficient spațiu de stocare"</string>
+ <string name="unarchive_error_storage_body" msgid="6879544407568780524">"Pentru a restabili aplicația, eliberează spațiu pe dispozitiv. Spațiu de stocare necesar: <xliff:g id="BYTES">%1$s</xliff:g>"</string>
+ <string name="unarchive_action_required_title" msgid="4971245740162604619">"Acțiune necesară"</string>
+ <string name="unarchive_action_required_body" msgid="1679431572983989231">"Urmează pașii de mai jos pentru a restabili aplicația"</string>
+ <string name="unarchive_error_installer_disabled_title" msgid="4815715617014985605">"<xliff:g id="INSTALLERNAME">%1$s</xliff:g> este dezactivat"</string>
+ <!-- no translation found for unarchive_error_installer_disabled_body (4820821285907011729) -->
+ <skip />
+ <string name="unarchive_error_installer_uninstalled_title" msgid="3748354109176326489">"<xliff:g id="INSTALLERNAME">%1$s</xliff:g> este dezinstalat"</string>
+ <string name="unarchive_error_installer_uninstalled_body" msgid="944733542444183204">"Pentru a restabili aplicația, va trebui să instalezi <xliff:g id="INSTALLERNAME">%1$s</xliff:g>"</string>
+ <string name="unarchive_action_required_continue" msgid="5711202111224184257">"Continuă"</string>
+ <string name="unarchive_clear_storage_button" msgid="1549537154535608744">"Șterge datele stocate"</string>
+ <string name="unarchive_settings_button" msgid="3504171760009177425">"Setări"</string>
+ <string name="close" msgid="5214897374055647996">"Închide"</string>
</resources>
diff --git a/packages/PackageInstaller/res/values-ru/strings.xml b/packages/PackageInstaller/res/values-ru/strings.xml
index e368f12..93cc6d8 100644
--- a/packages/PackageInstaller/res/values-ru/strings.xml
+++ b/packages/PackageInstaller/res/values-ru/strings.xml
@@ -66,6 +66,7 @@
<string name="uninstall_keep_data" msgid="7002379587465487550">"Сохранить данные приложения (<xliff:g id="SIZE">%1$s</xliff:g>)"</string>
<string name="uninstall_application_text_current_user_clone_profile" msgid="835170400160011636">"Удалить это приложение?"</string>
<string name="uninstall_application_text_with_clone_instance" msgid="6944473334273349036">"Удалить это приложение? Клон приложения <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g> также будет удален."</string>
+ <string name="uninstall_application_text_current_user_private_profile" msgid="867004464945674674">"Удалить это приложение из личного пространства?"</string>
<string name="uninstalling_notification_channel" msgid="840153394325714653">"Активные процессы удаления"</string>
<string name="uninstall_failure_notification_channel" msgid="1136405866767576588">"Ошибки удаления"</string>
<string name="uninstalling" msgid="8709566347688966845">"Удаление…"</string>
@@ -106,4 +107,21 @@
<string name="unarchive_application_title" msgid="7958278328280721421">"Восстановить приложение \"<xliff:g id="APPNAME">%1$s</xliff:g>\" из <xliff:g id="INSTALLERNAME">%1$s</xliff:g>?"</string>
<string name="unarchive_body_text" msgid="8244155079861708964">"Приложение начнет скачиваться в фоновом режиме."</string>
<string name="restore" msgid="8460854736328970444">"Восстановить"</string>
+ <string name="unarchive_error_offline_title" msgid="4021785324565678605">"Нет доступа к Сети"</string>
+ <string name="unarchive_error_offline_body" msgid="255717000519772755">"Приложение автоматически восстановится, когда устройство будет подключено к интернету."</string>
+ <string name="unarchive_error_generic_title" msgid="7123457671482449992">"Что-то пошло не так"</string>
+ <string name="unarchive_error_generic_body" msgid="4486803312463813079">"Не удалось восстановить приложение."</string>
+ <string name="unarchive_error_storage_title" msgid="5080723357273852630">"Недостаточно места"</string>
+ <string name="unarchive_error_storage_body" msgid="6879544407568780524">"Чтобы восстановить приложение, освободите место на устройстве. Необходимо <xliff:g id="BYTES">%1$s</xliff:g>."</string>
+ <string name="unarchive_action_required_title" msgid="4971245740162604619">"Требуется действие"</string>
+ <string name="unarchive_action_required_body" msgid="1679431572983989231">"Чтобы восстановить приложение, следуйте дальнейшим инструкциям."</string>
+ <string name="unarchive_error_installer_disabled_title" msgid="4815715617014985605">"Установщик \"<xliff:g id="INSTALLERNAME">%1$s</xliff:g>\" отключен"</string>
+ <!-- no translation found for unarchive_error_installer_disabled_body (4820821285907011729) -->
+ <skip />
+ <string name="unarchive_error_installer_uninstalled_title" msgid="3748354109176326489">"Установщик \"<xliff:g id="INSTALLERNAME">%1$s</xliff:g>\" удален"</string>
+ <string name="unarchive_error_installer_uninstalled_body" msgid="944733542444183204">"Чтобы восстановить приложение, установите программу \"<xliff:g id="INSTALLERNAME">%1$s</xliff:g>\"."</string>
+ <string name="unarchive_action_required_continue" msgid="5711202111224184257">"Продолжить"</string>
+ <string name="unarchive_clear_storage_button" msgid="1549537154535608744">"Очистить хранилище"</string>
+ <string name="unarchive_settings_button" msgid="3504171760009177425">"Настройки"</string>
+ <string name="close" msgid="5214897374055647996">"Закрыть"</string>
</resources>
diff --git a/packages/PackageInstaller/res/values-si/strings.xml b/packages/PackageInstaller/res/values-si/strings.xml
index cea50a6..7ee1c78 100644
--- a/packages/PackageInstaller/res/values-si/strings.xml
+++ b/packages/PackageInstaller/res/values-si/strings.xml
@@ -66,6 +66,7 @@
<string name="uninstall_keep_data" msgid="7002379587465487550">"යෙදුම් දත්තවලින් <xliff:g id="SIZE">%1$s</xliff:g> තබා ගන්න."</string>
<string name="uninstall_application_text_current_user_clone_profile" msgid="835170400160011636">"ඔබට මෙම යෙදුම මැකීමට අවශ්ය ද?"</string>
<string name="uninstall_application_text_with_clone_instance" msgid="6944473334273349036">"ඔබට මෙම යෙදුම අස්ථාපනය කිරීමට අවශ්ය ද? <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g> ක්ලෝනය ද මකා දැමෙනු ඇත."</string>
+ <string name="uninstall_application_text_current_user_private_profile" msgid="867004464945674674">"ඔබට ඔබේ පෞද්ගලික අවකාශයෙන් මෙම යෙදුම අස්ථාපනය කිරීමට අවශ්ය ද?"</string>
<string name="uninstalling_notification_channel" msgid="840153394325714653">"අස්ථාපන ධාවනය කරමින්"</string>
<string name="uninstall_failure_notification_channel" msgid="1136405866767576588">"අසාර්ථක වූ අස්ථාපන"</string>
<string name="uninstalling" msgid="8709566347688966845">"අස්ථාපනය කරමින්…"</string>
@@ -106,4 +107,21 @@
<string name="unarchive_application_title" msgid="7958278328280721421">"<xliff:g id="INSTALLERNAME">%1$s</xliff:g> වෙතින් <xliff:g id="APPNAME">%1$s</xliff:g> ප්රතිසාධනය කරන්න ද?"</string>
<string name="unarchive_body_text" msgid="8244155079861708964">"මෙම යෙදුම පසුබිමේ බාගැනීම ආරම්භ කරනු ඇත"</string>
<string name="restore" msgid="8460854736328970444">"ප්රතිසාධනය කරන්න"</string>
+ <string name="unarchive_error_offline_title" msgid="4021785324565678605">"ඔබ නොබැඳි වේ"</string>
+ <string name="unarchive_error_offline_body" msgid="255717000519772755">"ඔබ අන්තර්ජාලයට සම්බන්ධ වූ විට මෙම යෙදුම ස්වයංක්රීයව ප්රතිසාධනය වනු ඇත"</string>
+ <string name="unarchive_error_generic_title" msgid="7123457671482449992">"යමක් වැරදී ඇත"</string>
+ <string name="unarchive_error_generic_body" msgid="4486803312463813079">"මෙම යෙදුම ප්රතිසාධනය කිරීමට උත්සාහ කිරීමේ ගැටලුවක් ඇති විය"</string>
+ <string name="unarchive_error_storage_title" msgid="5080723357273852630">"ප්රමාණවත් ආචයනයක් නොමැත"</string>
+ <string name="unarchive_error_storage_body" msgid="6879544407568780524">"මෙම යෙදුම ප්රතිසාධනය කිරීම සඳහා, ඔබට මෙම උපාංගයෙහි ඉඩ නිදහස් කර ගත හැක. අවශ්ය ආචයනය: <xliff:g id="BYTES">%1$s</xliff:g>"</string>
+ <string name="unarchive_action_required_title" msgid="4971245740162604619">"ක්රියාමාර්ගය අවශ්යයි"</string>
+ <string name="unarchive_action_required_body" msgid="1679431572983989231">"මෙම යෙදුම ප්රතිසාධනය කිරීමට මීළඟ පියවර අනුගමනය කරන්න"</string>
+ <string name="unarchive_error_installer_disabled_title" msgid="4815715617014985605">"<xliff:g id="INSTALLERNAME">%1$s</xliff:g> අබල කර ඇත"</string>
+ <!-- no translation found for unarchive_error_installer_disabled_body (4820821285907011729) -->
+ <skip />
+ <string name="unarchive_error_installer_uninstalled_title" msgid="3748354109176326489">"<xliff:g id="INSTALLERNAME">%1$s</xliff:g> අස්ථාපනය කර ඇත"</string>
+ <string name="unarchive_error_installer_uninstalled_body" msgid="944733542444183204">"මෙම යෙදුම ප්රතිසාධනය කිරීම සඳහා, ඔබට <xliff:g id="INSTALLERNAME">%1$s</xliff:g> ස්ථාපනය කිරීමට අවශ්ය වනු ඇත"</string>
+ <string name="unarchive_action_required_continue" msgid="5711202111224184257">"ඉදිරියට යන්න"</string>
+ <string name="unarchive_clear_storage_button" msgid="1549537154535608744">"ආචයනය හිස් කරන්න"</string>
+ <string name="unarchive_settings_button" msgid="3504171760009177425">"සැකසීම්"</string>
+ <string name="close" msgid="5214897374055647996">"වසන්න"</string>
</resources>
diff --git a/packages/PackageInstaller/res/values-sk/strings.xml b/packages/PackageInstaller/res/values-sk/strings.xml
index 34117c3..785a080 100644
--- a/packages/PackageInstaller/res/values-sk/strings.xml
+++ b/packages/PackageInstaller/res/values-sk/strings.xml
@@ -66,6 +66,7 @@
<string name="uninstall_keep_data" msgid="7002379587465487550">"Zachovať nasledujúcu veľkosť dát aplikácie: <xliff:g id="SIZE">%1$s</xliff:g>."</string>
<string name="uninstall_application_text_current_user_clone_profile" msgid="835170400160011636">"Chcete túto aplikáciu odstrániť?"</string>
<string name="uninstall_application_text_with_clone_instance" msgid="6944473334273349036">"Chcete túto aplikáciu odinštalovať? Bude odstránený aj klon aplikácie <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g>."</string>
+ <string name="uninstall_application_text_current_user_private_profile" msgid="867004464945674674">"Chcete túto aplikáciu odinštalovať zo svojho súkromného priestoru?"</string>
<string name="uninstalling_notification_channel" msgid="840153394325714653">"Prebiehajúce odinštalovania"</string>
<string name="uninstall_failure_notification_channel" msgid="1136405866767576588">"Neúspešné odinštalácie"</string>
<string name="uninstalling" msgid="8709566347688966845">"Prebieha odinštalovanie..."</string>
@@ -106,4 +107,21 @@
<string name="unarchive_application_title" msgid="7958278328280721421">"Chcete obnoviť <xliff:g id="APPNAME">%1$s</xliff:g> z inštalátora <xliff:g id="INSTALLERNAME">%1$s</xliff:g>?"</string>
<string name="unarchive_body_text" msgid="8244155079861708964">"Táto aplikácia sa začne sťahovať na pozadí"</string>
<string name="restore" msgid="8460854736328970444">"Obnoviť"</string>
+ <string name="unarchive_error_offline_title" msgid="4021785324565678605">"Ste offline"</string>
+ <string name="unarchive_error_offline_body" msgid="255717000519772755">"Po pripojení k internetu bude táto aplikácia automaticky obnovená"</string>
+ <string name="unarchive_error_generic_title" msgid="7123457671482449992">"Niečo sa pokazilo"</string>
+ <string name="unarchive_error_generic_body" msgid="4486803312463813079">"Pri pokuse o obnovenie tejto aplikácie sa vyskytol problém"</string>
+ <string name="unarchive_error_storage_title" msgid="5080723357273852630">"Úložisko je nedostatočné"</string>
+ <string name="unarchive_error_storage_body" msgid="6879544407568780524">"Ak chcete túto aplikáciu obnoviť, môžete uvoľniť priestor v tomto zariadení. Potrebný priestor: <xliff:g id="BYTES">%1$s</xliff:g>"</string>
+ <string name="unarchive_action_required_title" msgid="4971245740162604619">"Vyžaduje sa akcia"</string>
+ <string name="unarchive_action_required_body" msgid="1679431572983989231">"Podľa nasledujúcich krokov obnovte túto aplikáciu"</string>
+ <string name="unarchive_error_installer_disabled_title" msgid="4815715617014985605">"Inštalátor <xliff:g id="INSTALLERNAME">%1$s</xliff:g> je deaktivovaný"</string>
+ <!-- no translation found for unarchive_error_installer_disabled_body (4820821285907011729) -->
+ <skip />
+ <string name="unarchive_error_installer_uninstalled_title" msgid="3748354109176326489">"Inštalátor <xliff:g id="INSTALLERNAME">%1$s</xliff:g> je odinštalovaný"</string>
+ <string name="unarchive_error_installer_uninstalled_body" msgid="944733542444183204">"Ak chcete túto aplikáciu obnoviť, musíte si nainštalovať <xliff:g id="INSTALLERNAME">%1$s</xliff:g>"</string>
+ <string name="unarchive_action_required_continue" msgid="5711202111224184257">"Pokračovať"</string>
+ <string name="unarchive_clear_storage_button" msgid="1549537154535608744">"Vymazať priestor"</string>
+ <string name="unarchive_settings_button" msgid="3504171760009177425">"Nastavenia"</string>
+ <string name="close" msgid="5214897374055647996">"Zavrieť"</string>
</resources>
diff --git a/packages/PackageInstaller/res/values-sl/strings.xml b/packages/PackageInstaller/res/values-sl/strings.xml
index a303759..eae7c272 100644
--- a/packages/PackageInstaller/res/values-sl/strings.xml
+++ b/packages/PackageInstaller/res/values-sl/strings.xml
@@ -66,6 +66,7 @@
<string name="uninstall_keep_data" msgid="7002379587465487550">"Obdrži <xliff:g id="SIZE">%1$s</xliff:g> podatkov aplikacije."</string>
<string name="uninstall_application_text_current_user_clone_profile" msgid="835170400160011636">"Ali želite izbrisati to aplikacijo?"</string>
<string name="uninstall_application_text_with_clone_instance" msgid="6944473334273349036">"Ali želite odmestiti to aplikacijo? Izbrisana bo tudi klonirana aplikacija <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g>."</string>
+ <string name="uninstall_application_text_current_user_private_profile" msgid="867004464945674674">"Ali želite to aplikacijo odmestiti iz zasebnega prostora?"</string>
<string name="uninstalling_notification_channel" msgid="840153394325714653">"Odstranitve v teku"</string>
<string name="uninstall_failure_notification_channel" msgid="1136405866767576588">"Neuspele odstranitve"</string>
<string name="uninstalling" msgid="8709566347688966845">"Odstranjevanje …"</string>
@@ -106,4 +107,21 @@
<string name="unarchive_application_title" msgid="7958278328280721421">"Želite obnoviti aplikacijo <xliff:g id="APPNAME">%1$s</xliff:g> iz aplikacije <xliff:g id="INSTALLERNAME">%1$s</xliff:g>?"</string>
<string name="unarchive_body_text" msgid="8244155079861708964">"Aplikacija bo začela prenos v ozadju"</string>
<string name="restore" msgid="8460854736328970444">"Obnovi"</string>
+ <string name="unarchive_error_offline_title" msgid="4021785324565678605">"Nimate vzpostavljene povezave"</string>
+ <string name="unarchive_error_offline_body" msgid="255717000519772755">"Ta aplikacija bo samodejno obnovljena, ko boste povezani v internet."</string>
+ <string name="unarchive_error_generic_title" msgid="7123457671482449992">"Prišlo je do težave"</string>
+ <string name="unarchive_error_generic_body" msgid="4486803312463813079">"Pri obnavljanju te aplikacije je prišlo do težave."</string>
+ <string name="unarchive_error_storage_title" msgid="5080723357273852630">"Ni dovolj prostora za shranjevanje"</string>
+ <string name="unarchive_error_storage_body" msgid="6879544407568780524">"Če želite obnoviti to aplikacijo, sprostite prostor v tej napravi. Potrebni prostor za shranjevanje: <xliff:g id="BYTES">%1$s</xliff:g>"</string>
+ <string name="unarchive_action_required_title" msgid="4971245740162604619">"Potrebno je ukrepanje"</string>
+ <string name="unarchive_action_required_body" msgid="1679431572983989231">"Če želite obnoviti to aplikacijo, uporabite postopek, opisan v nadaljevanju."</string>
+ <string name="unarchive_error_installer_disabled_title" msgid="4815715617014985605">"Namestitveni program <xliff:g id="INSTALLERNAME">%1$s</xliff:g> je onemogočen"</string>
+ <!-- no translation found for unarchive_error_installer_disabled_body (4820821285907011729) -->
+ <skip />
+ <string name="unarchive_error_installer_uninstalled_title" msgid="3748354109176326489">"Namestitveni program <xliff:g id="INSTALLERNAME">%1$s</xliff:g> je odmeščen"</string>
+ <string name="unarchive_error_installer_uninstalled_body" msgid="944733542444183204">"Če želite obnoviti to aplikacijo, morate namestiti <xliff:g id="INSTALLERNAME">%1$s</xliff:g>."</string>
+ <string name="unarchive_action_required_continue" msgid="5711202111224184257">"Nadaljuj"</string>
+ <string name="unarchive_clear_storage_button" msgid="1549537154535608744">"Počisti shrambo"</string>
+ <string name="unarchive_settings_button" msgid="3504171760009177425">"Nastavitve"</string>
+ <string name="close" msgid="5214897374055647996">"Zapri"</string>
</resources>
diff --git a/packages/PackageInstaller/res/values-sq/strings.xml b/packages/PackageInstaller/res/values-sq/strings.xml
index 7f68c8b..b1f2775 100644
--- a/packages/PackageInstaller/res/values-sq/strings.xml
+++ b/packages/PackageInstaller/res/values-sq/strings.xml
@@ -66,6 +66,7 @@
<string name="uninstall_keep_data" msgid="7002379587465487550">"Mbaj <xliff:g id="SIZE">%1$s</xliff:g> nga të dhënat e aplikacionit."</string>
<string name="uninstall_application_text_current_user_clone_profile" msgid="835170400160011636">"Dëshiron ta fshish këtë aplikacion?"</string>
<string name="uninstall_application_text_with_clone_instance" msgid="6944473334273349036">"Dëshiron ta çinstalosh këtë aplikacion? Kloni i <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g> do të fshihet gjithashtu."</string>
+ <string name="uninstall_application_text_current_user_private_profile" msgid="867004464945674674">"Dëshiron ta çinstalosh këtë aplikacion nga hapësira jote private?"</string>
<string name="uninstalling_notification_channel" msgid="840153394325714653">"Çinstalimet në ekzekutim"</string>
<string name="uninstall_failure_notification_channel" msgid="1136405866767576588">"Çinstalimet e dështuara"</string>
<string name="uninstalling" msgid="8709566347688966845">"Po çinstalohet…"</string>
@@ -106,4 +107,21 @@
<string name="unarchive_application_title" msgid="7958278328280721421">"Të restaurohet <xliff:g id="APPNAME">%1$s</xliff:g> nga <xliff:g id="INSTALLERNAME">%1$s</xliff:g>?"</string>
<string name="unarchive_body_text" msgid="8244155079861708964">"Ky aplikacion do të fillojë të shkarkohet në sfond"</string>
<string name="restore" msgid="8460854736328970444">"Restauro"</string>
+ <string name="unarchive_error_offline_title" msgid="4021785324565678605">"Je offline"</string>
+ <string name="unarchive_error_offline_body" msgid="255717000519772755">"Ky aplikacion do të restaurohet automatikisht kur të lidhesh me internetin"</string>
+ <string name="unarchive_error_generic_title" msgid="7123457671482449992">"Ndodhi një gabim"</string>
+ <string name="unarchive_error_generic_body" msgid="4486803312463813079">"Pati një problem gjatë përpjekjes për të restauruar këtë aplikacion"</string>
+ <string name="unarchive_error_storage_title" msgid="5080723357273852630">"Hapësira ruajtëse e pamjaftueshme"</string>
+ <string name="unarchive_error_storage_body" msgid="6879544407568780524">"Për ta restauruar këtë aplikacion, mund të lirosh hapësirë në këtë pajisje. Hapësira ruajtëse e kërkuar: <xliff:g id="BYTES">%1$s</xliff:g>"</string>
+ <string name="unarchive_action_required_title" msgid="4971245740162604619">"Kërkohet veprim"</string>
+ <string name="unarchive_action_required_body" msgid="1679431572983989231">"Ndiq hapat e radhës për të restauruar këtë aplikacion"</string>
+ <string name="unarchive_error_installer_disabled_title" msgid="4815715617014985605">"<xliff:g id="INSTALLERNAME">%1$s</xliff:g> është çaktivizuar"</string>
+ <!-- no translation found for unarchive_error_installer_disabled_body (4820821285907011729) -->
+ <skip />
+ <string name="unarchive_error_installer_uninstalled_title" msgid="3748354109176326489">"<xliff:g id="INSTALLERNAME">%1$s</xliff:g> është çinstaluar"</string>
+ <string name="unarchive_error_installer_uninstalled_body" msgid="944733542444183204">"Për ta restauruar këtë aplikacion, do të të duhet të instalosh <xliff:g id="INSTALLERNAME">%1$s</xliff:g>"</string>
+ <string name="unarchive_action_required_continue" msgid="5711202111224184257">"Vazhdo"</string>
+ <string name="unarchive_clear_storage_button" msgid="1549537154535608744">"Pastro hapësirën ruajtëse"</string>
+ <string name="unarchive_settings_button" msgid="3504171760009177425">"Cilësimet"</string>
+ <string name="close" msgid="5214897374055647996">"Mbyll"</string>
</resources>
diff --git a/packages/PackageInstaller/res/values-sr/strings.xml b/packages/PackageInstaller/res/values-sr/strings.xml
index 196e784..3c51f34 100644
--- a/packages/PackageInstaller/res/values-sr/strings.xml
+++ b/packages/PackageInstaller/res/values-sr/strings.xml
@@ -66,6 +66,7 @@
<string name="uninstall_keep_data" msgid="7002379587465487550">"Задржи <xliff:g id="SIZE">%1$s</xliff:g> података апликације."</string>
<string name="uninstall_application_text_current_user_clone_profile" msgid="835170400160011636">"Желите да избришете ову апликацију?"</string>
<string name="uninstall_application_text_with_clone_instance" msgid="6944473334273349036">"Желите да деинсталирате ову апликацију? Клон апликације <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g> ће такође бити избрисан."</string>
+ <string name="uninstall_application_text_current_user_private_profile" msgid="867004464945674674">"Желите да деинсталирате ову апликацију из приватног простора?"</string>
<string name="uninstalling_notification_channel" msgid="840153394325714653">"Активна деинсталирања"</string>
<string name="uninstall_failure_notification_channel" msgid="1136405866767576588">"Неуспела деинсталирања"</string>
<string name="uninstalling" msgid="8709566347688966845">"Деинсталира се…"</string>
@@ -106,4 +107,21 @@
<string name="unarchive_application_title" msgid="7958278328280721421">"Желите да вратите <xliff:g id="APPNAME">%1$s</xliff:g> из <xliff:g id="INSTALLERNAME">%1$s</xliff:g>?"</string>
<string name="unarchive_body_text" msgid="8244155079861708964">"Апликација ће започети преузимање у позадини."</string>
<string name="restore" msgid="8460854736328970444">"Врати"</string>
+ <string name="unarchive_error_offline_title" msgid="4021785324565678605">"Офлајн сте"</string>
+ <string name="unarchive_error_offline_body" msgid="255717000519772755">"Ова апликација ће бити враћена аутоматски када се повежете на интернет"</string>
+ <string name="unarchive_error_generic_title" msgid="7123457671482449992">"Дошло је до грешке"</string>
+ <string name="unarchive_error_generic_body" msgid="4486803312463813079">"Дошло је до проблема при враћању ове апликације"</string>
+ <string name="unarchive_error_storage_title" msgid="5080723357273852630">"Нема довољно меморијског простора"</string>
+ <string name="unarchive_error_storage_body" msgid="6879544407568780524">"Можете да ослободите простор на овом уређају да бисте вратили ову апликацију. Потребан меморијски простор: <xliff:g id="BYTES">%1$s</xliff:g>"</string>
+ <string name="unarchive_action_required_title" msgid="4971245740162604619">"Треба да реагујете"</string>
+ <string name="unarchive_action_required_body" msgid="1679431572983989231">"Пратите даља упутства да бисте вратили ову апликацију"</string>
+ <string name="unarchive_error_installer_disabled_title" msgid="4815715617014985605">"Онемогућен <xliff:g id="INSTALLERNAME">%1$s</xliff:g>"</string>
+ <!-- no translation found for unarchive_error_installer_disabled_body (4820821285907011729) -->
+ <skip />
+ <string name="unarchive_error_installer_uninstalled_title" msgid="3748354109176326489">"Деинсталиран <xliff:g id="INSTALLERNAME">%1$s</xliff:g>"</string>
+ <string name="unarchive_error_installer_uninstalled_body" msgid="944733542444183204">"Да бисте вратили ову апликацију, треба да инсталирате <xliff:g id="INSTALLERNAME">%1$s</xliff:g>"</string>
+ <string name="unarchive_action_required_continue" msgid="5711202111224184257">"Настави"</string>
+ <string name="unarchive_clear_storage_button" msgid="1549537154535608744">"Обриши меморијски простор"</string>
+ <string name="unarchive_settings_button" msgid="3504171760009177425">"Подешавања"</string>
+ <string name="close" msgid="5214897374055647996">"Затвори"</string>
</resources>
diff --git a/packages/PackageInstaller/res/values-sv/strings.xml b/packages/PackageInstaller/res/values-sv/strings.xml
index 0ce696e..3fd403c 100644
--- a/packages/PackageInstaller/res/values-sv/strings.xml
+++ b/packages/PackageInstaller/res/values-sv/strings.xml
@@ -66,6 +66,7 @@
<string name="uninstall_keep_data" msgid="7002379587465487550">"Behåll <xliff:g id="SIZE">%1$s</xliff:g> appdata."</string>
<string name="uninstall_application_text_current_user_clone_profile" msgid="835170400160011636">"Vill du radera den här appen?"</string>
<string name="uninstall_application_text_with_clone_instance" msgid="6944473334273349036">"Vill du avinstallera den här appen? Klonen av <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g> raderas också."</string>
+ <string name="uninstall_application_text_current_user_private_profile" msgid="867004464945674674">"Vill du avinstallera appen från ditt privata rum?"</string>
<string name="uninstalling_notification_channel" msgid="840153394325714653">"Avinstallationer som pågår"</string>
<string name="uninstall_failure_notification_channel" msgid="1136405866767576588">"Avinstallationer som misslyckats"</string>
<string name="uninstalling" msgid="8709566347688966845">"Avinstallerar …"</string>
@@ -106,4 +107,21 @@
<string name="unarchive_application_title" msgid="7958278328280721421">"Vill du återställa <xliff:g id="APPNAME">%1$s</xliff:g> från <xliff:g id="INSTALLERNAME">%1$s</xliff:g>?"</string>
<string name="unarchive_body_text" msgid="8244155079861708964">"Appen börjar ladda ned i bakgrunden"</string>
<string name="restore" msgid="8460854736328970444">"Återställ"</string>
+ <string name="unarchive_error_offline_title" msgid="4021785324565678605">"Du är offline"</string>
+ <string name="unarchive_error_offline_body" msgid="255717000519772755">"Appen återställs automatiskt när du är ansluten till internet"</string>
+ <string name="unarchive_error_generic_title" msgid="7123457671482449992">"Något gick fel"</string>
+ <string name="unarchive_error_generic_body" msgid="4486803312463813079">"Det gick inte att återställa appen"</string>
+ <string name="unarchive_error_storage_title" msgid="5080723357273852630">"Inte tillräckligt med lagringsutrymme"</string>
+ <string name="unarchive_error_storage_body" msgid="6879544407568780524">"Frigör lagringsutrymme på enheten om du vill återställa appen. Tillgängligt lagringsutrymme som krävs: <xliff:g id="BYTES">%1$s</xliff:g>"</string>
+ <string name="unarchive_action_required_title" msgid="4971245740162604619">"Åtgärd krävs"</string>
+ <string name="unarchive_action_required_body" msgid="1679431572983989231">"Följ anvisningarna för att återställa appen"</string>
+ <string name="unarchive_error_installer_disabled_title" msgid="4815715617014985605">"<xliff:g id="INSTALLERNAME">%1$s</xliff:g> är inaktiverad"</string>
+ <!-- no translation found for unarchive_error_installer_disabled_body (4820821285907011729) -->
+ <skip />
+ <string name="unarchive_error_installer_uninstalled_title" msgid="3748354109176326489">"<xliff:g id="INSTALLERNAME">%1$s</xliff:g> är avinstallerad"</string>
+ <string name="unarchive_error_installer_uninstalled_body" msgid="944733542444183204">"Du måste installera <xliff:g id="INSTALLERNAME">%1$s</xliff:g> om du vill återställa appen"</string>
+ <string name="unarchive_action_required_continue" msgid="5711202111224184257">"Fortsätt"</string>
+ <string name="unarchive_clear_storage_button" msgid="1549537154535608744">"Rensa lagringsutrymme"</string>
+ <string name="unarchive_settings_button" msgid="3504171760009177425">"Inställningar"</string>
+ <string name="close" msgid="5214897374055647996">"Stäng"</string>
</resources>
diff --git a/packages/PackageInstaller/res/values-sw/strings.xml b/packages/PackageInstaller/res/values-sw/strings.xml
index 0a34d81..58d3277 100644
--- a/packages/PackageInstaller/res/values-sw/strings.xml
+++ b/packages/PackageInstaller/res/values-sw/strings.xml
@@ -66,6 +66,7 @@
<string name="uninstall_keep_data" msgid="7002379587465487550">"Dumisha <xliff:g id="SIZE">%1$s</xliff:g> ya data ya programu."</string>
<string name="uninstall_application_text_current_user_clone_profile" msgid="835170400160011636">"Ungependa kufuta programu hii?"</string>
<string name="uninstall_application_text_with_clone_instance" msgid="6944473334273349036">"Ungependa kuondoa programu hii? Nakala ya <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g> pia itafutwa."</string>
+ <string name="uninstall_application_text_current_user_private_profile" msgid="867004464945674674">"Je, ungependa kuondoa programu hii kwenye nafasi yako ya faragha?"</string>
<string name="uninstalling_notification_channel" msgid="840153394325714653">"Programu zinazoondolewa"</string>
<string name="uninstall_failure_notification_channel" msgid="1136405866767576588">"Mara ambazo programu haikuondolewa"</string>
<string name="uninstalling" msgid="8709566347688966845">"Inaondoa…"</string>
@@ -106,4 +107,21 @@
<string name="unarchive_application_title" msgid="7958278328280721421">"Je, ungependa kurejesha <xliff:g id="APPNAME">%1$s</xliff:g> kutoka kwenye <xliff:g id="INSTALLERNAME">%1$s</xliff:g>?"</string>
<string name="unarchive_body_text" msgid="8244155079861708964">"Itaanza kupakua programu hii chinichini"</string>
<string name="restore" msgid="8460854736328970444">"Rejesha"</string>
+ <string name="unarchive_error_offline_title" msgid="4021785324565678605">"Uko nje ya mtandao"</string>
+ <string name="unarchive_error_offline_body" msgid="255717000519772755">"Programu hii itarejeshwa kiotomatiki utakapounganisha kwenye intaneti"</string>
+ <string name="unarchive_error_generic_title" msgid="7123457671482449992">"Hitilafu fulani imetokea"</string>
+ <string name="unarchive_error_generic_body" msgid="4486803312463813079">"Hitilafu fulani imetokea wakati wa kujaribu kurejesha programu hii"</string>
+ <string name="unarchive_error_storage_title" msgid="5080723357273852630">"Nafasi ya hifadhi haitoshi"</string>
+ <string name="unarchive_error_storage_body" msgid="6879544407568780524">"Ili urejeshe programu hii, unaweza kufuta faili ili upate nafasi kwenye kifaa hiki. Nafasi ya hifadhi inayohitajika: <xliff:g id="BYTES">%1$s</xliff:g>"</string>
+ <string name="unarchive_action_required_title" msgid="4971245740162604619">"Unahitaji kuchukua hatua"</string>
+ <string name="unarchive_action_required_body" msgid="1679431572983989231">"Fuata hatua zinazofuata ili urejeshe programu hii"</string>
+ <string name="unarchive_error_installer_disabled_title" msgid="4815715617014985605">"<xliff:g id="INSTALLERNAME">%1$s</xliff:g> imezimwa"</string>
+ <!-- no translation found for unarchive_error_installer_disabled_body (4820821285907011729) -->
+ <skip />
+ <string name="unarchive_error_installer_uninstalled_title" msgid="3748354109176326489">"<xliff:g id="INSTALLERNAME">%1$s</xliff:g> imeondolewa"</string>
+ <string name="unarchive_error_installer_uninstalled_body" msgid="944733542444183204">"Ili urejeshe programu hii, utahitaji kusakinisha <xliff:g id="INSTALLERNAME">%1$s</xliff:g>"</string>
+ <string name="unarchive_action_required_continue" msgid="5711202111224184257">"Endelea"</string>
+ <string name="unarchive_clear_storage_button" msgid="1549537154535608744">"Futa data kwenye hifadhi"</string>
+ <string name="unarchive_settings_button" msgid="3504171760009177425">"Mipangilio"</string>
+ <string name="close" msgid="5214897374055647996">"Funga"</string>
</resources>
diff --git a/packages/PackageInstaller/res/values-ta/strings.xml b/packages/PackageInstaller/res/values-ta/strings.xml
index 322ce5c..4ae9e91 100644
--- a/packages/PackageInstaller/res/values-ta/strings.xml
+++ b/packages/PackageInstaller/res/values-ta/strings.xml
@@ -66,6 +66,7 @@
<string name="uninstall_keep_data" msgid="7002379587465487550">"<xliff:g id="SIZE">%1$s</xliff:g> ஆப்ஸ் தரவை வைத்திரு."</string>
<string name="uninstall_application_text_current_user_clone_profile" msgid="835170400160011636">"இந்த ஆப்ஸை நீக்க வேண்டுமா?"</string>
<string name="uninstall_application_text_with_clone_instance" msgid="6944473334273349036">"இந்த ஆப்ஸை நிறுவல் நீக்க வேண்டுமா? <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g> குளோனும் நீக்கப்படும்."</string>
+ <string name="uninstall_application_text_current_user_private_profile" msgid="867004464945674674">"உங்கள் தனிப்பட்ட சேமிப்பிடத்திலிருந்து இந்த ஆப்ஸை நிறுவல் நீக்க வேண்டுமா?"</string>
<string name="uninstalling_notification_channel" msgid="840153394325714653">"இயக்கத்திலுள்ள நிறுவல் நீக்கங்கள்"</string>
<string name="uninstall_failure_notification_channel" msgid="1136405866767576588">"தோல்வியுற்ற நிறுவல் நீக்கங்கள்"</string>
<string name="uninstalling" msgid="8709566347688966845">"நிறுவல் நீக்குகிறது…"</string>
@@ -106,4 +107,21 @@
<string name="unarchive_application_title" msgid="7958278328280721421">"<xliff:g id="INSTALLERNAME">%1$s</xliff:g>ல் இருந்து <xliff:g id="APPNAME">%1$s</xliff:g> ஐ மீட்டெடுக்கவா?"</string>
<string name="unarchive_body_text" msgid="8244155079861708964">"இந்த ஆப்ஸ் பின்னணியில் பதிவிறக்கத் தொடங்கும்"</string>
<string name="restore" msgid="8460854736328970444">"மீட்டெடு"</string>
+ <string name="unarchive_error_offline_title" msgid="4021785324565678605">"ஆஃப்லைனில் உள்ளீர்கள்"</string>
+ <string name="unarchive_error_offline_body" msgid="255717000519772755">"நீங்கள் இணையத்துடன் இணைக்கப்பட்டிருக்கும்போது இந்த ஆப்ஸ் தானாக மீட்டெடுக்கப்படும்"</string>
+ <string name="unarchive_error_generic_title" msgid="7123457671482449992">"ஏதோ தவறாகிவிட்டது"</string>
+ <string name="unarchive_error_generic_body" msgid="4486803312463813079">"இந்த ஆப்ஸை மீட்டெடுக்க முயலும்போது சிக்கல் ஏற்பட்டது"</string>
+ <string name="unarchive_error_storage_title" msgid="5080723357273852630">"போதுமான சேமிப்பகம் இல்லை"</string>
+ <string name="unarchive_error_storage_body" msgid="6879544407568780524">"இந்த ஆப்ஸை மீட்டெடுக்க, இந்தச் சாதனத்தில் உள்ள சேமிப்பகத்தை காலியாக்கலாம். தேவைப்படும் சேமிப்பகம்: <xliff:g id="BYTES">%1$s</xliff:g>"</string>
+ <string name="unarchive_action_required_title" msgid="4971245740162604619">"நடவடிக்கை தேவை"</string>
+ <string name="unarchive_action_required_body" msgid="1679431572983989231">"இந்த ஆப்ஸை மீட்டெடுக்க அடுத்த வழிமுறைகளைப் பின்பற்றுங்கள்"</string>
+ <string name="unarchive_error_installer_disabled_title" msgid="4815715617014985605">"<xliff:g id="INSTALLERNAME">%1$s</xliff:g> முடக்கப்பட்டுள்ளது"</string>
+ <!-- no translation found for unarchive_error_installer_disabled_body (4820821285907011729) -->
+ <skip />
+ <string name="unarchive_error_installer_uninstalled_title" msgid="3748354109176326489">"<xliff:g id="INSTALLERNAME">%1$s</xliff:g> நிறுவல் நீக்கப்பட்டது"</string>
+ <string name="unarchive_error_installer_uninstalled_body" msgid="944733542444183204">"இந்த ஆப்ஸை மீட்டெடுக்க <xliff:g id="INSTALLERNAME">%1$s</xliff:g> ஐ நிறுவ வேண்டும்"</string>
+ <string name="unarchive_action_required_continue" msgid="5711202111224184257">"தொடர்க"</string>
+ <string name="unarchive_clear_storage_button" msgid="1549537154535608744">"சேமிப்பகத்தைக் காலியாக்கு"</string>
+ <string name="unarchive_settings_button" msgid="3504171760009177425">"அமைப்புகள்"</string>
+ <string name="close" msgid="5214897374055647996">"மூடுக"</string>
</resources>
diff --git a/packages/PackageInstaller/res/values-te/strings.xml b/packages/PackageInstaller/res/values-te/strings.xml
index 9abc87e..45f895b 100644
--- a/packages/PackageInstaller/res/values-te/strings.xml
+++ b/packages/PackageInstaller/res/values-te/strings.xml
@@ -66,6 +66,7 @@
<string name="uninstall_keep_data" msgid="7002379587465487550">"<xliff:g id="SIZE">%1$s</xliff:g> యాప్ డేటాను ఉంచండి."</string>
<string name="uninstall_application_text_current_user_clone_profile" msgid="835170400160011636">"మీరు ఈ యాప్ను తొలగించాలనుకుంటున్నారా?"</string>
<string name="uninstall_application_text_with_clone_instance" msgid="6944473334273349036">"మీరు ఈ యాప్ను అన్ఇన్స్టాల్ చేయాలనుకుంటున్నారా? <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g> క్లోన్ కూడా తొలగించబడుతుంది."</string>
+ <string name="uninstall_application_text_current_user_private_profile" msgid="867004464945674674">"మీరు మీ ప్రైవేట్ స్పేస్ నుండి ఈ యాప్ను అన్ఇన్స్టాల్ చేయాలనుకుంటున్నారా?"</string>
<string name="uninstalling_notification_channel" msgid="840153394325714653">"అన్ఇన్స్టాల్ చేయబడుతున్నవి"</string>
<string name="uninstall_failure_notification_channel" msgid="1136405866767576588">"విఫలమైన అన్ఇన్స్టాల్లు"</string>
<string name="uninstalling" msgid="8709566347688966845">"అన్ఇన్స్టాల్ చేస్తోంది…"</string>
@@ -106,4 +107,21 @@
<string name="unarchive_application_title" msgid="7958278328280721421">"<xliff:g id="INSTALLERNAME">%1$s</xliff:g> నుండి <xliff:g id="APPNAME">%1$s</xliff:g>ను రీస్టోర్ చేయాలా?"</string>
<string name="unarchive_body_text" msgid="8244155079861708964">"ఈ యాప్ బ్యాక్గ్రౌండ్లో డౌన్లోడ్ అవ్వడం ప్రారంభమవుతుంది"</string>
<string name="restore" msgid="8460854736328970444">"రీస్టోర్ చేయండి"</string>
+ <string name="unarchive_error_offline_title" msgid="4021785324565678605">"మీరు ఆఫ్లైన్లో ఉన్నారు"</string>
+ <string name="unarchive_error_offline_body" msgid="255717000519772755">"మీరు ఇంటర్నెట్కు కనెక్ట్ అయ్యి ఉన్నప్పుడు ఈ యాప్ ఆటోమేటిక్గా రీస్టోర్ చేయబడుతుంది"</string>
+ <string name="unarchive_error_generic_title" msgid="7123457671482449992">"ఏదో పొరపాటు జరిగింది"</string>
+ <string name="unarchive_error_generic_body" msgid="4486803312463813079">"ఈ యాప్ను రీస్టోర్ చేయడానికి ట్రై చేస్తున్నపుడు సమస్య ఏర్పడింది"</string>
+ <string name="unarchive_error_storage_title" msgid="5080723357273852630">"తగినంత స్టోరేజ్ స్పేస్ లేదు"</string>
+ <string name="unarchive_error_storage_body" msgid="6879544407568780524">"ఈ యాప్ను రీస్టోర్ చేయడానికి, మీరు ఈ పరికరంలో స్పేస్ను ఖాళీ చేయవచ్చు. స్టోరేజ్ అవసరం: <xliff:g id="BYTES">%1$s</xliff:g>"</string>
+ <string name="unarchive_action_required_title" msgid="4971245740162604619">"మీరు పూర్తి చేయాల్సిన చర్య"</string>
+ <string name="unarchive_action_required_body" msgid="1679431572983989231">"ఈ యాప్ను రీస్టోర్ చేయడానికి తదుపరి దశలను ఫాలో అవ్వండి"</string>
+ <string name="unarchive_error_installer_disabled_title" msgid="4815715617014985605">"<xliff:g id="INSTALLERNAME">%1$s</xliff:g> డిజేబుల్ చేయబడింది"</string>
+ <!-- no translation found for unarchive_error_installer_disabled_body (4820821285907011729) -->
+ <skip />
+ <string name="unarchive_error_installer_uninstalled_title" msgid="3748354109176326489">"<xliff:g id="INSTALLERNAME">%1$s</xliff:g> అన్ఇన్స్టాల్ చేయబడింది"</string>
+ <string name="unarchive_error_installer_uninstalled_body" msgid="944733542444183204">"ఈ యాప్ను రీస్టోర్ చేయడానికి, మీరు <xliff:g id="INSTALLERNAME">%1$s</xliff:g>ను ఇన్స్టాల్ చేయాలి"</string>
+ <string name="unarchive_action_required_continue" msgid="5711202111224184257">"కొనసాగించండి"</string>
+ <string name="unarchive_clear_storage_button" msgid="1549537154535608744">"స్టోరేజ్ను క్లియర్ చేయండి"</string>
+ <string name="unarchive_settings_button" msgid="3504171760009177425">"సెట్టింగ్లు"</string>
+ <string name="close" msgid="5214897374055647996">"మూసివేయండి"</string>
</resources>
diff --git a/packages/PackageInstaller/res/values-th/strings.xml b/packages/PackageInstaller/res/values-th/strings.xml
index b1faa1c..7cdb3b2 100644
--- a/packages/PackageInstaller/res/values-th/strings.xml
+++ b/packages/PackageInstaller/res/values-th/strings.xml
@@ -66,6 +66,7 @@
<string name="uninstall_keep_data" msgid="7002379587465487550">"เก็บข้อมูลแอปไว้ <xliff:g id="SIZE">%1$s</xliff:g>"</string>
<string name="uninstall_application_text_current_user_clone_profile" msgid="835170400160011636">"ต้องการลบแอปนี้ไหม"</string>
<string name="uninstall_application_text_with_clone_instance" msgid="6944473334273349036">"ต้องการถอนการติดตั้งแอปนี้ไหม ระบบจะลบโคลนของ <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g> ด้วย"</string>
+ <string name="uninstall_application_text_current_user_private_profile" msgid="867004464945674674">"คุณต้องการถอนการติดตั้งแอปนี้จากพื้นที่ส่วนตัวไหม"</string>
<string name="uninstalling_notification_channel" msgid="840153394325714653">"กำลังเรียกใช้การถอนการติดตั้ง"</string>
<string name="uninstall_failure_notification_channel" msgid="1136405866767576588">"ถอนการติดตั้งไม่สำเร็จ"</string>
<string name="uninstalling" msgid="8709566347688966845">"กำลังถอนการติดตั้ง…"</string>
@@ -106,4 +107,21 @@
<string name="unarchive_application_title" msgid="7958278328280721421">"กู้คืน <xliff:g id="APPNAME">%1$s</xliff:g> จาก <xliff:g id="INSTALLERNAME">%1$s</xliff:g> ใช่ไหม"</string>
<string name="unarchive_body_text" msgid="8244155079861708964">"แอปนี้จะเริ่มดาวน์โหลดในเบื้องหลัง"</string>
<string name="restore" msgid="8460854736328970444">"กู้คืน"</string>
+ <string name="unarchive_error_offline_title" msgid="4021785324565678605">"คุณออฟไลน์อยู่"</string>
+ <string name="unarchive_error_offline_body" msgid="255717000519772755">"แอปนี้จะคืนค่าโดยอัตโนมัติเมื่อคุณเชื่อมต่อกับอินเทอร์เน็ต"</string>
+ <string name="unarchive_error_generic_title" msgid="7123457671482449992">"เกิดข้อผิดพลาด"</string>
+ <string name="unarchive_error_generic_body" msgid="4486803312463813079">"เกิดปัญหาขณะพยายามคืนค่าแอปนี้"</string>
+ <string name="unarchive_error_storage_title" msgid="5080723357273852630">"พื้นที่เก็บข้อมูลไม่เพียงพอ"</string>
+ <string name="unarchive_error_storage_body" msgid="6879544407568780524">"หากต้องการคืนค่าแอปนี้ คุณสามารถเพิ่มพื้นที่ว่างในอุปกรณ์ โดยจะต้องใช้พื้นที่เก็บข้อมูล <xliff:g id="BYTES">%1$s</xliff:g>"</string>
+ <string name="unarchive_action_required_title" msgid="4971245740162604619">"ขอให้ดำเนินการ"</string>
+ <string name="unarchive_action_required_body" msgid="1679431572983989231">"ทำตามขั้นตอนถัดไปเพื่อคืนค่าแอปนี้"</string>
+ <string name="unarchive_error_installer_disabled_title" msgid="4815715617014985605">"<xliff:g id="INSTALLERNAME">%1$s</xliff:g> ถูกปิดใช้"</string>
+ <!-- no translation found for unarchive_error_installer_disabled_body (4820821285907011729) -->
+ <skip />
+ <string name="unarchive_error_installer_uninstalled_title" msgid="3748354109176326489">"<xliff:g id="INSTALLERNAME">%1$s</xliff:g> ถูกถอนการติดตั้ง"</string>
+ <string name="unarchive_error_installer_uninstalled_body" msgid="944733542444183204">"หากต้องการคืนค่าแอปนี้ คุณจะต้องติดตั้ง <xliff:g id="INSTALLERNAME">%1$s</xliff:g>"</string>
+ <string name="unarchive_action_required_continue" msgid="5711202111224184257">"ต่อไป"</string>
+ <string name="unarchive_clear_storage_button" msgid="1549537154535608744">"ล้างพื้นที่เก็บข้อมูล"</string>
+ <string name="unarchive_settings_button" msgid="3504171760009177425">"การตั้งค่า"</string>
+ <string name="close" msgid="5214897374055647996">"ปิด"</string>
</resources>
diff --git a/packages/PackageInstaller/res/values-tl/strings.xml b/packages/PackageInstaller/res/values-tl/strings.xml
index 8e6e2517..f084030 100644
--- a/packages/PackageInstaller/res/values-tl/strings.xml
+++ b/packages/PackageInstaller/res/values-tl/strings.xml
@@ -66,6 +66,7 @@
<string name="uninstall_keep_data" msgid="7002379587465487550">"Panatilihin ang <xliff:g id="SIZE">%1$s</xliff:g> ng data ng app."</string>
<string name="uninstall_application_text_current_user_clone_profile" msgid="835170400160011636">"Gusto mo bang i-delete ang app na ito?"</string>
<string name="uninstall_application_text_with_clone_instance" msgid="6944473334273349036">"Gusto mo bang i-uninstall ang app na ito? Made-delete din ang clone ng <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g>."</string>
+ <string name="uninstall_application_text_current_user_private_profile" msgid="867004464945674674">"Gusto mo bang i-uninstall ang app na ito sa iyong pribadong space?"</string>
<string name="uninstalling_notification_channel" msgid="840153394325714653">"Mga kasalukuyang pag-uninstall"</string>
<string name="uninstall_failure_notification_channel" msgid="1136405866767576588">"Mga hindi na-uninstall"</string>
<string name="uninstalling" msgid="8709566347688966845">"Ina-uninstall…"</string>
@@ -106,4 +107,21 @@
<string name="unarchive_application_title" msgid="7958278328280721421">"I-restore ang <xliff:g id="APPNAME">%1$s</xliff:g> mula sa <xliff:g id="INSTALLERNAME">%1$s</xliff:g>?"</string>
<string name="unarchive_body_text" msgid="8244155079861708964">"Magsisimulang mag-download ang app na ito sa background"</string>
<string name="restore" msgid="8460854736328970444">"I-restore"</string>
+ <string name="unarchive_error_offline_title" msgid="4021785324565678605">"Offline ka"</string>
+ <string name="unarchive_error_offline_body" msgid="255717000519772755">"Awtomatikong mare-restore ang app na ito kapag nakakonekta ka sa internet"</string>
+ <string name="unarchive_error_generic_title" msgid="7123457671482449992">"Nagkaproblema"</string>
+ <string name="unarchive_error_generic_body" msgid="4486803312463813079">"Nagkaproblema sa pagsubok na i-restore ang app na ito"</string>
+ <string name="unarchive_error_storage_title" msgid="5080723357273852630">"Hindi sapat ang storage"</string>
+ <string name="unarchive_error_storage_body" msgid="6879544407568780524">"Para i-restore ang app na ito, puwede kang magbakante ng espasyo sa device na ito. Kinakailangang storage: <xliff:g id="BYTES">%1$s</xliff:g>"</string>
+ <string name="unarchive_action_required_title" msgid="4971245740162604619">"Nangangailangan ng pagkilos"</string>
+ <string name="unarchive_action_required_body" msgid="1679431572983989231">"Sundin ang mga susunod na hakbang para i-restore ang app na ito"</string>
+ <string name="unarchive_error_installer_disabled_title" msgid="4815715617014985605">"Naka-disable ang <xliff:g id="INSTALLERNAME">%1$s</xliff:g>"</string>
+ <!-- no translation found for unarchive_error_installer_disabled_body (4820821285907011729) -->
+ <skip />
+ <string name="unarchive_error_installer_uninstalled_title" msgid="3748354109176326489">"Na-uninstall ang <xliff:g id="INSTALLERNAME">%1$s</xliff:g>"</string>
+ <string name="unarchive_error_installer_uninstalled_body" msgid="944733542444183204">"Para i-restore ang app na ito, kailangan mong i-install ang <xliff:g id="INSTALLERNAME">%1$s</xliff:g>"</string>
+ <string name="unarchive_action_required_continue" msgid="5711202111224184257">"Magpatuloy"</string>
+ <string name="unarchive_clear_storage_button" msgid="1549537154535608744">"I-clear ang storage"</string>
+ <string name="unarchive_settings_button" msgid="3504171760009177425">"Mga Setting"</string>
+ <string name="close" msgid="5214897374055647996">"Isara"</string>
</resources>
diff --git a/packages/PackageInstaller/res/values-tr/strings.xml b/packages/PackageInstaller/res/values-tr/strings.xml
index dc84030..c322991 100644
--- a/packages/PackageInstaller/res/values-tr/strings.xml
+++ b/packages/PackageInstaller/res/values-tr/strings.xml
@@ -66,6 +66,7 @@
<string name="uninstall_keep_data" msgid="7002379587465487550">"Uygulama verilerinin <xliff:g id="SIZE">%1$s</xliff:g> kadarını sakla."</string>
<string name="uninstall_application_text_current_user_clone_profile" msgid="835170400160011636">"Bu uygulamayı silmek istiyor musunuz?"</string>
<string name="uninstall_application_text_with_clone_instance" msgid="6944473334273349036">"Bu uygulamanın yüklemesini kaldırmak istiyor musunuz? <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g> klonu da silinecektir."</string>
+ <string name="uninstall_application_text_current_user_private_profile" msgid="867004464945674674">"Bu uygulamanın gizli alanınızdaki yüklemesini kaldırmak istiyor musunuz?"</string>
<string name="uninstalling_notification_channel" msgid="840153394325714653">"Devam eden yükleme kaldırma işlemleri"</string>
<string name="uninstall_failure_notification_channel" msgid="1136405866767576588">"Başarısız yükleme kaldırma işlemleri"</string>
<string name="uninstalling" msgid="8709566347688966845">"Yükleme kaldırılıyor…"</string>
@@ -106,4 +107,21 @@
<string name="unarchive_application_title" msgid="7958278328280721421">"<xliff:g id="APPNAME">%1$s</xliff:g> uygulaması <xliff:g id="INSTALLERNAME">%1$s</xliff:g> üzerinden geri yüklensin mi?"</string>
<string name="unarchive_body_text" msgid="8244155079861708964">"Bu uygulama arka planda indirilmeye başlanacak"</string>
<string name="restore" msgid="8460854736328970444">"Geri yükle"</string>
+ <string name="unarchive_error_offline_title" msgid="4021785324565678605">"İnternete bağlı değilsiniz"</string>
+ <string name="unarchive_error_offline_body" msgid="255717000519772755">"Bu uygulama, internete bağlandığınızda otomatik olarak geri yüklenecek"</string>
+ <string name="unarchive_error_generic_title" msgid="7123457671482449992">"Bir hata oluştu"</string>
+ <string name="unarchive_error_generic_body" msgid="4486803312463813079">"Bu uygulamayı geri yüklemeye çalışırken bir sorun oluştu"</string>
+ <string name="unarchive_error_storage_title" msgid="5080723357273852630">"Yeterli depolama alanı yok"</string>
+ <string name="unarchive_error_storage_body" msgid="6879544407568780524">"Bu uygulamayı geri yüklemek için bu cihazda yer açabilirsiniz. Bunun için <xliff:g id="BYTES">%1$s</xliff:g> depolama alanı gerekiyor"</string>
+ <string name="unarchive_action_required_title" msgid="4971245740162604619">"İşlem gerekli"</string>
+ <string name="unarchive_action_required_body" msgid="1679431572983989231">"Bu uygulamayı geri yüklemek için sonraki adımları uygulayın"</string>
+ <string name="unarchive_error_installer_disabled_title" msgid="4815715617014985605">"<xliff:g id="INSTALLERNAME">%1$s</xliff:g> devre dışı bırakıldı"</string>
+ <!-- no translation found for unarchive_error_installer_disabled_body (4820821285907011729) -->
+ <skip />
+ <string name="unarchive_error_installer_uninstalled_title" msgid="3748354109176326489">"<xliff:g id="INSTALLERNAME">%1$s</xliff:g> yüklemesi kaldırılmış"</string>
+ <string name="unarchive_error_installer_uninstalled_body" msgid="944733542444183204">"Bu uygulamayı geri yüklemek için <xliff:g id="INSTALLERNAME">%1$s</xliff:g> yükleyicisini yüklemeniz gerekiyor"</string>
+ <string name="unarchive_action_required_continue" msgid="5711202111224184257">"Devam"</string>
+ <string name="unarchive_clear_storage_button" msgid="1549537154535608744">"Depolama alanını temizle"</string>
+ <string name="unarchive_settings_button" msgid="3504171760009177425">"Ayarlar"</string>
+ <string name="close" msgid="5214897374055647996">"Kapat"</string>
</resources>
diff --git a/packages/PackageInstaller/res/values-uk/strings.xml b/packages/PackageInstaller/res/values-uk/strings.xml
index 3d7083f..657eb39 100644
--- a/packages/PackageInstaller/res/values-uk/strings.xml
+++ b/packages/PackageInstaller/res/values-uk/strings.xml
@@ -66,6 +66,7 @@
<string name="uninstall_keep_data" msgid="7002379587465487550">"Залишити <xliff:g id="SIZE">%1$s</xliff:g> даних додатка."</string>
<string name="uninstall_application_text_current_user_clone_profile" msgid="835170400160011636">"Видалити цей додаток?"</string>
<string name="uninstall_application_text_with_clone_instance" msgid="6944473334273349036">"Видалити цей додаток? Копію <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g> також буде видалено."</string>
+ <string name="uninstall_application_text_current_user_private_profile" msgid="867004464945674674">"Видалити цей додаток із вашого приватного простору?"</string>
<string name="uninstalling_notification_channel" msgid="840153394325714653">"Активні видалення"</string>
<string name="uninstall_failure_notification_channel" msgid="1136405866767576588">"Невиконані видалення"</string>
<string name="uninstalling" msgid="8709566347688966845">"Видалення..."</string>
@@ -106,4 +107,21 @@
<string name="unarchive_application_title" msgid="7958278328280721421">"Відновити додаток <xliff:g id="APPNAME">%1$s</xliff:g> з <xliff:g id="INSTALLERNAME">%1$s</xliff:g>?"</string>
<string name="unarchive_body_text" msgid="8244155079861708964">"Цей додаток почне завантажуватись у фоновому режимі"</string>
<string name="restore" msgid="8460854736328970444">"Відновити"</string>
+ <string name="unarchive_error_offline_title" msgid="4021785324565678605">"Пристрій не в мережі"</string>
+ <string name="unarchive_error_offline_body" msgid="255717000519772755">"Додаток автоматично відновиться, коли пристрій підключиться до Інтернету"</string>
+ <string name="unarchive_error_generic_title" msgid="7123457671482449992">"Помилка"</string>
+ <string name="unarchive_error_generic_body" msgid="4486803312463813079">"Під час спроби відновити цей додаток сталася помилка"</string>
+ <string name="unarchive_error_storage_title" msgid="5080723357273852630">"Недостатньо пам’яті"</string>
+ <string name="unarchive_error_storage_body" msgid="6879544407568780524">"Щоб відновити цей додаток, ви можете звільнити місце на пристрої. Потрібний обсяг пам’яті: <xliff:g id="BYTES">%1$s</xliff:g>"</string>
+ <string name="unarchive_action_required_title" msgid="4971245740162604619">"Потрібна дія"</string>
+ <string name="unarchive_action_required_body" msgid="1679431572983989231">"Виконайте подальші вказівки, щоб відновити цей додаток"</string>
+ <string name="unarchive_error_installer_disabled_title" msgid="4815715617014985605">"<xliff:g id="INSTALLERNAME">%1$s</xliff:g> вимкнено"</string>
+ <!-- no translation found for unarchive_error_installer_disabled_body (4820821285907011729) -->
+ <skip />
+ <string name="unarchive_error_installer_uninstalled_title" msgid="3748354109176326489">"<xliff:g id="INSTALLERNAME">%1$s</xliff:g> видалено"</string>
+ <string name="unarchive_error_installer_uninstalled_body" msgid="944733542444183204">"Щоб відновити цей додаток, установіть <xliff:g id="INSTALLERNAME">%1$s</xliff:g>"</string>
+ <string name="unarchive_action_required_continue" msgid="5711202111224184257">"Продовжити"</string>
+ <string name="unarchive_clear_storage_button" msgid="1549537154535608744">"Очистити пам’ять"</string>
+ <string name="unarchive_settings_button" msgid="3504171760009177425">"Налаштування"</string>
+ <string name="close" msgid="5214897374055647996">"Закрити"</string>
</resources>
diff --git a/packages/PackageInstaller/res/values-ur/strings.xml b/packages/PackageInstaller/res/values-ur/strings.xml
index 08a8315..f496e10 100644
--- a/packages/PackageInstaller/res/values-ur/strings.xml
+++ b/packages/PackageInstaller/res/values-ur/strings.xml
@@ -66,6 +66,7 @@
<string name="uninstall_keep_data" msgid="7002379587465487550">"ایپ ڈیٹا کا <xliff:g id="SIZE">%1$s</xliff:g> رکھیں۔"</string>
<string name="uninstall_application_text_current_user_clone_profile" msgid="835170400160011636">"کیا آپ یہ ایپ حذف کرنا چاہتے ہیں؟"</string>
<string name="uninstall_application_text_with_clone_instance" msgid="6944473334273349036">"کیا آپ یہ ایپ اَن انسٹال کرنا چاہتے ہیں؟ <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g> کلون کو بھی حذف کر دیا جائے گا۔"</string>
+ <string name="uninstall_application_text_current_user_private_profile" msgid="867004464945674674">"کیا آپ اس ایپ کو اپنی نجی جگہ سے اَن انسٹال کرنا چاہتے ہیں؟"</string>
<string name="uninstalling_notification_channel" msgid="840153394325714653">"چل رہے اَن انسٹالز"</string>
<string name="uninstall_failure_notification_channel" msgid="1136405866767576588">"ناکام اَن انسٹالز"</string>
<string name="uninstalling" msgid="8709566347688966845">"اَن انسٹال ہو رہا ہے…"</string>
@@ -106,4 +107,21 @@
<string name="unarchive_application_title" msgid="7958278328280721421">"<xliff:g id="APPNAME">%1$s</xliff:g> کو <xliff:g id="INSTALLERNAME">%1$s</xliff:g> سے بحال کریں"</string>
<string name="unarchive_body_text" msgid="8244155079861708964">"یہ ایپ پس منظر میں ڈاؤن لوڈ ہونا شروع ہو جائے گی"</string>
<string name="restore" msgid="8460854736328970444">"بحال کریں"</string>
+ <string name="unarchive_error_offline_title" msgid="4021785324565678605">"آپ آف لائن ہیں"</string>
+ <string name="unarchive_error_offline_body" msgid="255717000519772755">"جب آپ انٹرنیٹ سے منسلک ہوں گے تو یہ ایپ خودکار طور پر بحال ہو جائے گی"</string>
+ <string name="unarchive_error_generic_title" msgid="7123457671482449992">"کچھ غلط ہو گیا"</string>
+ <string name="unarchive_error_generic_body" msgid="4486803312463813079">"اس ایپ کو بحال کرنے کی کوشش میں ایک مسئلہ تھا"</string>
+ <string name="unarchive_error_storage_title" msgid="5080723357273852630">"کافی اسٹوریج نہیں ہے"</string>
+ <string name="unarchive_error_storage_body" msgid="6879544407568780524">"اس ایپ کو بحال کرنے کے لیے، آپ اس آلہ پر اسپیس خالی کر سکتے ہیں۔ درکار اسٹوریج: <xliff:g id="BYTES">%1$s</xliff:g>"</string>
+ <string name="unarchive_action_required_title" msgid="4971245740162604619">"کارروائی درکار ہے"</string>
+ <string name="unarchive_action_required_body" msgid="1679431572983989231">"اس ایپ کو بحال کرنے کے لیے اگلے مراحل کی پیروی کریں"</string>
+ <string name="unarchive_error_installer_disabled_title" msgid="4815715617014985605">"<xliff:g id="INSTALLERNAME">%1$s</xliff:g> غیر فعال ہے"</string>
+ <!-- no translation found for unarchive_error_installer_disabled_body (4820821285907011729) -->
+ <skip />
+ <string name="unarchive_error_installer_uninstalled_title" msgid="3748354109176326489">"<xliff:g id="INSTALLERNAME">%1$s</xliff:g> اَن انسٹال ہو گیا ہے"</string>
+ <string name="unarchive_error_installer_uninstalled_body" msgid="944733542444183204">"اس ایپ کو بحال کرنے کے لیے، آپ کو <xliff:g id="INSTALLERNAME">%1$s</xliff:g> انسٹال کرنا ہوگا"</string>
+ <string name="unarchive_action_required_continue" msgid="5711202111224184257">"جاری رکھیں"</string>
+ <string name="unarchive_clear_storage_button" msgid="1549537154535608744">"اسٹوریج صاف کریں"</string>
+ <string name="unarchive_settings_button" msgid="3504171760009177425">"ترتیبات"</string>
+ <string name="close" msgid="5214897374055647996">"بند کریں"</string>
</resources>
diff --git a/packages/PackageInstaller/res/values-uz/strings.xml b/packages/PackageInstaller/res/values-uz/strings.xml
index 894e867..a1f116d 100644
--- a/packages/PackageInstaller/res/values-uz/strings.xml
+++ b/packages/PackageInstaller/res/values-uz/strings.xml
@@ -66,6 +66,7 @@
<string name="uninstall_keep_data" msgid="7002379587465487550">"<xliff:g id="SIZE">%1$s</xliff:g> hajmdagi ilova axborotlari saqlab qolinsin"</string>
<string name="uninstall_application_text_current_user_clone_profile" msgid="835170400160011636">"Bu ilova oʻchirilsinmi?"</string>
<string name="uninstall_application_text_with_clone_instance" msgid="6944473334273349036">"Bu ilovani oʻchirib tashlamoqchimisiz? <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g> nusxasi ham oʻchib ketadi."</string>
+ <string name="uninstall_application_text_current_user_private_profile" msgid="867004464945674674">"Bu ilovani maxfiy joydan olib tashlamoqchimisiz?"</string>
<string name="uninstalling_notification_channel" msgid="840153394325714653">"Davom etayotganlar"</string>
<string name="uninstall_failure_notification_channel" msgid="1136405866767576588">"Amalga oshmaganlar"</string>
<string name="uninstalling" msgid="8709566347688966845">"O‘chirilmoqda…"</string>
@@ -106,4 +107,21 @@
<string name="unarchive_application_title" msgid="7958278328280721421">"<xliff:g id="APPNAME">%1$s</xliff:g> ilovasi <xliff:g id="INSTALLERNAME">%1$s</xliff:g> orqali tiklansinmi?"</string>
<string name="unarchive_body_text" msgid="8244155079861708964">"Bu ilova orqa fonda yuklab olinishi boshlanadi"</string>
<string name="restore" msgid="8460854736328970444">"Tiklash"</string>
+ <string name="unarchive_error_offline_title" msgid="4021785324565678605">"Siz internetga ulanmagansiz"</string>
+ <string name="unarchive_error_offline_body" msgid="255717000519772755">"Internetga ulanganingizda bu ilova avtomatik ravishda tiklanadi"</string>
+ <string name="unarchive_error_generic_title" msgid="7123457671482449992">"Nimadir xato ketdi"</string>
+ <string name="unarchive_error_generic_body" msgid="4486803312463813079">"Bu ilovani tiklashda muammo chiqdi"</string>
+ <string name="unarchive_error_storage_title" msgid="5080723357273852630">"Xotirada yetarli boʻsh joy yoʻq"</string>
+ <string name="unarchive_error_storage_body" msgid="6879544407568780524">"Bu ilovani tiklash uchun ushbu qurilmada joy ochishingiz mumkin. Kerakli joy: <xliff:g id="BYTES">%1$s</xliff:g>"</string>
+ <string name="unarchive_action_required_title" msgid="4971245740162604619">"Amal bajarish zarur"</string>
+ <string name="unarchive_action_required_body" msgid="1679431572983989231">"Bu ilovani tiklash uchun keyingi qadamlarga rioya qiling"</string>
+ <string name="unarchive_error_installer_disabled_title" msgid="4815715617014985605">"<xliff:g id="INSTALLERNAME">%1$s</xliff:g> faolsizlantirilgan"</string>
+ <!-- no translation found for unarchive_error_installer_disabled_body (4820821285907011729) -->
+ <skip />
+ <string name="unarchive_error_installer_uninstalled_title" msgid="3748354109176326489">"<xliff:g id="INSTALLERNAME">%1$s</xliff:g> oʻchirib tashlandi"</string>
+ <string name="unarchive_error_installer_uninstalled_body" msgid="944733542444183204">"Bu ilovani tiklash uchun <xliff:g id="INSTALLERNAME">%1$s</xliff:g> oʻrnatilishi kerak"</string>
+ <string name="unarchive_action_required_continue" msgid="5711202111224184257">"Davom etish"</string>
+ <string name="unarchive_clear_storage_button" msgid="1549537154535608744">"Xotirani tozalash"</string>
+ <string name="unarchive_settings_button" msgid="3504171760009177425">"Sozlamalar"</string>
+ <string name="close" msgid="5214897374055647996">"Yopish"</string>
</resources>
diff --git a/packages/PackageInstaller/res/values-vi/strings.xml b/packages/PackageInstaller/res/values-vi/strings.xml
index 14959da..39d6725 100644
--- a/packages/PackageInstaller/res/values-vi/strings.xml
+++ b/packages/PackageInstaller/res/values-vi/strings.xml
@@ -66,6 +66,7 @@
<string name="uninstall_keep_data" msgid="7002379587465487550">"Giữ lại <xliff:g id="SIZE">%1$s</xliff:g> dữ liệu ứng dụng."</string>
<string name="uninstall_application_text_current_user_clone_profile" msgid="835170400160011636">"Bạn có muốn xoá ứng dụng này không?"</string>
<string name="uninstall_application_text_with_clone_instance" msgid="6944473334273349036">"Bạn có muốn gỡ cài đặt ứng dụng này không? Bản sao của <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g> cũng sẽ bị xoá."</string>
+ <string name="uninstall_application_text_current_user_private_profile" msgid="867004464945674674">"Bạn có muốn gỡ cài đặt ứng dụng này khỏi không gian riêng tư của mình không?"</string>
<string name="uninstalling_notification_channel" msgid="840153394325714653">"Các quá trình gỡ cài đặt đang chạy"</string>
<string name="uninstall_failure_notification_channel" msgid="1136405866767576588">"Gỡ cài đặt không thành công"</string>
<string name="uninstalling" msgid="8709566347688966845">"Đang gỡ cài đặt..."</string>
@@ -106,4 +107,21 @@
<string name="unarchive_application_title" msgid="7958278328280721421">"Khôi phục <xliff:g id="APPNAME">%1$s</xliff:g> từ <xliff:g id="INSTALLERNAME">%1$s</xliff:g>?"</string>
<string name="unarchive_body_text" msgid="8244155079861708964">"Ứng dụng này sẽ bắt đầu tải xuống ở chế độ nền"</string>
<string name="restore" msgid="8460854736328970444">"Khôi phục"</string>
+ <string name="unarchive_error_offline_title" msgid="4021785324565678605">"Không có kết nối mạng"</string>
+ <string name="unarchive_error_offline_body" msgid="255717000519772755">"Ứng dụng này sẽ tự động khôi phục khi bạn kết nối với Internet"</string>
+ <string name="unarchive_error_generic_title" msgid="7123457671482449992">"Đã xảy ra lỗi"</string>
+ <string name="unarchive_error_generic_body" msgid="4486803312463813079">"Đã xảy ra vấn đề khi tìm cách khôi phục ứng dụng này"</string>
+ <string name="unarchive_error_storage_title" msgid="5080723357273852630">"Không đủ dung lượng lưu trữ"</string>
+ <string name="unarchive_error_storage_body" msgid="6879544407568780524">"Để khôi phục ứng dụng này, bạn có thể giải phóng dung lượng trên thiết bị này. Dung lượng lưu trữ cần thiết: <xliff:g id="BYTES">%1$s</xliff:g>"</string>
+ <string name="unarchive_action_required_title" msgid="4971245740162604619">"Việc cần làm"</string>
+ <string name="unarchive_action_required_body" msgid="1679431572983989231">"Hãy làm theo các bước tiếp theo để khôi phục ứng dụng này"</string>
+ <string name="unarchive_error_installer_disabled_title" msgid="4815715617014985605">"<xliff:g id="INSTALLERNAME">%1$s</xliff:g> đã bị tắt"</string>
+ <!-- no translation found for unarchive_error_installer_disabled_body (4820821285907011729) -->
+ <skip />
+ <string name="unarchive_error_installer_uninstalled_title" msgid="3748354109176326489">"<xliff:g id="INSTALLERNAME">%1$s</xliff:g> đã bị gỡ cài đặt"</string>
+ <string name="unarchive_error_installer_uninstalled_body" msgid="944733542444183204">"Để khôi phục ứng dụng này, bạn sẽ phải cài đặt <xliff:g id="INSTALLERNAME">%1$s</xliff:g>"</string>
+ <string name="unarchive_action_required_continue" msgid="5711202111224184257">"Tiếp tục"</string>
+ <string name="unarchive_clear_storage_button" msgid="1549537154535608744">"Xoá bộ nhớ"</string>
+ <string name="unarchive_settings_button" msgid="3504171760009177425">"Cài đặt"</string>
+ <string name="close" msgid="5214897374055647996">"Đóng"</string>
</resources>
diff --git a/packages/PackageInstaller/res/values-zh-rCN/strings.xml b/packages/PackageInstaller/res/values-zh-rCN/strings.xml
index ae12559..07cadbf 100644
--- a/packages/PackageInstaller/res/values-zh-rCN/strings.xml
+++ b/packages/PackageInstaller/res/values-zh-rCN/strings.xml
@@ -66,6 +66,7 @@
<string name="uninstall_keep_data" msgid="7002379587465487550">"保留 <xliff:g id="SIZE">%1$s</xliff:g> 的应用数据。"</string>
<string name="uninstall_application_text_current_user_clone_profile" msgid="835170400160011636">"要删除此应用吗?"</string>
<string name="uninstall_application_text_with_clone_instance" msgid="6944473334273349036">"要卸载此应用吗?<xliff:g id="PACKAGE_LABEL">%1$s</xliff:g> 克隆应用也会被删除。"</string>
+ <string name="uninstall_application_text_current_user_private_profile" msgid="867004464945674674">"要从私密空间卸载此应用吗?"</string>
<string name="uninstalling_notification_channel" msgid="840153394325714653">"正在进行卸载操作"</string>
<string name="uninstall_failure_notification_channel" msgid="1136405866767576588">"卸载操作失败"</string>
<string name="uninstalling" msgid="8709566347688966845">"正在卸载…"</string>
@@ -106,4 +107,21 @@
<string name="unarchive_application_title" msgid="7958278328280721421">"要从 <xliff:g id="INSTALLERNAME">%1$s</xliff:g> 中恢复 <xliff:g id="APPNAME">%1$s</xliff:g> 吗?"</string>
<string name="unarchive_body_text" msgid="8244155079861708964">"系统将开始在后台下载此应用"</string>
<string name="restore" msgid="8460854736328970444">"恢复"</string>
+ <string name="unarchive_error_offline_title" msgid="4021785324565678605">"您没有联网"</string>
+ <string name="unarchive_error_offline_body" msgid="255717000519772755">"当您联网后,此应用将自动恢复"</string>
+ <string name="unarchive_error_generic_title" msgid="7123457671482449992">"出了点问题"</string>
+ <string name="unarchive_error_generic_body" msgid="4486803312463813079">"尝试恢复此应用时出现问题"</string>
+ <string name="unarchive_error_storage_title" msgid="5080723357273852630">"存储空间不足"</string>
+ <string name="unarchive_error_storage_body" msgid="6879544407568780524">"若要恢复此应用,您需要释放此设备上的空间。所需的存储空间为:<xliff:g id="BYTES">%1$s</xliff:g>"</string>
+ <string name="unarchive_action_required_title" msgid="4971245740162604619">"请采取行动"</string>
+ <string name="unarchive_action_required_body" msgid="1679431572983989231">"请按照后续步骤恢复此应用"</string>
+ <string name="unarchive_error_installer_disabled_title" msgid="4815715617014985605">"<xliff:g id="INSTALLERNAME">%1$s</xliff:g> 已停用"</string>
+ <!-- no translation found for unarchive_error_installer_disabled_body (4820821285907011729) -->
+ <skip />
+ <string name="unarchive_error_installer_uninstalled_title" msgid="3748354109176326489">"<xliff:g id="INSTALLERNAME">%1$s</xliff:g> 已卸载"</string>
+ <string name="unarchive_error_installer_uninstalled_body" msgid="944733542444183204">"若要恢复此应用,您需要安装 <xliff:g id="INSTALLERNAME">%1$s</xliff:g>"</string>
+ <string name="unarchive_action_required_continue" msgid="5711202111224184257">"继续"</string>
+ <string name="unarchive_clear_storage_button" msgid="1549537154535608744">"清空存储空间"</string>
+ <string name="unarchive_settings_button" msgid="3504171760009177425">"设置"</string>
+ <string name="close" msgid="5214897374055647996">"关闭"</string>
</resources>
diff --git a/packages/PackageInstaller/res/values-zh-rHK/strings.xml b/packages/PackageInstaller/res/values-zh-rHK/strings.xml
index 5a79817..3e13aff 100644
--- a/packages/PackageInstaller/res/values-zh-rHK/strings.xml
+++ b/packages/PackageInstaller/res/values-zh-rHK/strings.xml
@@ -66,6 +66,7 @@
<string name="uninstall_keep_data" msgid="7002379587465487550">"保留應用程式資料 (<xliff:g id="SIZE">%1$s</xliff:g>)。"</string>
<string name="uninstall_application_text_current_user_clone_profile" msgid="835170400160011636">"要刪除此應用程式嗎?"</string>
<string name="uninstall_application_text_with_clone_instance" msgid="6944473334273349036">"要解除安裝此應用程式嗎?「<xliff:g id="PACKAGE_LABEL">%1$s</xliff:g>」複製本亦將被刪除。"</string>
+ <string name="uninstall_application_text_current_user_private_profile" msgid="867004464945674674">"要從私人空間解除安裝此應用程式嗎?"</string>
<string name="uninstalling_notification_channel" msgid="840153394325714653">"正在執行的解除安裝操作"</string>
<string name="uninstall_failure_notification_channel" msgid="1136405866767576588">"失敗的解除安裝操作"</string>
<string name="uninstalling" msgid="8709566347688966845">"正在解除安裝…"</string>
@@ -106,4 +107,21 @@
<string name="unarchive_application_title" msgid="7958278328280721421">"要從「<xliff:g id="INSTALLERNAME">%1$s</xliff:g>」還原「<xliff:g id="APPNAME">%1$s</xliff:g>」嗎?"</string>
<string name="unarchive_body_text" msgid="8244155079861708964">"此應用程式將開始在背景下載"</string>
<string name="restore" msgid="8460854736328970444">"還原"</string>
+ <string name="unarchive_error_offline_title" msgid="4021785324565678605">"你已離線"</string>
+ <string name="unarchive_error_offline_body" msgid="255717000519772755">"連接互聯網後,系統就會自動還原此應用程式"</string>
+ <string name="unarchive_error_generic_title" msgid="7123457671482449992">"發生問題"</string>
+ <string name="unarchive_error_generic_body" msgid="4486803312463813079">"嘗試還原此應用程式時發生問題"</string>
+ <string name="unarchive_error_storage_title" msgid="5080723357273852630">"儲存空間不足"</string>
+ <string name="unarchive_error_storage_body" msgid="6879544407568780524">"如要還原此應用程式,請騰出此裝置的儲存空間。需要的儲存空間大小:<xliff:g id="BYTES">%1$s</xliff:g>"</string>
+ <string name="unarchive_action_required_title" msgid="4971245740162604619">"請即行動"</string>
+ <string name="unarchive_action_required_body" msgid="1679431572983989231">"按照後續步驟還原此應用程式"</string>
+ <string name="unarchive_error_installer_disabled_title" msgid="4815715617014985605">"已停用 <xliff:g id="INSTALLERNAME">%1$s</xliff:g>"</string>
+ <!-- no translation found for unarchive_error_installer_disabled_body (4820821285907011729) -->
+ <skip />
+ <string name="unarchive_error_installer_uninstalled_title" msgid="3748354109176326489">"已解除安裝 <xliff:g id="INSTALLERNAME">%1$s</xliff:g>"</string>
+ <string name="unarchive_error_installer_uninstalled_body" msgid="944733542444183204">"如要還原此應用程式,你必須安裝 <xliff:g id="INSTALLERNAME">%1$s</xliff:g>"</string>
+ <string name="unarchive_action_required_continue" msgid="5711202111224184257">"繼續"</string>
+ <string name="unarchive_clear_storage_button" msgid="1549537154535608744">"清除儲存空間"</string>
+ <string name="unarchive_settings_button" msgid="3504171760009177425">"設定"</string>
+ <string name="close" msgid="5214897374055647996">"關閉"</string>
</resources>
diff --git a/packages/PackageInstaller/res/values-zh-rTW/strings.xml b/packages/PackageInstaller/res/values-zh-rTW/strings.xml
index 873392b..f457462 100644
--- a/packages/PackageInstaller/res/values-zh-rTW/strings.xml
+++ b/packages/PackageInstaller/res/values-zh-rTW/strings.xml
@@ -66,6 +66,7 @@
<string name="uninstall_keep_data" msgid="7002379587465487550">"保留 <xliff:g id="SIZE">%1$s</xliff:g> 的應用程式資料。"</string>
<string name="uninstall_application_text_current_user_clone_profile" msgid="835170400160011636">"要刪除這個應用程式嗎?"</string>
<string name="uninstall_application_text_with_clone_instance" msgid="6944473334273349036">"要解除安裝這個應用程式嗎?系統也會一併刪除「<xliff:g id="PACKAGE_LABEL">%1$s</xliff:g>」副本。"</string>
+ <string name="uninstall_application_text_current_user_private_profile" msgid="867004464945674674">"想要從私人空間解除安裝這個應用程式嗎?"</string>
<string name="uninstalling_notification_channel" msgid="840153394325714653">"執行中的解除安裝作業"</string>
<string name="uninstall_failure_notification_channel" msgid="1136405866767576588">"失敗的解除安裝作業"</string>
<string name="uninstalling" msgid="8709566347688966845">"解除安裝中…"</string>
@@ -106,4 +107,21 @@
<string name="unarchive_application_title" msgid="7958278328280721421">"要從「<xliff:g id="INSTALLERNAME">%1$s</xliff:g>」還原「<xliff:g id="APPNAME">%1$s</xliff:g>」嗎?"</string>
<string name="unarchive_body_text" msgid="8244155079861708964">"系統將開始在背景下載這個應用程式"</string>
<string name="restore" msgid="8460854736328970444">"還原"</string>
+ <string name="unarchive_error_offline_title" msgid="4021785324565678605">"裝置目前離線"</string>
+ <string name="unarchive_error_offline_body" msgid="255717000519772755">"連上網際網路後,系統就會自動還原這個應用程式"</string>
+ <string name="unarchive_error_generic_title" msgid="7123457671482449992">"發生錯誤"</string>
+ <string name="unarchive_error_generic_body" msgid="4486803312463813079">"嘗試還原這個應用程式時發生問題"</string>
+ <string name="unarchive_error_storage_title" msgid="5080723357273852630">"儲存空間不足"</string>
+ <string name="unarchive_error_storage_body" msgid="6879544407568780524">"如要還原這個應用程式,請釋出這部裝置的儲存空間。需要的儲存空間大小:<xliff:g id="BYTES">%1$s</xliff:g>"</string>
+ <string name="unarchive_action_required_title" msgid="4971245740162604619">"敬請採取行動"</string>
+ <string name="unarchive_action_required_body" msgid="1679431572983989231">"請按照後續步驟還原這個應用程式"</string>
+ <string name="unarchive_error_installer_disabled_title" msgid="4815715617014985605">"「<xliff:g id="INSTALLERNAME">%1$s</xliff:g>」已停用"</string>
+ <!-- no translation found for unarchive_error_installer_disabled_body (4820821285907011729) -->
+ <skip />
+ <string name="unarchive_error_installer_uninstalled_title" msgid="3748354109176326489">"「<xliff:g id="INSTALLERNAME">%1$s</xliff:g>」已解除安裝"</string>
+ <string name="unarchive_error_installer_uninstalled_body" msgid="944733542444183204">"如要還原這個應用程式,請安裝「<xliff:g id="INSTALLERNAME">%1$s</xliff:g>」"</string>
+ <string name="unarchive_action_required_continue" msgid="5711202111224184257">"繼續"</string>
+ <string name="unarchive_clear_storage_button" msgid="1549537154535608744">"清除儲存空間"</string>
+ <string name="unarchive_settings_button" msgid="3504171760009177425">"設定"</string>
+ <string name="close" msgid="5214897374055647996">"關閉"</string>
</resources>
diff --git a/packages/PackageInstaller/res/values-zu/strings.xml b/packages/PackageInstaller/res/values-zu/strings.xml
index 8ff1e38..1de22a4 100644
--- a/packages/PackageInstaller/res/values-zu/strings.xml
+++ b/packages/PackageInstaller/res/values-zu/strings.xml
@@ -66,6 +66,7 @@
<string name="uninstall_keep_data" msgid="7002379587465487550">"Gcina u-<xliff:g id="SIZE">%1$s</xliff:g> wedatha yohlelo lokusebenza."</string>
<string name="uninstall_application_text_current_user_clone_profile" msgid="835170400160011636">"Ingabe ufuna ukusula le app?"</string>
<string name="uninstall_application_text_with_clone_instance" msgid="6944473334273349036">"Ufuna ukukhipha le app? I-clone ye-<xliff:g id="PACKAGE_LABEL">%1$s</xliff:g> nayo izosulwa."</string>
+ <string name="uninstall_application_text_current_user_private_profile" msgid="867004464945674674">"Ingabe ufuna ukukhipha le app endaweni yakho egodliwe?"</string>
<string name="uninstalling_notification_channel" msgid="840153394325714653">"Ukukhishwa okuqhubekayo"</string>
<string name="uninstall_failure_notification_channel" msgid="1136405866767576588">"Ukukhishwa okuhlulekile"</string>
<string name="uninstalling" msgid="8709566347688966845">"Iyakhipha..."</string>
@@ -106,4 +107,21 @@
<string name="unarchive_application_title" msgid="7958278328280721421">"Buyisela i-<xliff:g id="APPNAME">%1$s</xliff:g> ukusuka ku-<xliff:g id="INSTALLERNAME">%1$s</xliff:g>?"</string>
<string name="unarchive_body_text" msgid="8244155079861708964">"Le app izoqala ukudawuniloda ingemuva"</string>
<string name="restore" msgid="8460854736328970444">"Buyisela"</string>
+ <string name="unarchive_error_offline_title" msgid="4021785324565678605">"Awuxhunyiwe ku-inthanethi"</string>
+ <string name="unarchive_error_offline_body" msgid="255717000519772755">"Le app izobuyiswa ngokuzenzakalelayo uma usuxhume ku-inthanethi"</string>
+ <string name="unarchive_error_generic_title" msgid="7123457671482449992">"Kukhona okungahambanga kahle"</string>
+ <string name="unarchive_error_generic_body" msgid="4486803312463813079">"Kube nenkinga ekuzameni ukubuyisa le app"</string>
+ <string name="unarchive_error_storage_title" msgid="5080723357273852630">"Indawo yokubeka ayanele"</string>
+ <string name="unarchive_error_storage_body" msgid="6879544407568780524">"Ukuze ubuyise le app, ungavula isikhala kule divayisi. Isitoreji esidingekayo: <xliff:g id="BYTES">%1$s</xliff:g>"</string>
+ <string name="unarchive_action_required_title" msgid="4971245740162604619">"Kudingeka isenzo"</string>
+ <string name="unarchive_action_required_body" msgid="1679431572983989231">"Landela izinyathelo ezilandelayo ukuze ubuyise le app"</string>
+ <string name="unarchive_error_installer_disabled_title" msgid="4815715617014985605">"<xliff:g id="INSTALLERNAME">%1$s</xliff:g> ivimbelwe"</string>
+ <!-- no translation found for unarchive_error_installer_disabled_body (4820821285907011729) -->
+ <skip />
+ <string name="unarchive_error_installer_uninstalled_title" msgid="3748354109176326489">"Okuthi <xliff:g id="INSTALLERNAME">%1$s</xliff:g> kukhishiwe"</string>
+ <string name="unarchive_error_installer_uninstalled_body" msgid="944733542444183204">"Ukuze ubuyise le app, kuzodingeka ufake okuthi <xliff:g id="INSTALLERNAME">%1$s</xliff:g>"</string>
+ <string name="unarchive_action_required_continue" msgid="5711202111224184257">"Qhubeka"</string>
+ <string name="unarchive_clear_storage_button" msgid="1549537154535608744">"Sula isitoreji"</string>
+ <string name="unarchive_settings_button" msgid="3504171760009177425">"Amasethingi"</string>
+ <string name="close" msgid="5214897374055647996">"Vala"</string>
</resources>
diff --git a/packages/SettingsLib/Spa/TEST_MAPPING b/packages/SettingsLib/Spa/TEST_MAPPING
index b7ce518..be1e888 100644
--- a/packages/SettingsLib/Spa/TEST_MAPPING
+++ b/packages/SettingsLib/Spa/TEST_MAPPING
@@ -9,5 +9,10 @@
{
"name": "SettingsSpaUnitTests"
}
+ ],
+ "postsubmit": [
+ {
+ "name": "SpaScreenshotTests"
+ }
]
}
diff --git a/packages/SettingsLib/Spa/screenshot/assets/phone/light_landscape_actionButtons.png b/packages/SettingsLib/Spa/screenshot/assets/phone/light_landscape_actionButtons.png
index 74113d8..1a59722 100644
--- a/packages/SettingsLib/Spa/screenshot/assets/phone/light_landscape_actionButtons.png
+++ b/packages/SettingsLib/Spa/screenshot/assets/phone/light_landscape_actionButtons.png
Binary files differ
diff --git a/packages/SettingsLib/Spa/screenshot/assets/phone/light_landscape_barChart.png b/packages/SettingsLib/Spa/screenshot/assets/phone/light_landscape_barChart.png
index 0d22c6a..69017d0 100644
--- a/packages/SettingsLib/Spa/screenshot/assets/phone/light_landscape_barChart.png
+++ b/packages/SettingsLib/Spa/screenshot/assets/phone/light_landscape_barChart.png
Binary files differ
diff --git a/packages/SettingsLib/Spa/screenshot/assets/phone/light_landscape_footer.png b/packages/SettingsLib/Spa/screenshot/assets/phone/light_landscape_footer.png
index f77b8a7..dc2e594 100644
--- a/packages/SettingsLib/Spa/screenshot/assets/phone/light_landscape_footer.png
+++ b/packages/SettingsLib/Spa/screenshot/assets/phone/light_landscape_footer.png
Binary files differ
diff --git a/packages/SettingsLib/Spa/screenshot/assets/phone/light_landscape_imageIllustration.png b/packages/SettingsLib/Spa/screenshot/assets/phone/light_landscape_imageIllustration.png
index 9372791..7e1de6a 100644
--- a/packages/SettingsLib/Spa/screenshot/assets/phone/light_landscape_imageIllustration.png
+++ b/packages/SettingsLib/Spa/screenshot/assets/phone/light_landscape_imageIllustration.png
Binary files differ
diff --git a/packages/SettingsLib/Spa/screenshot/assets/phone/light_landscape_lineChart.png b/packages/SettingsLib/Spa/screenshot/assets/phone/light_landscape_lineChart.png
index dda9e9e..2218b5b 100644
--- a/packages/SettingsLib/Spa/screenshot/assets/phone/light_landscape_lineChart.png
+++ b/packages/SettingsLib/Spa/screenshot/assets/phone/light_landscape_lineChart.png
Binary files differ
diff --git a/packages/SettingsLib/Spa/screenshot/assets/phone/light_landscape_mainSwitchPreference.png b/packages/SettingsLib/Spa/screenshot/assets/phone/light_landscape_mainSwitchPreference.png
index bf19a2c..e18f42b 100644
--- a/packages/SettingsLib/Spa/screenshot/assets/phone/light_landscape_mainSwitchPreference.png
+++ b/packages/SettingsLib/Spa/screenshot/assets/phone/light_landscape_mainSwitchPreference.png
Binary files differ
diff --git a/packages/SettingsLib/Spa/screenshot/assets/phone/light_landscape_pieChart.png b/packages/SettingsLib/Spa/screenshot/assets/phone/light_landscape_pieChart.png
index b14e196e..21291a7 100644
--- a/packages/SettingsLib/Spa/screenshot/assets/phone/light_landscape_pieChart.png
+++ b/packages/SettingsLib/Spa/screenshot/assets/phone/light_landscape_pieChart.png
Binary files differ
diff --git a/packages/SettingsLib/Spa/screenshot/assets/phone/light_landscape_preference.png b/packages/SettingsLib/Spa/screenshot/assets/phone/light_landscape_preference.png
index c77f9b1..5c1a0e24 100644
--- a/packages/SettingsLib/Spa/screenshot/assets/phone/light_landscape_preference.png
+++ b/packages/SettingsLib/Spa/screenshot/assets/phone/light_landscape_preference.png
Binary files differ
diff --git a/packages/SettingsLib/Spa/screenshot/assets/phone/light_landscape_progressBar.png b/packages/SettingsLib/Spa/screenshot/assets/phone/light_landscape_progressBar.png
index f513830..4003506 100644
--- a/packages/SettingsLib/Spa/screenshot/assets/phone/light_landscape_progressBar.png
+++ b/packages/SettingsLib/Spa/screenshot/assets/phone/light_landscape_progressBar.png
Binary files differ
diff --git a/packages/SettingsLib/Spa/screenshot/assets/phone/light_landscape_slider.png b/packages/SettingsLib/Spa/screenshot/assets/phone/light_landscape_slider.png
index dda6f0a..1c669a6 100644
--- a/packages/SettingsLib/Spa/screenshot/assets/phone/light_landscape_slider.png
+++ b/packages/SettingsLib/Spa/screenshot/assets/phone/light_landscape_slider.png
Binary files differ
diff --git a/packages/SettingsLib/Spa/screenshot/assets/phone/light_landscape_spinner.png b/packages/SettingsLib/Spa/screenshot/assets/phone/light_landscape_spinner.png
index 7468169..101eb0c 100644
--- a/packages/SettingsLib/Spa/screenshot/assets/phone/light_landscape_spinner.png
+++ b/packages/SettingsLib/Spa/screenshot/assets/phone/light_landscape_spinner.png
Binary files differ
diff --git a/packages/SettingsLib/Spa/screenshot/assets/phone/light_landscape_switchPreference.png b/packages/SettingsLib/Spa/screenshot/assets/phone/light_landscape_switchPreference.png
index 669f443..9cb16ef 100644
--- a/packages/SettingsLib/Spa/screenshot/assets/phone/light_landscape_switchPreference.png
+++ b/packages/SettingsLib/Spa/screenshot/assets/phone/light_landscape_switchPreference.png
Binary files differ
diff --git a/packages/SettingsLib/Spa/screenshot/assets/phone/light_landscape_twoTargetSwitchPreference.png b/packages/SettingsLib/Spa/screenshot/assets/phone/light_landscape_twoTargetSwitchPreference.png
index 8e37cc0..20b11e3 100644
--- a/packages/SettingsLib/Spa/screenshot/assets/phone/light_landscape_twoTargetSwitchPreference.png
+++ b/packages/SettingsLib/Spa/screenshot/assets/phone/light_landscape_twoTargetSwitchPreference.png
Binary files differ
diff --git a/packages/SettingsLib/Spa/screenshot/assets/phone/light_portrait_actionButtons.png b/packages/SettingsLib/Spa/screenshot/assets/phone/light_portrait_actionButtons.png
index b0543e0..c2ad8ad 100644
--- a/packages/SettingsLib/Spa/screenshot/assets/phone/light_portrait_actionButtons.png
+++ b/packages/SettingsLib/Spa/screenshot/assets/phone/light_portrait_actionButtons.png
Binary files differ
diff --git a/packages/SettingsLib/Spa/screenshot/assets/phone/light_portrait_barChart.png b/packages/SettingsLib/Spa/screenshot/assets/phone/light_portrait_barChart.png
index 3755928..3408cca 100644
--- a/packages/SettingsLib/Spa/screenshot/assets/phone/light_portrait_barChart.png
+++ b/packages/SettingsLib/Spa/screenshot/assets/phone/light_portrait_barChart.png
Binary files differ
diff --git a/packages/SettingsLib/Spa/screenshot/assets/phone/light_portrait_footer.png b/packages/SettingsLib/Spa/screenshot/assets/phone/light_portrait_footer.png
index f77b8a7..dc2e594 100644
--- a/packages/SettingsLib/Spa/screenshot/assets/phone/light_portrait_footer.png
+++ b/packages/SettingsLib/Spa/screenshot/assets/phone/light_portrait_footer.png
Binary files differ
diff --git a/packages/SettingsLib/Spa/screenshot/assets/phone/light_portrait_imageIllustration.png b/packages/SettingsLib/Spa/screenshot/assets/phone/light_portrait_imageIllustration.png
index 7800149..c3ca8cd 100644
--- a/packages/SettingsLib/Spa/screenshot/assets/phone/light_portrait_imageIllustration.png
+++ b/packages/SettingsLib/Spa/screenshot/assets/phone/light_portrait_imageIllustration.png
Binary files differ
diff --git a/packages/SettingsLib/Spa/screenshot/assets/phone/light_portrait_lineChart.png b/packages/SettingsLib/Spa/screenshot/assets/phone/light_portrait_lineChart.png
index be40959..53b92dd 100644
--- a/packages/SettingsLib/Spa/screenshot/assets/phone/light_portrait_lineChart.png
+++ b/packages/SettingsLib/Spa/screenshot/assets/phone/light_portrait_lineChart.png
Binary files differ
diff --git a/packages/SettingsLib/Spa/screenshot/assets/phone/light_portrait_mainSwitchPreference.png b/packages/SettingsLib/Spa/screenshot/assets/phone/light_portrait_mainSwitchPreference.png
index 2d5894e..caa26a3 100644
--- a/packages/SettingsLib/Spa/screenshot/assets/phone/light_portrait_mainSwitchPreference.png
+++ b/packages/SettingsLib/Spa/screenshot/assets/phone/light_portrait_mainSwitchPreference.png
Binary files differ
diff --git a/packages/SettingsLib/Spa/screenshot/assets/phone/light_portrait_pieChart.png b/packages/SettingsLib/Spa/screenshot/assets/phone/light_portrait_pieChart.png
index 2a54b9e..02a943d 100644
--- a/packages/SettingsLib/Spa/screenshot/assets/phone/light_portrait_pieChart.png
+++ b/packages/SettingsLib/Spa/screenshot/assets/phone/light_portrait_pieChart.png
Binary files differ
diff --git a/packages/SettingsLib/Spa/screenshot/assets/phone/light_portrait_preference.png b/packages/SettingsLib/Spa/screenshot/assets/phone/light_portrait_preference.png
index b0fc305..c1abbc2 100644
--- a/packages/SettingsLib/Spa/screenshot/assets/phone/light_portrait_preference.png
+++ b/packages/SettingsLib/Spa/screenshot/assets/phone/light_portrait_preference.png
Binary files differ
diff --git a/packages/SettingsLib/Spa/screenshot/assets/phone/light_portrait_progressBar.png b/packages/SettingsLib/Spa/screenshot/assets/phone/light_portrait_progressBar.png
index 73f2407..cdb62f9 100644
--- a/packages/SettingsLib/Spa/screenshot/assets/phone/light_portrait_progressBar.png
+++ b/packages/SettingsLib/Spa/screenshot/assets/phone/light_portrait_progressBar.png
Binary files differ
diff --git a/packages/SettingsLib/Spa/screenshot/assets/phone/light_portrait_slider.png b/packages/SettingsLib/Spa/screenshot/assets/phone/light_portrait_slider.png
index 213c0b2..b3ae6b3 100644
--- a/packages/SettingsLib/Spa/screenshot/assets/phone/light_portrait_slider.png
+++ b/packages/SettingsLib/Spa/screenshot/assets/phone/light_portrait_slider.png
Binary files differ
diff --git a/packages/SettingsLib/Spa/screenshot/assets/phone/light_portrait_spinner.png b/packages/SettingsLib/Spa/screenshot/assets/phone/light_portrait_spinner.png
index 7468169..101eb0c 100644
--- a/packages/SettingsLib/Spa/screenshot/assets/phone/light_portrait_spinner.png
+++ b/packages/SettingsLib/Spa/screenshot/assets/phone/light_portrait_spinner.png
Binary files differ
diff --git a/packages/SettingsLib/Spa/screenshot/assets/phone/light_portrait_switchPreference.png b/packages/SettingsLib/Spa/screenshot/assets/phone/light_portrait_switchPreference.png
index ce7ab78..4227bb7 100644
--- a/packages/SettingsLib/Spa/screenshot/assets/phone/light_portrait_switchPreference.png
+++ b/packages/SettingsLib/Spa/screenshot/assets/phone/light_portrait_switchPreference.png
Binary files differ
diff --git a/packages/SettingsLib/Spa/screenshot/assets/phone/light_portrait_twoTargetSwitchPreference.png b/packages/SettingsLib/Spa/screenshot/assets/phone/light_portrait_twoTargetSwitchPreference.png
index 9d92f7a..52c4341 100644
--- a/packages/SettingsLib/Spa/screenshot/assets/phone/light_portrait_twoTargetSwitchPreference.png
+++ b/packages/SettingsLib/Spa/screenshot/assets/phone/light_portrait_twoTargetSwitchPreference.png
Binary files differ
diff --git a/packages/SettingsLib/Spa/screenshot/assets/tablet/dark_portrait_actionButtons.png b/packages/SettingsLib/Spa/screenshot/assets/tablet/dark_portrait_actionButtons.png
index 5255d14..eebac76 100644
--- a/packages/SettingsLib/Spa/screenshot/assets/tablet/dark_portrait_actionButtons.png
+++ b/packages/SettingsLib/Spa/screenshot/assets/tablet/dark_portrait_actionButtons.png
Binary files differ
diff --git a/packages/SettingsLib/Spa/screenshot/assets/tablet/dark_portrait_barChart.png b/packages/SettingsLib/Spa/screenshot/assets/tablet/dark_portrait_barChart.png
index 8f3f664..477d16c 100644
--- a/packages/SettingsLib/Spa/screenshot/assets/tablet/dark_portrait_barChart.png
+++ b/packages/SettingsLib/Spa/screenshot/assets/tablet/dark_portrait_barChart.png
Binary files differ
diff --git a/packages/SettingsLib/Spa/screenshot/assets/tablet/dark_portrait_footer.png b/packages/SettingsLib/Spa/screenshot/assets/tablet/dark_portrait_footer.png
index cc1de55..0dc83f9 100644
--- a/packages/SettingsLib/Spa/screenshot/assets/tablet/dark_portrait_footer.png
+++ b/packages/SettingsLib/Spa/screenshot/assets/tablet/dark_portrait_footer.png
Binary files differ
diff --git a/packages/SettingsLib/Spa/screenshot/assets/tablet/dark_portrait_imageIllustration.png b/packages/SettingsLib/Spa/screenshot/assets/tablet/dark_portrait_imageIllustration.png
index e29f26a..f32d7421 100644
--- a/packages/SettingsLib/Spa/screenshot/assets/tablet/dark_portrait_imageIllustration.png
+++ b/packages/SettingsLib/Spa/screenshot/assets/tablet/dark_portrait_imageIllustration.png
Binary files differ
diff --git a/packages/SettingsLib/Spa/screenshot/assets/tablet/dark_portrait_lineChart.png b/packages/SettingsLib/Spa/screenshot/assets/tablet/dark_portrait_lineChart.png
index 8b9bc5c..1de3b7f 100644
--- a/packages/SettingsLib/Spa/screenshot/assets/tablet/dark_portrait_lineChart.png
+++ b/packages/SettingsLib/Spa/screenshot/assets/tablet/dark_portrait_lineChart.png
Binary files differ
diff --git a/packages/SettingsLib/Spa/screenshot/assets/tablet/dark_portrait_mainSwitchPreference.png b/packages/SettingsLib/Spa/screenshot/assets/tablet/dark_portrait_mainSwitchPreference.png
index b1676b3..5e5ed6a 100644
--- a/packages/SettingsLib/Spa/screenshot/assets/tablet/dark_portrait_mainSwitchPreference.png
+++ b/packages/SettingsLib/Spa/screenshot/assets/tablet/dark_portrait_mainSwitchPreference.png
Binary files differ
diff --git a/packages/SettingsLib/Spa/screenshot/assets/tablet/dark_portrait_pieChart.png b/packages/SettingsLib/Spa/screenshot/assets/tablet/dark_portrait_pieChart.png
index 2a7b341..c133a6e 100644
--- a/packages/SettingsLib/Spa/screenshot/assets/tablet/dark_portrait_pieChart.png
+++ b/packages/SettingsLib/Spa/screenshot/assets/tablet/dark_portrait_pieChart.png
Binary files differ
diff --git a/packages/SettingsLib/Spa/screenshot/assets/tablet/dark_portrait_preference.png b/packages/SettingsLib/Spa/screenshot/assets/tablet/dark_portrait_preference.png
index 4845ea8..55acf95 100644
--- a/packages/SettingsLib/Spa/screenshot/assets/tablet/dark_portrait_preference.png
+++ b/packages/SettingsLib/Spa/screenshot/assets/tablet/dark_portrait_preference.png
Binary files differ
diff --git a/packages/SettingsLib/Spa/screenshot/assets/tablet/dark_portrait_progressBar.png b/packages/SettingsLib/Spa/screenshot/assets/tablet/dark_portrait_progressBar.png
index 6e860d3..f72dbc2 100644
--- a/packages/SettingsLib/Spa/screenshot/assets/tablet/dark_portrait_progressBar.png
+++ b/packages/SettingsLib/Spa/screenshot/assets/tablet/dark_portrait_progressBar.png
Binary files differ
diff --git a/packages/SettingsLib/Spa/screenshot/assets/tablet/dark_portrait_slider.png b/packages/SettingsLib/Spa/screenshot/assets/tablet/dark_portrait_slider.png
index d1abaa6..5a1c85d 100644
--- a/packages/SettingsLib/Spa/screenshot/assets/tablet/dark_portrait_slider.png
+++ b/packages/SettingsLib/Spa/screenshot/assets/tablet/dark_portrait_slider.png
Binary files differ
diff --git a/packages/SettingsLib/Spa/screenshot/assets/tablet/dark_portrait_spinner.png b/packages/SettingsLib/Spa/screenshot/assets/tablet/dark_portrait_spinner.png
index c211e0e..bc8144e 100644
--- a/packages/SettingsLib/Spa/screenshot/assets/tablet/dark_portrait_spinner.png
+++ b/packages/SettingsLib/Spa/screenshot/assets/tablet/dark_portrait_spinner.png
Binary files differ
diff --git a/packages/SettingsLib/Spa/screenshot/assets/tablet/dark_portrait_switchPreference.png b/packages/SettingsLib/Spa/screenshot/assets/tablet/dark_portrait_switchPreference.png
index 9c57e33..2b0351a 100644
--- a/packages/SettingsLib/Spa/screenshot/assets/tablet/dark_portrait_switchPreference.png
+++ b/packages/SettingsLib/Spa/screenshot/assets/tablet/dark_portrait_switchPreference.png
Binary files differ
diff --git a/packages/SettingsLib/Spa/screenshot/assets/tablet/dark_portrait_twoTargetSwitchPreference.png b/packages/SettingsLib/Spa/screenshot/assets/tablet/dark_portrait_twoTargetSwitchPreference.png
index d416a0b..bfcdb55 100644
--- a/packages/SettingsLib/Spa/screenshot/assets/tablet/dark_portrait_twoTargetSwitchPreference.png
+++ b/packages/SettingsLib/Spa/screenshot/assets/tablet/dark_portrait_twoTargetSwitchPreference.png
Binary files differ
diff --git a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/framework/common/BroadcastReceiverAsUserFlow.kt b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/framework/common/BroadcastReceiverAsUserFlow.kt
index 2c60db4..8c52d57 100644
--- a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/framework/common/BroadcastReceiverAsUserFlow.kt
+++ b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/framework/common/BroadcastReceiverAsUserFlow.kt
@@ -21,13 +21,17 @@
import android.content.Intent
import android.content.IntentFilter
import android.os.UserHandle
+import android.util.Log
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.callbackFlow
+import kotlinx.coroutines.flow.catch
import kotlinx.coroutines.flow.conflate
import kotlinx.coroutines.flow.flowOn
+private const val TAG = "BroadcastReceiverAsUser"
+
/**
* A [BroadcastReceiver] flow for the given [intentFilter].
*/
@@ -50,4 +54,6 @@
)
awaitClose { unregisterReceiver(broadcastReceiver) }
+}.catch { e ->
+ Log.e(TAG, "Error while broadcastReceiverAsUserFlow", e)
}.conflate().flowOn(Dispatchers.Default)
diff --git a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/framework/common/BroadcastReceiverAsUserFlowTest.kt b/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/framework/common/BroadcastReceiverAsUserFlowTest.kt
index dfb8e22..9cb33d2 100644
--- a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/framework/common/BroadcastReceiverAsUserFlowTest.kt
+++ b/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/framework/common/BroadcastReceiverAsUserFlowTest.kt
@@ -32,9 +32,11 @@
import org.junit.runner.RunWith
import org.mockito.kotlin.any
import org.mockito.kotlin.doAnswer
+import org.mockito.kotlin.doThrow
import org.mockito.kotlin.eq
import org.mockito.kotlin.isNull
import org.mockito.kotlin.mock
+import org.mockito.kotlin.stub
@RunWith(AndroidJUnit4::class)
class BroadcastReceiverAsUserFlowTest {
@@ -83,6 +85,18 @@
assertThat(onReceiveIsCalled).isTrue()
}
+ @Test
+ fun broadcastReceiverAsUserFlow_unregisterReceiverThrowException_noCrash() = runBlocking {
+ context.stub {
+ on { unregisterReceiver(any()) } doThrow IllegalArgumentException()
+ }
+ val flow = context.broadcastReceiverAsUserFlow(INTENT_FILTER, USER_HANDLE)
+
+ flow.firstWithTimeoutOrNull()
+
+ assertThat(registeredBroadcastReceiver).isNotNull()
+ }
+
private companion object {
val USER_HANDLE: UserHandle = UserHandle.of(0)
diff --git a/packages/SettingsLib/res/values-af/strings.xml b/packages/SettingsLib/res/values-af/strings.xml
index 3a25838..9ae4d0c 100644
--- a/packages/SettingsLib/res/values-af/strings.xml
+++ b/packages/SettingsLib/res/values-af/strings.xml
@@ -567,12 +567,9 @@
<string name="tv_media_transfer_earc_fallback_title" msgid="3098685494578519940">"HDMI eARC"</string>
<string name="tv_media_transfer_arc_subtitle" msgid="1040017851325069082">"Gekoppel deur ARC"</string>
<string name="tv_media_transfer_earc_subtitle" msgid="645191413103303077">"Gekoppel deur eARC"</string>
- <!-- no translation found for tv_media_transfer_default (5403053145185843843) -->
- <skip />
- <!-- no translation found for tv_media_transfer_hdmi (692569220956829921) -->
- <skip />
- <!-- no translation found for tv_media_transfer_internal_speakers (8181494402866565865) -->
- <skip />
+ <string name="tv_media_transfer_default" msgid="5403053145185843843">"TV-verstek"</string>
+ <string name="tv_media_transfer_hdmi" msgid="692569220956829921">"HDMI-uitset"</string>
+ <string name="tv_media_transfer_internal_speakers" msgid="8181494402866565865">"Interne luidsprekers"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Kan nie koppel nie. Skakel toestel af en weer aan"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Bedrade oudiotoestel"</string>
<string name="help_label" msgid="3528360748637781274">"Hulp en terugvoer"</string>
diff --git a/packages/SettingsLib/res/values-ar/strings.xml b/packages/SettingsLib/res/values-ar/strings.xml
index 6dd70fa..6c31c76 100644
--- a/packages/SettingsLib/res/values-ar/strings.xml
+++ b/packages/SettingsLib/res/values-ar/strings.xml
@@ -567,12 +567,9 @@
<string name="tv_media_transfer_earc_fallback_title" msgid="3098685494578519940">"HDMI eARC"</string>
<string name="tv_media_transfer_arc_subtitle" msgid="1040017851325069082">"متّصل من خلال ARC"</string>
<string name="tv_media_transfer_earc_subtitle" msgid="645191413103303077">"متّصل من خلال eARC"</string>
- <!-- no translation found for tv_media_transfer_default (5403053145185843843) -->
- <skip />
- <!-- no translation found for tv_media_transfer_hdmi (692569220956829921) -->
- <skip />
- <!-- no translation found for tv_media_transfer_internal_speakers (8181494402866565865) -->
- <skip />
+ <string name="tv_media_transfer_default" msgid="5403053145185843843">"الجهاز التلقائي لإخراج صوت التلفزيون"</string>
+ <string name="tv_media_transfer_hdmi" msgid="692569220956829921">"إخراج الصوت من خلال HDMI"</string>
+ <string name="tv_media_transfer_internal_speakers" msgid="8181494402866565865">"مكبّرات الصوت الداخلية"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"حدثت مشكلة أثناء الاتصال. يُرجى إيقاف الجهاز ثم إعادة تشغيله."</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"جهاز سماعي سلكي"</string>
<string name="help_label" msgid="3528360748637781274">"المساعدة والملاحظات"</string>
diff --git a/packages/SettingsLib/res/values-as/strings.xml b/packages/SettingsLib/res/values-as/strings.xml
index c8eeee3..8b06f5d 100644
--- a/packages/SettingsLib/res/values-as/strings.xml
+++ b/packages/SettingsLib/res/values-as/strings.xml
@@ -567,12 +567,9 @@
<string name="tv_media_transfer_earc_fallback_title" msgid="3098685494578519940">"HDMI eARC"</string>
<string name="tv_media_transfer_arc_subtitle" msgid="1040017851325069082">"ARCৰ জৰিয়তে সংযুক্ত"</string>
<string name="tv_media_transfer_earc_subtitle" msgid="645191413103303077">"eARCৰ জৰিয়তে সংযুক্ত"</string>
- <!-- no translation found for tv_media_transfer_default (5403053145185843843) -->
- <skip />
- <!-- no translation found for tv_media_transfer_hdmi (692569220956829921) -->
- <skip />
- <!-- no translation found for tv_media_transfer_internal_speakers (8181494402866565865) -->
- <skip />
+ <string name="tv_media_transfer_default" msgid="5403053145185843843">"টিভি ডিফ’ল্ট"</string>
+ <string name="tv_media_transfer_hdmi" msgid="692569220956829921">"HDMI আউটপুট"</string>
+ <string name="tv_media_transfer_internal_speakers" msgid="8181494402866565865">"অভ্যন্তৰীণ স্পীকাৰ"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"সংযোগ হোৱাত সমস্যা হৈছে। ডিভাইচটো অফ কৰি পুনৰ অন কৰক"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"তাঁৰযুক্ত অডিঅ’ ডিভাইচ"</string>
<string name="help_label" msgid="3528360748637781274">"সহায় আৰু মতামত"</string>
diff --git a/packages/SettingsLib/res/values-az/strings.xml b/packages/SettingsLib/res/values-az/strings.xml
index 34f506e..a36ab27 100644
--- a/packages/SettingsLib/res/values-az/strings.xml
+++ b/packages/SettingsLib/res/values-az/strings.xml
@@ -567,12 +567,9 @@
<string name="tv_media_transfer_earc_fallback_title" msgid="3098685494578519940">"HDMI eARC"</string>
<string name="tv_media_transfer_arc_subtitle" msgid="1040017851325069082">"Chrome-da Tətbiqin İşləmə Müddəti vasitəsilə qoşulub"</string>
<string name="tv_media_transfer_earc_subtitle" msgid="645191413103303077">"eARC vasitəsilə qoşulub"</string>
- <!-- no translation found for tv_media_transfer_default (5403053145185843843) -->
- <skip />
- <!-- no translation found for tv_media_transfer_hdmi (692569220956829921) -->
- <skip />
- <!-- no translation found for tv_media_transfer_internal_speakers (8181494402866565865) -->
- <skip />
+ <string name="tv_media_transfer_default" msgid="5403053145185843843">"TV defoltu"</string>
+ <string name="tv_media_transfer_hdmi" msgid="692569220956829921">"HDMI çıxışı"</string>
+ <string name="tv_media_transfer_internal_speakers" msgid="8181494402866565865">"Daxili dinamiklər"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Qoşulmaqla bağlı problem. Cihazı deaktiv edin, sonra yenidən aktiv edin"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Simli audio cihaz"</string>
<string name="help_label" msgid="3528360748637781274">"Yardım və rəy"</string>
diff --git a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
index ee75df2..83f7c05 100644
--- a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
+++ b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
@@ -567,12 +567,9 @@
<string name="tv_media_transfer_earc_fallback_title" msgid="3098685494578519940">"HDMI eARC"</string>
<string name="tv_media_transfer_arc_subtitle" msgid="1040017851325069082">"Povezano preko ARC-a"</string>
<string name="tv_media_transfer_earc_subtitle" msgid="645191413103303077">"Povezano preko eARC-a"</string>
- <!-- no translation found for tv_media_transfer_default (5403053145185843843) -->
- <skip />
- <!-- no translation found for tv_media_transfer_hdmi (692569220956829921) -->
- <skip />
- <!-- no translation found for tv_media_transfer_internal_speakers (8181494402866565865) -->
- <skip />
+ <string name="tv_media_transfer_default" msgid="5403053145185843843">"Podrazumevana vrednost za TV"</string>
+ <string name="tv_media_transfer_hdmi" msgid="692569220956829921">"HDMI izlaz"</string>
+ <string name="tv_media_transfer_internal_speakers" msgid="8181494402866565865">"Unutrašnji zvučnici"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Problem pri povezivanju. Isključite uređaj, pa ga ponovo uključite"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Žičani audio uređaj"</string>
<string name="help_label" msgid="3528360748637781274">"Pomoć i povratne informacije"</string>
diff --git a/packages/SettingsLib/res/values-be/strings.xml b/packages/SettingsLib/res/values-be/strings.xml
index c17d7236..7e8cd8b 100644
--- a/packages/SettingsLib/res/values-be/strings.xml
+++ b/packages/SettingsLib/res/values-be/strings.xml
@@ -567,12 +567,9 @@
<string name="tv_media_transfer_earc_fallback_title" msgid="3098685494578519940">"HDMI eARC"</string>
<string name="tv_media_transfer_arc_subtitle" msgid="1040017851325069082">"Падключана праз ARC"</string>
<string name="tv_media_transfer_earc_subtitle" msgid="645191413103303077">"Падключана праз eARC"</string>
- <!-- no translation found for tv_media_transfer_default (5403053145185843843) -->
- <skip />
- <!-- no translation found for tv_media_transfer_hdmi (692569220956829921) -->
- <skip />
- <!-- no translation found for tv_media_transfer_internal_speakers (8181494402866565865) -->
- <skip />
+ <string name="tv_media_transfer_default" msgid="5403053145185843843">"Стандартны аўдыявыхад тэлевізара"</string>
+ <string name="tv_media_transfer_hdmi" msgid="692569220956829921">"Выхад HDMI"</string>
+ <string name="tv_media_transfer_internal_speakers" msgid="8181494402866565865">"Унутраныя дынамікі"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Праблема з падключэннем. Выключыце і зноў уключыце прыладу"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Правадная аўдыяпрылада"</string>
<string name="help_label" msgid="3528360748637781274">"Даведка і водгукі"</string>
diff --git a/packages/SettingsLib/res/values-bg/strings.xml b/packages/SettingsLib/res/values-bg/strings.xml
index 222e758..d279349 100644
--- a/packages/SettingsLib/res/values-bg/strings.xml
+++ b/packages/SettingsLib/res/values-bg/strings.xml
@@ -567,12 +567,9 @@
<string name="tv_media_transfer_earc_fallback_title" msgid="3098685494578519940">"HDMI eARC"</string>
<string name="tv_media_transfer_arc_subtitle" msgid="1040017851325069082">"Свързано посредством ARC"</string>
<string name="tv_media_transfer_earc_subtitle" msgid="645191413103303077">"Свързано посредством eARC"</string>
- <!-- no translation found for tv_media_transfer_default (5403053145185843843) -->
- <skip />
- <!-- no translation found for tv_media_transfer_hdmi (692569220956829921) -->
- <skip />
- <!-- no translation found for tv_media_transfer_internal_speakers (8181494402866565865) -->
- <skip />
+ <string name="tv_media_transfer_default" msgid="5403053145185843843">"Стандартното за телевизора"</string>
+ <string name="tv_media_transfer_hdmi" msgid="692569220956829921">"HDMI изход"</string>
+ <string name="tv_media_transfer_internal_speakers" msgid="8181494402866565865">"Вградени високоговорители"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"При свързването възникна проблем. Изключете устройството и го включете отново"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Аудиоустройство с кабел"</string>
<string name="help_label" msgid="3528360748637781274">"Помощ и отзиви"</string>
diff --git a/packages/SettingsLib/res/values-bn/strings.xml b/packages/SettingsLib/res/values-bn/strings.xml
index a7c95df..3ac3a3b 100644
--- a/packages/SettingsLib/res/values-bn/strings.xml
+++ b/packages/SettingsLib/res/values-bn/strings.xml
@@ -567,12 +567,9 @@
<string name="tv_media_transfer_earc_fallback_title" msgid="3098685494578519940">"HDMI eARC"</string>
<string name="tv_media_transfer_arc_subtitle" msgid="1040017851325069082">"ARC-এর মাধ্যমে কানেক্ট করা হয়েছে"</string>
<string name="tv_media_transfer_earc_subtitle" msgid="645191413103303077">"eARC-এর মাধ্যমে কানেক্ট করা হয়েছে"</string>
- <!-- no translation found for tv_media_transfer_default (5403053145185843843) -->
- <skip />
- <!-- no translation found for tv_media_transfer_hdmi (692569220956829921) -->
- <skip />
- <!-- no translation found for tv_media_transfer_internal_speakers (8181494402866565865) -->
- <skip />
+ <string name="tv_media_transfer_default" msgid="5403053145185843843">"টিভির ডিফল্ট সেটিং"</string>
+ <string name="tv_media_transfer_hdmi" msgid="692569220956829921">"HDMI আউটপুট"</string>
+ <string name="tv_media_transfer_internal_speakers" msgid="8181494402866565865">"ইন্টার্নাল স্পিকার"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"কানেক্ট করতে সমস্যা হচ্ছে। ডিভাইস বন্ধ করে আবার চালু করুন"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"ওয়্যার অডিও ডিভাইস"</string>
<string name="help_label" msgid="3528360748637781274">"সহায়তা ও মতামত"</string>
diff --git a/packages/SettingsLib/res/values-bs/strings.xml b/packages/SettingsLib/res/values-bs/strings.xml
index 31ea4d4..f84ccb0 100644
--- a/packages/SettingsLib/res/values-bs/strings.xml
+++ b/packages/SettingsLib/res/values-bs/strings.xml
@@ -567,12 +567,9 @@
<string name="tv_media_transfer_earc_fallback_title" msgid="3098685494578519940">"HDMI eARC"</string>
<string name="tv_media_transfer_arc_subtitle" msgid="1040017851325069082">"Povezano je putem ARC-a"</string>
<string name="tv_media_transfer_earc_subtitle" msgid="645191413103303077">"Povezano je putem eARC-a"</string>
- <!-- no translation found for tv_media_transfer_default (5403053145185843843) -->
- <skip />
- <!-- no translation found for tv_media_transfer_hdmi (692569220956829921) -->
- <skip />
- <!-- no translation found for tv_media_transfer_internal_speakers (8181494402866565865) -->
- <skip />
+ <string name="tv_media_transfer_default" msgid="5403053145185843843">"Zadano za TV"</string>
+ <string name="tv_media_transfer_hdmi" msgid="692569220956829921">"HDMI izlaz"</string>
+ <string name="tv_media_transfer_internal_speakers" msgid="8181494402866565865">"Interni zvučnici"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Došlo je do problema prilikom povezivanja. Isključite, pa ponovo uključite uređaj"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Žičani audio uređaj"</string>
<string name="help_label" msgid="3528360748637781274">"Pomoć i povratne informacije"</string>
diff --git a/packages/SettingsLib/res/values-ca/strings.xml b/packages/SettingsLib/res/values-ca/strings.xml
index 1bb02c2..c205f74 100644
--- a/packages/SettingsLib/res/values-ca/strings.xml
+++ b/packages/SettingsLib/res/values-ca/strings.xml
@@ -567,12 +567,9 @@
<string name="tv_media_transfer_earc_fallback_title" msgid="3098685494578519940">"HDMI eARC"</string>
<string name="tv_media_transfer_arc_subtitle" msgid="1040017851325069082">"Connectat mitjançant ARC"</string>
<string name="tv_media_transfer_earc_subtitle" msgid="645191413103303077">"Connectat mitjançant eARC"</string>
- <!-- no translation found for tv_media_transfer_default (5403053145185843843) -->
- <skip />
- <!-- no translation found for tv_media_transfer_hdmi (692569220956829921) -->
- <skip />
- <!-- no translation found for tv_media_transfer_internal_speakers (8181494402866565865) -->
- <skip />
+ <string name="tv_media_transfer_default" msgid="5403053145185843843">"Televisor predeterminat"</string>
+ <string name="tv_media_transfer_hdmi" msgid="692569220956829921">"Sortida HDMI"</string>
+ <string name="tv_media_transfer_internal_speakers" msgid="8181494402866565865">"Altaveus interns"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Hi ha hagut un problema amb la connexió. Apaga el dispositiu i torna\'l a encendre."</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Dispositiu d\'àudio amb cable"</string>
<string name="help_label" msgid="3528360748637781274">"Ajuda i suggeriments"</string>
diff --git a/packages/SettingsLib/res/values-da/strings.xml b/packages/SettingsLib/res/values-da/strings.xml
index 7ab6669..2a6a247 100644
--- a/packages/SettingsLib/res/values-da/strings.xml
+++ b/packages/SettingsLib/res/values-da/strings.xml
@@ -567,12 +567,9 @@
<string name="tv_media_transfer_earc_fallback_title" msgid="3098685494578519940">"HDMI eARC"</string>
<string name="tv_media_transfer_arc_subtitle" msgid="1040017851325069082">"Forbundet via ARC"</string>
<string name="tv_media_transfer_earc_subtitle" msgid="645191413103303077">"Forbundet via eARC"</string>
- <!-- no translation found for tv_media_transfer_default (5403053145185843843) -->
- <skip />
- <!-- no translation found for tv_media_transfer_hdmi (692569220956829921) -->
- <skip />
- <!-- no translation found for tv_media_transfer_internal_speakers (8181494402866565865) -->
- <skip />
+ <string name="tv_media_transfer_default" msgid="5403053145185843843">"Standardindstillinger for fjernsyn"</string>
+ <string name="tv_media_transfer_hdmi" msgid="692569220956829921">"HDMI-udgang"</string>
+ <string name="tv_media_transfer_internal_speakers" msgid="8181494402866565865">"Interne højttalere"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Der kunne ikke oprettes forbindelse. Sluk og tænd enheden"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Lydenhed med ledning"</string>
<string name="help_label" msgid="3528360748637781274">"Hjælp og feedback"</string>
diff --git a/packages/SettingsLib/res/values-en-rAU/strings.xml b/packages/SettingsLib/res/values-en-rAU/strings.xml
index 29038bc..a5f089a 100644
--- a/packages/SettingsLib/res/values-en-rAU/strings.xml
+++ b/packages/SettingsLib/res/values-en-rAU/strings.xml
@@ -567,12 +567,9 @@
<string name="tv_media_transfer_earc_fallback_title" msgid="3098685494578519940">"HDMI eARC"</string>
<string name="tv_media_transfer_arc_subtitle" msgid="1040017851325069082">"Connected via ARC"</string>
<string name="tv_media_transfer_earc_subtitle" msgid="645191413103303077">"Connected via eARC"</string>
- <!-- no translation found for tv_media_transfer_default (5403053145185843843) -->
- <skip />
- <!-- no translation found for tv_media_transfer_hdmi (692569220956829921) -->
- <skip />
- <!-- no translation found for tv_media_transfer_internal_speakers (8181494402866565865) -->
- <skip />
+ <string name="tv_media_transfer_default" msgid="5403053145185843843">"TV default"</string>
+ <string name="tv_media_transfer_hdmi" msgid="692569220956829921">"HDMI output"</string>
+ <string name="tv_media_transfer_internal_speakers" msgid="8181494402866565865">"Internal speakers"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Problem connecting. Turn device off and back on"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Wired audio device"</string>
<string name="help_label" msgid="3528360748637781274">"Help and feedback"</string>
diff --git a/packages/SettingsLib/res/values-en-rGB/strings.xml b/packages/SettingsLib/res/values-en-rGB/strings.xml
index 29038bc..a5f089a 100644
--- a/packages/SettingsLib/res/values-en-rGB/strings.xml
+++ b/packages/SettingsLib/res/values-en-rGB/strings.xml
@@ -567,12 +567,9 @@
<string name="tv_media_transfer_earc_fallback_title" msgid="3098685494578519940">"HDMI eARC"</string>
<string name="tv_media_transfer_arc_subtitle" msgid="1040017851325069082">"Connected via ARC"</string>
<string name="tv_media_transfer_earc_subtitle" msgid="645191413103303077">"Connected via eARC"</string>
- <!-- no translation found for tv_media_transfer_default (5403053145185843843) -->
- <skip />
- <!-- no translation found for tv_media_transfer_hdmi (692569220956829921) -->
- <skip />
- <!-- no translation found for tv_media_transfer_internal_speakers (8181494402866565865) -->
- <skip />
+ <string name="tv_media_transfer_default" msgid="5403053145185843843">"TV default"</string>
+ <string name="tv_media_transfer_hdmi" msgid="692569220956829921">"HDMI output"</string>
+ <string name="tv_media_transfer_internal_speakers" msgid="8181494402866565865">"Internal speakers"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Problem connecting. Turn device off and back on"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Wired audio device"</string>
<string name="help_label" msgid="3528360748637781274">"Help and feedback"</string>
diff --git a/packages/SettingsLib/res/values-en-rIN/strings.xml b/packages/SettingsLib/res/values-en-rIN/strings.xml
index 29038bc..a5f089a 100644
--- a/packages/SettingsLib/res/values-en-rIN/strings.xml
+++ b/packages/SettingsLib/res/values-en-rIN/strings.xml
@@ -567,12 +567,9 @@
<string name="tv_media_transfer_earc_fallback_title" msgid="3098685494578519940">"HDMI eARC"</string>
<string name="tv_media_transfer_arc_subtitle" msgid="1040017851325069082">"Connected via ARC"</string>
<string name="tv_media_transfer_earc_subtitle" msgid="645191413103303077">"Connected via eARC"</string>
- <!-- no translation found for tv_media_transfer_default (5403053145185843843) -->
- <skip />
- <!-- no translation found for tv_media_transfer_hdmi (692569220956829921) -->
- <skip />
- <!-- no translation found for tv_media_transfer_internal_speakers (8181494402866565865) -->
- <skip />
+ <string name="tv_media_transfer_default" msgid="5403053145185843843">"TV default"</string>
+ <string name="tv_media_transfer_hdmi" msgid="692569220956829921">"HDMI output"</string>
+ <string name="tv_media_transfer_internal_speakers" msgid="8181494402866565865">"Internal speakers"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Problem connecting. Turn device off and back on"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Wired audio device"</string>
<string name="help_label" msgid="3528360748637781274">"Help and feedback"</string>
diff --git a/packages/SettingsLib/res/values-es/strings.xml b/packages/SettingsLib/res/values-es/strings.xml
index 82cd2bf..c07e1fd 100644
--- a/packages/SettingsLib/res/values-es/strings.xml
+++ b/packages/SettingsLib/res/values-es/strings.xml
@@ -567,12 +567,9 @@
<string name="tv_media_transfer_earc_fallback_title" msgid="3098685494578519940">"HDMI eARC"</string>
<string name="tv_media_transfer_arc_subtitle" msgid="1040017851325069082">"Conectado mediante ARC"</string>
<string name="tv_media_transfer_earc_subtitle" msgid="645191413103303077">"Conectado mediante eARC"</string>
- <!-- no translation found for tv_media_transfer_default (5403053145185843843) -->
- <skip />
- <!-- no translation found for tv_media_transfer_hdmi (692569220956829921) -->
- <skip />
- <!-- no translation found for tv_media_transfer_internal_speakers (8181494402866565865) -->
- <skip />
+ <string name="tv_media_transfer_default" msgid="5403053145185843843">"Predeterminada de la televisión"</string>
+ <string name="tv_media_transfer_hdmi" msgid="692569220956829921">"Salida HDMI"</string>
+ <string name="tv_media_transfer_internal_speakers" msgid="8181494402866565865">"Altavoces internos"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"No se ha podido conectar; reinicia el dispositivo"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Dispositivo de audio con cable"</string>
<string name="help_label" msgid="3528360748637781274">"Ayuda y comentarios"</string>
diff --git a/packages/SettingsLib/res/values-et/strings.xml b/packages/SettingsLib/res/values-et/strings.xml
index 35ae73e..ddc16b0 100644
--- a/packages/SettingsLib/res/values-et/strings.xml
+++ b/packages/SettingsLib/res/values-et/strings.xml
@@ -567,12 +567,9 @@
<string name="tv_media_transfer_earc_fallback_title" msgid="3098685494578519940">"HDMI eARC"</string>
<string name="tv_media_transfer_arc_subtitle" msgid="1040017851325069082">"Ühendatud ARC-i kaudu"</string>
<string name="tv_media_transfer_earc_subtitle" msgid="645191413103303077">"Ühendatud eARC-i kaudu"</string>
- <!-- no translation found for tv_media_transfer_default (5403053145185843843) -->
- <skip />
- <!-- no translation found for tv_media_transfer_hdmi (692569220956829921) -->
- <skip />
- <!-- no translation found for tv_media_transfer_internal_speakers (8181494402866565865) -->
- <skip />
+ <string name="tv_media_transfer_default" msgid="5403053145185843843">"Teleri vaikeväljund"</string>
+ <string name="tv_media_transfer_hdmi" msgid="692569220956829921">"HDMI-väljund"</string>
+ <string name="tv_media_transfer_internal_speakers" msgid="8181494402866565865">"Sisemised kõlarid"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Probleem ühendamisel. Lülitage seade välja ja uuesti sisse"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Juhtmega heliseade"</string>
<string name="help_label" msgid="3528360748637781274">"Abi ja tagasiside"</string>
diff --git a/packages/SettingsLib/res/values-eu/strings.xml b/packages/SettingsLib/res/values-eu/strings.xml
index 7ebad68..deb4bc6 100644
--- a/packages/SettingsLib/res/values-eu/strings.xml
+++ b/packages/SettingsLib/res/values-eu/strings.xml
@@ -567,12 +567,9 @@
<string name="tv_media_transfer_earc_fallback_title" msgid="3098685494578519940">"HDMI eARC"</string>
<string name="tv_media_transfer_arc_subtitle" msgid="1040017851325069082">"ARC bidez konektatuta"</string>
<string name="tv_media_transfer_earc_subtitle" msgid="645191413103303077">"eARC bidez konektatuta"</string>
- <!-- no translation found for tv_media_transfer_default (5403053145185843843) -->
- <skip />
- <!-- no translation found for tv_media_transfer_hdmi (692569220956829921) -->
- <skip />
- <!-- no translation found for tv_media_transfer_internal_speakers (8181494402866565865) -->
- <skip />
+ <string name="tv_media_transfer_default" msgid="5403053145185843843">"Telebistaren audio-erreproduzigailu lehenetsia"</string>
+ <string name="tv_media_transfer_hdmi" msgid="692569220956829921">"HDMI irteera"</string>
+ <string name="tv_media_transfer_internal_speakers" msgid="8181494402866565865">"Barneko bozgorailuak"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Arazo bat izan da konektatzean. Itzali gailua eta pitz ezazu berriro."</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Audio-gailu kableduna"</string>
<string name="help_label" msgid="3528360748637781274">"Laguntza eta iritziak"</string>
diff --git a/packages/SettingsLib/res/values-fa/strings.xml b/packages/SettingsLib/res/values-fa/strings.xml
index 51fd626..d73571e 100644
--- a/packages/SettingsLib/res/values-fa/strings.xml
+++ b/packages/SettingsLib/res/values-fa/strings.xml
@@ -567,12 +567,9 @@
<string name="tv_media_transfer_earc_fallback_title" msgid="3098685494578519940">"HDMI eARC"</string>
<string name="tv_media_transfer_arc_subtitle" msgid="1040017851325069082">"متصل ازطریق ARC"</string>
<string name="tv_media_transfer_earc_subtitle" msgid="645191413103303077">"متصل ازطریق eARC"</string>
- <!-- no translation found for tv_media_transfer_default (5403053145185843843) -->
- <skip />
- <!-- no translation found for tv_media_transfer_hdmi (692569220956829921) -->
- <skip />
- <!-- no translation found for tv_media_transfer_internal_speakers (8181494402866565865) -->
- <skip />
+ <string name="tv_media_transfer_default" msgid="5403053145185843843">"پیشفرض تلویزیون"</string>
+ <string name="tv_media_transfer_hdmi" msgid="692569220956829921">"خروجی HDMI"</string>
+ <string name="tv_media_transfer_internal_speakers" msgid="8181494402866565865">"بلندگوهای داخلی"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"مشکل در اتصال. دستگاه را خاموش و دوباره روشن کنید"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"دستگاه صوتی سیمی"</string>
<string name="help_label" msgid="3528360748637781274">"راهنما و بازخورد"</string>
diff --git a/packages/SettingsLib/res/values-fi/strings.xml b/packages/SettingsLib/res/values-fi/strings.xml
index f8c9054..3533d77 100644
--- a/packages/SettingsLib/res/values-fi/strings.xml
+++ b/packages/SettingsLib/res/values-fi/strings.xml
@@ -567,12 +567,9 @@
<string name="tv_media_transfer_earc_fallback_title" msgid="3098685494578519940">"HDMI eARC"</string>
<string name="tv_media_transfer_arc_subtitle" msgid="1040017851325069082">"Yhdistetty ARC:n kautta"</string>
<string name="tv_media_transfer_earc_subtitle" msgid="645191413103303077">"Yhdistetty eARC:n kautta"</string>
- <!-- no translation found for tv_media_transfer_default (5403053145185843843) -->
- <skip />
- <!-- no translation found for tv_media_transfer_hdmi (692569220956829921) -->
- <skip />
- <!-- no translation found for tv_media_transfer_internal_speakers (8181494402866565865) -->
- <skip />
+ <string name="tv_media_transfer_default" msgid="5403053145185843843">"TV:n oletusasetus"</string>
+ <string name="tv_media_transfer_hdmi" msgid="692569220956829921">"HDMI-toisto"</string>
+ <string name="tv_media_transfer_internal_speakers" msgid="8181494402866565865">"Sisäiset kaiuttimet"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Yhteysvirhe. Sammuta laite ja käynnistä se uudelleen."</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Langallinen äänilaite"</string>
<string name="help_label" msgid="3528360748637781274">"Ohje ja palaute"</string>
diff --git a/packages/SettingsLib/res/values-fr-rCA/strings.xml b/packages/SettingsLib/res/values-fr-rCA/strings.xml
index 2a7266d..06eeae0 100644
--- a/packages/SettingsLib/res/values-fr-rCA/strings.xml
+++ b/packages/SettingsLib/res/values-fr-rCA/strings.xml
@@ -567,12 +567,9 @@
<string name="tv_media_transfer_earc_fallback_title" msgid="3098685494578519940">"HDMI eARC"</string>
<string name="tv_media_transfer_arc_subtitle" msgid="1040017851325069082">"Connecté par ARC"</string>
<string name="tv_media_transfer_earc_subtitle" msgid="645191413103303077">"Connecté par eARC"</string>
- <!-- no translation found for tv_media_transfer_default (5403053145185843843) -->
- <skip />
- <!-- no translation found for tv_media_transfer_hdmi (692569220956829921) -->
- <skip />
- <!-- no translation found for tv_media_transfer_internal_speakers (8181494402866565865) -->
- <skip />
+ <string name="tv_media_transfer_default" msgid="5403053145185843843">"Sortie audio par défaut de la télévision"</string>
+ <string name="tv_media_transfer_hdmi" msgid="692569220956829921">"Sortie HDMI"</string>
+ <string name="tv_media_transfer_internal_speakers" msgid="8181494402866565865">"Haut-parleurs internes"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Problème de connexion. Éteingez et rallumez l\'appareil"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Appareil audio à câble"</string>
<string name="help_label" msgid="3528360748637781274">"Aide et commentaires"</string>
diff --git a/packages/SettingsLib/res/values-gl/strings.xml b/packages/SettingsLib/res/values-gl/strings.xml
index 7b79386..f896d16 100644
--- a/packages/SettingsLib/res/values-gl/strings.xml
+++ b/packages/SettingsLib/res/values-gl/strings.xml
@@ -567,12 +567,9 @@
<string name="tv_media_transfer_earc_fallback_title" msgid="3098685494578519940">"HDMI eARC"</string>
<string name="tv_media_transfer_arc_subtitle" msgid="1040017851325069082">"Conectado mediante ARC"</string>
<string name="tv_media_transfer_earc_subtitle" msgid="645191413103303077">"Conectado mediante eARC"</string>
- <!-- no translation found for tv_media_transfer_default (5403053145185843843) -->
- <skip />
- <!-- no translation found for tv_media_transfer_hdmi (692569220956829921) -->
- <skip />
- <!-- no translation found for tv_media_transfer_internal_speakers (8181494402866565865) -->
- <skip />
+ <string name="tv_media_transfer_default" msgid="5403053145185843843">"Opción predeterminada da televisión"</string>
+ <string name="tv_media_transfer_hdmi" msgid="692569220956829921">"Saída HDMI"</string>
+ <string name="tv_media_transfer_internal_speakers" msgid="8181494402866565865">"Altofalantes internos"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Produciuse un problema coa conexión. Apaga e acende o dispositivo."</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Dispositivo de audio con cable"</string>
<string name="help_label" msgid="3528360748637781274">"Axuda e comentarios"</string>
diff --git a/packages/SettingsLib/res/values-gu/strings.xml b/packages/SettingsLib/res/values-gu/strings.xml
index ec534da..50741dd 100644
--- a/packages/SettingsLib/res/values-gu/strings.xml
+++ b/packages/SettingsLib/res/values-gu/strings.xml
@@ -567,12 +567,9 @@
<string name="tv_media_transfer_earc_fallback_title" msgid="3098685494578519940">"HDMI eARC"</string>
<string name="tv_media_transfer_arc_subtitle" msgid="1040017851325069082">"ARC મારફતે કનેક્ટેડ"</string>
<string name="tv_media_transfer_earc_subtitle" msgid="645191413103303077">"eARC મારફતે કનેક્ટેડ"</string>
- <!-- no translation found for tv_media_transfer_default (5403053145185843843) -->
- <skip />
- <!-- no translation found for tv_media_transfer_hdmi (692569220956829921) -->
- <skip />
- <!-- no translation found for tv_media_transfer_internal_speakers (8181494402866565865) -->
- <skip />
+ <string name="tv_media_transfer_default" msgid="5403053145185843843">"ડિવાઇસનું ડિફૉલ્ટ ઑડિયો આઉટપુટ, ટીવી"</string>
+ <string name="tv_media_transfer_hdmi" msgid="692569220956829921">"HDMI આઉટપુટ"</string>
+ <string name="tv_media_transfer_internal_speakers" msgid="8181494402866565865">"આંતરિક સ્પીકર"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"કનેક્ટ કરવામાં સમસ્યા આવી રહી છે. ડિવાઇસને બંધ કરીને ફરી ચાલુ કરો"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"વાયરવાળો ઑડિયો ડિવાઇસ"</string>
<string name="help_label" msgid="3528360748637781274">"સહાય અને પ્રતિસાદ"</string>
diff --git a/packages/SettingsLib/res/values-hi/strings.xml b/packages/SettingsLib/res/values-hi/strings.xml
index 092c729..0a29b6a 100644
--- a/packages/SettingsLib/res/values-hi/strings.xml
+++ b/packages/SettingsLib/res/values-hi/strings.xml
@@ -567,12 +567,9 @@
<string name="tv_media_transfer_earc_fallback_title" msgid="3098685494578519940">"एचडीएमआई eARC"</string>
<string name="tv_media_transfer_arc_subtitle" msgid="1040017851325069082">"ARC से कनेक्ट किए गए डिवाइस"</string>
<string name="tv_media_transfer_earc_subtitle" msgid="645191413103303077">"eARC से कनेक्ट किए गए डिवाइस"</string>
- <!-- no translation found for tv_media_transfer_default (5403053145185843843) -->
- <skip />
- <!-- no translation found for tv_media_transfer_hdmi (692569220956829921) -->
- <skip />
- <!-- no translation found for tv_media_transfer_internal_speakers (8181494402866565865) -->
- <skip />
+ <string name="tv_media_transfer_default" msgid="5403053145185843843">"टीवी की डिफ़ॉल्ट सेटिंग"</string>
+ <string name="tv_media_transfer_hdmi" msgid="692569220956829921">"एचडीएमआई आउटपुट"</string>
+ <string name="tv_media_transfer_internal_speakers" msgid="8181494402866565865">"इंटरनल स्पीकर"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"कनेक्ट करने में समस्या हो रही है. डिवाइस को बंद करके चालू करें"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"वायर वाला ऑडियो डिवाइस"</string>
<string name="help_label" msgid="3528360748637781274">"सहायता और सुझाव"</string>
diff --git a/packages/SettingsLib/res/values-hr/strings.xml b/packages/SettingsLib/res/values-hr/strings.xml
index eaebfc9..b206ac0 100644
--- a/packages/SettingsLib/res/values-hr/strings.xml
+++ b/packages/SettingsLib/res/values-hr/strings.xml
@@ -567,12 +567,9 @@
<string name="tv_media_transfer_earc_fallback_title" msgid="3098685494578519940">"HDMI eARC"</string>
<string name="tv_media_transfer_arc_subtitle" msgid="1040017851325069082">"Povezano putem ARC-a"</string>
<string name="tv_media_transfer_earc_subtitle" msgid="645191413103303077">"Povezano putem eARC-a"</string>
- <!-- no translation found for tv_media_transfer_default (5403053145185843843) -->
- <skip />
- <!-- no translation found for tv_media_transfer_hdmi (692569220956829921) -->
- <skip />
- <!-- no translation found for tv_media_transfer_internal_speakers (8181494402866565865) -->
- <skip />
+ <string name="tv_media_transfer_default" msgid="5403053145185843843">"Zadano za TV"</string>
+ <string name="tv_media_transfer_hdmi" msgid="692569220956829921">"HDMI izlaz"</string>
+ <string name="tv_media_transfer_internal_speakers" msgid="8181494402866565865">"Unutarnji zvučnici"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Problem s povezivanjem. Isključite i ponovo uključite uređaj"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Žičani audiouređaj"</string>
<string name="help_label" msgid="3528360748637781274">"Pomoć i povratne informacije"</string>
diff --git a/packages/SettingsLib/res/values-hu/strings.xml b/packages/SettingsLib/res/values-hu/strings.xml
index d287ce3..68ff9ae 100644
--- a/packages/SettingsLib/res/values-hu/strings.xml
+++ b/packages/SettingsLib/res/values-hu/strings.xml
@@ -567,12 +567,9 @@
<string name="tv_media_transfer_earc_fallback_title" msgid="3098685494578519940">"HDMI eARC"</string>
<string name="tv_media_transfer_arc_subtitle" msgid="1040017851325069082">"Csatlakoztatva ARC-n keresztül"</string>
<string name="tv_media_transfer_earc_subtitle" msgid="645191413103303077">"Csatlakoztatva eARC-n keresztül"</string>
- <!-- no translation found for tv_media_transfer_default (5403053145185843843) -->
- <skip />
- <!-- no translation found for tv_media_transfer_hdmi (692569220956829921) -->
- <skip />
- <!-- no translation found for tv_media_transfer_internal_speakers (8181494402866565865) -->
- <skip />
+ <string name="tv_media_transfer_default" msgid="5403053145185843843">"Tévé alapértelmezett eszköze"</string>
+ <string name="tv_media_transfer_hdmi" msgid="692569220956829921">"HDMI-kimenet"</string>
+ <string name="tv_media_transfer_internal_speakers" msgid="8181494402866565865">"Belső hangszórók"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Sikertelen csatlakozás. Kapcsolja ki az eszközt, majd kapcsolja be újra."</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Vezetékes audioeszköz"</string>
<string name="help_label" msgid="3528360748637781274">"Súgó és visszajelzés"</string>
diff --git a/packages/SettingsLib/res/values-hy/strings.xml b/packages/SettingsLib/res/values-hy/strings.xml
index 4d27099..f3061a7 100644
--- a/packages/SettingsLib/res/values-hy/strings.xml
+++ b/packages/SettingsLib/res/values-hy/strings.xml
@@ -567,12 +567,9 @@
<string name="tv_media_transfer_earc_fallback_title" msgid="3098685494578519940">"HDMI eARC"</string>
<string name="tv_media_transfer_arc_subtitle" msgid="1040017851325069082">"Միացված է ARC-ի միջոցով"</string>
<string name="tv_media_transfer_earc_subtitle" msgid="645191413103303077">"Միացված է eARC-ի միջոցով"</string>
- <!-- no translation found for tv_media_transfer_default (5403053145185843843) -->
- <skip />
- <!-- no translation found for tv_media_transfer_hdmi (692569220956829921) -->
- <skip />
- <!-- no translation found for tv_media_transfer_internal_speakers (8181494402866565865) -->
- <skip />
+ <string name="tv_media_transfer_default" msgid="5403053145185843843">"Հեռուստացույցի կանխադրված կարգավորումներ"</string>
+ <string name="tv_media_transfer_hdmi" msgid="692569220956829921">"HDMI ելք"</string>
+ <string name="tv_media_transfer_internal_speakers" msgid="8181494402866565865">"Ներքին բարձրախոսներ"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Կապի խնդիր կա: Սարքն անջատեք և նորից միացրեք:"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Լարով աուդիո սարք"</string>
<string name="help_label" msgid="3528360748637781274">"Օգնություն և հետադարձ կապ"</string>
diff --git a/packages/SettingsLib/res/values-in/strings.xml b/packages/SettingsLib/res/values-in/strings.xml
index ce770af..2c16603 100644
--- a/packages/SettingsLib/res/values-in/strings.xml
+++ b/packages/SettingsLib/res/values-in/strings.xml
@@ -567,12 +567,9 @@
<string name="tv_media_transfer_earc_fallback_title" msgid="3098685494578519940">"HDMI eARC"</string>
<string name="tv_media_transfer_arc_subtitle" msgid="1040017851325069082">"Terhubung melalui ARC"</string>
<string name="tv_media_transfer_earc_subtitle" msgid="645191413103303077">"Terhubung melalui eARC"</string>
- <!-- no translation found for tv_media_transfer_default (5403053145185843843) -->
- <skip />
- <!-- no translation found for tv_media_transfer_hdmi (692569220956829921) -->
- <skip />
- <!-- no translation found for tv_media_transfer_internal_speakers (8181494402866565865) -->
- <skip />
+ <string name="tv_media_transfer_default" msgid="5403053145185843843">"TV sebagai default"</string>
+ <string name="tv_media_transfer_hdmi" msgid="692569220956829921">"Output HDMI"</string>
+ <string name="tv_media_transfer_internal_speakers" msgid="8181494402866565865">"Speaker internal"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Ada masalah saat menghubungkan. Nonaktifkan perangkat & aktifkan kembali"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Perangkat audio berkabel"</string>
<string name="help_label" msgid="3528360748637781274">"Bantuan & masukan"</string>
diff --git a/packages/SettingsLib/res/values-it/strings.xml b/packages/SettingsLib/res/values-it/strings.xml
index fd68d14..5a82e16 100644
--- a/packages/SettingsLib/res/values-it/strings.xml
+++ b/packages/SettingsLib/res/values-it/strings.xml
@@ -567,12 +567,9 @@
<string name="tv_media_transfer_earc_fallback_title" msgid="3098685494578519940">"eARC HDMI"</string>
<string name="tv_media_transfer_arc_subtitle" msgid="1040017851325069082">"Connessione tramite ARC"</string>
<string name="tv_media_transfer_earc_subtitle" msgid="645191413103303077">"Connessione tramite eARC"</string>
- <!-- no translation found for tv_media_transfer_default (5403053145185843843) -->
- <skip />
- <!-- no translation found for tv_media_transfer_hdmi (692569220956829921) -->
- <skip />
- <!-- no translation found for tv_media_transfer_internal_speakers (8181494402866565865) -->
- <skip />
+ <string name="tv_media_transfer_default" msgid="5403053145185843843">"TV predefinita"</string>
+ <string name="tv_media_transfer_hdmi" msgid="692569220956829921">"Uscita HDMI"</string>
+ <string name="tv_media_transfer_internal_speakers" msgid="8181494402866565865">"Speaker interni"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Problema di connessione. Spegni e riaccendi il dispositivo"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Dispositivo audio cablato"</string>
<string name="help_label" msgid="3528360748637781274">"Guida e feedback"</string>
diff --git a/packages/SettingsLib/res/values-ja/strings.xml b/packages/SettingsLib/res/values-ja/strings.xml
index 58d4f0e..5d57843 100644
--- a/packages/SettingsLib/res/values-ja/strings.xml
+++ b/packages/SettingsLib/res/values-ja/strings.xml
@@ -567,12 +567,9 @@
<string name="tv_media_transfer_earc_fallback_title" msgid="3098685494578519940">"HDMI eARC"</string>
<string name="tv_media_transfer_arc_subtitle" msgid="1040017851325069082">"ARC 経由で接続済み"</string>
<string name="tv_media_transfer_earc_subtitle" msgid="645191413103303077">"eARC 経由で接続済み"</string>
- <!-- no translation found for tv_media_transfer_default (5403053145185843843) -->
- <skip />
- <!-- no translation found for tv_media_transfer_hdmi (692569220956829921) -->
- <skip />
- <!-- no translation found for tv_media_transfer_internal_speakers (8181494402866565865) -->
- <skip />
+ <string name="tv_media_transfer_default" msgid="5403053145185843843">"テレビのデフォルト"</string>
+ <string name="tv_media_transfer_hdmi" msgid="692569220956829921">"HDMI 出力"</string>
+ <string name="tv_media_transfer_internal_speakers" msgid="8181494402866565865">"内蔵スピーカー"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"接続エラーです。デバイスを OFF にしてから ON に戻してください"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"有線オーディオ デバイス"</string>
<string name="help_label" msgid="3528360748637781274">"ヘルプとフィードバック"</string>
diff --git a/packages/SettingsLib/res/values-kk/strings.xml b/packages/SettingsLib/res/values-kk/strings.xml
index 0d31dde..a8fb9aa 100644
--- a/packages/SettingsLib/res/values-kk/strings.xml
+++ b/packages/SettingsLib/res/values-kk/strings.xml
@@ -567,12 +567,9 @@
<string name="tv_media_transfer_earc_fallback_title" msgid="3098685494578519940">"HDMI eARC"</string>
<string name="tv_media_transfer_arc_subtitle" msgid="1040017851325069082">"ARC арқылы жалғанған."</string>
<string name="tv_media_transfer_earc_subtitle" msgid="645191413103303077">"eARC арқылы жалғанған."</string>
- <!-- no translation found for tv_media_transfer_default (5403053145185843843) -->
- <skip />
- <!-- no translation found for tv_media_transfer_hdmi (692569220956829921) -->
- <skip />
- <!-- no translation found for tv_media_transfer_internal_speakers (8181494402866565865) -->
- <skip />
+ <string name="tv_media_transfer_default" msgid="5403053145185843843">"Теледидардың әдепкі шығысы"</string>
+ <string name="tv_media_transfer_hdmi" msgid="692569220956829921">"HDMI шығыс интерфейсі"</string>
+ <string name="tv_media_transfer_internal_speakers" msgid="8181494402866565865">"Ішкі динамиктер"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Байланыс орнату қатесі шығуып жатыр. Құрылғыны өшіріп, қайта қосыңыз."</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Сымды аудио құрылғысы"</string>
<string name="help_label" msgid="3528360748637781274">"Анықтама және пікір"</string>
diff --git a/packages/SettingsLib/res/values-km/strings.xml b/packages/SettingsLib/res/values-km/strings.xml
index 8ee7987..16f14ff 100644
--- a/packages/SettingsLib/res/values-km/strings.xml
+++ b/packages/SettingsLib/res/values-km/strings.xml
@@ -567,12 +567,9 @@
<string name="tv_media_transfer_earc_fallback_title" msgid="3098685494578519940">"HDMI eARC"</string>
<string name="tv_media_transfer_arc_subtitle" msgid="1040017851325069082">"បានភ្ជាប់តាមរយៈ ARC"</string>
<string name="tv_media_transfer_earc_subtitle" msgid="645191413103303077">"បានភ្ជាប់តាមរយៈ eARC"</string>
- <!-- no translation found for tv_media_transfer_default (5403053145185843843) -->
- <skip />
- <!-- no translation found for tv_media_transfer_hdmi (692569220956829921) -->
- <skip />
- <!-- no translation found for tv_media_transfer_internal_speakers (8181494402866565865) -->
- <skip />
+ <string name="tv_media_transfer_default" msgid="5403053145185843843">"លំនាំដើមទូរទស្សន៍"</string>
+ <string name="tv_media_transfer_hdmi" msgid="692569220956829921">"ធាតុចេញ HDMI"</string>
+ <string name="tv_media_transfer_internal_speakers" msgid="8181494402866565865">"ឧបករណ៍បំពងសំឡេងខាងក្នុង"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"មានបញ្ហាក្នុងការភ្ជាប់។ បិទ រួចបើកឧបករណ៍វិញ"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"ឧបករណ៍សំឡេងប្រើខ្សែ"</string>
<string name="help_label" msgid="3528360748637781274">"ជំនួយ និងមតិកែលម្អ"</string>
diff --git a/packages/SettingsLib/res/values-kn/strings.xml b/packages/SettingsLib/res/values-kn/strings.xml
index 73f7a20..640d4e9 100644
--- a/packages/SettingsLib/res/values-kn/strings.xml
+++ b/packages/SettingsLib/res/values-kn/strings.xml
@@ -567,12 +567,9 @@
<string name="tv_media_transfer_earc_fallback_title" msgid="3098685494578519940">"HDMI eARC"</string>
<string name="tv_media_transfer_arc_subtitle" msgid="1040017851325069082">"ARC ಮೂಲಕ ಕನೆಕ್ಟ್ ಮಾಡಲಾಗಿದೆ"</string>
<string name="tv_media_transfer_earc_subtitle" msgid="645191413103303077">"eARC ಮೂಲಕ ಕನೆಕ್ಟ್ ಮಾಡಲಾಗಿದೆ"</string>
- <!-- no translation found for tv_media_transfer_default (5403053145185843843) -->
- <skip />
- <!-- no translation found for tv_media_transfer_hdmi (692569220956829921) -->
- <skip />
- <!-- no translation found for tv_media_transfer_internal_speakers (8181494402866565865) -->
- <skip />
+ <string name="tv_media_transfer_default" msgid="5403053145185843843">"ಟಿವಿ ಡೀಫಾಲ್ಟ್"</string>
+ <string name="tv_media_transfer_hdmi" msgid="692569220956829921">"HDMI ಔಟ್ಪುಟ್"</string>
+ <string name="tv_media_transfer_internal_speakers" msgid="8181494402866565865">"ಆಂತರಿಕ ಸ್ಪೀಕರ್ಗಳು"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"ಕನೆಕ್ಟ್ ಮಾಡುವಾಗ ಸಮಸ್ಯೆ ಎದುರಾಗಿದೆ ಸಾಧನವನ್ನು ಆಫ್ ಮಾಡಿ ಹಾಗೂ ನಂತರ ಪುನಃ ಆನ್ ಮಾಡಿ"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"ವೈರ್ ಹೊಂದಿರುವ ಆಡಿಯೋ ಸಾಧನ"</string>
<string name="help_label" msgid="3528360748637781274">"ಸಹಾಯ ಮತ್ತು ಪ್ರತಿಕ್ರಿಯೆ"</string>
diff --git a/packages/SettingsLib/res/values-ko/strings.xml b/packages/SettingsLib/res/values-ko/strings.xml
index 418e47e..1bf0a51 100644
--- a/packages/SettingsLib/res/values-ko/strings.xml
+++ b/packages/SettingsLib/res/values-ko/strings.xml
@@ -567,12 +567,9 @@
<string name="tv_media_transfer_earc_fallback_title" msgid="3098685494578519940">"HDMI eARC"</string>
<string name="tv_media_transfer_arc_subtitle" msgid="1040017851325069082">"ARC를 통해 연결됨"</string>
<string name="tv_media_transfer_earc_subtitle" msgid="645191413103303077">"eARC를 통해 연결됨"</string>
- <!-- no translation found for tv_media_transfer_default (5403053145185843843) -->
- <skip />
- <!-- no translation found for tv_media_transfer_hdmi (692569220956829921) -->
- <skip />
- <!-- no translation found for tv_media_transfer_internal_speakers (8181494402866565865) -->
- <skip />
+ <string name="tv_media_transfer_default" msgid="5403053145185843843">"TV 기본값"</string>
+ <string name="tv_media_transfer_hdmi" msgid="692569220956829921">"HDMI 출력"</string>
+ <string name="tv_media_transfer_internal_speakers" msgid="8181494402866565865">"내부 스피커"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"연결 중에 문제가 발생했습니다. 기기를 껐다가 다시 켜 보세요."</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"유선 오디오 기기"</string>
<string name="help_label" msgid="3528360748637781274">"고객센터"</string>
diff --git a/packages/SettingsLib/res/values-ky/strings.xml b/packages/SettingsLib/res/values-ky/strings.xml
index 182e912..9565fb0 100644
--- a/packages/SettingsLib/res/values-ky/strings.xml
+++ b/packages/SettingsLib/res/values-ky/strings.xml
@@ -567,12 +567,9 @@
<string name="tv_media_transfer_earc_fallback_title" msgid="3098685494578519940">"HDMI eARC"</string>
<string name="tv_media_transfer_arc_subtitle" msgid="1040017851325069082">"ARC аркылуу туташты"</string>
<string name="tv_media_transfer_earc_subtitle" msgid="645191413103303077">"eARC аркылуу туташты"</string>
- <!-- no translation found for tv_media_transfer_default (5403053145185843843) -->
- <skip />
- <!-- no translation found for tv_media_transfer_hdmi (692569220956829921) -->
- <skip />
- <!-- no translation found for tv_media_transfer_internal_speakers (8181494402866565865) -->
- <skip />
+ <string name="tv_media_transfer_default" msgid="5403053145185843843">"Cыналгыдагы демейки түзмөк"</string>
+ <string name="tv_media_transfer_hdmi" msgid="692569220956829921">"HDMI аудио түзмөгү"</string>
+ <string name="tv_media_transfer_internal_speakers" msgid="8181494402866565865">"Ички динамиктер"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Туташууда маселе келип чыкты. Түзмөктү өчүрүп, кайра күйгүзүп көрүңүз"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Зымдуу аудио түзмөк"</string>
<string name="help_label" msgid="3528360748637781274">"Жардам/Пикир билдирүү"</string>
diff --git a/packages/SettingsLib/res/values-lo/strings.xml b/packages/SettingsLib/res/values-lo/strings.xml
index 5f8ba5f..23f249a0d 100644
--- a/packages/SettingsLib/res/values-lo/strings.xml
+++ b/packages/SettingsLib/res/values-lo/strings.xml
@@ -567,12 +567,9 @@
<string name="tv_media_transfer_earc_fallback_title" msgid="3098685494578519940">"HDMI eARC"</string>
<string name="tv_media_transfer_arc_subtitle" msgid="1040017851325069082">"ເຊື່ອມຕໍ່ຜ່ານ ARC ແລ້ວ"</string>
<string name="tv_media_transfer_earc_subtitle" msgid="645191413103303077">"ເຊື່ອມຕໍ່ຜ່ານ eARC ແລ້ວ"</string>
- <!-- no translation found for tv_media_transfer_default (5403053145185843843) -->
- <skip />
- <!-- no translation found for tv_media_transfer_hdmi (692569220956829921) -->
- <skip />
- <!-- no translation found for tv_media_transfer_internal_speakers (8181494402866565865) -->
- <skip />
+ <string name="tv_media_transfer_default" msgid="5403053145185843843">"ຄ່າເລີ່ມຕົ້ນສຳລັບໂທລະທັດ"</string>
+ <string name="tv_media_transfer_hdmi" msgid="692569220956829921">"ເອົ້າພຸດ HDMI"</string>
+ <string name="tv_media_transfer_internal_speakers" msgid="8181494402866565865">"ລຳໂພງຂອງເຄື່ອງ"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"ເກີດບັນຫາໃນການເຊື່ອມຕໍ່. ປິດອຸປະກອນແລ້ວເປີດກັບຄືນມາໃໝ່"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"ອຸປະກອນສຽງແບບມີສາຍ"</string>
<string name="help_label" msgid="3528360748637781274">"ຊ່ວຍເຫຼືອ ແລະ ຕິຊົມ"</string>
diff --git a/packages/SettingsLib/res/values-lt/strings.xml b/packages/SettingsLib/res/values-lt/strings.xml
index 5294f4a..f529ca4 100644
--- a/packages/SettingsLib/res/values-lt/strings.xml
+++ b/packages/SettingsLib/res/values-lt/strings.xml
@@ -567,12 +567,9 @@
<string name="tv_media_transfer_earc_fallback_title" msgid="3098685494578519940">"HDMI „eARC“"</string>
<string name="tv_media_transfer_arc_subtitle" msgid="1040017851325069082">"Prisijungta per ARC"</string>
<string name="tv_media_transfer_earc_subtitle" msgid="645191413103303077">"Prisijungta per „eARC“"</string>
- <!-- no translation found for tv_media_transfer_default (5403053145185843843) -->
- <skip />
- <!-- no translation found for tv_media_transfer_hdmi (692569220956829921) -->
- <skip />
- <!-- no translation found for tv_media_transfer_internal_speakers (8181494402866565865) -->
- <skip />
+ <string name="tv_media_transfer_default" msgid="5403053145185843843">"TV numatytoji išvestis"</string>
+ <string name="tv_media_transfer_hdmi" msgid="692569220956829921">"HDMI išvestis"</string>
+ <string name="tv_media_transfer_internal_speakers" msgid="8181494402866565865">"Vidiniai garsiakalbiai"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Prisijungiant kilo problema. Išjunkite įrenginį ir vėl jį įjunkite"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Laidinis garso įrenginys"</string>
<string name="help_label" msgid="3528360748637781274">"Pagalba ir atsiliepimai"</string>
diff --git a/packages/SettingsLib/res/values-lv/strings.xml b/packages/SettingsLib/res/values-lv/strings.xml
index 7ea01e7..24be0aa 100644
--- a/packages/SettingsLib/res/values-lv/strings.xml
+++ b/packages/SettingsLib/res/values-lv/strings.xml
@@ -567,12 +567,9 @@
<string name="tv_media_transfer_earc_fallback_title" msgid="3098685494578519940">"HDMI eARC"</string>
<string name="tv_media_transfer_arc_subtitle" msgid="1040017851325069082">"Savienojums izveidots, izmantojot ARC"</string>
<string name="tv_media_transfer_earc_subtitle" msgid="645191413103303077">"Savienojums izveidots, izmantojot eARC"</string>
- <!-- no translation found for tv_media_transfer_default (5403053145185843843) -->
- <skip />
- <!-- no translation found for tv_media_transfer_hdmi (692569220956829921) -->
- <skip />
- <!-- no translation found for tv_media_transfer_internal_speakers (8181494402866565865) -->
- <skip />
+ <string name="tv_media_transfer_default" msgid="5403053145185843843">"Noklusējuma iestatījums televizorā"</string>
+ <string name="tv_media_transfer_hdmi" msgid="692569220956829921">"HDMI izvade"</string>
+ <string name="tv_media_transfer_internal_speakers" msgid="8181494402866565865">"Iekšējie skaļruņi"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Radās problēma ar savienojuma izveidi. Izslēdziet un atkal ieslēdziet ierīci."</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Vadu audioierīce"</string>
<string name="help_label" msgid="3528360748637781274">"Palīdzība un atsauksmes"</string>
diff --git a/packages/SettingsLib/res/values-mk/strings.xml b/packages/SettingsLib/res/values-mk/strings.xml
index d38f42c..030a438 100644
--- a/packages/SettingsLib/res/values-mk/strings.xml
+++ b/packages/SettingsLib/res/values-mk/strings.xml
@@ -567,12 +567,9 @@
<string name="tv_media_transfer_earc_fallback_title" msgid="3098685494578519940">"HDMI eARC"</string>
<string name="tv_media_transfer_arc_subtitle" msgid="1040017851325069082">"Поврзано преку ARC"</string>
<string name="tv_media_transfer_earc_subtitle" msgid="645191413103303077">"Поврзано преку eARC"</string>
- <!-- no translation found for tv_media_transfer_default (5403053145185843843) -->
- <skip />
- <!-- no translation found for tv_media_transfer_hdmi (692569220956829921) -->
- <skip />
- <!-- no translation found for tv_media_transfer_internal_speakers (8181494402866565865) -->
- <skip />
+ <string name="tv_media_transfer_default" msgid="5403053145185843843">"Стандарден излез на телевизор"</string>
+ <string name="tv_media_transfer_hdmi" msgid="692569220956829921">"Излез за HDMI"</string>
+ <string name="tv_media_transfer_internal_speakers" msgid="8181494402866565865">"Внатрешни звучници"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Проблем со поврзување. Исклучете го уредот и повторно вклучете го"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Жичен аудиоуред"</string>
<string name="help_label" msgid="3528360748637781274">"Помош и повратни информации"</string>
diff --git a/packages/SettingsLib/res/values-ml/strings.xml b/packages/SettingsLib/res/values-ml/strings.xml
index 8b6150d..9a01b53 100644
--- a/packages/SettingsLib/res/values-ml/strings.xml
+++ b/packages/SettingsLib/res/values-ml/strings.xml
@@ -567,12 +567,9 @@
<string name="tv_media_transfer_earc_fallback_title" msgid="3098685494578519940">"HDMI eARC"</string>
<string name="tv_media_transfer_arc_subtitle" msgid="1040017851325069082">"ARC വഴി കണക്റ്റ് ചെയ്തിരിക്കുന്നു"</string>
<string name="tv_media_transfer_earc_subtitle" msgid="645191413103303077">"eARC വഴി കണക്റ്റ് ചെയ്തിരിക്കുന്നു"</string>
- <!-- no translation found for tv_media_transfer_default (5403053145185843843) -->
- <skip />
- <!-- no translation found for tv_media_transfer_hdmi (692569220956829921) -->
- <skip />
- <!-- no translation found for tv_media_transfer_internal_speakers (8181494402866565865) -->
- <skip />
+ <string name="tv_media_transfer_default" msgid="5403053145185843843">"ടിവി ഡിഫോൾട്ട്"</string>
+ <string name="tv_media_transfer_hdmi" msgid="692569220956829921">"HDMI ഔട്ട്പുട്ട്"</string>
+ <string name="tv_media_transfer_internal_speakers" msgid="8181494402866565865">"ആന്തരിക സ്പീക്കറുകൾ"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"കണക്റ്റ് ചെയ്യുന്നതിൽ പ്രശ്നമുണ്ടായി. ഉപകരണം ഓഫാക്കി വീണ്ടും ഓണാക്കുക"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"വയർ മുഖേന ബന്ധിപ്പിച്ച ഓഡിയോ ഉപകരണം"</string>
<string name="help_label" msgid="3528360748637781274">"സഹായവും ഫീഡ്ബാക്കും"</string>
diff --git a/packages/SettingsLib/res/values-mn/strings.xml b/packages/SettingsLib/res/values-mn/strings.xml
index e7c83a8..03fecc4 100644
--- a/packages/SettingsLib/res/values-mn/strings.xml
+++ b/packages/SettingsLib/res/values-mn/strings.xml
@@ -567,12 +567,9 @@
<string name="tv_media_transfer_earc_fallback_title" msgid="3098685494578519940">"HDMI eARC"</string>
<string name="tv_media_transfer_arc_subtitle" msgid="1040017851325069082">"ARC-р холбогдсон"</string>
<string name="tv_media_transfer_earc_subtitle" msgid="645191413103303077">"eARC-р холбогдсон"</string>
- <!-- no translation found for tv_media_transfer_default (5403053145185843843) -->
- <skip />
- <!-- no translation found for tv_media_transfer_hdmi (692569220956829921) -->
- <skip />
- <!-- no translation found for tv_media_transfer_internal_speakers (8181494402866565865) -->
- <skip />
+ <string name="tv_media_transfer_default" msgid="5403053145185843843">"ТВ-ийн өгөгдмөл"</string>
+ <string name="tv_media_transfer_hdmi" msgid="692569220956829921">"HDMI гаралт"</string>
+ <string name="tv_media_transfer_internal_speakers" msgid="8181494402866565865">"Дотоод чанга яригч"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Холбогдоход асуудал гарлаа. Төхөөрөмжийг унтраагаад дахин асаана уу"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Утастай аудио төхөөрөмж"</string>
<string name="help_label" msgid="3528360748637781274">"Тусламж, санал хүсэлт"</string>
diff --git a/packages/SettingsLib/res/values-mr/strings.xml b/packages/SettingsLib/res/values-mr/strings.xml
index 381d0b8..e4edf08 100644
--- a/packages/SettingsLib/res/values-mr/strings.xml
+++ b/packages/SettingsLib/res/values-mr/strings.xml
@@ -567,12 +567,9 @@
<string name="tv_media_transfer_earc_fallback_title" msgid="3098685494578519940">"HDMI eARC"</string>
<string name="tv_media_transfer_arc_subtitle" msgid="1040017851325069082">"ARC द्वारे कनेक्ट केलेली"</string>
<string name="tv_media_transfer_earc_subtitle" msgid="645191413103303077">"eARC द्वारे कनेक्ट केलेली"</string>
- <!-- no translation found for tv_media_transfer_default (5403053145185843843) -->
- <skip />
- <!-- no translation found for tv_media_transfer_hdmi (692569220956829921) -->
- <skip />
- <!-- no translation found for tv_media_transfer_internal_speakers (8181494402866565865) -->
- <skip />
+ <string name="tv_media_transfer_default" msgid="5403053145185843843">"टीव्ही डीफॉल्ट"</string>
+ <string name="tv_media_transfer_hdmi" msgid="692569220956829921">"HDMI आउटपुट"</string>
+ <string name="tv_media_transfer_internal_speakers" msgid="8181494402866565865">"अंतर्गत स्पीकर"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"कनेक्ट करण्यात समस्या आली. डिव्हाइस बंद करा आणि नंतर सुरू करा"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"वायर असलेले ऑडिओ डिव्हाइस"</string>
<string name="help_label" msgid="3528360748637781274">"मदत आणि फीडबॅक"</string>
diff --git a/packages/SettingsLib/res/values-ms/strings.xml b/packages/SettingsLib/res/values-ms/strings.xml
index 3e7d901..88f13f6f 100644
--- a/packages/SettingsLib/res/values-ms/strings.xml
+++ b/packages/SettingsLib/res/values-ms/strings.xml
@@ -567,12 +567,9 @@
<string name="tv_media_transfer_earc_fallback_title" msgid="3098685494578519940">"HDMI eARC"</string>
<string name="tv_media_transfer_arc_subtitle" msgid="1040017851325069082">"Disambungkan melalui ARC"</string>
<string name="tv_media_transfer_earc_subtitle" msgid="645191413103303077">"Disambungkan melalui eARC"</string>
- <!-- no translation found for tv_media_transfer_default (5403053145185843843) -->
- <skip />
- <!-- no translation found for tv_media_transfer_hdmi (692569220956829921) -->
- <skip />
- <!-- no translation found for tv_media_transfer_internal_speakers (8181494402866565865) -->
- <skip />
+ <string name="tv_media_transfer_default" msgid="5403053145185843843">"Tetapan lalai TV"</string>
+ <string name="tv_media_transfer_hdmi" msgid="692569220956829921">"Output HDMI"</string>
+ <string name="tv_media_transfer_internal_speakers" msgid="8181494402866565865">"Pembesar suara dalaman"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Masalah penyambungan. Matikan & hidupkan kembali peranti"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Peranti audio berwayar"</string>
<string name="help_label" msgid="3528360748637781274">"Bantuan & maklum balas"</string>
diff --git a/packages/SettingsLib/res/values-my/strings.xml b/packages/SettingsLib/res/values-my/strings.xml
index 68ae549..58e2cf4 100644
--- a/packages/SettingsLib/res/values-my/strings.xml
+++ b/packages/SettingsLib/res/values-my/strings.xml
@@ -567,12 +567,9 @@
<string name="tv_media_transfer_earc_fallback_title" msgid="3098685494578519940">"HDMI eARC"</string>
<string name="tv_media_transfer_arc_subtitle" msgid="1040017851325069082">"ARC မှတစ်ဆင့် ချိတ်ဆက်ထားသည်"</string>
<string name="tv_media_transfer_earc_subtitle" msgid="645191413103303077">"eARC မှတစ်ဆင့် ချိတ်ဆက်ထားသည်"</string>
- <!-- no translation found for tv_media_transfer_default (5403053145185843843) -->
- <skip />
- <!-- no translation found for tv_media_transfer_hdmi (692569220956829921) -->
- <skip />
- <!-- no translation found for tv_media_transfer_internal_speakers (8181494402866565865) -->
- <skip />
+ <string name="tv_media_transfer_default" msgid="5403053145185843843">"TV မူရင်း"</string>
+ <string name="tv_media_transfer_hdmi" msgid="692569220956829921">"HDMI အထွက်"</string>
+ <string name="tv_media_transfer_internal_speakers" msgid="8181494402866565865">"စက်ရှိ စပီကာများ"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"ချိတ်ဆက်ရာတွင် ပြဿနာရှိပါသည်။ စက်ကိုပိတ်ပြီး ပြန်ဖွင့်ပါ"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"ကြိုးတပ် အသံစက်ပစ္စည်း"</string>
<string name="help_label" msgid="3528360748637781274">"အကူအညီနှင့် အကြံပြုချက်"</string>
diff --git a/packages/SettingsLib/res/values-nb/strings.xml b/packages/SettingsLib/res/values-nb/strings.xml
index a11bfff..a5bfe5e 100644
--- a/packages/SettingsLib/res/values-nb/strings.xml
+++ b/packages/SettingsLib/res/values-nb/strings.xml
@@ -567,12 +567,9 @@
<string name="tv_media_transfer_earc_fallback_title" msgid="3098685494578519940">"HDMI eARC"</string>
<string name="tv_media_transfer_arc_subtitle" msgid="1040017851325069082">"Tilkoblet via ARC"</string>
<string name="tv_media_transfer_earc_subtitle" msgid="645191413103303077">"Tilkoblet via eARC"</string>
- <!-- no translation found for tv_media_transfer_default (5403053145185843843) -->
- <skip />
- <!-- no translation found for tv_media_transfer_hdmi (692569220956829921) -->
- <skip />
- <!-- no translation found for tv_media_transfer_internal_speakers (8181494402866565865) -->
- <skip />
+ <string name="tv_media_transfer_default" msgid="5403053145185843843">"TV-ens standardinnstilling"</string>
+ <string name="tv_media_transfer_hdmi" msgid="692569220956829921">"HDMI-utgang"</string>
+ <string name="tv_media_transfer_internal_speakers" msgid="8181494402866565865">"Interne høyttalere"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Tilkoblingsproblemer. Slå enheten av og på igjen"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Lydenhet med kabel"</string>
<string name="help_label" msgid="3528360748637781274">"Hjelp og tilbakemelding"</string>
diff --git a/packages/SettingsLib/res/values-ne/strings.xml b/packages/SettingsLib/res/values-ne/strings.xml
index b833c14..d8e1152 100644
--- a/packages/SettingsLib/res/values-ne/strings.xml
+++ b/packages/SettingsLib/res/values-ne/strings.xml
@@ -567,12 +567,9 @@
<string name="tv_media_transfer_earc_fallback_title" msgid="3098685494578519940">"HDMI eARC"</string>
<string name="tv_media_transfer_arc_subtitle" msgid="1040017851325069082">"ARC मार्फत कनेक्ट गरिएका"</string>
<string name="tv_media_transfer_earc_subtitle" msgid="645191413103303077">"eARC मार्फत कनेक्ट गरिएका"</string>
- <!-- no translation found for tv_media_transfer_default (5403053145185843843) -->
- <skip />
- <!-- no translation found for tv_media_transfer_hdmi (692569220956829921) -->
- <skip />
- <!-- no translation found for tv_media_transfer_internal_speakers (8181494402866565865) -->
- <skip />
+ <string name="tv_media_transfer_default" msgid="5403053145185843843">"टिभीको डिफल्ट अडियो आउटपुट"</string>
+ <string name="tv_media_transfer_hdmi" msgid="692569220956829921">"HDMI आउटपुट"</string>
+ <string name="tv_media_transfer_internal_speakers" msgid="8181494402866565865">"आन्तरिक स्पिकरहरू"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"जोड्ने क्रममा समस्या भयो। यन्त्रलाई निष्क्रिय पारेर फेरि अन गर्नुहोस्"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"तारयुक्त अडियो यन्त्र"</string>
<string name="help_label" msgid="3528360748637781274">"मद्दत र प्रतिक्रिया"</string>
diff --git a/packages/SettingsLib/res/values-nl/strings.xml b/packages/SettingsLib/res/values-nl/strings.xml
index f9215e5..a65ff730 100644
--- a/packages/SettingsLib/res/values-nl/strings.xml
+++ b/packages/SettingsLib/res/values-nl/strings.xml
@@ -567,12 +567,9 @@
<string name="tv_media_transfer_earc_fallback_title" msgid="3098685494578519940">"HDMI eARC"</string>
<string name="tv_media_transfer_arc_subtitle" msgid="1040017851325069082">"Verbonden via ARC"</string>
<string name="tv_media_transfer_earc_subtitle" msgid="645191413103303077">"Verbonden via eARC"</string>
- <!-- no translation found for tv_media_transfer_default (5403053145185843843) -->
- <skip />
- <!-- no translation found for tv_media_transfer_hdmi (692569220956829921) -->
- <skip />
- <!-- no translation found for tv_media_transfer_internal_speakers (8181494402866565865) -->
- <skip />
+ <string name="tv_media_transfer_default" msgid="5403053145185843843">"Tv-standaard"</string>
+ <string name="tv_media_transfer_hdmi" msgid="692569220956829921">"HDMI-uitvoer"</string>
+ <string name="tv_media_transfer_internal_speakers" msgid="8181494402866565865">"Interne speakers"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Probleem bij verbinding maken. Zet het apparaat uit en weer aan."</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Bedraad audioapparaat"</string>
<string name="help_label" msgid="3528360748637781274">"Hulp en feedback"</string>
diff --git a/packages/SettingsLib/res/values-or/strings.xml b/packages/SettingsLib/res/values-or/strings.xml
index c4ed005..add9ff7 100644
--- a/packages/SettingsLib/res/values-or/strings.xml
+++ b/packages/SettingsLib/res/values-or/strings.xml
@@ -567,12 +567,9 @@
<string name="tv_media_transfer_earc_fallback_title" msgid="3098685494578519940">"HDMI eARC"</string>
<string name="tv_media_transfer_arc_subtitle" msgid="1040017851325069082">"ARC ମାଧ୍ୟମରେ କନେକ୍ଟ କରାଯାଇଛି"</string>
<string name="tv_media_transfer_earc_subtitle" msgid="645191413103303077">"eARC ମାଧ୍ୟମରେ କନେକ୍ଟ କରାଯାଇଛି"</string>
- <!-- no translation found for tv_media_transfer_default (5403053145185843843) -->
- <skip />
- <!-- no translation found for tv_media_transfer_hdmi (692569220956829921) -->
- <skip />
- <!-- no translation found for tv_media_transfer_internal_speakers (8181494402866565865) -->
- <skip />
+ <string name="tv_media_transfer_default" msgid="5403053145185843843">"ଟିଭିର ଡିଫଲ୍ଟ ଅଡିଓ ଆଉଟପୁଟ"</string>
+ <string name="tv_media_transfer_hdmi" msgid="692569220956829921">"HDMI ଆଉଟପୁଟ"</string>
+ <string name="tv_media_transfer_internal_speakers" msgid="8181494402866565865">"ଇଣ୍ଟର୍ନଲ ସ୍ପିକର"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"ସଂଯୋଗ କରିବାରେ ସମସ୍ୟା ହେଉଛି। ଡିଭାଇସ୍ ବନ୍ଦ କରି ପୁଣି ଚାଲୁ କରନ୍ତୁ"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"ତାରଯୁକ୍ତ ଅଡିଓ ଡିଭାଇସ୍"</string>
<string name="help_label" msgid="3528360748637781274">"ସାହାଯ୍ୟ ଓ ମତାମତ"</string>
diff --git a/packages/SettingsLib/res/values-pa/strings.xml b/packages/SettingsLib/res/values-pa/strings.xml
index b7a67fd..4a33f05 100644
--- a/packages/SettingsLib/res/values-pa/strings.xml
+++ b/packages/SettingsLib/res/values-pa/strings.xml
@@ -567,12 +567,9 @@
<string name="tv_media_transfer_earc_fallback_title" msgid="3098685494578519940">"HDMI eARC"</string>
<string name="tv_media_transfer_arc_subtitle" msgid="1040017851325069082">"ARC ਰਾਹੀਂ ਕਨੈਕਟ ਕੀਤੇ ਗਏ ਡੀਵਾਈਸ"</string>
<string name="tv_media_transfer_earc_subtitle" msgid="645191413103303077">"eARC ਰਾਹੀਂ ਕਨੈਕਟ ਕੀਤੇ ਗਏ ਡੀਵਾਈਸ"</string>
- <!-- no translation found for tv_media_transfer_default (5403053145185843843) -->
- <skip />
- <!-- no translation found for tv_media_transfer_hdmi (692569220956829921) -->
- <skip />
- <!-- no translation found for tv_media_transfer_internal_speakers (8181494402866565865) -->
- <skip />
+ <string name="tv_media_transfer_default" msgid="5403053145185843843">"ਟੀਵੀ ਦਾ ਪੂਰਵ-ਨਿਰਧਾਰਿਤ ਆਊਟਪੁੱਟ"</string>
+ <string name="tv_media_transfer_hdmi" msgid="692569220956829921">"HDMI ਆਊਟਪੁੱਟ"</string>
+ <string name="tv_media_transfer_internal_speakers" msgid="8181494402866565865">"ਅੰਦਰੂਨੀ ਸਪੀਕਰ"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"ਕਨੈਕਟ ਕਰਨ ਵਿੱਚ ਸਮੱਸਿਆ ਆਈ। ਡੀਵਾਈਸ ਨੂੰ ਬੰਦ ਕਰਕੇ ਵਾਪਸ ਚਾਲੂ ਕਰੋ"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"ਤਾਰ ਵਾਲਾ ਆਡੀਓ ਡੀਵਾਈਸ"</string>
<string name="help_label" msgid="3528360748637781274">"ਮਦਦ ਅਤੇ ਵਿਚਾਰ"</string>
diff --git a/packages/SettingsLib/res/values-pl/strings.xml b/packages/SettingsLib/res/values-pl/strings.xml
index 3ef8fd7e..b319cab 100644
--- a/packages/SettingsLib/res/values-pl/strings.xml
+++ b/packages/SettingsLib/res/values-pl/strings.xml
@@ -567,12 +567,9 @@
<string name="tv_media_transfer_earc_fallback_title" msgid="3098685494578519940">"HDMI eARC"</string>
<string name="tv_media_transfer_arc_subtitle" msgid="1040017851325069082">"Połączono przez ARC"</string>
<string name="tv_media_transfer_earc_subtitle" msgid="645191413103303077">"Połączono przez eARC"</string>
- <!-- no translation found for tv_media_transfer_default (5403053145185843843) -->
- <skip />
- <!-- no translation found for tv_media_transfer_hdmi (692569220956829921) -->
- <skip />
- <!-- no translation found for tv_media_transfer_internal_speakers (8181494402866565865) -->
- <skip />
+ <string name="tv_media_transfer_default" msgid="5403053145185843843">"Ustawienie domyślne telewizora"</string>
+ <string name="tv_media_transfer_hdmi" msgid="692569220956829921">"Wyjście HDMI"</string>
+ <string name="tv_media_transfer_internal_speakers" msgid="8181494402866565865">"Głośniki wewnętrzne"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Problem z połączeniem. Wyłącz i ponownie włącz urządzenie"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Przewodowe urządzenie audio"</string>
<string name="help_label" msgid="3528360748637781274">"Pomoc i opinie"</string>
diff --git a/packages/SettingsLib/res/values-pt-rBR/strings.xml b/packages/SettingsLib/res/values-pt-rBR/strings.xml
index b76b37b..32fa1b6 100644
--- a/packages/SettingsLib/res/values-pt-rBR/strings.xml
+++ b/packages/SettingsLib/res/values-pt-rBR/strings.xml
@@ -237,8 +237,8 @@
<string name="adb_wireless_error" msgid="721958772149779856">"Erro"</string>
<string name="adb_wireless_settings" msgid="2295017847215680229">"Depuração por Wi-Fi"</string>
<string name="adb_wireless_list_empty_off" msgid="1713707973837255490">"Para acessar e usar dispositivos disponíveis, ative a depuração por Wi-Fi."</string>
- <string name="adb_pair_method_qrcode_title" msgid="6982904096137468634">"Parear o dispositivo com um código QR"</string>
- <string name="adb_pair_method_qrcode_summary" msgid="7130694277228970888">"Parear novos dispositivos usando um leitor de código QR"</string>
+ <string name="adb_pair_method_qrcode_title" msgid="6982904096137468634">"Parear o dispositivo com um QR code"</string>
+ <string name="adb_pair_method_qrcode_summary" msgid="7130694277228970888">"Parear novos dispositivos usando um leitor de QR code"</string>
<string name="adb_pair_method_code_title" msgid="1122590300445142904">"Parear o dispositivo com um código de pareamento"</string>
<string name="adb_pair_method_code_summary" msgid="6370414511333685185">"Parear novos dispositivos usando um código de seis dígitos"</string>
<string name="adb_paired_devices_title" msgid="5268997341526217362">"Dispositivos pareados"</string>
@@ -252,12 +252,12 @@
<string name="adb_pairing_device_dialog_pairing_code_label" msgid="3639239786669722731">"Código de pareamento por Wi‑Fi"</string>
<string name="adb_pairing_device_dialog_failed_title" msgid="3426758947882091735">"Falha no pareamento"</string>
<string name="adb_pairing_device_dialog_failed_msg" msgid="6611097519661997148">"Verifique se o dispositivo está conectado à mesma rede."</string>
- <string name="adb_wireless_qrcode_summary" msgid="8051414549011801917">"Parear dispositivo na rede Wi‑Fi fazendo a leitura do código QR"</string>
+ <string name="adb_wireless_qrcode_summary" msgid="8051414549011801917">"Parear dispositivo na rede Wi‑Fi fazendo a leitura do QR code"</string>
<string name="adb_wireless_verifying_qrcode_text" msgid="6123192424916029207">"Pareando dispositivo…"</string>
- <string name="adb_qrcode_pairing_device_failed_msg" msgid="6936292092592914132">"Falha ao parear o dispositivo. O código QR está incorreto ou o dispositivo não está conectado à mesma rede."</string>
+ <string name="adb_qrcode_pairing_device_failed_msg" msgid="6936292092592914132">"Falha ao parear o dispositivo. O QR code está incorreto ou o dispositivo não está conectado à mesma rede."</string>
<string name="adb_wireless_ip_addr_preference_title" msgid="8335132107715311730">"Endereço IP e porta"</string>
- <string name="adb_wireless_qrcode_pairing_title" msgid="1906409667944674707">"Ler código QR"</string>
- <string name="adb_wireless_qrcode_pairing_description" msgid="6014121407143607851">"Parear dispositivo na rede Wi‑Fi fazendo a leitura do código QR"</string>
+ <string name="adb_wireless_qrcode_pairing_title" msgid="1906409667944674707">"Ler QR code"</string>
+ <string name="adb_wireless_qrcode_pairing_description" msgid="6014121407143607851">"Parear dispositivo na rede Wi‑Fi fazendo a leitura do QR code"</string>
<string name="adb_wireless_no_network_msg" msgid="2365795244718494658">"Conecte-se a uma rede Wi-Fi"</string>
<string name="keywords_adb_wireless" msgid="6507505581882171240">"adb, debug, dev"</string>
<string name="bugreport_in_power" msgid="8664089072534638709">"Atalho para relatório de bugs"</string>
@@ -567,12 +567,9 @@
<string name="tv_media_transfer_earc_fallback_title" msgid="3098685494578519940">"HDMI eARC"</string>
<string name="tv_media_transfer_arc_subtitle" msgid="1040017851325069082">"Conectado via ARC"</string>
<string name="tv_media_transfer_earc_subtitle" msgid="645191413103303077">"Conectado via eARC"</string>
- <!-- no translation found for tv_media_transfer_default (5403053145185843843) -->
- <skip />
- <!-- no translation found for tv_media_transfer_hdmi (692569220956829921) -->
- <skip />
- <!-- no translation found for tv_media_transfer_internal_speakers (8181494402866565865) -->
- <skip />
+ <string name="tv_media_transfer_default" msgid="5403053145185843843">"Padrão da TV"</string>
+ <string name="tv_media_transfer_hdmi" msgid="692569220956829921">"Saída HDMI"</string>
+ <string name="tv_media_transfer_internal_speakers" msgid="8181494402866565865">"Alto-falantes internos"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Ocorreu um problema na conexão. Desligue o dispositivo e ligue-o novamente"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Dispositivo de áudio com fio"</string>
<string name="help_label" msgid="3528360748637781274">"Ajuda e feedback"</string>
diff --git a/packages/SettingsLib/res/values-pt/strings.xml b/packages/SettingsLib/res/values-pt/strings.xml
index b76b37b..32fa1b6 100644
--- a/packages/SettingsLib/res/values-pt/strings.xml
+++ b/packages/SettingsLib/res/values-pt/strings.xml
@@ -237,8 +237,8 @@
<string name="adb_wireless_error" msgid="721958772149779856">"Erro"</string>
<string name="adb_wireless_settings" msgid="2295017847215680229">"Depuração por Wi-Fi"</string>
<string name="adb_wireless_list_empty_off" msgid="1713707973837255490">"Para acessar e usar dispositivos disponíveis, ative a depuração por Wi-Fi."</string>
- <string name="adb_pair_method_qrcode_title" msgid="6982904096137468634">"Parear o dispositivo com um código QR"</string>
- <string name="adb_pair_method_qrcode_summary" msgid="7130694277228970888">"Parear novos dispositivos usando um leitor de código QR"</string>
+ <string name="adb_pair_method_qrcode_title" msgid="6982904096137468634">"Parear o dispositivo com um QR code"</string>
+ <string name="adb_pair_method_qrcode_summary" msgid="7130694277228970888">"Parear novos dispositivos usando um leitor de QR code"</string>
<string name="adb_pair_method_code_title" msgid="1122590300445142904">"Parear o dispositivo com um código de pareamento"</string>
<string name="adb_pair_method_code_summary" msgid="6370414511333685185">"Parear novos dispositivos usando um código de seis dígitos"</string>
<string name="adb_paired_devices_title" msgid="5268997341526217362">"Dispositivos pareados"</string>
@@ -252,12 +252,12 @@
<string name="adb_pairing_device_dialog_pairing_code_label" msgid="3639239786669722731">"Código de pareamento por Wi‑Fi"</string>
<string name="adb_pairing_device_dialog_failed_title" msgid="3426758947882091735">"Falha no pareamento"</string>
<string name="adb_pairing_device_dialog_failed_msg" msgid="6611097519661997148">"Verifique se o dispositivo está conectado à mesma rede."</string>
- <string name="adb_wireless_qrcode_summary" msgid="8051414549011801917">"Parear dispositivo na rede Wi‑Fi fazendo a leitura do código QR"</string>
+ <string name="adb_wireless_qrcode_summary" msgid="8051414549011801917">"Parear dispositivo na rede Wi‑Fi fazendo a leitura do QR code"</string>
<string name="adb_wireless_verifying_qrcode_text" msgid="6123192424916029207">"Pareando dispositivo…"</string>
- <string name="adb_qrcode_pairing_device_failed_msg" msgid="6936292092592914132">"Falha ao parear o dispositivo. O código QR está incorreto ou o dispositivo não está conectado à mesma rede."</string>
+ <string name="adb_qrcode_pairing_device_failed_msg" msgid="6936292092592914132">"Falha ao parear o dispositivo. O QR code está incorreto ou o dispositivo não está conectado à mesma rede."</string>
<string name="adb_wireless_ip_addr_preference_title" msgid="8335132107715311730">"Endereço IP e porta"</string>
- <string name="adb_wireless_qrcode_pairing_title" msgid="1906409667944674707">"Ler código QR"</string>
- <string name="adb_wireless_qrcode_pairing_description" msgid="6014121407143607851">"Parear dispositivo na rede Wi‑Fi fazendo a leitura do código QR"</string>
+ <string name="adb_wireless_qrcode_pairing_title" msgid="1906409667944674707">"Ler QR code"</string>
+ <string name="adb_wireless_qrcode_pairing_description" msgid="6014121407143607851">"Parear dispositivo na rede Wi‑Fi fazendo a leitura do QR code"</string>
<string name="adb_wireless_no_network_msg" msgid="2365795244718494658">"Conecte-se a uma rede Wi-Fi"</string>
<string name="keywords_adb_wireless" msgid="6507505581882171240">"adb, debug, dev"</string>
<string name="bugreport_in_power" msgid="8664089072534638709">"Atalho para relatório de bugs"</string>
@@ -567,12 +567,9 @@
<string name="tv_media_transfer_earc_fallback_title" msgid="3098685494578519940">"HDMI eARC"</string>
<string name="tv_media_transfer_arc_subtitle" msgid="1040017851325069082">"Conectado via ARC"</string>
<string name="tv_media_transfer_earc_subtitle" msgid="645191413103303077">"Conectado via eARC"</string>
- <!-- no translation found for tv_media_transfer_default (5403053145185843843) -->
- <skip />
- <!-- no translation found for tv_media_transfer_hdmi (692569220956829921) -->
- <skip />
- <!-- no translation found for tv_media_transfer_internal_speakers (8181494402866565865) -->
- <skip />
+ <string name="tv_media_transfer_default" msgid="5403053145185843843">"Padrão da TV"</string>
+ <string name="tv_media_transfer_hdmi" msgid="692569220956829921">"Saída HDMI"</string>
+ <string name="tv_media_transfer_internal_speakers" msgid="8181494402866565865">"Alto-falantes internos"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Ocorreu um problema na conexão. Desligue o dispositivo e ligue-o novamente"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Dispositivo de áudio com fio"</string>
<string name="help_label" msgid="3528360748637781274">"Ajuda e feedback"</string>
diff --git a/packages/SettingsLib/res/values-ru/strings.xml b/packages/SettingsLib/res/values-ru/strings.xml
index 862e3d4..fe65be5 100644
--- a/packages/SettingsLib/res/values-ru/strings.xml
+++ b/packages/SettingsLib/res/values-ru/strings.xml
@@ -567,12 +567,9 @@
<string name="tv_media_transfer_earc_fallback_title" msgid="3098685494578519940">"HDMI eARC"</string>
<string name="tv_media_transfer_arc_subtitle" msgid="1040017851325069082">"Подключено через ARC"</string>
<string name="tv_media_transfer_earc_subtitle" msgid="645191413103303077">"Подключено через eARC"</string>
- <!-- no translation found for tv_media_transfer_default (5403053145185843843) -->
- <skip />
- <!-- no translation found for tv_media_transfer_hdmi (692569220956829921) -->
- <skip />
- <!-- no translation found for tv_media_transfer_internal_speakers (8181494402866565865) -->
- <skip />
+ <string name="tv_media_transfer_default" msgid="5403053145185843843">"Стандартный выход на телевизоре"</string>
+ <string name="tv_media_transfer_hdmi" msgid="692569220956829921">"Выход HDMI"</string>
+ <string name="tv_media_transfer_internal_speakers" msgid="8181494402866565865">"Внутренние динамики"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Ошибка подключения. Выключите и снова включите устройство."</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Проводное аудиоустройство"</string>
<string name="help_label" msgid="3528360748637781274">"Справка/отзыв"</string>
diff --git a/packages/SettingsLib/res/values-si/strings.xml b/packages/SettingsLib/res/values-si/strings.xml
index 795abec..55e0778 100644
--- a/packages/SettingsLib/res/values-si/strings.xml
+++ b/packages/SettingsLib/res/values-si/strings.xml
@@ -567,12 +567,9 @@
<string name="tv_media_transfer_earc_fallback_title" msgid="3098685494578519940">"HDMI eARC"</string>
<string name="tv_media_transfer_arc_subtitle" msgid="1040017851325069082">"ARC හරහා සම්බන්ධ කර ඇත"</string>
<string name="tv_media_transfer_earc_subtitle" msgid="645191413103303077">"eARC හරහා සම්බන්ධ කර ඇත"</string>
- <!-- no translation found for tv_media_transfer_default (5403053145185843843) -->
- <skip />
- <!-- no translation found for tv_media_transfer_hdmi (692569220956829921) -->
- <skip />
- <!-- no translation found for tv_media_transfer_internal_speakers (8181494402866565865) -->
- <skip />
+ <string name="tv_media_transfer_default" msgid="5403053145185843843">"රූපවාහිනී පෙරනිමිය"</string>
+ <string name="tv_media_transfer_hdmi" msgid="692569220956829921">"HDMI ප්රතිදානය"</string>
+ <string name="tv_media_transfer_internal_speakers" msgid="8181494402866565865">"අභ්යන්තර ස්පීකර්"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"සම්බන්ධ කිරීමේ ගැටලුවකි උපාංගය ක්රියාවිරහිත කර & ආපසු ක්රියාත්මක කරන්න"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"රැහැන්ගත කළ ඕඩියෝ උපාංගය"</string>
<string name="help_label" msgid="3528360748637781274">"උදවු & ප්රතිපෝෂණ"</string>
diff --git a/packages/SettingsLib/res/values-sk/strings.xml b/packages/SettingsLib/res/values-sk/strings.xml
index 00c0bc1..4d03ddd 100644
--- a/packages/SettingsLib/res/values-sk/strings.xml
+++ b/packages/SettingsLib/res/values-sk/strings.xml
@@ -567,12 +567,9 @@
<string name="tv_media_transfer_earc_fallback_title" msgid="3098685494578519940">"HDMI eARC"</string>
<string name="tv_media_transfer_arc_subtitle" msgid="1040017851325069082">"Pripojené prostredníctvom rozhrania ARC"</string>
<string name="tv_media_transfer_earc_subtitle" msgid="645191413103303077">"Pripojené prostredníctvom rozhrania eARC"</string>
- <!-- no translation found for tv_media_transfer_default (5403053145185843843) -->
- <skip />
- <!-- no translation found for tv_media_transfer_hdmi (692569220956829921) -->
- <skip />
- <!-- no translation found for tv_media_transfer_internal_speakers (8181494402866565865) -->
- <skip />
+ <string name="tv_media_transfer_default" msgid="5403053145185843843">"Predvolené nastavenie televízora"</string>
+ <string name="tv_media_transfer_hdmi" msgid="692569220956829921">"Výstup HDMI"</string>
+ <string name="tv_media_transfer_internal_speakers" msgid="8181494402866565865">"Interné reproduktory"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Pri pripájaní sa vyskytol problém. Zariadenie vypnite a znova zapnite."</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Audio zariadenie s káblom"</string>
<string name="help_label" msgid="3528360748637781274">"Pomocník a spätná väzba"</string>
diff --git a/packages/SettingsLib/res/values-sq/strings.xml b/packages/SettingsLib/res/values-sq/strings.xml
index f204017..b627d09 100644
--- a/packages/SettingsLib/res/values-sq/strings.xml
+++ b/packages/SettingsLib/res/values-sq/strings.xml
@@ -567,12 +567,9 @@
<string name="tv_media_transfer_earc_fallback_title" msgid="3098685494578519940">"HDMI eARC"</string>
<string name="tv_media_transfer_arc_subtitle" msgid="1040017851325069082">"Lidhur përmes ARC-së"</string>
<string name="tv_media_transfer_earc_subtitle" msgid="645191413103303077">"Lidhur përmes eARC-së"</string>
- <!-- no translation found for tv_media_transfer_default (5403053145185843843) -->
- <skip />
- <!-- no translation found for tv_media_transfer_hdmi (692569220956829921) -->
- <skip />
- <!-- no translation found for tv_media_transfer_internal_speakers (8181494402866565865) -->
- <skip />
+ <string name="tv_media_transfer_default" msgid="5403053145185843843">"Parazgjedhja e televizorit"</string>
+ <string name="tv_media_transfer_hdmi" msgid="692569220956829921">"Dalja HDMI"</string>
+ <string name="tv_media_transfer_internal_speakers" msgid="8181494402866565865">"Altoparlantët e brendshëm"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Problem me lidhjen. Fike dhe ndize përsëri pajisjen"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Pajisja audio me tel"</string>
<string name="help_label" msgid="3528360748637781274">"Ndihma dhe komentet"</string>
diff --git a/packages/SettingsLib/res/values-sr/strings.xml b/packages/SettingsLib/res/values-sr/strings.xml
index b83986a..224be52 100644
--- a/packages/SettingsLib/res/values-sr/strings.xml
+++ b/packages/SettingsLib/res/values-sr/strings.xml
@@ -567,12 +567,9 @@
<string name="tv_media_transfer_earc_fallback_title" msgid="3098685494578519940">"HDMI eARC"</string>
<string name="tv_media_transfer_arc_subtitle" msgid="1040017851325069082">"Повезано преко ARC-а"</string>
<string name="tv_media_transfer_earc_subtitle" msgid="645191413103303077">"Повезано преко eARC-а"</string>
- <!-- no translation found for tv_media_transfer_default (5403053145185843843) -->
- <skip />
- <!-- no translation found for tv_media_transfer_hdmi (692569220956829921) -->
- <skip />
- <!-- no translation found for tv_media_transfer_internal_speakers (8181494402866565865) -->
- <skip />
+ <string name="tv_media_transfer_default" msgid="5403053145185843843">"Подразумевана вредност за ТВ"</string>
+ <string name="tv_media_transfer_hdmi" msgid="692569220956829921">"HDMI излаз"</string>
+ <string name="tv_media_transfer_internal_speakers" msgid="8181494402866565865">"Унутрашњи звучници"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Проблем при повезивању. Искључите уређај, па га поново укључите"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Жичани аудио уређај"</string>
<string name="help_label" msgid="3528360748637781274">"Помоћ и повратне информације"</string>
diff --git a/packages/SettingsLib/res/values-sv/strings.xml b/packages/SettingsLib/res/values-sv/strings.xml
index 58e3705..7ffad7c 100644
--- a/packages/SettingsLib/res/values-sv/strings.xml
+++ b/packages/SettingsLib/res/values-sv/strings.xml
@@ -567,12 +567,9 @@
<string name="tv_media_transfer_earc_fallback_title" msgid="3098685494578519940">"HDMI eARC"</string>
<string name="tv_media_transfer_arc_subtitle" msgid="1040017851325069082">"Ansluten via ARC"</string>
<string name="tv_media_transfer_earc_subtitle" msgid="645191413103303077">"Ansluten via eARC"</string>
- <!-- no translation found for tv_media_transfer_default (5403053145185843843) -->
- <skip />
- <!-- no translation found for tv_media_transfer_hdmi (692569220956829921) -->
- <skip />
- <!-- no translation found for tv_media_transfer_internal_speakers (8181494402866565865) -->
- <skip />
+ <string name="tv_media_transfer_default" msgid="5403053145185843843">"Standardutgång för tv:n"</string>
+ <string name="tv_media_transfer_hdmi" msgid="692569220956829921">"HDMI-utgång"</string>
+ <string name="tv_media_transfer_internal_speakers" msgid="8181494402866565865">"Interna högtalare"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Det gick inte att ansluta. Stäng av enheten och slå på den igen"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Ljudenhet med kabelanslutning"</string>
<string name="help_label" msgid="3528360748637781274">"Hjälp och feedback"</string>
diff --git a/packages/SettingsLib/res/values-ta/strings.xml b/packages/SettingsLib/res/values-ta/strings.xml
index 2a2536b..b76f7e3 100644
--- a/packages/SettingsLib/res/values-ta/strings.xml
+++ b/packages/SettingsLib/res/values-ta/strings.xml
@@ -567,12 +567,9 @@
<string name="tv_media_transfer_earc_fallback_title" msgid="3098685494578519940">"HDMI eARC"</string>
<string name="tv_media_transfer_arc_subtitle" msgid="1040017851325069082">"ARC மூலம் இணைக்கப்பட்டுள்ளவை"</string>
<string name="tv_media_transfer_earc_subtitle" msgid="645191413103303077">"eARC மூலம் இணைக்கப்பட்டுள்ளவை"</string>
- <!-- no translation found for tv_media_transfer_default (5403053145185843843) -->
- <skip />
- <!-- no translation found for tv_media_transfer_hdmi (692569220956829921) -->
- <skip />
- <!-- no translation found for tv_media_transfer_internal_speakers (8181494402866565865) -->
- <skip />
+ <string name="tv_media_transfer_default" msgid="5403053145185843843">"டிவி இயல்புநிலை"</string>
+ <string name="tv_media_transfer_hdmi" msgid="692569220956829921">"HDMI அவுட்புட்"</string>
+ <string name="tv_media_transfer_internal_speakers" msgid="8181494402866565865">"உட்புற ஸ்பீக்கர்கள்"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"இணைப்பதில் சிக்கல். சாதனத்தை ஆஃப் செய்து மீண்டும் ஆன் செய்யவும்"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"வயருடன்கூடிய ஆடியோ சாதனம்"</string>
<string name="help_label" msgid="3528360748637781274">"உதவியும் கருத்தும்"</string>
diff --git a/packages/SettingsLib/res/values-te/strings.xml b/packages/SettingsLib/res/values-te/strings.xml
index 303d310..23c00c1 100644
--- a/packages/SettingsLib/res/values-te/strings.xml
+++ b/packages/SettingsLib/res/values-te/strings.xml
@@ -567,12 +567,9 @@
<string name="tv_media_transfer_earc_fallback_title" msgid="3098685494578519940">"HDMI eARC"</string>
<string name="tv_media_transfer_arc_subtitle" msgid="1040017851325069082">"ARC ద్వారా కనెక్ట్ చేయబడింది"</string>
<string name="tv_media_transfer_earc_subtitle" msgid="645191413103303077">"eARC ద్వారా కనెక్ట్ చేయబడింది"</string>
- <!-- no translation found for tv_media_transfer_default (5403053145185843843) -->
- <skip />
- <!-- no translation found for tv_media_transfer_hdmi (692569220956829921) -->
- <skip />
- <!-- no translation found for tv_media_transfer_internal_speakers (8181494402866565865) -->
- <skip />
+ <string name="tv_media_transfer_default" msgid="5403053145185843843">"టీవీ ఆటోమేటిక్ సెట్టింగ్"</string>
+ <string name="tv_media_transfer_hdmi" msgid="692569220956829921">"HDMI అవుట్పుట్"</string>
+ <string name="tv_media_transfer_internal_speakers" msgid="8181494402866565865">"అంతర్గత స్పీకర్లు"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"కనెక్ట్ చేయడంలో సమస్య ఉంది. పరికరాన్ని ఆఫ్ చేసి, ఆపై తిరిగి ఆన్ చేయండి"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"వైర్ గల ఆడియో పరికరం"</string>
<string name="help_label" msgid="3528360748637781274">"సహాయం & ఫీడ్బ్యాక్"</string>
diff --git a/packages/SettingsLib/res/values-th/strings.xml b/packages/SettingsLib/res/values-th/strings.xml
index 0ac8cb8..4d9d382 100644
--- a/packages/SettingsLib/res/values-th/strings.xml
+++ b/packages/SettingsLib/res/values-th/strings.xml
@@ -567,12 +567,9 @@
<string name="tv_media_transfer_earc_fallback_title" msgid="3098685494578519940">"HDMI eARC"</string>
<string name="tv_media_transfer_arc_subtitle" msgid="1040017851325069082">"เชื่อมต่อผ่าน ARC"</string>
<string name="tv_media_transfer_earc_subtitle" msgid="645191413103303077">"เชื่อมต่อผ่าน eARC"</string>
- <!-- no translation found for tv_media_transfer_default (5403053145185843843) -->
- <skip />
- <!-- no translation found for tv_media_transfer_hdmi (692569220956829921) -->
- <skip />
- <!-- no translation found for tv_media_transfer_internal_speakers (8181494402866565865) -->
- <skip />
+ <string name="tv_media_transfer_default" msgid="5403053145185843843">"ค่าเริ่มต้นของทีวี"</string>
+ <string name="tv_media_transfer_hdmi" msgid="692569220956829921">"เอาต์พุต HDMI"</string>
+ <string name="tv_media_transfer_internal_speakers" msgid="8181494402866565865">"ลำโพงของเครื่อง"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"เกิดปัญหาในการเชื่อมต่อ ปิดอุปกรณ์แล้วเปิดใหม่อีกครั้ง"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"อุปกรณ์เสียงแบบมีสาย"</string>
<string name="help_label" msgid="3528360748637781274">"ความช่วยเหลือและความคิดเห็น"</string>
diff --git a/packages/SettingsLib/res/values-tl/strings.xml b/packages/SettingsLib/res/values-tl/strings.xml
index 4f92e1d..c9e3494 100644
--- a/packages/SettingsLib/res/values-tl/strings.xml
+++ b/packages/SettingsLib/res/values-tl/strings.xml
@@ -567,12 +567,9 @@
<string name="tv_media_transfer_earc_fallback_title" msgid="3098685494578519940">"HDMI eARC"</string>
<string name="tv_media_transfer_arc_subtitle" msgid="1040017851325069082">"Nakakonekta sa pamamagitan ng ARC"</string>
<string name="tv_media_transfer_earc_subtitle" msgid="645191413103303077">"Nakakonekta sa pamamagitan ng eARC"</string>
- <!-- no translation found for tv_media_transfer_default (5403053145185843843) -->
- <skip />
- <!-- no translation found for tv_media_transfer_hdmi (692569220956829921) -->
- <skip />
- <!-- no translation found for tv_media_transfer_internal_speakers (8181494402866565865) -->
- <skip />
+ <string name="tv_media_transfer_default" msgid="5403053145185843843">"Default ng TV"</string>
+ <string name="tv_media_transfer_hdmi" msgid="692569220956829921">"HDMI output"</string>
+ <string name="tv_media_transfer_internal_speakers" msgid="8181494402866565865">"Mga internal speaker"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Nagkaproblema sa pagkonekta. I-off at pagkatapos ay i-on ang device"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Wired na audio device"</string>
<string name="help_label" msgid="3528360748637781274">"Tulong at feedback"</string>
diff --git a/packages/SettingsLib/res/values-tr/strings.xml b/packages/SettingsLib/res/values-tr/strings.xml
index 795bb30..0f628b4 100644
--- a/packages/SettingsLib/res/values-tr/strings.xml
+++ b/packages/SettingsLib/res/values-tr/strings.xml
@@ -567,12 +567,9 @@
<string name="tv_media_transfer_earc_fallback_title" msgid="3098685494578519940">"HDMI eARC"</string>
<string name="tv_media_transfer_arc_subtitle" msgid="1040017851325069082">"ARC ile bağlandı"</string>
<string name="tv_media_transfer_earc_subtitle" msgid="645191413103303077">"eARC ile bağlandı"</string>
- <!-- no translation found for tv_media_transfer_default (5403053145185843843) -->
- <skip />
- <!-- no translation found for tv_media_transfer_hdmi (692569220956829921) -->
- <skip />
- <!-- no translation found for tv_media_transfer_internal_speakers (8181494402866565865) -->
- <skip />
+ <string name="tv_media_transfer_default" msgid="5403053145185843843">"TV varsayılanı"</string>
+ <string name="tv_media_transfer_hdmi" msgid="692569220956829921">"HDMI çıkışı"</string>
+ <string name="tv_media_transfer_internal_speakers" msgid="8181494402866565865">"Dahili hoparlörler"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Bağlanırken sorun oluştu. Cihazı kapatıp tekrar açın"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Kablolu ses cihazı"</string>
<string name="help_label" msgid="3528360748637781274">"Yardım ve geri bildirim"</string>
diff --git a/packages/SettingsLib/res/values-uk/strings.xml b/packages/SettingsLib/res/values-uk/strings.xml
index beb2c91..e00fbc9 100644
--- a/packages/SettingsLib/res/values-uk/strings.xml
+++ b/packages/SettingsLib/res/values-uk/strings.xml
@@ -567,12 +567,9 @@
<string name="tv_media_transfer_earc_fallback_title" msgid="3098685494578519940">"HDMI eARC"</string>
<string name="tv_media_transfer_arc_subtitle" msgid="1040017851325069082">"Підключено через ARC"</string>
<string name="tv_media_transfer_earc_subtitle" msgid="645191413103303077">"Підключено через eARC"</string>
- <!-- no translation found for tv_media_transfer_default (5403053145185843843) -->
- <skip />
- <!-- no translation found for tv_media_transfer_hdmi (692569220956829921) -->
- <skip />
- <!-- no translation found for tv_media_transfer_internal_speakers (8181494402866565865) -->
- <skip />
+ <string name="tv_media_transfer_default" msgid="5403053145185843843">"Стандартний вихід телевізора"</string>
+ <string name="tv_media_transfer_hdmi" msgid="692569220956829921">"Вихід HDMI"</string>
+ <string name="tv_media_transfer_internal_speakers" msgid="8181494402866565865">"Внутрішні динаміки"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Не вдається підключитися. Перезавантажте пристрій."</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Дротовий аудіопристрій"</string>
<string name="help_label" msgid="3528360748637781274">"Довідка й відгуки"</string>
diff --git a/packages/SettingsLib/res/values-ur/strings.xml b/packages/SettingsLib/res/values-ur/strings.xml
index 13718d9..0dcb12f 100644
--- a/packages/SettingsLib/res/values-ur/strings.xml
+++ b/packages/SettingsLib/res/values-ur/strings.xml
@@ -567,12 +567,9 @@
<string name="tv_media_transfer_earc_fallback_title" msgid="3098685494578519940">"HDMI eARC"</string>
<string name="tv_media_transfer_arc_subtitle" msgid="1040017851325069082">"ARC کے ذریعے منسلک ہے"</string>
<string name="tv_media_transfer_earc_subtitle" msgid="645191413103303077">"eARC کے ذریعے منسلک ہے"</string>
- <!-- no translation found for tv_media_transfer_default (5403053145185843843) -->
- <skip />
- <!-- no translation found for tv_media_transfer_hdmi (692569220956829921) -->
- <skip />
- <!-- no translation found for tv_media_transfer_internal_speakers (8181494402866565865) -->
- <skip />
+ <string name="tv_media_transfer_default" msgid="5403053145185843843">"TV ڈیفالٹ"</string>
+ <string name="tv_media_transfer_hdmi" msgid="692569220956829921">"HDMI آؤٹ پٹ"</string>
+ <string name="tv_media_transfer_internal_speakers" msgid="8181494402866565865">"اندرونی اسپیکرز"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"منسلک کرنے میں مسئلہ پیش آ گیا۔ آلہ کو آف اور بیک آن کریں"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"وائرڈ آڈیو آلہ"</string>
<string name="help_label" msgid="3528360748637781274">"مدد اور تاثرات"</string>
diff --git a/packages/SettingsLib/res/values-uz/strings.xml b/packages/SettingsLib/res/values-uz/strings.xml
index 7559a3d..c94ff4d 100644
--- a/packages/SettingsLib/res/values-uz/strings.xml
+++ b/packages/SettingsLib/res/values-uz/strings.xml
@@ -567,12 +567,9 @@
<string name="tv_media_transfer_earc_fallback_title" msgid="3098685494578519940">"HDMI eARC"</string>
<string name="tv_media_transfer_arc_subtitle" msgid="1040017851325069082">"ARC orqali ulangan"</string>
<string name="tv_media_transfer_earc_subtitle" msgid="645191413103303077">"eARC orqali ulangan"</string>
- <!-- no translation found for tv_media_transfer_default (5403053145185843843) -->
- <skip />
- <!-- no translation found for tv_media_transfer_hdmi (692569220956829921) -->
- <skip />
- <!-- no translation found for tv_media_transfer_internal_speakers (8181494402866565865) -->
- <skip />
+ <string name="tv_media_transfer_default" msgid="5403053145185843843">"Televizorda birlamchi"</string>
+ <string name="tv_media_transfer_hdmi" msgid="692569220956829921">"HDMI chiqishi"</string>
+ <string name="tv_media_transfer_internal_speakers" msgid="8181494402866565865">"Ichki karnaylar"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Ulanishda muammo yuz berdi. Qurilmani oʻchiring va yoqing"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Simli audio qurilma"</string>
<string name="help_label" msgid="3528360748637781274">"Yordam/fikr-mulohaza"</string>
diff --git a/packages/SettingsLib/res/values-vi/strings.xml b/packages/SettingsLib/res/values-vi/strings.xml
index ccdc0bc..03f0770 100644
--- a/packages/SettingsLib/res/values-vi/strings.xml
+++ b/packages/SettingsLib/res/values-vi/strings.xml
@@ -567,12 +567,9 @@
<string name="tv_media_transfer_earc_fallback_title" msgid="3098685494578519940">"HDMI eARC"</string>
<string name="tv_media_transfer_arc_subtitle" msgid="1040017851325069082">"Đã kết nối qua ARC"</string>
<string name="tv_media_transfer_earc_subtitle" msgid="645191413103303077">"Đã kết nối qua eARC"</string>
- <!-- no translation found for tv_media_transfer_default (5403053145185843843) -->
- <skip />
- <!-- no translation found for tv_media_transfer_hdmi (692569220956829921) -->
- <skip />
- <!-- no translation found for tv_media_transfer_internal_speakers (8181494402866565865) -->
- <skip />
+ <string name="tv_media_transfer_default" msgid="5403053145185843843">"Chế độ mặc định của TV"</string>
+ <string name="tv_media_transfer_hdmi" msgid="692569220956829921">"Đầu ra HDMI"</string>
+ <string name="tv_media_transfer_internal_speakers" msgid="8181494402866565865">"Các loa trong"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Sự cố kết nối. Hãy tắt thiết bị rồi bật lại"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Thiết bị âm thanh có dây"</string>
<string name="help_label" msgid="3528360748637781274">"Trợ giúp và phản hồi"</string>
diff --git a/packages/SettingsLib/res/values-zh-rCN/strings.xml b/packages/SettingsLib/res/values-zh-rCN/strings.xml
index 6b3e061..30db033 100644
--- a/packages/SettingsLib/res/values-zh-rCN/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rCN/strings.xml
@@ -567,12 +567,9 @@
<string name="tv_media_transfer_earc_fallback_title" msgid="3098685494578519940">"HDMI eARC"</string>
<string name="tv_media_transfer_arc_subtitle" msgid="1040017851325069082">"已通过 ARC 连接"</string>
<string name="tv_media_transfer_earc_subtitle" msgid="645191413103303077">"已通过 eARC 连接"</string>
- <!-- no translation found for tv_media_transfer_default (5403053145185843843) -->
- <skip />
- <!-- no translation found for tv_media_transfer_hdmi (692569220956829921) -->
- <skip />
- <!-- no translation found for tv_media_transfer_internal_speakers (8181494402866565865) -->
- <skip />
+ <string name="tv_media_transfer_default" msgid="5403053145185843843">"电视默认设置"</string>
+ <string name="tv_media_transfer_hdmi" msgid="692569220956829921">"HDMI 输出"</string>
+ <string name="tv_media_transfer_internal_speakers" msgid="8181494402866565865">"内置扬声器"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"连接时遇到问题。请关闭并重新开启设备"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"有线音频设备"</string>
<string name="help_label" msgid="3528360748637781274">"帮助和反馈"</string>
diff --git a/packages/SettingsLib/res/values-zh-rHK/strings.xml b/packages/SettingsLib/res/values-zh-rHK/strings.xml
index 3517109..2ce4de9 100644
--- a/packages/SettingsLib/res/values-zh-rHK/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rHK/strings.xml
@@ -567,12 +567,9 @@
<string name="tv_media_transfer_earc_fallback_title" msgid="3098685494578519940">"HDMI eARC"</string>
<string name="tv_media_transfer_arc_subtitle" msgid="1040017851325069082">"已透過 ARC 連接"</string>
<string name="tv_media_transfer_earc_subtitle" msgid="645191413103303077">"已透過 eARC 連接"</string>
- <!-- no translation found for tv_media_transfer_default (5403053145185843843) -->
- <skip />
- <!-- no translation found for tv_media_transfer_hdmi (692569220956829921) -->
- <skip />
- <!-- no translation found for tv_media_transfer_internal_speakers (8181494402866565865) -->
- <skip />
+ <string name="tv_media_transfer_default" msgid="5403053145185843843">"電視預設的音訊輸出"</string>
+ <string name="tv_media_transfer_hdmi" msgid="692569220956829921">"HDMI 輸出"</string>
+ <string name="tv_media_transfer_internal_speakers" msgid="8181494402866565865">"內置喇叭"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"無法連接,請關閉裝置然後重新開機"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"有線音響裝置"</string>
<string name="help_label" msgid="3528360748637781274">"說明與意見反映"</string>
diff --git a/packages/SettingsLib/res/values-zh-rTW/strings.xml b/packages/SettingsLib/res/values-zh-rTW/strings.xml
index eeed9f3..2fac076 100644
--- a/packages/SettingsLib/res/values-zh-rTW/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rTW/strings.xml
@@ -567,12 +567,9 @@
<string name="tv_media_transfer_earc_fallback_title" msgid="3098685494578519940">"HDMI eARC"</string>
<string name="tv_media_transfer_arc_subtitle" msgid="1040017851325069082">"透過 ARC 連線"</string>
<string name="tv_media_transfer_earc_subtitle" msgid="645191413103303077">"透過 eARC 連線"</string>
- <!-- no translation found for tv_media_transfer_default (5403053145185843843) -->
- <skip />
- <!-- no translation found for tv_media_transfer_hdmi (692569220956829921) -->
- <skip />
- <!-- no translation found for tv_media_transfer_internal_speakers (8181494402866565865) -->
- <skip />
+ <string name="tv_media_transfer_default" msgid="5403053145185843843">"電視預設的音訊輸出裝置"</string>
+ <string name="tv_media_transfer_hdmi" msgid="692569220956829921">"HDMI 輸出裝置"</string>
+ <string name="tv_media_transfer_internal_speakers" msgid="8181494402866565865">"內建揚聲器"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"無法連線,請關閉裝置後再重新開啟"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"有線音訊裝置"</string>
<string name="help_label" msgid="3528360748637781274">"說明與意見回饋"</string>
diff --git a/packages/SettingsLib/res/values-zu/strings.xml b/packages/SettingsLib/res/values-zu/strings.xml
index e94b929..9a81808 100644
--- a/packages/SettingsLib/res/values-zu/strings.xml
+++ b/packages/SettingsLib/res/values-zu/strings.xml
@@ -567,12 +567,9 @@
<string name="tv_media_transfer_earc_fallback_title" msgid="3098685494578519940">"I-HDMI eARC"</string>
<string name="tv_media_transfer_arc_subtitle" msgid="1040017851325069082">"Ixhunywe nge-ARC"</string>
<string name="tv_media_transfer_earc_subtitle" msgid="645191413103303077">"Ixhunywe nge-eARC"</string>
- <!-- no translation found for tv_media_transfer_default (5403053145185843843) -->
- <skip />
- <!-- no translation found for tv_media_transfer_hdmi (692569220956829921) -->
- <skip />
- <!-- no translation found for tv_media_transfer_internal_speakers (8181494402866565865) -->
- <skip />
+ <string name="tv_media_transfer_default" msgid="5403053145185843843">"I-TV ezenzakalelayo"</string>
+ <string name="tv_media_transfer_hdmi" msgid="692569220956829921">"umphumela we-HDMI"</string>
+ <string name="tv_media_transfer_internal_speakers" msgid="8181494402866565865">"Izipikha zangaphakathi"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Inkinga yokuxhumeka. Vala idivayisi futhi uphinde uyivule"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Idivayisi yomsindo enentambo"</string>
<string name="help_label" msgid="3528360748637781274">"Usizo nempendulo"</string>
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index b6a0c7b..d12d9d6 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -562,6 +562,9 @@
<!-- Permissions required for CTS test - NotificationManagerTest -->
<uses-permission android:name="android.permission.MANAGE_NOTIFICATION_LISTENERS" />
+ <!-- Permissions required for CTS test - NotificationManagerZenTest -->
+ <uses-permission android:name="android.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS" />
+
<!-- Permissions required for CTS test - CtsContactsProviderTestCases -->
<uses-permission android:name="android.contacts.permission.MANAGE_SIM_ACCOUNTS" />
<uses-permission android:name="android.permission.SET_DEFAULT_ACCOUNT_FOR_CONTACTS" />
diff --git a/packages/SystemUI/Android.bp b/packages/SystemUI/Android.bp
index 7cf562f..c2c5e00 100644
--- a/packages/SystemUI/Android.bp
+++ b/packages/SystemUI/Android.bp
@@ -190,6 +190,7 @@
"androidx.room_room-runtime",
"androidx.room_room-ktx",
"com.google.android.material_material",
+ "device_state_flags_lib",
"kotlinx_coroutines_android",
"kotlinx_coroutines",
"iconloader_base",
@@ -302,6 +303,7 @@
"androidx.exifinterface_exifinterface",
"androidx.room_room-runtime",
"androidx.room_room-ktx",
+ "device_state_flags_lib",
"kotlinx-coroutines-android",
"kotlinx-coroutines-core",
"kotlinx_coroutines_test",
diff --git a/packages/SystemUI/aconfig/systemui.aconfig b/packages/SystemUI/aconfig/systemui.aconfig
index f8b6419..c52a89c 100644
--- a/packages/SystemUI/aconfig/systemui.aconfig
+++ b/packages/SystemUI/aconfig/systemui.aconfig
@@ -202,3 +202,10 @@
description: "Faster wallpaper unlock transition"
bug: "298186160"
}
+
+flag {
+ name: "quick_settings_visual_haptics_longpress"
+ namespace: "systemui"
+ description: "Enable special visual and haptic effects for quick settings tiles with long-press actions"
+ bug: "229856884"
+}
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/NestedScrollToScene.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/NestedScrollToScene.kt
index 658b45f..2986504 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/NestedScrollToScene.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/NestedScrollToScene.kt
@@ -17,11 +17,13 @@
package com.android.compose.animation.scene
import androidx.compose.foundation.gestures.Orientation
-import androidx.compose.runtime.DisposableEffect
-import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
-import androidx.compose.ui.composed
-import androidx.compose.ui.input.nestedscroll.nestedScroll
+import androidx.compose.ui.input.nestedscroll.nestedScrollModifierNode
+import androidx.compose.ui.node.DelegatableNode
+import androidx.compose.ui.node.DelegatingNode
+import androidx.compose.ui.node.ModifierNodeElement
+import androidx.compose.ui.platform.InspectorInfo
+import com.android.compose.nestedscroll.PriorityNestedScrollConnection
/**
* Defines the behavior of the [SceneTransitionLayout] when a scrollable component is scrolled.
@@ -32,8 +34,9 @@
*/
enum class NestedScrollBehavior(val canStartOnPostFling: Boolean) {
/**
- * During scene transitions, scroll events are consumed by the [SceneTransitionLayout] instead
- * of the scrollable component.
+ * During scene transitions, if we are within
+ * [SceneTransitionLayoutImpl.transitionInterceptionThreshold], the [SceneTransitionLayout]
+ * consumes scroll events instead of the scrollable component.
*/
DuringTransitionBetweenScenes(canStartOnPostFling = false),
@@ -72,21 +75,101 @@
orientation: Orientation,
startBehavior: NestedScrollBehavior,
endBehavior: NestedScrollBehavior,
-): Modifier = composed {
- val connection =
- remember(layoutImpl, orientation, startBehavior, endBehavior) {
+) =
+ this then
+ NestedScrollToSceneElement(
+ layoutImpl = layoutImpl,
+ orientation = orientation,
+ startBehavior = startBehavior,
+ endBehavior = endBehavior,
+ )
+
+private data class NestedScrollToSceneElement(
+ private val layoutImpl: SceneTransitionLayoutImpl,
+ private val orientation: Orientation,
+ private val startBehavior: NestedScrollBehavior,
+ private val endBehavior: NestedScrollBehavior,
+) : ModifierNodeElement<NestedScrollToSceneNode>() {
+ override fun create() =
+ NestedScrollToSceneNode(
+ layoutImpl = layoutImpl,
+ orientation = orientation,
+ startBehavior = startBehavior,
+ endBehavior = endBehavior,
+ )
+
+ override fun update(node: NestedScrollToSceneNode) {
+ node.update(
+ layoutImpl = layoutImpl,
+ orientation = orientation,
+ startBehavior = startBehavior,
+ endBehavior = endBehavior,
+ )
+ }
+
+ override fun InspectorInfo.inspectableProperties() {
+ name = "nestedScrollToScene"
+ properties["layoutImpl"] = layoutImpl
+ properties["orientation"] = orientation
+ properties["startBehavior"] = startBehavior
+ properties["endBehavior"] = endBehavior
+ }
+}
+
+private class NestedScrollToSceneNode(
+ layoutImpl: SceneTransitionLayoutImpl,
+ orientation: Orientation,
+ startBehavior: NestedScrollBehavior,
+ endBehavior: NestedScrollBehavior,
+) : DelegatingNode() {
+ private var priorityNestedScrollConnection: PriorityNestedScrollConnection =
+ scenePriorityNestedScrollConnection(
+ layoutImpl = layoutImpl,
+ orientation = orientation,
+ startBehavior = startBehavior,
+ endBehavior = endBehavior,
+ )
+
+ private var nestedScrollNode: DelegatableNode =
+ nestedScrollModifierNode(
+ connection = priorityNestedScrollConnection,
+ dispatcher = null,
+ )
+
+ override fun onAttach() {
+ delegate(nestedScrollNode)
+ }
+
+ override fun onDetach() {
+ // Make sure we reset the scroll connection when this modifier is removed from composition
+ priorityNestedScrollConnection.reset()
+ }
+
+ fun update(
+ layoutImpl: SceneTransitionLayoutImpl,
+ orientation: Orientation,
+ startBehavior: NestedScrollBehavior,
+ endBehavior: NestedScrollBehavior,
+ ) {
+ // Clean up the old nested scroll connection
+ priorityNestedScrollConnection.reset()
+ undelegate(nestedScrollNode)
+
+ // Create a new nested scroll connection
+ priorityNestedScrollConnection =
scenePriorityNestedScrollConnection(
layoutImpl = layoutImpl,
orientation = orientation,
startBehavior = startBehavior,
- endBehavior = endBehavior
+ endBehavior = endBehavior,
)
- }
-
- // Make sure we reset the scroll connection when this modifier is removed from composition
- DisposableEffect(connection) { onDispose { connection.reset() } }
-
- nestedScroll(connection = connection)
+ nestedScrollNode =
+ nestedScrollModifierNode(
+ connection = priorityNestedScrollConnection,
+ dispatcher = null,
+ )
+ delegate(nestedScrollNode)
+ }
}
private fun scenePriorityNestedScrollConnection(
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalEditModeViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalEditModeViewModelTest.kt
index ea3006f..8896e6e 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalEditModeViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalEditModeViewModelTest.kt
@@ -39,6 +39,7 @@
import com.android.systemui.util.mockito.mock
import com.android.systemui.util.mockito.whenever
import com.google.common.truth.Truth.assertThat
+import javax.inject.Provider
import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.runTest
import org.junit.Before
@@ -83,7 +84,7 @@
underTest =
CommunalEditModeViewModel(
withDeps.communalInteractor,
- shadeViewController,
+ Provider { shadeViewController },
powerManager,
mediaHost,
)
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalViewModelTest.kt
index 9bd0835..7fbcae0 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalViewModelTest.kt
@@ -39,6 +39,7 @@
import com.android.systemui.util.mockito.mock
import com.android.systemui.util.mockito.whenever
import com.google.common.truth.Truth.assertThat
+import javax.inject.Provider
import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.runTest
import org.junit.Before
@@ -84,7 +85,7 @@
CommunalViewModel(
withDeps.communalInteractor,
withDeps.tutorialInteractor,
- shadeViewController,
+ Provider { shadeViewController },
powerManager,
mediaHost,
)
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/uimodenight/domain/UiModeNightTileDataInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/uimodenight/domain/UiModeNightTileDataInteractorTest.kt
new file mode 100644
index 0000000..7497ebd
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/uimodenight/domain/UiModeNightTileDataInteractorTest.kt
@@ -0,0 +1,200 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.qs.tiles.impl.uimodenight.domain
+
+import android.app.UiModeManager
+import android.content.res.Configuration
+import android.content.res.Configuration.UI_MODE_NIGHT_NO
+import android.content.res.Configuration.UI_MODE_NIGHT_YES
+import android.os.UserHandle
+import android.testing.LeakCheck
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.coroutines.collectValues
+import com.android.systemui.qs.tiles.base.interactor.DataUpdateTrigger
+import com.android.systemui.qs.tiles.impl.uimodenight.domain.interactor.UiModeNightTileDataInteractor
+import com.android.systemui.qs.tiles.impl.uimodenight.domain.model.UiModeNightTileModel
+import com.android.systemui.statusbar.phone.ConfigurationControllerImpl
+import com.android.systemui.statusbar.policy.ConfigurationController
+import com.android.systemui.util.mockito.mock
+import com.android.systemui.util.mockito.whenever
+import com.android.systemui.util.time.DateFormatUtil
+import com.android.systemui.utils.leaks.FakeBatteryController
+import com.android.systemui.utils.leaks.FakeLocationController
+import com.google.common.truth.Truth.assertThat
+import java.time.LocalTime
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.flowOf
+import kotlinx.coroutines.test.runCurrent
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.Mockito.verify
+
+@OptIn(ExperimentalCoroutinesApi::class)
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class UiModeNightTileDataInteractorTest : SysuiTestCase() {
+ private val configurationController: ConfigurationController =
+ ConfigurationControllerImpl(context)
+ private val batteryController = FakeBatteryController(LeakCheck())
+ private val locationController = FakeLocationController(LeakCheck())
+
+ private lateinit var underTest: UiModeNightTileDataInteractor
+
+ @Mock private lateinit var uiModeManager: UiModeManager
+ @Mock private lateinit var dateFormatUtil: DateFormatUtil
+
+ @Before
+ fun setup() {
+ uiModeManager = mock<UiModeManager>()
+ dateFormatUtil = mock<DateFormatUtil>()
+
+ whenever(uiModeManager.customNightModeStart).thenReturn(LocalTime.MIN)
+ whenever(uiModeManager.customNightModeEnd).thenReturn(LocalTime.MAX)
+
+ underTest =
+ UiModeNightTileDataInteractor(
+ context,
+ configurationController,
+ uiModeManager,
+ batteryController,
+ locationController,
+ dateFormatUtil
+ )
+ }
+
+ @Test
+ fun collectTileDataReadsUiModeManagerNightMode() = runTest {
+ val expectedNightMode = Configuration.UI_MODE_NIGHT_UNDEFINED
+ whenever(uiModeManager.nightMode).thenReturn(expectedNightMode)
+
+ val model by
+ collectLastValue(
+ underTest.tileData(TEST_USER, flowOf(DataUpdateTrigger.InitialRequest))
+ )
+ runCurrent()
+
+ assertThat(model).isNotNull()
+ val actualNightMode = model?.uiMode
+ assertThat(actualNightMode).isEqualTo(expectedNightMode)
+ }
+
+ @Test
+ fun collectTileDataReadsUiModeManagerNightModeCustomTypeAndTimes() = runTest {
+ collectLastValue(underTest.tileData(TEST_USER, flowOf(DataUpdateTrigger.InitialRequest)))
+
+ runCurrent()
+
+ verify(uiModeManager).nightMode
+ verify(uiModeManager).nightModeCustomType
+ verify(uiModeManager).customNightModeStart
+ verify(uiModeManager).customNightModeEnd
+ }
+
+ /** Here, available refers to the tile showing up, not the tile being clickable. */
+ @Test
+ fun isAvailableRegardlessOfPowerSaveModeOn() = runTest {
+ batteryController.setPowerSaveMode(true)
+
+ runCurrent()
+ val availability by collectLastValue(underTest.availability(TEST_USER))
+
+ assertThat(availability).isTrue()
+ }
+
+ @Test
+ fun dataMatchesConfigurationController() = runTest {
+ setUiMode(UI_MODE_NIGHT_NO)
+ val flowValues: List<UiModeNightTileModel> by
+ collectValues(underTest.tileData(TEST_USER, flowOf(DataUpdateTrigger.InitialRequest)))
+
+ runCurrent()
+ setUiMode(UI_MODE_NIGHT_YES)
+ runCurrent()
+ setUiMode(UI_MODE_NIGHT_NO)
+ runCurrent()
+
+ assertThat(flowValues.size).isEqualTo(3)
+ assertThat(flowValues.map { it.isNightMode }).containsExactly(false, true, false).inOrder()
+ }
+
+ @Test
+ fun dataMatchesBatteryController() = runTest {
+ batteryController.setPowerSaveMode(false)
+ val flowValues: List<UiModeNightTileModel> by
+ collectValues(underTest.tileData(TEST_USER, flowOf(DataUpdateTrigger.InitialRequest)))
+
+ runCurrent()
+ batteryController.setPowerSaveMode(true)
+ runCurrent()
+ batteryController.setPowerSaveMode(false)
+ runCurrent()
+
+ assertThat(flowValues.size).isEqualTo(3)
+ assertThat(flowValues.map { it.isPowerSave }).containsExactly(false, true, false).inOrder()
+ }
+
+ @Test
+ fun dataMatchesLocationController() = runTest {
+ locationController.setLocationEnabled(false)
+ val flowValues: List<UiModeNightTileModel> by
+ collectValues(underTest.tileData(TEST_USER, flowOf(DataUpdateTrigger.InitialRequest)))
+
+ runCurrent()
+ locationController.setLocationEnabled(true)
+ runCurrent()
+ locationController.setLocationEnabled(false)
+ runCurrent()
+
+ assertThat(flowValues.size).isEqualTo(3)
+ assertThat(flowValues.map { it.isLocationEnabled })
+ .containsExactly(false, true, false)
+ .inOrder()
+ }
+
+ @Test
+ fun collectTileDataReads24HourFormatFromDateTimeUtil() = runTest {
+ collectLastValue(underTest.tileData(TEST_USER, flowOf(DataUpdateTrigger.InitialRequest)))
+ runCurrent()
+
+ verify(dateFormatUtil).is24HourFormat
+ }
+
+ /**
+ * Use this method to trigger [ConfigurationController.ConfigurationListener.onUiModeChanged]
+ */
+ private fun setUiMode(uiMode: Int) {
+ val config = context.resources.configuration
+ val newConfig = Configuration(config)
+ newConfig.uiMode = uiMode
+
+ /** [underTest] will see this config the next time it creates a model */
+ context.orCreateTestableResources.overrideConfiguration(newConfig)
+
+ /** Trigger updateUiMode callbacks */
+ configurationController.onConfigurationChanged(newConfig)
+ }
+
+ private companion object {
+ val TEST_USER = UserHandle.of(1)!!
+ }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/uimodenight/domain/UiModeNightTileMapperTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/uimodenight/domain/UiModeNightTileMapperTest.kt
new file mode 100644
index 0000000..87f5009
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/uimodenight/domain/UiModeNightTileMapperTest.kt
@@ -0,0 +1,481 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.qs.tiles.impl.uimodenight.domain
+
+import android.app.UiModeManager
+import android.text.TextUtils
+import android.view.View
+import android.widget.Switch
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.common.shared.model.Icon
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.qs.tiles.impl.custom.QSTileStateSubject
+import com.android.systemui.qs.tiles.impl.uimodenight.UiModeNightTileModelHelper.createModel
+import com.android.systemui.qs.tiles.impl.uimodenight.qsUiModeNightTileConfig
+import com.android.systemui.qs.tiles.viewmodel.QSTileState
+import com.android.systemui.res.R
+import kotlin.reflect.KClass
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class UiModeNightTileMapperTest : SysuiTestCase() {
+ private val kosmos = Kosmos()
+ private val qsTileConfig = kosmos.qsUiModeNightTileConfig
+
+ private val mapper by lazy {
+ UiModeNightTileMapper(context.orCreateTestableResources.resources)
+ }
+
+ private fun createUiNightModeTileState(
+ iconRes: Int = R.drawable.qs_light_dark_theme_icon_off,
+ label: CharSequence = context.getString(R.string.quick_settings_ui_mode_night_label),
+ activationState: QSTileState.ActivationState = QSTileState.ActivationState.INACTIVE,
+ secondaryLabel: CharSequence? = null,
+ supportedActions: Set<QSTileState.UserAction> =
+ if (activationState == QSTileState.ActivationState.UNAVAILABLE)
+ setOf(QSTileState.UserAction.LONG_CLICK)
+ else setOf(QSTileState.UserAction.CLICK, QSTileState.UserAction.LONG_CLICK),
+ contentDescription: CharSequence? = null,
+ stateDescription: CharSequence? = null,
+ sideViewIcon: QSTileState.SideViewIcon = QSTileState.SideViewIcon.None,
+ enabledState: QSTileState.EnabledState = QSTileState.EnabledState.ENABLED,
+ expandedAccessibilityClass: KClass<out View>? = Switch::class,
+ ): QSTileState {
+ return QSTileState(
+ { Icon.Resource(iconRes, null) },
+ label,
+ activationState,
+ secondaryLabel,
+ supportedActions,
+ contentDescription,
+ stateDescription,
+ sideViewIcon,
+ enabledState,
+ expandedAccessibilityClass?.qualifiedName
+ )
+ }
+
+ @Test
+ fun mapsEnabledDataToUnavailableStateWhenOnPowerSave() {
+ val inputModel = createModel(nightMode = true, powerSave = true)
+
+ val actualState: QSTileState = mapper.map(qsTileConfig, inputModel)
+
+ val expectedLabel = context.getString(R.string.quick_settings_ui_mode_night_label)
+ val expectedSecondaryLabel =
+ context.getString(R.string.quick_settings_dark_mode_secondary_label_battery_saver)
+ val expectedContentDescription =
+ TextUtils.concat(expectedLabel, ", ", expectedSecondaryLabel)
+ val expectedState =
+ createUiNightModeTileState(
+ activationState = QSTileState.ActivationState.UNAVAILABLE,
+ secondaryLabel = expectedSecondaryLabel,
+ contentDescription = expectedContentDescription
+ )
+ QSTileStateSubject.assertThat(actualState).isEqualTo(expectedState)
+ }
+
+ @Test
+ fun mapsDisabledDataToUnavailableStateWhenOnPowerSave() {
+ val inputModel = createModel(nightMode = false, powerSave = true)
+
+ val actualState: QSTileState = mapper.map(qsTileConfig, inputModel)
+
+ val expectedLabel = context.getString(R.string.quick_settings_ui_mode_night_label)
+ val expectedSecondaryLabel =
+ context.getString(R.string.quick_settings_dark_mode_secondary_label_battery_saver)
+ val expectedContentDescription =
+ TextUtils.concat(expectedLabel, ", ", expectedSecondaryLabel)
+ val expectedState =
+ createUiNightModeTileState(
+ activationState = QSTileState.ActivationState.UNAVAILABLE,
+ secondaryLabel = expectedSecondaryLabel,
+ contentDescription = expectedContentDescription
+ )
+ QSTileStateSubject.assertThat(actualState).isEqualTo(expectedState)
+ }
+
+ @Test
+ fun mapsDisabledDataToInactiveState() {
+ val inputModel = createModel(nightMode = false, powerSave = false)
+
+ val actualState: QSTileState = mapper.map(qsTileConfig, inputModel)
+
+ val expectedLabel = context.getString(R.string.quick_settings_ui_mode_night_label)
+ val expectedSecondaryLabel = context.resources.getStringArray(R.array.tile_states_dark)[1]
+ val expectedState =
+ createUiNightModeTileState(
+ activationState = QSTileState.ActivationState.INACTIVE,
+ label = expectedLabel,
+ secondaryLabel = expectedSecondaryLabel,
+ contentDescription = expectedLabel
+ )
+ QSTileStateSubject.assertThat(actualState).isEqualTo(expectedState)
+ }
+
+ @Test
+ fun mapsEnabledDataToActiveState() {
+ val inputModel = createModel(true, false)
+
+ val actualState: QSTileState = mapper.map(qsTileConfig, inputModel)
+
+ val expectedLabel = context.getString(R.string.quick_settings_ui_mode_night_label)
+ val expectedSecondaryLabel = context.resources.getStringArray(R.array.tile_states_dark)[2]
+ val expectedState =
+ createUiNightModeTileState(
+ iconRes = R.drawable.qs_light_dark_theme_icon_on,
+ label = expectedLabel,
+ secondaryLabel = expectedSecondaryLabel,
+ activationState = QSTileState.ActivationState.ACTIVE,
+ contentDescription = expectedLabel
+ )
+ QSTileStateSubject.assertThat(actualState).isEqualTo(expectedState)
+ }
+
+ @Test
+ fun mapsEnabledDataToOnIconState() {
+ val inputModel = createModel(nightMode = true, powerSave = false)
+
+ val actualState: QSTileState = mapper.map(qsTileConfig, inputModel)
+
+ val expectedLabel = context.getString(R.string.quick_settings_ui_mode_night_label)
+ val expectedSecondaryLabel = context.resources.getStringArray(R.array.tile_states_dark)[2]
+ val expectedState =
+ createUiNightModeTileState(
+ iconRes = R.drawable.qs_light_dark_theme_icon_on,
+ label = expectedLabel,
+ secondaryLabel = expectedSecondaryLabel,
+ activationState = QSTileState.ActivationState.ACTIVE,
+ contentDescription = expectedLabel
+ )
+ QSTileStateSubject.assertThat(actualState).isEqualTo(expectedState)
+ }
+
+ @Test
+ fun mapsDisabledDataToOffIconState() {
+ val inputModel = createModel(nightMode = false, powerSave = false)
+
+ val actualState: QSTileState = mapper.map(qsTileConfig, inputModel)
+
+ val expectedLabel = context.getString(R.string.quick_settings_ui_mode_night_label)
+ val expectedSecondaryLabel = context.resources.getStringArray(R.array.tile_states_dark)[1]
+ val expectedState =
+ createUiNightModeTileState(
+ iconRes = R.drawable.qs_light_dark_theme_icon_off,
+ label = expectedLabel,
+ secondaryLabel = expectedSecondaryLabel,
+ activationState = QSTileState.ActivationState.INACTIVE,
+ contentDescription = expectedLabel
+ )
+ QSTileStateSubject.assertThat(actualState).isEqualTo(expectedState)
+ }
+
+ @Test
+ fun supportsClickAndLongClickActionsWhenNotInPowerSaveInNightMode() {
+ val inputModel = createModel(nightMode = true, powerSave = false)
+
+ val actualState: QSTileState = mapper.map(qsTileConfig, inputModel)
+
+ val expectedLabel = context.getString(R.string.quick_settings_ui_mode_night_label)
+ val expectedSecondaryLabel = context.resources.getStringArray(R.array.tile_states_dark)[2]
+ val expectedState =
+ createUiNightModeTileState(
+ iconRes = R.drawable.qs_light_dark_theme_icon_on,
+ label = expectedLabel,
+ secondaryLabel = expectedSecondaryLabel,
+ activationState = QSTileState.ActivationState.ACTIVE,
+ contentDescription = expectedLabel,
+ supportedActions =
+ setOf(QSTileState.UserAction.CLICK, QSTileState.UserAction.LONG_CLICK)
+ )
+ QSTileStateSubject.assertThat(actualState).isEqualTo(expectedState)
+ }
+
+ @Test
+ fun supportsOnlyLongClickActionWhenUnavailableInPowerSaveInNightMode() {
+ val inputModel = createModel(nightMode = true, powerSave = true)
+
+ val actualState: QSTileState = mapper.map(qsTileConfig, inputModel)
+
+ val expectedSecondaryLabel =
+ context.getString(R.string.quick_settings_dark_mode_secondary_label_battery_saver)
+ val expectedLabel = context.getString(R.string.quick_settings_ui_mode_night_label)
+ val expectedContentDescription =
+ TextUtils.concat(expectedLabel, ", ", expectedSecondaryLabel)
+ val expectedState =
+ createUiNightModeTileState(
+ iconRes = R.drawable.qs_light_dark_theme_icon_off,
+ label = expectedLabel,
+ secondaryLabel = expectedSecondaryLabel,
+ activationState = QSTileState.ActivationState.UNAVAILABLE,
+ contentDescription = expectedContentDescription,
+ supportedActions = setOf(QSTileState.UserAction.LONG_CLICK)
+ )
+ QSTileStateSubject.assertThat(actualState).isEqualTo(expectedState)
+ }
+
+ @Test
+ fun supportsClickAndLongClickActionsWhenNotInPowerSaveNotInNightMode() {
+ val inputModel = createModel(nightMode = false, powerSave = false)
+
+ val actualState: QSTileState = mapper.map(qsTileConfig, inputModel)
+
+ val expectedLabel = context.getString(R.string.quick_settings_ui_mode_night_label)
+ val expectedSecondaryLabel = context.resources.getStringArray(R.array.tile_states_dark)[1]
+ val expectedState =
+ createUiNightModeTileState(
+ iconRes = R.drawable.qs_light_dark_theme_icon_off,
+ label = expectedLabel,
+ secondaryLabel = expectedSecondaryLabel,
+ activationState = QSTileState.ActivationState.INACTIVE,
+ contentDescription = expectedLabel,
+ supportedActions =
+ setOf(QSTileState.UserAction.CLICK, QSTileState.UserAction.LONG_CLICK)
+ )
+ QSTileStateSubject.assertThat(actualState).isEqualTo(expectedState)
+ }
+
+ @Test
+ fun supportsOnlyClickActionWhenUnavailableInPowerSaveNotInNightMode() {
+ val inputModel = createModel(nightMode = false, powerSave = true)
+
+ val actualState: QSTileState = mapper.map(qsTileConfig, inputModel)
+
+ val expectedSecondaryLabel =
+ context.getString(R.string.quick_settings_dark_mode_secondary_label_battery_saver)
+ val expectedLabel = context.getString(R.string.quick_settings_ui_mode_night_label)
+ val expectedState =
+ createUiNightModeTileState(
+ iconRes = R.drawable.qs_light_dark_theme_icon_off,
+ label = expectedLabel,
+ secondaryLabel = expectedSecondaryLabel,
+ activationState = QSTileState.ActivationState.UNAVAILABLE,
+ contentDescription = TextUtils.concat(expectedLabel, ", ", expectedSecondaryLabel),
+ supportedActions = setOf(QSTileState.UserAction.LONG_CLICK)
+ )
+ QSTileStateSubject.assertThat(actualState).isEqualTo(expectedState)
+ }
+
+ @Test
+ fun secondaryLabelCorrectWhenInPowerSaveMode() {
+ val inputModel = createModel(powerSave = true)
+
+ val actualState: QSTileState = mapper.map(qsTileConfig, inputModel)
+
+ val expectedSecondaryLabel =
+ context.getString(R.string.quick_settings_dark_mode_secondary_label_battery_saver)
+ val expectedLabel = context.getString(R.string.quick_settings_ui_mode_night_label)
+ val expectedState =
+ createUiNightModeTileState(
+ iconRes = R.drawable.qs_light_dark_theme_icon_off,
+ label = expectedLabel,
+ secondaryLabel = expectedSecondaryLabel,
+ activationState = QSTileState.ActivationState.UNAVAILABLE,
+ contentDescription = TextUtils.concat(expectedLabel, ", ", expectedSecondaryLabel),
+ supportedActions = setOf(QSTileState.UserAction.LONG_CLICK)
+ )
+ QSTileStateSubject.assertThat(actualState).isEqualTo(expectedState)
+ }
+
+ @Test
+ fun secondaryLabelCorrectWhenInNightModeNotInPowerSaveModeLocationEnabledUiModeIsNightAuto() {
+ val inputModel =
+ createModel(
+ nightMode = true,
+ powerSave = false,
+ isLocationEnabled = true,
+ uiMode = UiModeManager.MODE_NIGHT_AUTO
+ )
+
+ val actualState: QSTileState = mapper.map(qsTileConfig, inputModel)
+
+ val expectedSecondaryLabel =
+ context.getString(R.string.quick_settings_dark_mode_secondary_label_until_sunrise)
+ val expectedLabel = context.getString(R.string.quick_settings_ui_mode_night_label)
+ val expectedState =
+ createUiNightModeTileState(
+ iconRes = R.drawable.qs_light_dark_theme_icon_on,
+ label = expectedLabel,
+ secondaryLabel = expectedSecondaryLabel,
+ activationState = QSTileState.ActivationState.ACTIVE,
+ contentDescription = TextUtils.concat(expectedLabel, ", ", expectedSecondaryLabel),
+ supportedActions =
+ setOf(QSTileState.UserAction.CLICK, QSTileState.UserAction.LONG_CLICK)
+ )
+ QSTileStateSubject.assertThat(actualState).isEqualTo(expectedState)
+ }
+
+ @Test
+ fun secondaryLabelCorrectWhenNotInNightModeNotInPowerSaveModeLocationEnableUiModeIsNightAuto() {
+ val inputModel =
+ createModel(
+ nightMode = false,
+ powerSave = false,
+ isLocationEnabled = true,
+ uiMode = UiModeManager.MODE_NIGHT_AUTO
+ )
+
+ val actualState: QSTileState = mapper.map(qsTileConfig, inputModel)
+
+ val expectedSecondaryLabel =
+ context.getString(R.string.quick_settings_dark_mode_secondary_label_on_at_sunset)
+ val expectedLabel = context.getString(R.string.quick_settings_ui_mode_night_label)
+ val expectedState =
+ createUiNightModeTileState(
+ iconRes = R.drawable.qs_light_dark_theme_icon_off,
+ label = expectedLabel,
+ secondaryLabel = expectedSecondaryLabel,
+ activationState = QSTileState.ActivationState.INACTIVE,
+ contentDescription = TextUtils.concat(expectedLabel, ", ", expectedSecondaryLabel),
+ supportedActions =
+ setOf(QSTileState.UserAction.CLICK, QSTileState.UserAction.LONG_CLICK)
+ )
+ QSTileStateSubject.assertThat(actualState).isEqualTo(expectedState)
+ }
+
+ @Test
+ fun secondaryLabelCorrectWhenNotInPowerSaveAndUiModeIsNightYesInNightMode() {
+ val inputModel =
+ createModel(nightMode = true, powerSave = false, uiMode = UiModeManager.MODE_NIGHT_YES)
+
+ val actualState: QSTileState = mapper.map(qsTileConfig, inputModel)
+
+ val expectedSecondaryLabel = context.resources.getStringArray(R.array.tile_states_dark)[2]
+
+ val expectedLabel = context.getString(R.string.quick_settings_ui_mode_night_label)
+ val expectedState =
+ createUiNightModeTileState(
+ iconRes = R.drawable.qs_light_dark_theme_icon_on,
+ label = expectedLabel,
+ secondaryLabel = expectedSecondaryLabel,
+ activationState = QSTileState.ActivationState.ACTIVE,
+ contentDescription = expectedLabel,
+ supportedActions =
+ setOf(QSTileState.UserAction.CLICK, QSTileState.UserAction.LONG_CLICK)
+ )
+ QSTileStateSubject.assertThat(actualState).isEqualTo(expectedState)
+ }
+
+ @Test
+ fun secondaryLabelCorrectWhenNotInPowerSaveAndUiModeIsNightNoNotInNightMode() {
+ val inputModel =
+ createModel(nightMode = false, powerSave = false, uiMode = UiModeManager.MODE_NIGHT_NO)
+
+ val actualState: QSTileState = mapper.map(qsTileConfig, inputModel)
+
+ val expectedSecondaryLabel = context.resources.getStringArray(R.array.tile_states_dark)[1]
+ val expectedLabel = context.getString(R.string.quick_settings_ui_mode_night_label)
+ val expectedState =
+ createUiNightModeTileState(
+ iconRes = R.drawable.qs_light_dark_theme_icon_off,
+ label = expectedLabel,
+ secondaryLabel = expectedSecondaryLabel,
+ activationState = QSTileState.ActivationState.INACTIVE,
+ contentDescription = expectedLabel,
+ supportedActions =
+ setOf(QSTileState.UserAction.CLICK, QSTileState.UserAction.LONG_CLICK)
+ )
+ QSTileStateSubject.assertThat(actualState).isEqualTo(expectedState)
+ }
+
+ @Test
+ fun secondaryLabelCorrectWhenNotInPowerSaveAndUiModeIsUnknownCustomNotInNightMode() {
+ val inputModel =
+ createModel(
+ nightMode = false,
+ powerSave = false,
+ uiMode = UiModeManager.MODE_NIGHT_CUSTOM,
+ nighModeCustomType = UiModeManager.MODE_NIGHT_CUSTOM_TYPE_UNKNOWN
+ )
+
+ val actualState: QSTileState = mapper.map(qsTileConfig, inputModel)
+
+ val expectedSecondaryLabel = context.resources.getStringArray(R.array.tile_states_dark)[1]
+ val expectedLabel = context.getString(R.string.quick_settings_ui_mode_night_label)
+ val expectedState =
+ createUiNightModeTileState(
+ iconRes = R.drawable.qs_light_dark_theme_icon_off,
+ label = expectedLabel,
+ secondaryLabel = expectedSecondaryLabel,
+ activationState = QSTileState.ActivationState.INACTIVE,
+ contentDescription = expectedLabel,
+ supportedActions =
+ setOf(QSTileState.UserAction.CLICK, QSTileState.UserAction.LONG_CLICK)
+ )
+ QSTileStateSubject.assertThat(actualState).isEqualTo(expectedState)
+ }
+
+ @Test
+ fun secondaryLabelCorrectWhenNotInPowerSaveAndUiModeIsUnknownCustomInNightMode() {
+ val inputModel =
+ createModel(
+ nightMode = true,
+ powerSave = false,
+ uiMode = UiModeManager.MODE_NIGHT_CUSTOM,
+ nighModeCustomType = UiModeManager.MODE_NIGHT_CUSTOM_TYPE_UNKNOWN
+ )
+
+ val actualState: QSTileState = mapper.map(qsTileConfig, inputModel)
+
+ val expectedSecondaryLabel = context.resources.getStringArray(R.array.tile_states_dark)[2]
+ val expectedLabel = context.getString(R.string.quick_settings_ui_mode_night_label)
+ val expectedState =
+ createUiNightModeTileState(
+ iconRes = R.drawable.qs_light_dark_theme_icon_on,
+ label = expectedLabel,
+ secondaryLabel = expectedSecondaryLabel,
+ activationState = QSTileState.ActivationState.ACTIVE,
+ contentDescription = expectedLabel,
+ supportedActions =
+ setOf(QSTileState.UserAction.CLICK, QSTileState.UserAction.LONG_CLICK)
+ )
+ QSTileStateSubject.assertThat(actualState).isEqualTo(expectedState)
+ }
+
+ @Test
+ fun secondaryLabelCorrectWhenInPowerSaveAndUiModeIsUnknownCustomNotInNightMode() {
+ val inputModel =
+ createModel(
+ nightMode = false,
+ powerSave = true,
+ uiMode = UiModeManager.MODE_NIGHT_CUSTOM,
+ nighModeCustomType = UiModeManager.MODE_NIGHT_CUSTOM_TYPE_UNKNOWN
+ )
+
+ val actualState: QSTileState = mapper.map(qsTileConfig, inputModel)
+
+ val expectedSecondaryLabel =
+ context.getString(R.string.quick_settings_dark_mode_secondary_label_battery_saver)
+ val expectedLabel = context.getString(R.string.quick_settings_ui_mode_night_label)
+ val expectedContentDescription =
+ TextUtils.concat(expectedLabel, ", ", expectedSecondaryLabel)
+ val expectedState =
+ createUiNightModeTileState(
+ iconRes = R.drawable.qs_light_dark_theme_icon_off,
+ label = expectedLabel,
+ secondaryLabel = expectedSecondaryLabel,
+ activationState = QSTileState.ActivationState.UNAVAILABLE,
+ contentDescription = expectedContentDescription,
+ supportedActions = setOf(QSTileState.UserAction.LONG_CLICK)
+ )
+ QSTileStateSubject.assertThat(actualState).isEqualTo(expectedState)
+ }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/uimodenight/domain/UiModeNightTileUserActionInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/uimodenight/domain/UiModeNightTileUserActionInteractorTest.kt
new file mode 100644
index 0000000..004ec62
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/uimodenight/domain/UiModeNightTileUserActionInteractorTest.kt
@@ -0,0 +1,125 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.qs.tiles.impl.uimodenight.domain
+
+import android.app.UiModeManager
+import android.provider.Settings
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.qs.tiles.base.actions.FakeQSTileIntentUserInputHandler
+import com.android.systemui.qs.tiles.base.actions.intentInputs
+import com.android.systemui.qs.tiles.base.interactor.QSTileInputTestKtx
+import com.android.systemui.qs.tiles.impl.uimodenight.UiModeNightTileModelHelper.createModel
+import com.android.systemui.qs.tiles.impl.uimodenight.domain.interactor.UiModeNightTileUserActionInteractor
+import com.android.systemui.util.mockito.any
+import com.android.systemui.util.mockito.mock
+import com.google.common.truth.Truth
+import kotlin.coroutines.EmptyCoroutineContext
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.Mockito.never
+import org.mockito.Mockito.verify
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class UiModeNightTileUserActionInteractorTest : SysuiTestCase() {
+
+ private val qsTileIntentUserActionHandler = FakeQSTileIntentUserInputHandler()
+
+ private lateinit var underTest: UiModeNightTileUserActionInteractor
+
+ @Mock private lateinit var uiModeManager: UiModeManager
+
+ @Before
+ fun setup() {
+ uiModeManager = mock<UiModeManager>()
+ underTest =
+ UiModeNightTileUserActionInteractor(
+ EmptyCoroutineContext,
+ uiModeManager,
+ qsTileIntentUserActionHandler
+ )
+ }
+
+ @Test
+ fun handleClickToEnable() = runTest {
+ val stateBeforeClick = false
+
+ underTest.handleInput(QSTileInputTestKtx.click(createModel(stateBeforeClick)))
+
+ verify(uiModeManager).setNightModeActivated(!stateBeforeClick)
+ }
+
+ @Test
+ fun handleClickToDisable() = runTest {
+ val stateBeforeClick = true
+
+ underTest.handleInput(QSTileInputTestKtx.click(createModel(stateBeforeClick)))
+
+ verify(uiModeManager).setNightModeActivated(!stateBeforeClick)
+ }
+
+ @Test
+ fun clickToEnableDoesNothingWhenInPowerSaveInNightMode() = runTest {
+ val isNightMode = true
+ val isPowerSave = true
+
+ underTest.handleInput(QSTileInputTestKtx.click(createModel(isNightMode, isPowerSave)))
+
+ verify(uiModeManager, never()).setNightModeActivated(any())
+ }
+
+ @Test
+ fun clickToEnableDoesNothingWhenInPowerSaveNotInNightMode() = runTest {
+ val isNightMode = false
+ val isPowerSave = true
+
+ underTest.handleInput(QSTileInputTestKtx.click(createModel(isNightMode, isPowerSave)))
+
+ verify(uiModeManager, never()).setNightModeActivated(any())
+ }
+
+ @Test
+ fun handleLongClickNightModeEnabled() = runTest {
+ val isNightMode = true
+
+ underTest.handleInput(QSTileInputTestKtx.longClick(createModel(isNightMode)))
+
+ Truth.assertThat(qsTileIntentUserActionHandler.handledInputs).hasSize(1)
+ val intentInput = qsTileIntentUserActionHandler.intentInputs.last()
+ val actualIntentAction = intentInput.intent.action
+ val expectedIntentAction = Settings.ACTION_DARK_THEME_SETTINGS
+ Truth.assertThat(actualIntentAction).isEqualTo(expectedIntentAction)
+ }
+
+ @Test
+ fun handleLongClickNightModeDisabled() = runTest {
+ val isNightMode = false
+
+ underTest.handleInput(QSTileInputTestKtx.longClick(createModel(isNightMode)))
+
+ Truth.assertThat(qsTileIntentUserActionHandler.handledInputs).hasSize(1)
+ val intentInput = qsTileIntentUserActionHandler.intentInputs.last()
+ val actualIntentAction = intentInput.intent.action
+ val expectedIntentAction = Settings.ACTION_DARK_THEME_SETTINGS
+ Truth.assertThat(actualIntentAction).isEqualTo(expectedIntentAction)
+ }
+}
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSTile.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSTile.java
index 06e9b10..5d85fba 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSTile.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSTile.java
@@ -174,7 +174,7 @@
public String spec;
/** Get the state text. */
- public String getStateText(int arrayResId, Resources resources) {
+ public CharSequence getStateText(int arrayResId, Resources resources) {
if (state == Tile.STATE_UNAVAILABLE || this instanceof QSTile.BooleanState) {
String[] array = resources.getStringArray(arrayResId);
return array[state];
@@ -184,13 +184,13 @@
}
/** Get the text for secondaryLabel. */
- public String getSecondaryLabel(String stateText) {
+ public CharSequence getSecondaryLabel(CharSequence stateText) {
// Use a local reference as the value might change from other threads
CharSequence localSecondaryLabel = secondaryLabel;
if (TextUtils.isEmpty(localSecondaryLabel)) {
return stateText;
}
- return localSecondaryLabel.toString();
+ return localSecondaryLabel;
}
public boolean copyTo(State other) {
diff --git a/packages/SystemUI/res-keyguard/drawable/bouncer_password_text_view_focused_background.xml b/packages/SystemUI/res-keyguard/drawable/bouncer_password_text_view_focused_background.xml
new file mode 100644
index 0000000..02e10cd
--- /dev/null
+++ b/packages/SystemUI/res-keyguard/drawable/bouncer_password_text_view_focused_background.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2023 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:state_focused="true">
+ <shape android:shape="rectangle">
+ <corners android:radius="16dp" />
+ <stroke android:width="3dp"
+ android:color="@color/bouncer_password_focus_color" />
+ </shape>
+ </item>
+</selector>
\ No newline at end of file
diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_bouncer_message_area.xml b/packages/SystemUI/res-keyguard/layout/keyguard_bouncer_message_area.xml
index 66c54f2..0b35559 100644
--- a/packages/SystemUI/res-keyguard/layout/keyguard_bouncer_message_area.xml
+++ b/packages/SystemUI/res-keyguard/layout/keyguard_bouncer_message_area.xml
@@ -23,7 +23,7 @@
android:layout_marginTop="@dimen/keyguard_lock_padding"
android:importantForAccessibility="no"
android:ellipsize="marquee"
- android:focusable="true"
+ android:focusable="false"
android:gravity="center"
android:singleLine="true" />
</merge>
diff --git a/packages/SystemUI/res-keyguard/values/styles.xml b/packages/SystemUI/res-keyguard/values/styles.xml
index 88f7bcd..6e6709f 100644
--- a/packages/SystemUI/res-keyguard/values/styles.xml
+++ b/packages/SystemUI/res-keyguard/values/styles.xml
@@ -76,6 +76,7 @@
</style>
<style name="Widget.TextView.Password" parent="@android:style/Widget.TextView">
<item name="android:fontFamily">@*android:string/config_headlineFontFamily</item>
+ <item name="android:background">@drawable/bouncer_password_text_view_focused_background</item>
<item name="android:gravity">center</item>
<item name="android:textColor">?android:attr/textColorPrimary</item>
</style>
diff --git a/packages/SystemUI/res/layout/connected_display_dialog.xml b/packages/SystemUI/res/layout/connected_display_dialog.xml
index 3f65aa7..8d7f7eb 100644
--- a/packages/SystemUI/res/layout/connected_display_dialog.xml
+++ b/packages/SystemUI/res/layout/connected_display_dialog.xml
@@ -45,6 +45,15 @@
android:text="@string/connected_display_dialog_start_mirroring"
android:textAppearance="@style/TextAppearance.Dialog.Title" />
+ <TextView
+ android:id="@+id/dual_display_warning"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:gravity="center"
+ android:visibility="gone"
+ android:text="@string/connected_display_dialog_dual_display_stop_warning"
+ android:textAppearance="@style/TextAppearance.Dialog.Body" />
+
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
diff --git a/packages/SystemUI/res/layout/screen_record_options.xml b/packages/SystemUI/res/layout/screen_record_options.xml
index 8916e42..fa345c9 100644
--- a/packages/SystemUI/res/layout/screen_record_options.xml
+++ b/packages/SystemUI/res/layout/screen_record_options.xml
@@ -40,16 +40,22 @@
android:popupBackground="@drawable/screenrecord_spinner_background"
android:dropDownWidth="274dp"
android:importantForAccessibility="yes"/>
- <Switch
+ <FrameLayout
+ android:id="@+id/screenrecord_audio_switch_container"
android:layout_width="wrap_content"
- android:minWidth="48dp"
- android:layout_height="48dp"
- android:layout_weight="0"
- android:layout_gravity="end"
- android:id="@+id/screenrecord_audio_switch"
- android:contentDescription="@string/screenrecord_audio_label"
- style="@style/ScreenRecord.Switch"
- android:importantForAccessibility="yes"/>
+ android:layout_height="wrap_content">
+ <Switch
+ android:layout_width="wrap_content"
+ android:minWidth="48dp"
+ android:layout_height="48dp"
+ android:layout_gravity="end"
+ android:focusable="false"
+ android:clickable="false"
+ android:id="@+id/screenrecord_audio_switch"
+ android:contentDescription="@string/screenrecord_audio_label"
+ style="@style/ScreenRecord.Switch"
+ android:importantForAccessibility="yes"/>
+ </FrameLayout>
</LinearLayout>
<LinearLayout
android:id="@+id/show_taps"
@@ -75,13 +81,20 @@
android:fontFamily="@*android:string/config_bodyFontFamily"
android:textColor="?android:attr/textColorPrimary"
android:contentDescription="@string/screenrecord_taps_label"/>
- <Switch
+ <FrameLayout
+ android:id="@+id/screenrecord_taps_switch_container"
android:layout_width="wrap_content"
- android:minWidth="48dp"
- android:layout_height="48dp"
- android:id="@+id/screenrecord_taps_switch"
- android:contentDescription="@string/screenrecord_taps_label"
- style="@style/ScreenRecord.Switch"
- android:importantForAccessibility="yes"/>
+ android:layout_height="wrap_content">
+ <Switch
+ android:layout_width="wrap_content"
+ android:minWidth="48dp"
+ android:layout_height="48dp"
+ android:focusable="false"
+ android:clickable="false"
+ android:id="@+id/screenrecord_taps_switch"
+ android:contentDescription="@string/screenrecord_taps_label"
+ style="@style/ScreenRecord.Switch"
+ android:importantForAccessibility="yes"/>
+ </FrameLayout>
</LinearLayout>
</LinearLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/udfps_touch_overlay.xml b/packages/SystemUI/res/layout/udfps_touch_overlay.xml
index ea92776..498d59b 100644
--- a/packages/SystemUI/res/layout/udfps_touch_overlay.xml
+++ b/packages/SystemUI/res/layout/udfps_touch_overlay.xml
@@ -17,6 +17,5 @@
<com.android.systemui.biometrics.ui.view.UdfpsTouchOverlay xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/udfps_touch_overlay"
android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:contentDescription="@string/accessibility_fingerprint_label">
+ android:layout_height="match_parent">
</com.android.systemui.biometrics.ui.view.UdfpsTouchOverlay>
diff --git a/packages/SystemUI/res/values-night/colors.xml b/packages/SystemUI/res/values-night/colors.xml
index bcc3c83..a22fd18 100644
--- a/packages/SystemUI/res/values-night/colors.xml
+++ b/packages/SystemUI/res/values-night/colors.xml
@@ -93,6 +93,9 @@
<color name="qs_user_switcher_selected_avatar_icon_color">#202124</color>
<!-- Color of background circle of user avatars in quick settings user switcher -->
<color name="qs_user_switcher_avatar_background">#3C4043</color>
+ <!-- Color of border for keyguard password input when focused -->
+ <color name="bouncer_password_focus_color">@*android:color/system_secondary_dark</color>
+
<!-- Accessibility floating menu -->
<color name="accessibility_floating_menu_background">#B3000000</color> <!-- 70% -->
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index 5f6a39a..462fc95 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -56,6 +56,8 @@
<color name="kg_user_switcher_restricted_avatar_icon_color">@color/GM2_grey_600</color>
<!-- Color of background circle of user avatars in keyguard user switcher -->
<color name="user_avatar_color_bg">?android:attr/colorBackgroundFloating</color>
+ <!-- Color of border for keyguard password input when focused -->
+ <color name="bouncer_password_focus_color">@*android:color/system_secondary_light</color>
<!-- Icon color for user avatars in user switcher quick settings -->
<color name="qs_user_switcher_avatar_icon_color">#3C4043</color>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index f49d2a1..7ca0b6e 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -3245,6 +3245,8 @@
<!--- Title of the dialog appearing when an external display is connected, asking whether to start mirroring [CHAR LIMIT=NONE]-->
<string name="connected_display_dialog_start_mirroring">Mirror to external display?</string>
+ <!--- Body of the mirroring dialog, shown when dual display is enabled. This signals that enabling mirroring will stop concurrent displays on a foldable device. [CHAR LIMIT=NONE]-->
+ <string name="connected_display_dialog_dual_display_stop_warning">Any dual screen activity currently running will be stopped</string>
<!--- Label of the "enable display" button of the dialog appearing when an external display is connected [CHAR LIMIT=NONE]-->
<string name="mirror_display">Mirror display</string>
<!--- Label of the dismiss button of the dialog appearing when an external display is connected [CHAR LIMIT=NONE]-->
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputView.java
index 36fe75f..9764de1 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputView.java
@@ -168,7 +168,6 @@
// Set selected property on so the view can send accessibility events.
mPasswordEntry.setSelected(true);
- mPasswordEntry.setDefaultFocusHighlightEnabled(false);
mOkButton = findViewById(R.id.key_enter);
diff --git a/packages/SystemUI/src/com/android/systemui/authentication/data/repository/AuthenticationRepository.kt b/packages/SystemUI/src/com/android/systemui/authentication/data/repository/AuthenticationRepository.kt
index 341d214..dd4ca92 100644
--- a/packages/SystemUI/src/com/android/systemui/authentication/data/repository/AuthenticationRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/authentication/data/repository/AuthenticationRepository.kt
@@ -21,7 +21,6 @@
import android.app.admin.DevicePolicyManager
import android.content.IntentFilter
import android.os.UserHandle
-import com.android.internal.widget.LockPatternChecker
import com.android.internal.widget.LockPatternUtils
import com.android.internal.widget.LockscreenCredential
import com.android.keyguard.KeyguardSecurityModel
@@ -40,8 +39,6 @@
import dagger.Module
import java.util.function.Function
import javax.inject.Inject
-import kotlin.coroutines.resume
-import kotlin.coroutines.suspendCoroutine
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.ExperimentalCoroutinesApi
@@ -193,8 +190,8 @@
override val throttling: MutableStateFlow<AuthenticationThrottlingModel?> =
MutableStateFlow(null)
- private val UserRepository.selectedUserId: Int
- get() = getSelectedUserInfo().id
+ private val selectedUserId: Int
+ get() = userRepository.getSelectedUserInfo().id
override val authenticationMethod: Flow<AuthenticationMethodModel> =
combine(userRepository.selectedUserInfo, mobileConnectionsRepository.isAnySimSecure) {
@@ -233,19 +230,15 @@
override suspend fun getAuthenticationMethod(): AuthenticationMethodModel {
return withContext(backgroundDispatcher) {
- blockingAuthenticationMethodInternal(userRepository.selectedUserId)
+ blockingAuthenticationMethodInternal(selectedUserId)
}
}
override suspend fun getPinLength(): Int {
- return withContext(backgroundDispatcher) {
- val selectedUserId = userRepository.selectedUserId
- lockPatternUtils.getPinLength(selectedUserId)
- }
+ return withContext(backgroundDispatcher) { lockPatternUtils.getPinLength(selectedUserId) }
}
override suspend fun reportAuthenticationAttempt(isSuccessful: Boolean) {
- val selectedUserId = userRepository.selectedUserId
withContext(backgroundDispatcher) {
if (isSuccessful) {
lockPatternUtils.reportSuccessfulPasswordAttempt(selectedUserId)
@@ -258,52 +251,32 @@
override suspend fun getFailedAuthenticationAttemptCount(): Int {
return withContext(backgroundDispatcher) {
- val selectedUserId = userRepository.selectedUserId
lockPatternUtils.getCurrentFailedPasswordAttempts(selectedUserId)
}
}
override suspend fun getThrottlingEndTimestamp(): Long {
return withContext(backgroundDispatcher) {
- val selectedUserId = userRepository.selectedUserId
lockPatternUtils.getLockoutAttemptDeadline(selectedUserId)
}
}
override suspend fun setThrottleDuration(durationMs: Int) {
withContext(backgroundDispatcher) {
- lockPatternUtils.setLockoutAttemptDeadline(
- userRepository.selectedUserId,
- durationMs,
- )
+ lockPatternUtils.setLockoutAttemptDeadline(selectedUserId, durationMs)
}
}
override suspend fun checkCredential(
credential: LockscreenCredential
): AuthenticationResultModel {
- return suspendCoroutine { continuation ->
- LockPatternChecker.checkCredential(
- lockPatternUtils,
- credential,
- userRepository.selectedUserId,
- object : LockPatternChecker.OnCheckCallback {
- override fun onChecked(matched: Boolean, throttleTimeoutMs: Int) {
- continuation.resume(
- AuthenticationResultModel(
- isSuccessful = matched,
- throttleDurationMs = throttleTimeoutMs,
- )
- )
- }
-
- override fun onCancelled() {
- continuation.resume(AuthenticationResultModel(isSuccessful = false))
- }
-
- override fun onEarlyMatched() = Unit
- }
- )
+ return withContext(backgroundDispatcher) {
+ try {
+ val matched = lockPatternUtils.checkCredential(credential, selectedUserId) {}
+ AuthenticationResultModel(isSuccessful = matched, throttleDurationMs = 0)
+ } catch (ex: LockPatternUtils.RequestThrottledException) {
+ AuthenticationResultModel(isSuccessful = false, throttleDurationMs = ex.timeoutMs)
+ }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/battery/BatteryMeterView.java b/packages/SystemUI/src/com/android/systemui/battery/BatteryMeterView.java
index b1a153a..24cd9b5 100644
--- a/packages/SystemUI/src/com/android/systemui/battery/BatteryMeterView.java
+++ b/packages/SystemUI/src/com/android/systemui/battery/BatteryMeterView.java
@@ -66,6 +66,8 @@
public static final int MODE_ON = 1;
public static final int MODE_OFF = 2;
public static final int MODE_ESTIMATE = 3;
+ @VisibleForTesting
+ public static final long LAYOUT_TRANSITION_DURATION = 200;
private final AccessorizedBatteryDrawable mDrawable;
private final ImageView mBatteryIconView;
@@ -134,7 +136,7 @@
private void setupLayoutTransition() {
LayoutTransition transition = new LayoutTransition();
- transition.setDuration(200);
+ transition.setDuration(LAYOUT_TRANSITION_DURATION);
// Animates appearing/disappearing of the battery percentage text using fade-in/fade-out
// and disables all other animation types
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/data/repository/DisplayStateRepository.kt b/packages/SystemUI/src/com/android/systemui/biometrics/data/repository/DisplayStateRepository.kt
index ff23837..b0143f5 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/data/repository/DisplayStateRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/data/repository/DisplayStateRepository.kt
@@ -60,6 +60,8 @@
val currentRotation: StateFlow<DisplayRotation>
}
+// TODO(b/296211844): This class could directly use DeviceStateRepository and DisplayRepository
+// instead.
@SysUISingleton
class DisplayStateRepositoryImpl
@Inject
diff --git a/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/BaseCommunalViewModel.kt b/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/BaseCommunalViewModel.kt
index bed4283..333fc19 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/BaseCommunalViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/BaseCommunalViewModel.kt
@@ -24,13 +24,14 @@
import com.android.systemui.communal.shared.model.CommunalSceneKey
import com.android.systemui.media.controls.ui.MediaHost
import com.android.systemui.shade.ShadeViewController
+import javax.inject.Provider
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.StateFlow
/** The base view model for the communal hub. */
abstract class BaseCommunalViewModel(
private val communalInteractor: CommunalInteractor,
- private val shadeViewController: ShadeViewController,
+ private val shadeViewController: Provider<ShadeViewController>,
private val powerManager: PowerManager,
val mediaHost: MediaHost,
) {
@@ -48,7 +49,7 @@
fun onOuterTouch(motionEvent: MotionEvent) {
// Forward the touch to the shade so that basic gestures like swipe up/down for
// shade/bouncer work.
- shadeViewController.handleExternalTouch(motionEvent)
+ shadeViewController.get().handleExternalTouch(motionEvent)
}
// TODO(b/308813166): remove once CommunalContainer is moved lower in z-order and doesn't block
diff --git a/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalEditModeViewModel.kt b/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalEditModeViewModel.kt
index b6843c5..c82e000 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalEditModeViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalEditModeViewModel.kt
@@ -25,6 +25,7 @@
import com.android.systemui.shade.ShadeViewController
import javax.inject.Inject
import javax.inject.Named
+import javax.inject.Provider
import kotlinx.coroutines.flow.Flow
/** The view model for communal hub in edit mode. */
@@ -33,7 +34,7 @@
@Inject
constructor(
private val communalInteractor: CommunalInteractor,
- shadeViewController: ShadeViewController,
+ shadeViewController: Provider<ShadeViewController>,
powerManager: PowerManager,
@Named(MediaModule.COMMUNAL_HUB) mediaHost: MediaHost,
) : BaseCommunalViewModel(communalInteractor, shadeViewController, powerManager, mediaHost) {
diff --git a/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalViewModel.kt b/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalViewModel.kt
index d7dcdb9..abf1986 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalViewModel.kt
@@ -26,6 +26,7 @@
import com.android.systemui.shade.ShadeViewController
import javax.inject.Inject
import javax.inject.Named
+import javax.inject.Provider
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.combine
@@ -39,7 +40,7 @@
constructor(
private val communalInteractor: CommunalInteractor,
tutorialInteractor: CommunalTutorialInteractor,
- shadeViewController: ShadeViewController,
+ shadeViewController: Provider<ShadeViewController>,
powerManager: PowerManager,
@Named(MediaModule.COMMUNAL_HUB) mediaHost: MediaHost,
) : BaseCommunalViewModel(communalInteractor, shadeViewController, powerManager, mediaHost) {
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java b/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java
index 9672fac..e7b8773 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java
@@ -36,6 +36,8 @@
import com.android.systemui.unfold.FoldStateLoggingProvider;
import com.android.systemui.unfold.SysUIUnfoldComponent;
import com.android.systemui.unfold.UnfoldTransitionProgressProvider;
+import com.android.systemui.unfold.dagger.UnfoldBg;
+import com.android.systemui.unfold.progress.UnfoldTransitionProgressForwarder;
import com.android.wm.shell.back.BackAnimation;
import com.android.wm.shell.bubbles.Bubbles;
import com.android.wm.shell.desktopmode.DesktopMode;
@@ -137,19 +139,26 @@
c.getUnfoldHapticsPlayer();
c.getNaturalRotationUnfoldProgressProvider().init();
c.getUnfoldLatencyTracker().init();
- c.getFoldStateLoggingProvider()
- .ifPresent(FoldStateLoggingProvider::init);
- c.getFoldStateLogger().ifPresent(FoldStateLogger::init);
- final UnfoldTransitionProgressProvider progressProvider =
- Flags.unfoldAnimationBackgroundProgress()
- ? c.getBgUnfoldTransitionProgressProvider()
- : c.getUnfoldTransitionProgressProvider();
- progressProvider.addCallback(c.getUnfoldTransitionProgressForwarder());
});
// No init method needed, just needs to be gotten so that it's created.
getMediaMuteAwaitConnectionCli();
getNearbyMediaDevicesManager();
getConnectingDisplayViewModel().init();
+ getFoldStateLoggingProvider().ifPresent(FoldStateLoggingProvider::init);
+ getFoldStateLogger().ifPresent(FoldStateLogger::init);
+
+ Optional<UnfoldTransitionProgressProvider> unfoldTransitionProgressProvider;
+
+ if (Flags.unfoldAnimationBackgroundProgress()) {
+ unfoldTransitionProgressProvider = getBgUnfoldTransitionProgressProvider();
+ } else {
+ unfoldTransitionProgressProvider = getUnfoldTransitionProgressProvider();
+ }
+ unfoldTransitionProgressProvider
+ .ifPresent(
+ (progressProvider) ->
+ getUnfoldTransitionProgressForwarder()
+ .ifPresent(progressProvider::addCallback));
}
/**
@@ -171,6 +180,37 @@
ContextComponentHelper getContextComponentHelper();
/**
+ * Creates a UnfoldTransitionProgressProvider that calculates progress in the background.
+ */
+ @SysUISingleton
+ @UnfoldBg
+ Optional<UnfoldTransitionProgressProvider> getBgUnfoldTransitionProgressProvider();
+
+ /**
+ * Creates a UnfoldTransitionProgressProvider that calculates progress in the main thread.
+ */
+ @SysUISingleton
+ Optional<UnfoldTransitionProgressProvider> getUnfoldTransitionProgressProvider();
+
+ /**
+ * Creates a UnfoldTransitionProgressForwarder.
+ */
+ @SysUISingleton
+ Optional<UnfoldTransitionProgressForwarder> getUnfoldTransitionProgressForwarder();
+
+ /**
+ * Creates a FoldStateLoggingProvider.
+ */
+ @SysUISingleton
+ Optional<FoldStateLoggingProvider> getFoldStateLoggingProvider();
+
+ /**
+ * Creates a FoldStateLogger.
+ */
+ @SysUISingleton
+ Optional<FoldStateLogger> getFoldStateLogger();
+
+ /**
* Main dependency providing module.
*/
@SysUISingleton
diff --git a/packages/SystemUI/src/com/android/systemui/display/DisplayModule.kt b/packages/SystemUI/src/com/android/systemui/display/DisplayModule.kt
index 65cd84b..373279c 100644
--- a/packages/SystemUI/src/com/android/systemui/display/DisplayModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/display/DisplayModule.kt
@@ -16,6 +16,8 @@
package com.android.systemui.display
+import com.android.systemui.display.data.repository.DeviceStateRepository
+import com.android.systemui.display.data.repository.DeviceStateRepositoryImpl
import com.android.systemui.display.data.repository.DisplayRepository
import com.android.systemui.display.data.repository.DisplayRepositoryImpl
import com.android.systemui.display.domain.interactor.ConnectedDisplayInteractor
@@ -32,4 +34,9 @@
): ConnectedDisplayInteractor
@Binds fun bindsDisplayRepository(displayRepository: DisplayRepositoryImpl): DisplayRepository
+
+ @Binds
+ fun bindsDeviceStateRepository(
+ deviceStateRepository: DeviceStateRepositoryImpl
+ ): DeviceStateRepository
}
diff --git a/packages/SystemUI/src/com/android/systemui/display/data/repository/DeviceStateRepository.kt b/packages/SystemUI/src/com/android/systemui/display/data/repository/DeviceStateRepository.kt
new file mode 100644
index 0000000..83337f7
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/display/data/repository/DeviceStateRepository.kt
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.display.data.repository
+
+import android.content.Context
+import android.hardware.devicestate.DeviceStateManager
+import com.android.internal.R
+import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
+import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.display.data.repository.DeviceStateRepository.DeviceState
+import java.util.concurrent.Executor
+import javax.inject.Inject
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.channels.awaitClose
+import kotlinx.coroutines.flow.SharingStarted
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.stateIn
+
+interface DeviceStateRepository {
+ val state: StateFlow<DeviceState>
+
+ enum class DeviceState {
+ /** Device state in [R.array.config_foldedDeviceStates] */
+ FOLDED,
+ /** Device state in [R.array.config_halfFoldedDeviceStates] */
+ HALF_FOLDED,
+ /** Device state in [R.array.config_openDeviceStates] */
+ UNFOLDED,
+ /** Device state in [R.array.config_rearDisplayDeviceStates] */
+ REAR_DISPLAY,
+ /** Device state in [R.array.config_concurrentDisplayDeviceStates] */
+ CONCURRENT_DISPLAY,
+ /** Device state in none of the other arrays. */
+ UNKNOWN,
+ }
+}
+
+class DeviceStateRepositoryImpl
+@Inject
+constructor(
+ context: Context,
+ deviceStateManager: DeviceStateManager,
+ @Background bgScope: CoroutineScope,
+ @Background executor: Executor
+) : DeviceStateRepository {
+
+ override val state: StateFlow<DeviceState> =
+ conflatedCallbackFlow {
+ val callback =
+ DeviceStateManager.DeviceStateCallback { state ->
+ trySend(deviceStateToPosture(state))
+ }
+ deviceStateManager.registerCallback(executor, callback)
+ awaitClose { deviceStateManager.unregisterCallback(callback) }
+ }
+ .stateIn(bgScope, started = SharingStarted.WhileSubscribed(), DeviceState.UNKNOWN)
+
+ private fun deviceStateToPosture(deviceStateId: Int): DeviceState {
+ return deviceStateMap.firstOrNull { (ids, _) -> deviceStateId in ids }?.deviceState
+ ?: DeviceState.UNKNOWN
+ }
+
+ private val deviceStateMap =
+ listOf(
+ R.array.config_foldedDeviceStates to DeviceState.FOLDED,
+ R.array.config_halfFoldedDeviceStates to DeviceState.HALF_FOLDED,
+ R.array.config_openDeviceStates to DeviceState.UNFOLDED,
+ R.array.config_rearDisplayDeviceStates to DeviceState.REAR_DISPLAY,
+ R.array.config_concurrentDisplayDeviceStates to DeviceState.CONCURRENT_DISPLAY,
+ )
+ .map { IdsPerDeviceState(context.resources.getIntArray(it.first).toSet(), it.second) }
+
+ private data class IdsPerDeviceState(val ids: Set<Int>, val deviceState: DeviceState)
+}
diff --git a/packages/SystemUI/src/com/android/systemui/display/domain/interactor/ConnectedDisplayInteractor.kt b/packages/SystemUI/src/com/android/systemui/display/domain/interactor/ConnectedDisplayInteractor.kt
index 20a9e5d..73b7a8a 100644
--- a/packages/SystemUI/src/com/android/systemui/display/domain/interactor/ConnectedDisplayInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/display/domain/interactor/ConnectedDisplayInteractor.kt
@@ -21,6 +21,7 @@
import android.view.Display
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.display.data.repository.DeviceStateRepository
import com.android.systemui.display.data.repository.DisplayRepository
import com.android.systemui.display.domain.interactor.ConnectedDisplayInteractor.PendingDisplay
import com.android.systemui.display.domain.interactor.ConnectedDisplayInteractor.State
@@ -55,6 +56,9 @@
/** Pending display that can be enabled to be used by the system. */
val pendingDisplay: Flow<PendingDisplay?>
+ /** Pending display that can be enabled to be used by the system. */
+ val concurrentDisplaysInProgress: Flow<Boolean>
+
/** Possible connected display state. */
enum class State {
DISCONNECTED,
@@ -84,6 +88,7 @@
private val virtualDeviceManager: VirtualDeviceManager,
keyguardRepository: KeyguardRepository,
displayRepository: DisplayRepository,
+ deviceStateRepository: DeviceStateRepository,
@Background backgroundCoroutineDispatcher: CoroutineDispatcher,
) : ConnectedDisplayInteractor {
@@ -128,9 +133,16 @@
}
}
+ override val concurrentDisplaysInProgress: Flow<Boolean> =
+ deviceStateRepository.state
+ .map { it == DeviceStateRepository.DeviceState.CONCURRENT_DISPLAY }
+ .distinctUntilChanged()
+ .flowOn(backgroundCoroutineDispatcher)
+
private fun DisplayRepository.PendingDisplay.toInteractorPendingDisplay(): PendingDisplay =
object : PendingDisplay {
override suspend fun enable() = this@toInteractorPendingDisplay.enable()
+
override suspend fun ignore() = this@toInteractorPendingDisplay.ignore()
}
diff --git a/packages/SystemUI/src/com/android/systemui/display/ui/view/MirroringConfirmationDialog.kt b/packages/SystemUI/src/com/android/systemui/display/ui/view/MirroringConfirmationDialog.kt
index d500d1c2..c0a873a 100644
--- a/packages/SystemUI/src/com/android/systemui/display/ui/view/MirroringConfirmationDialog.kt
+++ b/packages/SystemUI/src/com/android/systemui/display/ui/view/MirroringConfirmationDialog.kt
@@ -37,11 +37,13 @@
private val onCancelMirroring: View.OnClickListener,
private val navbarBottomInsetsProvider: () -> Int,
configurationController: ConfigurationController? = null,
+ private val showConcurrentDisplayInfo: Boolean = false,
theme: Int = R.style.Theme_SystemUI_Dialog,
) : SystemUIBottomSheetDialog(context, configurationController, theme) {
private lateinit var mirrorButton: TextView
private lateinit var dismissButton: TextView
+ private lateinit var dualDisplayWarning: TextView
private var enabledPressed = false
override fun onCreate(savedInstanceState: Bundle?) {
@@ -56,6 +58,11 @@
dismissButton =
requireViewById<TextView>(R.id.cancel).apply { setOnClickListener(onCancelMirroring) }
+ dualDisplayWarning =
+ requireViewById<TextView>(R.id.dual_display_warning).apply {
+ visibility = if (showConcurrentDisplayInfo) View.VISIBLE else View.GONE
+ }
+
setOnDismissListener {
if (!enabledPressed) {
onCancelMirroring.onClick(null)
diff --git a/packages/SystemUI/src/com/android/systemui/display/ui/viewmodel/ConnectingDisplayViewModel.kt b/packages/SystemUI/src/com/android/systemui/display/ui/viewmodel/ConnectingDisplayViewModel.kt
index 19b4d22..10aa703 100644
--- a/packages/SystemUI/src/com/android/systemui/display/ui/viewmodel/ConnectingDisplayViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/display/ui/viewmodel/ConnectingDisplayViewModel.kt
@@ -17,6 +17,7 @@
import android.app.Dialog
import android.content.Context
+import com.android.server.policy.feature.flags.Flags
import com.android.systemui.biometrics.Utils
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
@@ -28,8 +29,9 @@
import javax.inject.Inject
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.launchIn
-import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.launch
/**
@@ -44,25 +46,33 @@
private val connectedDisplayInteractor: ConnectedDisplayInteractor,
@Application private val scope: CoroutineScope,
@Background private val bgDispatcher: CoroutineDispatcher,
- private val configurationController: ConfigurationController
+ private val configurationController: ConfigurationController,
) {
private var dialog: Dialog? = null
/** Starts listening for pending displays. */
fun init() {
- connectedDisplayInteractor.pendingDisplay
- .onEach { pendingDisplay ->
+ val pendingDisplayFlow = connectedDisplayInteractor.pendingDisplay
+ val concurrentDisplaysInProgessFlow =
+ if (Flags.enableDualDisplayBlocking()) {
+ connectedDisplayInteractor.concurrentDisplaysInProgress
+ } else {
+ flow { emit(false) }
+ }
+ pendingDisplayFlow
+ .combine(concurrentDisplaysInProgessFlow) { pendingDisplay, concurrentDisplaysInProgress
+ ->
if (pendingDisplay == null) {
hideDialog()
} else {
- showDialog(pendingDisplay)
+ showDialog(pendingDisplay, concurrentDisplaysInProgress)
}
}
.launchIn(scope)
}
- private fun showDialog(pendingDisplay: PendingDisplay) {
+ private fun showDialog(pendingDisplay: PendingDisplay, concurrentDisplaysInProgess: Boolean) {
hideDialog()
dialog =
MirroringConfirmationDialog(
@@ -77,6 +87,7 @@
},
navbarBottomInsetsProvider = { Utils.getNavbarInsets(context).bottom },
configurationController,
+ showConcurrentDisplayInfo = concurrentDisplaysInProgess
)
.apply { show() }
}
diff --git a/packages/SystemUI/src/com/android/systemui/dump/LogBufferFreezer.kt b/packages/SystemUI/src/com/android/systemui/dump/LogBufferFreezer.kt
index 29f4642..a97d505 100644
--- a/packages/SystemUI/src/com/android/systemui/dump/LogBufferFreezer.kt
+++ b/packages/SystemUI/src/com/android/systemui/dump/LogBufferFreezer.kt
@@ -20,6 +20,7 @@
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
+import android.os.Trace
import android.os.UserHandle
import android.util.Log
import com.android.systemui.broadcast.BroadcastDispatcher
@@ -53,6 +54,8 @@
}
private fun onBugreportStarted() {
+ Trace.instantForTrack(Trace.TRACE_TAG_APP, "bugreport",
+ "BUGREPORT_STARTED broadcast received")
pendingToken?.run()
Log.i(TAG, "Freezing log buffers")
diff --git a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
index 11d6507..e8ceabf 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
+++ b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
@@ -438,12 +438,6 @@
val LOCKSCREEN_ENABLE_LANDSCAPE =
unreleasedFlag("lockscreen.enable_landscape")
- // TODO(b/281648899): Tracking bug
- @Keep
- @JvmField
- val WALLPAPER_MULTI_CROP =
- sysPropBooleanFlag("persist.wm.debug.wallpaper_multi_crop", default = false)
-
// 1200 - predictive back
@Keep
@JvmField
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java
index 5cc2e0a..45433e6 100644
--- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java
@@ -60,6 +60,7 @@
import android.os.Message;
import android.os.RemoteException;
import android.os.SystemProperties;
+import android.os.Trace;
import android.os.UserHandle;
import android.os.UserManager;
import android.provider.Settings;
@@ -1052,6 +1053,7 @@
if (ActivityManager.isUserAMonkey()) {
return;
}
+ Trace.instantForTrack(Trace.TRACE_TAG_APP, "bugreport", "BugReportAction#onPress");
// Add a little delay before executing, to give the
// dialog a chance to go away before it takes a
// screenshot.
@@ -1065,6 +1067,8 @@
mUiEventLogger.log(GlobalActionsEvent.GA_BUGREPORT_PRESS);
if (!mIActivityManager.launchBugReportHandlerApp()) {
Log.w(TAG, "Bugreport handler could not be launched");
+ Trace.instantForTrack(Trace.TRACE_TAG_APP, "bugreport",
+ "BugReportAction#requestingInteractiveBugReport");
mIActivityManager.requestInteractiveBugReport();
}
} catch (RemoteException e) {
@@ -1084,6 +1088,8 @@
// Take a "full" bugreport.
mMetricsLogger.action(MetricsEvent.ACTION_BUGREPORT_FROM_POWER_MENU_FULL);
mUiEventLogger.log(GlobalActionsEvent.GA_BUGREPORT_LONG_PRESS);
+ Trace.instantForTrack(Trace.TRACE_TAG_APP, "bugreport",
+ "BugReportAction#requestingFullBugReport");
mIActivityManager.requestFullBugReport();
} catch (RemoteException e) {
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewConfigurator.kt b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewConfigurator.kt
index 017dac2..20da00e 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewConfigurator.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewConfigurator.kt
@@ -43,6 +43,7 @@
import com.android.systemui.keyguard.ui.viewmodel.KeyguardIndicationAreaViewModel
import com.android.systemui.keyguard.ui.viewmodel.KeyguardRootViewModel
import com.android.systemui.keyguard.ui.viewmodel.OccludingAppDeviceEntryMessageViewModel
+import com.android.systemui.plugins.FalsingManager
import com.android.systemui.res.R
import com.android.systemui.shade.NotificationShadeWindowView
import com.android.systemui.shade.domain.interactor.ShadeInteractor
@@ -81,6 +82,7 @@
private val interactionJankMonitor: InteractionJankMonitor,
private val deviceEntryHapticsInteractor: DeviceEntryHapticsInteractor,
private val vibratorHelper: VibratorHelper,
+ private val falsingManager: FalsingManager,
) : CoreStartable {
private var rootViewHandle: DisposableHandle? = null
@@ -155,6 +157,7 @@
interactionJankMonitor,
deviceEntryHapticsInteractor,
vibratorHelper,
+ falsingManager,
)
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardBlueprintRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardBlueprintRepository.kt
index fbd62ce..48b6634 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardBlueprintRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardBlueprintRepository.kt
@@ -28,7 +28,7 @@
import javax.inject.Inject
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableSharedFlow
-import kotlinx.coroutines.flow.asSharedFlow
+import kotlinx.coroutines.flow.MutableStateFlow
/**
* Manages blueprint changes for the lockscreen.
@@ -48,17 +48,14 @@
configurationRepository: ConfigurationRepository,
blueprints: Set<@JvmSuppressWildcards KeyguardBlueprint>,
) {
- private val blueprintIdMap: TreeMap<String, KeyguardBlueprint> = TreeMap()
- private val _blueprint: MutableSharedFlow<KeyguardBlueprint> = MutableSharedFlow(replay = 1)
- val blueprint: Flow<KeyguardBlueprint> = _blueprint.asSharedFlow()
-
+ // This is TreeMap so that we can order the blueprints and assign numerical values to the
+ // blueprints in the adb tool.
+ private val blueprintIdMap: TreeMap<String, KeyguardBlueprint> =
+ TreeMap<String, KeyguardBlueprint>().apply { putAll(blueprints.associateBy { it.id }) }
+ val blueprint: MutableStateFlow<KeyguardBlueprint> = MutableStateFlow(blueprintIdMap[DEFAULT]!!)
+ val refreshBluePrint: MutableSharedFlow<Unit> = MutableSharedFlow(extraBufferCapacity = 1)
val configurationChange: Flow<Unit> = configurationRepository.onAnyConfigurationChange
- init {
- blueprintIdMap.putAll(blueprints.associateBy { it.id })
- applyBlueprint(blueprintIdMap[DEFAULT]!!)
- }
-
/**
* Emits the blueprint value to the collectors.
*
@@ -96,14 +93,17 @@
/** Emits the blueprint value to the collectors. */
fun applyBlueprint(blueprint: KeyguardBlueprint?) {
- blueprint?.let { _blueprint.tryEmit(it) }
+ if (blueprint == this.blueprint.value) {
+ refreshBlueprint()
+ return
+ }
+
+ blueprint?.let { this.blueprint.value = it }
}
/** Re-emits the last emitted blueprint value if possible. */
fun refreshBlueprint() {
- if (_blueprint.replayCache.isNotEmpty()) {
- _blueprint.tryEmit(_blueprint.replayCache.last())
- }
+ refreshBluePrint.tryEmit(Unit)
}
/** Prints all available blueprints to the PrintWriter. */
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepository.kt
index 2d6c0e1..b51edab6 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepository.kt
@@ -157,6 +157,9 @@
val lastDozeTapToWakePosition: StateFlow<Point?>
+ /** Last point that [KeyguardRootView] was tapped */
+ val lastRootViewTapPosition: MutableStateFlow<Point?>
+
/** Observable for the [StatusBarState] */
val statusBarState: StateFlow<StatusBarState>
@@ -418,6 +421,8 @@
_lastDozeTapToWakePosition.value = position
}
+ override val lastRootViewTapPosition: MutableStateFlow<Point?> = MutableStateFlow(null)
+
override val isDreamingWithOverlay: Flow<Boolean> =
conflatedCallbackFlow {
val callback =
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardBlueprintInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardBlueprintInteractor.kt
index 7dab84d..ba44e68 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardBlueprintInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardBlueprintInteractor.kt
@@ -21,11 +21,15 @@
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.keyguard.data.repository.KeyguardBlueprintRepository
+import com.android.systemui.keyguard.shared.model.KeyguardBlueprint
import com.android.systemui.keyguard.ui.view.layout.blueprints.DefaultKeyguardBlueprint
import com.android.systemui.keyguard.ui.view.layout.blueprints.SplitShadeKeyguardBlueprint
import com.android.systemui.statusbar.policy.SplitShadeStateController
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.merge
import kotlinx.coroutines.flow.onStart
import kotlinx.coroutines.launch
@@ -39,7 +43,18 @@
private val splitShadeStateController: SplitShadeStateController,
) {
- val blueprint = keyguardBlueprintRepository.blueprint
+ /**
+ * The current blueprint for the lockscreen.
+ *
+ * This flow can also emit the same blueprint value if refreshBlueprint is emitted.
+ */
+ val blueprint: Flow<KeyguardBlueprint> =
+ merge(
+ keyguardBlueprintRepository.blueprint,
+ keyguardBlueprintRepository.refreshBluePrint.map {
+ keyguardBlueprintRepository.blueprint.value
+ }
+ )
init {
applicationScope.launch {
@@ -91,4 +106,8 @@
fun refreshBlueprint() {
keyguardBlueprintRepository.refreshBlueprint()
}
+
+ fun getCurrentBlueprint(): KeyguardBlueprint {
+ return keyguardBlueprintRepository.blueprint.value
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt
index b8c3925..702386d 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt
@@ -171,6 +171,9 @@
/** Whether the keyguard is going away. */
val isKeyguardGoingAway: Flow<Boolean> = repository.isKeyguardGoingAway
+ /** Last point that [KeyguardRootView] view was tapped */
+ val lastRootViewTapPosition: Flow<Point?> = repository.lastRootViewTapPosition.asStateFlow()
+
/** Whether the primary bouncer is showing or not. */
val primaryBouncerShowing: Flow<Boolean> = bouncerRepository.primaryBouncerShow
@@ -304,6 +307,10 @@
repository.setClockShouldBeCentered(shouldBeCentered)
}
+ fun setLastRootViewTapPosition(point: Point?) {
+ repository.lastRootViewTapPosition.value = point
+ }
+
companion object {
private const val TAG = "KeyguardInteractor"
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardRootViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardRootViewBinder.kt
index 02c6f33..e603ead 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardRootViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardRootViewBinder.kt
@@ -19,6 +19,8 @@
import android.animation.Animator
import android.animation.AnimatorListenerAdapter
import android.annotation.DrawableRes
+import android.annotation.SuppressLint
+import android.graphics.Point
import android.view.HapticFeedbackConstants
import android.view.View
import android.view.View.OnLayoutChangeListener
@@ -47,6 +49,7 @@
import com.android.systemui.keyguard.ui.viewmodel.KeyguardRootViewModel
import com.android.systemui.keyguard.ui.viewmodel.OccludingAppDeviceEntryMessageViewModel
import com.android.systemui.lifecycle.repeatWhenAttached
+import com.android.systemui.plugins.FalsingManager
import com.android.systemui.plugins.clocks.ClockController
import com.android.systemui.res.R
import com.android.systemui.shade.domain.interactor.ShadeInteractor
@@ -73,6 +76,7 @@
@OptIn(ExperimentalCoroutinesApi::class)
object KeyguardRootViewBinder {
+ @SuppressLint("ClickableViewAccessibility")
@JvmStatic
fun bind(
view: ViewGroup,
@@ -87,6 +91,7 @@
interactionJankMonitor: InteractionJankMonitor?,
deviceEntryHapticsInteractor: DeviceEntryHapticsInteractor?,
vibratorHelper: VibratorHelper?,
+ falsingManager: FalsingManager?,
): DisposableHandle {
var onLayoutChangeListener: OnLayoutChange? = null
val childViews = mutableMapOf<Int, View>()
@@ -94,6 +99,16 @@
val burnInLayerId = R.id.burn_in_layer
val aodNotificationIconContainerId = R.id.aod_notification_icon_container
val largeClockId = R.id.lockscreen_clock_view_large
+
+ if (keyguardBottomAreaRefactor()) {
+ view.setOnTouchListener { _, event ->
+ if (falsingManager?.isFalseTap(FalsingManager.LOW_PENALTY) == false) {
+ viewModel.setRootViewLastTapPosition(Point(event.x.toInt(), event.y.toInt()))
+ }
+ false
+ }
+ }
+
val disposableHandle =
view.repeatWhenAttached {
repeatOnLifecycle(Lifecycle.State.CREATED) {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardSettingsViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardSettingsViewBinder.kt
index 8514225..11e63e7 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardSettingsViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardSettingsViewBinder.kt
@@ -17,6 +17,7 @@
package com.android.systemui.keyguard.ui.binder
+import android.graphics.Rect
import android.view.View
import androidx.core.view.isVisible
import androidx.lifecycle.Lifecycle
@@ -25,6 +26,8 @@
import com.android.systemui.animation.view.LaunchableLinearLayout
import com.android.systemui.common.ui.binder.IconViewBinder
import com.android.systemui.common.ui.binder.TextViewBinder
+import com.android.systemui.keyguard.ui.viewmodel.KeyguardLongPressViewModel
+import com.android.systemui.keyguard.ui.viewmodel.KeyguardRootViewModel
import com.android.systemui.keyguard.ui.viewmodel.KeyguardSettingsMenuViewModel
import com.android.systemui.keyguard.util.WallpaperPickerIntentUtils
import com.android.systemui.keyguard.util.WallpaperPickerIntentUtils.LAUNCH_SOURCE_KEYGUARD
@@ -35,12 +38,15 @@
import kotlinx.coroutines.DisposableHandle
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.filter
+import kotlinx.coroutines.flow.filterNotNull
import kotlinx.coroutines.launch
object KeyguardSettingsViewBinder {
fun bind(
parentView: View,
viewModel: KeyguardSettingsMenuViewModel,
+ longPressViewModel: KeyguardLongPressViewModel,
+ rootViewModel: KeyguardRootViewModel,
vibratorHelper: VibratorHelper,
activityStarter: ActivityStarter
): DisposableHandle {
@@ -88,6 +94,18 @@
}
}
}
+
+ launch {
+ rootViewModel.lastRootViewTapPosition.filterNotNull().collect { point ->
+ if (view.isVisible) {
+ val hitRect = Rect()
+ view.getHitRect(hitRect)
+ if (!hitRect.contains(point.x, point.y)) {
+ longPressViewModel.onTouchedOutside()
+ }
+ }
+ }
+ }
}
}
return disposableHandle
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/preview/KeyguardPreviewRenderer.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/preview/KeyguardPreviewRenderer.kt
index 4eecfde..03e45fd 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/preview/KeyguardPreviewRenderer.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/preview/KeyguardPreviewRenderer.kt
@@ -376,6 +376,7 @@
null, // jank monitor not required for preview mode
null, // device entry haptics not required preview mode
null, // device entry haptics not required for preview mode
+ null, // falsing manager not required for preview mode
)
)
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/blueprints/transitions/BaseBlueprintTransition.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/blueprints/transitions/BaseBlueprintTransition.kt
index 42b1c10..d0626d5 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/blueprints/transitions/BaseBlueprintTransition.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/blueprints/transitions/BaseBlueprintTransition.kt
@@ -24,6 +24,7 @@
import android.transition.Visibility
import android.view.View
import android.view.ViewGroup
+import androidx.constraintlayout.helper.widget.Layer
class BaseBlueprintTransition : TransitionSet() {
init {
@@ -31,6 +32,7 @@
addTransition(AlphaOutVisibility())
.addTransition(ChangeBounds())
.addTransition(AlphaInVisibility())
+ excludeTarget(Layer::class.java, /* exclude= */ true)
}
class AlphaOutVisibility : Visibility() {
override fun onDisappear(
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultSettingsPopupMenuSection.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultSettingsPopupMenuSection.kt
index 9a33f08..4bc2d86 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultSettingsPopupMenuSection.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultSettingsPopupMenuSection.kt
@@ -29,15 +29,15 @@
import androidx.constraintlayout.widget.ConstraintSet.WRAP_CONTENT
import androidx.core.view.isVisible
import com.android.systemui.Flags.keyguardBottomAreaRefactor
-import com.android.systemui.res.R
import com.android.systemui.animation.view.LaunchableLinearLayout
import com.android.systemui.dagger.qualifiers.Main
-import com.android.systemui.flags.FeatureFlags
-import com.android.systemui.flags.Flags
import com.android.systemui.keyguard.shared.model.KeyguardSection
import com.android.systemui.keyguard.ui.binder.KeyguardSettingsViewBinder
+import com.android.systemui.keyguard.ui.viewmodel.KeyguardLongPressViewModel
+import com.android.systemui.keyguard.ui.viewmodel.KeyguardRootViewModel
import com.android.systemui.keyguard.ui.viewmodel.KeyguardSettingsMenuViewModel
import com.android.systemui.plugins.ActivityStarter
+import com.android.systemui.res.R
import com.android.systemui.statusbar.VibratorHelper
import javax.inject.Inject
import kotlinx.coroutines.DisposableHandle
@@ -47,6 +47,8 @@
constructor(
@Main private val resources: Resources,
private val keyguardSettingsMenuViewModel: KeyguardSettingsMenuViewModel,
+ private val keyguardLongPressViewModel: KeyguardLongPressViewModel,
+ private val keyguardRootViewModel: KeyguardRootViewModel,
private val vibratorHelper: VibratorHelper,
private val activityStarter: ActivityStarter,
) : KeyguardSection() {
@@ -73,6 +75,8 @@
KeyguardSettingsViewBinder.bind(
constraintLayout.requireViewById<View>(R.id.keyguard_settings_button),
keyguardSettingsMenuViewModel,
+ keyguardLongPressViewModel,
+ keyguardRootViewModel,
vibratorHelper,
activityStarter,
)
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/SplitShadeNotificationStackScrollLayoutSection.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/SplitShadeNotificationStackScrollLayoutSection.kt
index 921fb3b..f5963be 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/SplitShadeNotificationStackScrollLayoutSection.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/SplitShadeNotificationStackScrollLayoutSection.kt
@@ -87,8 +87,13 @@
)
setGoneMargin(R.id.nssl_placeholder, TOP, bottomMargin)
} else {
- connect(R.id.nssl_placeholder, TOP, R.id.keyguard_status_view, TOP, bottomMargin)
+ val splitShadeTopMargin =
+ context.resources.getDimensionPixelSize(
+ R.dimen.large_screen_shade_header_height
+ )
+ connect(R.id.nssl_placeholder, TOP, PARENT_ID, TOP, splitShadeTopMargin)
}
+
connect(R.id.nssl_placeholder, START, PARENT_ID, START)
connect(R.id.nssl_placeholder, END, PARENT_ID, END)
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModel.kt
index 97ddbb0..4588e02 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModel.kt
@@ -17,6 +17,7 @@
package com.android.systemui.keyguard.ui.viewmodel
+import android.graphics.Point
import android.util.MathUtils
import android.view.View.VISIBLE
import com.android.app.animation.Interpolators
@@ -101,6 +102,9 @@
val goneToAodTransition = keyguardTransitionInteractor.transition(from = GONE, to = AOD)
+ /** Last point that the root view was tapped */
+ val lastRootViewTapPosition: Flow<Point?> = keyguardInteractor.lastRootViewTapPosition
+
/** the shared notification container bounds *on the lockscreen* */
val notificationBounds: StateFlow<NotificationContainerBounds> =
keyguardInteractor.notificationContainerBounds
@@ -262,4 +266,8 @@
}
.toAnimatedValueFlow()
}
+
+ fun setRootViewLastTapPosition(point: Point) {
+ keyguardInteractor.setLastRootViewTapPosition(point)
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/uimodenight/domain/UiModeNightTileMapper.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/uimodenight/domain/UiModeNightTileMapper.kt
new file mode 100644
index 0000000..3f30c75
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/uimodenight/domain/UiModeNightTileMapper.kt
@@ -0,0 +1,128 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.qs.tiles.impl.uimodenight.domain
+
+import android.app.UiModeManager
+import android.content.res.Resources
+import android.text.TextUtils
+import com.android.systemui.common.shared.model.Icon
+import com.android.systemui.dagger.qualifiers.Main
+import com.android.systemui.qs.tiles.base.interactor.QSTileDataToStateMapper
+import com.android.systemui.qs.tiles.impl.uimodenight.domain.model.UiModeNightTileModel
+import com.android.systemui.qs.tiles.viewmodel.QSTileConfig
+import com.android.systemui.qs.tiles.viewmodel.QSTileState
+import com.android.systemui.res.R
+import java.time.LocalTime
+import java.time.format.DateTimeFormatter
+import javax.inject.Inject
+
+/** Maps [UiModeNightTileModel] to [QSTileState]. */
+class UiModeNightTileMapper @Inject constructor(@Main private val resources: Resources) :
+ QSTileDataToStateMapper<UiModeNightTileModel> {
+ companion object {
+ val formatter12Hour: DateTimeFormatter = DateTimeFormatter.ofPattern("hh:mm a")
+ val formatter24Hour: DateTimeFormatter = DateTimeFormatter.ofPattern("HH:mm")
+ }
+ override fun map(config: QSTileConfig, data: UiModeNightTileModel): QSTileState =
+ with(data) {
+ QSTileState.build(resources, config.uiConfig) {
+ var shouldSetSecondaryLabel = false
+
+ if (isPowerSave) {
+ secondaryLabel =
+ resources.getString(
+ R.string.quick_settings_dark_mode_secondary_label_battery_saver
+ )
+ } else if (uiMode == UiModeManager.MODE_NIGHT_AUTO && isLocationEnabled) {
+ secondaryLabel =
+ resources.getString(
+ if (isNightMode)
+ R.string.quick_settings_dark_mode_secondary_label_until_sunrise
+ else R.string.quick_settings_dark_mode_secondary_label_on_at_sunset
+ )
+ } else if (uiMode == UiModeManager.MODE_NIGHT_CUSTOM) {
+ if (nightModeCustomType == UiModeManager.MODE_NIGHT_CUSTOM_TYPE_SCHEDULE) {
+ val time: LocalTime =
+ if (isNightMode) {
+ customNightModeEnd
+ } else {
+ customNightModeStart
+ }
+
+ val formatter: DateTimeFormatter =
+ if (is24HourFormat) formatter24Hour else formatter12Hour
+
+ secondaryLabel =
+ resources.getString(
+ if (isNightMode)
+ R.string.quick_settings_dark_mode_secondary_label_until
+ else R.string.quick_settings_dark_mode_secondary_label_on_at,
+ formatter.format(time)
+ )
+ } else if (
+ nightModeCustomType == UiModeManager.MODE_NIGHT_CUSTOM_TYPE_BEDTIME
+ ) {
+ secondaryLabel =
+ resources.getString(
+ if (isNightMode)
+ R.string
+ .quick_settings_dark_mode_secondary_label_until_bedtime_ends
+ else R.string.quick_settings_dark_mode_secondary_label_on_at_bedtime
+ )
+ } else {
+ secondaryLabel = null // undefined type of nightModeCustomType
+ shouldSetSecondaryLabel = true
+ }
+ } else {
+ secondaryLabel = null
+ shouldSetSecondaryLabel = true
+ }
+
+ contentDescription =
+ if (TextUtils.isEmpty(secondaryLabel)) label
+ else TextUtils.concat(label, ", ", secondaryLabel)
+ if (isPowerSave) {
+ activationState = QSTileState.ActivationState.UNAVAILABLE
+ if (shouldSetSecondaryLabel)
+ secondaryLabel = resources.getStringArray(R.array.tile_states_dark)[0]
+ } else {
+ activationState =
+ if (isNightMode) QSTileState.ActivationState.ACTIVE
+ else QSTileState.ActivationState.INACTIVE
+
+ if (shouldSetSecondaryLabel) {
+ secondaryLabel =
+ if (activationState == QSTileState.ActivationState.INACTIVE)
+ resources.getStringArray(R.array.tile_states_dark)[1]
+ else resources.getStringArray(R.array.tile_states_dark)[2]
+ }
+ }
+
+ val iconRes =
+ if (activationState == QSTileState.ActivationState.ACTIVE)
+ R.drawable.qs_light_dark_theme_icon_on
+ else R.drawable.qs_light_dark_theme_icon_off
+ val iconResource = Icon.Resource(iconRes, null)
+ icon = { iconResource }
+
+ supportedActions =
+ if (activationState == QSTileState.ActivationState.UNAVAILABLE)
+ setOf(QSTileState.UserAction.LONG_CLICK)
+ else setOf(QSTileState.UserAction.CLICK, QSTileState.UserAction.LONG_CLICK)
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/uimodenight/domain/interactor/UiModeNightTileDataInteractor.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/uimodenight/domain/interactor/UiModeNightTileDataInteractor.kt
new file mode 100644
index 0000000..c928e8a
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/uimodenight/domain/interactor/UiModeNightTileDataInteractor.kt
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.qs.tiles.impl.uimodenight.domain.interactor
+
+import android.app.UiModeManager
+import android.content.Context
+import android.content.res.Configuration
+import android.os.UserHandle
+import com.android.systemui.common.coroutine.ConflatedCallbackFlow
+import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.qs.tiles.base.interactor.DataUpdateTrigger
+import com.android.systemui.qs.tiles.base.interactor.QSTileDataInteractor
+import com.android.systemui.qs.tiles.impl.uimodenight.domain.model.UiModeNightTileModel
+import com.android.systemui.statusbar.policy.BatteryController
+import com.android.systemui.statusbar.policy.ConfigurationController
+import com.android.systemui.statusbar.policy.LocationController
+import com.android.systemui.util.time.DateFormatUtil
+import javax.inject.Inject
+import kotlinx.coroutines.channels.awaitClose
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.flowOf
+
+/** Observes ui mode night state changes providing the [UiModeNightTileModel]. */
+class UiModeNightTileDataInteractor
+@Inject
+constructor(
+ @Application private val context: Context,
+ private val configurationController: ConfigurationController,
+ private val uiModeManager: UiModeManager,
+ private val batteryController: BatteryController,
+ private val locationController: LocationController,
+ private val dateFormatUtil: DateFormatUtil,
+) : QSTileDataInteractor<UiModeNightTileModel> {
+
+ override fun tileData(
+ user: UserHandle,
+ triggers: Flow<DataUpdateTrigger>
+ ): Flow<UiModeNightTileModel> =
+ ConflatedCallbackFlow.conflatedCallbackFlow {
+ // send initial state
+ trySend(createModel())
+
+ val configurationCallback =
+ object : ConfigurationController.ConfigurationListener {
+ override fun onUiModeChanged() {
+ trySend(createModel())
+ }
+ }
+ configurationController.addCallback(configurationCallback)
+
+ val batteryCallback =
+ object : BatteryController.BatteryStateChangeCallback {
+ override fun onPowerSaveChanged(isPowerSave: Boolean) {
+ trySend(createModel())
+ }
+ }
+ batteryController.addCallback(batteryCallback)
+
+ val locationCallback =
+ object : LocationController.LocationChangeCallback {
+ override fun onLocationSettingsChanged(locationEnabled: Boolean) {
+ trySend(createModel())
+ }
+ }
+ locationController.addCallback(locationCallback)
+
+ awaitClose {
+ configurationController.removeCallback(configurationCallback)
+ batteryController.removeCallback(batteryCallback)
+ locationController.removeCallback(locationCallback)
+ }
+ }
+
+ private fun createModel(): UiModeNightTileModel {
+ val uiMode = uiModeManager.nightMode
+ val nightMode =
+ (context.resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK) ==
+ Configuration.UI_MODE_NIGHT_YES
+ val powerSave = batteryController.isPowerSave
+ val locationEnabled = locationController.isLocationEnabled
+ val nightModeCustomType = uiModeManager.nightModeCustomType
+ val use24HourFormat = dateFormatUtil.is24HourFormat
+ val customNightModeEnd = uiModeManager.customNightModeEnd
+ val customNightModeStart = uiModeManager.customNightModeStart
+
+ return UiModeNightTileModel(
+ uiMode,
+ nightMode,
+ powerSave,
+ locationEnabled,
+ nightModeCustomType,
+ use24HourFormat,
+ customNightModeEnd,
+ customNightModeStart
+ )
+ }
+
+ override fun availability(user: UserHandle): Flow<Boolean> = flowOf(true)
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/uimodenight/domain/interactor/UiModeNightTileUserActionInteractor.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/uimodenight/domain/interactor/UiModeNightTileUserActionInteractor.kt
new file mode 100644
index 0000000..00d7a62
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/uimodenight/domain/interactor/UiModeNightTileUserActionInteractor.kt
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.qs.tiles.impl.uimodenight.domain.interactor
+
+import android.app.UiModeManager
+import android.content.Intent
+import android.provider.Settings
+import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.qs.tiles.base.actions.QSTileIntentUserInputHandler
+import com.android.systemui.qs.tiles.base.interactor.QSTileInput
+import com.android.systemui.qs.tiles.base.interactor.QSTileUserActionInteractor
+import com.android.systemui.qs.tiles.impl.uimodenight.domain.model.UiModeNightTileModel
+import com.android.systemui.qs.tiles.viewmodel.QSTileUserAction
+import javax.inject.Inject
+import kotlin.coroutines.CoroutineContext
+import kotlinx.coroutines.withContext
+
+/** Handles ui mode night tile clicks. */
+class UiModeNightTileUserActionInteractor
+@Inject
+constructor(
+ @Background private val backgroundContext: CoroutineContext,
+ private val uiModeManager: UiModeManager,
+ private val qsTileIntentUserActionHandler: QSTileIntentUserInputHandler,
+) : QSTileUserActionInteractor<UiModeNightTileModel> {
+
+ override suspend fun handleInput(input: QSTileInput<UiModeNightTileModel>) =
+ with(input) {
+ when (action) {
+ is QSTileUserAction.Click -> {
+ if (!input.data.isPowerSave) {
+ withContext(backgroundContext) {
+ uiModeManager.setNightModeActivated(!input.data.isNightMode)
+ }
+ }
+ }
+ is QSTileUserAction.LongClick -> {
+ qsTileIntentUserActionHandler.handle(
+ action.view,
+ Intent(Settings.ACTION_DARK_THEME_SETTINGS)
+ )
+ }
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/uimodenight/domain/model/UiModeNightTileModel.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/uimodenight/domain/model/UiModeNightTileModel.kt
new file mode 100644
index 0000000..4fa1306
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/uimodenight/domain/model/UiModeNightTileModel.kt
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.qs.tiles.impl.uimodenight.domain.model
+
+import java.time.LocalTime
+
+/**
+ * UiModeNight tile model. Quick Settings tile for: Night Mode / Dark Theme / Dark Mode.
+ *
+ * @param isNightMode is true when the NightMode is enabled;
+ */
+data class UiModeNightTileModel(
+ val uiMode: Int,
+ val isNightMode: Boolean,
+ val isPowerSave: Boolean,
+ val isLocationEnabled: Boolean,
+ val nightModeCustomType: Int,
+ val is24HourFormat: Boolean,
+ val customNightModeEnd: LocalTime,
+ val customNightModeStart: LocalTime
+)
diff --git a/packages/SystemUI/src/com/android/systemui/scene/shared/flag/SceneContainerFlags.kt b/packages/SystemUI/src/com/android/systemui/scene/shared/flag/SceneContainerFlags.kt
index dbb58a3..1156250 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/shared/flag/SceneContainerFlags.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/shared/flag/SceneContainerFlags.kt
@@ -31,6 +31,7 @@
import com.android.systemui.flags.ResourceBooleanFlag
import com.android.systemui.flags.UnreleasedFlag
import com.android.systemui.keyguard.shared.KeyguardShadeMigrationNssl
+import com.android.systemui.media.controls.util.MediaInSceneContainerFlag
import com.android.systemui.res.R
import dagger.Module
import dagger.Provides
@@ -82,6 +83,10 @@
flagName = KeyguardShadeMigrationNssl.FLAG_NAME,
flagValue = KeyguardShadeMigrationNssl.isEnabled,
),
+ AconfigFlagMustBeEnabled(
+ flagName = MediaInSceneContainerFlag.FLAG_NAME,
+ flagValue = MediaInSceneContainerFlag.isEnabled,
+ ),
) +
classicFlagTokens.map { flagToken -> FlagMustBeEnabled(flagToken) } +
listOf(
diff --git a/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordPermissionDialogDelegate.kt b/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordPermissionDialogDelegate.kt
index 10d51a5..3eb26f4 100644
--- a/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordPermissionDialogDelegate.kt
+++ b/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordPermissionDialogDelegate.kt
@@ -28,6 +28,7 @@
import android.view.View
import android.view.View.GONE
import android.view.View.VISIBLE
+import android.view.ViewGroup
import android.view.accessibility.AccessibilityNodeInfo
import android.widget.AdapterView
import android.widget.ArrayAdapter
@@ -64,10 +65,13 @@
mediaProjectionMetricsLogger,
R.drawable.ic_screenrecord,
R.color.screenrecord_icon_color
- ), SystemUIDialog.Delegate {
+ ),
+ SystemUIDialog.Delegate {
private lateinit var tapsSwitch: Switch
+ private lateinit var tapsSwitchContainer: ViewGroup
private lateinit var tapsView: View
private lateinit var audioSwitch: Switch
+ private lateinit var audioSwitchContainer: ViewGroup
private lateinit var options: Spinner
override fun createDialog(): SystemUIDialog {
@@ -114,12 +118,17 @@
private fun initRecordOptionsView() {
audioSwitch = dialog.requireViewById(R.id.screenrecord_audio_switch)
tapsSwitch = dialog.requireViewById(R.id.screenrecord_taps_switch)
+ audioSwitchContainer = dialog.requireViewById(R.id.screenrecord_audio_switch_container)
+ tapsSwitchContainer = dialog.requireViewById(R.id.screenrecord_taps_switch_container)
// Add these listeners so that the switch only responds to movement
// within its target region, to meet accessibility requirements
audioSwitch.setOnTouchListener { _, event -> event.action == ACTION_MOVE }
tapsSwitch.setOnTouchListener { _, event -> event.action == ACTION_MOVE }
+ audioSwitchContainer.setOnClickListener { audioSwitch.toggle() }
+ tapsSwitchContainer.setOnClickListener { tapsSwitch.toggle() }
+
tapsView = dialog.requireViewById(R.id.show_taps)
updateTapsViewVisibility()
diff --git a/packages/SystemUI/src/com/android/systemui/shade/QuickSettingsController.java b/packages/SystemUI/src/com/android/systemui/shade/QuickSettingsController.java
index 8397caa..dd194eaa 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/QuickSettingsController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/QuickSettingsController.java
@@ -794,6 +794,13 @@
/** update Qs height state */
public void setExpansionHeight(float height) {
+ // TODO(b/277909752): remove below log when bug is fixed
+ if (mSplitShadeEnabled && mShadeExpandedFraction == 1.0f && height == 0
+ && mBarState == SHADE) {
+ Log.wtf(TAG,
+ "setting QS height to 0 in split shade while shade is open(ing). "
+ + "Value of isExpandImmediate() = " + isExpandImmediate());
+ }
int maxHeight = getMaxExpansionHeight();
height = Math.min(Math.max(
height, getMinExpansionHeight()), maxHeight);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
index 6cb079a..b6d4ded 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
@@ -139,7 +139,6 @@
private static final long RECENTLY_ALERTED_THRESHOLD_MS = TimeUnit.SECONDS.toMillis(30);
private static final SourceType BASE_VALUE = SourceType.from("BaseValue");
private static final SourceType FROM_PARENT = SourceType.from("FromParent(ENR)");
- private static final SourceType PINNED = SourceType.from("Pinned");
// We don't correctly track dark mode until the content views are inflated, so always update
// the background on first content update just in case it happens to be during a theme change.
@@ -147,7 +146,6 @@
private boolean mIsSnoozed;
private boolean mShowSnooze = false;
private boolean mIsFaded;
- private boolean mAnimatePinnedRoundness = false;
/**
* Listener for when {@link ExpandableNotificationRow} is laid out.
@@ -1053,14 +1051,6 @@
if (isAboveShelf() != wasAboveShelf) {
mAboveShelfChangedListener.onAboveShelfStateChanged(!wasAboveShelf);
}
- if (pinned) {
- // Should be animated if someone explicitly set it to 0 and the row is shown.
- boolean animated = mAnimatePinnedRoundness && isShown();
- requestRoundness(/* top = */ 1f, /* bottom = */ 1f, PINNED, animated);
- } else {
- requestRoundnessReset(PINNED);
- mAnimatePinnedRoundness = true;
- }
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackStateLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackStateLogger.kt
index d635f89..bf0c823 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackStateLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackStateLogger.kt
@@ -29,7 +29,7 @@
TAG,
LogLevel.ERROR,
{ str1 = logKey(key) },
- { "Heads up view disappearing $str1 for ANIMATION_TYPE_ADD" }
+ { "Heads up view appearing $str1 for ANIMATION_TYPE_ADD" }
)
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/domain/interactor/SharedNotificationContainerInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/domain/interactor/SharedNotificationContainerInteractor.kt
index c2c5eed..adf6cca 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/domain/interactor/SharedNotificationContainerInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/domain/interactor/SharedNotificationContainerInteractor.kt
@@ -68,6 +68,8 @@
marginTop = getDimensionPixelSize(R.dimen.notification_panel_margin_top),
marginTopLargeScreen =
getDimensionPixelSize(R.dimen.large_screen_shade_header_height),
+ keyguardSplitShadeTopMargin =
+ getDimensionPixelSize(R.dimen.keyguard_split_shade_top_margin),
)
}
}
@@ -95,5 +97,6 @@
val marginBottom: Int,
val marginTop: Int,
val marginTopLargeScreen: Int,
+ val keyguardSplitShadeTopMargin: Int,
)
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModel.kt
index b0f1038..5b854e6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModel.kt
@@ -83,6 +83,14 @@
marginTop =
if (it.useLargeScreenHeader) it.marginTopLargeScreen else it.marginTop,
useSplitShade = it.useSplitShade,
+ paddingTop =
+ if (it.useSplitShade) {
+ // When in split shade, the margin is applied twice as the legacy shade
+ // code uses it to calculate padding.
+ it.keyguardSplitShadeTopMargin - 2 * it.marginTopLargeScreen
+ } else {
+ 0
+ }
)
}
.distinctUntilChanged()
@@ -156,11 +164,7 @@
),
) { onLockscreen, bounds, config, (top, isInTransitionToAnyState, qsExpansion) ->
if (onLockscreen) {
- if (config.useSplitShade) {
- bounds.copy(top = 0f)
- } else {
- bounds
- }
+ bounds.copy(top = bounds.top + config.paddingTop)
} else {
// When QS expansion > 0, it should directly set the top padding so do not
// animate it
@@ -268,5 +272,6 @@
val marginEnd: Int,
val marginBottom: Int,
val useSplitShade: Boolean,
+ val paddingTop: Int,
)
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIDialog.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIDialog.java
index 93bc960..af6da3f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIDialog.java
@@ -146,7 +146,7 @@
* When you just need a dialog, call this.
*/
public SystemUIDialog create() {
- return create(new DialogDelegate<>(){});
+ return create(new DialogDelegate<>(){}, mContext);
}
/**
@@ -155,13 +155,18 @@
*
* When you need to customize the dialog, pass it a delegate.
*/
- public SystemUIDialog create(Delegate delegate) {
- return create((DialogDelegate<SystemUIDialog>) delegate);
+ public SystemUIDialog create(Delegate delegate, Context context) {
+ return create((DialogDelegate<SystemUIDialog>) delegate, context);
}
- private SystemUIDialog create(DialogDelegate<SystemUIDialog> dialogDelegate) {
+ public SystemUIDialog create(Delegate delegate) {
+ return create(delegate, mContext);
+ }
+
+ private SystemUIDialog create(DialogDelegate<SystemUIDialog> dialogDelegate,
+ Context context) {
return new SystemUIDialog(
- mContext,
+ context,
DEFAULT_THEME,
DEFAULT_DISMISS_ON_DEVICE_LOCK,
mFeatureFlags,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/binder/MobileIconBinder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/binder/MobileIconBinder.kt
index b93e443..a14e87c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/binder/MobileIconBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/binder/MobileIconBinder.kt
@@ -154,8 +154,13 @@
dataTypeId,
)
dataTypeId?.let { IconViewBinder.bind(dataTypeId, networkTypeView) }
+ val prevVis = networkTypeContainer.visibility
networkTypeContainer.visibility =
if (dataTypeId != null) VISIBLE else GONE
+
+ if (prevVis != networkTypeContainer.visibility) {
+ view.requestLayout()
+ }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/model/InternetTileModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/model/InternetTileModel.kt
index 1886590..ed0eb6d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/model/InternetTileModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/model/InternetTileModel.kt
@@ -29,7 +29,7 @@
/** Model describing the state that the QS Internet tile should be in. */
sealed interface InternetTileModel {
- val secondaryTitle: String?
+ val secondaryTitle: CharSequence?
val secondaryLabel: Text?
val iconId: Int?
val icon: QSTile.Icon?
@@ -62,7 +62,7 @@
}
data class Active(
- override val secondaryTitle: String? = null,
+ override val secondaryTitle: CharSequence? = null,
override val secondaryLabel: Text? = null,
override val iconId: Int? = null,
override val icon: QSTile.Icon? = null,
@@ -71,7 +71,7 @@
) : InternetTileModel
data class Inactive(
- override val secondaryTitle: String? = null,
+ override val secondaryTitle: CharSequence? = null,
override val secondaryLabel: Text? = null,
override val iconId: Int? = null,
override val icon: QSTile.Icon? = null,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/InternetTileViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/InternetTileViewModel.kt
index a80ea90..99b123f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/InternetTileViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/InternetTileViewModel.kt
@@ -17,13 +17,14 @@
package com.android.systemui.statusbar.pipeline.shared.ui.viewmodel
import android.content.Context
-import com.android.systemui.res.R
+import android.text.Html
import com.android.systemui.common.shared.model.ContentDescription
import com.android.systemui.common.shared.model.Text
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.qs.tileimpl.QSTileImpl
import com.android.systemui.qs.tileimpl.QSTileImpl.ResourceIcon
+import com.android.systemui.res.R
import com.android.systemui.statusbar.pipeline.airplane.data.repository.AirplaneModeRepository
import com.android.systemui.statusbar.pipeline.ethernet.domain.EthernetInteractor
import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.MobileIconsInteractor
@@ -120,7 +121,7 @@
InternetTileModel.Active(
secondaryTitle = secondary,
icon = SignalIcon(signalIcon.toSignalDrawableState()),
- stateDescription = ContentDescription.Loaded(secondary),
+ stateDescription = ContentDescription.Loaded(secondary.toString()),
contentDescription = ContentDescription.Loaded(internetLabel),
)
}
@@ -130,22 +131,25 @@
private fun mobileDataContentConcat(
networkName: String?,
dataContentDescription: CharSequence?
- ): String {
+ ): CharSequence {
if (dataContentDescription == null) {
return networkName ?: ""
}
if (networkName == null) {
- return dataContentDescription.toString()
+ return Html.fromHtml(dataContentDescription.toString(), 0)
}
- return context.getString(
- R.string.mobile_carrier_text_format,
- networkName,
- dataContentDescription
+ return Html.fromHtml(
+ context.getString(
+ R.string.mobile_carrier_text_format,
+ networkName,
+ dataContentDescription
+ ),
+ 0
)
}
- private fun loadString(resId: Int): String? =
+ private fun loadString(resId: Int): CharSequence? =
if (resId > 0) {
context.getString(resId)
} else {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateControllerImpl.java
index 3deb9e7..80c6802 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateControllerImpl.java
@@ -216,7 +216,11 @@
private void notifyKeyguardFaceAuthEnabledChanged() {
// Copy the list to allow removal during callback.
- new ArrayList<>(mCallbacks).forEach(Callback::onFaceEnrolledChanged);
+ new ArrayList<>(mCallbacks).forEach(callback -> {
+ if (callback != null) {
+ callback.onFaceEnrolledChanged();
+ }
+ });
}
private void notifyUnlockedChanged() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/PolicyModule.kt b/packages/SystemUI/src/com/android/systemui/statusbar/policy/PolicyModule.kt
index 0f2da2d..087e100 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/PolicyModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/PolicyModule.kt
@@ -38,6 +38,10 @@
import com.android.systemui.qs.tiles.impl.location.domain.interactor.LocationTileDataInteractor
import com.android.systemui.qs.tiles.impl.location.domain.interactor.LocationTileUserActionInteractor
import com.android.systemui.qs.tiles.impl.location.domain.model.LocationTileModel
+import com.android.systemui.qs.tiles.impl.uimodenight.domain.UiModeNightTileMapper
+import com.android.systemui.qs.tiles.impl.uimodenight.domain.interactor.UiModeNightTileDataInteractor
+import com.android.systemui.qs.tiles.impl.uimodenight.domain.interactor.UiModeNightTileUserActionInteractor
+import com.android.systemui.qs.tiles.impl.uimodenight.domain.model.UiModeNightTileModel
import com.android.systemui.qs.tiles.viewmodel.QSTileConfig
import com.android.systemui.qs.tiles.viewmodel.QSTileUIConfig
import com.android.systemui.qs.tiles.viewmodel.QSTileViewModel
@@ -64,6 +68,7 @@
const val FLASHLIGHT_TILE_SPEC = "flashlight"
const val LOCATION_TILE_SPEC = "location"
const val ALARM_TILE_SPEC = "alarm"
+ const val UIMODENIGHT_TILE_SPEC = "dark"
/** Inject flashlight config */
@Provides
@@ -160,6 +165,38 @@
stateInteractor,
mapper,
)
+
+ /** Inject uimodenight config */
+ @Provides
+ @IntoMap
+ @StringKey(UIMODENIGHT_TILE_SPEC)
+ fun provideUiModeNightTileConfig(uiEventLogger: QsEventLogger): QSTileConfig =
+ QSTileConfig(
+ tileSpec = TileSpec.create(UIMODENIGHT_TILE_SPEC),
+ uiConfig =
+ QSTileUIConfig.Resource(
+ iconRes = R.drawable.qs_light_dark_theme_icon_off,
+ labelRes = R.string.quick_settings_ui_mode_night_label,
+ ),
+ instanceId = uiEventLogger.getNewInstanceId(),
+ )
+
+ /** Inject uimodenight into tileViewModelMap in QSModule */
+ @Provides
+ @IntoMap
+ @StringKey(UIMODENIGHT_TILE_SPEC)
+ fun provideUiModeNightTileViewModel(
+ factory: QSTileViewModelFactory.Static<UiModeNightTileModel>,
+ mapper: UiModeNightTileMapper,
+ stateInteractor: UiModeNightTileDataInteractor,
+ userActionInteractor: UiModeNightTileUserActionInteractor
+ ): QSTileViewModel =
+ factory.create(
+ TileSpec.create(UIMODENIGHT_TILE_SPEC),
+ userActionInteractor,
+ stateInteractor,
+ mapper,
+ )
}
/** Inject FlashlightTile into tileMap in QSModule */
diff --git a/packages/SystemUI/src/com/android/systemui/unfold/SysUIUnfoldModule.kt b/packages/SystemUI/src/com/android/systemui/unfold/SysUIUnfoldModule.kt
index ff73e0e..10fc83c 100644
--- a/packages/SystemUI/src/com/android/systemui/unfold/SysUIUnfoldModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/unfold/SysUIUnfoldModule.kt
@@ -21,7 +21,6 @@
import com.android.systemui.shade.NotificationPanelUnfoldAnimationController
import com.android.systemui.statusbar.phone.StatusBarMoveFromCenterAnimationController
import com.android.systemui.unfold.dagger.UnfoldBg
-import com.android.systemui.unfold.progress.UnfoldTransitionProgressForwarder
import com.android.systemui.unfold.util.NaturalRotationUnfoldProgressProvider
import com.android.systemui.unfold.util.ScopedUnfoldTransitionProgressProvider
import com.android.systemui.unfold.util.UnfoldKeyguardVisibilityManager
@@ -107,20 +106,4 @@
fun getUnfoldLatencyTracker(): UnfoldLatencyTracker
fun getNaturalRotationUnfoldProgressProvider(): NaturalRotationUnfoldProgressProvider
-
- /** Creates a UnfoldTransitionProgressProvider that calculates progress in the main thread. */
- fun getUnfoldTransitionProgressProvider(): UnfoldTransitionProgressProvider
-
- /** Creates a UnfoldTransitionProgressProvider that calculates progress in the background. */
- @UnfoldBg
- fun getBgUnfoldTransitionProgressProvider(): UnfoldTransitionProgressProvider
-
- /** Creates a UnfoldTransitionProgressForwarder. */
- fun getUnfoldTransitionProgressForwarder(): UnfoldTransitionProgressForwarder
-
- /** Creates a FoldStateLoggingProvider. */
- fun getFoldStateLoggingProvider(): Optional<FoldStateLoggingProvider>
-
- /** Creates a FoldStateLogger. */
- fun getFoldStateLogger(): Optional<FoldStateLogger>
}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/CsdWarningDialog.java b/packages/SystemUI/src/com/android/systemui/volume/CsdWarningDialog.java
index d6e6f3f..bd698ab 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/CsdWarningDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/CsdWarningDialog.java
@@ -157,6 +157,7 @@
if (mCsdWarning == AudioManager.CSD_WARNING_DOSE_REPEATED_5X) {
// only show a notification in case we reached 500% of dose
show5XNotification();
+ dismissCsdDialog();
return;
}
super.show();
@@ -217,6 +218,10 @@
@Override
public void onDismiss(DialogInterface unused) {
+ dismissCsdDialog();
+ }
+
+ private void dismissCsdDialog() {
try {
mContext.unregisterReceiver(mReceiver);
} catch (IllegalArgumentException e) {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/display/data/repository/DeviceStateRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/display/data/repository/DeviceStateRepositoryTest.kt
new file mode 100644
index 0000000..21b8aca
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/display/data/repository/DeviceStateRepositoryTest.kt
@@ -0,0 +1,164 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.display.data.repository
+
+import android.hardware.devicestate.DeviceStateManager
+import android.testing.AndroidTestingRunner
+import android.testing.TestableLooper
+import androidx.test.filters.SmallTest
+import com.android.internal.R
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.coroutines.FlowValue
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.display.data.repository.DeviceStateRepository.DeviceState
+import com.android.systemui.util.concurrency.FakeExecutor
+import com.android.systemui.util.mockito.any
+import com.android.systemui.util.mockito.kotlinArgumentCaptor
+import com.android.systemui.util.mockito.mock
+import com.android.systemui.util.time.FakeSystemClock
+import com.google.common.truth.Truth.assertThat
+import kotlin.test.Test
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.UnconfinedTestDispatcher
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.runner.RunWith
+import org.mockito.Mockito.never
+import org.mockito.Mockito.verify
+
+@RunWith(AndroidTestingRunner::class)
+@TestableLooper.RunWithLooper
+@OptIn(ExperimentalCoroutinesApi::class)
+@SmallTest
+class DeviceStateRepositoryTest : SysuiTestCase() {
+
+ private val deviceStateManager = mock<DeviceStateManager>()
+ private val deviceStateManagerListener =
+ kotlinArgumentCaptor<DeviceStateManager.DeviceStateCallback>()
+
+ private val testScope = TestScope(UnconfinedTestDispatcher())
+ private val fakeExecutor = FakeExecutor(FakeSystemClock())
+
+ private lateinit var deviceStateRepository: DeviceStateRepositoryImpl
+
+ @Before
+ fun setup() {
+ mContext.orCreateTestableResources.apply {
+ addOverride(R.array.config_foldedDeviceStates, listOf(TEST_FOLDED).toIntArray())
+ addOverride(R.array.config_halfFoldedDeviceStates, TEST_HALF_FOLDED.toIntArray())
+ addOverride(R.array.config_openDeviceStates, TEST_UNFOLDED.toIntArray())
+ addOverride(R.array.config_rearDisplayDeviceStates, TEST_REAR_DISPLAY.toIntArray())
+ addOverride(
+ R.array.config_concurrentDisplayDeviceStates,
+ TEST_CONCURRENT_DISPLAY.toIntArray()
+ )
+ }
+ deviceStateRepository =
+ DeviceStateRepositoryImpl(
+ mContext,
+ deviceStateManager,
+ TestScope(UnconfinedTestDispatcher()),
+ fakeExecutor
+ )
+
+ // It should register only after there are clients collecting the flow
+ verify(deviceStateManager, never()).registerCallback(any(), any())
+ }
+
+ @Test
+ fun folded_receivesFoldedState() =
+ testScope.runTest {
+ val state = displayState()
+
+ deviceStateManagerListener.value.onStateChanged(TEST_FOLDED)
+
+ assertThat(state()).isEqualTo(DeviceState.FOLDED)
+ }
+
+ @Test
+ fun halfFolded_receivesHalfFoldedState() =
+ testScope.runTest {
+ val state = displayState()
+
+ deviceStateManagerListener.value.onStateChanged(TEST_HALF_FOLDED)
+
+ assertThat(state()).isEqualTo(DeviceState.HALF_FOLDED)
+ }
+
+ @Test
+ fun unfolded_receivesUnfoldedState() =
+ testScope.runTest {
+ val state = displayState()
+
+ deviceStateManagerListener.value.onStateChanged(TEST_UNFOLDED)
+
+ assertThat(state()).isEqualTo(DeviceState.UNFOLDED)
+ }
+
+ @Test
+ fun rearDisplay_receivesRearDisplayState() =
+ testScope.runTest {
+ val state = displayState()
+
+ deviceStateManagerListener.value.onStateChanged(TEST_REAR_DISPLAY)
+
+ assertThat(state()).isEqualTo(DeviceState.REAR_DISPLAY)
+ }
+
+ @Test
+ fun concurrentDisplay_receivesConcurrentDisplayState() =
+ testScope.runTest {
+ val state = displayState()
+
+ deviceStateManagerListener.value.onStateChanged(TEST_CONCURRENT_DISPLAY)
+
+ assertThat(state()).isEqualTo(DeviceState.CONCURRENT_DISPLAY)
+ }
+
+ @Test
+ fun unknownState_receivesUnknownState() =
+ testScope.runTest {
+ val state = displayState()
+
+ deviceStateManagerListener.value.onStateChanged(123456)
+
+ assertThat(state()).isEqualTo(DeviceState.UNKNOWN)
+ }
+
+ private fun TestScope.displayState(): FlowValue<DeviceState?> {
+ val flowValue = collectLastValue(deviceStateRepository.state)
+ verify(deviceStateManager)
+ .registerCallback(
+ any(),
+ deviceStateManagerListener.capture(),
+ )
+ return flowValue
+ }
+
+ private fun Int.toIntArray() = listOf(this).toIntArray()
+
+ private companion object {
+ // Used to fake the ids in the test. Note that there is no guarantees different devices will
+ // have the same ids (that's why the ones in this test start from 41)
+ const val TEST_FOLDED = 41
+ const val TEST_HALF_FOLDED = 42
+ const val TEST_UNFOLDED = 43
+ const val TEST_REAR_DISPLAY = 44
+ const val TEST_CONCURRENT_DISPLAY = 45
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/display/domain/interactor/ConnectedDisplayInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/display/domain/interactor/ConnectedDisplayInteractorTest.kt
index 1f18705..42b0f50 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/display/domain/interactor/ConnectedDisplayInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/display/domain/interactor/ConnectedDisplayInteractorTest.kt
@@ -28,6 +28,9 @@
import com.android.systemui.SysuiTestCase
import com.android.systemui.coroutines.FlowValue
import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.display.data.repository.DeviceStateRepository
+import com.android.systemui.display.data.repository.DeviceStateRepository.DeviceState.CONCURRENT_DISPLAY
+import com.android.systemui.display.data.repository.FakeDeviceStateRepository
import com.android.systemui.display.data.repository.FakeDisplayRepository
import com.android.systemui.display.data.repository.createPendingDisplay
import com.android.systemui.display.data.repository.display
@@ -59,11 +62,13 @@
private val fakeDisplayRepository = FakeDisplayRepository()
private val fakeKeyguardRepository = FakeKeyguardRepository()
+ private val fakeDeviceStateRepository = FakeDeviceStateRepository()
private val connectedDisplayStateProvider: ConnectedDisplayInteractor =
ConnectedDisplayInteractorImpl(
virtualDeviceManager,
fakeKeyguardRepository,
fakeDisplayRepository,
+ fakeDeviceStateRepository,
UnconfinedTestDispatcher(),
)
private val testScope = TestScope(UnconfinedTestDispatcher())
@@ -283,6 +288,44 @@
assertThat(pendingDisplay).isNull()
}
+ @Test
+ fun concurrentDisplaysInProgress_started_returnsTrue() =
+ testScope.runTest {
+ val concurrentDisplaysInProgress =
+ collectLastValue(connectedDisplayStateProvider.concurrentDisplaysInProgress)
+
+ fakeDeviceStateRepository.emit(CONCURRENT_DISPLAY)
+
+ assertThat(concurrentDisplaysInProgress()).isTrue()
+ }
+
+ @Test
+ fun concurrentDisplaysInProgress_stopped_returnsFalse() =
+ testScope.runTest {
+ val concurrentDisplaysInProgress =
+ collectLastValue(connectedDisplayStateProvider.concurrentDisplaysInProgress)
+
+ fakeDeviceStateRepository.emit(CONCURRENT_DISPLAY)
+ fakeDeviceStateRepository.emit(DeviceStateRepository.DeviceState.UNKNOWN)
+
+ assertThat(concurrentDisplaysInProgress()).isFalse()
+ }
+
+ @Test
+ fun concurrentDisplaysInProgress_otherStates_returnsFalse() =
+ testScope.runTest {
+ val concurrentDisplaysInProgress =
+ collectLastValue(connectedDisplayStateProvider.concurrentDisplaysInProgress)
+
+ DeviceStateRepository.DeviceState.entries
+ .filter { it != CONCURRENT_DISPLAY }
+ .forEach { deviceState ->
+ fakeDeviceStateRepository.emit(deviceState)
+
+ assertThat(concurrentDisplaysInProgress()).isFalse()
+ }
+ }
+
private fun TestScope.lastValue(): FlowValue<State?> =
collectLastValue(connectedDisplayStateProvider.connectedDisplayState)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardBlueprintRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardBlueprintRepositoryTest.kt
index 5852bdb..f2bd817 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardBlueprintRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardBlueprintRepositoryTest.kt
@@ -15,6 +15,8 @@
*
*/
+@file:OptIn(ExperimentalCoroutinesApi::class)
+
package com.android.systemui.keyguard.data.repository
import androidx.test.filters.SmallTest
@@ -25,8 +27,10 @@
import com.android.systemui.keyguard.ui.view.layout.blueprints.DefaultKeyguardBlueprint.Companion.DEFAULT
import com.android.systemui.util.mockito.whenever
import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.StandardTestDispatcher
import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
import org.junit.Before
import org.junit.Test
@@ -76,8 +80,21 @@
fun testTransitionToLayout_validId() {
assertThat(underTest.applyBlueprint(DEFAULT)).isTrue()
}
+
@Test
fun testTransitionToLayout_invalidId() {
assertThat(underTest.applyBlueprint("abc")).isFalse()
}
+
+ @Test
+ fun testTransitionToSameBlueprint_refreshesBlueprint() =
+ testScope.runTest {
+ val refreshBlueprint by collectLastValue(underTest.refreshBluePrint)
+ runCurrent()
+
+ underTest.applyBlueprint(defaultLockscreenBlueprint)
+ runCurrent()
+
+ assertThat(refreshBlueprint).isNotNull()
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/scene/shared/flag/SceneContainerFlagsTest.kt b/packages/SystemUI/tests/src/com/android/systemui/scene/shared/flag/SceneContainerFlagsTest.kt
index 0173c32..b90ccc0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/scene/shared/flag/SceneContainerFlagsTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/scene/shared/flag/SceneContainerFlagsTest.kt
@@ -27,6 +27,7 @@
import com.android.systemui.flags.ResourceBooleanFlag
import com.android.systemui.flags.UnreleasedFlag
import com.android.systemui.keyguard.shared.KeyguardShadeMigrationNssl
+import com.android.systemui.media.controls.util.MediaInSceneContainerFlag
import com.android.systemui.res.R
import com.google.common.truth.Truth.assertThat
import org.junit.Before
@@ -71,6 +72,7 @@
AconfigFlags.FLAG_SCENE_CONTAINER,
AconfigFlags.FLAG_KEYGUARD_BOTTOM_AREA_REFACTOR,
KeyguardShadeMigrationNssl.FLAG_NAME,
+ MediaInSceneContainerFlag.FLAG_NAME,
)
.forEach { flagToken ->
setFlagsRule.enableFlags(flagToken)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/events/SystemEventCoordinatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/events/SystemEventCoordinatorTest.kt
index bbc63f2..ae84df5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/events/SystemEventCoordinatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/events/SystemEventCoordinatorTest.kt
@@ -21,7 +21,6 @@
import com.android.systemui.SysuiTestCase
import com.android.systemui.display.domain.interactor.ConnectedDisplayInteractor
import com.android.systemui.display.domain.interactor.ConnectedDisplayInteractor.PendingDisplay
-import com.android.systemui.display.domain.interactor.ConnectedDisplayInteractor.State.CONNECTED
import com.android.systemui.privacy.PrivacyItemController
import com.android.systemui.statusbar.policy.BatteryController
import com.android.systemui.util.mockito.any
@@ -107,5 +106,7 @@
get() = flow
override val pendingDisplay: Flow<PendingDisplay?>
get() = MutableSharedFlow<PendingDisplay>()
+ override val concurrentDisplaysInProgress: Flow<Boolean>
+ get() = TODO("Not yet implemented")
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/domain/interactor/SharedNotificationContainerInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/domain/interactor/SharedNotificationContainerInteractorTest.kt
index 198f278..a07b570 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/domain/interactor/SharedNotificationContainerInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/domain/interactor/SharedNotificationContainerInteractorTest.kt
@@ -19,10 +19,10 @@
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
-import com.android.systemui.res.R
import com.android.systemui.SysuiTestCase
import com.android.systemui.common.ui.data.repository.FakeConfigurationRepository
import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.res.R
import com.android.systemui.statusbar.policy.ResourcesSplitShadeStateController
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.test.runCurrent
@@ -56,6 +56,7 @@
overrideResource(R.dimen.notification_panel_margin_bottom, 10)
overrideResource(R.dimen.notification_panel_margin_top, 10)
overrideResource(R.dimen.large_screen_shade_header_height, 0)
+ overrideResource(R.dimen.keyguard_split_shade_top_margin, 55)
val dimens = collectLastValue(underTest.configurationBasedDimensions)
@@ -70,5 +71,6 @@
assertThat(lastDimens.marginBottom).isGreaterThan(0)
assertThat(lastDimens.marginTop).isGreaterThan(0)
assertThat(lastDimens.marginTopLargeScreen).isEqualTo(0)
+ assertThat(lastDimens.keyguardSplitShadeTopMargin).isEqualTo(55)
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelTest.kt
index b4f7b20..2209e5e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelTest.kt
@@ -100,6 +100,34 @@
}
@Test
+ fun validatePaddingTopInSplitShade() =
+ testScope.runTest {
+ overrideResource(R.bool.config_use_split_notification_shade, true)
+ overrideResource(R.dimen.large_screen_shade_header_height, 10)
+ overrideResource(R.dimen.keyguard_split_shade_top_margin, 50)
+
+ val dimens by collectLastValue(underTest.configurationBasedDimensions)
+
+ configurationRepository.onAnyConfigurationChange()
+
+ assertThat(dimens!!.paddingTop).isEqualTo(30)
+ }
+
+ @Test
+ fun validatePaddingTop() =
+ testScope.runTest {
+ overrideResource(R.bool.config_use_split_notification_shade, false)
+ overrideResource(R.dimen.large_screen_shade_header_height, 10)
+ overrideResource(R.dimen.keyguard_split_shade_top_margin, 50)
+
+ val dimens by collectLastValue(underTest.configurationBasedDimensions)
+
+ configurationRepository.onAnyConfigurationChange()
+
+ assertThat(dimens!!.paddingTop).isEqualTo(0)
+ }
+
+ @Test
fun validateMarginEnd() =
testScope.runTest {
overrideResource(R.dimen.notification_panel_margin_horizontal, 50)
@@ -226,9 +254,9 @@
}
@Test
- fun positionOnLockscreenNotInSplitShade() =
+ fun boundsOnLockscreenNotInSplitShade() =
testScope.runTest {
- val position by collectLastValue(underTest.bounds)
+ val bounds by collectLastValue(underTest.bounds)
// When not in split shade
overrideResource(R.bool.config_use_split_notification_shade, false)
@@ -242,16 +270,19 @@
NotificationContainerBounds(top = 1f, bottom = 2f)
)
- assertThat(position).isEqualTo(NotificationContainerBounds(top = 1f, bottom = 2f))
+ assertThat(bounds).isEqualTo(NotificationContainerBounds(top = 1f, bottom = 2f))
}
@Test
- fun positionOnLockscreenInSplitShade() =
+ fun boundsOnLockscreenInSplitShade() =
testScope.runTest {
- val position by collectLastValue(underTest.bounds)
+ val bounds by collectLastValue(underTest.bounds)
// When in split shade
overrideResource(R.bool.config_use_split_notification_shade, true)
+ overrideResource(R.dimen.large_screen_shade_header_height, 10)
+ overrideResource(R.dimen.keyguard_split_shade_top_margin, 50)
+
configurationRepository.onAnyConfigurationChange()
runCurrent()
@@ -263,8 +294,8 @@
)
runCurrent()
- // Top should be overridden to 0f
- assertThat(position).isEqualTo(NotificationContainerBounds(top = 0f, bottom = 2f))
+ // Top should be equal to bounds (1) + padding adjustment (30)
+ assertThat(bounds).isEqualTo(NotificationContainerBounds(top = 31f, bottom = 2f))
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicyTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicyTest.kt
index da6c28a..7deee5a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicyTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicyTest.kt
@@ -321,5 +321,7 @@
get() = TODO("Not yet implemented")
override val pendingDisplay: Flow<PendingDisplay?>
get() = TODO("Not yet implemented")
+ override val concurrentDisplaysInProgress: Flow<Boolean>
+ get() = TODO("Not yet implemented")
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/InternetTileViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/InternetTileViewModelTest.kt
index 8405fb4..22dce3a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/InternetTileViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/InternetTileViewModelTest.kt
@@ -337,12 +337,12 @@
networkName.value = NetworkNameModel.Default("test network")
}
- assertThat(latest?.secondaryTitle).contains("test network")
+ assertThat(latest?.secondaryTitle.toString()).contains("test network")
assertThat(latest?.secondaryLabel).isNull()
assertThat(latest?.icon).isInstanceOf(SignalIcon::class.java)
assertThat(latest?.iconId).isNull()
assertThat(latest?.stateDescription.loadContentDescription(context))
- .isEqualTo(latest?.secondaryTitle)
+ .isEqualTo(latest?.secondaryTitle.toString())
assertThat(latest?.contentDescription.loadContentDescription(context))
.isEqualTo(internet)
}
diff --git a/core/java/android/window/ITrustedPresentationListener.aidl b/packages/SystemUI/tests/utils/src/android/view/accessibility/AccessibilityManagerKosmos.kt
similarity index 70%
copy from core/java/android/window/ITrustedPresentationListener.aidl
copy to packages/SystemUI/tests/utils/src/android/view/accessibility/AccessibilityManagerKosmos.kt
index b33128a..a11bf6a 100644
--- a/core/java/android/window/ITrustedPresentationListener.aidl
+++ b/packages/SystemUI/tests/utils/src/android/view/accessibility/AccessibilityManagerKosmos.kt
@@ -14,11 +14,10 @@
* limitations under the License.
*/
-package android.window;
+package android.view.accessibility
-/**
- * @hide
- */
-oneway interface ITrustedPresentationListener {
- void onTrustedPresentationChanged(in int[] enteredTrustedStateIds, in int[] exitedTrustedStateIds);
-}
\ No newline at end of file
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.Kosmos.Fixture
+import com.android.systemui.util.mockito.mock
+
+var Kosmos.accessibilityManager by Fixture { mock<AccessibilityManager>() }
diff --git a/core/java/android/window/ITrustedPresentationListener.aidl b/packages/SystemUI/tests/utils/src/com/android/internal/logging/MetricsLoggerKosmos.kt
similarity index 71%
copy from core/java/android/window/ITrustedPresentationListener.aidl
copy to packages/SystemUI/tests/utils/src/com/android/internal/logging/MetricsLoggerKosmos.kt
index b33128a..a1815c5 100644
--- a/core/java/android/window/ITrustedPresentationListener.aidl
+++ b/packages/SystemUI/tests/utils/src/com/android/internal/logging/MetricsLoggerKosmos.kt
@@ -14,11 +14,10 @@
* limitations under the License.
*/
-package android.window;
+package com.android.internal.logging
-/**
- * @hide
- */
-oneway interface ITrustedPresentationListener {
- void onTrustedPresentationChanged(in int[] enteredTrustedStateIds, in int[] exitedTrustedStateIds);
-}
\ No newline at end of file
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.Kosmos.Fixture
+import com.android.systemui.util.mockito.mock
+
+var Kosmos.metricsLogger by Fixture { mock<MetricsLogger>() }
diff --git a/core/java/android/window/ITrustedPresentationListener.aidl b/packages/SystemUI/tests/utils/src/com/android/internal/statusbar/StatusBarServiceKosmos.kt
similarity index 70%
copy from core/java/android/window/ITrustedPresentationListener.aidl
copy to packages/SystemUI/tests/utils/src/com/android/internal/statusbar/StatusBarServiceKosmos.kt
index b33128a..b1d67b8 100644
--- a/core/java/android/window/ITrustedPresentationListener.aidl
+++ b/packages/SystemUI/tests/utils/src/com/android/internal/statusbar/StatusBarServiceKosmos.kt
@@ -14,11 +14,10 @@
* limitations under the License.
*/
-package android.window;
+package com.android.internal.statusbar
-/**
- * @hide
- */
-oneway interface ITrustedPresentationListener {
- void onTrustedPresentationChanged(in int[] enteredTrustedStateIds, in int[] exitedTrustedStateIds);
-}
\ No newline at end of file
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.Kosmos.Fixture
+import com.android.systemui.util.mockito.mock
+
+var Kosmos.statusBarService by Fixture { mock<IStatusBarService>() }
diff --git a/core/java/android/window/ITrustedPresentationListener.aidl b/packages/SystemUI/tests/utils/src/com/android/systemui/accessibility/data/repository/AccessibilityRepositoryKosmos.kt
similarity index 64%
copy from core/java/android/window/ITrustedPresentationListener.aidl
copy to packages/SystemUI/tests/utils/src/com/android/systemui/accessibility/data/repository/AccessibilityRepositoryKosmos.kt
index b33128a..a464fa8 100644
--- a/core/java/android/window/ITrustedPresentationListener.aidl
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/accessibility/data/repository/AccessibilityRepositoryKosmos.kt
@@ -14,11 +14,12 @@
* limitations under the License.
*/
-package android.window;
+package com.android.systemui.accessibility.data.repository
-/**
- * @hide
- */
-oneway interface ITrustedPresentationListener {
- void onTrustedPresentationChanged(in int[] enteredTrustedStateIds, in int[] exitedTrustedStateIds);
-}
\ No newline at end of file
+import android.view.accessibility.accessibilityManager
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.Kosmos.Fixture
+
+val Kosmos.accessibilityRepository by Fixture {
+ AccessibilityRepository.invoke(a11yManager = accessibilityManager)
+}
diff --git a/core/java/android/window/ITrustedPresentationListener.aidl b/packages/SystemUI/tests/utils/src/com/android/systemui/accessibility/domain/interactor/AccessibilityInteractorKosmos.kt
similarity index 62%
copy from core/java/android/window/ITrustedPresentationListener.aidl
copy to packages/SystemUI/tests/utils/src/com/android/systemui/accessibility/domain/interactor/AccessibilityInteractorKosmos.kt
index b33128a..a48fe0a 100644
--- a/core/java/android/window/ITrustedPresentationListener.aidl
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/accessibility/domain/interactor/AccessibilityInteractorKosmos.kt
@@ -14,11 +14,14 @@
* limitations under the License.
*/
-package android.window;
+package com.android.systemui.accessibility.domain.interactor
-/**
- * @hide
- */
-oneway interface ITrustedPresentationListener {
- void onTrustedPresentationChanged(in int[] enteredTrustedStateIds, in int[] exitedTrustedStateIds);
-}
\ No newline at end of file
+import com.android.systemui.accessibility.data.repository.accessibilityRepository
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.Kosmos.Fixture
+
+val Kosmos.accessibilityInteractor by Fixture {
+ AccessibilityInteractor(
+ a11yRepo = accessibilityRepository,
+ )
+}
diff --git a/core/java/android/window/ITrustedPresentationListener.aidl b/packages/SystemUI/tests/utils/src/com/android/systemui/classifier/FalsingManagerFakeKosmos.kt
similarity index 75%
rename from core/java/android/window/ITrustedPresentationListener.aidl
rename to packages/SystemUI/tests/utils/src/com/android/systemui/classifier/FalsingManagerFakeKosmos.kt
index b33128a..72e1e8e 100644
--- a/core/java/android/window/ITrustedPresentationListener.aidl
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/classifier/FalsingManagerFakeKosmos.kt
@@ -14,11 +14,8 @@
* limitations under the License.
*/
-package android.window;
+package com.android.systemui.classifier
-/**
- * @hide
- */
-oneway interface ITrustedPresentationListener {
- void onTrustedPresentationChanged(in int[] enteredTrustedStateIds, in int[] exitedTrustedStateIds);
-}
\ No newline at end of file
+import com.android.systemui.kosmos.Kosmos
+
+val Kosmos.fakeFalsingManager by Kosmos.Fixture { FalsingManagerFake() }
diff --git a/core/java/android/window/ITrustedPresentationListener.aidl b/packages/SystemUI/tests/utils/src/com/android/systemui/classifier/FalsingManagerKosmos.kt
similarity index 75%
copy from core/java/android/window/ITrustedPresentationListener.aidl
copy to packages/SystemUI/tests/utils/src/com/android/systemui/classifier/FalsingManagerKosmos.kt
index b33128a..366db9c 100644
--- a/core/java/android/window/ITrustedPresentationListener.aidl
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/classifier/FalsingManagerKosmos.kt
@@ -14,11 +14,9 @@
* limitations under the License.
*/
-package android.window;
+package com.android.systemui.classifier
-/**
- * @hide
- */
-oneway interface ITrustedPresentationListener {
- void onTrustedPresentationChanged(in int[] enteredTrustedStateIds, in int[] exitedTrustedStateIds);
-}
\ No newline at end of file
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.Kosmos.Fixture
+
+val Kosmos.falsingManager by Fixture { fakeFalsingManager }
diff --git a/core/java/android/window/ITrustedPresentationListener.aidl b/packages/SystemUI/tests/utils/src/com/android/systemui/common/domain/interactor/ConfigurationInteractorKosmos.kt
similarity index 63%
copy from core/java/android/window/ITrustedPresentationListener.aidl
copy to packages/SystemUI/tests/utils/src/com/android/systemui/common/domain/interactor/ConfigurationInteractorKosmos.kt
index b33128a..94d9a72 100644
--- a/core/java/android/window/ITrustedPresentationListener.aidl
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/common/domain/interactor/ConfigurationInteractorKosmos.kt
@@ -14,11 +14,12 @@
* limitations under the License.
*/
-package android.window;
+package com.android.systemui.common.domain.interactor
-/**
- * @hide
- */
-oneway interface ITrustedPresentationListener {
- void onTrustedPresentationChanged(in int[] enteredTrustedStateIds, in int[] exitedTrustedStateIds);
-}
\ No newline at end of file
+import com.android.systemui.common.ui.data.repository.configurationRepository
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.Kosmos.Fixture
+
+val Kosmos.configurationInteractor by Fixture {
+ ConfigurationInteractorImpl(repository = configurationRepository)
+}
diff --git a/core/java/android/window/ITrustedPresentationListener.aidl b/packages/SystemUI/tests/utils/src/com/android/systemui/concurrency/FakeExecutorKosmos.kt
similarity index 68%
copy from core/java/android/window/ITrustedPresentationListener.aidl
copy to packages/SystemUI/tests/utils/src/com/android/systemui/concurrency/FakeExecutorKosmos.kt
index b33128a..ea887ea 100644
--- a/core/java/android/window/ITrustedPresentationListener.aidl
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/concurrency/FakeExecutorKosmos.kt
@@ -14,11 +14,10 @@
* limitations under the License.
*/
-package android.window;
+package com.android.systemui.concurrency
-/**
- * @hide
- */
-oneway interface ITrustedPresentationListener {
- void onTrustedPresentationChanged(in int[] enteredTrustedStateIds, in int[] exitedTrustedStateIds);
-}
\ No newline at end of file
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.util.concurrency.FakeExecutor
+import com.android.systemui.util.time.fakeSystemClock
+
+var Kosmos.fakeExecutor by Kosmos.Fixture { FakeExecutor(fakeSystemClock) }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/display/data/repository/FakeDeviceStateRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/display/data/repository/FakeDeviceStateRepository.kt
new file mode 100644
index 0000000..5f6dc6e
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/display/data/repository/FakeDeviceStateRepository.kt
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.display.data.repository
+
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.StateFlow
+
+/** Fake [DeviceStateRepository] implementation for testing. */
+class FakeDeviceStateRepository : DeviceStateRepository {
+ private val flow = MutableStateFlow(DeviceStateRepository.DeviceState.UNKNOWN)
+
+ /** Emits [value] as [displays] flow value. */
+ suspend fun emit(value: DeviceStateRepository.DeviceState) = flow.emit(value)
+
+ override val state: StateFlow<DeviceStateRepository.DeviceState>
+ get() = flow
+}
diff --git a/core/java/android/window/ITrustedPresentationListener.aidl b/packages/SystemUI/tests/utils/src/com/android/systemui/dump/DumpManagerKosmos.kt
similarity index 72%
copy from core/java/android/window/ITrustedPresentationListener.aidl
copy to packages/SystemUI/tests/utils/src/com/android/systemui/dump/DumpManagerKosmos.kt
index b33128a..7a6edd0 100644
--- a/core/java/android/window/ITrustedPresentationListener.aidl
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/dump/DumpManagerKosmos.kt
@@ -14,11 +14,10 @@
* limitations under the License.
*/
-package android.window;
+package com.android.systemui.dump
-/**
- * @hide
- */
-oneway interface ITrustedPresentationListener {
- void onTrustedPresentationChanged(in int[] enteredTrustedStateIds, in int[] exitedTrustedStateIds);
-}
\ No newline at end of file
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.Kosmos.Fixture
+import com.android.systemui.util.mockito.mock
+
+var Kosmos.dumpManager by Fixture { mock<DumpManager>() }
diff --git a/core/java/android/window/ITrustedPresentationListener.aidl b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/WakefulnessLifecycleKosmos.kt
similarity index 70%
copy from core/java/android/window/ITrustedPresentationListener.aidl
copy to packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/WakefulnessLifecycleKosmos.kt
index b33128a..934ea5f 100644
--- a/core/java/android/window/ITrustedPresentationListener.aidl
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/WakefulnessLifecycleKosmos.kt
@@ -14,11 +14,10 @@
* limitations under the License.
*/
-package android.window;
+package com.android.systemui.keyguard
-/**
- * @hide
- */
-oneway interface ITrustedPresentationListener {
- void onTrustedPresentationChanged(in int[] enteredTrustedStateIds, in int[] exitedTrustedStateIds);
-}
\ No newline at end of file
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.Kosmos.Fixture
+import com.android.systemui.util.mockito.mock
+
+var Kosmos.wakefulnessLifecycle by Fixture { mock<WakefulnessLifecycle>() }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardRepository.kt
index 81a7bec..0e7c662 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardRepository.kt
@@ -119,6 +119,8 @@
private val _keyguardAlpha = MutableStateFlow(1f)
override val keyguardAlpha: StateFlow<Float> = _keyguardAlpha
+ override val lastRootViewTapPosition: MutableStateFlow<Point?> = MutableStateFlow(null)
+
override fun setQuickSettingsVisible(isVisible: Boolean) {
_isQuickSettingsVisible.value = isVisible
}
diff --git a/core/java/android/window/ITrustedPresentationListener.aidl b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/NaturalScrollingSettingObserverKosmos.kt
similarity index 67%
copy from core/java/android/window/ITrustedPresentationListener.aidl
copy to packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/NaturalScrollingSettingObserverKosmos.kt
index b33128a..61fc6c7 100644
--- a/core/java/android/window/ITrustedPresentationListener.aidl
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/NaturalScrollingSettingObserverKosmos.kt
@@ -14,11 +14,10 @@
* limitations under the License.
*/
-package android.window;
+package com.android.systemui.keyguard.domain.interactor
-/**
- * @hide
- */
-oneway interface ITrustedPresentationListener {
- void onTrustedPresentationChanged(in int[] enteredTrustedStateIds, in int[] exitedTrustedStateIds);
-}
\ No newline at end of file
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.Kosmos.Fixture
+import com.android.systemui.util.mockito.mock
+
+var Kosmos.naturalScrollingSettingObserver by Fixture { mock<NaturalScrollingSettingObserver>() }
diff --git a/core/java/android/window/ITrustedPresentationListener.aidl b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/tiles/impl/uimodenight/UiModeNightTileKosmos.kt
similarity index 65%
copy from core/java/android/window/ITrustedPresentationListener.aidl
copy to packages/SystemUI/tests/utils/src/com/android/systemui/qs/tiles/impl/uimodenight/UiModeNightTileKosmos.kt
index b33128a..f0e5807 100644
--- a/core/java/android/window/ITrustedPresentationListener.aidl
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/tiles/impl/uimodenight/UiModeNightTileKosmos.kt
@@ -14,11 +14,11 @@
* limitations under the License.
*/
-package android.window;
+package com.android.systemui.qs.tiles.impl.uimodenight
-/**
- * @hide
- */
-oneway interface ITrustedPresentationListener {
- void onTrustedPresentationChanged(in int[] enteredTrustedStateIds, in int[] exitedTrustedStateIds);
-}
\ No newline at end of file
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.qs.qsEventLogger
+import com.android.systemui.statusbar.policy.PolicyModule
+
+val Kosmos.qsUiModeNightTileConfig by
+ Kosmos.Fixture { PolicyModule.provideUiModeNightTileConfig(qsEventLogger) }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/tiles/impl/uimodenight/UiModeNightTileModelHelper.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/tiles/impl/uimodenight/UiModeNightTileModelHelper.kt
new file mode 100644
index 0000000..1fe18e3
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/tiles/impl/uimodenight/UiModeNightTileModelHelper.kt
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.qs.tiles.impl.uimodenight
+
+import android.content.res.Configuration
+import com.android.systemui.qs.tiles.impl.uimodenight.domain.model.UiModeNightTileModel
+import java.time.LocalTime
+
+object UiModeNightTileModelHelper {
+
+ const val DEFAULT_NIGHT_MODE_CUSTOM_TYPE = 0
+ val defaultCustomNightEnd: LocalTime = LocalTime.MAX
+ val defaultCustomNightStart: LocalTime = LocalTime.MIN
+
+ fun createModel(
+ nightMode: Boolean = false,
+ powerSave: Boolean = false,
+ uiMode: Int = Configuration.UI_MODE_NIGHT_NO,
+ isLocationEnabled: Boolean = true,
+ nighModeCustomType: Int = DEFAULT_NIGHT_MODE_CUSTOM_TYPE,
+ is24HourFormat: Boolean = false,
+ customNightModeEnd: LocalTime = defaultCustomNightEnd,
+ customNightModeStart: LocalTime = defaultCustomNightStart
+ ): UiModeNightTileModel {
+ return UiModeNightTileModel(
+ uiMode,
+ nightMode,
+ powerSave,
+ isLocationEnabled,
+ nighModeCustomType,
+ is24HourFormat,
+ customNightModeEnd,
+ customNightModeStart
+ )
+ }
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/scene/data/repository/WindowRootViewVisibilityRepositoryKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/scene/data/repository/WindowRootViewVisibilityRepositoryKosmos.kt
new file mode 100644
index 0000000..11871d5
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/scene/data/repository/WindowRootViewVisibilityRepositoryKosmos.kt
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.scene.data.repository
+
+import com.android.internal.statusbar.statusBarService
+import com.android.systemui.concurrency.fakeExecutor
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.Kosmos.Fixture
+
+val Kosmos.windowRootViewVisibilityRepository by Fixture {
+ WindowRootViewVisibilityRepository(
+ statusBarService = statusBarService,
+ uiBgExecutor = fakeExecutor,
+ )
+}
diff --git a/core/java/android/window/ITrustedPresentationListener.aidl b/packages/SystemUI/tests/utils/src/com/android/systemui/shade/transition/LargeScreenShadeInterpolatorKosmos.kt
similarity index 68%
copy from core/java/android/window/ITrustedPresentationListener.aidl
copy to packages/SystemUI/tests/utils/src/com/android/systemui/shade/transition/LargeScreenShadeInterpolatorKosmos.kt
index b33128a..e50d59e 100644
--- a/core/java/android/window/ITrustedPresentationListener.aidl
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/shade/transition/LargeScreenShadeInterpolatorKosmos.kt
@@ -14,11 +14,10 @@
* limitations under the License.
*/
-package android.window;
+package com.android.systemui.shade.transition
-/**
- * @hide
- */
-oneway interface ITrustedPresentationListener {
- void onTrustedPresentationChanged(in int[] enteredTrustedStateIds, in int[] exitedTrustedStateIds);
-}
\ No newline at end of file
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.Kosmos.Fixture
+import com.android.systemui.util.mockito.mock
+
+var Kosmos.largeScreenShadeInterpolator by Fixture { mock<LargeScreenShadeInterpolator>() }
diff --git a/core/java/android/window/ITrustedPresentationListener.aidl b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/LockscreenShadeKeyguardTransitionControllerKosmos.kt
similarity index 65%
copy from core/java/android/window/ITrustedPresentationListener.aidl
copy to packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/LockscreenShadeKeyguardTransitionControllerKosmos.kt
index b33128a..e5a75d5 100644
--- a/core/java/android/window/ITrustedPresentationListener.aidl
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/LockscreenShadeKeyguardTransitionControllerKosmos.kt
@@ -14,11 +14,12 @@
* limitations under the License.
*/
-package android.window;
+package com.android.systemui.statusbar
-/**
- * @hide
- */
-oneway interface ITrustedPresentationListener {
- void onTrustedPresentationChanged(in int[] enteredTrustedStateIds, in int[] exitedTrustedStateIds);
-}
\ No newline at end of file
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.Kosmos.Fixture
+import com.android.systemui.util.mockito.mock
+
+var Kosmos.lockscreenShadeKeyguardTransitionControllerFactory by Fixture {
+ mock<LockscreenShadeKeyguardTransitionController.Factory>()
+}
diff --git a/core/java/android/window/ITrustedPresentationListener.aidl b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/LockscreenShadeQsTransitionControllerKosmos.kt
similarity index 66%
copy from core/java/android/window/ITrustedPresentationListener.aidl
copy to packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/LockscreenShadeQsTransitionControllerKosmos.kt
index b33128a..2767980 100644
--- a/core/java/android/window/ITrustedPresentationListener.aidl
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/LockscreenShadeQsTransitionControllerKosmos.kt
@@ -14,11 +14,12 @@
* limitations under the License.
*/
-package android.window;
+package com.android.systemui.statusbar
-/**
- * @hide
- */
-oneway interface ITrustedPresentationListener {
- void onTrustedPresentationChanged(in int[] enteredTrustedStateIds, in int[] exitedTrustedStateIds);
-}
\ No newline at end of file
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.Kosmos.Fixture
+import com.android.systemui.util.mockito.mock
+
+var Kosmos.lockscreenShadeQsTransitionControllerFactory by Fixture {
+ mock<LockscreenShadeQsTransitionController.Factory>()
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/LockscreenShadeScrimTransitionControllerKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/LockscreenShadeScrimTransitionControllerKosmos.kt
new file mode 100644
index 0000000..93a7adf
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/LockscreenShadeScrimTransitionControllerKosmos.kt
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar
+
+import android.content.testableContext
+import com.android.systemui.dump.dumpManager
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.Kosmos.Fixture
+import com.android.systemui.statusbar.phone.scrimController
+import com.android.systemui.statusbar.policy.configurationController
+import com.android.systemui.statusbar.policy.splitShadeStateController
+
+val Kosmos.lockscreenShadeScrimTransitionController by Fixture {
+ LockscreenShadeScrimTransitionController(
+ scrimController = scrimController,
+ context = testableContext,
+ configurationController = configurationController,
+ dumpManager = dumpManager,
+ splitShadeStateController = splitShadeStateController,
+ )
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerKosmos.kt
new file mode 100644
index 0000000..2752cc2
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerKosmos.kt
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar
+
+import android.content.testableContext
+import com.android.systemui.classifier.falsingCollector
+import com.android.systemui.classifier.falsingManager
+import com.android.systemui.dump.dumpManager
+import com.android.systemui.keyguard.domain.interactor.naturalScrollingSettingObserver
+import com.android.systemui.keyguard.wakefulnessLifecycle
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.Kosmos.Fixture
+import com.android.systemui.media.controls.ui.mediaHierarchyManager
+import com.android.systemui.plugins.activityStarter
+import com.android.systemui.power.domain.interactor.powerInteractor
+import com.android.systemui.shade.data.repository.shadeRepository
+import com.android.systemui.shade.domain.interactor.shadeInteractor
+import com.android.systemui.statusbar.notification.stack.ambientState
+import com.android.systemui.statusbar.phone.keyguardBypassController
+import com.android.systemui.statusbar.phone.lsShadeTransitionLogger
+import com.android.systemui.statusbar.policy.configurationController
+import com.android.systemui.statusbar.policy.splitShadeStateController
+
+val Kosmos.lockscreenShadeTransitionController by Fixture {
+ LockscreenShadeTransitionController(
+ statusBarStateController = sysuiStatusBarStateController,
+ logger = lsShadeTransitionLogger,
+ keyguardBypassController = keyguardBypassController,
+ lockScreenUserManager = notificationLockscreenUserManager,
+ falsingCollector = falsingCollector,
+ ambientState = ambientState,
+ mediaHierarchyManager = mediaHierarchyManager,
+ scrimTransitionController = lockscreenShadeScrimTransitionController,
+ keyguardTransitionControllerFactory = lockscreenShadeKeyguardTransitionControllerFactory,
+ depthController = notificationShadeDepthController,
+ context = testableContext,
+ splitShadeOverScrollerFactory = splitShadeLockScreenOverScrollerFactory,
+ singleShadeOverScrollerFactory = singleShadeLockScreenOverScrollerFactory,
+ activityStarter = activityStarter,
+ wakefulnessLifecycle = wakefulnessLifecycle,
+ configurationController = configurationController,
+ falsingManager = falsingManager,
+ dumpManager = dumpManager,
+ qsTransitionControllerFactory = lockscreenShadeQsTransitionControllerFactory,
+ shadeRepository = shadeRepository,
+ shadeInteractor = shadeInteractor,
+ powerInteractor = powerInteractor,
+ splitShadeStateController = splitShadeStateController,
+ naturalScrollingSettingObserver = naturalScrollingSettingObserver,
+ )
+}
diff --git a/core/java/android/window/ITrustedPresentationListener.aidl b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/MediaHierarchyManagerKosmos.kt
similarity index 69%
copy from core/java/android/window/ITrustedPresentationListener.aidl
copy to packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/MediaHierarchyManagerKosmos.kt
index b33128a..db2cdfa 100644
--- a/core/java/android/window/ITrustedPresentationListener.aidl
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/MediaHierarchyManagerKosmos.kt
@@ -14,11 +14,10 @@
* limitations under the License.
*/
-package android.window;
+package com.android.systemui.media.controls.ui
-/**
- * @hide
- */
-oneway interface ITrustedPresentationListener {
- void onTrustedPresentationChanged(in int[] enteredTrustedStateIds, in int[] exitedTrustedStateIds);
-}
\ No newline at end of file
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.Kosmos.Fixture
+import com.android.systemui.util.mockito.mock
+
+var Kosmos.mediaHierarchyManager by Fixture { mock<MediaHierarchyManager>() }
diff --git a/core/java/android/window/ITrustedPresentationListener.aidl b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerKosmos.kt
similarity index 68%
copy from core/java/android/window/ITrustedPresentationListener.aidl
copy to packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerKosmos.kt
index b33128a..3743812 100644
--- a/core/java/android/window/ITrustedPresentationListener.aidl
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerKosmos.kt
@@ -14,11 +14,12 @@
* limitations under the License.
*/
-package android.window;
+package com.android.systemui.statusbar
-/**
- * @hide
- */
-oneway interface ITrustedPresentationListener {
- void onTrustedPresentationChanged(in int[] enteredTrustedStateIds, in int[] exitedTrustedStateIds);
-}
\ No newline at end of file
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.Kosmos.Fixture
+import com.android.systemui.util.mockito.mock
+
+var Kosmos.notificationLockscreenUserManager by Fixture {
+ mock<NotificationLockscreenUserManager>()
+}
diff --git a/core/java/android/window/ITrustedPresentationListener.aidl b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/NotificationShadeDepthControllerKosmos.kt
similarity index 68%
copy from core/java/android/window/ITrustedPresentationListener.aidl
copy to packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/NotificationShadeDepthControllerKosmos.kt
index b33128a..3960cd1 100644
--- a/core/java/android/window/ITrustedPresentationListener.aidl
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/NotificationShadeDepthControllerKosmos.kt
@@ -14,11 +14,10 @@
* limitations under the License.
*/
-package android.window;
+package com.android.systemui.statusbar
-/**
- * @hide
- */
-oneway interface ITrustedPresentationListener {
- void onTrustedPresentationChanged(in int[] enteredTrustedStateIds, in int[] exitedTrustedStateIds);
-}
\ No newline at end of file
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.Kosmos.Fixture
+import com.android.systemui.util.mockito.mock
+
+var Kosmos.notificationShadeDepthController by Fixture { mock<NotificationShadeDepthController>() }
diff --git a/core/java/android/window/ITrustedPresentationListener.aidl b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/SingleShadeLockScreenOverScrollerKosmos.kt
similarity index 66%
copy from core/java/android/window/ITrustedPresentationListener.aidl
copy to packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/SingleShadeLockScreenOverScrollerKosmos.kt
index b33128a..43e39c0 100644
--- a/core/java/android/window/ITrustedPresentationListener.aidl
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/SingleShadeLockScreenOverScrollerKosmos.kt
@@ -14,11 +14,12 @@
* limitations under the License.
*/
-package android.window;
+package com.android.systemui.statusbar
-/**
- * @hide
- */
-oneway interface ITrustedPresentationListener {
- void onTrustedPresentationChanged(in int[] enteredTrustedStateIds, in int[] exitedTrustedStateIds);
-}
\ No newline at end of file
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.Kosmos.Fixture
+import com.android.systemui.util.mockito.mock
+
+var Kosmos.singleShadeLockScreenOverScrollerFactory by Fixture {
+ mock<SingleShadeLockScreenOverScroller.Factory>()
+}
diff --git a/core/java/android/window/ITrustedPresentationListener.aidl b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/SplitShadeLockScreenOverScrollerKosmos.kt
similarity index 67%
copy from core/java/android/window/ITrustedPresentationListener.aidl
copy to packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/SplitShadeLockScreenOverScrollerKosmos.kt
index b33128a..017371a 100644
--- a/core/java/android/window/ITrustedPresentationListener.aidl
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/SplitShadeLockScreenOverScrollerKosmos.kt
@@ -14,11 +14,12 @@
* limitations under the License.
*/
-package android.window;
+package com.android.systemui.statusbar
-/**
- * @hide
- */
-oneway interface ITrustedPresentationListener {
- void onTrustedPresentationChanged(in int[] enteredTrustedStateIds, in int[] exitedTrustedStateIds);
-}
\ No newline at end of file
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.Kosmos.Fixture
+import com.android.systemui.util.mockito.mock
+
+var Kosmos.splitShadeLockScreenOverScrollerFactory by Fixture {
+ mock<SplitShadeLockScreenOverScroller.Factory>()
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/domain/interactor/SeenNotificationsInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/domain/interactor/SeenNotificationsInteractorKosmos.kt
new file mode 100644
index 0000000..c1e0419
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/domain/interactor/SeenNotificationsInteractorKosmos.kt
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.notification.domain.interactor
+
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.Kosmos.Fixture
+import com.android.systemui.statusbar.notification.data.repository.activeNotificationListRepository
+
+val Kosmos.seenNotificationsInteractor by Fixture {
+ SeenNotificationsInteractor(
+ notificationListRepository = activeNotificationListRepository,
+ )
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/footer/ui/viewmodel/FooterViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/footer/ui/viewmodel/FooterViewModelKosmos.kt
new file mode 100644
index 0000000..ff22ca0
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/footer/ui/viewmodel/FooterViewModelKosmos.kt
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.notification.footer.ui.viewmodel
+
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.Kosmos.Fixture
+import com.android.systemui.shade.domain.interactor.shadeInteractor
+import com.android.systemui.statusbar.notification.domain.interactor.activeNotificationsInteractor
+import com.android.systemui.statusbar.notification.domain.interactor.seenNotificationsInteractor
+
+val Kosmos.footerViewModel by Fixture {
+ FooterViewModel(
+ activeNotificationsInteractor = activeNotificationsInteractor,
+ seenNotificationsInteractor = seenNotificationsInteractor,
+ shadeInteractor = shadeInteractor,
+ )
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/icon/domain/interactor/NotificationIconsInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/icon/domain/interactor/NotificationIconsInteractorKosmos.kt
index e7bd5ea..5c8fe0d 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/icon/domain/interactor/NotificationIconsInteractorKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/icon/domain/interactor/NotificationIconsInteractorKosmos.kt
@@ -20,31 +20,29 @@
import com.android.systemui.deviceentry.domain.interactor.deviceEntryInteractor
import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.Kosmos.Fixture
import com.android.systemui.statusbar.data.repository.notificationListenerSettingsRepository
import com.android.systemui.statusbar.notification.data.repository.notificationsKeyguardViewStateRepository
import com.android.systemui.statusbar.notification.domain.interactor.activeNotificationsInteractor
import com.android.wm.shell.bubbles.bubblesOptional
import kotlinx.coroutines.ExperimentalCoroutinesApi
-val Kosmos.alwaysOnDisplayNotificationIconsInteractor by
- Kosmos.Fixture {
- AlwaysOnDisplayNotificationIconsInteractor(
- deviceEntryInteractor = deviceEntryInteractor,
- iconsInteractor = notificationIconsInteractor,
- )
- }
-val Kosmos.statusBarNotificationIconsInteractor by
- Kosmos.Fixture {
- StatusBarNotificationIconsInteractor(
- iconsInteractor = notificationIconsInteractor,
- settingsRepository = notificationListenerSettingsRepository,
- )
- }
-val Kosmos.notificationIconsInteractor by
- Kosmos.Fixture {
- NotificationIconsInteractor(
- activeNotificationsInteractor = activeNotificationsInteractor,
- bubbles = bubblesOptional,
- keyguardViewStateRepository = notificationsKeyguardViewStateRepository,
- )
- }
+val Kosmos.alwaysOnDisplayNotificationIconsInteractor by Fixture {
+ AlwaysOnDisplayNotificationIconsInteractor(
+ deviceEntryInteractor = deviceEntryInteractor,
+ iconsInteractor = notificationIconsInteractor,
+ )
+}
+val Kosmos.statusBarNotificationIconsInteractor by Fixture {
+ StatusBarNotificationIconsInteractor(
+ iconsInteractor = notificationIconsInteractor,
+ settingsRepository = notificationListenerSettingsRepository,
+ )
+}
+val Kosmos.notificationIconsInteractor by Fixture {
+ NotificationIconsInteractor(
+ activeNotificationsInteractor = activeNotificationsInteractor,
+ bubbles = bubblesOptional,
+ keyguardViewStateRepository = notificationsKeyguardViewStateRepository,
+ )
+}
diff --git a/core/java/android/window/ITrustedPresentationListener.aidl b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/icon/ui/viewbinder/ShelfNotificationIconViewStoreKosmos.kt
similarity index 61%
copy from core/java/android/window/ITrustedPresentationListener.aidl
copy to packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/icon/ui/viewbinder/ShelfNotificationIconViewStoreKosmos.kt
index b33128a..f7f16a4 100644
--- a/core/java/android/window/ITrustedPresentationListener.aidl
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/icon/ui/viewbinder/ShelfNotificationIconViewStoreKosmos.kt
@@ -14,11 +14,12 @@
* limitations under the License.
*/
-package android.window;
+package com.android.systemui.statusbar.notification.icon.ui.viewbinder
-/**
- * @hide
- */
-oneway interface ITrustedPresentationListener {
- void onTrustedPresentationChanged(in int[] enteredTrustedStateIds, in int[] exitedTrustedStateIds);
-}
\ No newline at end of file
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.Kosmos.Fixture
+import com.android.systemui.statusbar.notification.stack.ui.viewbinder.notifCollection
+
+val Kosmos.shelfNotificationIconViewStore by Fixture {
+ ShelfNotificationIconViewStore(notifCollection = notifCollection)
+}
diff --git a/core/java/android/window/ITrustedPresentationListener.aidl b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/icon/ui/viewbinder/StatusBarIconViewBindingFailureTrackerKosmos.kt
similarity index 68%
copy from core/java/android/window/ITrustedPresentationListener.aidl
copy to packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/icon/ui/viewbinder/StatusBarIconViewBindingFailureTrackerKosmos.kt
index b33128a..dbd7c6b 100644
--- a/core/java/android/window/ITrustedPresentationListener.aidl
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/icon/ui/viewbinder/StatusBarIconViewBindingFailureTrackerKosmos.kt
@@ -14,11 +14,11 @@
* limitations under the License.
*/
-package android.window;
+package com.android.systemui.statusbar.notification.icon.ui.viewbinder
-/**
- * @hide
- */
-oneway interface ITrustedPresentationListener {
- void onTrustedPresentationChanged(in int[] enteredTrustedStateIds, in int[] exitedTrustedStateIds);
-}
\ No newline at end of file
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.Kosmos.Fixture
+
+val Kosmos.statusBarIconViewBindingFailureTracker by Fixture {
+ StatusBarIconViewBindingFailureTracker()
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerShelfViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerShelfViewModelKosmos.kt
new file mode 100644
index 0000000..d679bb6
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerShelfViewModelKosmos.kt
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.notification.icon.ui.viewmodel
+
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.statusbar.notification.icon.domain.interactor.notificationIconsInteractor
+
+val Kosmos.notificationIconContainerShelfViewModel by
+ Kosmos.Fixture {
+ NotificationIconContainerShelfViewModel(
+ interactor = notificationIconsInteractor,
+ )
+ }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/row/ui/viewmodel/ActivatableNotificationViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/row/ui/viewmodel/ActivatableNotificationViewModelKosmos.kt
new file mode 100644
index 0000000..2523975
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/row/ui/viewmodel/ActivatableNotificationViewModelKosmos.kt
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.notification.row.ui.viewmodel
+
+import com.android.systemui.accessibility.domain.interactor.accessibilityInteractor
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.Kosmos.Fixture
+
+val Kosmos.activatableNotificationViewModel by Fixture {
+ ActivatableNotificationViewModel.invoke(
+ a11yInteractor = accessibilityInteractor,
+ )
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/shelf/domain/interactor/NotificationShelfInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/shelf/domain/interactor/NotificationShelfInteractorKosmos.kt
new file mode 100644
index 0000000..2057b84
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/shelf/domain/interactor/NotificationShelfInteractorKosmos.kt
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.notification.shelf.domain.interactor
+
+import com.android.systemui.keyguard.data.repository.deviceEntryFaceAuthRepository
+import com.android.systemui.keyguard.data.repository.keyguardRepository
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.Kosmos.Fixture
+import com.android.systemui.power.domain.interactor.powerInteractor
+import com.android.systemui.statusbar.lockscreenShadeTransitionController
+
+val Kosmos.notificationShelfInteractor by Fixture {
+ NotificationShelfInteractor(
+ keyguardRepository = keyguardRepository,
+ deviceEntryFaceAuthRepository = deviceEntryFaceAuthRepository,
+ powerInteractor = powerInteractor,
+ keyguardTransitionController = lockscreenShadeTransitionController,
+ )
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/shelf/ui/viewmodel/NotificationShelfViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/shelf/ui/viewmodel/NotificationShelfViewModelKosmos.kt
new file mode 100644
index 0000000..988172c
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/shelf/ui/viewmodel/NotificationShelfViewModelKosmos.kt
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.notification.shelf.ui.viewmodel
+
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.Kosmos.Fixture
+import com.android.systemui.statusbar.notification.icon.ui.viewmodel.notificationIconContainerShelfViewModel
+import com.android.systemui.statusbar.notification.row.ui.viewmodel.activatableNotificationViewModel
+import com.android.systemui.statusbar.notification.shelf.domain.interactor.notificationShelfInteractor
+
+val Kosmos.notificationShelfViewModel by Fixture {
+ NotificationShelfViewModel(
+ interactor = notificationShelfInteractor,
+ activatableViewModel = activatableNotificationViewModel,
+ icons = notificationIconContainerShelfViewModel,
+ )
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/AmbientStateKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/AmbientStateKosmos.kt
new file mode 100644
index 0000000..83ac330
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/AmbientStateKosmos.kt
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.notification.stack
+
+import android.content.testableContext
+import com.android.systemui.dump.dumpManager
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.Kosmos.Fixture
+import com.android.systemui.shade.transition.largeScreenShadeInterpolator
+import com.android.systemui.statusbar.phone.statusBarKeyguardViewManager
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+
+@OptIn(ExperimentalCoroutinesApi::class)
+val Kosmos.ambientState by Fixture {
+ AmbientState(
+ /*context=*/ testableContext,
+ /*dumpManager=*/ dumpManager,
+ /*sectionProvider=*/ stackScrollAlgorithmSectionProvider,
+ /*bypassController=*/ stackScrollAlgorithmBypassController,
+ /*statusBarKeyguardViewManager=*/ statusBarKeyguardViewManager,
+ /*largeScreenShadeInterpolator=*/ largeScreenShadeInterpolator,
+ )
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithmKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithmKosmos.kt
new file mode 100644
index 0000000..67343c95
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithmKosmos.kt
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.notification.stack
+
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.Kosmos.Fixture
+import com.android.systemui.util.mockito.mock
+
+var Kosmos.stackScrollAlgorithmSectionProvider by Fixture {
+ mock<StackScrollAlgorithm.SectionProvider>()
+}
+
+var Kosmos.stackScrollAlgorithmBypassController by Fixture {
+ mock<StackScrollAlgorithm.BypassController>()
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/domain/interactor/HideNotificationsInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/domain/interactor/HideNotificationsInteractorKosmos.kt
new file mode 100644
index 0000000..baca8b2
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/domain/interactor/HideNotificationsInteractorKosmos.kt
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.notification.stack.domain.interactor
+
+import com.android.systemui.common.domain.interactor.configurationInteractor
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.Kosmos.Fixture
+import com.android.systemui.power.domain.interactor.powerInteractor
+import com.android.systemui.unfold.domain.interactor.unfoldTransitionInteractor
+import com.android.systemui.util.animation.data.repository.animationStatusRepository
+
+val Kosmos.hideNotificationsInteractor by Fixture {
+ HideNotificationsInteractor(
+ unfoldTransitionInteractor = unfoldTransitionInteractor,
+ configurationInteractor = configurationInteractor,
+ animationsStatus = animationStatusRepository,
+ powerInteractor = powerInteractor,
+ )
+}
diff --git a/core/java/android/window/ITrustedPresentationListener.aidl b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/NotifCollectionKosmos.kt
similarity index 63%
copy from core/java/android/window/ITrustedPresentationListener.aidl
copy to packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/NotifCollectionKosmos.kt
index b33128a..d98f496 100644
--- a/core/java/android/window/ITrustedPresentationListener.aidl
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/NotifCollectionKosmos.kt
@@ -14,11 +14,11 @@
* limitations under the License.
*/
-package android.window;
+package com.android.systemui.statusbar.notification.stack.ui.viewbinder
-/**
- * @hide
- */
-oneway interface ITrustedPresentationListener {
- void onTrustedPresentationChanged(in int[] enteredTrustedStateIds, in int[] exitedTrustedStateIds);
-}
\ No newline at end of file
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.Kosmos.Fixture
+import com.android.systemui.statusbar.notification.collection.NotifCollection
+import com.android.systemui.util.mockito.mock
+
+var Kosmos.notifCollection by Fixture { mock<NotifCollection>() }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/NotificationListViewBinderKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/NotificationListViewBinderKosmos.kt
new file mode 100644
index 0000000..75e5aeaf
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/NotificationListViewBinderKosmos.kt
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.notification.stack.ui.viewbinder
+
+import com.android.internal.logging.metricsLogger
+import com.android.systemui.classifier.falsingManager
+import com.android.systemui.common.ui.configurationState
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.Kosmos.Fixture
+import com.android.systemui.kosmos.testDispatcher
+import com.android.systemui.statusbar.notification.icon.ui.viewbinder.shelfNotificationIconViewStore
+import com.android.systemui.statusbar.notification.icon.ui.viewbinder.statusBarIconViewBindingFailureTracker
+import com.android.systemui.statusbar.notification.stack.ui.viewmodel.notificationListViewModel
+import com.android.systemui.statusbar.phone.notificationIconAreaController
+import com.android.systemui.statusbar.policy.configurationController
+
+val Kosmos.notificationListViewBinder by Fixture {
+ NotificationListViewBinder(
+ viewModel = notificationListViewModel,
+ backgroundDispatcher = testDispatcher,
+ configuration = configurationState,
+ configurationController = configurationController,
+ falsingManager = falsingManager,
+ iconAreaController = notificationIconAreaController,
+ iconViewBindingFailureTracker = statusBarIconViewBindingFailureTracker,
+ metricsLogger = metricsLogger,
+ shelfIconViewStore = shelfNotificationIconViewStore,
+ )
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/HideListViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/HideListViewModelKosmos.kt
new file mode 100644
index 0000000..0dc62bf
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/HideListViewModelKosmos.kt
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.notification.stack.ui.viewmodel
+
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.Kosmos.Fixture
+import com.android.systemui.statusbar.notification.stack.domain.interactor.hideNotificationsInteractor
+import javax.inject.Provider
+
+val Kosmos.hideListViewModel by Fixture {
+ HideListViewModel(hideNotificationsInteractor = Provider { hideNotificationsInteractor })
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationListViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationListViewModelKosmos.kt
new file mode 100644
index 0000000..44f3134
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationListViewModelKosmos.kt
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.notification.stack.ui.viewmodel
+
+import com.android.systemui.keyguard.domain.interactor.keyguardTransitionInteractor
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.Kosmos.Fixture
+import com.android.systemui.shade.domain.interactor.shadeInteractor
+import com.android.systemui.statusbar.notification.domain.interactor.activeNotificationsInteractor
+import com.android.systemui.statusbar.notification.domain.interactor.seenNotificationsInteractor
+import com.android.systemui.statusbar.notification.footer.ui.viewmodel.footerViewModel
+import com.android.systemui.statusbar.notification.shelf.ui.viewmodel.notificationShelfViewModel
+import com.android.systemui.statusbar.policy.domain.interactor.zenModeInteractor
+import java.util.Optional
+
+val Kosmos.notificationListViewModel by Fixture {
+ NotificationListViewModel(
+ shelf = notificationShelfViewModel,
+ hideListViewModel = hideListViewModel,
+ footer = Optional.of(footerViewModel),
+ activeNotificationsInteractor = activeNotificationsInteractor,
+ keyguardTransitionInteractor = keyguardTransitionInteractor,
+ seenNotificationsInteractor = seenNotificationsInteractor,
+ shadeInteractor = shadeInteractor,
+ zenModeInteractor = zenModeInteractor,
+ )
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/WindowRootViewVisibilityInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/WindowRootViewVisibilityInteractorKosmos.kt
new file mode 100644
index 0000000..e4313bb1
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/WindowRootViewVisibilityInteractorKosmos.kt
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.notification.stack.ui.viewmodel
+
+import com.android.systemui.keyguard.data.repository.keyguardRepository
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.Kosmos.Fixture
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.power.domain.interactor.powerInteractor
+import com.android.systemui.scene.data.repository.windowRootViewVisibilityRepository
+import com.android.systemui.scene.domain.interactor.WindowRootViewVisibilityInteractor
+import com.android.systemui.statusbar.policy.headsUpManager
+
+val Kosmos.windowRootViewVisibilityInteractor by Fixture {
+ WindowRootViewVisibilityInteractor(
+ scope = testScope,
+ windowRootViewVisibilityRepository = windowRootViewVisibilityRepository,
+ keyguardRepository = keyguardRepository,
+ headsUpManager = headsUpManager,
+ powerInteractor = powerInteractor,
+ )
+}
diff --git a/core/java/android/window/ITrustedPresentationListener.aidl b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/KeyguardBypassControllerKosmos.kt
similarity index 69%
copy from core/java/android/window/ITrustedPresentationListener.aidl
copy to packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/KeyguardBypassControllerKosmos.kt
index b33128a..f4a1da0 100644
--- a/core/java/android/window/ITrustedPresentationListener.aidl
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/KeyguardBypassControllerKosmos.kt
@@ -14,11 +14,10 @@
* limitations under the License.
*/
-package android.window;
+package com.android.systemui.statusbar.phone
-/**
- * @hide
- */
-oneway interface ITrustedPresentationListener {
- void onTrustedPresentationChanged(in int[] enteredTrustedStateIds, in int[] exitedTrustedStateIds);
-}
\ No newline at end of file
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.Kosmos.Fixture
+import com.android.systemui.util.mockito.mock
+
+var Kosmos.keyguardBypassController by Fixture { mock<KeyguardBypassController>() }
diff --git a/core/java/android/window/ITrustedPresentationListener.aidl b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/LSShadeTransitionLoggerKosmos.kt
similarity index 69%
copy from core/java/android/window/ITrustedPresentationListener.aidl
copy to packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/LSShadeTransitionLoggerKosmos.kt
index b33128a..496102f 100644
--- a/core/java/android/window/ITrustedPresentationListener.aidl
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/LSShadeTransitionLoggerKosmos.kt
@@ -14,11 +14,10 @@
* limitations under the License.
*/
-package android.window;
+package com.android.systemui.statusbar.phone
-/**
- * @hide
- */
-oneway interface ITrustedPresentationListener {
- void onTrustedPresentationChanged(in int[] enteredTrustedStateIds, in int[] exitedTrustedStateIds);
-}
\ No newline at end of file
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.Kosmos.Fixture
+import com.android.systemui.util.mockito.mock
+
+var Kosmos.lsShadeTransitionLogger by Fixture { mock<LSShadeTransitionLogger>() }
diff --git a/core/java/android/window/ITrustedPresentationListener.aidl b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/NotificationIconAreaControllerKosmos.kt
similarity index 68%
copy from core/java/android/window/ITrustedPresentationListener.aidl
copy to packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/NotificationIconAreaControllerKosmos.kt
index b33128a..d44e061 100644
--- a/core/java/android/window/ITrustedPresentationListener.aidl
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/NotificationIconAreaControllerKosmos.kt
@@ -14,11 +14,10 @@
* limitations under the License.
*/
-package android.window;
+package com.android.systemui.statusbar.phone
-/**
- * @hide
- */
-oneway interface ITrustedPresentationListener {
- void onTrustedPresentationChanged(in int[] enteredTrustedStateIds, in int[] exitedTrustedStateIds);
-}
\ No newline at end of file
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.Kosmos.Fixture
+import com.android.systemui.util.mockito.mock
+
+var Kosmos.notificationIconAreaController by Fixture { mock<NotificationIconAreaController>() }
diff --git a/core/java/android/window/ITrustedPresentationListener.aidl b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/ScrimControllerKosmos.kt
similarity index 70%
copy from core/java/android/window/ITrustedPresentationListener.aidl
copy to packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/ScrimControllerKosmos.kt
index b33128a..3ff57022 100644
--- a/core/java/android/window/ITrustedPresentationListener.aidl
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/ScrimControllerKosmos.kt
@@ -14,11 +14,10 @@
* limitations under the License.
*/
-package android.window;
+package com.android.systemui.statusbar.phone
-/**
- * @hide
- */
-oneway interface ITrustedPresentationListener {
- void onTrustedPresentationChanged(in int[] enteredTrustedStateIds, in int[] exitedTrustedStateIds);
-}
\ No newline at end of file
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.Kosmos.Fixture
+import com.android.systemui.util.mockito.mock
+
+var Kosmos.scrimController by Fixture { mock<ScrimController>() }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerKosmos.kt
index 4e15ea2..ddce4c8 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerKosmos.kt
@@ -18,5 +18,7 @@
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.util.mockito.mock
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+@OptIn(ExperimentalCoroutinesApi::class)
var Kosmos.statusBarKeyguardViewManager by Kosmos.Fixture { mock<StatusBarKeyguardViewManager>() }
diff --git a/core/java/android/window/ITrustedPresentationListener.aidl b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/policy/HeadsUpManagerKosmos.kt
similarity index 70%
copy from core/java/android/window/ITrustedPresentationListener.aidl
copy to packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/policy/HeadsUpManagerKosmos.kt
index b33128a..a4db00c 100644
--- a/core/java/android/window/ITrustedPresentationListener.aidl
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/policy/HeadsUpManagerKosmos.kt
@@ -14,11 +14,10 @@
* limitations under the License.
*/
-package android.window;
+package com.android.systemui.statusbar.policy
-/**
- * @hide
- */
-oneway interface ITrustedPresentationListener {
- void onTrustedPresentationChanged(in int[] enteredTrustedStateIds, in int[] exitedTrustedStateIds);
-}
\ No newline at end of file
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.Kosmos.Fixture
+import com.android.systemui.util.mockito.mock
+
+var Kosmos.headsUpManager by Fixture { mock<HeadsUpManager>() }
diff --git a/core/java/android/window/ITrustedPresentationListener.aidl b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/policy/data/repository/ZenModeRepositoryKosmos.kt
similarity index 67%
copy from core/java/android/window/ITrustedPresentationListener.aidl
copy to packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/policy/data/repository/ZenModeRepositoryKosmos.kt
index b33128a..1ec7511 100644
--- a/core/java/android/window/ITrustedPresentationListener.aidl
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/policy/data/repository/ZenModeRepositoryKosmos.kt
@@ -14,11 +14,10 @@
* limitations under the License.
*/
-package android.window;
+package com.android.systemui.statusbar.policy.data.repository
-/**
- * @hide
- */
-oneway interface ITrustedPresentationListener {
- void onTrustedPresentationChanged(in int[] enteredTrustedStateIds, in int[] exitedTrustedStateIds);
-}
\ No newline at end of file
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.Kosmos.Fixture
+
+val Kosmos.zenModeRepository by Fixture { fakeZenModeRepository }
+val Kosmos.fakeZenModeRepository by Fixture { FakeZenModeRepository() }
diff --git a/core/java/android/window/ITrustedPresentationListener.aidl b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/policy/domain/interactor/ZenModeInteractorKosmos.kt
similarity index 63%
copy from core/java/android/window/ITrustedPresentationListener.aidl
copy to packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/policy/domain/interactor/ZenModeInteractorKosmos.kt
index b33128a..78242b6 100644
--- a/core/java/android/window/ITrustedPresentationListener.aidl
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/policy/domain/interactor/ZenModeInteractorKosmos.kt
@@ -14,11 +14,14 @@
* limitations under the License.
*/
-package android.window;
+package com.android.systemui.statusbar.policy.domain.interactor
-/**
- * @hide
- */
-oneway interface ITrustedPresentationListener {
- void onTrustedPresentationChanged(in int[] enteredTrustedStateIds, in int[] exitedTrustedStateIds);
-}
\ No newline at end of file
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.Kosmos.Fixture
+import com.android.systemui.statusbar.policy.data.repository.zenModeRepository
+
+val Kosmos.zenModeInteractor by Fixture {
+ ZenModeInteractor(
+ repository = zenModeRepository,
+ )
+}
diff --git a/core/java/android/window/ITrustedPresentationListener.aidl b/packages/SystemUI/tests/utils/src/com/android/systemui/unfold/UnfoldTransitionProgressProviderKosmos.kt
similarity index 68%
copy from core/java/android/window/ITrustedPresentationListener.aidl
copy to packages/SystemUI/tests/utils/src/com/android/systemui/unfold/UnfoldTransitionProgressProviderKosmos.kt
index b33128a..7c54a57 100644
--- a/core/java/android/window/ITrustedPresentationListener.aidl
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/unfold/UnfoldTransitionProgressProviderKosmos.kt
@@ -14,11 +14,10 @@
* limitations under the License.
*/
-package android.window;
+package com.android.systemui.unfold
-/**
- * @hide
- */
-oneway interface ITrustedPresentationListener {
- void onTrustedPresentationChanged(in int[] enteredTrustedStateIds, in int[] exitedTrustedStateIds);
-}
\ No newline at end of file
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.Kosmos.Fixture
+import com.android.systemui.util.mockito.mock
+
+var Kosmos.unfoldTransitionProgressProvider by Fixture { mock<UnfoldTransitionProgressProvider>() }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/unfold/data/repository/UnfoldTransitionRepositoryKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/unfold/data/repository/UnfoldTransitionRepositoryKosmos.kt
new file mode 100644
index 0000000..2a250c8
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/unfold/data/repository/UnfoldTransitionRepositoryKosmos.kt
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.unfold.data.repository
+
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.Kosmos.Fixture
+import com.android.systemui.unfold.unfoldTransitionProgressProvider
+import java.util.Optional
+
+val Kosmos.unfoldTransitionRepository by Fixture {
+ UnfoldTransitionRepositoryImpl(
+ unfoldProgressProvider = Optional.of(unfoldTransitionProgressProvider),
+ )
+}
diff --git a/core/java/android/window/ITrustedPresentationListener.aidl b/packages/SystemUI/tests/utils/src/com/android/systemui/unfold/domain/interactor/UnfoldTransitionInteractorKosmos.kt
similarity index 63%
copy from core/java/android/window/ITrustedPresentationListener.aidl
copy to packages/SystemUI/tests/utils/src/com/android/systemui/unfold/domain/interactor/UnfoldTransitionInteractorKosmos.kt
index b33128a..d03616a 100644
--- a/core/java/android/window/ITrustedPresentationListener.aidl
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/unfold/domain/interactor/UnfoldTransitionInteractorKosmos.kt
@@ -14,11 +14,12 @@
* limitations under the License.
*/
-package android.window;
+package com.android.systemui.unfold.domain.interactor
-/**
- * @hide
- */
-oneway interface ITrustedPresentationListener {
- void onTrustedPresentationChanged(in int[] enteredTrustedStateIds, in int[] exitedTrustedStateIds);
-}
\ No newline at end of file
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.Kosmos.Fixture
+import com.android.systemui.unfold.data.repository.unfoldTransitionRepository
+
+val Kosmos.unfoldTransitionInteractor by Fixture {
+ UnfoldTransitionInteractorImpl(repository = unfoldTransitionRepository)
+}
diff --git a/core/java/android/window/ITrustedPresentationListener.aidl b/packages/SystemUI/tests/utils/src/com/android/systemui/util/animation/data/repository/AnimationStatusRepositoryKosmos.kt
similarity index 65%
copy from core/java/android/window/ITrustedPresentationListener.aidl
copy to packages/SystemUI/tests/utils/src/com/android/systemui/util/animation/data/repository/AnimationStatusRepositoryKosmos.kt
index b33128a..63ea085 100644
--- a/core/java/android/window/ITrustedPresentationListener.aidl
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/util/animation/data/repository/AnimationStatusRepositoryKosmos.kt
@@ -14,11 +14,10 @@
* limitations under the License.
*/
-package android.window;
+package com.android.systemui.util.animation.data.repository
-/**
- * @hide
- */
-oneway interface ITrustedPresentationListener {
- void onTrustedPresentationChanged(in int[] enteredTrustedStateIds, in int[] exitedTrustedStateIds);
-}
\ No newline at end of file
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.Kosmos.Fixture
+
+val Kosmos.animationStatusRepository by Fixture { fakeAnimationStatusRepository }
+val Kosmos.fakeAnimationStatusRepository by Fixture { FakeAnimationStatusRepository() }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/utils/leaks/FakeBatteryController.java b/packages/SystemUI/tests/utils/src/com/android/systemui/utils/leaks/FakeBatteryController.java
index 209cac6..5ae033c 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/utils/leaks/FakeBatteryController.java
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/utils/leaks/FakeBatteryController.java
@@ -22,11 +22,16 @@
import com.android.systemui.statusbar.policy.BatteryController.BatteryStateChangeCallback;
import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.List;
public class FakeBatteryController extends BaseLeakChecker<BatteryStateChangeCallback>
implements BatteryController {
private boolean mIsAodPowerSave = false;
private boolean mWirelessCharging;
+ private boolean mPowerSaveMode = false;
+
+ private final List<BatteryStateChangeCallback> mCallbacks = new ArrayList<>();
public FakeBatteryController(LeakCheck test) {
super(test, "battery");
@@ -44,12 +49,18 @@
@Override
public void setPowerSaveMode(boolean powerSave) {
-
+ mPowerSaveMode = powerSave;
+ for (BatteryStateChangeCallback callback: mCallbacks) {
+ callback.onPowerSaveChanged(powerSave);
+ }
}
+ /**
+ * Note: this method ignores the View argument
+ */
@Override
public void setPowerSaveMode(boolean powerSave, View view) {
-
+ setPowerSaveMode(powerSave);
}
@Override
@@ -59,7 +70,7 @@
@Override
public boolean isPowerSave() {
- return false;
+ return mPowerSaveMode;
}
@Override
@@ -79,4 +90,14 @@
public void setWirelessCharging(boolean wirelessCharging) {
mWirelessCharging = wirelessCharging;
}
+
+ @Override
+ public void addCallback(BatteryStateChangeCallback listener) {
+ mCallbacks.add(listener);
+ }
+
+ @Override
+ public void removeCallback(BatteryStateChangeCallback listener) {
+ mCallbacks.remove(listener);
+ }
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/utils/leaks/FakeLocationController.java b/packages/SystemUI/tests/utils/src/com/android/systemui/utils/leaks/FakeLocationController.java
index 3c63275..442d15b 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/utils/leaks/FakeLocationController.java
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/utils/leaks/FakeLocationController.java
@@ -26,6 +26,7 @@
implements LocationController {
private final List<LocationChangeCallback> mCallbacks = new ArrayList<>();
+ private boolean mLocationEnabled = false;
public FakeLocationController(LeakCheck test) {
super(test, "location");
@@ -38,13 +39,14 @@
@Override
public boolean isLocationEnabled() {
- return false;
+ return mLocationEnabled;
}
@Override
public boolean setLocationEnabled(boolean enabled) {
+ mLocationEnabled = enabled;
mCallbacks.forEach(callback -> callback.onLocationSettingsChanged(enabled));
- return false;
+ return true;
}
@Override
diff --git a/ravenwood/framework-minus-apex-ravenwood-policies.txt b/ravenwood/framework-minus-apex-ravenwood-policies.txt
index 6a6ae38..c9069e5 100644
--- a/ravenwood/framework-minus-apex-ravenwood-policies.txt
+++ b/ravenwood/framework-minus-apex-ravenwood-policies.txt
@@ -74,6 +74,7 @@
class android.util.proto.WireTypeMismatchException stubclass
# Misc
+class android.util.BackupUtils stubclass
class android.util.Dumpable stubclass
class android.util.DebugUtils stubclass
class android.util.MathUtils stubclass
@@ -81,15 +82,11 @@
class android.util.UtilConfig stubclass
# Internals
-class com.android.internal.util.FastMath stubclass
-class com.android.internal.util.FastPrintWriter stubclass
-class com.android.internal.util.GrowingArrayUtils stubclass
-class com.android.internal.util.LineBreakBufferedWriter stubclass
-class com.android.internal.util.Parcelling stubclass
+class com.android.internal.util.FileRotator stubclass
+class com.android.internal.util.HexDump stubclass
+class com.android.internal.util.MessageUtils stubclass
class com.android.internal.util.Preconditions stubclass
-class com.android.internal.util.StringPool stubclass
-
-class com.android.internal.os.SomeArgs stubclass
+class com.android.internal.util.TokenBucket stubclass
# Parcel
class android.os.ParcelFormatException stubclass
diff --git a/ravenwood/junit-src/android/platform/test/annotations/IgnoreUnderRavenwood.java b/ravenwood/junit-src/android/platform/test/annotations/IgnoreUnderRavenwood.java
index edb0442..916dd59 100644
--- a/ravenwood/junit-src/android/platform/test/annotations/IgnoreUnderRavenwood.java
+++ b/ravenwood/junit-src/android/platform/test/annotations/IgnoreUnderRavenwood.java
@@ -36,7 +36,7 @@
*
* @hide
*/
-@Target(ElementType.METHOD)
+@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface IgnoreUnderRavenwood {
/**
diff --git a/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodRule.java b/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodRule.java
index 9db5b98..d175713 100644
--- a/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodRule.java
+++ b/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodRule.java
@@ -93,7 +93,7 @@
/**
* Return if the current process is running under a Ravenwood test environment.
*/
- public boolean isUnderRavenwood() {
+ public static boolean isUnderRavenwood() {
return IS_UNDER_RAVENWOOD;
}
@@ -102,6 +102,9 @@
return new Statement() {
@Override
public void evaluate() throws Throwable {
+ if (description.getTestClass().getAnnotation(IgnoreUnderRavenwood.class) != null) {
+ Assume.assumeFalse(IS_UNDER_RAVENWOOD);
+ }
if (description.getAnnotation(IgnoreUnderRavenwood.class) != null) {
Assume.assumeFalse(IS_UNDER_RAVENWOOD);
}
diff --git a/ravenwood/ravenwood-annotation-allowed-classes.txt b/ravenwood/ravenwood-annotation-allowed-classes.txt
index 2902932..831fce1 100644
--- a/ravenwood/ravenwood-annotation-allowed-classes.txt
+++ b/ravenwood/ravenwood-annotation-allowed-classes.txt
@@ -4,11 +4,21 @@
android.util.AtomicFile
android.util.DataUnit
+android.util.DayOfMonthCursor
+android.util.DumpableContainer
android.util.EventLog
android.util.IntArray
+android.util.KeyValueListParser
android.util.LongArray
+android.util.LongArrayQueue
+android.util.LongSparseLongArray
android.util.LruCache
+android.util.MonthDisplayHelper
+android.util.RecurrenceRule
+android.util.RotationUtils
android.util.Slog
+android.util.SparseDoubleArray
+android.util.SparseSetArray
android.util.TimeUtils
android.util.Xml
@@ -41,6 +51,17 @@
android.content.IntentFilter
android.content.UriMatcher
+android.content.pm.PackageInfo
+android.content.pm.ApplicationInfo
+android.content.pm.PackageItemInfo
+android.content.pm.ComponentInfo
+android.content.pm.ActivityInfo
+android.content.pm.ServiceInfo
+android.content.pm.PathPermission
+android.content.pm.ProviderInfo
+android.content.pm.ResolveInfo
+android.content.pm.Signature
+
android.database.AbstractCursor
android.database.CharArrayBuffer
android.database.ContentObservable
@@ -68,3 +89,30 @@
android.graphics.RectF
com.android.server.LocalServices
+
+com.android.internal.os.SomeArgs
+
+com.android.internal.util.BitUtils
+com.android.internal.util.BitwiseInputStream
+com.android.internal.util.BitwiseOutputStream
+com.android.internal.util.CallbackRegistry
+com.android.internal.util.DumpableContainer
+com.android.internal.util.dump.DumpableContainerImpl
+com.android.internal.util.DumpUtils
+com.android.internal.util.FastMath
+com.android.internal.util.FastPrintWriter
+com.android.internal.util.FileRotator
+com.android.internal.util.GrowingArrayUtils
+com.android.internal.util.HeavyHitterSketch
+com.android.internal.util.LineBreakBufferedWriter
+com.android.internal.util.ObjectUtils
+com.android.internal.util.Parcelling
+com.android.internal.util.ParseUtils
+com.android.internal.util.ProcFileReader
+com.android.internal.util.QuickSelect
+com.android.internal.util.RingBuffer
+com.android.internal.util.StringPool
+
+com.google.android.collect.Lists
+com.google.android.collect.Maps
+com.google.android.collect.Sets
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index 5bffe80..440e996 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -4406,6 +4406,28 @@
}
@Override
+ public boolean isAccessibilityServiceWarningRequired(AccessibilityServiceInfo info) {
+ mSecurityPolicy.enforceCallingOrSelfPermission(Manifest.permission.MANAGE_ACCESSIBILITY);
+
+ // Warning is not required if the service is already enabled.
+ synchronized (mLock) {
+ final AccessibilityUserState userState = getCurrentUserStateLocked();
+ if (userState.getEnabledServicesLocked().contains(info.getComponentName())) {
+ return false;
+ }
+ }
+ // Warning is not required if the service is already assigned to a shortcut.
+ for (int shortcutType : AccessibilityManager.SHORTCUT_TYPES) {
+ if (getAccessibilityShortcutTargets(shortcutType).contains(
+ info.getComponentName().flattenToString())) {
+ return false;
+ }
+ }
+ // Warning is required by default.
+ return true;
+ }
+
+ @Override
public void dump(FileDescriptor fd, final PrintWriter pw, String[] args) {
if (!DumpUtils.checkDumpPermission(mContext, LOG_TAG, pw)) return;
synchronized (mLock) {
diff --git a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
index 258820a..77a5e3d 100644
--- a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
+++ b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
@@ -43,7 +43,9 @@
import android.app.PendingIntent;
import android.app.admin.DevicePolicyManagerInternal;
import android.app.admin.DevicePolicyManagerInternal.OnCrossProfileWidgetProvidersChangeListener;
+import android.app.usage.Flags;
import android.app.usage.UsageEvents;
+import android.app.usage.UsageStatsManager;
import android.app.usage.UsageStatsManagerInternal;
import android.appwidget.AppWidgetManager;
import android.appwidget.AppWidgetManagerInternal;
@@ -83,6 +85,7 @@
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
+import android.os.PersistableBundle;
import android.os.Process;
import android.os.RemoteException;
import android.os.SystemClock;
@@ -3815,14 +3818,27 @@
final SparseArray<String> uid2PackageName = new SparseArray<String>();
uid2PackageName.put(providerId.uid, packageName);
mAppOpsManagerInternal.updateAppWidgetVisibility(uid2PackageName, true);
- mUsageStatsManagerInternal.reportEvent(packageName,
- UserHandle.getUserId(providerId.uid), UsageEvents.Event.USER_INTERACTION);
+ reportWidgetInteractionEvent(packageName, UserHandle.getUserId(providerId.uid),
+ "tap");
}
} finally {
Binder.restoreCallingIdentity(ident);
}
}
+ private void reportWidgetInteractionEvent(@NonNull String packageName, @UserIdInt int userId,
+ @NonNull String action) {
+ if (Flags.userInteractionTypeApi()) {
+ PersistableBundle extras = new PersistableBundle();
+ extras.putString(UsageStatsManager.EXTRA_EVENT_CATEGORY, "android.appwidget");
+ extras.putString(UsageStatsManager.EXTRA_EVENT_ACTION, action);
+ mUsageStatsManagerInternal.reportUserInteractionEvent(packageName, userId, extras);
+ } else {
+ mUsageStatsManagerInternal.reportEvent(packageName, userId,
+ UsageEvents.Event.USER_INTERACTION);
+ }
+ }
+
private final class CallbackHandler extends Handler {
public static final int MSG_NOTIFY_UPDATE_APP_WIDGET = 1;
public static final int MSG_NOTIFY_PROVIDER_CHANGED = 2;
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
index 518b81f..fd8ab96 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
@@ -19,7 +19,7 @@
import static android.service.autofill.FillEventHistory.Event.NO_SAVE_UI_REASON_NONE;
import static android.service.autofill.FillEventHistory.Event.UI_TYPE_INLINE;
import static android.service.autofill.FillRequest.FLAG_MANUAL_REQUEST;
-import static android.service.autofill.FillRequest.FLAG_SCREEN_HAS_CREDMAN_FIELD;
+import static android.service.autofill.FillRequest.FLAG_VIEW_REQUESTS_CREDMAN_SERVICE;
import static android.view.autofill.AutofillManager.ACTION_START_SESSION;
import static android.view.autofill.AutofillManager.FLAG_ADD_CLIENT_ENABLED;
import static android.view.autofill.AutofillManager.FLAG_ADD_CLIENT_ENABLED_FOR_AUGMENTED_AUTOFILL_ONLY;
@@ -104,10 +104,6 @@
extends AbstractPerUserSystemService<AutofillManagerServiceImpl, AutofillManagerService> {
private static final String TAG = "AutofillManagerServiceImpl";
-
- private static final ComponentName CREDMAN_SERVICE_COMPONENT_NAME =
- new ComponentName("com.android.credentialmanager",
- "com.android.credentialmanager.autofill.CredentialAutofillService");
private static final int MAX_SESSION_ID_CREATE_TRIES = 2048;
/** Minimum interval to prune abandoned sessions */
@@ -536,22 +532,15 @@
|| mSessions.indexOfKey(sessionId) >= 0);
assertCallerLocked(clientActivity, compatMode);
-
ComponentName serviceComponentName = mInfo == null ? null
: mInfo.getServiceInfo().getComponentName();
-
- if (isAutofillCredmanIntegrationEnabled()
- && ((flags & FLAG_SCREEN_HAS_CREDMAN_FIELD) != 0)) {
- // Hardcode to credential manager proxy service
- Slog.i(TAG, "Routing to CredentialAutofillService");
- serviceComponentName = CREDMAN_SERVICE_COMPONENT_NAME;
- }
+ boolean isPrimaryCredential = (flags & FLAG_VIEW_REQUESTS_CREDMAN_SERVICE) != 0;
final Session newSession = new Session(this, mUi, getContext(), mHandler, mUserId, mLock,
sessionId, taskId, clientUid, clientActivityToken, clientCallback, hasCallback,
mUiLatencyHistory, mWtfHistory, serviceComponentName,
clientActivity, compatMode, bindInstantServiceAllowed, forAugmentedAutofillOnly,
- flags, mInputMethodManagerInternal);
+ flags, mInputMethodManagerInternal, isPrimaryCredential);
mSessions.put(newSession.id, newSession);
return newSession;
diff --git a/services/autofill/java/com/android/server/autofill/SecondaryProviderHandler.java b/services/autofill/java/com/android/server/autofill/SecondaryProviderHandler.java
new file mode 100644
index 0000000..d9741c8
--- /dev/null
+++ b/services/autofill/java/com/android/server/autofill/SecondaryProviderHandler.java
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.autofill;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.IntentSender;
+import android.service.autofill.FillRequest;
+import android.service.autofill.FillResponse;
+import android.util.Slog;
+
+import java.util.Objects;
+
+
+/**
+ * Requests autofill response from a Remote Autofill Service. This autofill service can be
+ * either a Credential Autofill Service or the user-opted autofill service.
+ *
+ * <p> With the credman integration, Autofill Framework handles two types of autofill flows -
+ * regular autofill flow and the credman integrated autofill flow. With the credman integrated
+ * autofill, the data source for the autofill is handled by the credential autofill proxy
+ * service, which is hidden from users. By the time a session gets created, the framework
+ * decides on one of the two flows by setting the remote fill service to be either the
+ * user-elected autofill service or the hidden credential autofill service by looking at the
+ * user-focused view's credential attribute. If the user needs both flows concurrently because
+ * the screen has both regular autofill fields and credential fields, then secondary provider
+ * handler will be used to fetch supplementary fill response. Depending on which remote fill
+ * service the session was initially created with, the secondary provider handler will contain
+ * the remaining autofill service. </p>
+ *
+ * @hide
+ */
+final class SecondaryProviderHandler implements RemoteFillService.FillServiceCallbacks {
+ private static final String TAG = "SecondaryProviderHandler";
+
+ private final RemoteFillService mRemoteFillService;
+ private final SecondaryProviderCallback mCallback;
+ private FillRequest mLastFillRequest;
+ private int mLastFlag;
+
+ SecondaryProviderHandler(
+ @NonNull Context context, int userId, boolean bindInstantServiceAllowed,
+ SecondaryProviderCallback callback, ComponentName componentName) {
+ mRemoteFillService = new RemoteFillService(context, componentName, userId, this,
+ bindInstantServiceAllowed);
+ mCallback = callback;
+ Slog.v(TAG, "Creating a secondary provider handler with component name, " + componentName);
+ }
+ @Override
+ public void onServiceDied(RemoteFillService service) {
+ mRemoteFillService.destroy();
+ }
+
+ @Override
+ public void onFillRequestSuccess(int requestId, @Nullable FillResponse response,
+ @NonNull String servicePackageName, int requestFlags) {
+ Slog.v(TAG, "Received a fill response: " + response);
+ mCallback.onSecondaryFillResponse(response, mLastFlag);
+ }
+
+ @Override
+ public void onFillRequestFailure(int requestId, @Nullable CharSequence message) {
+
+ }
+
+ @Override
+ public void onFillRequestTimeout(int requestId) {
+
+ }
+
+ @Override
+ public void onSaveRequestSuccess(@NonNull String servicePackageName,
+ @Nullable IntentSender intentSender) {
+
+ }
+
+ @Override
+ public void onSaveRequestFailure(@Nullable CharSequence message,
+ @NonNull String servicePackageName) {
+
+ }
+
+ /**
+ * Requests a new fill response. If the fill request is same as the last requested fill request,
+ * then the request is duped.
+ */
+ public void onFillRequest(FillRequest pendingFillRequest, int flag) {
+ if (Objects.equals(pendingFillRequest, mLastFillRequest)) {
+ Slog.v(TAG, "Deduping fill request to secondary provider.");
+ return;
+ }
+ Slog.v(TAG, "Requesting fill response to secondary provider.");
+ mLastFlag = flag;
+ mLastFillRequest = pendingFillRequest;
+ mRemoteFillService.onFillRequest(pendingFillRequest);
+ }
+
+ public void destroy() {
+ mRemoteFillService.destroy();
+ }
+
+ interface SecondaryProviderCallback {
+ void onSecondaryFillResponse(@Nullable FillResponse fillResponse, int flags);
+ }
+}
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index 07e9c50..d527ce0 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -35,6 +35,7 @@
import static android.service.autofill.FillRequest.FLAG_SCREEN_HAS_CREDMAN_FIELD;
import static android.service.autofill.FillRequest.FLAG_SUPPORTS_FILL_DIALOG;
import static android.service.autofill.FillRequest.FLAG_VIEW_NOT_FOCUSED;
+import static android.service.autofill.FillRequest.FLAG_VIEW_REQUESTS_CREDMAN_SERVICE;
import static android.service.autofill.FillRequest.INVALID_REQUEST_ID;
import static android.view.autofill.AutofillManager.ACTION_RESPONSE_EXPIRED;
import static android.view.autofill.AutofillManager.ACTION_START_SESSION;
@@ -228,6 +229,10 @@
private static final int DEFAULT__FILL_REQUEST_ID_SNAPSHOT = -2;
private static final int DEFAULT__FIELD_CLASSIFICATION_REQUEST_ID_SNAPSHOT = -2;
+ private static final ComponentName CREDMAN_SERVICE_COMPONENT_NAME =
+ new ComponentName("com.android.credentialmanager",
+ "com.android.credentialmanager.autofill.CredentialAutofillService");
+
final Object mLock;
private final AutofillManagerServiceImpl mService;
@@ -343,6 +348,22 @@
@Nullable
private final RemoteFillService mRemoteFillService;
+ /**
+ * With the credman integration, Autofill Framework handles two types of autofill flows -
+ * regular autofill flow and the credman integrated autofill flow. With the credman integrated
+ * autofill, the data source for the autofill is handled by the credential autofill proxy
+ * service, which is hidden from users. By the time a session gets created, the framework
+ * decides on one of the two flows by setting the remote fill service to be either the
+ * user-elected autofill service or the hidden credential autofill service by looking at the
+ * user-focused view's credential attribute. If the user needs both flows concurrently because
+ * the screen has both regular autofill fields and credential fields, then secondary provider
+ * handler will be used to fetch supplementary fill response. Depending on which remote fill
+ * service the session was initially created with, the secondary provider handler will contain
+ * the remaining autofill service.
+ */
+ @Nullable
+ private final SecondaryProviderHandler mSecondaryProviderHandler;
+
@GuardedBy("mLock")
private SparseArray<FillResponse> mResponses;
@@ -358,6 +379,9 @@
*/
private boolean mHasCallback;
+ /** Whether the session has credential provider as the primary provider. */
+ private boolean mIsPrimaryCredential;
+
@GuardedBy("mLock")
private boolean mDelayedFillBroadcastReceiverRegistered;
@@ -689,7 +713,6 @@
mPendingFillRequest.getDelayedFillIntentSender());
}
mLastFillRequest = mPendingFillRequest;
-
mRemoteFillService.onFillRequest(mPendingFillRequest);
mPendingInlineSuggestionsRequest = null;
mWaitForInlineRequest = false;
@@ -776,7 +799,7 @@
+ mUrlBar.getWebDomain());
}
final ViewState viewState = new ViewState(urlBarId, Session.this,
- ViewState.STATE_URL_BAR);
+ ViewState.STATE_URL_BAR, mIsPrimaryCredential);
mViewStates.put(urlBarId, viewState);
}
}
@@ -1187,7 +1210,8 @@
setViewStatesLocked(
existingResponse,
ViewState.STATE_INITIAL,
- /* clearResponse= */ true);
+ /* clearResponse= */ true,
+ /* isPrimary= */ true);
mFillRequestEventLogger.maybeSetRequestTriggerReason(
TRIGGER_REASON_SERVED_FROM_CACHED_RESPONSE);
}
@@ -1352,7 +1376,8 @@
@NonNull LocalLog wtfHistory, @Nullable ComponentName serviceComponentName,
@NonNull ComponentName componentName, boolean compatMode,
boolean bindInstantServiceAllowed, boolean forAugmentedAutofillOnly, int flags,
- @NonNull InputMethodManagerInternal inputMethodManagerInternal) {
+ @NonNull InputMethodManagerInternal inputMethodManagerInternal,
+ boolean isPrimaryCredential) {
if (sessionId < 0) {
wtf(null, "Non-positive sessionId: %s", sessionId);
}
@@ -1365,9 +1390,24 @@
mLock = lock;
mUi = ui;
mHandler = handler;
- mRemoteFillService = serviceComponentName == null ? null
- : new RemoteFillService(context, serviceComponentName, userId, this,
+
+ ComponentName primaryServiceComponentName, secondaryServiceComponentName;
+ if (isPrimaryCredential) {
+ primaryServiceComponentName = CREDMAN_SERVICE_COMPONENT_NAME;
+ secondaryServiceComponentName = serviceComponentName;
+ } else {
+ primaryServiceComponentName = serviceComponentName;
+ secondaryServiceComponentName = CREDMAN_SERVICE_COMPONENT_NAME;
+ }
+ Slog.v(TAG, "Primary service component name: " + primaryServiceComponentName
+ + ", secondary service component name: " + secondaryServiceComponentName);
+
+ mRemoteFillService = primaryServiceComponentName == null ? null
+ : new RemoteFillService(context, primaryServiceComponentName, userId, this,
bindInstantServiceAllowed);
+ mSecondaryProviderHandler = secondaryServiceComponentName == null ? null
+ : new SecondaryProviderHandler(context, userId, bindInstantServiceAllowed,
+ this::onSecondaryFillResponse, secondaryServiceComponentName);
mActivityToken = activityToken;
mHasCallback = hasCallback;
mUiLatencyHistory = uiLatencyHistory;
@@ -1389,6 +1429,7 @@
mSessionCommittedEventLogger = SessionCommittedEventLogger.forSessionId(sessionId);
mSessionCommittedEventLogger.maybeSetComponentPackageUid(uid);
mSaveEventLogger = SaveEventLogger.forSessionId(sessionId);
+ mIsPrimaryCredential = isPrimaryCredential;
synchronized (mLock) {
mSessionFlags = new SessionFlags();
@@ -1758,6 +1799,22 @@
return createShallowCopy(response, resultContainer);
}
+ private void onSecondaryFillResponse(@Nullable FillResponse fillResponse, int flags) {
+ if (fillResponse == null) {
+ return;
+ }
+ synchronized (mLock) {
+ setViewStatesLocked(fillResponse, ViewState.STATE_FILLABLE, /* clearResponse= */ false,
+ /* isPrimary= */ false);
+
+ // Updates the UI, if necessary.
+ final ViewState currentView = mViewStates.get(mCurrentViewId);
+ if (currentView != null) {
+ currentView.maybeCallOnFillReady(flags);
+ }
+ }
+ }
+
private FillResponse createShallowCopy(
FillResponse response, DatasetComputationContainer container) {
return FillResponse.shallowCopy(
@@ -4008,6 +4065,17 @@
return true;
}
+ boolean shouldRequestSecondaryProvider(int flags) {
+ if (mIsPrimaryCredential) {
+ return (flags & FLAG_VIEW_REQUESTS_CREDMAN_SERVICE) == 0;
+ } else {
+ return (flags & FLAG_VIEW_REQUESTS_CREDMAN_SERVICE) != 0;
+ }
+ }
+
+ // ErrorProne says mAssistReceiver#mLastFillRequest needs to be guarded by
+ // 'Session.this.mLock', which is the same as mLock.
+ @SuppressWarnings("GuardedBy")
@GuardedBy("mLock")
void updateLocked(AutofillId id, Rect virtualBounds, AutofillValue value, int action,
int flags) {
@@ -4045,7 +4113,8 @@
if (sVerbose) Slog.v(TAG, "Creating viewState for " + id);
boolean isIgnored = isIgnoredLocked(id);
viewState = new ViewState(id, this,
- isIgnored ? ViewState.STATE_IGNORED : ViewState.STATE_INITIAL);
+ isIgnored ? ViewState.STATE_IGNORED : ViewState.STATE_INITIAL,
+ mIsPrimaryCredential);
mViewStates.put(id, viewState);
// TODO(b/73648631): for optimization purposes, should also ignore if change is
@@ -4136,6 +4205,12 @@
}
break;
case ACTION_VIEW_ENTERED:
+ if (shouldRequestSecondaryProvider(flags)
+ && mSecondaryProviderHandler != null
+ && mAssistReceiver.mLastFillRequest != null) {
+ mSecondaryProviderHandler.onFillRequest(mAssistReceiver.mLastFillRequest,
+ flags);
+ }
mLatencyBaseTime = SystemClock.elapsedRealtime();
boolean wasPreviouslyFillDialog = mPreviouslyFillDialogPotentiallyStarted;
mPreviouslyFillDialogPotentiallyStarted = false;
@@ -4911,7 +4986,8 @@
private void replaceResponseLocked(@NonNull FillResponse oldResponse,
@NonNull FillResponse newResponse, @Nullable Bundle newClientState) {
// Disassociate view states with the old response
- setViewStatesLocked(oldResponse, ViewState.STATE_INITIAL, true);
+ setViewStatesLocked(oldResponse, ViewState.STATE_INITIAL, /* clearResponse= */ true,
+ /* isPrimary= */ true);
// Move over the id
newResponse.setRequestId(oldResponse.getRequestId());
// Now process the new response
@@ -5308,7 +5384,8 @@
mPresentationStatsEventLogger.maybeSetAvailableCount(datasetList, mCurrentViewId);
mFillResponseEventLogger.maybeSetDatasetsCountAfterPotentialPccFiltering(datasetList);
- setViewStatesLocked(newResponse, ViewState.STATE_FILLABLE, false);
+ setViewStatesLocked(newResponse, ViewState.STATE_FILLABLE, /* clearResponse= */ false,
+ /* isPrimary= */ true);
updateFillDialogTriggerIdsLocked();
updateTrackedIdsLocked();
@@ -5325,7 +5402,8 @@
* Sets the state of all views in the given response.
*/
@GuardedBy("mLock")
- private void setViewStatesLocked(FillResponse response, int state, boolean clearResponse) {
+ private void setViewStatesLocked(FillResponse response, int state, boolean clearResponse,
+ boolean isPrimary) {
final List<Dataset> datasets = response.getDatasets();
if (datasets != null && !datasets.isEmpty()) {
for (int i = 0; i < datasets.size(); i++) {
@@ -5334,15 +5412,15 @@
Slog.w(TAG, "Ignoring null dataset on " + datasets);
continue;
}
- setViewStatesLocked(response, dataset, state, clearResponse);
+ setViewStatesLocked(response, dataset, state, clearResponse, isPrimary);
}
} else if (response.getAuthentication() != null) {
for (AutofillId autofillId : response.getAuthenticationIds()) {
final ViewState viewState = createOrUpdateViewStateLocked(autofillId, state, null);
if (!clearResponse) {
- viewState.setResponse(response);
+ viewState.setResponse(response, isPrimary);
} else {
- viewState.setResponse(null);
+ viewState.setResponse(null, isPrimary);
}
}
}
@@ -5375,7 +5453,7 @@
*/
@GuardedBy("mLock")
private void setViewStatesLocked(@Nullable FillResponse response, @NonNull Dataset dataset,
- int state, boolean clearResponse) {
+ int state, boolean clearResponse, boolean isPrimary) {
final ArrayList<AutofillId> ids = dataset.getFieldIds();
final ArrayList<AutofillValue> values = dataset.getFieldValues();
for (int j = 0; j < ids.size(); j++) {
@@ -5387,9 +5465,9 @@
viewState.setDatasetId(datasetId);
}
if (clearResponse) {
- viewState.setResponse(null);
+ viewState.setResponse(null, isPrimary);
} else if (response != null) {
- viewState.setResponse(response);
+ viewState.setResponse(response, isPrimary);
}
}
}
@@ -5401,7 +5479,7 @@
if (viewState != null) {
viewState.setState(state);
} else {
- viewState = new ViewState(id, this, state);
+ viewState = new ViewState(id, this, state, mIsPrimaryCredential);
if (sVerbose) {
Slog.v(TAG, "Adding autofillable view with id " + id + " and state " + state);
}
@@ -5446,7 +5524,9 @@
mService.logDatasetAuthenticationSelected(dataset.getId(), id, mClientState, uiType);
mPresentationStatsEventLogger.maybeSetAuthenticationType(
AUTHENTICATION_TYPE_DATASET_AUTHENTICATION);
- setViewStatesLocked(null, dataset, ViewState.STATE_WAITING_DATASET_AUTH, false);
+ // does not matter the value of isPrimary because null response won't be overridden.
+ setViewStatesLocked(null, dataset, ViewState.STATE_WAITING_DATASET_AUTH,
+ /* clearResponse= */ false, /* isPrimary= */ true);
final Intent fillInIntent = createAuthFillInIntentLocked(requestId, mClientState,
dataset.getAuthenticationExtras());
if (fillInIntent == null) {
@@ -6044,7 +6124,10 @@
}
mSelectedDatasetIds.add(dataset.getId());
}
- setViewStatesLocked(null, dataset, ViewState.STATE_AUTOFILLED, false);
+ // does not matter the value of isPrimary because null response won't be
+ // overridden.
+ setViewStatesLocked(null, dataset, ViewState.STATE_AUTOFILLED,
+ /* clearResponse= */ false, /* isPrimary= */ true);
}
} catch (RemoteException e) {
Slog.w(TAG, "Error autofilling activity: " + e);
@@ -6222,6 +6305,9 @@
if (remoteFillService != null) {
remoteFillService.destroy();
}
+ if (mSecondaryProviderHandler != null) {
+ mSecondaryProviderHandler.destroy();
+ }
mSessionState = STATE_REMOVED;
}
diff --git a/services/autofill/java/com/android/server/autofill/ViewState.java b/services/autofill/java/com/android/server/autofill/ViewState.java
index 12695ac..b0bb9ec 100644
--- a/services/autofill/java/com/android/server/autofill/ViewState.java
+++ b/services/autofill/java/com/android/server/autofill/ViewState.java
@@ -17,6 +17,7 @@
package com.android.server.autofill;
import static android.service.autofill.FillRequest.FLAG_MANUAL_REQUEST;
+import static android.service.autofill.FillRequest.FLAG_VIEW_REQUESTS_CREDMAN_SERVICE;
import static com.android.server.autofill.Helper.sDebug;
@@ -89,7 +90,21 @@
private final Listener mListener;
- private FillResponse mResponse;
+ private final boolean mIsPrimaryCredential;
+
+ /**
+ * There are two sources of fill response. The fill response from the session's remote fill
+ * service and the fill response from the secondary provider handler. Primary Fill Response
+ * stores the fill response from the session's remote fill service.
+ */
+ private FillResponse mPrimaryFillResponse;
+
+ /**
+ * Secondary fill response stores the fill response from the secondary provider handler. Based
+ * on whether the user focuses on a credential view or an autofill view, the relevant fill
+ * response will be used to show the autofill suggestions.
+ */
+ private FillResponse mSecondaryFillResponse;
private AutofillValue mCurrentValue;
private AutofillValue mAutofilledValue;
private AutofillValue mSanitizedValue;
@@ -97,10 +112,11 @@
private int mState;
private String mDatasetId;
- ViewState(AutofillId id, Listener listener, int state) {
+ ViewState(AutofillId id, Listener listener, int state, boolean isPrimaryCredential) {
this.id = id;
mListener = listener;
mState = state;
+ mIsPrimaryCredential = isPrimaryCredential;
}
/**
@@ -143,11 +159,19 @@
@Nullable
FillResponse getResponse() {
- return mResponse;
+ return mPrimaryFillResponse;
}
void setResponse(FillResponse response) {
- mResponse = response;
+ setResponse(response, /* isPrimary= */ true);
+ }
+
+ void setResponse(@Nullable FillResponse response, boolean isPrimary) {
+ if (isPrimary) {
+ mPrimaryFillResponse = response;
+ } else {
+ mSecondaryFillResponse = response;
+ }
}
int getState() {
@@ -211,13 +235,24 @@
return;
}
// First try the current response associated with this View.
- if (mResponse != null) {
- if (mResponse.getDatasets() != null || mResponse.getAuthentication() != null) {
- mListener.onFillReady(mResponse, this.id, mCurrentValue, flags);
+ FillResponse requestedResponse = requestingPrimaryResponse(flags)
+ ? mPrimaryFillResponse : mSecondaryFillResponse;
+ if (requestedResponse != null) {
+ if (requestedResponse.getDatasets() != null
+ || requestedResponse.getAuthentication() != null) {
+ mListener.onFillReady(requestedResponse, this.id, mCurrentValue, flags);
}
}
}
+ private boolean requestingPrimaryResponse(int flags) {
+ if (mIsPrimaryCredential) {
+ return (flags & FLAG_VIEW_REQUESTS_CREDMAN_SERVICE) != 0;
+ } else {
+ return (flags & FLAG_VIEW_REQUESTS_CREDMAN_SERVICE) == 0;
+ }
+ }
+
@Override
public String toString() {
final StringBuilder builder = new StringBuilder("ViewState: [id=").append(id);
@@ -247,8 +282,14 @@
pw.print(prefix); pw.print("datasetId:" ); pw.println(mDatasetId);
}
pw.print(prefix); pw.print("state:" ); pw.println(getStateAsString());
- if (mResponse != null) {
- pw.print(prefix); pw.print("response id:");pw.println(mResponse.getRequestId());
+ pw.print(prefix); pw.print("is primary credential:"); pw.println(mIsPrimaryCredential);
+ if (mPrimaryFillResponse != null) {
+ pw.print(prefix); pw.print("primary response id:");
+ pw.println(mPrimaryFillResponse.getRequestId());
+ }
+ if (mSecondaryFillResponse != null) {
+ pw.print(prefix); pw.print("secondary response id:");
+ pw.println(mSecondaryFillResponse.getRequestId());
}
if (mCurrentValue != null) {
pw.print(prefix); pw.print("currentValue:" ); pw.println(mCurrentValue);
diff --git a/services/core/Android.bp b/services/core/Android.bp
index 8ed3fd6..b4cf34e 100644
--- a/services/core/Android.bp
+++ b/services/core/Android.bp
@@ -201,6 +201,7 @@
"biometrics_flags_lib",
"am_flags_lib",
"com_android_wm_shell_flags_lib",
+ "com.android.server.utils_aconfig-java",
"service-jobscheduler-deviceidle.flags-aconfig-java",
],
javac_shard_size: 50,
diff --git a/services/core/java/com/android/server/BinaryTransparencyService.java b/services/core/java/com/android/server/BinaryTransparencyService.java
index eb3ec24..05d07ae 100644
--- a/services/core/java/com/android/server/BinaryTransparencyService.java
+++ b/services/core/java/com/android/server/BinaryTransparencyService.java
@@ -1464,15 +1464,17 @@
FrameworkStatsLog.write(FrameworkStatsLog.VBMETA_DIGEST_REPORTED, mVbmetaDigest);
if (android.security.Flags.binaryTransparencySepolicyHash()) {
- byte[] sepolicyHash = PackageUtils.computeSha256DigestForLargeFileAsBytes(
- "/sys/fs/selinux/policy", PackageUtils.createLargeFileBuffer());
- String sepolicyHashEncoded = null;
- if (sepolicyHash != null) {
- sepolicyHashEncoded = HexEncoding.encodeToString(sepolicyHash, false);
- Slog.d(TAG, "sepolicy hash: " + sepolicyHashEncoded);
- }
- FrameworkStatsLog.write(FrameworkStatsLog.BOOT_INTEGRITY_INFO_REPORTED,
- sepolicyHashEncoded, mVbmetaDigest);
+ IoThread.getExecutor().execute(() -> {
+ byte[] sepolicyHash = PackageUtils.computeSha256DigestForLargeFileAsBytes(
+ "/sys/fs/selinux/policy", PackageUtils.createLargeFileBuffer());
+ String sepolicyHashEncoded = null;
+ if (sepolicyHash != null) {
+ sepolicyHashEncoded = HexEncoding.encodeToString(sepolicyHash, false);
+ Slog.d(TAG, "sepolicy hash: " + sepolicyHashEncoded);
+ }
+ FrameworkStatsLog.write(FrameworkStatsLog.BOOT_INTEGRITY_INFO_REPORTED,
+ sepolicyHashEncoded, mVbmetaDigest);
+ });
}
}
diff --git a/services/core/java/com/android/server/Watchdog.java b/services/core/java/com/android/server/Watchdog.java
index 382ee6e..4bb9f4f 100644
--- a/services/core/java/com/android/server/Watchdog.java
+++ b/services/core/java/com/android/server/Watchdog.java
@@ -103,7 +103,7 @@
// will be half the full timeout).
//
// The pre-watchdog event is similar to a full watchdog except it does not crash system server.
- private static final int PRE_WATCHDOG_TIMEOUT_RATIO = 3;
+ private static final int PRE_WATCHDOG_TIMEOUT_RATIO = 4;
// These are temporally ordered: larger values as lateness increases
static final int COMPLETED = 0;
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index 5f1a7e7..7191684 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -241,6 +241,7 @@
import com.android.server.am.ServiceRecord.ShortFgsInfo;
import com.android.server.pm.KnownPackages;
import com.android.server.uri.NeededUriGrants;
+import com.android.server.utils.AnrTimer;
import com.android.server.wm.ActivityServiceConnectionsHolder;
import java.io.FileDescriptor;
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 469f209..3e533a6 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -475,6 +475,7 @@
import com.android.server.uri.GrantUri;
import com.android.server.uri.NeededUriGrants;
import com.android.server.uri.UriGrantsManagerInternal;
+import com.android.server.utils.AnrTimer;
import com.android.server.utils.PriorityDump;
import com.android.server.utils.Slogf;
import com.android.server.utils.TimingsTraceAndSlog;
@@ -1709,19 +1710,23 @@
private static final int INDEX_NATIVE_PSS = 0;
private static final int INDEX_NATIVE_SWAP_PSS = 1;
private static final int INDEX_NATIVE_RSS = 2;
- private static final int INDEX_DALVIK_PSS = 3;
- private static final int INDEX_DALVIK_SWAP_PSS = 4;
- private static final int INDEX_DALVIK_RSS = 5;
- private static final int INDEX_OTHER_PSS = 6;
- private static final int INDEX_OTHER_SWAP_PSS = 7;
- private static final int INDEX_OTHER_RSS = 8;
- private static final int INDEX_TOTAL_PSS = 9;
- private static final int INDEX_TOTAL_SWAP_PSS = 10;
- private static final int INDEX_TOTAL_RSS = 11;
- private static final int INDEX_TOTAL_NATIVE_PSS = 12;
- private static final int INDEX_TOTAL_MEMTRACK_GRAPHICS = 13;
- private static final int INDEX_TOTAL_MEMTRACK_GL = 14;
- private static final int INDEX_LAST = 15;
+ private static final int INDEX_NATIVE_PRIVATE_DIRTY = 3;
+ private static final int INDEX_DALVIK_PSS = 4;
+ private static final int INDEX_DALVIK_SWAP_PSS = 5;
+ private static final int INDEX_DALVIK_RSS = 6;
+ private static final int INDEX_DALVIK_PRIVATE_DIRTY = 7;
+ private static final int INDEX_OTHER_PSS = 8;
+ private static final int INDEX_OTHER_SWAP_PSS = 9;
+ private static final int INDEX_OTHER_RSS = 10;
+ private static final int INDEX_OTHER_PRIVATE_DIRTY = 11;
+ private static final int INDEX_TOTAL_PSS = 12;
+ private static final int INDEX_TOTAL_SWAP_PSS = 13;
+ private static final int INDEX_TOTAL_RSS = 14;
+ private static final int INDEX_TOTAL_PRIVATE_DIRTY = 15;
+ private static final int INDEX_TOTAL_NATIVE_PSS = 16;
+ private static final int INDEX_TOTAL_MEMTRACK_GRAPHICS = 17;
+ private static final int INDEX_TOTAL_MEMTRACK_GL = 18;
+ private static final int INDEX_LAST = 19;
/**
* Used to notify activity lifecycle events.
@@ -11711,13 +11716,14 @@
final long pss;
final long swapPss;
final long mRss;
+ final long mPrivateDirty;
final int id; // pid
final int userId;
final boolean hasActivities;
ArrayList<MemItem> subitems;
- MemItem(String label, String shortLabel, long pss, long swapPss, long rss, int id,
- @UserIdInt int userId,
+ MemItem(String label, String shortLabel, long pss, long swapPss, long rss,
+ long privateDirty, int id, @UserIdInt int userId,
boolean hasActivities) {
this.isProc = true;
this.label = label;
@@ -11725,18 +11731,21 @@
this.pss = pss;
this.swapPss = swapPss;
this.mRss = rss;
+ this.mPrivateDirty = privateDirty;
this.id = id;
this.userId = userId;
this.hasActivities = hasActivities;
}
- MemItem(String label, String shortLabel, long pss, long swapPss, long rss, int id) {
+ MemItem(String label, String shortLabel, long pss, long swapPss, long rss,
+ long privateDirty, int id) {
this.isProc = false;
this.label = label;
this.shortLabel = shortLabel;
this.pss = pss;
this.swapPss = swapPss;
this.mRss = rss;
+ this.mPrivateDirty = privateDirty;
this.id = id;
this.userId = UserHandle.USER_SYSTEM;
this.hasActivities = false;
@@ -11761,7 +11770,7 @@
static final void dumpMemItems(PrintWriter pw, String prefix, String tag,
ArrayList<MemItem> items, boolean sort, boolean isCompact, boolean dumpPss,
- boolean dumpSwapPss) {
+ boolean dumpSwapPss, boolean dumpPrivateDirty) {
if (sort && !isCompact) {
sortMemItems(items, dumpPss);
}
@@ -11769,14 +11778,18 @@
for (int i=0; i<items.size(); i++) {
MemItem mi = items.get(i);
if (!isCompact) {
- if (dumpPss && dumpSwapPss) {
- pw.printf("%s%s: %-60s (%s in swap)\n", prefix, stringifyKBSize(mi.pss),
- mi.label, stringifyKBSize(mi.swapPss));
- } else {
- pw.printf("%s%s: %s%s\n", prefix, stringifyKBSize(dumpPss ? mi.pss : mi.mRss),
+ pw.printf("%s%s: %s%s\n", prefix, stringifyKBSize(dumpPss ? mi.pss : mi.mRss),
mi.label,
mi.userId != UserHandle.USER_SYSTEM ? " (user " + mi.userId + ")" : "");
+ if (dumpPss && dumpSwapPss) {
+ pw.printf("(%s in swap%s", stringifyKBSize(mi.swapPss),
+ dumpPrivateDirty ? ", " : ")");
}
+ if (dumpPrivateDirty) {
+ pw.printf("%s%s private dirty)", dumpSwapPss ? "" : "(",
+ stringifyKBSize(mi.mPrivateDirty));
+ }
+ pw.printf("\n");
} else if (mi.isProc) {
pw.print("proc,"); pw.print(tag); pw.print(","); pw.print(mi.shortLabel);
pw.print(","); pw.print(mi.id); pw.print(",");
@@ -11790,7 +11803,7 @@
}
if (mi.subitems != null) {
dumpMemItems(pw, prefix + " ", mi.shortLabel, mi.subitems,
- true, isCompact, dumpPss, dumpSwapPss);
+ true, isCompact, dumpPss, dumpSwapPss, dumpPrivateDirty);
}
}
}
@@ -11958,6 +11971,7 @@
boolean isCheckinRequest;
boolean dumpSwapPss;
boolean dumpProto;
+ boolean mDumpPrivateDirty;
}
@NeverCompile // Avoid size overhead of debugging code.
@@ -11976,6 +11990,7 @@
opts.isCheckinRequest = false;
opts.dumpSwapPss = false;
opts.dumpProto = asProto;
+ opts.mDumpPrivateDirty = false;
int opti = 0;
while (opti < args.length) {
@@ -11998,6 +12013,8 @@
opts.dumpSummaryOnly = true;
} else if ("-S".equals(opt)) {
opts.dumpSwapPss = true;
+ } else if ("-p".equals(opt)) {
+ opts.mDumpPrivateDirty = true;
} else if ("--unreachable".equals(opt)) {
opts.dumpUnreachable = true;
} else if ("--oom".equals(opt)) {
@@ -12018,6 +12035,7 @@
pw.println(" -c: dump in a compact machine-parseable representation.");
pw.println(" -s: dump only summary of application memory usage.");
pw.println(" -S: dump also SwapPss.");
+ pw.println(" -p: dump also private dirty memory usage.");
pw.println(" --oom: only show processes organized by oom adj.");
pw.println(" --local: only collect details locally, don't call process.");
pw.println(" --package: interpret process arg as package, dumping all");
@@ -12136,14 +12154,18 @@
EmptyArray.LONG;
long[] dalvikSubitemRss = opts.dumpDalvik ? new long[Debug.MemoryInfo.NUM_DVK_STATS] :
EmptyArray.LONG;
+ long[] dalvikSubitemPrivateDirty = opts.dumpDalvik
+ ? new long[Debug.MemoryInfo.NUM_DVK_STATS] : EmptyArray.LONG;
long[] miscPss = new long[Debug.MemoryInfo.NUM_OTHER_STATS];
long[] miscSwapPss = new long[Debug.MemoryInfo.NUM_OTHER_STATS];
long[] miscRss = new long[Debug.MemoryInfo.NUM_OTHER_STATS];
+ long[] miscPrivateDirty = new long[Debug.MemoryInfo.NUM_OTHER_STATS];
long[] memtrackTmp = new long[4];
long oomPss[] = new long[DUMP_MEM_OOM_LABEL.length];
long oomSwapPss[] = new long[DUMP_MEM_OOM_LABEL.length];
long[] oomRss = new long[DUMP_MEM_OOM_LABEL.length];
+ long[] oomPrivateDirty = new long[DUMP_MEM_OOM_LABEL.length];
ArrayList<MemItem>[] oomProcs = (ArrayList<MemItem>[])
new ArrayList[DUMP_MEM_OOM_LABEL.length];
@@ -12239,6 +12261,7 @@
final long myTotalUss = mi.getTotalUss();
final long myTotalRss = mi.getTotalRss();
final long myTotalSwapPss = mi.getTotalSwappedOutPss();
+ final long myTotalPrivateDirty = mi.getTotalPrivateDirty();
synchronized (mProcLock) {
if (r.getThread() != null && oomAdj == r.mState.getSetAdjWithServices()) {
@@ -12252,29 +12275,36 @@
ss[INDEX_TOTAL_PSS] += myTotalPss;
ss[INDEX_TOTAL_SWAP_PSS] += myTotalSwapPss;
ss[INDEX_TOTAL_RSS] += myTotalRss;
+ ss[INDEX_TOTAL_PRIVATE_DIRTY] += myTotalPrivateDirty;
ss[INDEX_TOTAL_MEMTRACK_GRAPHICS] += memtrackGraphics;
ss[INDEX_TOTAL_MEMTRACK_GL] += memtrackGl;
MemItem pssItem = new MemItem(r.processName + " (pid " + pid +
(hasActivities ? " / activities)" : ")"), r.processName, myTotalPss,
- myTotalSwapPss, myTotalRss, pid, r.userId, hasActivities);
+ myTotalSwapPss, myTotalRss, myTotalPrivateDirty,
+ pid, r.userId, hasActivities);
procMems.add(pssItem);
procMemsMap.put(pid, pssItem);
ss[INDEX_NATIVE_PSS] += mi.nativePss;
ss[INDEX_NATIVE_SWAP_PSS] += mi.nativeSwappedOutPss;
ss[INDEX_NATIVE_RSS] += mi.nativeRss;
+ ss[INDEX_NATIVE_PRIVATE_DIRTY] += mi.nativePrivateDirty;
ss[INDEX_DALVIK_PSS] += mi.dalvikPss;
ss[INDEX_DALVIK_SWAP_PSS] += mi.dalvikSwappedOutPss;
ss[INDEX_DALVIK_RSS] += mi.dalvikRss;
+ ss[INDEX_DALVIK_PRIVATE_DIRTY] += mi.dalvikPrivateDirty;
for (int j=0; j<dalvikSubitemPss.length; j++) {
dalvikSubitemPss[j] += mi.getOtherPss(Debug.MemoryInfo.NUM_OTHER_STATS + j);
dalvikSubitemSwapPss[j] +=
mi.getOtherSwappedOutPss(Debug.MemoryInfo.NUM_OTHER_STATS + j);
+ dalvikSubitemPrivateDirty[j] +=
+ mi.getOtherPrivateDirty(Debug.MemoryInfo.NUM_OTHER_STATS + j);
dalvikSubitemRss[j] += mi.getOtherRss(Debug.MemoryInfo.NUM_OTHER_STATS + j);
}
ss[INDEX_OTHER_PSS] += mi.otherPss;
ss[INDEX_OTHER_RSS] += mi.otherRss;
ss[INDEX_OTHER_SWAP_PSS] += mi.otherSwappedOutPss;
+ ss[INDEX_OTHER_PRIVATE_DIRTY] += mi.otherPrivateDirty;
for (int j=0; j<Debug.MemoryInfo.NUM_OTHER_STATS; j++) {
long mem = mi.getOtherPss(j);
miscPss[j] += mem;
@@ -12282,6 +12312,9 @@
mem = mi.getOtherSwappedOutPss(j);
miscSwapPss[j] += mem;
ss[INDEX_OTHER_SWAP_PSS] -= mem;
+ mem = mi.getOtherPrivateDirty(j);
+ miscPrivateDirty[j] += mem;
+ ss[INDEX_OTHER_PRIVATE_DIRTY] -= mem;
mem = mi.getOtherRss(j);
miscRss[j] += mem;
ss[INDEX_OTHER_RSS] -= mem;
@@ -12298,6 +12331,7 @@
&& oomAdj < DUMP_MEM_OOM_ADJ[oomIndex + 1])) {
oomPss[oomIndex] += myTotalPss;
oomSwapPss[oomIndex] += myTotalSwapPss;
+ oomPrivateDirty[oomIndex] += myTotalPrivateDirty;
if (oomProcs[oomIndex] == null) {
oomProcs[oomIndex] = new ArrayList<MemItem>();
}
@@ -12344,6 +12378,7 @@
final long myTotalPss = info.getTotalPss();
final long myTotalSwapPss = info.getTotalSwappedOutPss();
final long myTotalRss = info.getTotalRss();
+ final long myTotalPrivateDirty = info.getTotalPrivateDirty();
ss[INDEX_TOTAL_PSS] += myTotalPss;
ss[INDEX_TOTAL_SWAP_PSS] += myTotalSwapPss;
ss[INDEX_TOTAL_RSS] += myTotalRss;
@@ -12353,15 +12388,17 @@
MemItem pssItem = new MemItem(st.name + " (pid " + st.pid + ")",
st.name, myTotalPss, info.getSummaryTotalSwapPss(), myTotalRss,
- st.pid, UserHandle.getUserId(st.uid), false);
+ myTotalPrivateDirty, st.pid, UserHandle.getUserId(st.uid), false);
procMems.add(pssItem);
ss[INDEX_NATIVE_PSS] += info.nativePss;
ss[INDEX_NATIVE_SWAP_PSS] += info.nativeSwappedOutPss;
ss[INDEX_NATIVE_RSS] += info.nativeRss;
+ ss[INDEX_NATIVE_PRIVATE_DIRTY] += info.nativePrivateDirty;
ss[INDEX_DALVIK_PSS] += info.dalvikPss;
ss[INDEX_DALVIK_SWAP_PSS] += info.dalvikSwappedOutPss;
ss[INDEX_DALVIK_RSS] += info.dalvikRss;
+ ss[INDEX_DALVIK_PRIVATE_DIRTY] += info.dalvikPrivateDirty;
for (int j = 0; j < dalvikSubitemPss.length; j++) {
dalvikSubitemPss[j] += info.getOtherPss(
Debug.MemoryInfo.NUM_OTHER_STATS + j);
@@ -12369,10 +12406,13 @@
info.getOtherSwappedOutPss(Debug.MemoryInfo.NUM_OTHER_STATS + j);
dalvikSubitemRss[j] += info.getOtherRss(Debug.MemoryInfo.NUM_OTHER_STATS
+ j);
+ dalvikSubitemPrivateDirty[j] +=
+ info.getOtherPrivateDirty(Debug.MemoryInfo.NUM_OTHER_STATS + j);
}
ss[INDEX_OTHER_PSS] += info.otherPss;
ss[INDEX_OTHER_SWAP_PSS] += info.otherSwappedOutPss;
ss[INDEX_OTHER_RSS] += info.otherRss;
+ ss[INDEX_OTHER_PRIVATE_DIRTY] += info.otherPrivateDirty;
for (int j = 0; j < Debug.MemoryInfo.NUM_OTHER_STATS; j++) {
long mem = info.getOtherPss(j);
miscPss[j] += mem;
@@ -12383,6 +12423,9 @@
mem = info.getOtherRss(j);
miscRss[j] += mem;
ss[INDEX_OTHER_RSS] -= mem;
+ mem = info.getOtherPrivateDirty(j);
+ miscPrivateDirty[j] += mem;
+ ss[INDEX_OTHER_PRIVATE_DIRTY] -= mem;
}
oomPss[0] += myTotalPss;
oomSwapPss[0] += myTotalSwapPss;
@@ -12391,21 +12434,26 @@
}
oomProcs[0].add(pssItem);
oomRss[0] += myTotalRss;
+ oomPrivateDirty[0] += myTotalPrivateDirty;
}
});
ArrayList<MemItem> catMems = new ArrayList<MemItem>();
catMems.add(new MemItem("Native", "Native",
- ss[INDEX_NATIVE_PSS], ss[INDEX_NATIVE_SWAP_PSS], ss[INDEX_NATIVE_RSS], -1));
+ ss[INDEX_NATIVE_PSS], ss[INDEX_NATIVE_SWAP_PSS],
+ ss[INDEX_NATIVE_RSS], ss[INDEX_NATIVE_PRIVATE_DIRTY], -1));
final int dalvikId = -2;
catMems.add(new MemItem("Dalvik", "Dalvik", ss[INDEX_DALVIK_PSS],
- ss[INDEX_DALVIK_SWAP_PSS], ss[INDEX_DALVIK_RSS], dalvikId));
+ ss[INDEX_DALVIK_SWAP_PSS], ss[INDEX_DALVIK_RSS],
+ ss[INDEX_DALVIK_PRIVATE_DIRTY], dalvikId));
catMems.add(new MemItem("Unknown", "Unknown", ss[INDEX_OTHER_PSS],
- ss[INDEX_OTHER_SWAP_PSS], ss[INDEX_OTHER_RSS], -3));
+ ss[INDEX_OTHER_SWAP_PSS], ss[INDEX_OTHER_RSS],
+ ss[INDEX_OTHER_PRIVATE_DIRTY], -3));
for (int j=0; j<Debug.MemoryInfo.NUM_OTHER_STATS; j++) {
String label = Debug.MemoryInfo.getOtherLabel(j);
- catMems.add(new MemItem(label, label, miscPss[j], miscSwapPss[j], miscRss[j], j));
+ catMems.add(new MemItem(label, label, miscPss[j], miscSwapPss[j], miscRss[j],
+ miscPrivateDirty[j], j));
}
if (dalvikSubitemPss.length > 0) {
// Add dalvik subitems.
@@ -12431,7 +12479,8 @@
final String name = Debug.MemoryInfo.getOtherLabel(
Debug.MemoryInfo.NUM_OTHER_STATS + j);
memItem.subitems.add(new MemItem(name, name, dalvikSubitemPss[j],
- dalvikSubitemSwapPss[j], dalvikSubitemRss[j], j));
+ dalvikSubitemSwapPss[j], dalvikSubitemRss[j],
+ dalvikSubitemPrivateDirty[j], j));
}
}
}
@@ -12442,7 +12491,7 @@
String label = opts.isCompact ? DUMP_MEM_OOM_COMPACT_LABEL[j]
: DUMP_MEM_OOM_LABEL[j];
MemItem item = new MemItem(label, label, oomPss[j], oomSwapPss[j], oomRss[j],
- DUMP_MEM_OOM_ADJ[j]);
+ oomPrivateDirty[j], DUMP_MEM_OOM_ADJ[j]);
item.subitems = oomProcs[j];
oomMems.add(item);
}
@@ -12453,33 +12502,34 @@
if (!brief && !opts.oomOnly && !opts.isCompact) {
pw.println();
pw.println("Total RSS by process:");
- dumpMemItems(pw, " ", "proc", procMems, true, opts.isCompact, false, false);
+ dumpMemItems(pw, " ", "proc", procMems, true, opts.isCompact, false, false, false);
pw.println();
}
if (!opts.isCompact) {
pw.println("Total RSS by OOM adjustment:");
}
- dumpMemItems(pw, " ", "oom", oomMems, false, opts.isCompact, false, false);
+ dumpMemItems(pw, " ", "oom", oomMems, false, opts.isCompact, false, false, false);
if (!brief && !opts.oomOnly) {
PrintWriter out = categoryPw != null ? categoryPw : pw;
if (!opts.isCompact) {
out.println();
out.println("Total RSS by category:");
}
- dumpMemItems(out, " ", "cat", catMems, true, opts.isCompact, false, false);
+ dumpMemItems(out, " ", "cat", catMems, true, opts.isCompact, false, false, false);
}
opts.dumpSwapPss = opts.dumpSwapPss && hasSwapPss && ss[INDEX_TOTAL_SWAP_PSS] != 0;
if (!brief && !opts.oomOnly && !opts.isCompact) {
pw.println();
pw.println("Total PSS by process:");
dumpMemItems(pw, " ", "proc", procMems, true, opts.isCompact, true,
- opts.dumpSwapPss);
+ opts.dumpSwapPss, opts.mDumpPrivateDirty);
pw.println();
}
if (!opts.isCompact) {
pw.println("Total PSS by OOM adjustment:");
}
- dumpMemItems(pw, " ", "oom", oomMems, false, opts.isCompact, true, opts.dumpSwapPss);
+ dumpMemItems(pw, " ", "oom", oomMems, false, opts.isCompact, true, opts.dumpSwapPss,
+ opts.mDumpPrivateDirty);
if (!brief && !opts.oomOnly) {
PrintWriter out = categoryPw != null ? categoryPw : pw;
if (!opts.isCompact) {
@@ -12487,7 +12537,7 @@
out.println("Total PSS by category:");
}
dumpMemItems(out, " ", "cat", catMems, true, opts.isCompact, true,
- opts.dumpSwapPss);
+ opts.dumpSwapPss, opts.mDumpPrivateDirty);
}
if (!opts.isCompact) {
pw.println();
@@ -12889,7 +12939,7 @@
ss[INDEX_TOTAL_RSS] += myTotalRss;
MemItem pssItem = new MemItem(r.processName + " (pid " + pid +
(hasActivities ? " / activities)" : ")"), r.processName, myTotalPss,
- myTotalSwapPss, myTotalRss, pid, r.userId, hasActivities);
+ myTotalSwapPss, myTotalRss, 0, pid, r.userId, hasActivities);
procMems.add(pssItem);
procMemsMap.put(pid, pssItem);
@@ -12976,7 +13026,7 @@
ss[INDEX_TOTAL_NATIVE_PSS] += myTotalPss;
MemItem pssItem = new MemItem(st.name + " (pid " + st.pid + ")",
- st.name, myTotalPss, info.getSummaryTotalSwapPss(), myTotalRss,
+ st.name, myTotalPss, info.getSummaryTotalSwapPss(), myTotalRss, 0,
st.pid, UserHandle.getUserId(st.uid), false);
procMems.add(pssItem);
@@ -13021,15 +13071,16 @@
ArrayList<MemItem> catMems = new ArrayList<MemItem>();
catMems.add(new MemItem("Native", "Native", ss[INDEX_NATIVE_PSS],
- ss[INDEX_NATIVE_SWAP_PSS], ss[INDEX_NATIVE_RSS], -1));
+ ss[INDEX_NATIVE_SWAP_PSS], ss[INDEX_NATIVE_RSS], 0, -1));
final int dalvikId = -2;
catMems.add(new MemItem("Dalvik", "Dalvik", ss[INDEX_DALVIK_PSS],
- ss[INDEX_DALVIK_SWAP_PSS], ss[INDEX_DALVIK_RSS], dalvikId));
+ ss[INDEX_DALVIK_SWAP_PSS], ss[INDEX_DALVIK_RSS], 0, dalvikId));
catMems.add(new MemItem("Unknown", "Unknown", ss[INDEX_OTHER_PSS],
- ss[INDEX_OTHER_SWAP_PSS], ss[INDEX_OTHER_RSS], -3));
+ ss[INDEX_OTHER_SWAP_PSS], ss[INDEX_OTHER_RSS], 0, -3));
for (int j=0; j<Debug.MemoryInfo.NUM_OTHER_STATS; j++) {
String label = Debug.MemoryInfo.getOtherLabel(j);
- catMems.add(new MemItem(label, label, miscPss[j], miscSwapPss[j], miscRss[j], j));
+ catMems.add(new MemItem(label, label, miscPss[j], miscSwapPss[j],
+ miscRss[j], 0, j));
}
if (dalvikSubitemPss.length > 0) {
// Add dalvik subitems.
@@ -13055,7 +13106,7 @@
final String name = Debug.MemoryInfo.getOtherLabel(
Debug.MemoryInfo.NUM_OTHER_STATS + j);
memItem.subitems.add(new MemItem(name, name, dalvikSubitemPss[j],
- dalvikSubitemSwapPss[j], dalvikSubitemRss[j], j));
+ dalvikSubitemSwapPss[j], dalvikSubitemRss[j], 0, j));
}
}
}
@@ -13065,7 +13116,7 @@
if (oomPss[j] != 0) {
String label = opts.isCompact ? DUMP_MEM_OOM_COMPACT_LABEL[j]
: DUMP_MEM_OOM_LABEL[j];
- MemItem item = new MemItem(label, label, oomPss[j], oomSwapPss[j], oomRss[j],
+ MemItem item = new MemItem(label, label, oomPss[j], oomSwapPss[j], oomRss[j], 0,
DUMP_MEM_OOM_ADJ[j]);
item.subitems = oomProcs[j];
oomMems.add(item);
diff --git a/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java b/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java
index ad49991..2cac7a0 100644
--- a/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java
+++ b/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java
@@ -88,6 +88,7 @@
import com.android.server.am.BroadcastProcessQueue.BroadcastConsumer;
import com.android.server.am.BroadcastProcessQueue.BroadcastPredicate;
import com.android.server.am.BroadcastRecord.DeliveryState;
+import com.android.server.utils.AnrTimer;
import dalvik.annotation.optimization.NeverCompile;
diff --git a/services/core/java/com/android/server/am/flags.aconfig b/services/core/java/com/android/server/am/flags.aconfig
index 2ed079a..d9e8ddd 100644
--- a/services/core/java/com/android/server/am/flags.aconfig
+++ b/services/core/java/com/android/server/am/flags.aconfig
@@ -9,14 +9,6 @@
}
flag {
- name: "anr_timer_service_enabled"
- namespace: "system_performance"
- is_fixed_read_only: true
- description: "Feature flag for the ANR timer service"
- bug: "282428924"
-}
-
-flag {
name: "fgs_abuse_detection"
namespace: "backstage_power"
description: "Detect abusive FGS behavior for certain types (camera, mic, media, location)."
diff --git a/services/core/java/com/android/server/audio/AdiDeviceState.java b/services/core/java/com/android/server/audio/AdiDeviceState.java
index b91e633..ffdab7d 100644
--- a/services/core/java/com/android/server/audio/AdiDeviceState.java
+++ b/services/core/java/com/android/server/audio/AdiDeviceState.java
@@ -21,6 +21,8 @@
import static android.media.AudioSystem.isBluetoothDevice;
import static android.media.audio.Flags.automaticBtDeviceType;
+import static com.android.internal.annotations.VisibleForTesting.Visibility.PACKAGE;
+
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.media.AudioDeviceAttributes;
@@ -31,13 +33,16 @@
import android.util.Log;
import android.util.Pair;
+import com.android.internal.annotations.VisibleForTesting;
+
import java.util.Objects;
/**
* Class representing all devices that were previously or are currently connected. Data is
* persisted in {@link android.provider.Settings.Secure}
*/
-/*package*/ final class AdiDeviceState {
+@VisibleForTesting(visibility = PACKAGE)
+public final class AdiDeviceState {
private static final String TAG = "AS.AdiDeviceState";
private static final String SETTING_FIELD_SEPARATOR = ",";
diff --git a/services/core/java/com/android/server/audio/AudioDeviceInventory.java b/services/core/java/com/android/server/audio/AudioDeviceInventory.java
index 98b210f..e54bf64 100644
--- a/services/core/java/com/android/server/audio/AudioDeviceInventory.java
+++ b/services/core/java/com/android/server/audio/AudioDeviceInventory.java
@@ -31,6 +31,8 @@
import static android.media.audio.Flags.automaticBtDeviceType;
+import static com.android.internal.annotations.VisibleForTesting.Visibility.PACKAGE;
+
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.bluetooth.BluetoothAdapter;
@@ -347,7 +349,8 @@
* @return the found {@link AdiDeviceState} or {@code null} otherwise.
*/
@Nullable
- AdiDeviceState findBtDeviceStateForAddress(String address, int deviceType) {
+ @VisibleForTesting(visibility = PACKAGE)
+ public AdiDeviceState findBtDeviceStateForAddress(String address, int deviceType) {
Set<Integer> deviceSet;
if (isBluetoothA2dpOutDevice(deviceType)) {
deviceSet = DEVICE_OUT_ALL_A2DP_SET;
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 8cec24d..f7b7aaa 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -39,6 +39,7 @@
import static android.provider.Settings.Secure.VOLUME_HUSH_OFF;
import static android.provider.Settings.Secure.VOLUME_HUSH_VIBRATE;
+import static com.android.internal.annotations.VisibleForTesting.Visibility.PACKAGE;
import static com.android.media.audio.Flags.alarmMinVolumeZero;
import static com.android.media.audio.Flags.bluetoothMacAddressAnonymization;
import static com.android.media.audio.Flags.disablePrescaleAbsoluteVolume;
@@ -6785,7 +6786,8 @@
return mContentResolver;
}
- /*package*/ SettingsAdapter getSettings() {
+ @VisibleForTesting(visibility = PACKAGE)
+ public SettingsAdapter getSettings() {
return mSettings;
}
@@ -11250,7 +11252,9 @@
return mDeviceBroker.isBluetoothAudioDeviceCategoryFixed(address);
}
- /*package*/void onUpdatedAdiDeviceState(AdiDeviceState deviceState) {
+ /** Update the sound dose and spatializer state based on the new AdiDeviceState. */
+ @VisibleForTesting(visibility = PACKAGE)
+ public void onUpdatedAdiDeviceState(AdiDeviceState deviceState) {
if (deviceState == null) {
return;
}
diff --git a/services/core/java/com/android/server/content/SyncJobService.java b/services/core/java/com/android/server/content/SyncJobService.java
index cd3f0f0..1da7f0c 100644
--- a/services/core/java/com/android/server/content/SyncJobService.java
+++ b/services/core/java/com/android/server/content/SyncJobService.java
@@ -19,7 +19,6 @@
import android.annotation.Nullable;
import android.app.job.JobParameters;
import android.app.job.JobService;
-import android.content.pm.PackageManagerInternal;
import android.os.Message;
import android.os.SystemClock;
import android.util.Log;
@@ -29,7 +28,6 @@
import android.util.SparseLongArray;
import com.android.internal.annotations.GuardedBy;
-import com.android.server.LocalServices;
public class SyncJobService extends JobService {
private static final String TAG = "SyncManager";
@@ -99,20 +97,6 @@
return true;
}
- // TODO(b/209852664): remove this logic from here once it's added within JobScheduler.
- // JobScheduler should not call onStartJob for syncs whose source packages are stopped.
- // Until JS adds the relevant logic, this is a temporary solution to keep deferring syncs
- // for packages in the stopped state.
- if (android.content.pm.Flags.stayStopped()) {
- if (LocalServices.getService(PackageManagerInternal.class)
- .isPackageStopped(op.owningPackage, op.target.userId)) {
- if (Log.isLoggable(TAG, Log.DEBUG)) {
- Slog.d(TAG, "Skipping sync for force-stopped package: " + op.owningPackage);
- }
- return false;
- }
- }
-
boolean isLoggable = Log.isLoggable(TAG, Log.VERBOSE);
synchronized (sLock) {
final int jobId = params.getJobId();
diff --git a/services/core/java/com/android/server/display/color/ColorDisplayService.java b/services/core/java/com/android/server/display/color/ColorDisplayService.java
index e3aa161..a313bcf 100644
--- a/services/core/java/com/android/server/display/color/ColorDisplayService.java
+++ b/services/core/java/com/android/server/display/color/ColorDisplayService.java
@@ -1745,8 +1745,8 @@
@Override
public boolean setSaturationLevel(int level) {
- final boolean hasTransformsPermission = getContext()
- .checkCallingPermission(Manifest.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS)
+ final boolean hasTransformsPermission = getContext().checkCallingOrSelfPermission(
+ Manifest.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS)
== PackageManager.PERMISSION_GRANTED;
final boolean hasLegacyPermission = getContext()
.checkCallingPermission(Manifest.permission.CONTROL_DISPLAY_SATURATION)
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java
index 0671464..64abb81 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java
@@ -566,7 +566,9 @@
HdmiDeviceInfo cecDeviceInfo = mService.getHdmiCecNetwork().getCecDeviceInfo(address);
// If no non-default display name is available for the device, request the devices OSD name.
- if (cecDeviceInfo != null && cecDeviceInfo.getDisplayName().equals(
+ // On TV devices, the OSD name is queried in NewDeviceAction instead.
+ if (!mService.isTvDevice() && cecDeviceInfo != null
+ && cecDeviceInfo.getDisplayName().equals(
HdmiUtils.getDefaultDeviceName(address))) {
mService.sendCecCommand(
HdmiCecMessageBuilder.buildGiveOsdNameCommand(
@@ -1117,6 +1119,7 @@
}
// Returns all actions matched with given class type.
+ @VisibleForTesting
@ServiceThreadOnly
<T extends HdmiCecFeatureAction> List<T> getActions(final Class<T> clazz) {
assertRunOnServiceThread();
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java
index 824c8db..ba4d320 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java
@@ -126,6 +126,10 @@
private void launchDeviceDiscovery() {
assertRunOnServiceThread();
clearDeviceInfoList();
+ if (hasAction(DeviceDiscoveryAction.class)) {
+ Slog.i(TAG, "Device Discovery Action is in progress. Restarting.");
+ removeAction(DeviceDiscoveryAction.class);
+ }
DeviceDiscoveryAction action = new DeviceDiscoveryAction(this,
new DeviceDiscoveryAction.DeviceDiscoveryCallback() {
@Override
diff --git a/services/core/java/com/android/server/hdmi/RequestActiveSourceAction.java b/services/core/java/com/android/server/hdmi/RequestActiveSourceAction.java
index 017c86d..d250416 100644
--- a/services/core/java/com/android/server/hdmi/RequestActiveSourceAction.java
+++ b/services/core/java/com/android/server/hdmi/RequestActiveSourceAction.java
@@ -29,6 +29,12 @@
// State to wait for the <Active Source> message.
private static final int STATE_WAIT_FOR_ACTIVE_SOURCE = 1;
+ // Number of retries <Request Active Source> is sent if no device answers this message.
+ private static final int MAX_SEND_RETRY_COUNT = 1;
+
+ private int mSendRetryCount = 0;
+
+
RequestActiveSourceAction(HdmiCecLocalDevice source, IHdmiControlCallback callback) {
super(source, callback);
}
@@ -60,7 +66,12 @@
return;
}
if (mState == STATE_WAIT_FOR_ACTIVE_SOURCE) {
- finishWithCallback(HdmiControlManager.RESULT_TIMEOUT);
+ if (mSendRetryCount++ < MAX_SEND_RETRY_COUNT) {
+ sendCommand(HdmiCecMessageBuilder.buildRequestActiveSource(getSourceAddress()));
+ addTimer(mState, HdmiConfig.TIMEOUT_MS);
+ } else {
+ finishWithCallback(HdmiControlManager.RESULT_TIMEOUT);
+ }
}
}
}
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerInternal.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerInternal.java
index 14daf62..ffd714b 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerInternal.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerInternal.java
@@ -159,9 +159,12 @@
/**
* Updates the IME visibility, back disposition and show IME picker status for SystemUI.
* TODO(b/189923292): Making SystemUI to be true IME icon controller vs. presenter that
- * controlled by IMMS.
+ * controlled by IMMS.
+ *
+ * @param disableImeIcon indicates whether IME icon should be enabled or not
+ * @param displayId the display for which to update the IME window status
*/
- public abstract void updateImeWindowStatus(boolean disableImeIcon);
+ public abstract void updateImeWindowStatus(boolean disableImeIcon, int displayId);
/**
* Finish stylus handwriting by calling {@link InputMethodService#finishStylusHandwriting()} if
@@ -269,7 +272,7 @@
}
@Override
- public void updateImeWindowStatus(boolean disableImeIcon) {
+ public void updateImeWindowStatus(boolean disableImeIcon, int displayId) {
}
@Override
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index 98f627c..b1a362d 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -1188,23 +1188,6 @@
}
/**
- * {@link BroadcastReceiver} that is intended to listen to broadcasts sent to the system user
- * only.
- */
- private final class ImmsBroadcastReceiverForSystemUser extends BroadcastReceiver {
- @Override
- public void onReceive(Context context, Intent intent) {
- final String action = intent.getAction();
- if (Intent.ACTION_USER_ADDED.equals(action)
- || Intent.ACTION_USER_REMOVED.equals(action)) {
- updateCurrentProfileIds();
- } else {
- Slog.w(TAG, "Unexpected intent " + intent);
- }
- }
- }
-
- /**
* {@link BroadcastReceiver} that is intended to listen to broadcasts sent to all the users.
*/
private final class ImmsBroadcastReceiverForAllUsers extends BroadcastReceiver {
@@ -1611,9 +1594,16 @@
@Override
public void onUserUnlocking(@NonNull TargetUser user) {
// Called on ActivityManager thread.
+ SecureSettingsWrapper.onUserUnlocking(user.getUserIdentifier());
mService.mHandler.obtainMessage(MSG_SYSTEM_UNLOCK_USER, user.getUserIdentifier(), 0)
.sendToTarget();
}
+
+ @Override
+ public void onUserStarting(TargetUser user) {
+ // Called on ActivityManager thread.
+ SecureSettingsWrapper.onUserStarting(user.getUserIdentifier());
+ }
}
void onUnlockUser(@UserIdInt int userId) {
@@ -1665,6 +1655,7 @@
@Nullable InputMethodBindingController bindingControllerForTesting) {
mContext = context;
mRes = context.getResources();
+ SecureSettingsWrapper.onStart(mContext);
// TODO(b/196206770): Disallow I/O on this thread. Currently it's needed for loading
// additional subtypes in switchUserOnHandlerLocked().
final ServiceThread thread =
@@ -1700,7 +1691,6 @@
// mSettings should be created before buildInputMethodListLocked
mSettings = new InputMethodSettings(mContext, mMethodMap, userId, !mSystemReady);
- updateCurrentProfileIds();
AdditionalSubtypeUtils.load(mAdditionalSubtypeMap, userId);
mSwitchingController =
InputMethodSubtypeSwitchingController.createInstanceLocked(mSettings, context);
@@ -1818,7 +1808,6 @@
final boolean useCopyOnWriteSettings =
!mSystemReady || !mUserManagerInternal.isUserUnlockingOrUnlocked(newUserId);
mSettings.switchCurrentUser(newUserId, useCopyOnWriteSettings);
- updateCurrentProfileIds();
// Additional subtypes should be reset when the user is changed
AdditionalSubtypeUtils.load(mAdditionalSubtypeMap, newUserId);
final String defaultImiId = mSettings.getSelectedInputMethod();
@@ -1869,12 +1858,6 @@
}
}
- void updateCurrentProfileIds() {
- mSettings.setCurrentProfileIds(
- mUserManagerInternal.getProfileIds(mSettings.getCurrentUserId(),
- false /* enabledOnly */));
- }
-
/**
* TODO(b/32343335): The entire systemRunning() method needs to be revisited.
*/
@@ -1921,12 +1904,6 @@
mMyPackageMonitor.register(mContext, null, UserHandle.ALL, true);
mSettingsObserver.registerContentObserverLocked(currentUserId);
- final IntentFilter broadcastFilterForSystemUser = new IntentFilter();
- broadcastFilterForSystemUser.addAction(Intent.ACTION_USER_ADDED);
- broadcastFilterForSystemUser.addAction(Intent.ACTION_USER_REMOVED);
- mContext.registerReceiver(new ImmsBroadcastReceiverForSystemUser(),
- broadcastFilterForSystemUser);
-
final IntentFilter broadcastFilterForAllUsers = new IntentFilter();
broadcastFilterForAllUsers.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
mContext.registerReceiverAsUser(new ImmsBroadcastReceiverForAllUsers(),
@@ -3788,8 +3765,14 @@
mVisibilityStateComputer.mShowForced = false;
}
- // cross-profile access is always allowed here to allow profile-switching.
- if (!mSettings.isCurrentProfile(userId)) {
+ final int currentUserId = mSettings.getCurrentUserId();
+ if (userId != currentUserId) {
+ if (ArrayUtils.contains(
+ mUserManagerInternal.getProfileIds(currentUserId, false), userId)) {
+ // cross-profile access is always allowed here to allow profile-switching.
+ scheduleSwitchUserTaskLocked(userId, cs.mClient);
+ return InputBindResult.USER_SWITCHING;
+ }
Slog.w(TAG, "A background user is requesting window. Hiding IME.");
Slog.w(TAG, "If you need to impersonate a foreground user/profile from"
+ " a background user, use EditorInfo.targetInputMethodUser with"
@@ -3799,11 +3782,6 @@
return InputBindResult.INVALID_USER;
}
- if (userId != mSettings.getCurrentUserId()) {
- scheduleSwitchUserTaskLocked(userId, cs.mClient);
- return InputBindResult.USER_SWITCHING;
- }
-
final boolean sameWindowFocused = mCurFocusedWindow == windowToken;
final boolean isTextEditor = (startInputFlags & StartInputFlags.IS_TEXT_EDITOR) != 0;
final boolean startInputByWinGainedFocus =
@@ -5696,7 +5674,7 @@
}
@Override
- public void updateImeWindowStatus(boolean disableImeIcon) {
+ public void updateImeWindowStatus(boolean disableImeIcon, int displayId) {
mHandler.obtainMessage(MSG_UPDATE_IME_WINDOW_STATUS, disableImeIcon ? 1 : 0, 0)
.sendToTarget();
}
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodUtils.java b/services/core/java/com/android/server/inputmethod/InputMethodUtils.java
index c661c86..b4338f6 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodUtils.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodUtils.java
@@ -21,7 +21,6 @@
import android.annotation.UserHandleAware;
import android.annotation.UserIdInt;
import android.content.ComponentName;
-import android.content.ContentResolver;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
@@ -34,7 +33,6 @@
import android.provider.Settings;
import android.text.TextUtils;
import android.util.ArrayMap;
-import android.util.ArraySet;
import android.util.IntArray;
import android.util.Pair;
import android.util.Printer;
@@ -51,7 +49,6 @@
import java.io.PrintWriter;
import java.util.ArrayList;
-import java.util.Arrays;
import java.util.List;
import java.util.function.Predicate;
@@ -211,36 +208,15 @@
*/
@UserHandleAware
public static class InputMethodSettings {
- private final TextUtils.SimpleStringSplitter mInputMethodSplitter =
- new TextUtils.SimpleStringSplitter(INPUT_METHOD_SEPARATOR);
-
- private final TextUtils.SimpleStringSplitter mSubtypeSplitter =
- new TextUtils.SimpleStringSplitter(INPUT_METHOD_SUBTYPE_SEPARATOR);
-
@NonNull
private Context mUserAwareContext;
- private ContentResolver mResolver;
private final ArrayMap<String, InputMethodInfo> mMethodMap;
- /**
- * On-memory data store to emulate when {@link #mCopyOnWrite} is {@code true}.
- */
- private final ArrayMap<String, String> mCopyOnWriteDataStore = new ArrayMap<>();
-
- private static final ArraySet<String> CLONE_TO_MANAGED_PROFILE = new ArraySet<>();
- static {
- Settings.Secure.getCloneToManagedProfileSettings(CLONE_TO_MANAGED_PROFILE);
- }
-
- private static final UserManagerInternal sUserManagerInternal =
- LocalServices.getService(UserManagerInternal.class);
-
private boolean mCopyOnWrite = false;
@NonNull
private String mEnabledInputMethodsStrCache = "";
@UserIdInt
private int mCurrentUserId;
- private int[] mCurrentProfileIds = new int[0];
private static void buildEnabledInputMethodsSettingString(
StringBuilder builder, Pair<String, ArrayList<String>> ime) {
@@ -281,7 +257,6 @@
mUserAwareContext = context.getUserId() == userId
? context
: context.createContextAsUser(UserHandle.of(userId), 0 /* flags */);
- mResolver = mUserAwareContext.getContentResolver();
}
InputMethodSettings(@NonNull Context context,
@@ -305,79 +280,38 @@
Slog.d(TAG, "--- Switch the current user from " + mCurrentUserId + " to " + userId);
}
if (mCurrentUserId != userId || mCopyOnWrite != copyOnWrite) {
- mCopyOnWriteDataStore.clear();
mEnabledInputMethodsStrCache = "";
- // TODO: mCurrentProfileIds should be cleared here.
}
if (mUserAwareContext.getUserId() != userId) {
initContentWithUserContext(mUserAwareContext, userId);
}
mCurrentUserId = userId;
mCopyOnWrite = copyOnWrite;
- // TODO: mCurrentProfileIds should be updated here.
}
private void putString(@NonNull String key, @Nullable String str) {
- if (mCopyOnWrite) {
- mCopyOnWriteDataStore.put(key, str);
- } else {
- final int userId = CLONE_TO_MANAGED_PROFILE.contains(key)
- ? sUserManagerInternal.getProfileParentId(mCurrentUserId) : mCurrentUserId;
- Settings.Secure.putStringForUser(mResolver, key, str, userId);
- }
+ SecureSettingsWrapper.putString(key, str, mCurrentUserId);
}
@Nullable
private String getString(@NonNull String key, @Nullable String defaultValue) {
- final String result;
- if (mCopyOnWrite && mCopyOnWriteDataStore.containsKey(key)) {
- result = mCopyOnWriteDataStore.get(key);
- } else {
- result = Settings.Secure.getStringForUser(mResolver, key, mCurrentUserId);
- }
- return result != null ? result : defaultValue;
+ return SecureSettingsWrapper.getString(key, defaultValue, mCurrentUserId);
}
private void putInt(String key, int value) {
- if (mCopyOnWrite) {
- mCopyOnWriteDataStore.put(key, String.valueOf(value));
- } else {
- final int userId = CLONE_TO_MANAGED_PROFILE.contains(key)
- ? sUserManagerInternal.getProfileParentId(mCurrentUserId) : mCurrentUserId;
- Settings.Secure.putIntForUser(mResolver, key, value, userId);
- }
+ SecureSettingsWrapper.putInt(key, value, mCurrentUserId);
}
private int getInt(String key, int defaultValue) {
- if (mCopyOnWrite && mCopyOnWriteDataStore.containsKey(key)) {
- final String result = mCopyOnWriteDataStore.get(key);
- return result != null ? Integer.parseInt(result) : defaultValue;
- }
- return Settings.Secure.getIntForUser(mResolver, key, defaultValue, mCurrentUserId);
+ return SecureSettingsWrapper.getInt(key, defaultValue, mCurrentUserId);
}
private void putBoolean(String key, boolean value) {
- putInt(key, value ? 1 : 0);
+ SecureSettingsWrapper.putBoolean(key, value, mCurrentUserId);
}
private boolean getBoolean(String key, boolean defaultValue) {
- return getInt(key, defaultValue ? 1 : 0) == 1;
- }
-
- public void setCurrentProfileIds(int[] currentProfileIds) {
- synchronized (this) {
- mCurrentProfileIds = currentProfileIds;
- }
- }
-
- public boolean isCurrentProfile(int userId) {
- synchronized (this) {
- if (userId == mCurrentUserId) return true;
- for (int i = 0; i < mCurrentProfileIds.length; i++) {
- if (userId == mCurrentProfileIds[i]) return true;
- }
- return false;
- }
+ return SecureSettingsWrapper.getBoolean(key, defaultValue, mCurrentUserId);
}
ArrayList<InputMethodInfo> getEnabledInputMethodListLocked() {
@@ -428,8 +362,8 @@
List<Pair<String, ArrayList<String>>> getEnabledInputMethodsAndSubtypeListLocked() {
return buildInputMethodsAndSubtypeList(getEnabledInputMethodsStr(),
- mInputMethodSplitter,
- mSubtypeSplitter);
+ new TextUtils.SimpleStringSplitter(INPUT_METHOD_SEPARATOR),
+ new TextUtils.SimpleStringSplitter(INPUT_METHOD_SUBTYPE_SEPARATOR));
}
List<String> getEnabledInputMethodNames() {
@@ -700,16 +634,20 @@
if (TextUtils.isEmpty(subtypeHistoryStr)) {
return imsList;
}
- mInputMethodSplitter.setString(subtypeHistoryStr);
- while (mInputMethodSplitter.hasNext()) {
- String nextImsStr = mInputMethodSplitter.next();
- mSubtypeSplitter.setString(nextImsStr);
- if (mSubtypeSplitter.hasNext()) {
+ final TextUtils.SimpleStringSplitter inputMethodSplitter =
+ new TextUtils.SimpleStringSplitter(INPUT_METHOD_SEPARATOR);
+ final TextUtils.SimpleStringSplitter subtypeSplitter =
+ new TextUtils.SimpleStringSplitter(INPUT_METHOD_SUBTYPE_SEPARATOR);
+ inputMethodSplitter.setString(subtypeHistoryStr);
+ while (inputMethodSplitter.hasNext()) {
+ String nextImsStr = inputMethodSplitter.next();
+ subtypeSplitter.setString(nextImsStr);
+ if (subtypeSplitter.hasNext()) {
String subtypeId = NOT_A_SUBTYPE_ID_STR;
// The first element is ime id.
- String imeId = mSubtypeSplitter.next();
- while (mSubtypeSplitter.hasNext()) {
- subtypeId = mSubtypeSplitter.next();
+ String imeId = subtypeSplitter.next();
+ while (subtypeSplitter.hasNext()) {
+ subtypeId = subtypeSplitter.next();
break;
}
imsList.add(new Pair<>(imeId, subtypeId));
@@ -950,7 +888,6 @@
public void dumpLocked(final Printer pw, final String prefix) {
pw.println(prefix + "mCurrentUserId=" + mCurrentUserId);
- pw.println(prefix + "mCurrentProfileIds=" + Arrays.toString(mCurrentProfileIds));
pw.println(prefix + "mCopyOnWrite=" + mCopyOnWrite);
pw.println(prefix + "mEnabledInputMethodsStrCache=" + mEnabledInputMethodsStrCache);
}
@@ -1029,9 +966,7 @@
static List<String> getEnabledInputMethodIdsForFiltering(@NonNull Context context,
@UserIdInt int userId) {
final String enabledInputMethodsStr = TextUtils.nullIfEmpty(
- Settings.Secure.getStringForUser(
- context.getContentResolver(),
- Settings.Secure.ENABLED_INPUT_METHODS,
+ SecureSettingsWrapper.getString(Settings.Secure.ENABLED_INPUT_METHODS, null,
userId));
if (enabledInputMethodsStr == null) {
return List.of();
diff --git a/services/core/java/com/android/server/inputmethod/OWNERS b/services/core/java/com/android/server/inputmethod/OWNERS
index 6e5eb56..aa638aa 100644
--- a/services/core/java/com/android/server/inputmethod/OWNERS
+++ b/services/core/java/com/android/server/inputmethod/OWNERS
@@ -3,6 +3,8 @@
roosa@google.com
yukawa@google.com
tarandeep@google.com
+fstern@google.com
+cosminbaies@google.com
ogunwale@google.com #{LAST_RESORT_SUGGESTION}
jjaggi@google.com #{LAST_RESORT_SUGGESTION}
diff --git a/services/core/java/com/android/server/inputmethod/SecureSettingsWrapper.java b/services/core/java/com/android/server/inputmethod/SecureSettingsWrapper.java
new file mode 100644
index 0000000..559b625
--- /dev/null
+++ b/services/core/java/com/android/server/inputmethod/SecureSettingsWrapper.java
@@ -0,0 +1,371 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.inputmethod;
+
+import android.annotation.AnyThread;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.UserIdInt;
+import android.app.ActivityManagerInternal;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.pm.UserInfo;
+import android.provider.Settings;
+import android.util.ArrayMap;
+import android.util.ArraySet;
+import android.util.SparseArray;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.server.LocalServices;
+import com.android.server.pm.UserManagerInternal;
+
+/**
+ * A thread-safe utility class to encapsulate accesses to {@link Settings.Secure} that may need a
+ * special handling for direct-boot support.
+ *
+ * <p>Any changes made until the user storage is unlocked are non-persistent and will be reset
+ * to the persistent value when the user storage is unlocked.</p>
+ */
+final class SecureSettingsWrapper {
+ @Nullable
+ private static volatile ContentResolver sContentResolver = null;
+
+ /**
+ * Not intended to be instantiated.
+ */
+ private SecureSettingsWrapper() {
+ }
+
+ private static final ArraySet<String> CLONE_TO_MANAGED_PROFILE = new ArraySet<>();
+ static {
+ Settings.Secure.getCloneToManagedProfileSettings(CLONE_TO_MANAGED_PROFILE);
+ }
+
+ @AnyThread
+ @UserIdInt
+ private static int getUserIdForClonedSettings(@NonNull String key, @UserIdInt int userId) {
+ return CLONE_TO_MANAGED_PROFILE.contains(key)
+ ? LocalServices.getService(UserManagerInternal.class).getProfileParentId(userId)
+ : userId;
+ }
+
+ private interface ReaderWriter {
+ @AnyThread
+ void putString(@NonNull String key, @Nullable String value);
+
+ @AnyThread
+ @Nullable
+ String getString(@NonNull String key, @Nullable String defaultValue);
+
+ @AnyThread
+ void putInt(String key, int value);
+
+ @AnyThread
+ int getInt(String key, int defaultValue);
+ }
+
+ private static class UnlockedUserImpl implements ReaderWriter {
+ @UserIdInt
+ private final int mUserId;
+
+ private final ContentResolver mContentResolver;
+
+ UnlockedUserImpl(@UserIdInt int userId, @NonNull ContentResolver contentResolver) {
+ mUserId = userId;
+ mContentResolver = contentResolver;
+ }
+
+ @AnyThread
+ @Override
+ public void putString(String key, String value) {
+ final int userId = getUserIdForClonedSettings(key, mUserId);
+ Settings.Secure.putStringForUser(mContentResolver, key, value, userId);
+ }
+
+ @AnyThread
+ @Nullable
+ @Override
+ public String getString(String key, String defaultValue) {
+ final String result = Settings.Secure.getStringForUser(mContentResolver, key, mUserId);
+ return result != null ? result : defaultValue;
+ }
+
+ @AnyThread
+ @Override
+ public void putInt(String key, int value) {
+ final int userId = getUserIdForClonedSettings(key, mUserId);
+ Settings.Secure.putIntForUser(mContentResolver, key, value, userId);
+ }
+
+ @AnyThread
+ @Override
+ public int getInt(String key, int defaultValue) {
+ return Settings.Secure.getIntForUser(mContentResolver, key, defaultValue, mUserId);
+ }
+ }
+
+ /**
+ * For users whose storages are not unlocked yet, we do not want to update IME related Secure
+ * Settings. Any write operations will be forwarded to
+ * {@link LockedUserImpl#mNonPersistentKeyValues} so that we can return the volatile data until
+ * the user storage is unlocked.
+ */
+ private static final class LockedUserImpl extends UnlockedUserImpl {
+ @GuardedBy("mNonPersistentKeyValues")
+ private final ArrayMap<String, String> mNonPersistentKeyValues = new ArrayMap<>();
+
+ LockedUserImpl(@UserIdInt int userId, @NonNull ContentResolver contentResolver) {
+ super(userId, contentResolver);
+ }
+
+ @AnyThread
+ @Override
+ public void putString(String key, String value) {
+ synchronized (mNonPersistentKeyValues) {
+ mNonPersistentKeyValues.put(key, value);
+ }
+ }
+
+ @AnyThread
+ @Nullable
+ @Override
+ public String getString(String key, String defaultValue) {
+ synchronized (mNonPersistentKeyValues) {
+ if (mNonPersistentKeyValues.containsKey(key)) {
+ final String result = mNonPersistentKeyValues.get(key);
+ return result != null ? result : defaultValue;
+ }
+ return super.getString(key, defaultValue);
+ }
+ }
+
+ @AnyThread
+ @Override
+ public void putInt(String key, int value) {
+ synchronized (mNonPersistentKeyValues) {
+ mNonPersistentKeyValues.put(key, String.valueOf(value));
+ }
+ }
+
+ @AnyThread
+ @Override
+ public int getInt(String key, int defaultValue) {
+ synchronized (mNonPersistentKeyValues) {
+ if (mNonPersistentKeyValues.containsKey(key)) {
+ final String result = mNonPersistentKeyValues.get(key);
+ return result != null ? Integer.parseInt(result) : defaultValue;
+ }
+ return super.getInt(key, defaultValue);
+ }
+ }
+ }
+
+ @GuardedBy("sUserMap")
+ @NonNull
+ private static final SparseArray<ReaderWriter> sUserMap = new SparseArray<>();
+
+ private static final ReaderWriter NOOP = new ReaderWriter() {
+ @Override
+ public void putString(String key, String str) {
+ }
+
+ @Override
+ public String getString(String key, String defaultValue) {
+ return defaultValue;
+ }
+
+ @Override
+ public void putInt(String key, int value) {
+ }
+
+ @Override
+ public int getInt(String key, int defaultValue) {
+ return defaultValue;
+ }
+ };
+
+ private static ReaderWriter createImpl(@NonNull UserManagerInternal userManagerInternal,
+ @UserIdInt int userId) {
+ return userManagerInternal.isUserUnlockingOrUnlocked(userId)
+ ? new UnlockedUserImpl(userId, sContentResolver)
+ : new LockedUserImpl(userId, sContentResolver);
+ }
+
+ @NonNull
+ @AnyThread
+ private static ReaderWriter putOrGet(@UserIdInt int userId,
+ @NonNull ReaderWriter readerWriter) {
+ final boolean isUnlockedUserImpl = readerWriter instanceof UnlockedUserImpl;
+ synchronized (sUserMap) {
+ final ReaderWriter current = sUserMap.get(userId);
+ if (current == null) {
+ sUserMap.put(userId, readerWriter);
+ return readerWriter;
+ }
+ // Upgrading from CopyOnWriteImpl to DirectImpl is allowed.
+ if (current instanceof LockedUserImpl && isUnlockedUserImpl) {
+ sUserMap.put(userId, readerWriter);
+ return readerWriter;
+ }
+ return current;
+ }
+ }
+
+ @NonNull
+ @AnyThread
+ private static ReaderWriter get(@UserIdInt int userId) {
+ synchronized (sUserMap) {
+ final ReaderWriter readerWriter = sUserMap.get(userId);
+ if (readerWriter != null) {
+ return readerWriter;
+ }
+ }
+ final UserManagerInternal userManagerInternal =
+ LocalServices.getService(UserManagerInternal.class);
+ if (!userManagerInternal.exists(userId)) {
+ return NOOP;
+ }
+ return putOrGet(userId, createImpl(userManagerInternal, userId));
+ }
+
+ /**
+ * Called when {@link InputMethodManagerService} is starting.
+ *
+ * @param context the {@link Context} to be used.
+ */
+ @AnyThread
+ static void onStart(@NonNull Context context) {
+ sContentResolver = context.getContentResolver();
+
+ final int userId = LocalServices.getService(ActivityManagerInternal.class)
+ .getCurrentUserId();
+ final UserManagerInternal userManagerInternal =
+ LocalServices.getService(UserManagerInternal.class);
+ putOrGet(userId, createImpl(userManagerInternal, userId));
+
+ userManagerInternal.addUserLifecycleListener(
+ new UserManagerInternal.UserLifecycleListener() {
+ @Override
+ public void onUserRemoved(UserInfo user) {
+ synchronized (sUserMap) {
+ sUserMap.remove(userId);
+ }
+ }
+ }
+ );
+ }
+
+ /**
+ * Called when a user is starting.
+ *
+ * @param userId the ID of the user who is starting.
+ */
+ @AnyThread
+ static void onUserStarting(@UserIdInt int userId) {
+ putOrGet(userId, createImpl(LocalServices.getService(UserManagerInternal.class), userId));
+ }
+
+ /**
+ * Called when a user is being unlocked.
+ *
+ * @param userId the ID of the user whose storage is being unlocked.
+ */
+ @AnyThread
+ static void onUserUnlocking(@UserIdInt int userId) {
+ final ReaderWriter readerWriter = new UnlockedUserImpl(userId, sContentResolver);
+ putOrGet(userId, readerWriter);
+ }
+
+ /**
+ * Put the given string {@code value} to {@code key}.
+ *
+ * @param key a secure settings key.
+ * @param value a secure settings value.
+ * @param userId the ID of a user whose secure settings will be updated.
+ * @see Settings.Secure#putStringForUser(ContentResolver, String, String, int)
+ */
+ @AnyThread
+ static void putString(String key, String value, @UserIdInt int userId) {
+ get(userId).putString(key, value);
+ }
+
+ /**
+ * Get a string value with the given {@code key}
+ *
+ * @param key a secure settings key.
+ * @param defaultValue the default value when the value is not found.
+ * @param userId the ID of a user whose secure settings will be updated.
+ * @return The string value if it is found. {@code defaultValue} otherwise.
+ * @see Settings.Secure#getStringForUser(ContentResolver, String, int)
+ */
+ @AnyThread
+ @Nullable
+ static String getString(String key, String defaultValue, @UserIdInt int userId) {
+ return get(userId).getString(key, defaultValue);
+ }
+
+ /**
+ * Put the given integer {@code value} to {@code key}.
+ *
+ * @param key a secure settings key.
+ * @param value a secure settings value.
+ * @param userId the ID of a user whose secure settings will be updated.
+ * @see Settings.Secure#putIntForUser(ContentResolver, String, int, int)
+ */
+ @AnyThread
+ static void putInt(String key, int value, @UserIdInt int userId) {
+ get(userId).putInt(key, value);
+ }
+
+ /**
+ * Get an integer value with the given {@code key}
+ *
+ * @param key a secure settings key.
+ * @param defaultValue the default value when the value is not found.
+ * @param userId the ID of a user whose secure settings will be updated.
+ * @return The integer value if it is found. {@code defaultValue} otherwise.
+c */
+ @AnyThread
+ static int getInt(String key, int defaultValue, @UserIdInt int userId) {
+ return get(userId).getInt(key, defaultValue);
+ }
+
+ /**
+ * Put the given boolean {@code value} to {@code key}.
+ *
+ * @param key a secure settings key.
+ * @param value a secure settings value.
+ * @param userId the ID of a user whose secure settings will be updated.
+ */
+ @AnyThread
+ static void putBoolean(String key, boolean value, @UserIdInt int userId) {
+ get(userId).putInt(key, value ? 1 : 0);
+ }
+
+ /**
+ * Get a boolean value with the given {@code key}
+ *
+ * @param key a secure settings key.
+ * @param defaultValue the default value when the value is not found.
+ * @param userId the ID of a user whose secure settings will be updated.
+ * @return The boolean value if it is found. {@code defaultValue} otherwise.
+ */
+ @AnyThread
+ static boolean getBoolean(String key, boolean defaultValue, @UserIdInt int userId) {
+ return get(userId).getInt(key, defaultValue ? 1 : 0) == 1;
+ }
+}
diff --git a/services/core/java/com/android/server/media/AudioAttributesUtils.java b/services/core/java/com/android/server/media/AudioAttributesUtils.java
deleted file mode 100644
index 8cb334d..0000000
--- a/services/core/java/com/android/server/media/AudioAttributesUtils.java
+++ /dev/null
@@ -1,125 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.media;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.media.AudioAttributes;
-import android.media.AudioDeviceAttributes;
-import android.media.AudioDeviceInfo;
-import android.media.MediaRoute2Info;
-
-import com.android.media.flags.Flags;
-
-/* package */ final class AudioAttributesUtils {
-
- /* package */ static final AudioAttributes ATTRIBUTES_MEDIA = new AudioAttributes.Builder()
- .setUsage(AudioAttributes.USAGE_MEDIA)
- .build();
-
- private AudioAttributesUtils() {
- // no-op to prevent instantiation.
- }
-
- @MediaRoute2Info.Type
- /* package */ static int mapToMediaRouteType(
- @NonNull AudioDeviceAttributes audioDeviceAttributes) {
- if (Flags.enableAudioPoliciesDeviceAndBluetoothController()) {
- switch (audioDeviceAttributes.getType()) {
- case AudioDeviceInfo.TYPE_HDMI_ARC:
- return MediaRoute2Info.TYPE_HDMI_ARC;
- case AudioDeviceInfo.TYPE_HDMI_EARC:
- return MediaRoute2Info.TYPE_HDMI_EARC;
- }
- }
- switch (audioDeviceAttributes.getType()) {
- case AudioDeviceInfo.TYPE_BUILTIN_EARPIECE:
- case AudioDeviceInfo.TYPE_BUILTIN_SPEAKER:
- return MediaRoute2Info.TYPE_BUILTIN_SPEAKER;
- case AudioDeviceInfo.TYPE_WIRED_HEADSET:
- return MediaRoute2Info.TYPE_WIRED_HEADSET;
- case AudioDeviceInfo.TYPE_WIRED_HEADPHONES:
- return MediaRoute2Info.TYPE_WIRED_HEADPHONES;
- case AudioDeviceInfo.TYPE_DOCK:
- case AudioDeviceInfo.TYPE_DOCK_ANALOG:
- return MediaRoute2Info.TYPE_DOCK;
- case AudioDeviceInfo.TYPE_HDMI:
- case AudioDeviceInfo.TYPE_HDMI_ARC:
- case AudioDeviceInfo.TYPE_HDMI_EARC:
- return MediaRoute2Info.TYPE_HDMI;
- case AudioDeviceInfo.TYPE_USB_DEVICE:
- return MediaRoute2Info.TYPE_USB_DEVICE;
- case AudioDeviceInfo.TYPE_BLUETOOTH_A2DP:
- return MediaRoute2Info.TYPE_BLUETOOTH_A2DP;
- case AudioDeviceInfo.TYPE_BLE_HEADSET:
- return MediaRoute2Info.TYPE_BLE_HEADSET;
- case AudioDeviceInfo.TYPE_HEARING_AID:
- return MediaRoute2Info.TYPE_HEARING_AID;
- default:
- return MediaRoute2Info.TYPE_UNKNOWN;
- }
- }
-
- /* package */ static boolean isDeviceOutputAttributes(
- @Nullable AudioDeviceAttributes audioDeviceAttributes) {
- if (audioDeviceAttributes == null) {
- return false;
- }
-
- if (audioDeviceAttributes.getRole() != AudioDeviceAttributes.ROLE_OUTPUT) {
- return false;
- }
-
- switch (audioDeviceAttributes.getType()) {
- case AudioDeviceInfo.TYPE_BUILTIN_EARPIECE:
- case AudioDeviceInfo.TYPE_BUILTIN_SPEAKER:
- case AudioDeviceInfo.TYPE_WIRED_HEADSET:
- case AudioDeviceInfo.TYPE_WIRED_HEADPHONES:
- case AudioDeviceInfo.TYPE_DOCK:
- case AudioDeviceInfo.TYPE_DOCK_ANALOG:
- case AudioDeviceInfo.TYPE_HDMI:
- case AudioDeviceInfo.TYPE_HDMI_ARC:
- case AudioDeviceInfo.TYPE_HDMI_EARC:
- case AudioDeviceInfo.TYPE_USB_DEVICE:
- return true;
- default:
- return false;
- }
- }
-
- /* package */ static boolean isBluetoothOutputAttributes(
- @Nullable AudioDeviceAttributes audioDeviceAttributes) {
- if (audioDeviceAttributes == null) {
- return false;
- }
-
- if (audioDeviceAttributes.getRole() != AudioDeviceAttributes.ROLE_OUTPUT) {
- return false;
- }
-
- switch (audioDeviceAttributes.getType()) {
- case AudioDeviceInfo.TYPE_BLUETOOTH_A2DP:
- case AudioDeviceInfo.TYPE_BLE_HEADSET:
- case AudioDeviceInfo.TYPE_BLE_SPEAKER:
- case AudioDeviceInfo.TYPE_HEARING_AID:
- return true;
- default:
- return false;
- }
- }
-
-}
diff --git a/services/core/java/com/android/server/media/AudioPoliciesBluetoothRouteController.java b/services/core/java/com/android/server/media/AudioPoliciesBluetoothRouteController.java
index 8bc69c2..a00999d 100644
--- a/services/core/java/com/android/server/media/AudioPoliciesBluetoothRouteController.java
+++ b/services/core/java/com/android/server/media/AudioPoliciesBluetoothRouteController.java
@@ -17,7 +17,6 @@
package com.android.server.media;
import static android.bluetooth.BluetoothAdapter.ACTIVE_DEVICE_AUDIO;
-import static android.bluetooth.BluetoothAdapter.STATE_CONNECTED;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -31,38 +30,37 @@
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
-import android.media.AudioManager;
-import android.media.AudioSystem;
import android.media.MediaRoute2Info;
import android.os.UserHandle;
import android.text.TextUtils;
+import android.util.Log;
import android.util.Slog;
import android.util.SparseBooleanArray;
-import android.util.SparseIntArray;
import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;
import java.util.ArrayList;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
+import java.util.function.Function;
+import java.util.stream.Collectors;
/**
- * Controls bluetooth routes and provides selected route override.
+ * Maintains a list of connected {@link BluetoothDevice bluetooth devices} and allows their
+ * activation.
*
- * <p>The controller offers similar functionality to {@link LegacyBluetoothRouteController} but does
- * not support routes selection logic. Instead, relies on external clients to make a decision
- * about currently selected route.
- *
- * <p>Selected route override should be used by {@link AudioManager} which is aware of Audio
- * Policies.
+ * <p>This class also serves as ground truth for assigning {@link MediaRoute2Info#getId() route ids}
+ * for bluetooth routes via {@link #getRouteIdForBluetoothAddress}.
*/
-/* package */ class AudioPoliciesBluetoothRouteController
- implements BluetoothRouteController {
- private static final String TAG = "APBtRouteController";
+// TODO: b/305199571 - Rename this class to remove the RouteController suffix, which causes
+// confusion with the BluetoothRouteController interface.
+/* package */ class AudioPoliciesBluetoothRouteController {
+ private static final String TAG = SystemMediaRoute2Provider.TAG;
private static final String HEARING_AID_ROUTE_ID_PREFIX = "HEARING_AID_";
private static final String LE_AUDIO_ROUTE_ID_PREFIX = "LE_AUDIO_";
@@ -75,11 +73,8 @@
private final DeviceStateChangedReceiver mDeviceStateChangedReceiver =
new DeviceStateChangedReceiver();
- @NonNull
- private final Map<String, BluetoothRouteInfo> mBluetoothRoutes = new HashMap<>();
-
- @NonNull
- private final SparseIntArray mVolumeMap = new SparseIntArray();
+ @NonNull private Map<String, BluetoothDevice> mAddressToBondedDevice = new HashMap<>();
+ @NonNull private final Map<String, BluetoothRouteInfo> mBluetoothRoutes = new HashMap<>();
@NonNull
private final Context mContext;
@@ -89,11 +84,6 @@
private final BluetoothRouteController.BluetoothRoutesUpdatedListener mListener;
@NonNull
private final BluetoothProfileMonitor mBluetoothProfileMonitor;
- @NonNull
- private final AudioManager mAudioManager;
-
- @Nullable
- private BluetoothRouteInfo mSelectedBluetoothRoute;
AudioPoliciesBluetoothRouteController(@NonNull Context context,
@NonNull BluetoothAdapter bluetoothAdapter,
@@ -107,21 +97,12 @@
@NonNull BluetoothAdapter bluetoothAdapter,
@NonNull BluetoothProfileMonitor bluetoothProfileMonitor,
@NonNull BluetoothRouteController.BluetoothRoutesUpdatedListener listener) {
- Objects.requireNonNull(context);
- Objects.requireNonNull(bluetoothAdapter);
- Objects.requireNonNull(bluetoothProfileMonitor);
- Objects.requireNonNull(listener);
-
- mContext = context;
- mBluetoothAdapter = bluetoothAdapter;
- mBluetoothProfileMonitor = bluetoothProfileMonitor;
- mAudioManager = mContext.getSystemService(AudioManager.class);
- mListener = listener;
-
- updateBluetoothRoutes();
+ mContext = Objects.requireNonNull(context);
+ mBluetoothAdapter = Objects.requireNonNull(bluetoothAdapter);
+ mBluetoothProfileMonitor = Objects.requireNonNull(bluetoothProfileMonitor);
+ mListener = Objects.requireNonNull(listener);
}
- @Override
public void start(UserHandle user) {
mBluetoothProfileMonitor.start();
@@ -133,122 +114,63 @@
IntentFilter deviceStateChangedIntentFilter = new IntentFilter();
- deviceStateChangedIntentFilter.addAction(BluetoothA2dp.ACTION_ACTIVE_DEVICE_CHANGED);
deviceStateChangedIntentFilter.addAction(BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED);
deviceStateChangedIntentFilter.addAction(BluetoothHearingAid.ACTION_ACTIVE_DEVICE_CHANGED);
deviceStateChangedIntentFilter.addAction(
BluetoothHearingAid.ACTION_CONNECTION_STATE_CHANGED);
deviceStateChangedIntentFilter.addAction(
BluetoothLeAudio.ACTION_LE_AUDIO_CONNECTION_STATE_CHANGED);
- deviceStateChangedIntentFilter.addAction(
- BluetoothLeAudio.ACTION_LE_AUDIO_ACTIVE_DEVICE_CHANGED);
mContext.registerReceiverAsUser(mDeviceStateChangedReceiver, user,
deviceStateChangedIntentFilter, null, null);
+ updateBluetoothRoutes();
}
- @Override
public void stop() {
mContext.unregisterReceiver(mAdapterStateChangedReceiver);
mContext.unregisterReceiver(mDeviceStateChangedReceiver);
}
- @Override
- public boolean selectRoute(@Nullable String deviceAddress) {
- synchronized (this) {
- // Fetch all available devices in order to avoid race conditions with Bluetooth stack.
- updateBluetoothRoutes();
-
- if (deviceAddress == null) {
- mSelectedBluetoothRoute = null;
- return true;
- }
-
- BluetoothRouteInfo bluetoothRouteInfo = mBluetoothRoutes.get(deviceAddress);
-
- if (bluetoothRouteInfo == null) {
- Slog.w(TAG, "Cannot find bluetooth route for " + deviceAddress);
- return false;
- }
-
- mSelectedBluetoothRoute = bluetoothRouteInfo;
- setRouteConnectionState(mSelectedBluetoothRoute, STATE_CONNECTED);
-
- updateConnectivityStateForDevicesInTheSameGroup();
-
- return true;
- }
+ @Nullable
+ public synchronized String getRouteIdForBluetoothAddress(@Nullable String address) {
+ BluetoothDevice bluetoothDevice = mAddressToBondedDevice.get(address);
+ // TODO: b/305199571 - Optimize the following statement to avoid creating the full
+ // MediaRoute2Info instance. We just need the id.
+ return bluetoothDevice != null
+ ? createBluetoothRoute(bluetoothDevice).mRoute.getId()
+ : null;
}
- /**
- * Updates connectivity state for devices in the same devices group.
- *
- * <p>{@link BluetoothProfile#LE_AUDIO} and {@link BluetoothProfile#HEARING_AID} support
- * grouping devices. Devices that belong to the same group should have the same routeId but
- * different physical address.
- *
- * <p>In case one of the devices from the group is selected then other devices should also
- * reflect this by changing their connectivity status to
- * {@link MediaRoute2Info#CONNECTION_STATE_CONNECTED}.
- */
- private void updateConnectivityStateForDevicesInTheSameGroup() {
- synchronized (this) {
- for (BluetoothRouteInfo btRoute : mBluetoothRoutes.values()) {
- if (TextUtils.equals(btRoute.mRoute.getId(), mSelectedBluetoothRoute.mRoute.getId())
- && !TextUtils.equals(btRoute.mBtDevice.getAddress(),
- mSelectedBluetoothRoute.mBtDevice.getAddress())) {
- setRouteConnectionState(btRoute, STATE_CONNECTED);
- }
- }
- }
- }
-
- @Override
- public void transferTo(@Nullable String routeId) {
- if (routeId == null) {
- mBluetoothAdapter.removeActiveDevice(ACTIVE_DEVICE_AUDIO);
- return;
- }
-
- BluetoothRouteInfo btRouteInfo = findBluetoothRouteWithRouteId(routeId);
+ public synchronized void activateBluetoothDeviceWithAddress(String address) {
+ BluetoothRouteInfo btRouteInfo = mBluetoothRoutes.get(address);
if (btRouteInfo == null) {
- Slog.w(TAG, "transferTo: Unknown route. ID=" + routeId);
+ Slog.w(TAG, "activateBluetoothDeviceWithAddress: Ignoring unknown address " + address);
return;
}
-
mBluetoothAdapter.setActiveDevice(btRouteInfo.mBtDevice, ACTIVE_DEVICE_AUDIO);
}
- @Nullable
- private BluetoothRouteInfo findBluetoothRouteWithRouteId(@Nullable String routeId) {
- if (routeId == null) {
- return null;
- }
- synchronized (this) {
- for (BluetoothRouteInfo btRouteInfo : mBluetoothRoutes.values()) {
- if (TextUtils.equals(btRouteInfo.mRoute.getId(), routeId)) {
- return btRouteInfo;
- }
- }
- }
- return null;
- }
-
private void updateBluetoothRoutes() {
Set<BluetoothDevice> bondedDevices = mBluetoothAdapter.getBondedDevices();
- if (bondedDevices == null) {
- return;
- }
-
synchronized (this) {
mBluetoothRoutes.clear();
-
- // We need to query all available to BT stack devices in order to avoid inconsistency
- // between external services, like, AndroidManager, and BT stack.
+ if (bondedDevices == null) {
+ // Bonded devices is null upon running into a BluetoothAdapter error.
+ Log.w(TAG, "BluetoothAdapter.getBondedDevices returned null.");
+ return;
+ }
+ // We don't clear bonded devices if we receive a null getBondedDevices result, because
+ // that probably means that the bluetooth stack ran into an issue. Not that all devices
+ // have been unpaired.
+ mAddressToBondedDevice =
+ bondedDevices.stream()
+ .collect(
+ Collectors.toMap(
+ BluetoothDevice::getAddress, Function.identity()));
for (BluetoothDevice device : bondedDevices) {
- if (isDeviceConnected(device)) {
+ if (device.isConnected()) {
BluetoothRouteInfo newBtRoute = createBluetoothRoute(device);
if (newBtRoute.mConnectedProfiles.size() > 0) {
mBluetoothRoutes.put(device.getAddress(), newBtRoute);
@@ -258,106 +180,51 @@
}
}
- @VisibleForTesting
- /* package */ boolean isDeviceConnected(@NonNull BluetoothDevice device) {
- return device.isConnected();
- }
-
- @Nullable
- @Override
- public MediaRoute2Info getSelectedRoute() {
- synchronized (this) {
- if (mSelectedBluetoothRoute == null) {
- return null;
- }
-
- return mSelectedBluetoothRoute.mRoute;
- }
- }
-
@NonNull
- @Override
- public List<MediaRoute2Info> getTransferableRoutes() {
- List<MediaRoute2Info> routes = getAllBluetoothRoutes();
- synchronized (this) {
- if (mSelectedBluetoothRoute != null) {
- routes.remove(mSelectedBluetoothRoute.mRoute);
- }
- }
- return routes;
- }
-
- @NonNull
- @Override
- public List<MediaRoute2Info> getAllBluetoothRoutes() {
+ public List<MediaRoute2Info> getAvailableBluetoothRoutes() {
List<MediaRoute2Info> routes = new ArrayList<>();
- List<String> routeIds = new ArrayList<>();
-
- MediaRoute2Info selectedRoute = getSelectedRoute();
- if (selectedRoute != null) {
- routes.add(selectedRoute);
- routeIds.add(selectedRoute.getId());
- }
+ Set<String> routeIds = new HashSet<>();
synchronized (this) {
for (BluetoothRouteInfo btRoute : mBluetoothRoutes.values()) {
- // A pair of hearing aid devices or having the same hardware address
- if (routeIds.contains(btRoute.mRoute.getId())) {
- continue;
+ // See createBluetoothRoute for info on why we do this.
+ if (routeIds.add(btRoute.mRoute.getId())) {
+ routes.add(btRoute.mRoute);
}
- routes.add(btRoute.mRoute);
- routeIds.add(btRoute.mRoute.getId());
}
}
return routes;
}
- @Override
- public boolean updateVolumeForDevices(int devices, int volume) {
- int routeType;
- if ((devices & (AudioSystem.DEVICE_OUT_HEARING_AID)) != 0) {
- routeType = MediaRoute2Info.TYPE_HEARING_AID;
- } else if ((devices & (AudioManager.DEVICE_OUT_BLUETOOTH_A2DP
- | AudioManager.DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES
- | AudioManager.DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER)) != 0) {
- routeType = MediaRoute2Info.TYPE_BLUETOOTH_A2DP;
- } else if ((devices & (AudioManager.DEVICE_OUT_BLE_HEADSET)) != 0) {
- routeType = MediaRoute2Info.TYPE_BLE_HEADSET;
- } else {
- return false;
- }
-
- synchronized (this) {
- mVolumeMap.put(routeType, volume);
- if (mSelectedBluetoothRoute == null
- || mSelectedBluetoothRoute.mRoute.getType() != routeType) {
- return false;
- }
-
- mSelectedBluetoothRoute.mRoute =
- new MediaRoute2Info.Builder(mSelectedBluetoothRoute.mRoute)
- .setVolume(volume)
- .build();
- }
-
- notifyBluetoothRoutesUpdated();
- return true;
- }
-
private void notifyBluetoothRoutesUpdated() {
mListener.onBluetoothRoutesUpdated();
}
+ /**
+ * Creates a new {@link BluetoothRouteInfo}, including its member {@link
+ * BluetoothRouteInfo#mRoute}.
+ *
+ * <p>The most important logic in this method is around the {@link MediaRoute2Info#getId() route
+ * id} assignment. In some cases we want to group multiple {@link BluetoothDevice bluetooth
+ * devices} as a single media route. For example, the left and right hearing aids get exposed as
+ * two different BluetoothDevice instances, but we want to show them as a single route. In this
+ * case, we assign the same route id to all "group" bluetooth devices (like left and right
+ * hearing aids), so that a single route is exposed for both of them.
+ *
+ * <p>Deduplication by id happens downstream because we need to be able to refer to all
+ * bluetooth devices individually, since the audio stack refers to a bluetooth device group by
+ * any of its member devices.
+ */
private BluetoothRouteInfo createBluetoothRoute(BluetoothDevice device) {
BluetoothRouteInfo
newBtRoute = new BluetoothRouteInfo();
newBtRoute.mBtDevice = device;
-
- String routeId = device.getAddress();
String deviceName = device.getName();
if (TextUtils.isEmpty(deviceName)) {
deviceName = mContext.getResources().getText(R.string.unknownName).toString();
}
+
+ String routeId = device.getAddress();
int type = MediaRoute2Info.TYPE_BLUETOOTH_A2DP;
newBtRoute.mConnectedProfiles = new SparseBooleanArray();
if (mBluetoothProfileMonitor.isProfileSupported(BluetoothProfile.A2DP, device)) {
@@ -365,7 +232,6 @@
}
if (mBluetoothProfileMonitor.isProfileSupported(BluetoothProfile.HEARING_AID, device)) {
newBtRoute.mConnectedProfiles.put(BluetoothProfile.HEARING_AID, true);
- // Intentionally assign the same ID for a pair of devices to publish only one of them.
routeId = HEARING_AID_ROUTE_ID_PREFIX
+ mBluetoothProfileMonitor.getGroupId(BluetoothProfile.HEARING_AID, device);
type = MediaRoute2Info.TYPE_HEARING_AID;
@@ -377,66 +243,27 @@
type = MediaRoute2Info.TYPE_BLE_HEADSET;
}
- // Current volume will be set when connected.
- newBtRoute.mRoute = new MediaRoute2Info.Builder(routeId, deviceName)
- .addFeature(MediaRoute2Info.FEATURE_LIVE_AUDIO)
- .addFeature(MediaRoute2Info.FEATURE_LOCAL_PLAYBACK)
- .setConnectionState(MediaRoute2Info.CONNECTION_STATE_DISCONNECTED)
- .setDescription(mContext.getResources().getText(
- R.string.bluetooth_a2dp_audio_route_name).toString())
- .setType(type)
- .setVolumeHandling(MediaRoute2Info.PLAYBACK_VOLUME_VARIABLE)
- .setVolumeMax(mAudioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC))
- .setAddress(device.getAddress())
- .build();
+ // Note that volume is only relevant for active bluetooth routes, and those are managed via
+ // AudioManager.
+ newBtRoute.mRoute =
+ new MediaRoute2Info.Builder(routeId, deviceName)
+ .addFeature(MediaRoute2Info.FEATURE_LIVE_AUDIO)
+ .addFeature(MediaRoute2Info.FEATURE_LOCAL_PLAYBACK)
+ .setConnectionState(MediaRoute2Info.CONNECTION_STATE_DISCONNECTED)
+ .setDescription(
+ mContext.getResources()
+ .getText(R.string.bluetooth_a2dp_audio_route_name)
+ .toString())
+ .setType(type)
+ .setAddress(device.getAddress())
+ .build();
return newBtRoute;
}
- private void setRouteConnectionState(@NonNull BluetoothRouteInfo btRoute,
- @MediaRoute2Info.ConnectionState int state) {
- if (btRoute == null) {
- Slog.w(TAG, "setRouteConnectionState: route shouldn't be null");
- return;
- }
- if (btRoute.mRoute.getConnectionState() == state) {
- return;
- }
-
- MediaRoute2Info.Builder builder = new MediaRoute2Info.Builder(btRoute.mRoute)
- .setConnectionState(state);
- builder.setType(btRoute.getRouteType());
-
-
-
- if (state == MediaRoute2Info.CONNECTION_STATE_CONNECTED) {
- int currentVolume;
- synchronized (this) {
- currentVolume = mVolumeMap.get(btRoute.getRouteType(), 0);
- }
- builder.setVolume(currentVolume);
- }
-
- btRoute.mRoute = builder.build();
- }
-
private static class BluetoothRouteInfo {
private BluetoothDevice mBtDevice;
private MediaRoute2Info mRoute;
private SparseBooleanArray mConnectedProfiles;
-
- @MediaRoute2Info.Type
- int getRouteType() {
- // Let hearing aid profile have a priority.
- if (mConnectedProfiles.get(BluetoothProfile.HEARING_AID, false)) {
- return MediaRoute2Info.TYPE_HEARING_AID;
- }
-
- if (mConnectedProfiles.get(BluetoothProfile.LE_AUDIO, false)) {
- return MediaRoute2Info.TYPE_BLE_HEADSET;
- }
-
- return MediaRoute2Info.TYPE_BLUETOOTH_A2DP;
- }
}
private class AdapterStateChangedReceiver extends BroadcastReceiver {
@@ -468,9 +295,6 @@
@Override
public void onReceive(Context context, Intent intent) {
switch (intent.getAction()) {
- case BluetoothA2dp.ACTION_ACTIVE_DEVICE_CHANGED:
- case BluetoothHearingAid.ACTION_ACTIVE_DEVICE_CHANGED:
- case BluetoothLeAudio.ACTION_LE_AUDIO_ACTIVE_DEVICE_CHANGED:
case BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED:
case BluetoothHearingAid.ACTION_CONNECTION_STATE_CHANGED:
case BluetoothLeAudio.ACTION_LE_AUDIO_CONNECTION_STATE_CHANGED:
diff --git a/services/core/java/com/android/server/media/AudioPoliciesDeviceRouteController.java b/services/core/java/com/android/server/media/AudioPoliciesDeviceRouteController.java
index 6bdfae2..173c452 100644
--- a/services/core/java/com/android/server/media/AudioPoliciesDeviceRouteController.java
+++ b/services/core/java/com/android/server/media/AudioPoliciesDeviceRouteController.java
@@ -17,228 +17,601 @@
package com.android.server.media;
import static android.media.MediaRoute2Info.FEATURE_LIVE_AUDIO;
-import static android.media.MediaRoute2Info.FEATURE_LIVE_VIDEO;
import static android.media.MediaRoute2Info.FEATURE_LOCAL_PLAYBACK;
-import static android.media.MediaRoute2Info.TYPE_BUILTIN_SPEAKER;
-import static android.media.MediaRoute2Info.TYPE_DOCK;
-import static android.media.MediaRoute2Info.TYPE_HDMI;
-import static android.media.MediaRoute2Info.TYPE_HDMI_ARC;
-import static android.media.MediaRoute2Info.TYPE_HDMI_EARC;
-import static android.media.MediaRoute2Info.TYPE_USB_DEVICE;
-import static android.media.MediaRoute2Info.TYPE_WIRED_HEADPHONES;
-import static android.media.MediaRoute2Info.TYPE_WIRED_HEADSET;
+import android.Manifest;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothDevice;
import android.content.Context;
+import android.media.AudioAttributes;
+import android.media.AudioDeviceAttributes;
+import android.media.AudioDeviceCallback;
+import android.media.AudioDeviceInfo;
import android.media.AudioManager;
-import android.media.AudioRoutesInfo;
-import android.media.IAudioRoutesObserver;
-import android.media.IAudioService;
import android.media.MediaRoute2Info;
-import android.os.RemoteException;
+import android.media.audiopolicy.AudioProductStrategy;
+import android.os.Handler;
+import android.os.HandlerExecutor;
+import android.os.Looper;
+import android.os.UserHandle;
+import android.text.TextUtils;
import android.util.Slog;
+import android.util.SparseArray;
import com.android.internal.R;
-import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.media.BluetoothRouteController.NoOpBluetoothRouteController;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
import java.util.Objects;
+/**
+ * Maintains a list of all available routes and supports transfers to any of them.
+ *
+ * <p>This implementation is intended for use in conjunction with {@link
+ * NoOpBluetoothRouteController}, as it manages bluetooth devices directly.
+ *
+ * <p>This implementation obtains and manages all routes via {@link AudioManager}, with the
+ * exception of {@link AudioManager#handleBluetoothActiveDeviceChanged inactive bluetooth} routes
+ * which are managed by {@link AudioPoliciesBluetoothRouteController}, which depends on the
+ * bluetooth stack (for example {@link BluetoothAdapter}.
+ */
+// TODO: b/305199571 - Rename this class to avoid the AudioPolicies prefix, which has been flagged
+// by the audio team as a confusing name.
/* package */ final class AudioPoliciesDeviceRouteController implements DeviceRouteController {
-
- private static final String TAG = "APDeviceRoutesController";
+ private static final String TAG = SystemMediaRoute2Provider.TAG;
@NonNull
- private final Context mContext;
- @NonNull
- private final AudioManager mAudioManager;
- @NonNull
- private final IAudioService mAudioService;
+ private static final AudioAttributes MEDIA_USAGE_AUDIO_ATTRIBUTES =
+ new AudioAttributes.Builder().setUsage(AudioAttributes.USAGE_MEDIA).build();
@NonNull
- private final OnDeviceRouteChangedListener mOnDeviceRouteChangedListener;
- @NonNull
- private final AudioRoutesObserver mAudioRoutesObserver = new AudioRoutesObserver();
+ private static final SparseArray<SystemRouteInfo> AUDIO_DEVICE_INFO_TYPE_TO_ROUTE_INFO =
+ new SparseArray<>();
- private int mDeviceVolume;
+ @NonNull private final Context mContext;
+ @NonNull private final AudioManager mAudioManager;
+ @NonNull private final Handler mHandler;
+ @NonNull private final OnDeviceRouteChangedListener mOnDeviceRouteChangedListener;
+ @NonNull private final AudioPoliciesBluetoothRouteController mBluetoothRouteController;
@NonNull
- private MediaRoute2Info mDeviceRoute;
- @Nullable
- private MediaRoute2Info mSelectedRoute;
+ private final Map<String, MediaRoute2InfoHolder> mRouteIdToAvailableDeviceRoutes =
+ new HashMap<>();
- @VisibleForTesting
- /* package */ AudioPoliciesDeviceRouteController(@NonNull Context context,
+ @NonNull private final AudioProductStrategy mStrategyForMedia;
+
+ @NonNull private final AudioDeviceCallback mAudioDeviceCallback = new AudioDeviceCallbackImpl();
+
+ @NonNull
+ private final AudioManager.OnDevicesForAttributesChangedListener
+ mOnDevicesForAttributesChangedListener = this::onDevicesForAttributesChangedListener;
+
+ @NonNull private MediaRoute2Info mSelectedRoute;
+
+ // TODO: b/305199571 - Support nullable btAdapter and strategyForMedia which, when null, means
+ // no support for transferring to inactive bluetooth routes and transferring to any routes
+ // respectively.
+ @RequiresPermission(
+ anyOf = {
+ Manifest.permission.MODIFY_AUDIO_ROUTING,
+ Manifest.permission.QUERY_AUDIO_STATE
+ })
+ /* package */ AudioPoliciesDeviceRouteController(
+ @NonNull Context context,
@NonNull AudioManager audioManager,
- @NonNull IAudioService audioService,
+ @NonNull Looper looper,
+ @NonNull AudioProductStrategy strategyForMedia,
+ @NonNull BluetoothAdapter btAdapter,
@NonNull OnDeviceRouteChangedListener onDeviceRouteChangedListener) {
- Objects.requireNonNull(context);
- Objects.requireNonNull(audioManager);
- Objects.requireNonNull(audioService);
- Objects.requireNonNull(onDeviceRouteChangedListener);
-
- mContext = context;
- mOnDeviceRouteChangedListener = onDeviceRouteChangedListener;
-
- mAudioManager = audioManager;
- mAudioService = audioService;
-
- AudioRoutesInfo newAudioRoutes = null;
- try {
- newAudioRoutes = mAudioService.startWatchingRoutes(mAudioRoutesObserver);
- } catch (RemoteException e) {
- Slog.w(TAG, "Cannot connect to audio service to start listen to routes", e);
- }
-
- mDeviceRoute = createRouteFromAudioInfo(newAudioRoutes);
+ mContext = Objects.requireNonNull(context);
+ mAudioManager = Objects.requireNonNull(audioManager);
+ mHandler = new Handler(Objects.requireNonNull(looper));
+ mStrategyForMedia = Objects.requireNonNull(strategyForMedia);
+ mOnDeviceRouteChangedListener = Objects.requireNonNull(onDeviceRouteChangedListener);
+ mBluetoothRouteController =
+ new AudioPoliciesBluetoothRouteController(
+ mContext, btAdapter, this::rebuildAvailableRoutesAndNotify);
+ // Just build routes but don't notify. The caller may not expect the listener to be invoked
+ // before this constructor has finished executing.
+ rebuildAvailableRoutes();
}
+ @RequiresPermission(
+ anyOf = {
+ Manifest.permission.MODIFY_AUDIO_ROUTING,
+ Manifest.permission.QUERY_AUDIO_STATE
+ })
@Override
- public synchronized boolean selectRoute(@Nullable Integer type) {
- if (type == null) {
- mSelectedRoute = null;
- return true;
- }
+ public void start(UserHandle mUser) {
+ mBluetoothRouteController.start(mUser);
+ mAudioManager.registerAudioDeviceCallback(mAudioDeviceCallback, mHandler);
+ mAudioManager.addOnDevicesForAttributesChangedListener(
+ AudioRoutingUtils.ATTRIBUTES_MEDIA,
+ new HandlerExecutor(mHandler),
+ mOnDevicesForAttributesChangedListener);
+ }
- if (!isDeviceRouteType(type)) {
- return false;
- }
-
- mSelectedRoute = createRouteFromAudioInfo(type);
- return true;
+ @RequiresPermission(
+ anyOf = {
+ Manifest.permission.MODIFY_AUDIO_ROUTING,
+ Manifest.permission.QUERY_AUDIO_STATE
+ })
+ @Override
+ public void stop() {
+ mAudioManager.removeOnDevicesForAttributesChangedListener(
+ mOnDevicesForAttributesChangedListener);
+ mAudioManager.unregisterAudioDeviceCallback(mAudioDeviceCallback);
+ mBluetoothRouteController.stop();
+ mHandler.removeCallbacksAndMessages(/* token= */ null);
}
@Override
@NonNull
public synchronized MediaRoute2Info getSelectedRoute() {
- if (mSelectedRoute != null) {
- return mSelectedRoute;
- }
- return mDeviceRoute;
+ return mSelectedRoute;
}
@Override
+ @NonNull
+ public synchronized List<MediaRoute2Info> getAvailableRoutes() {
+ return mRouteIdToAvailableDeviceRoutes.values().stream()
+ .map(it -> it.mMediaRoute2Info)
+ .toList();
+ }
+
+ @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
+ @Override
+ public synchronized void transferTo(@Nullable String routeId) {
+ if (routeId == null) {
+ // This should never happen: This branch should only execute when the matching bluetooth
+ // route controller is not the no-op one.
+ // TODO: b/305199571 - Make routeId non-null and remove this branch once we remove the
+ // legacy route controller implementations.
+ Slog.e(TAG, "Unexpected call to AudioPoliciesDeviceRouteController#transferTo(null)");
+ return;
+ }
+ MediaRoute2InfoHolder mediaRoute2InfoHolder = mRouteIdToAvailableDeviceRoutes.get(routeId);
+ if (mediaRoute2InfoHolder == null) {
+ Slog.w(TAG, "transferTo: Ignoring transfer request to unknown route id : " + routeId);
+ return;
+ }
+ if (mediaRoute2InfoHolder.mCorrespondsToInactiveBluetoothRoute) {
+ // By default, the last connected device is the active route so we don't need to apply a
+ // routing audio policy.
+ mBluetoothRouteController.activateBluetoothDeviceWithAddress(
+ mediaRoute2InfoHolder.mMediaRoute2Info.getAddress());
+ mAudioManager.removePreferredDeviceForStrategy(mStrategyForMedia);
+ } else {
+ AudioDeviceAttributes attr =
+ new AudioDeviceAttributes(
+ AudioDeviceAttributes.ROLE_OUTPUT,
+ mediaRoute2InfoHolder.mAudioDeviceInfoType,
+ /* address= */ ""); // This is not a BT device, hence no address needed.
+ mAudioManager.setPreferredDeviceForStrategy(mStrategyForMedia, attr);
+ }
+ }
+
+ @RequiresPermission(
+ anyOf = {
+ Manifest.permission.MODIFY_AUDIO_ROUTING,
+ Manifest.permission.QUERY_AUDIO_STATE
+ })
+ @Override
public synchronized boolean updateVolume(int volume) {
- if (mDeviceVolume == volume) {
- return false;
- }
-
- mDeviceVolume = volume;
-
- if (mSelectedRoute != null) {
- mSelectedRoute = new MediaRoute2Info.Builder(mSelectedRoute)
- .setVolume(volume)
- .build();
- }
-
- mDeviceRoute = new MediaRoute2Info.Builder(mDeviceRoute)
- .setVolume(volume)
- .build();
-
+ // TODO: b/305199571 - Optimize so that we only update the volume of the selected route. We
+ // don't need to rebuild all available routes.
+ rebuildAvailableRoutesAndNotify();
return true;
}
- @NonNull
- private MediaRoute2Info createRouteFromAudioInfo(@Nullable AudioRoutesInfo newRoutes) {
- int type = TYPE_BUILTIN_SPEAKER;
+ @RequiresPermission(
+ anyOf = {
+ Manifest.permission.MODIFY_AUDIO_ROUTING,
+ Manifest.permission.QUERY_AUDIO_STATE
+ })
+ private void onDevicesForAttributesChangedListener(
+ AudioAttributes attributes, List<AudioDeviceAttributes> unusedAudioDeviceAttributes) {
+ if (attributes.getUsage() == AudioAttributes.USAGE_MEDIA) {
+ // We only care about the media usage. Ignore everything else.
+ rebuildAvailableRoutesAndNotify();
+ }
+ }
- if (newRoutes != null) {
- if ((newRoutes.mainType & AudioRoutesInfo.MAIN_HEADPHONES) != 0) {
- type = TYPE_WIRED_HEADPHONES;
- } else if ((newRoutes.mainType & AudioRoutesInfo.MAIN_HEADSET) != 0) {
- type = TYPE_WIRED_HEADSET;
- } else if ((newRoutes.mainType & AudioRoutesInfo.MAIN_DOCK_SPEAKERS) != 0) {
- type = TYPE_DOCK;
- } else if ((newRoutes.mainType & AudioRoutesInfo.MAIN_HDMI) != 0) {
- type = TYPE_HDMI;
- } else if ((newRoutes.mainType & AudioRoutesInfo.MAIN_USB) != 0) {
- type = TYPE_USB_DEVICE;
+ @RequiresPermission(
+ anyOf = {
+ Manifest.permission.MODIFY_AUDIO_ROUTING,
+ Manifest.permission.QUERY_AUDIO_STATE
+ })
+ private synchronized void rebuildAvailableRoutesAndNotify() {
+ rebuildAvailableRoutes();
+ mOnDeviceRouteChangedListener.onDeviceRouteChanged();
+ }
+
+ @RequiresPermission(
+ anyOf = {
+ Manifest.permission.MODIFY_AUDIO_ROUTING,
+ Manifest.permission.QUERY_AUDIO_STATE
+ })
+ private synchronized void rebuildAvailableRoutes() {
+ List<AudioDeviceAttributes> attributesOfSelectedOutputDevices =
+ mAudioManager.getDevicesForAttributes(MEDIA_USAGE_AUDIO_ATTRIBUTES);
+ int selectedDeviceAttributesType;
+ if (attributesOfSelectedOutputDevices.isEmpty()) {
+ Slog.e(
+ TAG,
+ "Unexpected empty list of output devices for media. Using built-in speakers.");
+ selectedDeviceAttributesType = AudioDeviceInfo.TYPE_BUILTIN_SPEAKER;
+ } else {
+ if (attributesOfSelectedOutputDevices.size() > 1) {
+ Slog.w(
+ TAG,
+ "AudioManager.getDevicesForAttributes returned more than one element. Using"
+ + " the first one.");
+ }
+ selectedDeviceAttributesType = attributesOfSelectedOutputDevices.get(0).getType();
+ }
+
+ AudioDeviceInfo[] audioDeviceInfos =
+ mAudioManager.getDevices(AudioManager.GET_DEVICES_OUTPUTS);
+ mRouteIdToAvailableDeviceRoutes.clear();
+ MediaRoute2InfoHolder newSelectedRouteHolder = null;
+ for (AudioDeviceInfo audioDeviceInfo : audioDeviceInfos) {
+ MediaRoute2Info mediaRoute2Info =
+ createMediaRoute2InfoFromAudioDeviceInfo(audioDeviceInfo);
+ // Null means audioDeviceInfo is not a supported media output, like a phone's builtin
+ // earpiece. We ignore those.
+ if (mediaRoute2Info != null) {
+ int audioDeviceInfoType = audioDeviceInfo.getType();
+ MediaRoute2InfoHolder newHolder =
+ MediaRoute2InfoHolder.createForAudioManagerRoute(
+ mediaRoute2Info, audioDeviceInfoType);
+ mRouteIdToAvailableDeviceRoutes.put(mediaRoute2Info.getId(), newHolder);
+ if (selectedDeviceAttributesType == audioDeviceInfoType) {
+ newSelectedRouteHolder = newHolder;
+ }
}
}
- return createRouteFromAudioInfo(type);
- }
-
- @NonNull
- private MediaRoute2Info createRouteFromAudioInfo(@MediaRoute2Info.Type int type) {
- int name = R.string.default_audio_route_name;
- switch (type) {
- case TYPE_WIRED_HEADPHONES:
- case TYPE_WIRED_HEADSET:
- name = R.string.default_audio_route_name_headphones;
- break;
- case TYPE_DOCK:
- name = R.string.default_audio_route_name_dock_speakers;
- break;
- case TYPE_HDMI:
- case TYPE_HDMI_ARC:
- case TYPE_HDMI_EARC:
- name = R.string.default_audio_route_name_external_device;
- break;
- case TYPE_USB_DEVICE:
- name = R.string.default_audio_route_name_usb;
- break;
+ if (mRouteIdToAvailableDeviceRoutes.isEmpty()) {
+ // Due to an unknown reason (possibly an audio server crash), we ended up with an empty
+ // list of routes. Our entire codebase assumes at least one system route always exists,
+ // so we create a placeholder route represented as a built-in speaker for
+ // user-presentation purposes.
+ Slog.e(TAG, "Ended up with an empty list of routes. Creating a placeholder route.");
+ MediaRoute2InfoHolder placeholderRouteHolder = createPlaceholderBuiltinSpeakerRoute();
+ String placeholderRouteId = placeholderRouteHolder.mMediaRoute2Info.getId();
+ mRouteIdToAvailableDeviceRoutes.put(placeholderRouteId, placeholderRouteHolder);
}
- synchronized (this) {
- return new MediaRoute2Info.Builder(
- MediaRoute2Info.ROUTE_ID_DEVICE,
- mContext.getResources().getText(name).toString())
- .setVolumeHandling(
- mAudioManager.isVolumeFixed()
- ? MediaRoute2Info.PLAYBACK_VOLUME_FIXED
- : MediaRoute2Info.PLAYBACK_VOLUME_VARIABLE)
- .setVolume(mDeviceVolume)
- .setVolumeMax(mAudioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC))
- .setType(type)
- .addFeature(FEATURE_LIVE_AUDIO)
- .addFeature(FEATURE_LIVE_VIDEO)
- .addFeature(FEATURE_LOCAL_PLAYBACK)
- .setConnectionState(MediaRoute2Info.CONNECTION_STATE_CONNECTED)
- .build();
+ if (newSelectedRouteHolder == null) {
+ Slog.e(
+ TAG,
+ "Could not map this selected device attribute type to an available route: "
+ + selectedDeviceAttributesType);
+ // We know mRouteIdToAvailableDeviceRoutes is not empty.
+ newSelectedRouteHolder = mRouteIdToAvailableDeviceRoutes.values().iterator().next();
+ }
+ MediaRoute2InfoHolder selectedRouteHolderWithUpdatedVolumeInfo =
+ newSelectedRouteHolder.copyWithVolumeInfoFromAudioManager(mAudioManager);
+ mRouteIdToAvailableDeviceRoutes.put(
+ newSelectedRouteHolder.mMediaRoute2Info.getId(),
+ selectedRouteHolderWithUpdatedVolumeInfo);
+ mSelectedRoute = selectedRouteHolderWithUpdatedVolumeInfo.mMediaRoute2Info;
+
+ // We only add those BT routes that we have not already obtained from audio manager (which
+ // are active).
+ mBluetoothRouteController.getAvailableBluetoothRoutes().stream()
+ .filter(it -> !mRouteIdToAvailableDeviceRoutes.containsKey(it.getId()))
+ .map(MediaRoute2InfoHolder::createForInactiveBluetoothRoute)
+ .forEach(
+ it -> mRouteIdToAvailableDeviceRoutes.put(it.mMediaRoute2Info.getId(), it));
+ }
+
+ private MediaRoute2InfoHolder createPlaceholderBuiltinSpeakerRoute() {
+ int type = AudioDeviceInfo.TYPE_BUILTIN_SPEAKER;
+ return MediaRoute2InfoHolder.createForAudioManagerRoute(
+ createMediaRoute2Info(
+ /* routeId= */ null, type, /* productName= */ null, /* address= */ null),
+ type);
+ }
+
+ @Nullable
+ private MediaRoute2Info createMediaRoute2InfoFromAudioDeviceInfo(
+ AudioDeviceInfo audioDeviceInfo) {
+ String address = audioDeviceInfo.getAddress();
+ // Passing a null route id means we want to get the default id for the route. Generally, we
+ // only expect to pass null for non-Bluetooth routes.
+ String routeId =
+ TextUtils.isEmpty(address)
+ ? null
+ : mBluetoothRouteController.getRouteIdForBluetoothAddress(address);
+ return createMediaRoute2Info(
+ routeId, audioDeviceInfo.getType(), audioDeviceInfo.getProductName(), address);
+ }
+
+ /**
+ * Creates a new {@link MediaRoute2Info} using the provided information.
+ *
+ * @param routeId A route id, or null to use an id pre-defined for the given {@code type}.
+ * @param audioDeviceInfoType The type as obtained from {@link AudioDeviceInfo#getType}.
+ * @param productName The product name as obtained from {@link
+ * AudioDeviceInfo#getProductName()}, or null to use a predefined name for the given {@code
+ * type}.
+ * @param address The type as obtained from {@link AudioDeviceInfo#getAddress()} or {@link
+ * BluetoothDevice#getAddress()}.
+ * @return The new {@link MediaRoute2Info}.
+ */
+ @Nullable
+ private MediaRoute2Info createMediaRoute2Info(
+ @Nullable String routeId,
+ int audioDeviceInfoType,
+ @Nullable CharSequence productName,
+ @Nullable String address) {
+ SystemRouteInfo systemRouteInfo =
+ AUDIO_DEVICE_INFO_TYPE_TO_ROUTE_INFO.get(audioDeviceInfoType);
+ if (systemRouteInfo == null) {
+ // Device type that's intentionally unsupported for media output, like the built-in
+ // earpiece.
+ return null;
+ }
+ CharSequence humanReadableName = productName;
+ if (TextUtils.isEmpty(humanReadableName)) {
+ humanReadableName = mContext.getResources().getText(systemRouteInfo.mNameResource);
+ }
+ if (routeId == null) {
+ // The caller hasn't provided an id, so we use a pre-defined one. This happens when we
+ // are creating a non-BT route, or we are creating a BT route but a race condition
+ // caused AudioManager to expose the BT route before BluetoothAdapter, preventing us
+ // from getting an id using BluetoothRouteController#getRouteIdForBluetoothAddress.
+ routeId = systemRouteInfo.mDefaultRouteId;
+ }
+ return new MediaRoute2Info.Builder(routeId, humanReadableName)
+ .setType(systemRouteInfo.mMediaRoute2InfoType)
+ .setAddress(address)
+ .setSystemRoute(true)
+ .addFeature(FEATURE_LIVE_AUDIO)
+ .addFeature(FEATURE_LOCAL_PLAYBACK)
+ .setConnectionState(MediaRoute2Info.CONNECTION_STATE_CONNECTED)
+ .build();
+ }
+
+ /**
+ * Holds a {@link MediaRoute2Info} and associated information that we don't want to put in the
+ * {@link MediaRoute2Info} class because it's solely necessary for the implementation of this
+ * class.
+ */
+ private static class MediaRoute2InfoHolder {
+
+ public final MediaRoute2Info mMediaRoute2Info;
+ public final int mAudioDeviceInfoType;
+ public final boolean mCorrespondsToInactiveBluetoothRoute;
+
+ public static MediaRoute2InfoHolder createForAudioManagerRoute(
+ MediaRoute2Info mediaRoute2Info, int audioDeviceInfoType) {
+ return new MediaRoute2InfoHolder(
+ mediaRoute2Info,
+ audioDeviceInfoType,
+ /* correspondsToInactiveBluetoothRoute= */ false);
+ }
+
+ public static MediaRoute2InfoHolder createForInactiveBluetoothRoute(
+ MediaRoute2Info mediaRoute2Info) {
+ // There's no corresponding audio device info, hence the audio device info type is
+ // unknown.
+ return new MediaRoute2InfoHolder(
+ mediaRoute2Info,
+ /* audioDeviceInfoType= */ AudioDeviceInfo.TYPE_UNKNOWN,
+ /* correspondsToInactiveBluetoothRoute= */ true);
+ }
+
+ private MediaRoute2InfoHolder(
+ MediaRoute2Info mediaRoute2Info,
+ int audioDeviceInfoType,
+ boolean correspondsToInactiveBluetoothRoute) {
+ mMediaRoute2Info = mediaRoute2Info;
+ mAudioDeviceInfoType = audioDeviceInfoType;
+ mCorrespondsToInactiveBluetoothRoute = correspondsToInactiveBluetoothRoute;
+ }
+
+ public MediaRoute2InfoHolder copyWithVolumeInfoFromAudioManager(
+ AudioManager mAudioManager) {
+ MediaRoute2Info routeInfoWithVolumeInfo =
+ new MediaRoute2Info.Builder(mMediaRoute2Info)
+ .setVolumeHandling(
+ mAudioManager.isVolumeFixed()
+ ? MediaRoute2Info.PLAYBACK_VOLUME_FIXED
+ : MediaRoute2Info.PLAYBACK_VOLUME_VARIABLE)
+ .setVolume(mAudioManager.getStreamVolume(AudioManager.STREAM_MUSIC))
+ .setVolumeMax(
+ mAudioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC))
+ .build();
+ return new MediaRoute2InfoHolder(
+ routeInfoWithVolumeInfo,
+ mAudioDeviceInfoType,
+ mCorrespondsToInactiveBluetoothRoute);
}
}
/**
- * Checks if the given type is a device route.
- *
- * <p>Device route means a route which is either built-in or wired to the current device.
- *
- * @param type specifies the type of the device.
- * @return {@code true} if the device is wired or built-in and {@code false} otherwise.
+ * Holds route information about an {@link AudioDeviceInfo#getType() audio device info type}.
*/
- private boolean isDeviceRouteType(@MediaRoute2Info.Type int type) {
- switch (type) {
- case TYPE_BUILTIN_SPEAKER:
- case TYPE_WIRED_HEADPHONES:
- case TYPE_WIRED_HEADSET:
- case TYPE_DOCK:
- case TYPE_HDMI:
- case TYPE_HDMI_ARC:
- case TYPE_HDMI_EARC:
- case TYPE_USB_DEVICE:
- return true;
- default:
- return false;
+ private static class SystemRouteInfo {
+ /** The type to use for {@link MediaRoute2Info#getType()}. */
+ public final int mMediaRoute2InfoType;
+
+ /**
+ * Holds the route id to use if no other id is provided.
+ *
+ * <p>We only expect this id to be used for non-bluetooth routes. For bluetooth routes, in a
+ * normal scenario, the id is generated from the device information (like address, or
+ * hiSyncId), and this value is ignored. A non-normal scenario may occur when there's race
+ * condition between {@link BluetoothAdapter} and {@link AudioManager}, who are not
+ * synchronized.
+ */
+ public final String mDefaultRouteId;
+
+ /**
+ * The name to use for {@link MediaRoute2Info#getName()}.
+ *
+ * <p>Usually replaced by the UI layer with a localized string.
+ */
+ public final int mNameResource;
+
+ private SystemRouteInfo(int mediaRoute2InfoType, String defaultRouteId, int nameResource) {
+ mMediaRoute2InfoType = mediaRoute2InfoType;
+ mDefaultRouteId = defaultRouteId;
+ mNameResource = nameResource;
}
}
- private class AudioRoutesObserver extends IAudioRoutesObserver.Stub {
-
+ private class AudioDeviceCallbackImpl extends AudioDeviceCallback {
+ @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
@Override
- public void dispatchAudioRoutesChanged(AudioRoutesInfo newAudioRoutes) {
- boolean isDeviceRouteChanged;
- MediaRoute2Info deviceRoute = createRouteFromAudioInfo(newAudioRoutes);
-
- synchronized (AudioPoliciesDeviceRouteController.this) {
- mDeviceRoute = deviceRoute;
- isDeviceRouteChanged = mSelectedRoute == null;
+ public void onAudioDevicesAdded(AudioDeviceInfo[] addedDevices) {
+ for (AudioDeviceInfo deviceInfo : addedDevices) {
+ if (AUDIO_DEVICE_INFO_TYPE_TO_ROUTE_INFO.contains(deviceInfo.getType())) {
+ // When a new valid media output is connected, we clear any routing policies so
+ // that the default routing logic from the audio framework kicks in. As a result
+ // of this, when the user connects a bluetooth device or a wired headset, the
+ // new device becomes the active route, which is the traditional behavior.
+ mAudioManager.removePreferredDeviceForStrategy(mStrategyForMedia);
+ rebuildAvailableRoutesAndNotify();
+ break;
+ }
}
+ }
- if (isDeviceRouteChanged) {
- mOnDeviceRouteChangedListener.onDeviceRouteChanged();
+ @RequiresPermission(
+ anyOf = {
+ Manifest.permission.MODIFY_AUDIO_ROUTING,
+ Manifest.permission.QUERY_AUDIO_STATE
+ })
+ @Override
+ public void onAudioDevicesRemoved(AudioDeviceInfo[] removedDevices) {
+ for (AudioDeviceInfo deviceInfo : removedDevices) {
+ if (AUDIO_DEVICE_INFO_TYPE_TO_ROUTE_INFO.contains(deviceInfo.getType())) {
+ rebuildAvailableRoutesAndNotify();
+ break;
+ }
}
}
}
+ static {
+ AUDIO_DEVICE_INFO_TYPE_TO_ROUTE_INFO.put(
+ AudioDeviceInfo.TYPE_BUILTIN_SPEAKER,
+ new SystemRouteInfo(
+ MediaRoute2Info.TYPE_BUILTIN_SPEAKER,
+ /* defaultRouteId= */ "ROUTE_ID_BUILTIN_SPEAKER",
+ /* nameResource= */ R.string.default_audio_route_name));
+ AUDIO_DEVICE_INFO_TYPE_TO_ROUTE_INFO.put(
+ AudioDeviceInfo.TYPE_WIRED_HEADSET,
+ new SystemRouteInfo(
+ MediaRoute2Info.TYPE_WIRED_HEADSET,
+ /* defaultRouteId= */ "ROUTE_ID_WIRED_HEADSET",
+ /* nameResource= */ R.string.default_audio_route_name_headphones));
+ AUDIO_DEVICE_INFO_TYPE_TO_ROUTE_INFO.put(
+ AudioDeviceInfo.TYPE_WIRED_HEADPHONES,
+ new SystemRouteInfo(
+ MediaRoute2Info.TYPE_WIRED_HEADPHONES,
+ /* defaultRouteId= */ "ROUTE_ID_WIRED_HEADPHONES",
+ /* nameResource= */ R.string.default_audio_route_name_headphones));
+ AUDIO_DEVICE_INFO_TYPE_TO_ROUTE_INFO.put(
+ AudioDeviceInfo.TYPE_BLUETOOTH_A2DP,
+ new SystemRouteInfo(
+ MediaRoute2Info.TYPE_BLUETOOTH_A2DP,
+ /* defaultRouteId= */ "ROUTE_ID_BLUETOOTH_A2DP",
+ /* nameResource= */ R.string.bluetooth_a2dp_audio_route_name));
+ AUDIO_DEVICE_INFO_TYPE_TO_ROUTE_INFO.put(
+ AudioDeviceInfo.TYPE_HDMI,
+ new SystemRouteInfo(
+ MediaRoute2Info.TYPE_HDMI,
+ /* defaultRouteId= */ "ROUTE_ID_HDMI",
+ /* nameResource= */ R.string.default_audio_route_name_external_device));
+ AUDIO_DEVICE_INFO_TYPE_TO_ROUTE_INFO.put(
+ AudioDeviceInfo.TYPE_DOCK,
+ new SystemRouteInfo(
+ MediaRoute2Info.TYPE_DOCK,
+ /* defaultRouteId= */ "ROUTE_ID_DOCK",
+ /* nameResource= */ R.string.default_audio_route_name_dock_speakers));
+ AUDIO_DEVICE_INFO_TYPE_TO_ROUTE_INFO.put(
+ AudioDeviceInfo.TYPE_USB_DEVICE,
+ new SystemRouteInfo(
+ MediaRoute2Info.TYPE_USB_DEVICE,
+ /* defaultRouteId= */ "ROUTE_ID_USB_DEVICE",
+ /* nameResource= */ R.string.default_audio_route_name_usb));
+ AUDIO_DEVICE_INFO_TYPE_TO_ROUTE_INFO.put(
+ AudioDeviceInfo.TYPE_USB_HEADSET,
+ new SystemRouteInfo(
+ MediaRoute2Info.TYPE_USB_HEADSET,
+ /* defaultRouteId= */ "ROUTE_ID_USB_HEADSET",
+ /* nameResource= */ R.string.default_audio_route_name_usb));
+ AUDIO_DEVICE_INFO_TYPE_TO_ROUTE_INFO.put(
+ AudioDeviceInfo.TYPE_HDMI_ARC,
+ new SystemRouteInfo(
+ MediaRoute2Info.TYPE_HDMI_ARC,
+ /* defaultRouteId= */ "ROUTE_ID_HDMI_ARC",
+ /* nameResource= */ R.string.default_audio_route_name_external_device));
+ AUDIO_DEVICE_INFO_TYPE_TO_ROUTE_INFO.put(
+ AudioDeviceInfo.TYPE_HDMI_EARC,
+ new SystemRouteInfo(
+ MediaRoute2Info.TYPE_HDMI_EARC,
+ /* defaultRouteId= */ "ROUTE_ID_HDMI_EARC",
+ /* nameResource= */ R.string.default_audio_route_name_external_device));
+ // TODO: b/305199571 - Add a proper type constants and human readable names for AUX_LINE,
+ // LINE_ANALOG, LINE_DIGITAL, BLE_BROADCAST, BLE_SPEAKER, BLE_HEADSET, and HEARING_AID.
+ AUDIO_DEVICE_INFO_TYPE_TO_ROUTE_INFO.put(
+ AudioDeviceInfo.TYPE_HEARING_AID,
+ new SystemRouteInfo(
+ MediaRoute2Info.TYPE_HEARING_AID,
+ /* defaultRouteId= */ "ROUTE_ID_HEARING_AID",
+ /* nameResource= */ R.string.bluetooth_a2dp_audio_route_name));
+ AUDIO_DEVICE_INFO_TYPE_TO_ROUTE_INFO.put(
+ AudioDeviceInfo.TYPE_BLE_HEADSET,
+ new SystemRouteInfo(
+ MediaRoute2Info.TYPE_BLE_HEADSET,
+ /* defaultRouteId= */ "ROUTE_ID_BLE_HEADSET",
+ /* nameResource= */ R.string.bluetooth_a2dp_audio_route_name));
+ AUDIO_DEVICE_INFO_TYPE_TO_ROUTE_INFO.put(
+ AudioDeviceInfo.TYPE_BLE_SPEAKER,
+ new SystemRouteInfo(
+ MediaRoute2Info.TYPE_BLE_HEADSET, // TODO: b/305199571 - Make a new type.
+ /* defaultRouteId= */ "ROUTE_ID_BLE_SPEAKER",
+ /* nameResource= */ R.string.bluetooth_a2dp_audio_route_name));
+ AUDIO_DEVICE_INFO_TYPE_TO_ROUTE_INFO.put(
+ AudioDeviceInfo.TYPE_BLE_BROADCAST,
+ new SystemRouteInfo(
+ MediaRoute2Info.TYPE_BLE_HEADSET,
+ /* defaultRouteId= */ "ROUTE_ID_BLE_BROADCAST",
+ /* nameResource= */ R.string.bluetooth_a2dp_audio_route_name));
+ AUDIO_DEVICE_INFO_TYPE_TO_ROUTE_INFO.put(
+ AudioDeviceInfo.TYPE_LINE_DIGITAL,
+ new SystemRouteInfo(
+ MediaRoute2Info.TYPE_UNKNOWN,
+ /* defaultRouteId= */ "ROUTE_ID_LINE_DIGITAL",
+ /* nameResource= */ R.string.default_audio_route_name_external_device));
+ AUDIO_DEVICE_INFO_TYPE_TO_ROUTE_INFO.put(
+ AudioDeviceInfo.TYPE_LINE_ANALOG,
+ new SystemRouteInfo(
+ MediaRoute2Info.TYPE_UNKNOWN,
+ /* defaultRouteId= */ "ROUTE_ID_LINE_ANALOG",
+ /* nameResource= */ R.string.default_audio_route_name_external_device));
+ AUDIO_DEVICE_INFO_TYPE_TO_ROUTE_INFO.put(
+ AudioDeviceInfo.TYPE_AUX_LINE,
+ new SystemRouteInfo(
+ MediaRoute2Info.TYPE_UNKNOWN,
+ /* defaultRouteId= */ "ROUTE_ID_AUX_LINE",
+ /* nameResource= */ R.string.default_audio_route_name_external_device));
+ AUDIO_DEVICE_INFO_TYPE_TO_ROUTE_INFO.put(
+ AudioDeviceInfo.TYPE_DOCK_ANALOG,
+ new SystemRouteInfo(
+ MediaRoute2Info.TYPE_DOCK,
+ /* defaultRouteId= */ "ROUTE_ID_DOCK_ANALOG",
+ /* nameResource= */ R.string.default_audio_route_name_dock_speakers));
+ }
}
diff --git a/services/core/java/com/android/server/media/AudioRoutingUtils.java b/services/core/java/com/android/server/media/AudioRoutingUtils.java
new file mode 100644
index 0000000..13f11eb
--- /dev/null
+++ b/services/core/java/com/android/server/media/AudioRoutingUtils.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.media;
+
+import android.Manifest;
+import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
+import android.media.AudioAttributes;
+import android.media.AudioManager;
+import android.media.audiopolicy.AudioProductStrategy;
+
+/** Holds utils related to routing in the audio framework. */
+/* package */ final class AudioRoutingUtils {
+
+ /* package */ static final AudioAttributes ATTRIBUTES_MEDIA =
+ new AudioAttributes.Builder().setUsage(AudioAttributes.USAGE_MEDIA).build();
+
+ @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
+ @Nullable
+ /* package */ static AudioProductStrategy getMediaAudioProductStrategy() {
+ for (AudioProductStrategy strategy : AudioManager.getAudioProductStrategies()) {
+ if (strategy.supportsAudioAttributes(AudioRoutingUtils.ATTRIBUTES_MEDIA)) {
+ return strategy;
+ }
+ }
+ return null;
+ }
+
+ private AudioRoutingUtils() {
+ // no-op to prevent instantiation.
+ }
+}
diff --git a/services/core/java/com/android/server/media/BluetoothRouteController.java b/services/core/java/com/android/server/media/BluetoothRouteController.java
index 2b01001..74fdf6e 100644
--- a/services/core/java/com/android/server/media/BluetoothRouteController.java
+++ b/services/core/java/com/android/server/media/BluetoothRouteController.java
@@ -44,19 +44,11 @@
@NonNull
static BluetoothRouteController createInstance(@NonNull Context context,
@NonNull BluetoothRouteController.BluetoothRoutesUpdatedListener listener) {
- Objects.requireNonNull(context);
Objects.requireNonNull(listener);
+ BluetoothAdapter btAdapter = context.getSystemService(BluetoothManager.class).getAdapter();
- BluetoothManager bluetoothManager = (BluetoothManager)
- context.getSystemService(Context.BLUETOOTH_SERVICE);
- BluetoothAdapter btAdapter = bluetoothManager.getAdapter();
-
- if (btAdapter == null) {
+ if (btAdapter == null || Flags.enableAudioPoliciesDeviceAndBluetoothController()) {
return new NoOpBluetoothRouteController();
- }
-
- if (Flags.enableAudioPoliciesDeviceAndBluetoothController()) {
- return new AudioPoliciesBluetoothRouteController(context, btAdapter, listener);
} else {
return new LegacyBluetoothRouteController(context, btAdapter, listener);
}
@@ -74,17 +66,6 @@
*/
void stop();
-
- /**
- * Selects the route with the given {@code deviceAddress}.
- *
- * @param deviceAddress The physical address of the device to select. May be null to unselect
- * the currently selected device.
- * @return Whether the selection succeeds. If the selection fails, the state of the instance
- * remains unaltered.
- */
- boolean selectRoute(@Nullable String deviceAddress);
-
/**
* Transfers Bluetooth output to the given route.
*
@@ -158,12 +139,6 @@
}
@Override
- public boolean selectRoute(String deviceAddress) {
- // no op
- return false;
- }
-
- @Override
public void transferTo(String routeId) {
// no op
}
diff --git a/services/core/java/com/android/server/media/DeviceRouteController.java b/services/core/java/com/android/server/media/DeviceRouteController.java
index 0fdaaa7..9f175a9 100644
--- a/services/core/java/com/android/server/media/DeviceRouteController.java
+++ b/services/core/java/com/android/server/media/DeviceRouteController.java
@@ -16,17 +16,25 @@
package com.android.server.media;
+import android.Manifest;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothManager;
import android.content.Context;
import android.media.AudioManager;
-import android.media.IAudioRoutesObserver;
import android.media.IAudioService;
import android.media.MediaRoute2Info;
+import android.media.audiopolicy.AudioProductStrategy;
+import android.os.Looper;
import android.os.ServiceManager;
+import android.os.UserHandle;
import com.android.media.flags.Flags;
+import java.util.List;
+
/**
* Controls device routes.
*
@@ -37,46 +45,67 @@
*/
/* package */ interface DeviceRouteController {
- /**
- * Returns a new instance of {@link DeviceRouteController}.
- */
- /* package */ static DeviceRouteController createInstance(@NonNull Context context,
+ /** Returns a new instance of {@link DeviceRouteController}. */
+ @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
+ /* package */ static DeviceRouteController createInstance(
+ @NonNull Context context,
+ @NonNull Looper looper,
@NonNull OnDeviceRouteChangedListener onDeviceRouteChangedListener) {
AudioManager audioManager = context.getSystemService(AudioManager.class);
- IAudioService audioService = IAudioService.Stub.asInterface(
- ServiceManager.getService(Context.AUDIO_SERVICE));
+ AudioProductStrategy strategyForMedia = AudioRoutingUtils.getMediaAudioProductStrategy();
- if (Flags.enableAudioPoliciesDeviceAndBluetoothController()) {
- return new AudioPoliciesDeviceRouteController(context,
+ BluetoothManager bluetoothManager = context.getSystemService(BluetoothManager.class);
+ BluetoothAdapter btAdapter =
+ bluetoothManager != null ? bluetoothManager.getAdapter() : null;
+
+ // TODO: b/305199571 - Make the audio policies implementation work without the need for a
+ // bluetooth adapter or a strategy for media. If no strategy for media is available we can
+ // disallow media router transfers, and without a bluetooth adapter we can remove support
+ // for transfers to inactive bluetooth routes.
+ if (strategyForMedia != null
+ && btAdapter != null
+ && Flags.enableAudioPoliciesDeviceAndBluetoothController()) {
+ return new AudioPoliciesDeviceRouteController(
+ context,
audioManager,
- audioService,
+ looper,
+ strategyForMedia,
+ btAdapter,
onDeviceRouteChangedListener);
} else {
- return new LegacyDeviceRouteController(context,
- audioManager,
- audioService,
- onDeviceRouteChangedListener);
+ IAudioService audioService =
+ IAudioService.Stub.asInterface(
+ ServiceManager.getService(Context.AUDIO_SERVICE));
+ return new LegacyDeviceRouteController(
+ context, audioManager, audioService, onDeviceRouteChangedListener);
}
}
- /**
- * Select the route with the given built-in or wired {@link MediaRoute2Info.Type}.
- *
- * <p>If the type is {@code null} then unselects the route and falls back to the default device
- * route observed from
- * {@link com.android.server.audio.AudioService#startWatchingRoutes(IAudioRoutesObserver)}.
- *
- * @param type device type. May be {@code null} to unselect currently selected route.
- * @return whether the selection succeeds. If the selection fails the state of the controller
- * remains intact.
- */
- boolean selectRoute(@Nullable @MediaRoute2Info.Type Integer type);
-
/** Returns the currently selected device (built-in or wired) route. */
@NonNull
MediaRoute2Info getSelectedRoute();
/**
+ * Returns all available routes.
+ *
+ * <p>Note that this method returns available routes including the selected route because (a)
+ * this interface doesn't guarantee that the internal state of the controller won't change
+ * between calls to {@link #getSelectedRoute()} and this method and (b) {@link
+ * #getSelectedRoute()} may be treated as a transferable route (not a selected route) if the
+ * selected route is from {@link BluetoothRouteController}.
+ */
+ List<MediaRoute2Info> getAvailableRoutes();
+
+ /**
+ * Transfers device output to the given route.
+ *
+ * <p>If the route is {@code null} then active route will be deactivated.
+ *
+ * @param routeId to switch to or {@code null} to unset the active device.
+ */
+ void transferTo(@Nullable String routeId);
+
+ /**
* Updates device route volume.
*
* @param volume specifies a volume for the device route or 0 for unknown.
@@ -85,6 +114,18 @@
boolean updateVolume(int volume);
/**
+ * Starts listening for changes in the system to keep an up to date view of available and
+ * selected devices.
+ */
+ void start(UserHandle mUser);
+
+ /**
+ * Stops keeping the internal state up to date with the system, releasing any resources acquired
+ * in {@link #start}
+ */
+ void stop();
+
+ /**
* Interface for receiving events when device route has changed.
*/
interface OnDeviceRouteChangedListener {
diff --git a/services/core/java/com/android/server/media/LegacyBluetoothRouteController.java b/services/core/java/com/android/server/media/LegacyBluetoothRouteController.java
index ba3cecf..041fceaf 100644
--- a/services/core/java/com/android/server/media/LegacyBluetoothRouteController.java
+++ b/services/core/java/com/android/server/media/LegacyBluetoothRouteController.java
@@ -132,12 +132,6 @@
mContext.unregisterReceiver(mDeviceStateChangedReceiver);
}
- @Override
- public boolean selectRoute(String deviceAddress) {
- // No-op as the class decides if a route is selected based on Bluetooth events.
- return false;
- }
-
/**
* Transfers to a given bluetooth route.
* The dedicated BT device with the route would be activated.
diff --git a/services/core/java/com/android/server/media/LegacyDeviceRouteController.java b/services/core/java/com/android/server/media/LegacyDeviceRouteController.java
index 65874e2..c0f2834 100644
--- a/services/core/java/com/android/server/media/LegacyDeviceRouteController.java
+++ b/services/core/java/com/android/server/media/LegacyDeviceRouteController.java
@@ -35,11 +35,13 @@
import android.media.IAudioService;
import android.media.MediaRoute2Info;
import android.os.RemoteException;
+import android.os.UserHandle;
import android.util.Slog;
import com.android.internal.R;
-import com.android.internal.annotations.VisibleForTesting;
+import java.util.Collections;
+import java.util.List;
import java.util.Objects;
/**
@@ -73,7 +75,6 @@
private int mDeviceVolume;
private MediaRoute2Info mDeviceRoute;
- @VisibleForTesting
/* package */ LegacyDeviceRouteController(@NonNull Context context,
@NonNull AudioManager audioManager,
@NonNull IAudioService audioService,
@@ -100,9 +101,13 @@
}
@Override
- public boolean selectRoute(@Nullable Integer type) {
- // No-op as the controller does not support selection from the outside of the class.
- return false;
+ public void start(UserHandle mUser) {
+ // Nothing to do.
+ }
+
+ @Override
+ public void stop() {
+ // Nothing to do.
}
@Override
@@ -112,6 +117,17 @@
}
@Override
+ public synchronized List<MediaRoute2Info> getAvailableRoutes() {
+ return Collections.emptyList();
+ }
+
+ @Override
+ public synchronized void transferTo(@Nullable String routeId) {
+ // Unsupported. This implementation doesn't support transferable routes (always exposes a
+ // single non-bluetooth route).
+ }
+
+ @Override
public synchronized boolean updateVolume(int volume) {
if (mDeviceVolume == volume) {
return false;
diff --git a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
index 4821fbe..df9e741 100644
--- a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
+++ b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
@@ -193,26 +193,6 @@
// Start of methods that implement MediaRouter2 operations.
- @RequiresPermission(Manifest.permission.MEDIA_CONTENT_CONTROL)
- @NonNull
- public boolean verifyPackageExists(@NonNull String clientPackageName) {
- final int pid = Binder.getCallingPid();
- final int uid = Binder.getCallingUid();
- final long token = Binder.clearCallingIdentity();
-
- try {
- // TODO (b/305919655) - Handle revoking of MEDIA_ROUTING_CONTROL at runtime.
- enforcePrivilegedRoutingPermissions(uid, pid, /* callerPackageName */ null);
- PackageManager pm = mContext.getPackageManager();
- pm.getPackageInfo(clientPackageName, PackageManager.PackageInfoFlags.of(0));
- return true;
- } catch (PackageManager.NameNotFoundException ex) {
- return false;
- } finally {
- Binder.restoreCallingIdentity(token);
- }
- }
-
@NonNull
public List<MediaRoute2Info> getSystemRoutes() {
final int uid = Binder.getCallingUid();
@@ -491,13 +471,65 @@
final int callerUid = Binder.getCallingUid();
final int callerPid = Binder.getCallingPid();
- final int callerUserId = UserHandle.getUserHandleForUid(callerUid).getIdentifier();
+ final UserHandle callerUser = Binder.getCallingUserHandle();
+
+ // TODO (b/305919655) - Handle revoking of MEDIA_ROUTING_CONTROL at runtime.
+ enforcePrivilegedRoutingPermissions(callerUid, callerPid, callerPackageName);
final long token = Binder.clearCallingIdentity();
try {
synchronized (mLock) {
registerManagerLocked(
- manager, callerUid, callerPid, callerPackageName, callerUserId);
+ manager,
+ callerUid,
+ callerPid,
+ callerPackageName,
+ /* targetPackageName */ null,
+ callerUser);
+ }
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
+ @RequiresPermission(
+ anyOf = {
+ Manifest.permission.MEDIA_CONTENT_CONTROL,
+ Manifest.permission.MEDIA_ROUTING_CONTROL
+ })
+ public void registerProxyRouter(
+ @NonNull IMediaRouter2Manager manager,
+ @NonNull String callerPackageName,
+ @NonNull String targetPackageName,
+ @NonNull UserHandle targetUser) {
+ Objects.requireNonNull(manager, "manager must not be null");
+ Objects.requireNonNull(targetUser, "targetUser must not be null");
+
+ if (TextUtils.isEmpty(targetPackageName)) {
+ throw new IllegalArgumentException("targetPackageName must not be empty");
+ }
+
+ int callerUid = Binder.getCallingUid();
+ int callerPid = Binder.getCallingPid();
+ final long token = Binder.clearCallingIdentity();
+
+ try {
+ // TODO (b/305919655) - Handle revoking of MEDIA_ROUTING_CONTROL at runtime.
+ enforcePrivilegedRoutingPermissions(callerUid, callerPid, callerPackageName);
+ enforceCrossUserPermissions(callerUid, callerPid, targetUser);
+ if (!verifyPackageExistsForUser(targetPackageName, targetUser)) {
+ throw new IllegalArgumentException(
+ "targetPackageName does not exist: " + targetPackageName);
+ }
+
+ synchronized (mLock) {
+ registerManagerLocked(
+ manager,
+ callerUid,
+ callerPid,
+ callerPackageName,
+ targetPackageName,
+ targetUser);
}
} finally {
Binder.restoreCallingIdentity(token);
@@ -761,6 +793,37 @@
}
}
+ @RequiresPermission(value = Manifest.permission.INTERACT_ACROSS_USERS)
+ private boolean verifyPackageExistsForUser(
+ @NonNull String clientPackageName, @NonNull UserHandle user) {
+ try {
+ PackageManager pm = mContext.getPackageManager();
+ pm.getPackageInfoAsUser(
+ clientPackageName, PackageManager.PackageInfoFlags.of(0), user.getIdentifier());
+ return true;
+ } catch (PackageManager.NameNotFoundException ex) {
+ return false;
+ }
+ }
+
+ /**
+ * Enforces the caller has {@link Manifest.permission#INTERACT_ACROSS_USERS_FULL} if the
+ * caller's user is different from the target user.
+ */
+ private void enforceCrossUserPermissions(
+ int callerUid, int callerPid, @NonNull UserHandle targetUser) {
+ int callerUserId = UserHandle.getUserId(callerUid);
+
+ if (targetUser.getIdentifier() != callerUserId) {
+ mContext.enforcePermission(
+ Manifest.permission.INTERACT_ACROSS_USERS_FULL,
+ callerPid,
+ callerUid,
+ "Must hold INTERACT_ACROSS_USERS_FULL to control an app in a different"
+ + " userId.");
+ }
+ }
+
// End of methods that implements operations for both MediaRouter2 and MediaRouter2Manager.
public void dump(@NonNull PrintWriter pw, @NonNull String prefix) {
@@ -1203,7 +1266,8 @@
int callerUid,
int callerPid,
@NonNull String callerPackageName,
- int callerUserId) {
+ @Nullable String targetPackageName,
+ @NonNull UserHandle targetUser) {
final IBinder binder = manager.asBinder();
ManagerRecord managerRecord = mAllManagerRecords.get(binder);
@@ -1217,15 +1281,18 @@
TAG,
TextUtils.formatSimple(
"registerManager | callerUid: %d, callerPid: %d, callerPackage: %s,"
- + " callerUserId: %d",
- callerUid, callerPid, callerPackageName, callerUserId));
+ + "targetPackageName: %s, targetUserId: %d",
+ callerUid, callerPid, callerPackageName, targetPackageName, targetUser));
- // TODO (b/305919655) - Handle revoking of MEDIA_ROUTING_CONTROL at runtime.
- enforcePrivilegedRoutingPermissions(callerUid, callerPid, callerPackageName);
-
- UserRecord userRecord = getOrCreateUserRecordLocked(callerUserId);
- managerRecord = new ManagerRecord(
- userRecord, manager, callerUid, callerPid, callerPackageName);
+ UserRecord userRecord = getOrCreateUserRecordLocked(targetUser.getIdentifier());
+ managerRecord =
+ new ManagerRecord(
+ userRecord,
+ manager,
+ callerUid,
+ callerPid,
+ callerPackageName,
+ targetPackageName);
try {
binder.linkToDeath(managerRecord, 0);
} catch (RemoteException ex) {
@@ -1791,22 +1858,30 @@
}
final class ManagerRecord implements IBinder.DeathRecipient {
- public final UserRecord mUserRecord;
- public final IMediaRouter2Manager mManager;
+ @NonNull public final UserRecord mUserRecord;
+ @NonNull public final IMediaRouter2Manager mManager;
public final int mOwnerUid;
public final int mOwnerPid;
- public final String mOwnerPackageName;
+ @NonNull public final String mOwnerPackageName;
public final int mManagerId;
- public SessionCreationRequest mLastSessionCreationRequest;
+ // TODO (b/281072508): Document behaviour around nullability for mTargetPackageName.
+ @Nullable public final String mTargetPackageName;
+ @Nullable public SessionCreationRequest mLastSessionCreationRequest;
public boolean mIsScanning;
- ManagerRecord(UserRecord userRecord, IMediaRouter2Manager manager,
- int ownerUid, int ownerPid, String ownerPackageName) {
+ ManagerRecord(
+ @NonNull UserRecord userRecord,
+ @NonNull IMediaRouter2Manager manager,
+ int ownerUid,
+ int ownerPid,
+ @NonNull String ownerPackageName,
+ @Nullable String targetPackageName) {
mUserRecord = userRecord;
mManager = manager;
mOwnerUid = ownerUid;
mOwnerPid = ownerPid;
mOwnerPackageName = ownerPackageName;
+ mTargetPackageName = targetPackageName;
mManagerId = mNextRouterOrManagerId.getAndIncrement();
}
@@ -2833,46 +2908,69 @@
if (service == null) {
return;
}
- List<RouterRecord> activeRouterRecords = Collections.emptyList();
+ List<RouterRecord> activeRouterRecords;
List<RouterRecord> allRouterRecords = getRouterRecords();
- List<ManagerRecord> managerRecords = getManagerRecords();
- boolean isManagerScanning = false;
- if (Flags.disableScreenOffBroadcastReceiver()
- || service.mPowerManager.isInteractive()) {
- isManagerScanning = managerRecords.stream().anyMatch(manager ->
- manager.mIsScanning && service.mActivityManager
- .getPackageImportance(manager.mOwnerPackageName)
- <= sPackageImportanceForScanning);
+ boolean areManagersScanning = areManagersScanning(service, getManagerRecords());
- if (isManagerScanning) {
- activeRouterRecords = allRouterRecords;
- } else {
- activeRouterRecords =
- allRouterRecords.stream()
- .filter(
- record ->
- service.mActivityManager.getPackageImportance(
- record.mPackageName)
- <= sPackageImportanceForScanning)
- .collect(Collectors.toList());
- }
+ if (areManagersScanning) {
+ activeRouterRecords = allRouterRecords;
+ } else {
+ activeRouterRecords = getIndividuallyActiveRouters(service, allRouterRecords);
}
- for (MediaRoute2Provider provider : mRouteProviders) {
- if (provider instanceof MediaRoute2ProviderServiceProxy) {
- ((MediaRoute2ProviderServiceProxy) provider)
- .setManagerScanning(isManagerScanning);
- }
- }
+ updateManagerScanningForProviders(areManagersScanning);
- // Build a composite RouteDiscoveryPreference that matches all of the routes
- // that match one or more of the individual discovery preferences. It may also
- // match additional routes. The composite RouteDiscoveryPreference can be used
- // to query route providers once to obtain all of the routes of interest, which
- // can be subsequently filtered for the individual discovery preferences.
- Set<String> preferredFeatures = new HashSet<>();
Set<String> activelyScanningPackages = new HashSet<>();
+ RouteDiscoveryPreference newPreference =
+ buildCompositeDiscoveryPreference(
+ activeRouterRecords, areManagersScanning, activelyScanningPackages);
+
+ if (updateScanningOnUserRecord(service, activelyScanningPackages, newPreference)) {
+ updateDiscoveryPreferenceForProviders(activelyScanningPackages);
+ }
+ }
+
+ private void updateDiscoveryPreferenceForProviders(Set<String> activelyScanningPackages) {
+ for (MediaRoute2Provider provider : mRouteProviders) {
+ provider.updateDiscoveryPreference(
+ activelyScanningPackages, mUserRecord.mCompositeDiscoveryPreference);
+ }
+ }
+
+ private boolean updateScanningOnUserRecord(
+ MediaRouter2ServiceImpl service,
+ Set<String> activelyScanningPackages,
+ RouteDiscoveryPreference newPreference) {
+ synchronized (service.mLock) {
+ if (newPreference.equals(mUserRecord.mCompositeDiscoveryPreference)
+ && activelyScanningPackages.equals(mUserRecord.mActivelyScanningPackages)) {
+ return false;
+ }
+ mUserRecord.mCompositeDiscoveryPreference = newPreference;
+ mUserRecord.mActivelyScanningPackages = activelyScanningPackages;
+ }
+ return true;
+ }
+
+ /**
+ * Returns a composite {@link RouteDiscoveryPreference} that aggregates every router
+ * record's individual discovery preference.
+ *
+ * <p>The {@link RouteDiscoveryPreference#shouldPerformActiveScan() active scan value} of
+ * the composite discovery preference is true if one of the router records is actively
+ * scanning or if {@code shouldForceActiveScan} is true.
+ *
+ * <p>The composite RouteDiscoveryPreference is used to query route providers once to obtain
+ * all the routes of interest, which can be subsequently filtered for the individual
+ * discovery preferences.
+ */
+ @NonNull
+ private static RouteDiscoveryPreference buildCompositeDiscoveryPreference(
+ List<RouterRecord> activeRouterRecords,
+ boolean shouldForceActiveScan,
+ Set<String> activelyScanningPackages) {
+ Set<String> preferredFeatures = new HashSet<>();
boolean activeScan = false;
for (RouterRecord activeRouterRecord : activeRouterRecords) {
RouteDiscoveryPreference preference = activeRouterRecord.mDiscoveryPreference;
@@ -2882,23 +2980,53 @@
activelyScanningPackages.add(activeRouterRecord.mPackageName);
}
}
- RouteDiscoveryPreference newPreference = new RouteDiscoveryPreference.Builder(
- List.copyOf(preferredFeatures), activeScan || isManagerScanning).build();
+ return new RouteDiscoveryPreference.Builder(
+ List.copyOf(preferredFeatures), activeScan || shouldForceActiveScan)
+ .build();
+ }
- synchronized (service.mLock) {
- if (newPreference.equals(mUserRecord.mCompositeDiscoveryPreference)
- && activelyScanningPackages.equals(mUserRecord.mActivelyScanningPackages)) {
- return;
- }
- mUserRecord.mCompositeDiscoveryPreference = newPreference;
- mUserRecord.mActivelyScanningPackages = activelyScanningPackages;
- }
+ private void updateManagerScanningForProviders(boolean isManagerScanning) {
for (MediaRoute2Provider provider : mRouteProviders) {
- provider.updateDiscoveryPreference(
- activelyScanningPackages, mUserRecord.mCompositeDiscoveryPreference);
+ if (provider instanceof MediaRoute2ProviderServiceProxy) {
+ ((MediaRoute2ProviderServiceProxy) provider)
+ .setManagerScanning(isManagerScanning);
+ }
}
}
+ @NonNull
+ private static List<RouterRecord> getIndividuallyActiveRouters(
+ MediaRouter2ServiceImpl service, List<RouterRecord> allRouterRecords) {
+ if (!Flags.disableScreenOffBroadcastReceiver()
+ && !service.mPowerManager.isInteractive()) {
+ return Collections.emptyList();
+ }
+
+ return allRouterRecords.stream()
+ .filter(
+ record ->
+ service.mActivityManager.getPackageImportance(
+ record.mPackageName)
+ <= sPackageImportanceForScanning)
+ .collect(Collectors.toList());
+ }
+
+ private static boolean areManagersScanning(
+ MediaRouter2ServiceImpl service, List<ManagerRecord> managerRecords) {
+ if (!Flags.disableScreenOffBroadcastReceiver()
+ && !service.mPowerManager.isInteractive()) {
+ return false;
+ }
+
+ return managerRecords.stream()
+ .anyMatch(
+ manager ->
+ manager.mIsScanning
+ && service.mActivityManager.getPackageImportance(
+ manager.mOwnerPackageName)
+ <= sPackageImportanceForScanning);
+ }
+
private MediaRoute2Provider findProvider(@Nullable String providerId) {
for (MediaRoute2Provider provider : mRouteProviders) {
if (TextUtils.equals(provider.getUniqueId(), providerId)) {
diff --git a/services/core/java/com/android/server/media/MediaRouterService.java b/services/core/java/com/android/server/media/MediaRouterService.java
index 6df4a95..e562b3f 100644
--- a/services/core/java/com/android/server/media/MediaRouterService.java
+++ b/services/core/java/com/android/server/media/MediaRouterService.java
@@ -409,13 +409,6 @@
}
// Binder call
- @RequiresPermission(Manifest.permission.MEDIA_CONTENT_CONTROL)
- @Override
- public boolean verifyPackageExists(String clientPackageName) {
- return mService2.verifyPackageExists(clientPackageName);
- }
-
- // Binder call
@Override
public List<MediaRoute2Info> getSystemRoutes() {
return mService2.getSystemRoutes();
@@ -547,6 +540,19 @@
mService2.registerManager(manager, callerPackageName);
}
+ @Override
+ public void registerProxyRouter(
+ @NonNull IMediaRouter2Manager manager,
+ @NonNull String callerPackageName,
+ @NonNull String targetPackageName,
+ @NonNull UserHandle targetUser) {
+ final int uid = Binder.getCallingUid();
+ if (!validatePackageName(uid, callerPackageName)) {
+ throw new SecurityException("callerPackageName must match the calling uid");
+ }
+ mService2.registerProxyRouter(manager, callerPackageName, targetPackageName, targetUser);
+ }
+
// Binder call
@Override
public void unregisterManager(IMediaRouter2Manager manager) {
diff --git a/services/core/java/com/android/server/media/SystemMediaRoute2Provider.java b/services/core/java/com/android/server/media/SystemMediaRoute2Provider.java
index c8dba80..9d151c2 100644
--- a/services/core/java/com/android/server/media/SystemMediaRoute2Provider.java
+++ b/services/core/java/com/android/server/media/SystemMediaRoute2Provider.java
@@ -16,15 +16,12 @@
package com.android.server.media;
-import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
-import android.media.AudioAttributes;
-import android.media.AudioDeviceAttributes;
import android.media.AudioManager;
import android.media.MediaRoute2Info;
import android.media.MediaRoute2ProviderInfo;
@@ -51,7 +48,8 @@
*/
// TODO: check thread safety. We may need to use lock to protect variables.
class SystemMediaRoute2Provider extends MediaRoute2Provider {
- private static final String TAG = "MR2SystemProvider";
+ // Package-visible to use this tag for all system routing logic (done across multiple classes).
+ /* package */ static final String TAG = "MR2SystemProvider";
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
private static final ComponentName COMPONENT_NAME = new ComponentName(
@@ -77,26 +75,6 @@
private final AudioManagerBroadcastReceiver mAudioReceiver =
new AudioManagerBroadcastReceiver();
- private final AudioManager.OnDevicesForAttributesChangedListener
- mOnDevicesForAttributesChangedListener =
- new AudioManager.OnDevicesForAttributesChangedListener() {
- @Override
- public void onDevicesForAttributesChanged(@NonNull AudioAttributes attributes,
- @NonNull List<AudioDeviceAttributes> devices) {
- if (attributes.getUsage() != AudioAttributes.USAGE_MEDIA) {
- return;
- }
-
- mHandler.post(() -> {
- updateSelectedAudioDevice(devices);
- notifyProviderState();
- if (updateSessionInfosIfNeeded()) {
- notifySessionInfoUpdated();
- }
- });
- }
- };
-
private final Object mRequestLock = new Object();
@GuardedBy("mRequestLock")
private volatile SessionCreationRequest mPendingSessionCreationRequest;
@@ -106,7 +84,8 @@
mIsSystemRouteProvider = true;
mContext = context;
mUser = user;
- mHandler = new Handler(Looper.getMainLooper());
+ Looper looper = Looper.getMainLooper();
+ mHandler = new Handler(looper);
mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
@@ -123,25 +102,15 @@
mDeviceRouteController =
DeviceRouteController.createInstance(
context,
- () -> {
- mHandler.post(
- () -> {
- publishProviderState();
- if (updateSessionInfosIfNeeded()) {
- notifySessionInfoUpdated();
- }
- });
- });
-
- mAudioManager.addOnDevicesForAttributesChangedListener(
- AudioAttributesUtils.ATTRIBUTES_MEDIA, mContext.getMainExecutor(),
- mOnDevicesForAttributesChangedListener);
-
- // These methods below should be called after all fields are initialized, as they
- // access the fields inside.
- List<AudioDeviceAttributes> devices =
- mAudioManager.getDevicesForAttributes(AudioAttributesUtils.ATTRIBUTES_MEDIA);
- updateSelectedAudioDevice(devices);
+ looper,
+ () ->
+ mHandler.post(
+ () -> {
+ publishProviderState();
+ if (updateSessionInfosIfNeeded()) {
+ notifySessionInfoUpdated();
+ }
+ }));
updateProviderState();
updateSessionInfosIfNeeded();
}
@@ -151,20 +120,22 @@
intentFilter.addAction(AudioManager.STREAM_DEVICES_CHANGED_ACTION);
mContext.registerReceiverAsUser(mAudioReceiver, mUser,
intentFilter, null, null);
-
- mHandler.post(() -> {
- mBluetoothRouteController.start(mUser);
- notifyProviderState();
- });
+ mHandler.post(
+ () -> {
+ mDeviceRouteController.start(mUser);
+ mBluetoothRouteController.start(mUser);
+ });
updateVolume();
}
public void stop() {
mContext.unregisterReceiver(mAudioReceiver);
- mHandler.post(() -> {
- mBluetoothRouteController.stop();
- notifyProviderState();
- });
+ mHandler.post(
+ () -> {
+ mBluetoothRouteController.stop();
+ mDeviceRouteController.stop();
+ notifyProviderState();
+ });
}
@Override
@@ -225,13 +196,26 @@
public void transferToRoute(long requestId, String sessionId, String routeId) {
if (TextUtils.equals(routeId, MediaRoute2Info.ROUTE_ID_DEFAULT)) {
// The currently selected route is the default route.
+ Log.w(TAG, "Ignoring transfer to " + MediaRoute2Info.ROUTE_ID_DEFAULT);
return;
}
-
MediaRoute2Info selectedDeviceRoute = mDeviceRouteController.getSelectedRoute();
- if (TextUtils.equals(routeId, selectedDeviceRoute.getId())) {
+ boolean isAvailableDeviceRoute =
+ mDeviceRouteController.getAvailableRoutes().stream()
+ .anyMatch(it -> it.getId().equals(routeId));
+ boolean isSelectedDeviceRoute = TextUtils.equals(routeId, selectedDeviceRoute.getId());
+
+ if (isSelectedDeviceRoute || isAvailableDeviceRoute) {
+ // The requested route is managed by the device route controller. Note that the selected
+ // device route doesn't necessarily match mSelectedRouteId (which is the selected route
+ // of the routing session). If the selected device route is transferred to, we need to
+ // make the bluetooth routes inactive so that the device route becomes the selected
+ // route of the routing session.
+ mDeviceRouteController.transferTo(routeId);
mBluetoothRouteController.transferTo(null);
} else {
+ // The requested route is managed by the bluetooth route controller.
+ mDeviceRouteController.transferTo(null);
mBluetoothRouteController.transferTo(routeId);
}
}
@@ -280,41 +264,38 @@
MediaRoute2Info selectedDeviceRoute = mDeviceRouteController.getSelectedRoute();
- RoutingSessionInfo.Builder builder = new RoutingSessionInfo.Builder(
- SYSTEM_SESSION_ID, packageName).setSystemSession(true);
+ RoutingSessionInfo.Builder builder =
+ new RoutingSessionInfo.Builder(SYSTEM_SESSION_ID, packageName)
+ .setSystemSession(true);
builder.addSelectedRoute(selectedDeviceRoute.getId());
for (MediaRoute2Info route : mBluetoothRouteController.getAllBluetoothRoutes()) {
builder.addTransferableRoute(route.getId());
}
+
+ if (Flags.enableAudioPoliciesDeviceAndBluetoothController()) {
+ for (MediaRoute2Info route : mDeviceRouteController.getAvailableRoutes()) {
+ if (!TextUtils.equals(selectedDeviceRoute.getId(), route.getId())) {
+ builder.addTransferableRoute(route.getId());
+ }
+ }
+ }
return builder.setProviderId(mUniqueId).build();
}
}
- private void updateSelectedAudioDevice(@NonNull List<AudioDeviceAttributes> devices) {
- if (devices.isEmpty()) {
- Slog.w(TAG, "The list of preferred devices was empty.");
- return;
- }
-
- AudioDeviceAttributes audioDeviceAttributes = devices.get(0);
-
- if (AudioAttributesUtils.isDeviceOutputAttributes(audioDeviceAttributes)) {
- mDeviceRouteController.selectRoute(
- AudioAttributesUtils.mapToMediaRouteType(audioDeviceAttributes));
- mBluetoothRouteController.selectRoute(null);
- } else if (AudioAttributesUtils.isBluetoothOutputAttributes(audioDeviceAttributes)) {
- mDeviceRouteController.selectRoute(null);
- mBluetoothRouteController.selectRoute(audioDeviceAttributes.getAddress());
- } else {
- Slog.w(TAG, "Unknown audio attributes: " + audioDeviceAttributes);
- }
- }
-
private void updateProviderState() {
MediaRoute2ProviderInfo.Builder builder = new MediaRoute2ProviderInfo.Builder();
// We must have a device route in the provider info.
- builder.addRoute(mDeviceRouteController.getSelectedRoute());
+ if (Flags.enableAudioPoliciesDeviceAndBluetoothController()) {
+ List<MediaRoute2Info> deviceRoutes = mDeviceRouteController.getAvailableRoutes();
+ for (MediaRoute2Info route : deviceRoutes) {
+ builder.addRoute(route);
+ }
+ setProviderState(builder.build());
+ } else {
+ builder.addRoute(mDeviceRouteController.getSelectedRoute());
+ }
for (MediaRoute2Info route : mBluetoothRouteController.getAllBluetoothRoutes()) {
builder.addRoute(route);
@@ -352,7 +333,14 @@
.setProviderId(mUniqueId)
.build();
builder.addSelectedRoute(mSelectedRouteId);
-
+ if (Flags.enableAudioPoliciesDeviceAndBluetoothController()) {
+ for (MediaRoute2Info route : mDeviceRouteController.getAvailableRoutes()) {
+ String routeId = route.getId();
+ if (!mSelectedRouteId.equals(routeId)) {
+ builder.addTransferableRoute(routeId);
+ }
+ }
+ }
for (MediaRoute2Info route : mBluetoothRouteController.getTransferableRoutes()) {
builder.addTransferableRoute(route.getId());
}
diff --git a/services/core/java/com/android/server/notification/DefaultDeviceEffectsApplier.java b/services/core/java/com/android/server/notification/DefaultDeviceEffectsApplier.java
new file mode 100644
index 0000000..9fdeda4
--- /dev/null
+++ b/services/core/java/com/android/server/notification/DefaultDeviceEffectsApplier.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.notification;
+
+import android.app.UiModeManager;
+import android.app.WallpaperManager;
+import android.content.Context;
+import android.hardware.display.ColorDisplayManager;
+import android.os.Binder;
+import android.os.PowerManager;
+import android.service.notification.DeviceEffectsApplier;
+import android.service.notification.ZenDeviceEffects;
+
+/** Default implementation for {@link DeviceEffectsApplier}. */
+class DefaultDeviceEffectsApplier implements DeviceEffectsApplier {
+
+ private static final String SUPPRESS_AMBIENT_DISPLAY_TOKEN =
+ "DefaultDeviceEffectsApplier:SuppressAmbientDisplay";
+ private static final int SATURATION_LEVEL_GRAYSCALE = 0;
+ private static final int SATURATION_LEVEL_FULL_COLOR = 100;
+ private static final float WALLPAPER_DIM_AMOUNT_DIMMED = 0.6f;
+ private static final float WALLPAPER_DIM_AMOUNT_NORMAL = 0f;
+
+ private final ColorDisplayManager mColorDisplayManager;
+ private final PowerManager mPowerManager;
+ private final UiModeManager mUiModeManager;
+ private final WallpaperManager mWallpaperManager;
+
+ DefaultDeviceEffectsApplier(Context context) {
+ mColorDisplayManager = context.getSystemService(ColorDisplayManager.class);
+ mPowerManager = context.getSystemService(PowerManager.class);
+ mUiModeManager = context.getSystemService(UiModeManager.class);
+ mWallpaperManager = context.getSystemService(WallpaperManager.class);
+ }
+
+ @Override
+ public void apply(ZenDeviceEffects effects) {
+ Binder.withCleanCallingIdentity(() -> {
+ mPowerManager.suppressAmbientDisplay(SUPPRESS_AMBIENT_DISPLAY_TOKEN,
+ effects.shouldSuppressAmbientDisplay());
+
+ if (mColorDisplayManager != null) {
+ mColorDisplayManager.setSaturationLevel(
+ effects.shouldDisplayGrayscale() ? SATURATION_LEVEL_GRAYSCALE
+ : SATURATION_LEVEL_FULL_COLOR);
+ }
+
+ if (mWallpaperManager != null) {
+ mWallpaperManager.setWallpaperDimAmount(
+ effects.shouldDimWallpaper() ? WALLPAPER_DIM_AMOUNT_DIMMED
+ : WALLPAPER_DIM_AMOUNT_NORMAL);
+ }
+
+ // TODO: b/308673343 - Apply dark theme (via UiModeManager) when screen is off.
+ });
+ }
+}
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 3c6887c1..02845fb 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -2941,6 +2941,12 @@
registerDeviceConfigChange();
migrateDefaultNAS();
maybeShowInitialReviewPermissionsNotification();
+
+ if (android.app.Flags.modesApi()) {
+ // Cannot be done earlier, as some services aren't ready until this point.
+ mZenModeHelper.setDeviceEffectsApplier(
+ new DefaultDeviceEffectsApplier(getContext()));
+ }
} else if (phase == SystemService.PHASE_ACTIVITY_MANAGER_READY) {
mSnoozeHelper.scheduleRepostsForPersistedNotifications(System.currentTimeMillis());
} else if (phase == SystemService.PHASE_DEVICE_SPECIFIC_SERVICES_READY) {
diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java
index 5c37eea..218519f 100644
--- a/services/core/java/com/android/server/notification/ZenModeHelper.java
+++ b/services/core/java/com/android/server/notification/ZenModeHelper.java
@@ -27,8 +27,8 @@
import static com.android.internal.util.FrameworkStatsLog.DND_MODE_RULE;
-import android.annotation.IntDef;
import android.annotation.DrawableRes;
+import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SuppressLint;
@@ -76,6 +76,7 @@
import android.provider.Settings.Global;
import android.service.notification.Condition;
import android.service.notification.ConditionProviderService;
+import android.service.notification.DeviceEffectsApplier;
import android.service.notification.ZenDeviceEffects;
import android.service.notification.ZenModeConfig;
import android.service.notification.ZenModeConfig.ZenRule;
@@ -175,6 +176,8 @@
@VisibleForTesting protected int mZenMode;
@VisibleForTesting protected NotificationManager.Policy mConsolidatedPolicy;
+ @GuardedBy("mConfigLock")
+ private ZenDeviceEffects mConsolidatedDeviceEffects = new ZenDeviceEffects.Builder().build();
private int mUser = UserHandle.USER_SYSTEM;
private final Object mConfigLock = new Object();
@@ -182,6 +185,8 @@
@VisibleForTesting protected ZenModeConfig mConfig;
@VisibleForTesting protected AudioManagerInternal mAudioManager;
protected PackageManager mPm;
+ @GuardedBy("mConfigLock")
+ private DeviceEffectsApplier mDeviceEffectsApplier;
private long mSuppressedEffects;
public static final long SUPPRESSED_EFFECT_NOTIFICATIONS = 1;
@@ -189,7 +194,7 @@
public static final long SUPPRESSED_EFFECT_ALL = SUPPRESSED_EFFECT_CALLS
| SUPPRESSED_EFFECT_NOTIFICATIONS;
- @VisibleForTesting protected boolean mIsBootComplete;
+ @VisibleForTesting protected boolean mIsSystemServicesReady;
private String[] mPriorityOnlyDndExemptPackages;
@@ -285,10 +290,33 @@
mPm = mContext.getPackageManager();
mHandler.postMetricsTimer();
cleanUpZenRules();
- mIsBootComplete = true;
+ mIsSystemServicesReady = true;
showZenUpgradeNotification(mZenMode);
}
+ /**
+ * Set the {@link DeviceEffectsApplier} used to apply the consolidated effects.
+ *
+ * <p>If effects were calculated previously (for example, when we loaded a {@link ZenModeConfig}
+ * that includes activated rules), they will be applied immediately.
+ */
+ void setDeviceEffectsApplier(@NonNull DeviceEffectsApplier deviceEffectsApplier) {
+ if (!Flags.modesApi()) {
+ return;
+ }
+ ZenDeviceEffects consolidatedDeviceEffects;
+ synchronized (mConfigLock) {
+ if (mDeviceEffectsApplier != null) {
+ throw new IllegalStateException("Already set up a DeviceEffectsApplier!");
+ }
+ mDeviceEffectsApplier = deviceEffectsApplier;
+ consolidatedDeviceEffects = mConsolidatedDeviceEffects;
+ }
+ if (consolidatedDeviceEffects.hasEffects()) {
+ applyConsolidatedDeviceEffects();
+ }
+ }
+
public void onUserSwitched(int user) {
loadConfigForUser(user, "onUserSwitched");
}
@@ -1349,7 +1377,7 @@
mConfig = config;
dispatchOnConfigChanged();
- updateConsolidatedPolicy(reason);
+ updateAndApplyConsolidatedPolicyAndDeviceEffects(reason);
}
final String val = Integer.toString(config.hashCode());
Global.putString(mContext.getContentResolver(), Global.ZEN_MODE_CONFIG_ETAG, val);
@@ -1398,7 +1426,7 @@
ZenLog.traceSetZenMode(zen, reason);
mZenMode = zen;
setZenModeSetting(mZenMode);
- updateConsolidatedPolicy(reason);
+ updateAndApplyConsolidatedPolicyAndDeviceEffects(reason);
boolean shouldApplyToRinger = setRingerMode && (zen != zenBefore || (
zen == Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS
&& policyHashBefore != mConsolidatedPolicy.hashCode()));
@@ -1459,25 +1487,56 @@
}
}
- private void updateConsolidatedPolicy(String reason) {
+ private void updateAndApplyConsolidatedPolicyAndDeviceEffects(String reason) {
synchronized (mConfigLock) {
if (mConfig == null) return;
ZenPolicy policy = new ZenPolicy();
+ ZenDeviceEffects.Builder deviceEffectsBuilder = new ZenDeviceEffects.Builder();
if (mConfig.manualRule != null) {
applyCustomPolicy(policy, mConfig.manualRule);
+ if (Flags.modesApi()) {
+ deviceEffectsBuilder.add(mConfig.manualRule.zenDeviceEffects);
+ }
}
for (ZenRule automaticRule : mConfig.automaticRules.values()) {
if (automaticRule.isAutomaticActive()) {
applyCustomPolicy(policy, automaticRule);
+ if (Flags.modesApi()) {
+ deviceEffectsBuilder.add(automaticRule.zenDeviceEffects);
+ }
}
}
+
Policy newPolicy = mConfig.toNotificationPolicy(policy);
if (!Objects.equals(mConsolidatedPolicy, newPolicy)) {
mConsolidatedPolicy = newPolicy;
dispatchOnConsolidatedPolicyChanged();
ZenLog.traceSetConsolidatedZenPolicy(mConsolidatedPolicy, reason);
}
+
+ if (Flags.modesApi()) {
+ ZenDeviceEffects deviceEffects = deviceEffectsBuilder.build();
+ if (!deviceEffects.equals(mConsolidatedDeviceEffects)) {
+ mConsolidatedDeviceEffects = deviceEffects;
+ mHandler.postApplyDeviceEffects();
+ }
+ }
+ }
+ }
+
+ private void applyConsolidatedDeviceEffects() {
+ if (!Flags.modesApi()) {
+ return;
+ }
+ DeviceEffectsApplier applier;
+ ZenDeviceEffects effects;
+ synchronized (mConfigLock) {
+ applier = mDeviceEffectsApplier;
+ effects = mConsolidatedDeviceEffects;
+ }
+ if (applier != null) {
+ applier.apply(effects);
}
}
@@ -1893,7 +1952,7 @@
private void showZenUpgradeNotification(int zen) {
final boolean isWatch = mContext.getPackageManager().hasSystemFeature(
PackageManager.FEATURE_WATCH);
- final boolean showNotification = mIsBootComplete
+ final boolean showNotification = mIsSystemServicesReady
&& zen != Global.ZEN_MODE_OFF
&& !isWatch
&& Settings.Secure.getInt(mContext.getContentResolver(),
@@ -2067,6 +2126,7 @@
private static final int MSG_DISPATCH = 1;
private static final int MSG_METRICS = 2;
private static final int MSG_RINGER_AUDIO = 5;
+ private static final int MSG_APPLY_EFFECTS = 6;
private static final long METRICS_PERIOD_MS = 6 * 60 * 60 * 1000;
@@ -2089,6 +2149,11 @@
sendMessage(obtainMessage(MSG_RINGER_AUDIO, shouldApplyToRinger));
}
+ private void postApplyDeviceEffects() {
+ removeMessages(MSG_APPLY_EFFECTS);
+ sendEmptyMessage(MSG_APPLY_EFFECTS);
+ }
+
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
@@ -2101,6 +2166,10 @@
case MSG_RINGER_AUDIO:
boolean shouldApplyToRinger = (boolean) msg.obj;
updateRingerAndAudio(shouldApplyToRinger);
+ break;
+ case MSG_APPLY_EFFECTS:
+ applyConsolidatedDeviceEffects();
+ break;
}
}
}
diff --git a/services/core/java/com/android/server/om/OverlayManagerShellCommand.java b/services/core/java/com/android/server/om/OverlayManagerShellCommand.java
index f77d7898..d9c8ec6 100644
--- a/services/core/java/com/android/server/om/OverlayManagerShellCommand.java
+++ b/services/core/java/com/android/server/om/OverlayManagerShellCommand.java
@@ -317,11 +317,11 @@
return 1;
}
final String overlayPackageName = "com.android.shell";
- FabricatedOverlay.Builder overlayBuilder = new FabricatedOverlay.Builder(
- overlayPackageName, name, targetPackage)
- .setTargetOverlayable(targetOverlayable);
+ FabricatedOverlay overlay = new FabricatedOverlay(name, targetPackage);
+ overlay.setTargetOverlayable(targetOverlayable);
+ overlay.setOwningPackage(overlayPackageName);
if (filename != null) {
- int result = addOverlayValuesFromXml(overlayBuilder, targetPackage, filename);
+ int result = addOverlayValuesFromXml(overlay, targetPackage, filename);
if (result != 0) {
return result;
}
@@ -329,18 +329,18 @@
final String resourceName = getNextArgRequired();
final String typeStr = getNextArgRequired();
final String strData = String.join(" ", peekRemainingArgs());
- if (addOverlayValue(overlayBuilder, resourceName, typeStr, strData, config) != 0) {
+ if (addOverlayValue(overlay, resourceName, typeStr, strData, config) != 0) {
return 1;
}
}
mInterface.commit(new OverlayManagerTransaction.Builder()
- .registerFabricatedOverlay(overlayBuilder.build()).build());
+ .registerFabricatedOverlay(overlay).build());
return 0;
}
private int addOverlayValuesFromXml(
- FabricatedOverlay.Builder overlayBuilder, String targetPackage, String filename) {
+ FabricatedOverlay overlay, String targetPackage, String filename) {
final PrintWriter err = getErrPrintWriter();
File file = new File(filename);
if (!file.exists()) {
@@ -388,7 +388,7 @@
return 1;
}
String config = parser.getAttributeValue(null, "config");
- if (addOverlayValue(overlayBuilder, targetPackage + ':' + target,
+ if (addOverlayValue(overlay, targetPackage + ':' + target,
overlayType, value, config) != 0) {
return 1;
}
@@ -405,8 +405,8 @@
return 0;
}
- private int addOverlayValue(FabricatedOverlay.Builder overlayBuilder,
- String resourceName, String typeString, String valueString, String configuration) {
+ private int addOverlayValue(FabricatedOverlay overlay, String resourceName, String typeString,
+ String valueString, String configuration) {
final int type;
typeString = typeString.toLowerCase(Locale.getDefault());
if (TYPE_MAP.containsKey(typeString)) {
@@ -419,10 +419,14 @@
}
}
if (type == TypedValue.TYPE_STRING) {
- overlayBuilder.setResourceValue(resourceName, type, valueString, configuration);
+ overlay.setResourceValue(resourceName, type, valueString, configuration);
} else if (type < 0) {
ParcelFileDescriptor pfd = openFileForSystem(valueString, "r");
- overlayBuilder.setResourceValue(resourceName, pfd, configuration);
+ if (valueString.endsWith(".9.png")) {
+ overlay.setNinePatchResourceValue(resourceName, pfd, configuration);
+ } else {
+ overlay.setResourceValue(resourceName, pfd, configuration);
+ }
} else {
final int intData;
if (valueString.startsWith("0x")) {
@@ -430,7 +434,7 @@
} else {
intData = Integer.parseUnsignedInt(valueString);
}
- overlayBuilder.setResourceValue(resourceName, type, intData, configuration);
+ overlay.setResourceValue(resourceName, type, intData, configuration);
}
return 0;
}
diff --git a/services/core/java/com/android/server/pdb/TEST_MAPPING b/services/core/java/com/android/server/pdb/TEST_MAPPING
new file mode 100644
index 0000000..1aa8601
--- /dev/null
+++ b/services/core/java/com/android/server/pdb/TEST_MAPPING
@@ -0,0 +1,12 @@
+{
+ "postsubmit": [
+ {
+ "name": "FrameworksServicesTests",
+ "options": [
+ {
+ "include-filter": "com.android.server.pdb.PersistentDataBlockServiceTest"
+ }
+ ]
+ }
+ ]
+}
diff --git a/services/core/java/com/android/server/pm/ComputerEngine.java b/services/core/java/com/android/server/pm/ComputerEngine.java
index b2d4a2c..7c425b82 100644
--- a/services/core/java/com/android/server/pm/ComputerEngine.java
+++ b/services/core/java/com/android/server/pm/ComputerEngine.java
@@ -1532,7 +1532,9 @@
ai, flags, state, userId);
pi.signingInfo = ps.getSigningInfo();
pi.signatures = getDeprecatedSignatures(pi.signingInfo.getSigningDetails(), flags);
- pi.setArchiveTimeMillis(state.getArchiveTimeMillis());
+ if (state.getArchiveState() != null) {
+ pi.setArchiveTimeMillis(state.getArchiveState().getArchiveTimeMillis());
+ }
if (DEBUG_PACKAGE_INFO) {
Log.v(TAG, "ps.pkg is n/a for ["
diff --git a/services/core/java/com/android/server/pm/DeletePackageHelper.java b/services/core/java/com/android/server/pm/DeletePackageHelper.java
index 07e0ddf..80e6c83 100644
--- a/services/core/java/com/android/server/pm/DeletePackageHelper.java
+++ b/services/core/java/com/android/server/pm/DeletePackageHelper.java
@@ -21,7 +21,6 @@
import static android.content.pm.Flags.sdkLibIndependence;
import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
-import static android.content.pm.PackageManager.DELETE_ARCHIVE;
import static android.content.pm.PackageManager.DELETE_KEEP_DATA;
import static android.content.pm.PackageManager.DELETE_SUCCEEDED;
import static android.content.pm.PackageManager.MATCH_KNOWN_PACKAGES;
@@ -613,10 +612,6 @@
firstInstallTime,
PackageManager.USER_MIN_ASPECT_RATIO_UNSET,
archiveState);
-
- if ((flags & DELETE_ARCHIVE) != 0) {
- ps.modifyUserState(nextUserId).setArchiveTimeMillis(System.currentTimeMillis());
- }
}
mPm.mSettings.writeKernelMappingLPr(ps);
}
diff --git a/services/core/java/com/android/server/pm/InstallPackageHelper.java b/services/core/java/com/android/server/pm/InstallPackageHelper.java
index 3e7c8c4..8270481 100644
--- a/services/core/java/com/android/server/pm/InstallPackageHelper.java
+++ b/services/core/java/com/android/server/pm/InstallPackageHelper.java
@@ -691,7 +691,6 @@
pkgSetting.setUninstallReason(PackageManager.UNINSTALL_REASON_UNKNOWN, userId);
pkgSetting.setFirstInstallTime(System.currentTimeMillis(), userId);
// Clear any existing archive state.
- pkgSetting.setArchiveTimeMillis(0, userId);
pkgSetting.setArchiveState(null, userId);
mPm.mSettings.writePackageRestrictionsLPr(userId);
mPm.mSettings.writeKernelMappingLPr(pkgSetting);
@@ -2272,7 +2271,6 @@
}
// Clear any existing archive state.
ps.setArchiveState(null, userId);
- ps.setArchiveTimeMillis(0, userId);
} else if (allUsers != null) {
// The caller explicitly specified INSTALL_ALL_USERS flag.
// Thus, updating the settings to install the app for all users.
@@ -2297,7 +2295,6 @@
}
// Clear any existing archive state.
ps.setArchiveState(null, currentUserId);
- ps.setArchiveTimeMillis(0, currentUserId);
} else {
ps.setInstalled(false, currentUserId);
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index c0c98de..968ea66 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -1379,9 +1379,9 @@
final InstallSourceInfo installSourceInfo = snapshot.getInstallSourceInfo(packageName,
userId);
- final String initiatingPackageName = installSourceInfo.getInitiatingPackageName();
final String installerPackageName;
if (installSourceInfo != null) {
+ final String initiatingPackageName = installSourceInfo.getInitiatingPackageName();
if (!isInstalledByAdb(initiatingPackageName)) {
installerPackageName = initiatingPackageName;
} else {
diff --git a/services/core/java/com/android/server/pm/PackageSetting.java b/services/core/java/com/android/server/pm/PackageSetting.java
index 26dc576..174df44 100644
--- a/services/core/java/com/android/server/pm/PackageSetting.java
+++ b/services/core/java/com/android/server/pm/PackageSetting.java
@@ -775,11 +775,6 @@
onChanged();
}
- void setArchiveTimeMillis(long value, int userId) {
- modifyUserState(userId).setArchiveTimeMillis(value);
- onChanged();
- }
-
boolean getInstalled(int userId) {
return readUserState(userId).isInstalled();
}
diff --git a/services/core/java/com/android/server/pm/RemovePackageHelper.java b/services/core/java/com/android/server/pm/RemovePackageHelper.java
index 80f69a4..7ee32fb 100644
--- a/services/core/java/com/android/server/pm/RemovePackageHelper.java
+++ b/services/core/java/com/android/server/pm/RemovePackageHelper.java
@@ -419,9 +419,6 @@
Slog.d(TAG, " user " + userId + ": " + wasInstalled + " => " + false);
}
deletedPs.setInstalled(/* installed= */ false, userId);
- if (isArchive) {
- deletedPs.modifyUserState(userId).setArchiveTimeMillis(currentTimeMillis);
- }
}
}
// make sure to preserve per-user installed state if this removal was just
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index 107dc76..2cbf714 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -372,7 +372,6 @@
private static final String ATTR_ARCHIVE_INSTALLER_TITLE = "installer-title";
private static final String ATTR_ARCHIVE_ICON_PATH = "icon-path";
private static final String ATTR_ARCHIVE_MONOCHROME_ICON_PATH = "monochrome-icon-path";
-
private static final String ATTR_ARCHIVE_TIME = "archive-time";
private final Handler mHandler;
@@ -1933,8 +1932,6 @@
ATTR_SPLASH_SCREEN_THEME);
final long firstInstallTime = parser.getAttributeLongHex(null,
ATTR_FIRST_INSTALL_TIME, 0);
- final long archiveTime = parser.getAttributeLongHex(null,
- ATTR_ARCHIVE_TIME, 0);
final int minAspectRatio = parser.getAttributeInt(null,
ATTR_MIN_ASPECT_RATIO,
PackageManager.USER_MIN_ASPECT_RATIO_UNSET);
@@ -2022,7 +2019,6 @@
firstInstallTime != 0 ? firstInstallTime
: origFirstInstallTimes.getOrDefault(name, 0L),
minAspectRatio, archiveState);
- ps.setArchiveTimeMillis(archiveTime, userId);
mDomainVerificationManager.setLegacyUserState(name, userId, verifState);
} else if (tagName.equals("preferred-activities")) {
readPreferredActivitiesLPw(parser, userId);
@@ -2054,6 +2050,7 @@
throws XmlPullParserException, IOException {
String installerTitle = parser.getAttributeValue(null,
ATTR_ARCHIVE_INSTALLER_TITLE);
+ final long archiveTimeMillis = parser.getAttributeLongHex(null, ATTR_ARCHIVE_TIME, 0);
List<ArchiveState.ArchiveActivityInfo> activityInfos =
parseArchiveActivityInfos(parser);
@@ -2067,7 +2064,7 @@
return null;
}
- return new ArchiveState(activityInfos, installerTitle);
+ return new ArchiveState(activityInfos, installerTitle, archiveTimeMillis);
}
private static List<ArchiveState.ArchiveActivityInfo> parseArchiveActivityInfos(
@@ -2385,8 +2382,6 @@
}
serializer.attributeLongHex(null, ATTR_FIRST_INSTALL_TIME,
ustate.getFirstInstallTimeMillis());
- serializer.attributeLongHex(null, ATTR_ARCHIVE_TIME,
- ustate.getArchiveTimeMillis());
if (ustate.getUninstallReason()
!= PackageManager.UNINSTALL_REASON_UNKNOWN) {
serializer.attributeInt(null, ATTR_UNINSTALL_REASON,
@@ -2488,6 +2483,7 @@
serializer.startTag(null, TAG_ARCHIVE_STATE);
serializer.attribute(null, ATTR_ARCHIVE_INSTALLER_TITLE, archiveState.getInstallerTitle());
+ serializer.attributeLongHex(null, ATTR_ARCHIVE_TIME, archiveState.getArchiveTimeMillis());
for (ArchiveState.ArchiveActivityInfo activityInfo : archiveState.getActivityInfos()) {
serializer.startTag(null, TAG_ARCHIVE_ACTIVITY_INFO);
serializer.attribute(null, ATTR_ARCHIVE_ACTIVITY_TITLE, activityInfo.getTitle());
@@ -5293,9 +5289,11 @@
date.setTime(pus.getFirstInstallTimeMillis());
pw.println(sdf.format(date));
- pw.print(" archiveTime=");
- date.setTime(pus.getArchiveTimeMillis());
- pw.println(sdf.format(date));
+ if (pus.getArchiveState() != null) {
+ pw.print(" archiveTime=");
+ date.setTime(pus.getArchiveState().getArchiveTimeMillis());
+ pw.println(sdf.format(date));
+ }
pw.print(" uninstallReason=");
pw.println(userState.getUninstallReason());
diff --git a/services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java b/services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java
index 7910edc..d642018 100644
--- a/services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java
+++ b/services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java
@@ -152,7 +152,9 @@
info.compileSdkVersionCodename = pkg.getCompileSdkVersionCodeName();
info.firstInstallTime = firstInstallTime;
info.lastUpdateTime = lastUpdateTime;
- info.setArchiveTimeMillis(state.getArchiveTimeMillis());
+ if (state.getArchiveState() != null) {
+ info.setArchiveTimeMillis(state.getArchiveState().getArchiveTimeMillis());
+ }
if ((flags & PackageManager.GET_GIDS) != 0) {
info.gids = gids;
}
@@ -346,7 +348,7 @@
}
/**
- * Retrieve the deprecated {@link PackageInfo.signatures} field of signing certificates
+ * Retrieve the deprecated {@link PackageInfo.signatures} field of signing certificates
*/
public static Signature[] getDeprecatedSignatures(SigningDetails signingDetails, long flags) {
if ((flags & PackageManager.GET_SIGNATURES) == 0) {
diff --git a/services/core/java/com/android/server/pm/pkg/ArchiveState.java b/services/core/java/com/android/server/pm/pkg/ArchiveState.java
index 1e40d44..009bb9f 100644
--- a/services/core/java/com/android/server/pm/pkg/ArchiveState.java
+++ b/services/core/java/com/android/server/pm/pkg/ArchiveState.java
@@ -16,9 +16,10 @@
package com.android.server.pm.pkg;
-import android.content.ComponentName;
+import android.annotation.CurrentTimeMillisLong;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.content.ComponentName;
import com.android.internal.util.AnnotationValidations;
import com.android.internal.util.DataClass;
@@ -51,14 +52,45 @@
@NonNull
private final String mInstallerTitle;
- /** Information about a main activity of an archived app. */
+ /**
+ * The time at which the app was archived for the user. Units are as per
+ * {@link System#currentTimeMillis()}.
+ */
+ private final @CurrentTimeMillisLong long mArchiveTimeMillis;
+
+ /**
+ * Creates a new ArchiveState.
+ *
+ * @param activityInfos
+ * Information about main activities.
+ *
+ * <p> This list has at least one entry. In the vast majority of cases, this list has only one
+ * entry.
+ * @param installerTitle
+ * Corresponds to android:label of the installer responsible for the unarchival of the app.
+ * Stored in the installer's locale .*
+ */
+ public ArchiveState(
+ @NonNull List<ArchiveActivityInfo> activityInfos,
+ @NonNull String installerTitle) {
+ this(activityInfos, installerTitle, System.currentTimeMillis());
+ }
+
+
+ /**
+ * Information about a main activity of an archived app.
+ */
@DataClass(genEqualsHashCode = true, genToString = true)
public static class ArchiveActivityInfo {
- /** Corresponds to the activity's android:label in the app's locale. */
+ /**
+ * Corresponds to the activity's android:label in the app's locale.
+ */
@NonNull
private final String mTitle;
- /** The component name of the original activity (pre-archival). */
+ /**
+ * The component name of the original activity (pre-archival).
+ */
@NonNull
private final ComponentName mOriginalComponentName;
@@ -69,7 +101,9 @@
@Nullable
private final Path mIconBitmap;
- /** See {@link #mIconBitmap}. Only set if the app defined a monochrome icon. */
+ /**
+ * See {@link #mIconBitmap}. Only set if the app defined a monochrome icon.
+ */
@Nullable
private final Path mMonochromeIconBitmap;
@@ -93,6 +127,8 @@
*
* @param title
* Corresponds to the activity's android:label in the app's locale.
+ * @param originalComponentName
+ * The component name of the original activity (pre-archival).
* @param iconBitmap
* The path to the stored icon of the activity in the app's locale. Null if the app does
* not define any icon (default icon would be shown on the launcher).
@@ -106,9 +142,11 @@
@Nullable Path iconBitmap,
@Nullable Path monochromeIconBitmap) {
this.mTitle = title;
+ AnnotationValidations.validate(
+ NonNull.class, null, mTitle);
this.mOriginalComponentName = originalComponentName;
- AnnotationValidations.validate(NonNull.class, null, mTitle);
- AnnotationValidations.validate(NonNull.class, null, mOriginalComponentName);
+ AnnotationValidations.validate(
+ NonNull.class, null, mOriginalComponentName);
this.mIconBitmap = iconBitmap;
this.mMonochromeIconBitmap = monochromeIconBitmap;
@@ -125,7 +163,7 @@
/**
* The component name of the original activity (pre-archival).
- */
+ */
@DataClass.Generated.Member
public @NonNull ComponentName getOriginalComponentName() {
return mOriginalComponentName;
@@ -189,18 +227,17 @@
int _hash = 1;
_hash = 31 * _hash + java.util.Objects.hashCode(mTitle);
- _hash = 31* _hash + java.util.Objects.hashCode(mOriginalComponentName);
+ _hash = 31 * _hash + java.util.Objects.hashCode(mOriginalComponentName);
_hash = 31 * _hash + java.util.Objects.hashCode(mIconBitmap);
_hash = 31 * _hash + java.util.Objects.hashCode(mMonochromeIconBitmap);
return _hash;
}
@DataClass.Generated(
- time = 1693590309015L,
+ time = 1701471309832L,
codegenVersion = "1.0.23",
sourceFile = "frameworks/base/services/core/java/com/android/server/pm/pkg/ArchiveState.java",
- inputSignatures =
- "private final @android.annotation.NonNull java.lang.String mTitle\nprivate final @android.annotation.NonNull android.content.ComponentName mOriginalComponentName\nprivate final @android.annotation.Nullable java.nio.file.Path mIconBitmap\nprivate final @android.annotation.Nullable java.nio.file.Path mMonochromeIconBitmap\nclass ArchiveActivityInfo extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genEqualsHashCode=true, genToString=true)")
+ inputSignatures = "private final @android.annotation.NonNull java.lang.String mTitle\nprivate final @android.annotation.NonNull android.content.ComponentName mOriginalComponentName\nprivate final @android.annotation.Nullable java.nio.file.Path mIconBitmap\nprivate final @android.annotation.Nullable java.nio.file.Path mMonochromeIconBitmap\nclass ArchiveActivityInfo extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genEqualsHashCode=true, genToString=true)")
@Deprecated
private void __metadata() {}
@@ -238,15 +275,24 @@
* @param installerTitle
* Corresponds to android:label of the installer responsible for the unarchival of the app.
* Stored in the installer's locale .
+ * @param archiveTimeMillis
+ * The time at which the app was archived for the user. Units are as per
+ * {@link System#currentTimeMillis()}.
*/
@DataClass.Generated.Member
public ArchiveState(
@NonNull List<ArchiveActivityInfo> activityInfos,
- @NonNull String installerTitle) {
+ @NonNull String installerTitle,
+ @CurrentTimeMillisLong long archiveTimeMillis) {
this.mActivityInfos = activityInfos;
- AnnotationValidations.validate(NonNull.class, null, mActivityInfos);
+ AnnotationValidations.validate(
+ NonNull.class, null, mActivityInfos);
this.mInstallerTitle = installerTitle;
- AnnotationValidations.validate(NonNull.class, null, mInstallerTitle);
+ AnnotationValidations.validate(
+ NonNull.class, null, mInstallerTitle);
+ this.mArchiveTimeMillis = archiveTimeMillis;
+ AnnotationValidations.validate(
+ CurrentTimeMillisLong.class, null, mArchiveTimeMillis);
// onConstructed(); // You can define this method to get a callback
}
@@ -271,6 +317,15 @@
return mInstallerTitle;
}
+ /**
+ * The time at which the app was archived for the user. Units are as per
+ * {@link System#currentTimeMillis()}.
+ */
+ @DataClass.Generated.Member
+ public @CurrentTimeMillisLong long getArchiveTimeMillis() {
+ return mArchiveTimeMillis;
+ }
+
@Override
@DataClass.Generated.Member
public String toString() {
@@ -279,7 +334,8 @@
return "ArchiveState { " +
"activityInfos = " + mActivityInfos + ", " +
- "installerTitle = " + mInstallerTitle +
+ "installerTitle = " + mInstallerTitle + ", " +
+ "archiveTimeMillis = " + mArchiveTimeMillis +
" }";
}
@@ -297,7 +353,8 @@
//noinspection PointlessBooleanExpression
return true
&& java.util.Objects.equals(mActivityInfos, that.mActivityInfos)
- && java.util.Objects.equals(mInstallerTitle, that.mInstallerTitle);
+ && java.util.Objects.equals(mInstallerTitle, that.mInstallerTitle)
+ && mArchiveTimeMillis == that.mArchiveTimeMillis;
}
@Override
@@ -309,14 +366,15 @@
int _hash = 1;
_hash = 31 * _hash + java.util.Objects.hashCode(mActivityInfos);
_hash = 31 * _hash + java.util.Objects.hashCode(mInstallerTitle);
+ _hash = 31 * _hash + Long.hashCode(mArchiveTimeMillis);
return _hash;
}
@DataClass.Generated(
- time = 1693590309027L,
+ time = 1701471309853L,
codegenVersion = "1.0.23",
sourceFile = "frameworks/base/services/core/java/com/android/server/pm/pkg/ArchiveState.java",
- inputSignatures = "private final @android.annotation.NonNull java.util.List<com.android.server.pm.pkg.ArchiveActivityInfo> mActivityInfos\nprivate final @android.annotation.NonNull java.lang.String mInstallerTitle\nclass ArchiveState extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genEqualsHashCode=true, genToString=true)")
+ inputSignatures = "private final @android.annotation.NonNull java.util.List<com.android.server.pm.pkg.ArchiveActivityInfo> mActivityInfos\nprivate final @android.annotation.NonNull java.lang.String mInstallerTitle\nprivate final @android.annotation.CurrentTimeMillisLong long mArchiveTimeMillis\nclass ArchiveState extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genEqualsHashCode=true, genToString=true)")
@Deprecated
private void __metadata() {}
diff --git a/services/core/java/com/android/server/pm/pkg/PackageUserState.java b/services/core/java/com/android/server/pm/pkg/PackageUserState.java
index 8eb3466..2a81a86 100644
--- a/services/core/java/com/android/server/pm/pkg/PackageUserState.java
+++ b/services/core/java/com/android/server/pm/pkg/PackageUserState.java
@@ -256,10 +256,4 @@
* @hide
*/
boolean dataExists();
-
- /**
- * Timestamp of when the app is archived on the user.
- * @hide
- */
- long getArchiveTimeMillis();
}
diff --git a/services/core/java/com/android/server/pm/pkg/PackageUserStateDefault.java b/services/core/java/com/android/server/pm/pkg/PackageUserStateDefault.java
index defd343..2f4ad2d8 100644
--- a/services/core/java/com/android/server/pm/pkg/PackageUserStateDefault.java
+++ b/services/core/java/com/android/server/pm/pkg/PackageUserStateDefault.java
@@ -206,9 +206,4 @@
public boolean dataExists() {
return true;
}
-
- @Override
- public long getArchiveTimeMillis() {
- return 0;
- }
}
diff --git a/services/core/java/com/android/server/pm/pkg/PackageUserStateImpl.java b/services/core/java/com/android/server/pm/pkg/PackageUserStateImpl.java
index c0ea7cc..c5ef525 100644
--- a/services/core/java/com/android/server/pm/pkg/PackageUserStateImpl.java
+++ b/services/core/java/com/android/server/pm/pkg/PackageUserStateImpl.java
@@ -135,8 +135,6 @@
@Nullable
private ArchiveState mArchiveState;
- private @CurrentTimeMillisLong long mArchiveTimeMillis;
-
@NonNull
final SnapshotCache<PackageUserStateImpl> mSnapshot;
@@ -189,7 +187,6 @@
? null : other.mComponentLabelIconOverrideMap.snapshot();
mFirstInstallTimeMillis = other.mFirstInstallTimeMillis;
mArchiveState = other.mArchiveState;
- mArchiveTimeMillis = other.mArchiveTimeMillis;
mSnapshot = new SnapshotCache.Sealed<>();
}
@@ -613,16 +610,6 @@
return this;
}
- /**
- * Sets the timestamp when the app is archived on this user.
- */
- @NonNull
- public PackageUserStateImpl setArchiveTimeMillis(@CurrentTimeMillisLong long value) {
- mArchiveTimeMillis = value;
- onChanged();
- return this;
- }
-
@NonNull
@Override
public Map<String, OverlayPaths> getSharedLibraryOverlayPaths() {
@@ -811,11 +798,6 @@
}
@DataClass.Generated.Member
- public @CurrentTimeMillisLong long getArchiveTimeMillis() {
- return mArchiveTimeMillis;
- }
-
- @DataClass.Generated.Member
public @NonNull SnapshotCache<PackageUserStateImpl> getSnapshot() {
return mSnapshot;
}
@@ -892,7 +874,6 @@
&& mFirstInstallTimeMillis == that.mFirstInstallTimeMillis
&& watchableEquals(that.mWatchable)
&& Objects.equals(mArchiveState, that.mArchiveState)
- && mArchiveTimeMillis == that.mArchiveTimeMillis
&& snapshotEquals(that.mSnapshot);
}
@@ -923,16 +904,15 @@
_hash = 31 * _hash + Long.hashCode(mFirstInstallTimeMillis);
_hash = 31 * _hash + watchableHashCode();
_hash = 31 * _hash + Objects.hashCode(mArchiveState);
- _hash = 31 * _hash + Long.hashCode(mArchiveTimeMillis);
_hash = 31 * _hash + snapshotHashCode();
return _hash;
}
@DataClass.Generated(
- time = 1699917927942L,
+ time = 1701470095849L,
codegenVersion = "1.0.23",
sourceFile = "frameworks/base/services/core/java/com/android/server/pm/pkg/PackageUserStateImpl.java",
- inputSignatures = "private int mBooleans\nprotected @android.annotation.Nullable com.android.server.utils.WatchedArraySet<java.lang.String> mDisabledComponentsWatched\nprotected @android.annotation.Nullable com.android.server.utils.WatchedArraySet<java.lang.String> mEnabledComponentsWatched\nprivate long mCeDataInode\nprivate long mDeDataInode\nprivate int mDistractionFlags\nprivate @android.content.pm.PackageManager.EnabledState int mEnabledState\nprivate @android.content.pm.PackageManager.InstallReason int mInstallReason\nprivate @android.content.pm.PackageManager.UninstallReason int mUninstallReason\nprivate @android.annotation.Nullable java.lang.String mHarmfulAppWarning\nprivate @android.annotation.Nullable java.lang.String mLastDisableAppCaller\nprivate @android.annotation.Nullable android.content.pm.overlay.OverlayPaths mOverlayPaths\nprotected @android.annotation.Nullable com.android.server.utils.WatchedArrayMap<java.lang.String,android.content.pm.overlay.OverlayPaths> mSharedLibraryOverlayPaths\nprivate @android.annotation.Nullable java.lang.String mSplashScreenTheme\nprivate @android.content.pm.PackageManager.UserMinAspectRatio int mMinAspectRatio\nprivate @android.annotation.Nullable com.android.server.utils.WatchedArrayMap<java.lang.String,com.android.server.pm.pkg.SuspendParams> mSuspendParams\nprivate @android.annotation.Nullable com.android.server.utils.WatchedArrayMap<android.content.ComponentName,android.util.Pair<java.lang.String,java.lang.Integer>> mComponentLabelIconOverrideMap\nprivate @android.annotation.CurrentTimeMillisLong long mFirstInstallTimeMillis\nprivate @android.annotation.Nullable com.android.server.utils.Watchable mWatchable\nprivate @android.annotation.Nullable com.android.server.pm.pkg.ArchiveState mArchiveState\nprivate @android.annotation.CurrentTimeMillisLong long mArchiveTimeMillis\nfinal @android.annotation.NonNull com.android.server.utils.SnapshotCache<com.android.server.pm.pkg.PackageUserStateImpl> mSnapshot\nprivate void setBoolean(int,boolean)\nprivate boolean getBoolean(int)\nprivate com.android.server.utils.SnapshotCache<com.android.server.pm.pkg.PackageUserStateImpl> makeCache()\nprivate void onChanged()\npublic @android.annotation.NonNull @java.lang.Override com.android.server.pm.pkg.PackageUserStateImpl snapshot()\npublic @android.annotation.Nullable boolean setOverlayPaths(android.content.pm.overlay.OverlayPaths)\npublic boolean setSharedLibraryOverlayPaths(java.lang.String,android.content.pm.overlay.OverlayPaths)\npublic @android.annotation.Nullable @java.lang.Override com.android.server.utils.WatchedArraySet<java.lang.String> getDisabledComponentsNoCopy()\npublic @android.annotation.Nullable @java.lang.Override com.android.server.utils.WatchedArraySet<java.lang.String> getEnabledComponentsNoCopy()\npublic @android.annotation.NonNull @java.lang.Override android.util.ArraySet<java.lang.String> getDisabledComponents()\npublic @android.annotation.NonNull @java.lang.Override android.util.ArraySet<java.lang.String> getEnabledComponents()\npublic @java.lang.Override boolean isComponentEnabled(java.lang.String)\npublic @java.lang.Override boolean isComponentDisabled(java.lang.String)\npublic @java.lang.Override android.content.pm.overlay.OverlayPaths getAllOverlayPaths()\npublic @com.android.internal.annotations.VisibleForTesting boolean overrideLabelAndIcon(android.content.ComponentName,java.lang.String,java.lang.Integer)\npublic void resetOverrideComponentLabelIcon()\npublic @android.annotation.Nullable android.util.Pair<java.lang.String,java.lang.Integer> getOverrideLabelIconForComponent(android.content.ComponentName)\npublic @java.lang.Override boolean isSuspended()\npublic com.android.server.pm.pkg.PackageUserStateImpl putSuspendParams(java.lang.String,com.android.server.pm.pkg.SuspendParams)\npublic com.android.server.pm.pkg.PackageUserStateImpl removeSuspension(java.lang.String)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setDisabledComponents(android.util.ArraySet<java.lang.String>)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setEnabledComponents(android.util.ArraySet<java.lang.String>)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setEnabledComponents(com.android.server.utils.WatchedArraySet<java.lang.String>)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setDisabledComponents(com.android.server.utils.WatchedArraySet<java.lang.String>)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setCeDataInode(long)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setDeDataInode(long)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setInstalled(boolean)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setStopped(boolean)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setNotLaunched(boolean)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setHidden(boolean)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setDistractionFlags(int)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setInstantApp(boolean)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setVirtualPreload(boolean)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setEnabledState(int)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setInstallReason(int)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setUninstallReason(int)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setHarmfulAppWarning(java.lang.String)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setLastDisableAppCaller(java.lang.String)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setSharedLibraryOverlayPaths(android.util.ArrayMap<java.lang.String,android.content.pm.overlay.OverlayPaths>)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setSplashScreenTheme(java.lang.String)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setMinAspectRatio(int)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setSuspendParams(android.util.ArrayMap<java.lang.String,com.android.server.pm.pkg.SuspendParams>)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setComponentLabelIconOverrideMap(android.util.ArrayMap<android.content.ComponentName,android.util.Pair<java.lang.String,java.lang.Integer>>)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setFirstInstallTimeMillis(long)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setArchiveState(com.android.server.pm.pkg.ArchiveState)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setArchiveTimeMillis(long)\npublic @android.annotation.NonNull @java.lang.Override java.util.Map<java.lang.String,android.content.pm.overlay.OverlayPaths> getSharedLibraryOverlayPaths()\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setWatchable(com.android.server.utils.Watchable)\nprivate boolean watchableEquals(com.android.server.utils.Watchable)\nprivate int watchableHashCode()\nprivate boolean snapshotEquals(com.android.server.utils.SnapshotCache<com.android.server.pm.pkg.PackageUserStateImpl>)\nprivate int snapshotHashCode()\npublic @java.lang.Override boolean isInstalled()\npublic @java.lang.Override boolean isStopped()\npublic @java.lang.Override boolean isNotLaunched()\npublic @java.lang.Override boolean isHidden()\npublic @java.lang.Override boolean isInstantApp()\npublic @java.lang.Override boolean isVirtualPreload()\npublic @java.lang.Override boolean isQuarantined()\npublic @java.lang.Override boolean dataExists()\nclass PackageUserStateImpl extends com.android.server.utils.WatchableImpl implements [com.android.server.pm.pkg.PackageUserStateInternal, com.android.server.utils.Snappable]\nprivate static final int INSTALLED\nprivate static final int STOPPED\nprivate static final int NOT_LAUNCHED\nprivate static final int HIDDEN\nprivate static final int INSTANT_APP\nprivate static final int VIRTUAL_PRELOADED\nclass Booleans extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genConstructor=false, genBuilder=false, genEqualsHashCode=true)")
+ inputSignatures = "private int mBooleans\nprotected @android.annotation.Nullable com.android.server.utils.WatchedArraySet<java.lang.String> mDisabledComponentsWatched\nprotected @android.annotation.Nullable com.android.server.utils.WatchedArraySet<java.lang.String> mEnabledComponentsWatched\nprivate long mCeDataInode\nprivate long mDeDataInode\nprivate int mDistractionFlags\nprivate @android.content.pm.PackageManager.EnabledState int mEnabledState\nprivate @android.content.pm.PackageManager.InstallReason int mInstallReason\nprivate @android.content.pm.PackageManager.UninstallReason int mUninstallReason\nprivate @android.annotation.Nullable java.lang.String mHarmfulAppWarning\nprivate @android.annotation.Nullable java.lang.String mLastDisableAppCaller\nprivate @android.annotation.Nullable android.content.pm.overlay.OverlayPaths mOverlayPaths\nprotected @android.annotation.Nullable com.android.server.utils.WatchedArrayMap<java.lang.String,android.content.pm.overlay.OverlayPaths> mSharedLibraryOverlayPaths\nprivate @android.annotation.Nullable java.lang.String mSplashScreenTheme\nprivate @android.content.pm.PackageManager.UserMinAspectRatio int mMinAspectRatio\nprivate @android.annotation.Nullable com.android.server.utils.WatchedArrayMap<java.lang.String,com.android.server.pm.pkg.SuspendParams> mSuspendParams\nprivate @android.annotation.Nullable com.android.server.utils.WatchedArrayMap<android.content.ComponentName,android.util.Pair<java.lang.String,java.lang.Integer>> mComponentLabelIconOverrideMap\nprivate @android.annotation.CurrentTimeMillisLong long mFirstInstallTimeMillis\nprivate @android.annotation.Nullable com.android.server.utils.Watchable mWatchable\nprivate @android.annotation.Nullable com.android.server.pm.pkg.ArchiveState mArchiveState\nfinal @android.annotation.NonNull com.android.server.utils.SnapshotCache<com.android.server.pm.pkg.PackageUserStateImpl> mSnapshot\nprivate void setBoolean(int,boolean)\nprivate boolean getBoolean(int)\nprivate com.android.server.utils.SnapshotCache<com.android.server.pm.pkg.PackageUserStateImpl> makeCache()\nprivate void onChanged()\npublic @android.annotation.NonNull @java.lang.Override com.android.server.pm.pkg.PackageUserStateImpl snapshot()\npublic @android.annotation.Nullable boolean setOverlayPaths(android.content.pm.overlay.OverlayPaths)\npublic boolean setSharedLibraryOverlayPaths(java.lang.String,android.content.pm.overlay.OverlayPaths)\npublic @android.annotation.Nullable @java.lang.Override com.android.server.utils.WatchedArraySet<java.lang.String> getDisabledComponentsNoCopy()\npublic @android.annotation.Nullable @java.lang.Override com.android.server.utils.WatchedArraySet<java.lang.String> getEnabledComponentsNoCopy()\npublic @android.annotation.NonNull @java.lang.Override android.util.ArraySet<java.lang.String> getDisabledComponents()\npublic @android.annotation.NonNull @java.lang.Override android.util.ArraySet<java.lang.String> getEnabledComponents()\npublic @java.lang.Override boolean isComponentEnabled(java.lang.String)\npublic @java.lang.Override boolean isComponentDisabled(java.lang.String)\npublic @java.lang.Override android.content.pm.overlay.OverlayPaths getAllOverlayPaths()\npublic @com.android.internal.annotations.VisibleForTesting boolean overrideLabelAndIcon(android.content.ComponentName,java.lang.String,java.lang.Integer)\npublic void resetOverrideComponentLabelIcon()\npublic @android.annotation.Nullable android.util.Pair<java.lang.String,java.lang.Integer> getOverrideLabelIconForComponent(android.content.ComponentName)\npublic @java.lang.Override boolean isSuspended()\npublic com.android.server.pm.pkg.PackageUserStateImpl putSuspendParams(java.lang.String,com.android.server.pm.pkg.SuspendParams)\npublic com.android.server.pm.pkg.PackageUserStateImpl removeSuspension(java.lang.String)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setDisabledComponents(android.util.ArraySet<java.lang.String>)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setEnabledComponents(android.util.ArraySet<java.lang.String>)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setEnabledComponents(com.android.server.utils.WatchedArraySet<java.lang.String>)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setDisabledComponents(com.android.server.utils.WatchedArraySet<java.lang.String>)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setCeDataInode(long)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setDeDataInode(long)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setInstalled(boolean)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setStopped(boolean)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setNotLaunched(boolean)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setHidden(boolean)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setDistractionFlags(int)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setInstantApp(boolean)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setVirtualPreload(boolean)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setEnabledState(int)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setInstallReason(int)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setUninstallReason(int)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setHarmfulAppWarning(java.lang.String)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setLastDisableAppCaller(java.lang.String)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setSharedLibraryOverlayPaths(android.util.ArrayMap<java.lang.String,android.content.pm.overlay.OverlayPaths>)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setSplashScreenTheme(java.lang.String)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setMinAspectRatio(int)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setSuspendParams(android.util.ArrayMap<java.lang.String,com.android.server.pm.pkg.SuspendParams>)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setComponentLabelIconOverrideMap(android.util.ArrayMap<android.content.ComponentName,android.util.Pair<java.lang.String,java.lang.Integer>>)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setFirstInstallTimeMillis(long)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setArchiveState(com.android.server.pm.pkg.ArchiveState)\npublic @android.annotation.NonNull @java.lang.Override java.util.Map<java.lang.String,android.content.pm.overlay.OverlayPaths> getSharedLibraryOverlayPaths()\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setWatchable(com.android.server.utils.Watchable)\nprivate boolean watchableEquals(com.android.server.utils.Watchable)\nprivate int watchableHashCode()\nprivate boolean snapshotEquals(com.android.server.utils.SnapshotCache<com.android.server.pm.pkg.PackageUserStateImpl>)\nprivate int snapshotHashCode()\npublic @java.lang.Override boolean isInstalled()\npublic @java.lang.Override boolean isStopped()\npublic @java.lang.Override boolean isNotLaunched()\npublic @java.lang.Override boolean isHidden()\npublic @java.lang.Override boolean isInstantApp()\npublic @java.lang.Override boolean isVirtualPreload()\npublic @java.lang.Override boolean isQuarantined()\npublic @java.lang.Override boolean dataExists()\nclass PackageUserStateImpl extends com.android.server.utils.WatchableImpl implements [com.android.server.pm.pkg.PackageUserStateInternal, com.android.server.utils.Snappable]\nprivate static final int INSTALLED\nprivate static final int STOPPED\nprivate static final int NOT_LAUNCHED\nprivate static final int HIDDEN\nprivate static final int INSTANT_APP\nprivate static final int VIRTUAL_PRELOADED\nclass Booleans extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genConstructor=false, genBuilder=false, genEqualsHashCode=true)")
@Deprecated
private void __metadata() {}
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 30bce2f4..4e5dc1d 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -17,11 +17,13 @@
package com.android.server.policy;
import static android.Manifest.permission.INTERNAL_SYSTEM_WINDOW;
+import static android.Manifest.permission.OVERRIDE_SYSTEM_KEY_BEHAVIOR_IN_FOCUSED_WINDOW;
import static android.Manifest.permission.SYSTEM_ALERT_WINDOW;
import static android.Manifest.permission.SYSTEM_APPLICATION_OVERLAY;
import static android.app.AppOpsManager.OP_CREATE_ACCESSIBILITY_OVERLAY;
import static android.app.AppOpsManager.OP_SYSTEM_ALERT_WINDOW;
import static android.app.AppOpsManager.OP_TOAST_WINDOW;
+import static android.content.PermissionChecker.PID_UNKNOWN;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE;
@@ -117,6 +119,7 @@
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.content.PermissionChecker;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
@@ -690,6 +693,8 @@
private final com.android.internal.policy.LogDecelerateInterpolator mLogDecelerateInterpolator
= new LogDecelerateInterpolator(100, 0);
+ private final DeferredKeyActionExecutor mDeferredKeyActionExecutor =
+ new DeferredKeyActionExecutor();
private volatile int mTopFocusedDisplayId = INVALID_DISPLAY;
@@ -698,6 +703,7 @@
private KeyCombinationManager mKeyCombinationManager;
private SingleKeyGestureDetector mSingleKeyGestureDetector;
private GestureLauncherService mGestureLauncherService;
+ private ButtonOverridePermissionChecker mButtonOverridePermissionChecker;
private boolean mLockNowPending = false;
@@ -725,6 +731,7 @@
private static final int MSG_RINGER_TOGGLE_CHORD = 24;
private static final int MSG_SWITCH_KEYBOARD_LAYOUT = 25;
private static final int MSG_LOG_KEYBOARD_SYSTEM_EVENT = 26;
+ private static final int MSG_SET_DEFERRED_KEY_ACTIONS_EXECUTABLE = 27;
private class PolicyHandler extends Handler {
@@ -792,7 +799,9 @@
mAutofillManagerInternal.onBackKeyPressed();
break;
case MSG_SYSTEM_KEY_PRESS:
- sendSystemKeyToStatusBar((KeyEvent) msg.obj);
+ KeyEvent event = (KeyEvent) msg.obj;
+ sendSystemKeyToStatusBar(event);
+ event.recycle();
break;
case MSG_HANDLE_ALL_APPS:
launchAllAppsAction();
@@ -809,6 +818,11 @@
case MSG_LOG_KEYBOARD_SYSTEM_EVENT:
handleKeyboardSystemEvent(KeyboardLogEvent.from(msg.arg1), (KeyEvent) msg.obj);
break;
+ case MSG_SET_DEFERRED_KEY_ACTIONS_EXECUTABLE:
+ final int keyCode = msg.arg1;
+ final long downTime = (Long) msg.obj;
+ mDeferredKeyActionExecutor.setActionsExecutable(keyCode, downTime);
+ break;
}
}
}
@@ -2234,6 +2248,10 @@
IActivityManager getActivityManagerService() {
return ActivityManager.getService();
}
+
+ ButtonOverridePermissionChecker getButtonOverridePermissionChecker() {
+ return new ButtonOverridePermissionChecker();
+ }
}
/** {@inheritDoc} */
@@ -2499,6 +2517,7 @@
mKeyguardDelegate = injector.getKeyguardServiceDelegate();
initKeyCombinationRules();
initSingleKeyGestureRules(injector.getLooper());
+ mButtonOverridePermissionChecker = injector.getButtonOverridePermissionChecker();
mSideFpsEventHandler = new SideFpsEventHandler(mContext, mHandler, mPowerManager);
}
@@ -2768,17 +2787,33 @@
if (mShouldEarlyShortPressOnStemPrimary) {
return;
}
- stemPrimaryPress(1 /*count*/);
+ // Short-press should be triggered only if app doesn't handle it.
+ mDeferredKeyActionExecutor.queueKeyAction(
+ KeyEvent.KEYCODE_STEM_PRIMARY, downTime, () -> stemPrimaryPress(1 /*count*/));
}
@Override
void onLongPress(long eventTime) {
- stemPrimaryLongPress(eventTime);
+ // Long-press should be triggered only if app doesn't handle it.
+ mDeferredKeyActionExecutor.queueKeyAction(
+ KeyEvent.KEYCODE_STEM_PRIMARY,
+ eventTime,
+ () -> stemPrimaryLongPress(eventTime));
}
@Override
void onMultiPress(long downTime, int count, int unusedDisplayId) {
- stemPrimaryPress(count);
+ // Triple-press stem to toggle accessibility gesture should always be triggered
+ // regardless of if app handles it.
+ if (count == 3
+ && mTriplePressOnStemPrimaryBehavior
+ == TRIPLE_PRESS_PRIMARY_TOGGLE_ACCESSIBILITY) {
+ stemPrimaryPress(count);
+ } else {
+ // Other multi-press gestures should be triggered only if app doesn't handle it.
+ mDeferredKeyActionExecutor.queueKeyAction(
+ KeyEvent.KEYCODE_STEM_PRIMARY, downTime, () -> stemPrimaryPress(count));
+ }
}
@Override
@@ -2792,7 +2827,9 @@
mBackgroundRecentTaskInfoOnStemPrimarySingleKeyUp =
mActivityTaskManagerInternal.getMostRecentTaskFromBackground();
if (mShouldEarlyShortPressOnStemPrimary) {
- stemPrimaryPress(1 /*pressCount*/);
+ // Key-up gesture should be triggered only if app doesn't handle it.
+ mDeferredKeyActionExecutor.queueKeyAction(
+ KeyEvent.KEYCODE_STEM_PRIMARY, eventTime, () -> stemPrimaryPress(1));
}
}
}
@@ -3750,6 +3787,15 @@
return true;
}
break;
+ case KeyEvent.KEYCODE_STEM_PRIMARY:
+ if (prepareToSendSystemKeyToApplication(focusedToken, event)) {
+ // Send to app.
+ return false;
+ } else {
+ // Intercepted.
+ sendSystemKeyToStatusBarAsync(event);
+ return true;
+ }
}
if (isValidGlobalKey(keyCode)
&& mGlobalKeyManager.handleGlobalKey(mContext, keyCode, event)) {
@@ -3760,6 +3806,60 @@
return (metaState & KeyEvent.META_META_ON) != 0;
}
+ /**
+ * In this function, we check whether a system key should be sent to the application. We also
+ * detect the key gesture on this key, even if the key will be sent to the app. The gesture
+ * action, if any, will not be executed immediately. It will be queued and execute only after
+ * the application tells us that it didn't handle this key.
+ *
+ * @return true if this key should be sent to the application. This also means that the target
+ * application has the necessary permissions to receive this key. Return false otherwise.
+ */
+ private boolean prepareToSendSystemKeyToApplication(IBinder focusedToken, KeyEvent event) {
+ final int keyCode = event.getKeyCode();
+ if (!event.isSystem()) {
+ Log.wtf(
+ TAG,
+ "Illegal keycode provided to prepareToSendSystemKeyToApplication: "
+ + KeyEvent.keyCodeToString(keyCode));
+ return false;
+ }
+ final boolean isDown = event.getAction() == KeyEvent.ACTION_DOWN;
+ if (isDown && event.getRepeatCount() == 0) {
+ // This happens at the initial DOWN event. Check focused window permission now.
+ final KeyInterceptionInfo info =
+ mWindowManagerInternal.getKeyInterceptionInfoFromToken(focusedToken);
+ if (info != null
+ && mButtonOverridePermissionChecker.canAppOverrideSystemKey(
+ mContext, info.windowOwnerUid)) {
+ // Focused window has the permission. Pass the event to it.
+ return true;
+ } else {
+ // Focused window doesn't have the permission. Intercept the event.
+ // If the initial DOWN event is intercepted, follow-up events will be intercepted
+ // too. So we know the gesture won't be handled by app, and can handle the gesture
+ // in system.
+ setDeferredKeyActionsExecutableAsync(keyCode, event.getDownTime());
+ return false;
+ }
+ } else {
+ // This happens after the initial DOWN event. We will just reuse the initial decision.
+ // I.e., if the initial DOWN event was dispatched, follow-up events should be
+ // dispatched. Otherwise, follow-up events should be consumed.
+ final Set<Integer> consumedKeys = mConsumedKeysForDevice.get(event.getDeviceId());
+ final boolean wasConsumed = consumedKeys != null && consumedKeys.contains(keyCode);
+ return !wasConsumed;
+ }
+ }
+
+ private void setDeferredKeyActionsExecutableAsync(int keyCode, long downTime) {
+ Message msg = Message.obtain(mHandler, MSG_SET_DEFERRED_KEY_ACTIONS_EXECUTABLE);
+ msg.arg1 = keyCode;
+ msg.obj = downTime;
+ msg.setAsynchronous(true);
+ msg.sendToTarget();
+ }
+
@SuppressLint("MissingPermission")
private void injectBackGesture(long downtime) {
// Create and inject down event
@@ -3977,11 +4077,34 @@
mContext.closeSystemDialogs();
}
return true;
+ case KeyEvent.KEYCODE_STEM_PRIMARY:
+ handleUnhandledSystemKey(event);
+ sendSystemKeyToStatusBarAsync(event);
+ return true;
}
return false;
}
+ /**
+ * Called when a system key was sent to application and was unhandled. We will execute any
+ * queued actions associated with this key code at this point.
+ */
+ private void handleUnhandledSystemKey(KeyEvent event) {
+ if (!event.isSystem()) {
+ Log.wtf(
+ TAG,
+ "Illegal keycode provided to handleUnhandledSystemKey: "
+ + KeyEvent.keyCodeToString(event.getKeyCode()));
+ return;
+ }
+ if (event.getAction() == KeyEvent.ACTION_DOWN && event.getRepeatCount() == 0) {
+ // If the initial DOWN event is unhandled by app, follow-up events will also be
+ // unhandled by app. So we can handle the key event in system.
+ setDeferredKeyActionsExecutableAsync(event.getKeyCode(), event.getDownTime());
+ }
+ }
+
private void sendSwitchKeyboardLayout(@NonNull KeyEvent event, int direction) {
mHandler.obtainMessage(MSG_SWITCH_KEYBOARD_LAYOUT, event.getDeviceId(),
direction).sendToTarget();
@@ -4904,9 +5027,6 @@
case KeyEvent.KEYCODE_MACRO_4:
result &= ~ACTION_PASS_TO_USER;
break;
- case KeyEvent.KEYCODE_STEM_PRIMARY:
- sendSystemKeyToStatusBarAsync(event);
- break;
}
if (useHapticFeedback) {
@@ -5016,7 +5136,8 @@
* Notify the StatusBar that a system key was pressed without blocking the current thread.
*/
private void sendSystemKeyToStatusBarAsync(KeyEvent keyEvent) {
- Message message = mHandler.obtainMessage(MSG_SYSTEM_KEY_PRESS, keyEvent);
+ // Make a copy because the event may be recycled.
+ Message message = mHandler.obtainMessage(MSG_SYSTEM_KEY_PRESS, KeyEvent.obtain(keyEvent));
message.setAsynchronous(true);
mHandler.sendMessage(message);
}
@@ -6468,6 +6589,7 @@
mGlobalKeyManager.dump(prefix, pw);
mKeyCombinationManager.dump(prefix, pw);
mSingleKeyGestureDetector.dump(prefix, pw);
+ mDeferredKeyActionExecutor.dump(prefix, pw);
if (mWakeGestureListener != null) {
mWakeGestureListener.dump(pw, prefix);
@@ -6793,4 +6915,19 @@
+ " name.");
}
}
+
+ /** A helper class to check button override permission. */
+ static class ButtonOverridePermissionChecker {
+ boolean canAppOverrideSystemKey(Context context, int uid) {
+ return PermissionChecker.checkPermissionForDataDelivery(
+ context,
+ OVERRIDE_SYSTEM_KEY_BEHAVIOR_IN_FOCUSED_WINDOW,
+ PID_UNKNOWN,
+ uid,
+ null,
+ null,
+ null)
+ == PERMISSION_GRANTED;
+ }
+ }
}
diff --git a/services/core/java/com/android/server/utils/Android.bp b/services/core/java/com/android/server/utils/Android.bp
new file mode 100644
index 0000000..3a334be
--- /dev/null
+++ b/services/core/java/com/android/server/utils/Android.bp
@@ -0,0 +1,10 @@
+aconfig_declarations {
+ name: "com.android.server.utils-aconfig",
+ package: "com.android.server.utils",
+ srcs: ["*.aconfig"],
+}
+
+java_aconfig_library {
+ name: "com.android.server.utils_aconfig-java",
+ aconfig_declarations: "com.android.server.utils-aconfig",
+}
diff --git a/services/core/java/com/android/server/am/AnrTimer.java b/services/core/java/com/android/server/utils/AnrTimer.java
similarity index 98%
rename from services/core/java/com/android/server/am/AnrTimer.java
rename to services/core/java/com/android/server/utils/AnrTimer.java
index 3e17930..2b6dffb 100644
--- a/services/core/java/com/android/server/am/AnrTimer.java
+++ b/services/core/java/com/android/server/utils/AnrTimer.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.server.am;
+package com.android.server.utils;
import static android.text.TextUtils.formatSimple;
@@ -77,7 +77,7 @@
*
* @hide
*/
-class AnrTimer<V> {
+public class AnrTimer<V> {
/**
* The log tag.
@@ -568,7 +568,7 @@
* @param label A name for this instance.
* @param extend A flag to indicate if expired timers can be granted extensions.
*/
- AnrTimer(@NonNull Handler handler, int what, @NonNull String label, boolean extend) {
+ public AnrTimer(@NonNull Handler handler, int what, @NonNull String label, boolean extend) {
this(handler, what, label, extend, new Injector(handler));
}
@@ -580,7 +580,7 @@
* @param what The "what" parameter for the expiration message.
* @param label A name for this instance.
*/
- AnrTimer(@NonNull Handler handler, int what, @NonNull String label) {
+ public AnrTimer(@NonNull Handler handler, int what, @NonNull String label) {
this(handler, what, label, false);
}
@@ -591,7 +591,7 @@
*
* @return true if the service is flag-enabled.
*/
- boolean serviceEnabled() {
+ public boolean serviceEnabled() {
return mFeature.enabled();
}
@@ -856,7 +856,7 @@
* @param timeoutMs The timer timeout, in milliseconds.
* @return true if the timer was successfully created.
*/
- boolean start(@NonNull V arg, int pid, int uid, long timeoutMs) {
+ public boolean start(@NonNull V arg, int pid, int uid, long timeoutMs) {
return mFeature.start(arg, pid, uid, timeoutMs);
}
@@ -867,7 +867,7 @@
*
* @return true if the timer was found and was running.
*/
- boolean cancel(@NonNull V arg) {
+ public boolean cancel(@NonNull V arg) {
return mFeature.cancel(arg);
}
@@ -878,7 +878,7 @@
*
* @return true if the timer was found and was expired.
*/
- boolean accept(@NonNull V arg) {
+ public boolean accept(@NonNull V arg) {
return mFeature.accept(arg);
}
@@ -892,7 +892,7 @@
*
* @return true if the timer was found and was expired.
*/
- boolean discard(@NonNull V arg) {
+ public boolean discard(@NonNull V arg) {
return mFeature.discard(arg);
}
@@ -1010,7 +1010,7 @@
/**
* Dumpsys output.
*/
- static void dump(@NonNull PrintWriter pw, boolean verbose) {
+ public static void dump(@NonNull PrintWriter pw, boolean verbose) {
final IndentingPrintWriter ipw = new IndentingPrintWriter(pw);
ipw.println("AnrTimer statistics");
ipw.increaseIndent();
diff --git a/services/core/java/com/android/server/utils/flags.aconfig b/services/core/java/com/android/server/utils/flags.aconfig
new file mode 100644
index 0000000..489e21a
--- /dev/null
+++ b/services/core/java/com/android/server/utils/flags.aconfig
@@ -0,0 +1,9 @@
+package: "com.android.server.utils"
+
+flag {
+ name: "anr_timer_service_enabled"
+ namespace: "system_performance"
+ is_fixed_read_only: true
+ description: "Feature flag for the ANR timer service"
+ bug: "282428924"
+}
diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
index e088d9a..1485b96 100644
--- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
+++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
@@ -40,6 +40,7 @@
import static com.android.server.wallpaper.WallpaperUtils.WALLPAPER_LOCK_ORIG;
import static com.android.server.wallpaper.WallpaperUtils.getWallpaperDir;
import static com.android.server.wallpaper.WallpaperUtils.makeWallpaperIdLocked;
+import static com.android.window.flags.Flags.multiCrop;
import android.annotation.NonNull;
import android.app.ActivityManager;
@@ -93,7 +94,6 @@
import android.os.SELinux;
import android.os.ShellCallback;
import android.os.SystemClock;
-import android.os.SystemProperties;
import android.os.UserHandle;
import android.os.UserManager;
import android.os.storage.StorageManager;
@@ -1516,8 +1516,7 @@
mColorsChangedListeners = new SparseArray<>();
mWallpaperDataParser = new WallpaperDataParser(mContext, mWallpaperDisplayHelper,
mWallpaperCropper);
- mIsMultiCropEnabled =
- SystemProperties.getBoolean("persist.wm.debug.wallpaper_multi_crop", false);
+ mIsMultiCropEnabled = multiCrop();
LocalServices.addService(WallpaperManagerInternal.class, new LocalService());
}
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index b8b102f..91f45a7 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -76,6 +76,7 @@
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_IMMERSIVE;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_LOCKTASK;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_TASKS;
+import static com.android.sdksandbox.flags.Flags.sandboxActivitySdkBasedContext;
import static com.android.server.am.ActivityManagerService.STOCK_PM_FLAGS;
import static com.android.server.am.ActivityManagerServiceDumpActivitiesProto.ROOT_WINDOW_CONTAINER;
import static com.android.server.am.ActivityManagerServiceDumpProcessesProto.CONFIG_WILL_CHANGE;
@@ -125,7 +126,6 @@
import static com.android.server.wm.Task.REPARENT_KEEP_ROOT_TASK_AT_FRONT;
import static com.android.server.wm.WindowManagerService.MY_PID;
import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_NORMAL;
-import static com.android.sdksandbox.flags.Flags.sandboxActivitySdkBasedContext;
import android.Manifest;
import android.annotation.IntDef;
@@ -1261,10 +1261,10 @@
true /*validateIncomingUser*/);
}
- static boolean isSdkSandboxActivity(Context context, Intent intent) {
+ static boolean isSdkSandboxActivityIntent(Context context, Intent intent) {
return intent != null
&& (sandboxActivitySdkBasedContext()
- ? SdkSandboxActivityAuthority.isSdkSandboxActivity(context, intent)
+ ? SdkSandboxActivityAuthority.isSdkSandboxActivityIntent(context, intent)
: intent.isSandboxActivity(context));
}
@@ -1278,7 +1278,7 @@
assertPackageMatchesCallingUid(callingPackage);
enforceNotIsolatedCaller("startActivityAsUser");
- if (isSdkSandboxActivity(mContext, intent)) {
+ if (isSdkSandboxActivityIntent(mContext, intent)) {
SdkSandboxManagerLocal sdkSandboxManagerLocal = LocalManagerRegistry.getManager(
SdkSandboxManagerLocal.class);
sdkSandboxManagerLocal.enforceAllowedToHostSandboxedActivity(
diff --git a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
index a21b9b4..4a479aa 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
@@ -1085,7 +1085,8 @@
// Remove the process record so it won't be considered as alive.
mService.mProcessNames.remove(wpc.mName, wpc.mUid);
mService.mProcessMap.remove(wpc.getPid());
- } else if (ActivityTaskManagerService.isSdkSandboxActivity(mService.mContext, r.intent)) {
+ } else if (ActivityTaskManagerService.isSdkSandboxActivityIntent(
+ mService.mContext, r.intent)) {
Slog.e(TAG, "Abort sandbox activity launching as no sandbox process to host it.");
r.finishIfPossible("No sandbox process for the activity", false /* oomAdj */);
r.launchFailed = true;
diff --git a/services/core/java/com/android/server/wm/BackNavigationController.java b/services/core/java/com/android/server/wm/BackNavigationController.java
index be7b855..c5902c9 100644
--- a/services/core/java/com/android/server/wm/BackNavigationController.java
+++ b/services/core/java/com/android/server/wm/BackNavigationController.java
@@ -395,7 +395,8 @@
*
* @return false if unable to predict what will happen
*/
- private static boolean getAnimatablePrevActivities(@NonNull Task currentTask,
+ @VisibleForTesting
+ static boolean getAnimatablePrevActivities(@NonNull Task currentTask,
@NonNull ActivityRecord currentActivity,
@NonNull ArrayList<ActivityRecord> outPrevActivities) {
if (currentActivity.mAtmService
@@ -413,45 +414,86 @@
// Searching previous
final ActivityRecord prevActivity = currentTask.getActivity((below) -> !below.finishing,
currentActivity, false /*includeBoundary*/, true /*traverseTopToBottom*/);
- if (prevActivity == null) {
- // No previous activity in this task, can still predict if previous task exists.
- return true;
- }
- if (currentTask.getActivity((above) -> !above.finishing, currentActivity,
- false /*includeBoundary*/, false /*traverseTopToBottom*/) != null) {
- // another activity is above this activity, don't know what will happen
- return false;
- }
final TaskFragment currTF = currentActivity.getTaskFragment();
- final TaskFragment prevTF = prevActivity.getTaskFragment();
- if (currTF != prevTF && prevTF != null) {
- final TaskFragment prevTFAdjacent = prevTF.getAdjacentTaskFragment();
- if (prevTFAdjacent != null) {
- if (prevTFAdjacent == currTF) {
- outPrevActivities.clear();
- // No more activity in task, so it can predict if previous task exists.
- // Otherwise, unable to predict what will happen when app receive
- // back key, skip animation.
- return currentTask.getActivity((below) -> !below.finishing, prevActivity,
+ if (currTF != null && currTF.asTask() == null) {
+ // The currentActivity is embedded, search for the candidate previous activities.
+ if (prevActivity != null && currTF.hasChild(prevActivity)) {
+ // PrevActivity is under the same task fragment, that's it.
+ outPrevActivities.add(prevActivity);
+ return true;
+ }
+ if (currTF.getAdjacentTaskFragment() != null) {
+ // The two TFs are adjacent (visually displayed side-by-side), search if any
+ // activity below the lowest one
+ // If companion, those two TF will be closed together.
+ if (currTF.getCompanionTaskFragment() != null) {
+ final WindowContainer commonParent = currTF.getParent();
+ final TaskFragment adjacentTF = currTF.getAdjacentTaskFragment();
+ final TaskFragment lowerTF = commonParent.mChildren.indexOf(currTF)
+ < commonParent.mChildren.indexOf(adjacentTF)
+ ? currTF : adjacentTF;
+ final ActivityRecord lowerActivity = lowerTF.getTopNonFinishingActivity();
+ // TODO (b/274997067) close currTF + companionTF, open next activities if any.
+ // Allow to predict next task if no more activity in task. Or return previous
+ // activities for cross-activity animation.
+ return currentTask.getActivity((below) -> !below.finishing, lowerActivity,
false /*includeBoundary*/, true /*traverseTopToBottom*/) == null;
- } else {
- final ActivityRecord prevActivityAdjacent =
- prevTFAdjacent.getTopNonFinishingActivity();
- if (prevActivityAdjacent != null) {
- outPrevActivities.add(prevActivityAdjacent);
- } else {
- // Don't know what will happen.
- outPrevActivities.clear();
- return false;
- }
}
+ // Unable to predict if no companion, it can only close current activity and make
+ // prev Activity full screened.
+ return false;
+ } else if (currTF.getCompanionTaskFragment() != null) {
+ // TF is isStacked, search bottom activity from companion TF.
+ //
+ // Sample hierarchy: search for underPrevious if any.
+ // Current TF
+ // Companion TF (bottomActivityInCompanion)
+ // Bottom Activity not inside companion TF (underPrevious)
+ final TaskFragment companionTF = currTF.getCompanionTaskFragment();
+ // find bottom activity in Companion TF.
+ final ActivityRecord bottomActivityInCompanion = companionTF.getActivity(
+ (below) -> !below.finishing, false /* traverseTopToBottom */);
+ final ActivityRecord underPrevious = currentTask.getActivity(
+ (below) -> !below.finishing, bottomActivityInCompanion,
+ false /*includeBoundary*/, true /*traverseTopToBottom*/);
+ if (underPrevious != null) {
+ outPrevActivities.add(underPrevious);
+ addPreviousAdjacentActivityIfExist(underPrevious, outPrevActivities);
+ }
+ return true;
}
}
+
+ if (prevActivity == null) {
+ // No previous activity in this Task nor TaskFragment, it can still predict if previous
+ // task exists.
+ return true;
+ }
+ // Add possible adjacent activity if prevActivity is embedded
+ addPreviousAdjacentActivityIfExist(prevActivity, outPrevActivities);
outPrevActivities.add(prevActivity);
return true;
}
+ private static void addPreviousAdjacentActivityIfExist(@NonNull ActivityRecord prevActivity,
+ @NonNull ArrayList<ActivityRecord> outPrevActivities) {
+ final TaskFragment prevTF = prevActivity.getTaskFragment();
+ if (prevTF == null || prevTF.asTask() != null) {
+ return;
+ }
+
+ final TaskFragment prevTFAdjacent = prevTF.getAdjacentTaskFragment();
+ if (prevTFAdjacent == null || prevTFAdjacent.asTask() != null) {
+ return;
+ }
+ final ActivityRecord prevActivityAdjacent =
+ prevTFAdjacent.getTopNonFinishingActivity();
+ if (prevActivityAdjacent != null) {
+ outPrevActivities.add(prevActivityAdjacent);
+ }
+ }
+
private static void findAdjacentActivityIfExist(@NonNull ActivityRecord mainActivity,
@NonNull ArrayList<ActivityRecord> outList) {
final TaskFragment mainTF = mainActivity.getTaskFragment();
diff --git a/services/core/java/com/android/server/wm/BackgroundActivityStartController.java b/services/core/java/com/android/server/wm/BackgroundActivityStartController.java
index 4625b4fe..f8b22c9 100644
--- a/services/core/java/com/android/server/wm/BackgroundActivityStartController.java
+++ b/services/core/java/com/android/server/wm/BackgroundActivityStartController.java
@@ -614,6 +614,15 @@
== ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_SYSTEM_DEFINED;
if (callerCanAllow && realCallerCanAllow) {
// Both caller and real caller allow with system defined behavior
+ if (state.mBalAllowedByPiCreatorWithHardening.allowsBackgroundActivityStarts()) {
+ // Will be allowed even with BAL hardening.
+ if (DEBUG_ACTIVITY_STARTS) {
+ Slog.d(TAG, "Activity start allowed by caller. "
+ + state.dump(resultForCaller, resultForRealCaller));
+ }
+ // return the realCaller result for backwards compatibility
+ return statsLog(resultForRealCaller, state);
+ }
if (state.mBalAllowedByPiCreator.allowsBackgroundActivityStarts()) {
Slog.wtf(TAG,
"With Android 15 BAL hardening this activity start may be blocked"
@@ -632,6 +641,14 @@
}
if (callerCanAllow) {
// Allowed before V by creator
+ if (state.mBalAllowedByPiCreatorWithHardening.allowsBackgroundActivityStarts()) {
+ // Will be allowed even with BAL hardening.
+ if (DEBUG_ACTIVITY_STARTS) {
+ Slog.d(TAG, "Activity start allowed by caller. "
+ + state.dump(resultForCaller, resultForRealCaller));
+ }
+ return statsLog(resultForCaller, state);
+ }
if (state.mBalAllowedByPiCreator.allowsBackgroundActivityStarts()) {
Slog.wtf(TAG,
"With Android 15 BAL hardening this activity start may be blocked"
diff --git a/services/core/java/com/android/server/wm/DisplayArea.java b/services/core/java/com/android/server/wm/DisplayArea.java
index f51bf7f..0006bd2 100644
--- a/services/core/java/com/android/server/wm/DisplayArea.java
+++ b/services/core/java/com/android/server/wm/DisplayArea.java
@@ -420,7 +420,7 @@
@Override
ActivityRecord getActivity(Predicate<ActivityRecord> callback, boolean traverseTopToBottom,
ActivityRecord boundary) {
- if (mType == Type.ABOVE_TASKS || mType == Type.BELOW_TASKS) {
+ if (mType == Type.ABOVE_TASKS) {
return null;
}
return super.getActivity(callback, traverseTopToBottom, boundary);
@@ -428,23 +428,39 @@
@Override
Task getTask(Predicate<Task> callback, boolean traverseTopToBottom) {
- if (mType == Type.ABOVE_TASKS || mType == Type.BELOW_TASKS) {
+ if (mType == Type.ABOVE_TASKS) {
return null;
}
return super.getTask(callback, traverseTopToBottom);
}
@Override
+ Task getRootTask(Predicate<Task> callback, boolean traverseTopToBottom) {
+ if (mType == Type.ABOVE_TASKS) {
+ return null;
+ }
+ return super.getRootTask(callback, traverseTopToBottom);
+ }
+
+ @Override
boolean forAllActivities(Predicate<ActivityRecord> callback, boolean traverseTopToBottom) {
- if (mType == Type.ABOVE_TASKS || mType == Type.BELOW_TASKS) {
+ if (mType == Type.ABOVE_TASKS) {
return false;
}
return super.forAllActivities(callback, traverseTopToBottom);
}
@Override
+ void forAllActivities(Consumer<ActivityRecord> callback, boolean traverseTopToBottom) {
+ if (mType == Type.ABOVE_TASKS) {
+ return;
+ }
+ super.forAllActivities(callback, traverseTopToBottom);
+ }
+
+ @Override
boolean forAllRootTasks(Predicate<Task> callback, boolean traverseTopToBottom) {
- if (mType == Type.ABOVE_TASKS || mType == Type.BELOW_TASKS) {
+ if (mType == Type.ABOVE_TASKS) {
return false;
}
return super.forAllRootTasks(callback, traverseTopToBottom);
@@ -452,7 +468,7 @@
@Override
boolean forAllTasks(Predicate<Task> callback) {
- if (mType == Type.ABOVE_TASKS || mType == Type.BELOW_TASKS) {
+ if (mType == Type.ABOVE_TASKS) {
return false;
}
return super.forAllTasks(callback);
@@ -460,13 +476,29 @@
@Override
boolean forAllLeafTasks(Predicate<Task> callback) {
- if (mType == Type.ABOVE_TASKS || mType == Type.BELOW_TASKS) {
+ if (mType == Type.ABOVE_TASKS) {
return false;
}
return super.forAllLeafTasks(callback);
}
@Override
+ void forAllLeafTasks(Consumer<Task> callback, boolean traverseTopToBottom) {
+ if (mType == Type.ABOVE_TASKS) {
+ return;
+ }
+ super.forAllLeafTasks(callback, traverseTopToBottom);
+ }
+
+ @Override
+ boolean forAllLeafTaskFragments(Predicate<TaskFragment> callback) {
+ if (mType == Type.ABOVE_TASKS) {
+ return false;
+ }
+ return super.forAllLeafTaskFragments(callback);
+ }
+
+ @Override
void forAllDisplayAreas(Consumer<DisplayArea> callback) {
super.forAllDisplayAreas(callback);
callback.accept(this);
diff --git a/services/core/java/com/android/server/wm/InputMonitor.java b/services/core/java/com/android/server/wm/InputMonitor.java
index 14912d0..bf30af3 100644
--- a/services/core/java/com/android/server/wm/InputMonitor.java
+++ b/services/core/java/com/android/server/wm/InputMonitor.java
@@ -461,7 +461,7 @@
// in animating before the next app window focused, or IME icon
// persists on the bottom when swiping the task to recents.
InputMethodManagerInternal.get().updateImeWindowStatus(
- true /* disableImeIcon */);
+ true /* disableImeIcon */, mDisplayContent.getDisplayId());
}
}
return;
diff --git a/services/core/java/com/android/server/wm/KeyguardController.java b/services/core/java/com/android/server/wm/KeyguardController.java
index ccaa3b0..cbc7b83 100644
--- a/services/core/java/com/android/server/wm/KeyguardController.java
+++ b/services/core/java/com/android/server/wm/KeyguardController.java
@@ -240,7 +240,8 @@
// state when evaluating visibilities.
updateKeyguardSleepToken();
mRootWindowContainer.ensureActivitiesVisible(null, 0, !PRESERVE_WINDOWS);
- InputMethodManagerInternal.get().updateImeWindowStatus(false /* disableImeIcon */);
+ InputMethodManagerInternal.get().updateImeWindowStatus(false /* disableImeIcon */,
+ displayId);
setWakeTransitionReady();
if (aodChanged) {
// Ensure the new state takes effect.
diff --git a/services/core/java/com/android/server/wm/RecentsAnimationController.java b/services/core/java/com/android/server/wm/RecentsAnimationController.java
index ef25726..dd538de 100644
--- a/services/core/java/com/android/server/wm/RecentsAnimationController.java
+++ b/services/core/java/com/android/server/wm/RecentsAnimationController.java
@@ -967,7 +967,8 @@
// Restore IME icon only when moving the original app task to front from recents, in case
// IME icon may missing if the moving task has already been the current focused task.
if (reorderMode == REORDER_MOVE_TO_ORIGINAL_POSITION && !mIsAddingTaskToTargets) {
- InputMethodManagerInternal.get().updateImeWindowStatus(false /* disableImeIcon */);
+ InputMethodManagerInternal.get().updateImeWindowStatus(
+ false /* disableImeIcon */, mDisplayId);
}
// Update the input windows after the animation is complete
diff --git a/services/core/java/com/android/server/wm/Transition.java b/services/core/java/com/android/server/wm/Transition.java
index 4243948..76c4a0e 100644
--- a/services/core/java/com/android/server/wm/Transition.java
+++ b/services/core/java/com/android/server/wm/Transition.java
@@ -1390,7 +1390,7 @@
// recents, in case IME icon may missing if the moving task has already been
// the current focused task.
InputMethodManagerInternal.get().updateImeWindowStatus(
- false /* disableImeIcon */);
+ false /* disableImeIcon */, dc.getDisplayId());
}
// An uncommitted transient launch can leave incomplete lifecycles if visibilities
// didn't change (eg. re-ordering with translucent tasks will leave launcher
diff --git a/services/core/java/com/android/server/wm/TrustedPresentationListenerController.java b/services/core/java/com/android/server/wm/TrustedPresentationListenerController.java
deleted file mode 100644
index e82dc37..0000000
--- a/services/core/java/com/android/server/wm/TrustedPresentationListenerController.java
+++ /dev/null
@@ -1,448 +0,0 @@
-/*
- * Copyright 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.wm;
-
-import static android.graphics.Matrix.MSCALE_X;
-import static android.graphics.Matrix.MSCALE_Y;
-import static android.graphics.Matrix.MSKEW_X;
-import static android.graphics.Matrix.MSKEW_Y;
-
-import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_TPL;
-
-import android.graphics.Matrix;
-import android.graphics.Rect;
-import android.graphics.RectF;
-import android.graphics.Region;
-import android.os.Handler;
-import android.os.HandlerThread;
-import android.os.IBinder;
-import android.os.RemoteException;
-import android.util.ArrayMap;
-import android.util.ArraySet;
-import android.util.IntArray;
-import android.util.Pair;
-import android.util.Size;
-import android.view.InputWindowHandle;
-import android.window.ITrustedPresentationListener;
-import android.window.TrustedPresentationThresholds;
-import android.window.WindowInfosListener;
-
-import com.android.internal.protolog.common.ProtoLog;
-import com.android.server.wm.utils.RegionUtils;
-
-import java.io.PrintWriter;
-import java.util.ArrayList;
-import java.util.Optional;
-
-/**
- * Class to handle TrustedPresentationListener registrations in a thread safe manner. This class
- * also takes care of cleaning up listeners when the remote process dies.
- */
-public class TrustedPresentationListenerController {
-
- // Should only be accessed by the posting to the handler
- private class Listeners {
- private final class ListenerDeathRecipient implements IBinder.DeathRecipient {
- IBinder mListenerBinder;
- int mInstances;
-
- ListenerDeathRecipient(IBinder listenerBinder) {
- mListenerBinder = listenerBinder;
- mInstances = 0;
- try {
- mListenerBinder.linkToDeath(this, 0);
- } catch (RemoteException ignore) {
- }
- }
-
- void addInstance() {
- mInstances++;
- }
-
- // return true if there are no instances alive
- boolean removeInstance() {
- mInstances--;
- if (mInstances > 0) {
- return false;
- }
- mListenerBinder.unlinkToDeath(this, 0);
- return true;
- }
-
- public void binderDied() {
- mHandler.post(() -> {
- mUniqueListeners.remove(mListenerBinder);
- removeListeners(mListenerBinder, Optional.empty());
- });
- }
- }
-
- // tracks binder deaths for cleanup
- ArrayMap<IBinder, ListenerDeathRecipient> mUniqueListeners = new ArrayMap<>();
- ArrayMap<IBinder /*window*/, ArrayList<TrustedPresentationInfo>> mWindowToListeners =
- new ArrayMap<>();
-
- void register(IBinder window, ITrustedPresentationListener listener,
- TrustedPresentationThresholds thresholds, int id) {
- var listenersForWindow = mWindowToListeners.computeIfAbsent(window,
- iBinder -> new ArrayList<>());
- listenersForWindow.add(new TrustedPresentationInfo(thresholds, id, listener));
-
- // register death listener
- var listenerBinder = listener.asBinder();
- var deathRecipient = mUniqueListeners.computeIfAbsent(listenerBinder,
- ListenerDeathRecipient::new);
- deathRecipient.addInstance();
- }
-
- void unregister(ITrustedPresentationListener trustedPresentationListener, int id) {
- var listenerBinder = trustedPresentationListener.asBinder();
- var deathRecipient = mUniqueListeners.get(listenerBinder);
- if (deathRecipient == null) {
- ProtoLog.e(WM_DEBUG_TPL, "unregister failed, couldn't find"
- + " deathRecipient for %s with id=%d", trustedPresentationListener, id);
- return;
- }
-
- if (deathRecipient.removeInstance()) {
- mUniqueListeners.remove(listenerBinder);
- }
- removeListeners(listenerBinder, Optional.of(id));
- }
-
- boolean isEmpty() {
- return mWindowToListeners.isEmpty();
- }
-
- ArrayList<TrustedPresentationInfo> get(IBinder windowToken) {
- return mWindowToListeners.get(windowToken);
- }
-
- private void removeListeners(IBinder listenerBinder, Optional<Integer> id) {
- for (int i = mWindowToListeners.size() - 1; i >= 0; i--) {
- var listeners = mWindowToListeners.valueAt(i);
- for (int j = listeners.size() - 1; j >= 0; j--) {
- var listener = listeners.get(j);
- if (listener.mListener.asBinder() == listenerBinder && (id.isEmpty()
- || listener.mId == id.get())) {
- listeners.remove(j);
- }
- }
- if (listeners.isEmpty()) {
- mWindowToListeners.removeAt(i);
- }
- }
- }
- }
-
- private final Object mHandlerThreadLock = new Object();
- private HandlerThread mHandlerThread;
- private Handler mHandler;
-
- private WindowInfosListener mWindowInfosListener;
-
- Listeners mRegisteredListeners = new Listeners();
-
- private InputWindowHandle[] mLastWindowHandles;
-
- private final Object mIgnoredWindowTokensLock = new Object();
-
- private final ArraySet<IBinder> mIgnoredWindowTokens = new ArraySet<>();
-
- private void startHandlerThreadIfNeeded() {
- synchronized (mHandlerThreadLock) {
- if (mHandler == null) {
- mHandlerThread = new HandlerThread("WindowInfosListenerForTpl");
- mHandlerThread.start();
- mHandler = new Handler(mHandlerThread.getLooper());
- }
- }
- }
-
- void addIgnoredWindowTokens(IBinder token) {
- synchronized (mIgnoredWindowTokensLock) {
- mIgnoredWindowTokens.add(token);
- }
- }
-
- void removeIgnoredWindowTokens(IBinder token) {
- synchronized (mIgnoredWindowTokensLock) {
- mIgnoredWindowTokens.remove(token);
- }
- }
-
- void registerListener(IBinder window, ITrustedPresentationListener listener,
- TrustedPresentationThresholds thresholds, int id) {
- startHandlerThreadIfNeeded();
- mHandler.post(() -> {
- ProtoLog.d(WM_DEBUG_TPL, "Registering listener=%s with id=%d for window=%s with %s",
- listener, id, window, thresholds);
-
- mRegisteredListeners.register(window, listener, thresholds, id);
- registerWindowInfosListener();
- // Update the initial state for the new registered listener
- computeTpl(mLastWindowHandles);
- });
- }
-
- void unregisterListener(ITrustedPresentationListener listener, int id) {
- startHandlerThreadIfNeeded();
- mHandler.post(() -> {
- ProtoLog.d(WM_DEBUG_TPL, "Unregistering listener=%s with id=%d",
- listener, id);
-
- mRegisteredListeners.unregister(listener, id);
- if (mRegisteredListeners.isEmpty()) {
- unregisterWindowInfosListener();
- }
- });
- }
-
- void dump(PrintWriter pw) {
- final String innerPrefix = " ";
- pw.println("TrustedPresentationListenerController:");
- pw.println(innerPrefix + "Active unique listeners ("
- + mRegisteredListeners.mUniqueListeners.size() + "):");
- for (int i = 0; i < mRegisteredListeners.mWindowToListeners.size(); i++) {
- pw.println(
- innerPrefix + " window=" + mRegisteredListeners.mWindowToListeners.keyAt(i));
- final var listeners = mRegisteredListeners.mWindowToListeners.valueAt(i);
- for (int j = 0; j < listeners.size(); j++) {
- final var listener = listeners.get(j);
- pw.println(innerPrefix + innerPrefix + " listener=" + listener.mListener.asBinder()
- + " id=" + listener.mId
- + " thresholds=" + listener.mThresholds);
- }
- }
- }
-
- private void registerWindowInfosListener() {
- if (mWindowInfosListener != null) {
- return;
- }
-
- mWindowInfosListener = new WindowInfosListener() {
- @Override
- public void onWindowInfosChanged(InputWindowHandle[] windowHandles,
- DisplayInfo[] displayInfos) {
- mHandler.post(() -> computeTpl(windowHandles));
- }
- };
- mLastWindowHandles = mWindowInfosListener.register().first;
- }
-
- private void unregisterWindowInfosListener() {
- if (mWindowInfosListener == null) {
- return;
- }
-
- mWindowInfosListener.unregister();
- mWindowInfosListener = null;
- mLastWindowHandles = null;
- }
-
- private void computeTpl(InputWindowHandle[] windowHandles) {
- mLastWindowHandles = windowHandles;
- if (mLastWindowHandles == null || mLastWindowHandles.length == 0
- || mRegisteredListeners.isEmpty()) {
- return;
- }
-
- Rect tmpRect = new Rect();
- Matrix tmpInverseMatrix = new Matrix();
- float[] tmpMatrix = new float[9];
- Region coveredRegionsAbove = new Region();
- long currTimeMs = System.currentTimeMillis();
- ProtoLog.v(WM_DEBUG_TPL, "Checking %d windows", mLastWindowHandles.length);
-
- ArrayMap<ITrustedPresentationListener, Pair<IntArray, IntArray>> listenerUpdates =
- new ArrayMap<>();
- ArraySet<IBinder> ignoredWindowTokens;
- synchronized (mIgnoredWindowTokensLock) {
- ignoredWindowTokens = new ArraySet<>(mIgnoredWindowTokens);
- }
- for (var windowHandle : mLastWindowHandles) {
- if (ignoredWindowTokens.contains(windowHandle.getWindowToken())) {
- ProtoLog.v(WM_DEBUG_TPL, "Skipping %s", windowHandle.name);
- continue;
- }
- tmpRect.set(windowHandle.frame);
- var listeners = mRegisteredListeners.get(windowHandle.getWindowToken());
- if (listeners != null) {
- Region region = new Region();
- region.op(tmpRect, coveredRegionsAbove, Region.Op.DIFFERENCE);
- windowHandle.transform.invert(tmpInverseMatrix);
- tmpInverseMatrix.getValues(tmpMatrix);
- float scaleX = (float) Math.sqrt(tmpMatrix[MSCALE_X] * tmpMatrix[MSCALE_X]
- + tmpMatrix[MSKEW_X] * tmpMatrix[MSKEW_X]);
- float scaleY = (float) Math.sqrt(tmpMatrix[MSCALE_Y] * tmpMatrix[MSCALE_Y]
- + tmpMatrix[MSKEW_Y] * tmpMatrix[MSKEW_Y]);
-
- float fractionRendered = computeFractionRendered(region, new RectF(tmpRect),
- windowHandle.contentSize,
- scaleX, scaleY);
-
- checkIfInThreshold(listeners, listenerUpdates, fractionRendered, windowHandle.alpha,
- currTimeMs);
- }
-
- coveredRegionsAbove.op(tmpRect, Region.Op.UNION);
- ProtoLog.v(WM_DEBUG_TPL, "coveredRegionsAbove updated with %s frame:%s region:%s",
- windowHandle.name, tmpRect.toShortString(), coveredRegionsAbove);
- }
-
- for (int i = 0; i < listenerUpdates.size(); i++) {
- var updates = listenerUpdates.valueAt(i);
- var listener = listenerUpdates.keyAt(i);
- try {
- listener.onTrustedPresentationChanged(updates.first.toArray(),
- updates.second.toArray());
- } catch (RemoteException ignore) {
- }
- }
- }
-
- private void addListenerUpdate(
- ArrayMap<ITrustedPresentationListener, Pair<IntArray, IntArray>> listenerUpdates,
- ITrustedPresentationListener listener, int id, boolean presentationState) {
- var updates = listenerUpdates.get(listener);
- if (updates == null) {
- updates = new Pair<>(new IntArray(), new IntArray());
- listenerUpdates.put(listener, updates);
- }
- if (presentationState) {
- updates.first.add(id);
- } else {
- updates.second.add(id);
- }
- }
-
-
- private void checkIfInThreshold(
- ArrayList<TrustedPresentationInfo> listeners,
- ArrayMap<ITrustedPresentationListener, Pair<IntArray, IntArray>> listenerUpdates,
- float fractionRendered, float alpha, long currTimeMs) {
- ProtoLog.v(WM_DEBUG_TPL, "checkIfInThreshold fractionRendered=%f alpha=%f currTimeMs=%d",
- fractionRendered, alpha, currTimeMs);
- for (int i = 0; i < listeners.size(); i++) {
- var trustedPresentationInfo = listeners.get(i);
- var listener = trustedPresentationInfo.mListener;
- boolean lastState = trustedPresentationInfo.mLastComputedTrustedPresentationState;
- boolean newState =
- (alpha >= trustedPresentationInfo.mThresholds.mMinAlpha) && (fractionRendered
- >= trustedPresentationInfo.mThresholds.mMinFractionRendered);
- trustedPresentationInfo.mLastComputedTrustedPresentationState = newState;
-
- ProtoLog.v(WM_DEBUG_TPL,
- "lastState=%s newState=%s alpha=%f minAlpha=%f fractionRendered=%f "
- + "minFractionRendered=%f",
- lastState, newState, alpha, trustedPresentationInfo.mThresholds.mMinAlpha,
- fractionRendered, trustedPresentationInfo.mThresholds.mMinFractionRendered);
-
- if (lastState && !newState) {
- // We were in the trusted presentation state, but now we left it,
- // emit the callback if needed
- if (trustedPresentationInfo.mLastReportedTrustedPresentationState) {
- trustedPresentationInfo.mLastReportedTrustedPresentationState = false;
- addListenerUpdate(listenerUpdates, listener,
- trustedPresentationInfo.mId, /*presentationState*/ false);
- ProtoLog.d(WM_DEBUG_TPL, "Adding untrusted state listener=%s with id=%d",
- listener, trustedPresentationInfo.mId);
- }
- // Reset the timer
- trustedPresentationInfo.mEnteredTrustedPresentationStateTime = -1;
- } else if (!lastState && newState) {
- // We were not in the trusted presentation state, but we entered it, begin the timer
- // and make sure this gets called at least once more!
- trustedPresentationInfo.mEnteredTrustedPresentationStateTime = currTimeMs;
- mHandler.postDelayed(() -> {
- computeTpl(mLastWindowHandles);
- }, (long) (trustedPresentationInfo.mThresholds.mStabilityRequirementMs * 1.5));
- }
-
- // Has the timer elapsed, but we are still in the state? Emit a callback if needed
- if (!trustedPresentationInfo.mLastReportedTrustedPresentationState && newState && (
- currTimeMs - trustedPresentationInfo.mEnteredTrustedPresentationStateTime
- > trustedPresentationInfo.mThresholds.mStabilityRequirementMs)) {
- trustedPresentationInfo.mLastReportedTrustedPresentationState = true;
- addListenerUpdate(listenerUpdates, listener,
- trustedPresentationInfo.mId, /*presentationState*/ true);
- ProtoLog.d(WM_DEBUG_TPL, "Adding trusted state listener=%s with id=%d",
- listener, trustedPresentationInfo.mId);
- }
- }
- }
-
- private float computeFractionRendered(Region visibleRegion, RectF screenBounds,
- Size contentSize,
- float sx, float sy) {
- ProtoLog.v(WM_DEBUG_TPL,
- "computeFractionRendered: visibleRegion=%s screenBounds=%s contentSize=%s "
- + "scale=%f,%f",
- visibleRegion, screenBounds, contentSize, sx, sy);
-
- if (contentSize.getWidth() == 0 || contentSize.getHeight() == 0) {
- return -1;
- }
- if (screenBounds.width() == 0 || screenBounds.height() == 0) {
- return -1;
- }
-
- float fractionRendered = Math.min(sx * sy, 1.0f);
- ProtoLog.v(WM_DEBUG_TPL, "fractionRendered scale=%f", fractionRendered);
-
- float boundsOverSourceW = screenBounds.width() / (float) contentSize.getWidth();
- float boundsOverSourceH = screenBounds.height() / (float) contentSize.getHeight();
- fractionRendered *= boundsOverSourceW * boundsOverSourceH;
- ProtoLog.v(WM_DEBUG_TPL, "fractionRendered boundsOverSource=%f", fractionRendered);
- // Compute the size of all the rects since they may be disconnected.
- float[] visibleSize = new float[1];
- RegionUtils.forEachRect(visibleRegion, rect -> {
- float size = rect.width() * rect.height();
- visibleSize[0] += size;
- });
-
- fractionRendered *= visibleSize[0] / (screenBounds.width() * screenBounds.height());
- return fractionRendered;
- }
-
- private static class TrustedPresentationInfo {
- boolean mLastComputedTrustedPresentationState = false;
- boolean mLastReportedTrustedPresentationState = false;
- long mEnteredTrustedPresentationStateTime = -1;
- final TrustedPresentationThresholds mThresholds;
-
- final ITrustedPresentationListener mListener;
- final int mId;
-
- private TrustedPresentationInfo(TrustedPresentationThresholds thresholds, int id,
- ITrustedPresentationListener listener) {
- mThresholds = thresholds;
- mId = id;
- mListener = listener;
- checkValid(thresholds);
- }
-
- private void checkValid(TrustedPresentationThresholds thresholds) {
- if (thresholds.mMinAlpha <= 0 || thresholds.mMinFractionRendered <= 0
- || thresholds.mStabilityRequirementMs < 1) {
- throw new IllegalArgumentException(
- "TrustedPresentationThresholds values are invalid");
- }
- }
- }
-}
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 0c57036..0d2c94d 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -303,11 +303,9 @@
import android.window.ClientWindowFrames;
import android.window.ISurfaceSyncGroupCompletedListener;
import android.window.ITaskFpsCallback;
-import android.window.ITrustedPresentationListener;
import android.window.ScreenCapture;
import android.window.SystemPerformanceHinter;
import android.window.TaskSnapshot;
-import android.window.TrustedPresentationThresholds;
import android.window.WindowContainerToken;
import android.window.WindowContextInfo;
@@ -766,9 +764,6 @@
private final SurfaceSyncGroupController mSurfaceSyncGroupController =
new SurfaceSyncGroupController();
- final TrustedPresentationListenerController mTrustedPresentationListenerController =
- new TrustedPresentationListenerController();
-
@VisibleForTesting
final class SettingsObserver extends ContentObserver {
private final Uri mDisplayInversionEnabledUri =
@@ -7176,7 +7171,6 @@
pw.println(separator);
}
mSystemPerformanceHinter.dump(pw, "");
- mTrustedPresentationListenerController.dump(pw);
}
}
@@ -9777,17 +9771,4 @@
Binder.restoreCallingIdentity(origId);
}
}
-
- @Override
- public void registerTrustedPresentationListener(IBinder window,
- ITrustedPresentationListener listener,
- TrustedPresentationThresholds thresholds, int id) {
- mTrustedPresentationListenerController.registerListener(window, listener, thresholds, id);
- }
-
- @Override
- public void unregisterTrustedPresentationListener(ITrustedPresentationListener listener,
- int id) {
- mTrustedPresentationListenerController.unregisterListener(listener, id);
- }
}
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 7bc7e2c..b890a9e 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -1189,11 +1189,6 @@
ProtoLog.v(WM_DEBUG_ADD_REMOVE, "Adding %s to %s", this, parentWindow);
parentWindow.addChild(this, sWindowSubLayerComparator);
}
-
- if (token.mRoundedCornerOverlay) {
- mWmService.mTrustedPresentationListenerController.addIgnoredWindowTokens(
- getWindowToken());
- }
}
@Override
@@ -2398,9 +2393,6 @@
}
mWmService.postWindowRemoveCleanupLocked(this);
-
- mWmService.mTrustedPresentationListenerController.removeIgnoredWindowTokens(
- getWindowToken());
}
@Override
@@ -5630,9 +5622,10 @@
if (mKeyInterceptionInfo == null
|| mKeyInterceptionInfo.layoutParamsPrivateFlags != getAttrs().privateFlags
|| mKeyInterceptionInfo.layoutParamsType != getAttrs().type
- || mKeyInterceptionInfo.windowTitle != getWindowTag()) {
+ || mKeyInterceptionInfo.windowTitle != getWindowTag()
+ || mKeyInterceptionInfo.windowOwnerUid != getOwningUid()) {
mKeyInterceptionInfo = new KeyInterceptionInfo(getAttrs().type, getAttrs().privateFlags,
- getWindowTag().toString());
+ getWindowTag().toString(), getOwningUid());
}
return mKeyInterceptionInfo;
}
diff --git a/services/incremental/IncrementalService.cpp b/services/incremental/IncrementalService.cpp
index 81a5472..a8e6f68 100644
--- a/services/incremental/IncrementalService.cpp
+++ b/services/incremental/IncrementalService.cpp
@@ -910,7 +910,7 @@
constants().readLogsDisabledMarkerName),
0777, idFromMetadata(metadata), {})) {
//{.metadata = {metadata.data(), (IncFsSize)metadata.size()}})) {
- LOG(ERROR) << "Failed to make marker file for storageId: " << storageId;
+ LOG(ERROR) << "Failed to make marker file for storageId: " << storageId << " err: " << -err;
return;
}
diff --git a/services/permission/java/com/android/server/permission/access/permission/DevicePermissionPolicy.kt b/services/permission/java/com/android/server/permission/access/permission/DevicePermissionPolicy.kt
index bb68bc5..44609ac 100644
--- a/services/permission/java/com/android/server/permission/access/permission/DevicePermissionPolicy.kt
+++ b/services/permission/java/com/android/server/permission/access/permission/DevicePermissionPolicy.kt
@@ -61,6 +61,38 @@
}
}
+ fun MutateStateScope.removeInactiveDevicesPermission(activePersistentDeviceIds: Set<String>) {
+ newState.userStates.forEachIndexed { _, userId, userState ->
+ userState.appIdDevicePermissionFlags.forEachReversedIndexed { _, appId, _ ->
+ val appIdDevicePermissionFlags =
+ newState.mutateUserState(userId)!!.mutateAppIdDevicePermissionFlags()
+ val devicePermissionFlags =
+ appIdDevicePermissionFlags.mutate(appId) ?: return@forEachReversedIndexed
+
+ val removePersistentDeviceIds = mutableSetOf<String>()
+ devicePermissionFlags.forEachIndexed { _, deviceId, _ ->
+ if (!activePersistentDeviceIds.contains(deviceId)) {
+ removePersistentDeviceIds.add(deviceId)
+ }
+ }
+
+ removePersistentDeviceIds.forEach { deviceId -> devicePermissionFlags -= deviceId }
+ }
+ }
+ }
+
+ fun MutateStateScope.onDeviceIdRemoved(deviceId: String) {
+ newState.userStates.forEachIndexed { _, userId, userState ->
+ userState.appIdDevicePermissionFlags.forEachReversedIndexed { _, appId, _ ->
+ val appIdDevicePermissionFlags =
+ newState.mutateUserState(userId)!!.mutateAppIdDevicePermissionFlags()
+ val devicePermissionFlags =
+ appIdDevicePermissionFlags.mutate(appId) ?: return@forEachReversedIndexed
+ devicePermissionFlags -= deviceId
+ }
+ }
+ }
+
override fun MutateStateScope.onStorageVolumeMounted(
volumeUuid: String?,
packageNames: List<String>,
diff --git a/services/permission/java/com/android/server/permission/access/permission/PermissionService.kt b/services/permission/java/com/android/server/permission/access/permission/PermissionService.kt
index 7c53950..a7d3249 100644
--- a/services/permission/java/com/android/server/permission/access/permission/PermissionService.kt
+++ b/services/permission/java/com/android/server/permission/access/permission/PermissionService.kt
@@ -2314,6 +2314,18 @@
service.onSystemReady()
virtualDeviceManagerInternal =
LocalServices.getService(VirtualDeviceManagerInternal::class.java)
+
+ virtualDeviceManagerInternal?.allPersistentDeviceIds?.let { persistentDeviceIds ->
+ service.mutateState {
+ with(devicePolicy) { removeInactiveDevicesPermission(persistentDeviceIds) }
+ }
+ }
+
+ // trim permission states for the external devices, when they are removed.
+ virtualDeviceManagerInternal?.registerPersistentDeviceIdRemovedListener { persistentDeviceId
+ ->
+ service.mutateState { with(devicePolicy) { onDeviceIdRemoved(persistentDeviceId) } }
+ }
permissionControllerManager =
PermissionControllerManager(context, PermissionThread.getHandler())
}
@@ -2681,8 +2693,8 @@
permissionName in NOTIFICATIONS_PERMISSIONS &&
runtimePermissionRevokedUids.get(uid, true)
}
- runtimePermissionChangedUidDevices
- .getOrPut(uid) { mutableSetOf() } += persistentDeviceId
+ runtimePermissionChangedUidDevices.getOrPut(uid) { mutableSetOf() } +=
+ persistentDeviceId
}
if (permission.hasGids && !wasPermissionGranted && isPermissionGranted) {
@@ -2799,8 +2811,7 @@
fun onPermissionsChanged(uid: Int, persistentDeviceId: String) {
if (listeners.registeredCallbackCount > 0) {
- obtainMessage(MSG_ON_PERMISSIONS_CHANGED, uid, 0, persistentDeviceId)
- .sendToTarget()
+ obtainMessage(MSG_ON_PERMISSIONS_CHANGED, uid, 0, persistentDeviceId).sendToTarget()
}
}
diff --git a/services/robotests/src/com/android/server/media/AudioPoliciesBluetoothRouteControllerTest.java b/services/robotests/src/com/android/server/media/AudioPoliciesBluetoothRouteControllerTest.java
deleted file mode 100644
index 0ad4184..0000000
--- a/services/robotests/src/com/android/server/media/AudioPoliciesBluetoothRouteControllerTest.java
+++ /dev/null
@@ -1,293 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.media;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.mockito.Mockito.any;
-import static org.mockito.Mockito.eq;
-import static org.mockito.Mockito.when;
-
-import android.app.Application;
-import android.bluetooth.BluetoothA2dp;
-import android.bluetooth.BluetoothAdapter;
-import android.bluetooth.BluetoothDevice;
-import android.bluetooth.BluetoothManager;
-import android.bluetooth.BluetoothProfile;
-import android.content.Context;
-import android.content.Intent;
-import android.media.AudioManager;
-import android.media.MediaRoute2Info;
-import android.os.UserHandle;
-
-import androidx.test.core.app.ApplicationProvider;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-import org.robolectric.RobolectricTestRunner;
-import org.robolectric.Shadows;
-import org.robolectric.shadows.ShadowBluetoothAdapter;
-import org.robolectric.shadows.ShadowBluetoothDevice;
-
-import java.util.Collection;
-import java.util.HashSet;
-import java.util.Set;
-
-@RunWith(RobolectricTestRunner.class)
-public class AudioPoliciesBluetoothRouteControllerTest {
-
- private static final String DEVICE_ADDRESS_UNKNOWN = ":unknown:ip:address:";
- private static final String DEVICE_ADDRESS_SAMPLE_1 = "30:59:8B:E4:C6:35";
- private static final String DEVICE_ADDRESS_SAMPLE_2 = "0D:0D:A6:FF:8D:B6";
- private static final String DEVICE_ADDRESS_SAMPLE_3 = "2D:9B:0C:C2:6F:78";
- private static final String DEVICE_ADDRESS_SAMPLE_4 = "66:88:F9:2D:A8:1E";
-
- private Context mContext;
-
- private ShadowBluetoothAdapter mShadowBluetoothAdapter;
-
- @Mock
- private BluetoothRouteController.BluetoothRoutesUpdatedListener mListener;
-
- @Mock
- private BluetoothProfileMonitor mBluetoothProfileMonitor;
-
- private AudioPoliciesBluetoothRouteController mAudioPoliciesBluetoothRouteController;
-
- @Before
- public void setUp() {
- MockitoAnnotations.initMocks(this);
-
- Application application = ApplicationProvider.getApplicationContext();
- mContext = application;
-
- BluetoothManager bluetoothManager = (BluetoothManager)
- mContext.getSystemService(Context.BLUETOOTH_SERVICE);
-
- BluetoothAdapter bluetoothAdapter = bluetoothManager.getAdapter();
- mShadowBluetoothAdapter = Shadows.shadowOf(bluetoothAdapter);
-
- mAudioPoliciesBluetoothRouteController =
- new AudioPoliciesBluetoothRouteController(mContext, bluetoothAdapter,
- mBluetoothProfileMonitor, mListener) {
- @Override
- boolean isDeviceConnected(BluetoothDevice device) {
- return true;
- }
- };
-
- // Enable A2DP profile.
- when(mBluetoothProfileMonitor.isProfileSupported(eq(BluetoothProfile.A2DP), any()))
- .thenReturn(true);
- mShadowBluetoothAdapter.setProfileConnectionState(BluetoothProfile.A2DP,
- BluetoothProfile.STATE_CONNECTED);
-
- mAudioPoliciesBluetoothRouteController.start(UserHandle.of(0));
- }
-
- @Test
- public void getSelectedRoute_noBluetoothRoutesAvailable_returnsNull() {
- assertThat(mAudioPoliciesBluetoothRouteController.getSelectedRoute()).isNull();
- }
-
- @Test
- public void selectRoute_noBluetoothRoutesAvailable_returnsFalse() {
- assertThat(mAudioPoliciesBluetoothRouteController
- .selectRoute(DEVICE_ADDRESS_UNKNOWN)).isFalse();
- }
-
- @Test
- public void selectRoute_noDeviceWithGivenAddress_returnsFalse() {
- Set<BluetoothDevice> devices = generateFakeBluetoothDevicesSet(
- DEVICE_ADDRESS_SAMPLE_1, DEVICE_ADDRESS_SAMPLE_3);
-
- mShadowBluetoothAdapter.setBondedDevices(devices);
-
- assertThat(mAudioPoliciesBluetoothRouteController
- .selectRoute(DEVICE_ADDRESS_SAMPLE_2)).isFalse();
- }
-
- @Test
- public void selectRoute_deviceIsInDevicesSet_returnsTrue() {
- Set<BluetoothDevice> devices = generateFakeBluetoothDevicesSet(
- DEVICE_ADDRESS_SAMPLE_1, DEVICE_ADDRESS_SAMPLE_2);
-
- mShadowBluetoothAdapter.setBondedDevices(devices);
-
- assertThat(mAudioPoliciesBluetoothRouteController
- .selectRoute(DEVICE_ADDRESS_SAMPLE_1)).isTrue();
- }
-
- @Test
- public void selectRoute_resetSelectedDevice_returnsTrue() {
- Set<BluetoothDevice> devices = generateFakeBluetoothDevicesSet(
- DEVICE_ADDRESS_SAMPLE_1, DEVICE_ADDRESS_SAMPLE_2);
-
- mShadowBluetoothAdapter.setBondedDevices(devices);
-
- mAudioPoliciesBluetoothRouteController.selectRoute(DEVICE_ADDRESS_SAMPLE_1);
- assertThat(mAudioPoliciesBluetoothRouteController.selectRoute(null)).isTrue();
- }
-
- @Test
- public void selectRoute_noSelectedDevice_returnsTrue() {
- Set<BluetoothDevice> devices = generateFakeBluetoothDevicesSet(
- DEVICE_ADDRESS_SAMPLE_1, DEVICE_ADDRESS_SAMPLE_2);
-
- mShadowBluetoothAdapter.setBondedDevices(devices);
-
- assertThat(mAudioPoliciesBluetoothRouteController.selectRoute(null)).isTrue();
- }
-
- @Test
- public void getSelectedRoute_updateRouteFailed_returnsNull() {
- Set<BluetoothDevice> devices = generateFakeBluetoothDevicesSet(
- DEVICE_ADDRESS_SAMPLE_1, DEVICE_ADDRESS_SAMPLE_2);
-
- mShadowBluetoothAdapter.setBondedDevices(devices);
- mAudioPoliciesBluetoothRouteController
- .selectRoute(DEVICE_ADDRESS_SAMPLE_3);
-
- assertThat(mAudioPoliciesBluetoothRouteController.getSelectedRoute()).isNull();
- }
-
- @Test
- public void getSelectedRoute_updateRouteSuccessful_returnsUpdateDevice() {
- Set<BluetoothDevice> devices = generateFakeBluetoothDevicesSet(
- DEVICE_ADDRESS_SAMPLE_1, DEVICE_ADDRESS_SAMPLE_2, DEVICE_ADDRESS_SAMPLE_4);
-
- assertThat(mAudioPoliciesBluetoothRouteController.getSelectedRoute()).isNull();
-
- mShadowBluetoothAdapter.setBondedDevices(devices);
-
- assertThat(mAudioPoliciesBluetoothRouteController
- .selectRoute(DEVICE_ADDRESS_SAMPLE_4)).isTrue();
-
- MediaRoute2Info selectedRoute = mAudioPoliciesBluetoothRouteController.getSelectedRoute();
- assertThat(selectedRoute.getAddress()).isEqualTo(DEVICE_ADDRESS_SAMPLE_4);
- }
-
- @Test
- public void getSelectedRoute_resetSelectedRoute_returnsNull() {
- Set<BluetoothDevice> devices = generateFakeBluetoothDevicesSet(
- DEVICE_ADDRESS_SAMPLE_1, DEVICE_ADDRESS_SAMPLE_2, DEVICE_ADDRESS_SAMPLE_4);
-
- mShadowBluetoothAdapter.setBondedDevices(devices);
-
- // Device is not null now.
- mAudioPoliciesBluetoothRouteController.selectRoute(DEVICE_ADDRESS_SAMPLE_4);
- // Rest the device.
- mAudioPoliciesBluetoothRouteController.selectRoute(null);
-
- assertThat(mAudioPoliciesBluetoothRouteController.getSelectedRoute())
- .isNull();
- }
-
- @Test
- public void getTransferableRoutes_noSelectedRoute_returnsAllBluetoothDevices() {
- String[] addresses = new String[] { DEVICE_ADDRESS_SAMPLE_1,
- DEVICE_ADDRESS_SAMPLE_2, DEVICE_ADDRESS_SAMPLE_4 };
- Set<BluetoothDevice> devices = generateFakeBluetoothDevicesSet(addresses);
- mShadowBluetoothAdapter.setBondedDevices(devices);
-
- // Force route controller to update bluetooth devices list.
- sendBluetoothDevicesChangedBroadcast();
-
- Set<String> transferableDevices = extractAddressesListFrom(
- mAudioPoliciesBluetoothRouteController.getTransferableRoutes());
- assertThat(transferableDevices).containsExactlyElementsIn(addresses);
- }
-
- @Test
- public void getTransferableRoutes_hasSelectedRoute_returnsRoutesWithoutSelectedDevice() {
- String[] addresses = new String[] { DEVICE_ADDRESS_SAMPLE_1,
- DEVICE_ADDRESS_SAMPLE_2, DEVICE_ADDRESS_SAMPLE_4 };
- Set<BluetoothDevice> devices = generateFakeBluetoothDevicesSet(addresses);
- mShadowBluetoothAdapter.setBondedDevices(devices);
-
- // Force route controller to update bluetooth devices list.
- sendBluetoothDevicesChangedBroadcast();
- mAudioPoliciesBluetoothRouteController.selectRoute(DEVICE_ADDRESS_SAMPLE_4);
-
- Set<String> transferableDevices = extractAddressesListFrom(
- mAudioPoliciesBluetoothRouteController.getTransferableRoutes());
- assertThat(transferableDevices).containsExactly(DEVICE_ADDRESS_SAMPLE_1,
- DEVICE_ADDRESS_SAMPLE_2);
- }
-
- @Test
- public void getAllBluetoothRoutes_hasSelectedRoute_returnsAllRoutes() {
- String[] addresses = new String[] { DEVICE_ADDRESS_SAMPLE_1,
- DEVICE_ADDRESS_SAMPLE_2, DEVICE_ADDRESS_SAMPLE_4 };
- Set<BluetoothDevice> devices = generateFakeBluetoothDevicesSet(addresses);
- mShadowBluetoothAdapter.setBondedDevices(devices);
-
- // Force route controller to update bluetooth devices list.
- sendBluetoothDevicesChangedBroadcast();
- mAudioPoliciesBluetoothRouteController.selectRoute(DEVICE_ADDRESS_SAMPLE_4);
-
- Set<String> bluetoothDevices = extractAddressesListFrom(
- mAudioPoliciesBluetoothRouteController.getAllBluetoothRoutes());
- assertThat(bluetoothDevices).containsExactlyElementsIn(addresses);
- }
-
- @Test
- public void updateVolumeForDevice_setVolumeForA2DPTo25_selectedRouteVolumeIsUpdated() {
- String[] addresses = new String[] { DEVICE_ADDRESS_SAMPLE_1,
- DEVICE_ADDRESS_SAMPLE_2, DEVICE_ADDRESS_SAMPLE_4 };
- Set<BluetoothDevice> devices = generateFakeBluetoothDevicesSet(addresses);
- mShadowBluetoothAdapter.setBondedDevices(devices);
-
- // Force route controller to update bluetooth devices list.
- sendBluetoothDevicesChangedBroadcast();
- mAudioPoliciesBluetoothRouteController.selectRoute(DEVICE_ADDRESS_SAMPLE_4);
-
- mAudioPoliciesBluetoothRouteController.updateVolumeForDevices(
- AudioManager.DEVICE_OUT_BLUETOOTH_A2DP, 25);
-
- MediaRoute2Info selectedRoute = mAudioPoliciesBluetoothRouteController.getSelectedRoute();
- assertThat(selectedRoute.getVolume()).isEqualTo(25);
- }
-
- private void sendBluetoothDevicesChangedBroadcast() {
- Intent intent = new Intent(BluetoothA2dp.ACTION_ACTIVE_DEVICE_CHANGED);
- mContext.sendBroadcast(intent);
- }
-
- private static Set<String> extractAddressesListFrom(Collection<MediaRoute2Info> routes) {
- Set<String> addresses = new HashSet<>();
-
- for (MediaRoute2Info route: routes) {
- addresses.add(route.getAddress());
- }
-
- return addresses;
- }
-
- private static Set<BluetoothDevice> generateFakeBluetoothDevicesSet(String... addresses) {
- Set<BluetoothDevice> devices = new HashSet<>();
-
- for (String address: addresses) {
- devices.add(ShadowBluetoothDevice.newInstance(address));
- }
-
- return devices;
- }
-}
diff --git a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageUserStateTest.java b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageUserStateTest.java
index 87a297b..c0c7032 100644
--- a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageUserStateTest.java
+++ b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageUserStateTest.java
@@ -404,6 +404,7 @@
@Test
public void archiveState() {
+ final long currentTimeMillis = System.currentTimeMillis();
PackageUserStateImpl packageUserState = new PackageUserStateImpl();
ArchiveState.ArchiveActivityInfo archiveActivityInfo =
new ArchiveState.ArchiveActivityInfo(
@@ -415,5 +416,23 @@
"installerTitle");
packageUserState.setArchiveState(archiveState);
assertEquals(archiveState, packageUserState.getArchiveState());
+ assertTrue(archiveState.getArchiveTimeMillis() > currentTimeMillis);
+ }
+
+ @Test
+ public void archiveStateWithTimestamp() {
+ final long currentTimeMillis = System.currentTimeMillis();
+ PackageUserStateImpl packageUserState = new PackageUserStateImpl();
+ ArchiveState.ArchiveActivityInfo archiveActivityInfo =
+ new ArchiveState.ArchiveActivityInfo(
+ "appTitle",
+ new ComponentName("pkg", "class"),
+ Path.of("/path1"),
+ Path.of("/path2"));
+ ArchiveState archiveState = new ArchiveState(List.of(archiveActivityInfo),
+ "installerTitle", currentTimeMillis);
+ packageUserState.setArchiveState(archiveState);
+ assertEquals(archiveState, packageUserState.getArchiveState());
+ assertEquals(archiveState.getArchiveTimeMillis(), currentTimeMillis);
}
}
diff --git a/services/tests/mockingservicestests/src/com/android/server/job/controllers/BackgroundJobsControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/job/controllers/BackgroundJobsControllerTest.java
new file mode 100644
index 0000000..cdae8c6
--- /dev/null
+++ b/services/tests/mockingservicestests/src/com/android/server/job/controllers/BackgroundJobsControllerTest.java
@@ -0,0 +1,291 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.job.controllers;
+
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.when;
+import static com.android.server.job.JobSchedulerService.FREQUENT_INDEX;
+import static com.android.server.job.controllers.JobStatus.CONSTRAINT_BACKGROUND_NOT_RESTRICTED;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyLong;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+
+import android.app.ActivityManagerInternal;
+import android.app.AppGlobals;
+import android.app.job.JobInfo;
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.IPackageManager;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManagerInternal;
+import android.net.Uri;
+import android.os.UserHandle;
+import android.platform.test.flag.junit.SetFlagsRule;
+import android.util.ArraySet;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.server.AppStateTracker;
+import com.android.server.AppStateTrackerImpl;
+import com.android.server.LocalServices;
+import com.android.server.job.JobSchedulerService;
+import com.android.server.job.JobStore;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.ArgumentMatchers;
+import org.mockito.Mock;
+import org.mockito.MockitoSession;
+import org.mockito.quality.Strictness;
+
+@RunWith(AndroidJUnit4.class)
+public class BackgroundJobsControllerTest {
+ private static final int CALLING_UID = 1000;
+ private static final String CALLING_PACKAGE = "com.test.calling.package";
+ private static final String SOURCE_PACKAGE = "com.android.frameworks.mockingservicestests";
+ private static final int SOURCE_UID = 10001;
+ private static final int ALTERNATE_UID = 12345;
+ private static final String ALTERNATE_SOURCE_PACKAGE = "com.test.alternate.package";
+ private static final int SOURCE_USER_ID = 0;
+
+ private BackgroundJobsController mBackgroundJobsController;
+ private BroadcastReceiver mStoppedReceiver;
+ private JobStore mJobStore;
+
+ private MockitoSession mMockingSession;
+ @Mock
+ private Context mContext;
+ @Mock
+ private AppStateTrackerImpl mAppStateTrackerImpl;
+ @Mock
+ private IPackageManager mIPackageManager;
+ @Mock
+ private JobSchedulerService mJobSchedulerService;
+ @Mock
+ private PackageManagerInternal mPackageManagerInternal;
+ @Mock
+ private PackageManager mPackageManager;
+
+ @Rule
+ public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
+
+ @Before
+ public void setUp() throws Exception {
+ mMockingSession = mockitoSession()
+ .initMocks(this)
+ .mockStatic(AppGlobals.class)
+ .mockStatic(LocalServices.class)
+ .strictness(Strictness.LENIENT)
+ .startMocking();
+
+ // Called in StateController constructor.
+ when(mJobSchedulerService.getTestableContext()).thenReturn(mContext);
+ when(mJobSchedulerService.getLock()).thenReturn(mJobSchedulerService);
+ // Called in BackgroundJobsController constructor.
+ doReturn(mock(ActivityManagerInternal.class))
+ .when(() -> LocalServices.getService(ActivityManagerInternal.class));
+ doReturn(mAppStateTrackerImpl)
+ .when(() -> LocalServices.getService(AppStateTracker.class));
+ doReturn(mPackageManagerInternal)
+ .when(() -> LocalServices.getService(PackageManagerInternal.class));
+ mJobStore = JobStore.initAndGetForTesting(mContext, mContext.getFilesDir());
+ when(mJobSchedulerService.getJobStore()).thenReturn(mJobStore);
+ // Called in JobStatus constructor.
+ doReturn(mIPackageManager).when(AppGlobals::getPackageManager);
+
+ doReturn(false).when(mAppStateTrackerImpl)
+ .areJobsRestricted(anyInt(), anyString(), anyBoolean());
+ doReturn(true).when(mAppStateTrackerImpl)
+ .isRunAnyInBackgroundAppOpsAllowed(anyInt(), anyString());
+
+ // Initialize real objects.
+ // Capture the listeners.
+ ArgumentCaptor<BroadcastReceiver> receiverCaptor =
+ ArgumentCaptor.forClass(BroadcastReceiver.class);
+
+ when(mContext.getPackageManager()).thenReturn(mPackageManager);
+ mBackgroundJobsController = new BackgroundJobsController(mJobSchedulerService);
+ mBackgroundJobsController.startTrackingLocked();
+
+ verify(mContext).registerReceiverAsUser(receiverCaptor.capture(), any(),
+ ArgumentMatchers.argThat(filter ->
+ filter.hasAction(Intent.ACTION_PACKAGE_RESTARTED)
+ && filter.hasAction(Intent.ACTION_PACKAGE_UNSTOPPED)),
+ any(), any());
+ mStoppedReceiver = receiverCaptor.getValue();
+
+ // Need to do this since we're using a mock JS and not a real object.
+ doReturn(new ArraySet<>(new String[]{SOURCE_PACKAGE}))
+ .when(mJobSchedulerService).getPackagesForUidLocked(SOURCE_UID);
+ doReturn(new ArraySet<>(new String[]{ALTERNATE_SOURCE_PACKAGE}))
+ .when(mJobSchedulerService).getPackagesForUidLocked(ALTERNATE_UID);
+ setPackageUid(ALTERNATE_UID, ALTERNATE_SOURCE_PACKAGE);
+ setPackageUid(SOURCE_UID, SOURCE_PACKAGE);
+ }
+
+ @After
+ public void tearDown() {
+ if (mMockingSession != null) {
+ mMockingSession.finishMocking();
+ }
+ }
+
+ private void setPackageUid(final int uid, final String pkgName) throws Exception {
+ doReturn(uid).when(mIPackageManager)
+ .getPackageUid(eq(pkgName), anyLong(), eq(UserHandle.getUserId(uid)));
+ }
+
+ private void setStoppedState(int uid, String pkgName, boolean stopped) {
+ Intent intent = new Intent(
+ stopped ? Intent.ACTION_PACKAGE_RESTARTED : Intent.ACTION_PACKAGE_UNSTOPPED);
+ intent.putExtra(Intent.EXTRA_UID, uid);
+ intent.setData(Uri.fromParts(IntentFilter.SCHEME_PACKAGE, pkgName, null));
+ mStoppedReceiver.onReceive(mContext, intent);
+ }
+
+ private void setUidBias(int uid, int bias) {
+ int prevBias = mJobSchedulerService.getUidBias(uid);
+ doReturn(bias).when(mJobSchedulerService).getUidBias(uid);
+ synchronized (mBackgroundJobsController.mLock) {
+ mBackgroundJobsController.onUidBiasChangedLocked(uid, prevBias, bias);
+ }
+ }
+
+ private void trackJobs(JobStatus... jobs) {
+ for (JobStatus job : jobs) {
+ mJobStore.add(job);
+ synchronized (mBackgroundJobsController.mLock) {
+ mBackgroundJobsController.maybeStartTrackingJobLocked(job, null);
+ }
+ }
+ }
+
+ private JobInfo.Builder createBaseJobInfoBuilder(String pkgName, int jobId) {
+ final ComponentName cn = spy(new ComponentName(pkgName, "TestBJCJobService"));
+ doReturn("TestBJCJobService").when(cn).flattenToShortString();
+ return new JobInfo.Builder(jobId, cn);
+ }
+
+ private JobStatus createJobStatus(String testTag, String packageName, int callingUid,
+ JobInfo jobInfo) {
+ JobStatus js = JobStatus.createFromJobInfo(
+ jobInfo, callingUid, packageName, SOURCE_USER_ID, "BJCTest", testTag);
+ js.serviceProcessName = "testProcess";
+ // Make sure tests aren't passing just because the default bucket is likely ACTIVE.
+ js.setStandbyBucket(FREQUENT_INDEX);
+ return js;
+ }
+
+ @Test
+ public void testStopped_disabled() {
+ mSetFlagsRule.disableFlags(android.content.pm.Flags.FLAG_STAY_STOPPED);
+ // Scheduled by SOURCE_UID:SOURCE_PACKAGE for itself.
+ JobStatus directJob1 = createJobStatus("testStopped", SOURCE_PACKAGE, SOURCE_UID,
+ createBaseJobInfoBuilder(SOURCE_PACKAGE, 1).build());
+ // Scheduled by ALTERNATE_UID:ALTERNATE_SOURCE_PACKAGE for itself.
+ JobStatus directJob2 = createJobStatus("testStopped",
+ ALTERNATE_SOURCE_PACKAGE, ALTERNATE_UID,
+ createBaseJobInfoBuilder(ALTERNATE_SOURCE_PACKAGE, 2).build());
+ // Scheduled by CALLING_PACKAGE for SOURCE_PACKAGE.
+ JobStatus proxyJob1 = createJobStatus("testStopped", SOURCE_PACKAGE, CALLING_UID,
+ createBaseJobInfoBuilder(CALLING_PACKAGE, 3).build());
+ // Scheduled by CALLING_PACKAGE for ALTERNATE_SOURCE_PACKAGE.
+ JobStatus proxyJob2 = createJobStatus("testStopped",
+ ALTERNATE_SOURCE_PACKAGE, CALLING_UID,
+ createBaseJobInfoBuilder(CALLING_PACKAGE, 4).build());
+
+ trackJobs(directJob1, directJob2, proxyJob1, proxyJob2);
+
+ setStoppedState(ALTERNATE_UID, ALTERNATE_SOURCE_PACKAGE, true);
+ assertTrue(directJob1.isConstraintSatisfied(CONSTRAINT_BACKGROUND_NOT_RESTRICTED));
+ assertFalse(directJob1.isUserBgRestricted());
+ assertTrue(directJob2.isConstraintSatisfied(CONSTRAINT_BACKGROUND_NOT_RESTRICTED));
+ assertFalse(directJob2.isUserBgRestricted());
+ assertTrue(proxyJob1.isConstraintSatisfied(CONSTRAINT_BACKGROUND_NOT_RESTRICTED));
+ assertFalse(proxyJob1.isUserBgRestricted());
+ assertTrue(proxyJob2.isConstraintSatisfied(CONSTRAINT_BACKGROUND_NOT_RESTRICTED));
+ assertFalse(proxyJob2.isUserBgRestricted());
+
+ setStoppedState(ALTERNATE_UID, ALTERNATE_SOURCE_PACKAGE, false);
+ assertTrue(directJob1.isConstraintSatisfied(CONSTRAINT_BACKGROUND_NOT_RESTRICTED));
+ assertFalse(directJob1.isUserBgRestricted());
+ assertTrue(directJob2.isConstraintSatisfied(CONSTRAINT_BACKGROUND_NOT_RESTRICTED));
+ assertFalse(directJob2.isUserBgRestricted());
+ assertTrue(proxyJob1.isConstraintSatisfied(CONSTRAINT_BACKGROUND_NOT_RESTRICTED));
+ assertFalse(proxyJob1.isUserBgRestricted());
+ assertTrue(proxyJob2.isConstraintSatisfied(CONSTRAINT_BACKGROUND_NOT_RESTRICTED));
+ assertFalse(proxyJob2.isUserBgRestricted());
+ }
+
+ @Test
+ public void testStopped_enabled() {
+ mSetFlagsRule.enableFlags(android.content.pm.Flags.FLAG_STAY_STOPPED);
+ // Scheduled by SOURCE_UID:SOURCE_PACKAGE for itself.
+ JobStatus directJob1 = createJobStatus("testStopped", SOURCE_PACKAGE, SOURCE_UID,
+ createBaseJobInfoBuilder(SOURCE_PACKAGE, 1).build());
+ // Scheduled by ALTERNATE_UID:ALTERNATE_SOURCE_PACKAGE for itself.
+ JobStatus directJob2 = createJobStatus("testStopped",
+ ALTERNATE_SOURCE_PACKAGE, ALTERNATE_UID,
+ createBaseJobInfoBuilder(ALTERNATE_SOURCE_PACKAGE, 2).build());
+ // Scheduled by CALLING_PACKAGE for SOURCE_PACKAGE.
+ JobStatus proxyJob1 = createJobStatus("testStopped", SOURCE_PACKAGE, CALLING_UID,
+ createBaseJobInfoBuilder(CALLING_PACKAGE, 3).build());
+ // Scheduled by CALLING_PACKAGE for ALTERNATE_SOURCE_PACKAGE.
+ JobStatus proxyJob2 = createJobStatus("testStopped",
+ ALTERNATE_SOURCE_PACKAGE, CALLING_UID,
+ createBaseJobInfoBuilder(CALLING_PACKAGE, 4).build());
+
+ trackJobs(directJob1, directJob2, proxyJob1, proxyJob2);
+
+ setStoppedState(ALTERNATE_UID, ALTERNATE_SOURCE_PACKAGE, true);
+ assertTrue(directJob1.isConstraintSatisfied(CONSTRAINT_BACKGROUND_NOT_RESTRICTED));
+ assertFalse(directJob1.isUserBgRestricted());
+ assertFalse(directJob2.isConstraintSatisfied(CONSTRAINT_BACKGROUND_NOT_RESTRICTED));
+ assertTrue(directJob2.isUserBgRestricted());
+ assertTrue(proxyJob1.isConstraintSatisfied(CONSTRAINT_BACKGROUND_NOT_RESTRICTED));
+ assertFalse(proxyJob1.isUserBgRestricted());
+ assertFalse(proxyJob2.isConstraintSatisfied(CONSTRAINT_BACKGROUND_NOT_RESTRICTED));
+ assertTrue(proxyJob2.isUserBgRestricted());
+
+ setStoppedState(ALTERNATE_UID, ALTERNATE_SOURCE_PACKAGE, false);
+ assertTrue(directJob1.isConstraintSatisfied(CONSTRAINT_BACKGROUND_NOT_RESTRICTED));
+ assertFalse(directJob1.isUserBgRestricted());
+ assertTrue(directJob2.isConstraintSatisfied(CONSTRAINT_BACKGROUND_NOT_RESTRICTED));
+ assertFalse(directJob2.isUserBgRestricted());
+ assertTrue(proxyJob1.isConstraintSatisfied(CONSTRAINT_BACKGROUND_NOT_RESTRICTED));
+ assertFalse(proxyJob1.isUserBgRestricted());
+ assertTrue(proxyJob2.isConstraintSatisfied(CONSTRAINT_BACKGROUND_NOT_RESTRICTED));
+ assertFalse(proxyJob2.isUserBgRestricted());
+ }
+}
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/PackageArchiverTest.java b/services/tests/mockingservicestests/src/com/android/server/pm/PackageArchiverTest.java
index 3e73aa3..2332988 100644
--- a/services/tests/mockingservicestests/src/com/android/server/pm/PackageArchiverTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/PackageArchiverTest.java
@@ -366,9 +366,17 @@
eq(new VersionedPackage(PACKAGE, PackageManager.VERSION_CODE_HIGHEST)),
eq(CALLER_PACKAGE), eq(DELETE_ARCHIVE | DELETE_KEEP_DATA), eq(mIntentSender),
eq(UserHandle.CURRENT.getIdentifier()), anyInt());
- assertThat(mPackageSetting.readUserState(
- UserHandle.CURRENT.getIdentifier()).getArchiveState()).isEqualTo(
- createArchiveState());
+
+ ArchiveState expectedArchiveState = createArchiveState();
+ ArchiveState actualArchiveState = mPackageSetting.readUserState(
+ UserHandle.CURRENT.getIdentifier()).getArchiveState();
+ assertThat(actualArchiveState.getActivityInfos())
+ .isEqualTo(expectedArchiveState.getActivityInfos());
+ assertThat(actualArchiveState.getInstallerTitle())
+ .isEqualTo(expectedArchiveState.getInstallerTitle());
+ // The timestamps are expected to be different
+ assertThat(actualArchiveState.getArchiveTimeMillis())
+ .isNotEqualTo(expectedArchiveState.getArchiveTimeMillis());
}
@Test
@@ -383,9 +391,17 @@
eq(DELETE_ARCHIVE | DELETE_KEEP_DATA | PackageManager.DELETE_SHOW_DIALOG),
eq(mIntentSender),
eq(UserHandle.CURRENT.getIdentifier()), anyInt());
- assertThat(mPackageSetting.readUserState(
- UserHandle.CURRENT.getIdentifier()).getArchiveState()).isEqualTo(
- createArchiveState());
+
+ ArchiveState expectedArchiveState = createArchiveState();
+ ArchiveState actualArchiveState = mPackageSetting.readUserState(
+ UserHandle.CURRENT.getIdentifier()).getArchiveState();
+ assertThat(actualArchiveState.getActivityInfos())
+ .isEqualTo(expectedArchiveState.getActivityInfos());
+ assertThat(actualArchiveState.getInstallerTitle())
+ .isEqualTo(expectedArchiveState.getInstallerTitle());
+ // The timestamps are expected to be different
+ assertThat(actualArchiveState.getArchiveTimeMillis())
+ .isNotEqualTo(expectedArchiveState.getArchiveTimeMillis());
}
@Test
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityManagerServiceTest.java
index 800350a..57c3a1d 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityManagerServiceTest.java
@@ -21,6 +21,7 @@
import static android.provider.Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN;
import static android.provider.Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_NONE;
import static android.provider.Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW;
+import static android.view.accessibility.Flags.FLAG_CLEANUP_ACCESSIBILITY_WARNING_DIALOG;
import static com.android.internal.accessibility.AccessibilityShortcutController.ACCESSIBILITY_HEARING_AIDS_COMPONENT_NAME;
import static com.android.internal.accessibility.AccessibilityShortcutController.MAGNIFICATION_CONTROLLER_NAME;
@@ -852,6 +853,53 @@
assertThat(lockState.get()).containsExactly(false);
}
+ @Test
+ @RequiresFlagsEnabled(FLAG_CLEANUP_ACCESSIBILITY_WARNING_DIALOG)
+ public void testIsAccessibilityServiceWarningRequired_requiredByDefault() {
+ mockManageAccessibilityGranted(mTestableContext);
+ final AccessibilityServiceInfo info = new AccessibilityServiceInfo();
+ info.setComponentName(COMPONENT_NAME);
+
+ assertThat(mA11yms.isAccessibilityServiceWarningRequired(info)).isTrue();
+ }
+
+ @Test
+ @RequiresFlagsEnabled(FLAG_CLEANUP_ACCESSIBILITY_WARNING_DIALOG)
+ public void testIsAccessibilityServiceWarningRequired_notRequiredIfAlreadyEnabled() {
+ mockManageAccessibilityGranted(mTestableContext);
+ final AccessibilityServiceInfo info_a = new AccessibilityServiceInfo();
+ info_a.setComponentName(COMPONENT_NAME);
+ final AccessibilityServiceInfo info_b = new AccessibilityServiceInfo();
+ info_b.setComponentName(new ComponentName("package_b", "class_b"));
+ final AccessibilityUserState userState = mA11yms.getCurrentUserState();
+ userState.mEnabledServices.clear();
+ userState.mEnabledServices.add(info_b.getComponentName());
+
+ assertThat(mA11yms.isAccessibilityServiceWarningRequired(info_a)).isTrue();
+ assertThat(mA11yms.isAccessibilityServiceWarningRequired(info_b)).isFalse();
+ }
+
+ @Test
+ @RequiresFlagsEnabled(FLAG_CLEANUP_ACCESSIBILITY_WARNING_DIALOG)
+ public void testIsAccessibilityServiceWarningRequired_notRequiredIfExistingShortcut() {
+ mockManageAccessibilityGranted(mTestableContext);
+ final AccessibilityServiceInfo info_a = new AccessibilityServiceInfo();
+ info_a.setComponentName(new ComponentName("package_a", "class_a"));
+ final AccessibilityServiceInfo info_b = new AccessibilityServiceInfo();
+ info_b.setComponentName(new ComponentName("package_b", "class_b"));
+ final AccessibilityServiceInfo info_c = new AccessibilityServiceInfo();
+ info_c.setComponentName(new ComponentName("package_c", "class_c"));
+ final AccessibilityUserState userState = mA11yms.getCurrentUserState();
+ userState.mAccessibilityButtonTargets.clear();
+ userState.mAccessibilityButtonTargets.add(info_b.getComponentName().flattenToString());
+ userState.mAccessibilityShortcutKeyTargets.clear();
+ userState.mAccessibilityShortcutKeyTargets.add(info_c.getComponentName().flattenToString());
+
+ assertThat(mA11yms.isAccessibilityServiceWarningRequired(info_a)).isTrue();
+ assertThat(mA11yms.isAccessibilityServiceWarningRequired(info_b)).isFalse();
+ assertThat(mA11yms.isAccessibilityServiceWarningRequired(info_c)).isFalse();
+ }
+
// Single package intents can trigger multiple PackageMonitor callbacks.
// Collect the state of the lock in a set, since tests only care if calls
// were all locked or all unlocked.
diff --git a/services/tests/servicestests/src/com/android/server/am/AnrTimerTest.java b/services/tests/servicestests/src/com/android/server/am/AnrTimerTest.java
deleted file mode 100644
index 44d6760..0000000
--- a/services/tests/servicestests/src/com/android/server/am/AnrTimerTest.java
+++ /dev/null
@@ -1,389 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.am;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-
-import android.platform.test.annotations.Presubmit;
-
-import android.os.Handler;
-import android.os.Looper;
-import android.os.Message;
-import android.os.SystemClock;
-
-import android.util.Log;
-
-import androidx.test.filters.SmallTest;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-
-import java.util.ArrayList;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
-
-/**
- * Build/Install/Run:
- * atest FrameworksServicesTests:AnrTimerTest
- */
-@SmallTest
-@Presubmit
-public class AnrTimerTest {
-
- /**
- * A handler that allows control over when to dispatch messages and callbacks. Because most
- * Handler methods are final, the only thing this handler can intercept is sending messages.
- * This handler allows unit tests to be written without a need to sleep (which leads to flaky
- * tests).
- *
- * This code was cloned from {@link com.android.systemui.utils.os.FakeHandler}.
- */
- static class TestHandler extends Handler {
-
- private boolean mImmediate = true;
- private ArrayList<Message> mQueuedMessages = new ArrayList<>();
-
- ArrayList<Long> mDelays = new ArrayList<>();
-
- TestHandler(Looper looper, Callback callback, boolean immediate) {
- super(looper, callback);
- mImmediate = immediate;
- }
-
- TestHandler(Looper looper, Callback callback) {
- this(looper, callback, true);
- }
-
- /**
- * Override sendMessageAtTime. In immediate mode, the message is immediately dispatched.
- * In non-immediate mode, the message is enqueued to the real handler. In both cases, the
- * original delay is computed by comparing the target dispatch time with 'now'. This
- * computation is prone to errors if the code experiences delays. The computed time is
- * captured in the mDelays list.
- */
- @Override
- public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
- long delay = uptimeMillis - SystemClock.uptimeMillis();
- mDelays.add(delay);
- if (mImmediate) {
- mQueuedMessages.add(msg);
- dispatchQueuedMessages();
- } else {
- super.sendMessageAtTime(msg, uptimeMillis);
- }
- return true;
- }
-
- void setImmediate(boolean immediate) {
- mImmediate = immediate;
- }
-
- /** Dispatch any messages that have been queued on the calling thread. */
- void dispatchQueuedMessages() {
- ArrayList<Message> messages = new ArrayList<>(mQueuedMessages);
- mQueuedMessages.clear();
- for (Message msg : messages) {
- dispatchMessage(msg);
- }
- }
-
- /**
- * Compare the captured delays with the input array. The comparison is fuzzy because the
- * captured delay (see sendMessageAtTime) is affected by process delays.
- */
- void verifyDelays(long[] r) {
- final long FUZZ = 10;
- assertEquals(r.length, mDelays.size());
- for (int i = 0; i < mDelays.size(); i++) {
- long t = r[i];
- long v = mDelays.get(i);
- assertTrue(v >= t - FUZZ && v <= t + FUZZ);
- }
- }
- }
-
- private Handler mHandler;
- private CountDownLatch mLatch = null;
- private ArrayList<Message> mMessages;
-
- // The commonly used message timeout key.
- private static final int MSG_TIMEOUT = 1;
-
- @Before
- public void setUp() {
- mHandler = new Handler(Looper.getMainLooper(), this::expirationHandler);
- mMessages = new ArrayList<>();
- mLatch = new CountDownLatch(1);
- AnrTimer.resetTimerListForHermeticTest();
- }
-
- @After
- public void tearDown() {
- mHandler = null;
- mMessages = null;
- }
-
- // When a timer expires, set the expiration time in the message and add it to the queue.
- private boolean expirationHandler(Message msg) {
- mMessages.add(Message.obtain(msg));
- mLatch.countDown();
- return false;
- }
-
- // The test argument includes a pid and uid, and a tag. The tag is used to distinguish
- // different message instances.
- private static class TestArg {
- final int pid;
- final int uid;
- final int tag;
-
- TestArg(int pid, int uid, int tag) {
- this.pid = pid;
- this.uid = uid;
- this.tag = tag;
- }
- @Override
- public String toString() {
- return String.format("pid=%d uid=%d tag=%d", pid, uid, tag);
- }
- }
-
- /**
- * An instrumented AnrTimer.
- */
- private class TestAnrTimer extends AnrTimer {
- // A local copy of 'what'. The field in AnrTimer is private.
- final int mWhat;
-
- TestAnrTimer(Handler h, int key, String tag) {
- super(h, key, tag);
- mWhat = key;
- }
-
- TestAnrTimer() {
- this(mHandler, MSG_TIMEOUT, caller());
- }
-
- TestAnrTimer(Handler h, int key, String tag, boolean extend, TestInjector injector) {
- super(h, key, tag, extend, injector);
- mWhat = key;
- }
-
- TestAnrTimer(boolean extend, TestInjector injector) {
- this(mHandler, MSG_TIMEOUT, caller(), extend, injector);
- }
-
- // Return the name of method that called the constructor, assuming that this function is
- // called from inside the constructor. The calling method is used to name the AnrTimer
- // instance so that logs are easier to understand.
- private static String caller() {
- final int n = 4;
- StackTraceElement[] stack = Thread.currentThread().getStackTrace();
- if (stack.length < n+1) return "test";
- return stack[n].getMethodName();
- }
-
- boolean start(TestArg arg, long millis) {
- return start(arg, arg.pid, arg.uid, millis);
- }
-
- int what() {
- return mWhat;
- }
- }
-
- private static class TestTracker extends AnrTimer.CpuTracker {
- long index = 0;
- final int skip;
- TestTracker(int skip) {
- this.skip = skip;
- }
- long delay(int pid) {
- return index++ * skip;
- }
- }
-
- private class TestInjector extends AnrTimer.Injector {
- final boolean mImmediate;
- final AnrTimer.CpuTracker mTracker;
- TestHandler mTestHandler;
-
- TestInjector(int skip, boolean immediate) {
- super(mHandler);
- mTracker = new TestTracker(skip);
- mImmediate = immediate;
- }
-
- TestInjector(int skip) {
- this(skip, true);
- }
-
- @Override
- Handler newHandler(Handler.Callback callback) {
- if (mTestHandler == null) {
- mTestHandler = new TestHandler(mHandler.getLooper(), callback, mImmediate);
- }
- return mTestHandler;
- }
-
- /** Fetch the allocated handle. This does not check for nulls. */
- TestHandler getHandler() {
- return mTestHandler;
- }
-
- /**
- * This override returns the tracker supplied in the constructor. It does not create a
- * new one.
- */
- @Override
- AnrTimer.CpuTracker newTracker() {
- return mTracker;
- }
-
- /** For test purposes, always enable the feature. */
- @Override
- boolean isFeatureEnabled() {
- return true;
- }
- }
-
- // Tests
- // 1. Start a timer and wait for expiration.
- // 2. Start a timer and cancel it. Verify no expiration.
- // 3. Start a timer. Shortly thereafter, restart it. Verify only one expiration.
- // 4. Start a couple of timers. Verify max active timers. Discard one and verify the active
- // count drops by 1. Accept one and verify the active count drops by 1.
-
- @Test
- public void testSimpleTimeout() throws Exception {
- // Create an immediate TestHandler.
- TestInjector injector = new TestInjector(0);
- TestAnrTimer timer = new TestAnrTimer(false, injector);
- TestArg t = new TestArg(1, 1, 3);
- assertTrue(timer.start(t, 10));
- // Delivery is immediate but occurs on a different thread.
- assertTrue(mLatch.await(100, TimeUnit.MILLISECONDS));
- assertEquals(1, mMessages.size());
- Message m = mMessages.get(0);
- assertEquals(timer.what(), m.what);
- assertEquals(t, m.obj);
-
- // Verify that the timer is still present.
- assertEquals(1, AnrTimer.sizeOfTimerList());
- assertTrue(timer.accept(t));
- assertEquals(0, AnrTimer.sizeOfTimerList());
-
- // Verify that the timer no longer exists.
- assertFalse(timer.accept(t));
- }
-
- @Test
- public void testCancel() throws Exception {
- // Create an non-immediate TestHandler.
- TestInjector injector = new TestInjector(0, false);
- TestAnrTimer timer = new TestAnrTimer(false, injector);
-
- Handler handler = injector.getHandler();
- assertNotNull(handler);
- assertTrue(handler instanceof TestHandler);
-
- // The tests that follow check for a 'what' of 0 (zero), which is the message key used
- // by AnrTimer internally.
- TestArg t = new TestArg(1, 1, 3);
- assertFalse(handler.hasMessages(0));
- assertTrue(timer.start(t, 100));
- assertTrue(handler.hasMessages(0));
- assertTrue(timer.cancel(t));
- assertFalse(handler.hasMessages(0));
-
- // Verify that no expiration messages were delivered.
- assertEquals(0, mMessages.size());
- assertEquals(0, AnrTimer.sizeOfTimerList());
- }
-
- @Test
- public void testRestart() throws Exception {
- // Create an non-immediate TestHandler.
- TestInjector injector = new TestInjector(0, false);
- TestAnrTimer timer = new TestAnrTimer(false, injector);
-
- TestArg t = new TestArg(1, 1, 3);
- assertTrue(timer.start(t, 2500));
- assertTrue(timer.start(t, 1000));
-
- // Verify that the test handler saw two timeouts.
- injector.getHandler().verifyDelays(new long[] { 2500, 1000 });
-
- // Verify that there is a single timer. Then cancel it.
- assertEquals(1, AnrTimer.sizeOfTimerList());
- assertTrue(timer.cancel(t));
- assertEquals(0, AnrTimer.sizeOfTimerList());
- }
-
- @Test
- public void testExtendNormal() throws Exception {
- // Create an immediate TestHandler.
- TestInjector injector = new TestInjector(5);
- TestAnrTimer timer = new TestAnrTimer(true, injector);
- TestArg t = new TestArg(1, 1, 3);
- assertTrue(timer.start(t, 10));
-
- assertTrue(mLatch.await(100, TimeUnit.MILLISECONDS));
- assertEquals(1, mMessages.size());
- Message m = mMessages.get(0);
- assertEquals(timer.what(), m.what);
- assertEquals(t, m.obj);
-
- // Verify that the test handler saw two timeouts: one of 10ms and one of 5ms.
- injector.getHandler().verifyDelays(new long[] { 10, 5 });
-
- // Verify that the timer is still present. Then remove it and verify that the list is
- // empty.
- assertEquals(1, AnrTimer.sizeOfTimerList());
- assertTrue(timer.accept(t));
- assertEquals(0, AnrTimer.sizeOfTimerList());
- }
-
- @Test
- public void testExtendOversize() throws Exception {
- // Create an immediate TestHandler.
- TestInjector injector = new TestInjector(25);
- TestAnrTimer timer = new TestAnrTimer(true, injector);
- TestArg t = new TestArg(1, 1, 3);
- assertTrue(timer.start(t, 10));
-
- assertTrue(mLatch.await(100, TimeUnit.MILLISECONDS));
- assertEquals(1, mMessages.size());
- Message m = mMessages.get(0);
- assertEquals(timer.what(), m.what);
- assertEquals(t, m.obj);
-
- // Verify that the test handler saw two timeouts: one of 10ms and one of 10ms.
- injector.getHandler().verifyDelays(new long[] { 10, 10 });
-
- // Verify that the timer is still present. Then remove it and verify that the list is
- // empty.
- assertEquals(1, AnrTimer.sizeOfTimerList());
- assertTrue(timer.accept(t));
- assertEquals(0, AnrTimer.sizeOfTimerList());
- }
-}
diff --git a/services/tests/servicestests/src/com/android/server/audio/AudioDeviceBrokerTest.java b/services/tests/servicestests/src/com/android/server/audio/AudioDeviceBrokerTest.java
index 0d58542..cc3c880 100644
--- a/services/tests/servicestests/src/com/android/server/audio/AudioDeviceBrokerTest.java
+++ b/services/tests/servicestests/src/com/android/server/audio/AudioDeviceBrokerTest.java
@@ -15,14 +15,28 @@
*/
package com.android.server.audio;
+import static android.bluetooth.BluetoothDevice.DEVICE_TYPE_DEFAULT;
+import static android.bluetooth.BluetoothDevice.DEVICE_TYPE_HEADSET;
+import static android.media.audio.Flags.automaticBtDeviceType;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.timeout;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import android.Manifest;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.content.Context;
@@ -40,10 +54,10 @@
import androidx.test.platform.app.InstrumentationRegistry;
import org.junit.After;
-import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.ArgumentMatchers;
import org.mockito.Mock;
import org.mockito.Spy;
@@ -70,6 +84,9 @@
Context context = InstrumentationRegistry.getInstrumentation().getTargetContext();
mMockAudioService = mock(AudioService.class);
+ SettingsAdapter mockAdapter = mock(SettingsAdapter.class);
+ when(mMockAudioService.getSettings()).thenReturn(mockAdapter);
+ when(mockAdapter.getSecureStringForUser(any(), any(), anyInt())).thenReturn("");
when(mMockAudioService.getBluetoothContextualVolumeStream())
.thenReturn(AudioSystem.STREAM_MUSIC);
@@ -82,7 +99,6 @@
BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
mFakeBtDevice = adapter.getRemoteDevice("00:01:02:03:04:05");
- Assert.assertNotNull("invalid null BT device", mFakeBtDevice);
}
@After
@@ -100,15 +116,14 @@
@Test
public void testPostA2dpDeviceConnectionChange() throws Exception {
Log.i(TAG, "starting testPostA2dpDeviceConnectionChange");
- Assert.assertNotNull("invalid null BT device", mFakeBtDevice);
+ assertNotNull("invalid null BT device", mFakeBtDevice);
mAudioDeviceBroker.queueOnBluetoothActiveDeviceChanged(
new AudioDeviceBroker.BtDeviceChangedData(mFakeBtDevice, null,
BluetoothProfileConnectionInfo.createA2dpInfo(true, 1), "testSource"));
Thread.sleep(2 * MAX_MESSAGE_HANDLING_DELAY_MS);
verify(mSpyDevInventory, times(1)).setBluetoothActiveDevice(
- any(AudioDeviceBroker.BtDeviceInfo.class)
- );
+ any(AudioDeviceBroker.BtDeviceInfo.class));
// verify the connection was reported to AudioSystem
checkSingleSystemConnection(mFakeBtDevice);
@@ -212,7 +227,7 @@
AudioManager.DEVICE_OUT_SPEAKER, null);
new AdiDeviceState(AudioDeviceInfo.TYPE_BLUETOOTH_A2DP,
AudioManager.DEVICE_OUT_BLUETOOTH_A2DP, null);
- Assert.fail();
+ fail();
} catch (NullPointerException e) { }
}
@@ -228,11 +243,114 @@
final AdiDeviceState result = AdiDeviceState.fromPersistedString(persistString);
Log.i(TAG, "original:" + devState);
Log.i(TAG, "result :" + result);
- Assert.assertEquals(devState, result);
+ assertEquals(devState, result);
+ }
+
+ @Test
+ public void testIsBluetoothAudioDeviceCategoryFixed() throws Exception {
+ Log.i(TAG, "starting testIsBluetoothAudioDeviceCategoryFixed");
+
+ if (!automaticBtDeviceType()) {
+ Log.i(TAG, "Enable automaticBtDeviceType flag to run the test "
+ + "testIsBluetoothAudioDeviceCategoryFixed");
+ return;
+ }
+ assertNotNull("invalid null BT device", mFakeBtDevice);
+
+ final AdiDeviceState devState = new AdiDeviceState(AudioDeviceInfo.TYPE_BLUETOOTH_A2DP,
+ AudioManager.DEVICE_OUT_BLUETOOTH_A2DP, mFakeBtDevice.getAddress());
+ doReturn(devState).when(mSpyDevInventory).findBtDeviceStateForAddress(
+ mFakeBtDevice.getAddress(), AudioManager.DEVICE_OUT_BLUETOOTH_A2DP);
+ try {
+ InstrumentationRegistry.getInstrumentation().getUiAutomation()
+ .adoptShellPermissionIdentity(Manifest.permission.BLUETOOTH_PRIVILEGED);
+
+ // no metadata set
+ assertTrue(mFakeBtDevice.setMetadata(BluetoothDevice.METADATA_DEVICE_TYPE,
+ DEVICE_TYPE_DEFAULT.getBytes()));
+ assertFalse(
+ mAudioDeviceBroker.isBluetoothAudioDeviceCategoryFixed(
+ mFakeBtDevice.getAddress()));
+
+ // metadata set
+ assertTrue(mFakeBtDevice.setMetadata(BluetoothDevice.METADATA_DEVICE_TYPE,
+ DEVICE_TYPE_HEADSET.getBytes()));
+ assertTrue(mAudioDeviceBroker.isBluetoothAudioDeviceCategoryFixed(
+ mFakeBtDevice.getAddress()));
+ } finally {
+ InstrumentationRegistry.getInstrumentation().getUiAutomation()
+ .dropShellPermissionIdentity();
+ }
+ }
+
+ @Test
+ public void testGetAndUpdateBtAdiDeviceStateCategoryForAddress() throws Exception {
+ Log.i(TAG, "starting testGetAndUpdateBtAdiDeviceStateCategoryForAddress");
+
+ if (!automaticBtDeviceType()) {
+ Log.i(TAG, "Enable automaticBtDeviceType flag to run the test "
+ + "testGetAndUpdateBtAdiDeviceStateCategoryForAddress");
+ return;
+ }
+ assertNotNull("invalid null BT device", mFakeBtDevice);
+
+ final AdiDeviceState devState = new AdiDeviceState(AudioDeviceInfo.TYPE_BLUETOOTH_A2DP,
+ AudioManager.DEVICE_OUT_BLUETOOTH_A2DP, mFakeBtDevice.getAddress());
+ devState.setAudioDeviceCategory(AudioManager.AUDIO_DEVICE_CATEGORY_SPEAKER);
+ doReturn(devState).when(mSpyDevInventory).findBtDeviceStateForAddress(
+ eq(mFakeBtDevice.getAddress()), anyInt());
+ try {
+ InstrumentationRegistry.getInstrumentation().getUiAutomation()
+ .adoptShellPermissionIdentity(Manifest.permission.BLUETOOTH_PRIVILEGED);
+
+ // no metadata set
+ assertTrue(mFakeBtDevice.setMetadata(BluetoothDevice.METADATA_DEVICE_TYPE,
+ DEVICE_TYPE_DEFAULT.getBytes()));
+ assertEquals(AudioManager.AUDIO_DEVICE_CATEGORY_SPEAKER,
+ mAudioDeviceBroker.getAndUpdateBtAdiDeviceStateCategoryForAddress(
+ mFakeBtDevice.getAddress()));
+ verify(mMockAudioService,
+ timeout(MAX_MESSAGE_HANDLING_DELAY_MS).times(0)).onUpdatedAdiDeviceState(
+ eq(devState));
+
+ // metadata set
+ assertTrue(mFakeBtDevice.setMetadata(BluetoothDevice.METADATA_DEVICE_TYPE,
+ DEVICE_TYPE_HEADSET.getBytes()));
+ assertEquals(AudioManager.AUDIO_DEVICE_CATEGORY_HEADPHONES,
+ mAudioDeviceBroker.getAndUpdateBtAdiDeviceStateCategoryForAddress(
+ mFakeBtDevice.getAddress()));
+ verify(mMockAudioService,
+ timeout(MAX_MESSAGE_HANDLING_DELAY_MS)).onUpdatedAdiDeviceState(
+ any());
+ } finally {
+ InstrumentationRegistry.getInstrumentation().getUiAutomation()
+ .dropShellPermissionIdentity();
+ }
+ }
+
+ @Test
+ public void testAddAudioDeviceWithCategoryInInventoryIfNeeded() throws Exception {
+ Log.i(TAG, "starting testAddAudioDeviceWithCategoryInInventoryIfNeeded");
+
+ if (!automaticBtDeviceType()) {
+ Log.i(TAG, "Enable automaticBtDeviceType flag to run the test "
+ + "testAddAudioDeviceWithCategoryInInventoryIfNeeded");
+ return;
+ }
+ assertNotNull("invalid null BT device", mFakeBtDevice);
+
+ mAudioDeviceBroker.addAudioDeviceWithCategoryInInventoryIfNeeded(
+ mFakeBtDevice.getAddress(), AudioManager.AUDIO_DEVICE_CATEGORY_OTHER);
+
+ verify(mMockAudioService,
+ timeout(MAX_MESSAGE_HANDLING_DELAY_MS).atLeast(1)).onUpdatedAdiDeviceState(
+ ArgumentMatchers.argThat(devState -> devState.getAudioDeviceCategory()
+ == AudioManager.AUDIO_DEVICE_CATEGORY_OTHER));
}
private void doTestConnectionDisconnectionReconnection(int delayAfterDisconnection,
boolean mockMediaPlayback, boolean guaranteeSingleConnection) throws Exception {
+ assertNotNull("invalid null BT device", mFakeBtDevice);
when(mMockAudioService.getDeviceForStream(AudioManager.STREAM_MUSIC))
.thenReturn(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP);
when(mMockAudioService.isInCommunication()).thenReturn(false);
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java
index dec89d9..543fa57 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java
@@ -1774,6 +1774,18 @@
}
@Test
+ public void wakeUp_hotPlugIn_invokesDeviceDiscoveryOnce() {
+ mNativeWrapper.setPollAddressResponse(Constants.ADDR_PLAYBACK_2, SendMessageResult.SUCCESS);
+ mHdmiControlService.onWakeUp(HdmiControlService.WAKE_UP_SCREEN_ON);
+ mTestLooper.dispatchAll();
+
+ mNativeWrapper.onHotplugEvent(1, true);
+ mTestLooper.dispatchAll();
+
+ assertThat(mHdmiCecLocalDevicePlayback.getActions(DeviceDiscoveryAction.class)).hasSize(1);
+ }
+
+ @Test
public void hotplugDetectionAction_addDevice() {
int otherPlaybackLogicalAddress = mPlaybackLogicalAddress == Constants.ADDR_PLAYBACK_2
? Constants.ADDR_PLAYBACK_1 : Constants.ADDR_PLAYBACK_2;
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTvTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTvTest.java
index 9e5bea7..a2a8424 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTvTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTvTest.java
@@ -27,6 +27,8 @@
import static com.google.common.truth.Truth.assertThat;
+import static junit.framework.Assert.assertEquals;
+
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
@@ -1720,7 +1722,31 @@
mNativeWrapper.clearResultMessages();
mTestLooper.moveTimeForward(HdmiConfig.TIMEOUT_MS);
mTestLooper.dispatchAll();
+ assertThat(mNativeWrapper.getResultMessages()).doesNotContain(activeSourceFromTv);
+ // Skip the retry.
+ mTestLooper.moveTimeForward(HdmiConfig.TIMEOUT_MS);
+ mTestLooper.dispatchAll();
assertThat(mNativeWrapper.getResultMessages()).contains(activeSourceFromTv);
}
+
+ @Test
+ public void newDeviceConnectedIfOnlyOneGiveOsdNameSent() {
+ mHdmiControlService.getHdmiCecNetwork().clearDeviceList();
+ assertThat(mHdmiControlService.getHdmiCecNetwork().getDeviceInfoList(false))
+ .isEmpty();
+ HdmiCecMessage reportPhysicalAddress =
+ HdmiCecMessageBuilder.buildReportPhysicalAddressCommand(
+ ADDR_PLAYBACK_2, 0x1000, HdmiDeviceInfo.DEVICE_PLAYBACK);
+ HdmiCecMessage giveOsdName = HdmiCecMessageBuilder.buildGiveOsdNameCommand(
+ ADDR_TV, ADDR_PLAYBACK_2);
+ mNativeWrapper.onCecMessage(reportPhysicalAddress);
+ mTestLooper.dispatchAll();
+
+ // Wait until HdmiCecNetwork or NewDeviceAction is in progress
+ mTestLooper.moveTimeForward(HdmiConfig.TIMEOUT_MS);
+
+ // TV should only send <Give Osd Name> once
+ assertEquals(1, Collections.frequency(mNativeWrapper.getResultMessages(), giveOsdName));
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/media/AudioPoliciesDeviceRouteControllerTest.java b/services/tests/servicestests/src/com/android/server/media/AudioPoliciesDeviceRouteControllerTest.java
deleted file mode 100644
index 5aef7a3..0000000
--- a/services/tests/servicestests/src/com/android/server/media/AudioPoliciesDeviceRouteControllerTest.java
+++ /dev/null
@@ -1,247 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.media;
-
-import static com.google.common.truth.Truth.assertThat;
-import static com.google.common.truth.Truth.assertWithMessage;
-
-import static org.mockito.Mockito.anyInt;
-import static org.mockito.Mockito.when;
-
-import android.content.Context;
-import android.content.res.Resources;
-import android.media.AudioManager;
-import android.media.AudioRoutesInfo;
-import android.media.IAudioRoutesObserver;
-import android.media.MediaRoute2Info;
-import android.os.RemoteException;
-
-import com.android.internal.R;
-import com.android.server.audio.AudioService;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-import org.mockito.ArgumentCaptor;
-import org.mockito.Captor;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
-@RunWith(JUnit4.class)
-public class AudioPoliciesDeviceRouteControllerTest {
-
- private static final String ROUTE_NAME_DEFAULT = "default";
- private static final String ROUTE_NAME_DOCK = "dock";
- private static final String ROUTE_NAME_HEADPHONES = "headphones";
-
- private static final int VOLUME_SAMPLE_1 = 25;
-
- @Mock
- private Context mContext;
- @Mock
- private Resources mResources;
- @Mock
- private AudioManager mAudioManager;
- @Mock
- private AudioService mAudioService;
- @Mock
- private DeviceRouteController.OnDeviceRouteChangedListener mOnDeviceRouteChangedListener;
-
- @Captor
- private ArgumentCaptor<IAudioRoutesObserver.Stub> mAudioRoutesObserverCaptor;
-
- private AudioPoliciesDeviceRouteController mController;
-
- private IAudioRoutesObserver.Stub mAudioRoutesObserver;
-
- @Before
- public void setUp() {
- MockitoAnnotations.initMocks(this);
-
- when(mContext.getResources()).thenReturn(mResources);
- when(mResources.getText(anyInt())).thenReturn(ROUTE_NAME_DEFAULT);
-
- // Setting built-in speaker as default speaker.
- AudioRoutesInfo audioRoutesInfo = new AudioRoutesInfo();
- audioRoutesInfo.mainType = AudioRoutesInfo.MAIN_SPEAKER;
- when(mAudioService.startWatchingRoutes(mAudioRoutesObserverCaptor.capture()))
- .thenReturn(audioRoutesInfo);
-
- mController = new AudioPoliciesDeviceRouteController(
- mContext, mAudioManager, mAudioService, mOnDeviceRouteChangedListener);
-
- mAudioRoutesObserver = mAudioRoutesObserverCaptor.getValue();
- }
-
- @Test
- public void getDeviceRoute_noSelectedRoutes_returnsDefaultDevice() {
- MediaRoute2Info route2Info = mController.getSelectedRoute();
-
- assertThat(route2Info.getName()).isEqualTo(ROUTE_NAME_DEFAULT);
- assertThat(route2Info.getType()).isEqualTo(MediaRoute2Info.TYPE_BUILTIN_SPEAKER);
- }
-
- @Test
- public void getDeviceRoute_audioRouteHasChanged_returnsRouteFromAudioService() {
- when(mResources.getText(R.string.default_audio_route_name_headphones))
- .thenReturn(ROUTE_NAME_HEADPHONES);
-
- AudioRoutesInfo audioRoutesInfo = new AudioRoutesInfo();
- audioRoutesInfo.mainType = AudioRoutesInfo.MAIN_HEADPHONES;
- callAudioRoutesObserver(audioRoutesInfo);
-
- MediaRoute2Info route2Info = mController.getSelectedRoute();
- assertThat(route2Info.getName()).isEqualTo(ROUTE_NAME_HEADPHONES);
- assertThat(route2Info.getType()).isEqualTo(MediaRoute2Info.TYPE_WIRED_HEADPHONES);
- }
-
- @Test
- public void getDeviceRoute_selectDevice_returnsSelectedRoute() {
- when(mResources.getText(R.string.default_audio_route_name_dock_speakers))
- .thenReturn(ROUTE_NAME_DOCK);
-
- mController.selectRoute(MediaRoute2Info.TYPE_DOCK);
-
- MediaRoute2Info route2Info = mController.getSelectedRoute();
- assertThat(route2Info.getName()).isEqualTo(ROUTE_NAME_DOCK);
- assertThat(route2Info.getType()).isEqualTo(MediaRoute2Info.TYPE_DOCK);
- }
-
- @Test
- public void getDeviceRoute_hasSelectedAndAudioServiceRoutes_returnsSelectedRoute() {
- when(mResources.getText(R.string.default_audio_route_name_headphones))
- .thenReturn(ROUTE_NAME_HEADPHONES);
- when(mResources.getText(R.string.default_audio_route_name_dock_speakers))
- .thenReturn(ROUTE_NAME_DOCK);
-
- AudioRoutesInfo audioRoutesInfo = new AudioRoutesInfo();
- audioRoutesInfo.mainType = AudioRoutesInfo.MAIN_HEADPHONES;
- callAudioRoutesObserver(audioRoutesInfo);
-
- mController.selectRoute(MediaRoute2Info.TYPE_DOCK);
-
- MediaRoute2Info route2Info = mController.getSelectedRoute();
- assertThat(route2Info.getName()).isEqualTo(ROUTE_NAME_DOCK);
- assertThat(route2Info.getType()).isEqualTo(MediaRoute2Info.TYPE_DOCK);
- }
-
- @Test
- public void getDeviceRoute_unselectRoute_returnsAudioServiceRoute() {
- when(mResources.getText(R.string.default_audio_route_name_headphones))
- .thenReturn(ROUTE_NAME_HEADPHONES);
- when(mResources.getText(R.string.default_audio_route_name_dock_speakers))
- .thenReturn(ROUTE_NAME_DOCK);
-
- mController.selectRoute(MediaRoute2Info.TYPE_DOCK);
-
- AudioRoutesInfo audioRoutesInfo = new AudioRoutesInfo();
- audioRoutesInfo.mainType = AudioRoutesInfo.MAIN_HEADPHONES;
- callAudioRoutesObserver(audioRoutesInfo);
-
- mController.selectRoute(null);
-
- MediaRoute2Info route2Info = mController.getSelectedRoute();
- assertThat(route2Info.getName()).isEqualTo(ROUTE_NAME_HEADPHONES);
- assertThat(route2Info.getType()).isEqualTo(MediaRoute2Info.TYPE_WIRED_HEADPHONES);
- }
-
- @Test
- public void getDeviceRoute_selectRouteFails_returnsAudioServiceRoute() {
- when(mResources.getText(R.string.default_audio_route_name_headphones))
- .thenReturn(ROUTE_NAME_HEADPHONES);
-
- AudioRoutesInfo audioRoutesInfo = new AudioRoutesInfo();
- audioRoutesInfo.mainType = AudioRoutesInfo.MAIN_HEADPHONES;
- callAudioRoutesObserver(audioRoutesInfo);
-
- mController.selectRoute(MediaRoute2Info.TYPE_BLUETOOTH_A2DP);
-
- MediaRoute2Info route2Info = mController.getSelectedRoute();
- assertThat(route2Info.getName()).isEqualTo(ROUTE_NAME_HEADPHONES);
- assertThat(route2Info.getType()).isEqualTo(MediaRoute2Info.TYPE_WIRED_HEADPHONES);
- }
-
- @Test
- public void selectRoute_selectWiredRoute_returnsTrue() {
- assertThat(mController.selectRoute(MediaRoute2Info.TYPE_HDMI)).isTrue();
- }
-
- @Test
- public void selectRoute_selectBluetoothRoute_returnsFalse() {
- assertThat(mController.selectRoute(MediaRoute2Info.TYPE_BLUETOOTH_A2DP)).isFalse();
- }
-
- @Test
- public void selectRoute_unselectRoute_returnsTrue() {
- assertThat(mController.selectRoute(null)).isTrue();
- }
-
- @Test
- public void updateVolume_noSelectedRoute_deviceRouteVolumeChanged() {
- when(mResources.getText(R.string.default_audio_route_name_headphones))
- .thenReturn(ROUTE_NAME_HEADPHONES);
-
- AudioRoutesInfo audioRoutesInfo = new AudioRoutesInfo();
- audioRoutesInfo.mainType = AudioRoutesInfo.MAIN_HEADPHONES;
- callAudioRoutesObserver(audioRoutesInfo);
-
- mController.updateVolume(VOLUME_SAMPLE_1);
-
- MediaRoute2Info route2Info = mController.getSelectedRoute();
- assertThat(route2Info.getType()).isEqualTo(MediaRoute2Info.TYPE_WIRED_HEADPHONES);
- assertThat(route2Info.getVolume()).isEqualTo(VOLUME_SAMPLE_1);
- }
-
- @Test
- public void updateVolume_connectSelectedRouteLater_selectedRouteVolumeChanged() {
- when(mResources.getText(R.string.default_audio_route_name_headphones))
- .thenReturn(ROUTE_NAME_HEADPHONES);
- when(mResources.getText(R.string.default_audio_route_name_dock_speakers))
- .thenReturn(ROUTE_NAME_DOCK);
-
- AudioRoutesInfo audioRoutesInfo = new AudioRoutesInfo();
- audioRoutesInfo.mainType = AudioRoutesInfo.MAIN_HEADPHONES;
- callAudioRoutesObserver(audioRoutesInfo);
-
- mController.updateVolume(VOLUME_SAMPLE_1);
-
- mController.selectRoute(MediaRoute2Info.TYPE_DOCK);
-
- MediaRoute2Info route2Info = mController.getSelectedRoute();
- assertThat(route2Info.getType()).isEqualTo(MediaRoute2Info.TYPE_DOCK);
- assertThat(route2Info.getVolume()).isEqualTo(VOLUME_SAMPLE_1);
- }
-
- /**
- * Simulates {@link IAudioRoutesObserver.Stub#dispatchAudioRoutesChanged(AudioRoutesInfo)}
- * from {@link AudioService}. This happens when there is a wired route change,
- * like a wired headset being connected.
- *
- * @param audioRoutesInfo updated state of connected wired device
- */
- private void callAudioRoutesObserver(AudioRoutesInfo audioRoutesInfo) {
- try {
- // this is a captured observer implementation
- // from WiredRoutesController's AudioService#startWatchingRoutes call
- mAudioRoutesObserver.dispatchAudioRoutesChanged(audioRoutesInfo);
- } catch (RemoteException exception) {
- // Should not happen since the object is mocked.
- assertWithMessage("An unexpected RemoteException happened.").fail();
- }
- }
-}
diff --git a/services/tests/servicestests/src/com/android/server/media/DeviceRouteControllerTest.java b/services/tests/servicestests/src/com/android/server/media/DeviceRouteControllerTest.java
index 14b121d..0961b7d 100644
--- a/services/tests/servicestests/src/com/android/server/media/DeviceRouteControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/media/DeviceRouteControllerTest.java
@@ -19,6 +19,7 @@
import static com.android.media.flags.Flags.FLAG_ENABLE_AUDIO_POLICIES_DEVICE_AND_BLUETOOTH_CONTROLLER;
import android.content.Context;
+import android.os.Looper;
import android.platform.test.annotations.RequiresFlagsDisabled;
import android.platform.test.annotations.RequiresFlagsEnabled;
import android.platform.test.flag.junit.CheckFlagsRule;
@@ -56,7 +57,8 @@
@RequiresFlagsDisabled(FLAG_ENABLE_AUDIO_POLICIES_DEVICE_AND_BLUETOOTH_CONTROLLER)
public void createInstance_audioPoliciesFlagIsDisabled_createsLegacyController() {
DeviceRouteController deviceRouteController =
- DeviceRouteController.createInstance(mContext, mOnDeviceRouteChangedListener);
+ DeviceRouteController.createInstance(
+ mContext, Looper.getMainLooper(), mOnDeviceRouteChangedListener);
Truth.assertThat(deviceRouteController).isInstanceOf(LegacyDeviceRouteController.class);
}
@@ -65,7 +67,8 @@
@RequiresFlagsEnabled(FLAG_ENABLE_AUDIO_POLICIES_DEVICE_AND_BLUETOOTH_CONTROLLER)
public void createInstance_audioPoliciesFlagIsEnabled_createsAudioPoliciesController() {
DeviceRouteController deviceRouteController =
- DeviceRouteController.createInstance(mContext, mOnDeviceRouteChangedListener);
+ DeviceRouteController.createInstance(
+ mContext, Looper.getMainLooper(), mOnDeviceRouteChangedListener);
Truth.assertThat(deviceRouteController)
.isInstanceOf(AudioPoliciesDeviceRouteController.class);
diff --git a/services/tests/servicestests/src/com/android/server/utils/AnrTimerTest.java b/services/tests/servicestests/src/com/android/server/utils/AnrTimerTest.java
new file mode 100644
index 0000000..330dbb8
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/utils/AnrTimerTest.java
@@ -0,0 +1,203 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.utils;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+
+import android.platform.test.annotations.Presubmit;
+import androidx.test.filters.SmallTest;
+
+import com.android.internal.annotations.GuardedBy;
+
+import org.junit.Test;
+
+import java.util.ArrayList;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+@SmallTest
+@Presubmit
+public class AnrTimerTest {
+
+ // The commonly used message timeout key.
+ private static final int MSG_TIMEOUT = 1;
+
+ // The test argument includes a pid and uid, and a tag. The tag is used to distinguish
+ // different message instances. Additional fields (like what) capture delivery information
+ // that is checked by the test.
+ private static class TestArg {
+ final int pid;
+ final int uid;
+ int what;
+
+ TestArg(int pid, int uid) {
+ this.pid = pid;
+ this.uid = uid;
+ this.what = 0;
+ }
+ }
+
+ /**
+ * The test handler is a self-contained object for a single test.
+ */
+ private static class Helper {
+ final Object mLock = new Object();
+
+ final Handler mHandler;
+ final CountDownLatch mLatch;
+ @GuardedBy("mLock")
+ final ArrayList<TestArg> mMessages;
+
+ Helper(int expect) {
+ mHandler = new Handler(Looper.getMainLooper(), this::expirationHandler);
+ mMessages = new ArrayList<>();
+ mLatch = new CountDownLatch(expect);
+ }
+
+ /**
+ * When a timer expires, the object must be a TestArg. Update the TestArg with
+ * expiration metadata and save it.
+ */
+ private boolean expirationHandler(Message msg) {
+ synchronized (mLock) {
+ TestArg arg = (TestArg) msg.obj;
+ arg.what = msg.what;
+ mMessages.add(arg);
+ mLatch.countDown();
+ return false;
+ }
+ }
+
+ boolean await(long timeout) throws InterruptedException {
+ // No need to synchronize, as the CountDownLatch is already thread-safe.
+ return mLatch.await(timeout, TimeUnit.MILLISECONDS);
+ }
+
+ /**
+ * Fetch the received messages. Fail if the count of received messages is other than the
+ * expected count.
+ */
+ TestArg[] messages(int expected) {
+ synchronized (mLock) {
+ assertEquals(expected, mMessages.size());
+ return mMessages.toArray(new TestArg[expected]);
+ }
+ }
+ }
+
+ /**
+ * An instrumented AnrTimer.
+ */
+ private static class TestAnrTimer extends AnrTimer<TestArg> {
+ private TestAnrTimer(Handler h, int key, String tag) {
+ super(h, key, tag);
+ }
+
+ TestAnrTimer(Helper helper) {
+ this(helper.mHandler, MSG_TIMEOUT, caller());
+ }
+
+ void start(TestArg arg, long millis) {
+ start(arg, arg.pid, arg.uid, millis);
+ }
+
+ // Return the name of method that called the constructor, assuming that this function is
+ // called from inside the constructor. The calling method is used to name the AnrTimer
+ // instance so that logs are easier to understand.
+ private static String caller() {
+ final int n = 4;
+ StackTraceElement[] stack = Thread.currentThread().getStackTrace();
+ if (stack.length < n+1) return "test";
+ return stack[n].getMethodName();
+ }
+ }
+
+ void validate(TestArg expected, TestArg actual) {
+ assertEquals(expected, actual);
+ assertEquals(actual.what, MSG_TIMEOUT);
+ }
+
+
+ /**
+ * Verify that a simple expiration succeeds. The timer is started for 10ms. The test
+ * procedure waits 5s for the expiration message, but under correct operation, the test will
+ * only take 10ms
+ */
+ @Test
+ public void testSimpleTimeout() throws Exception {
+ Helper helper = new Helper(1);
+ TestAnrTimer timer = new TestAnrTimer(helper);
+ TestArg t = new TestArg(1, 1);
+ timer.start(t, 10);
+ // Delivery is immediate but occurs on a different thread.
+ assertTrue(helper.await(5000));
+ TestArg[] result = helper.messages(1);
+ validate(t, result[0]);
+ }
+
+ /**
+ * Verify that if three timers are scheduled, they are delivered in time order.
+ */
+ @Test
+ public void testMultipleTimers() throws Exception {
+ // Expect three messages.
+ Helper helper = new Helper(3);
+ TestAnrTimer timer = new TestAnrTimer(helper);
+ TestArg t1 = new TestArg(1, 1);
+ TestArg t2 = new TestArg(1, 2);
+ TestArg t3 = new TestArg(1, 3);
+ timer.start(t1, 50);
+ timer.start(t2, 60);
+ timer.start(t3, 40);
+ // Delivery is immediate but occurs on a different thread.
+ assertTrue(helper.await(5000));
+ TestArg[] result = helper.messages(3);
+ validate(t3, result[0]);
+ validate(t1, result[1]);
+ validate(t2, result[2]);
+ }
+
+ /**
+ * Verify that a canceled timer is not delivered.
+ */
+ @Test
+ public void testCancelTimer() throws Exception {
+ // Expect two messages.
+ Helper helper = new Helper(2);
+ TestAnrTimer timer = new TestAnrTimer(helper);
+ TestArg t1 = new TestArg(1, 1);
+ TestArg t2 = new TestArg(1, 2);
+ TestArg t3 = new TestArg(1, 3);
+ timer.start(t1, 50);
+ timer.start(t2, 60);
+ timer.start(t3, 40);
+ // Briefly pause.
+ assertFalse(helper.await(10));
+ timer.cancel(t1);
+ // Delivery is immediate but occurs on a different thread.
+ assertTrue(helper.await(5000));
+ TestArg[] result = helper.messages(2);
+ validate(t3, result[0]);
+ validate(t2, result[1]);
+ }
+}
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/DefaultDeviceEffectsApplierTest.java b/services/tests/uiservicestests/src/com/android/server/notification/DefaultDeviceEffectsApplierTest.java
new file mode 100644
index 0000000..5febd02
--- /dev/null
+++ b/services/tests/uiservicestests/src/com/android/server/notification/DefaultDeviceEffectsApplierTest.java
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.notification;
+
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyZeroInteractions;
+
+import android.app.UiModeManager;
+import android.app.WallpaperManager;
+import android.hardware.display.ColorDisplayManager;
+import android.os.PowerManager;
+import android.platform.test.flag.junit.SetFlagsRule;
+import android.service.notification.ZenDeviceEffects;
+import android.testing.TestableContext;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@RunWith(AndroidJUnit4.class)
+public class DefaultDeviceEffectsApplierTest {
+
+ @Rule
+ public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
+
+ private TestableContext mContext;
+ private DefaultDeviceEffectsApplier mApplier;
+ @Mock PowerManager mPowerManager;
+ @Mock ColorDisplayManager mColorDisplayManager;
+ @Mock UiModeManager mUiModeManager;
+ @Mock WallpaperManager mWallpaperManager;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ mContext = new TestableContext(InstrumentationRegistry.getContext(), null);
+ mContext.addMockSystemService(PowerManager.class, mPowerManager);
+ mContext.addMockSystemService(ColorDisplayManager.class, mColorDisplayManager);
+ mContext.addMockSystemService(UiModeManager.class, mUiModeManager);
+ mContext.addMockSystemService(WallpaperManager.class, mWallpaperManager);
+
+ mApplier = new DefaultDeviceEffectsApplier(mContext);
+ }
+
+ @Test
+ public void apply_appliesEffects() {
+ mSetFlagsRule.enableFlags(android.app.Flags.FLAG_MODES_API);
+
+ ZenDeviceEffects effects = new ZenDeviceEffects.Builder()
+ .setShouldSuppressAmbientDisplay(true)
+ .setShouldDimWallpaper(true)
+ .setShouldDisplayGrayscale(true)
+ .setShouldUseNightMode(true)
+ .build();
+ mApplier.apply(effects);
+
+ verify(mPowerManager).suppressAmbientDisplay(anyString(), eq(true));
+ verify(mColorDisplayManager).setSaturationLevel(eq(0));
+ verify(mWallpaperManager).setWallpaperDimAmount(eq(0.6f));
+ verifyZeroInteractions(mUiModeManager); // Coming later; adding now so test fails then. :)
+ }
+
+ @Test
+ public void apply_removesEffects() {
+ mSetFlagsRule.enableFlags(android.app.Flags.FLAG_MODES_API);
+
+ ZenDeviceEffects noEffects = new ZenDeviceEffects.Builder().build();
+ mApplier.apply(noEffects);
+
+ verify(mPowerManager).suppressAmbientDisplay(anyString(), eq(false));
+ verify(mColorDisplayManager).setSaturationLevel(eq(100));
+ verify(mWallpaperManager).setWallpaperDimAmount(eq(0.0f));
+ verifyZeroInteractions(mUiModeManager);
+ }
+
+ @Test
+ public void apply_missingSomeServices_okay() {
+ mSetFlagsRule.enableFlags(android.app.Flags.FLAG_MODES_API);
+ mContext.addMockSystemService(ColorDisplayManager.class, null);
+ mContext.addMockSystemService(WallpaperManager.class, null);
+
+ ZenDeviceEffects effects = new ZenDeviceEffects.Builder()
+ .setShouldSuppressAmbientDisplay(true)
+ .setShouldDimWallpaper(true)
+ .setShouldDisplayGrayscale(true)
+ .setShouldUseNightMode(true)
+ .build();
+ mApplier.apply(effects);
+
+ verify(mPowerManager).suppressAmbientDisplay(anyString(), eq(true));
+ // (And no crash from missing services).
+ }
+}
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
index b1fdec9..ef6fced 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
@@ -77,9 +77,9 @@
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.notNull;
import static org.mockito.Mockito.reset;
-import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.when;
import static org.mockito.Mockito.withSettings;
@@ -112,6 +112,7 @@
import android.provider.Settings;
import android.provider.Settings.Global;
import android.service.notification.Condition;
+import android.service.notification.DeviceEffectsApplier;
import android.service.notification.ZenDeviceEffects;
import android.service.notification.ZenModeConfig;
import android.service.notification.ZenModeConfig.ScheduleInfo;
@@ -188,8 +189,10 @@
.appendPath("test")
.build();
- private static final Condition CONDITION = new Condition(CONDITION_ID, "",
+ private static final Condition CONDITION_TRUE = new Condition(CONDITION_ID, "",
Condition.STATE_TRUE);
+ private static final Condition CONDITION_FALSE = new Condition(CONDITION_ID, "",
+ Condition.STATE_FALSE);
private static final String TRIGGER_DESC = "Every Night, 10pm to 6am";
private static final int TYPE = TYPE_BEDTIME;
private static final boolean ALLOW_MANUAL = true;
@@ -201,6 +204,7 @@
= NotificationManager.INTERRUPTION_FILTER_ALARMS;
private static final boolean ENABLED = true;
private static final int CREATION_TIME = 123;
+ private static final ZenDeviceEffects NO_EFFECTS = new ZenDeviceEffects.Builder().build();
@Rule
public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
@@ -212,6 +216,7 @@
private TestableLooper mTestableLooper;
private ZenModeHelper mZenModeHelper;
private ContentResolver mContentResolver;
+ @Mock DeviceEffectsApplier mDeviceEffectsApplier;
@Mock AppOpsManager mAppOps;
TestableFlagResolver mTestFlagResolver = new TestableFlagResolver();
ZenModeEventLoggerFake mZenModeEventLogger;
@@ -238,8 +243,9 @@
when(mPackageManager.getResourcesForApplication(anyString())).thenReturn(
mResources);
- when(mContext.getSystemService(AppOpsManager.class)).thenReturn(mAppOps);
- when(mContext.getSystemService(NotificationManager.class)).thenReturn(mNotificationManager);
+ mContext.addMockSystemService(AppOpsManager.class, mAppOps);
+ mContext.addMockSystemService(NotificationManager.class, mNotificationManager);
+
mConditionProviders = new ConditionProviders(mContext, new UserProfiles(),
AppGlobals.getPackageManager());
mConditionProviders.addSystemProvider(new CountdownConditionProvider());
@@ -609,7 +615,7 @@
// and we're setting zen mode on
Settings.Secure.putInt(mContentResolver, Settings.Secure.SHOW_ZEN_UPGRADE_NOTIFICATION, 1);
Settings.Secure.putInt(mContentResolver, Settings.Secure.ZEN_SETTINGS_UPDATED, 0);
- mZenModeHelper.mIsBootComplete = true;
+ mZenModeHelper.mIsSystemServicesReady = true;
mZenModeHelper.mConsolidatedPolicy = new Policy(0, 0, 0, 0, 0, 0);
mZenModeHelper.setZenModeSetting(ZEN_MODE_IMPORTANT_INTERRUPTIONS);
@@ -624,7 +630,7 @@
// doesn't show upgrade notification if stored settings says don't show
Settings.Secure.putInt(mContentResolver, Settings.Secure.SHOW_ZEN_UPGRADE_NOTIFICATION, 0);
Settings.Secure.putInt(mContentResolver, Settings.Secure.ZEN_SETTINGS_UPDATED, 0);
- mZenModeHelper.mIsBootComplete = true;
+ mZenModeHelper.mIsSystemServicesReady = true;
mZenModeHelper.setZenModeSetting(ZEN_MODE_IMPORTANT_INTERRUPTIONS);
verify(mNotificationManager, never()).notify(eq(ZenModeHelper.TAG),
@@ -636,7 +642,7 @@
// doesn't show upgrade notification since zen was already updated
Settings.Secure.putInt(mContentResolver, Settings.Secure.SHOW_ZEN_UPGRADE_NOTIFICATION, 0);
Settings.Secure.putInt(mContentResolver, Settings.Secure.ZEN_SETTINGS_UPDATED, 1);
- mZenModeHelper.mIsBootComplete = true;
+ mZenModeHelper.mIsSystemServicesReady = true;
mZenModeHelper.setZenModeSetting(ZEN_MODE_IMPORTANT_INTERRUPTIONS);
verify(mNotificationManager, never()).notify(eq(ZenModeHelper.TAG),
@@ -3060,7 +3066,7 @@
rule.configurationActivity = CONFIG_ACTIVITY;
rule.component = OWNER;
rule.conditionId = CONDITION_ID;
- rule.condition = CONDITION;
+ rule.condition = CONDITION_TRUE;
rule.enabled = ENABLED;
rule.creationTime = 123;
rule.id = "id";
@@ -3350,6 +3356,84 @@
}
@Test
+ public void testDeviceEffects_applied() {
+ mSetFlagsRule.enableFlags(android.app.Flags.FLAG_MODES_API);
+ mZenModeHelper.setDeviceEffectsApplier(mDeviceEffectsApplier);
+
+ ZenDeviceEffects effects = new ZenDeviceEffects.Builder()
+ .setShouldSuppressAmbientDisplay(true)
+ .setShouldDimWallpaper(true)
+ .build();
+ String ruleId = addRuleWithEffects(effects);
+ verify(mDeviceEffectsApplier, never()).apply(any());
+
+ mZenModeHelper.setAutomaticZenRuleState(ruleId, CONDITION_TRUE, CUSTOM_PKG_UID, false);
+ mTestableLooper.processAllMessages();
+
+ verify(mDeviceEffectsApplier).apply(eq(effects));
+ }
+
+ @Test
+ public void testDeviceEffects_onDeactivateRule_applied() {
+ mSetFlagsRule.enableFlags(android.app.Flags.FLAG_MODES_API);
+ mZenModeHelper.setDeviceEffectsApplier(mDeviceEffectsApplier);
+
+ ZenDeviceEffects zde = new ZenDeviceEffects.Builder().setShouldUseNightMode(true).build();
+ String ruleId = addRuleWithEffects(zde);
+ mZenModeHelper.setAutomaticZenRuleState(ruleId, CONDITION_TRUE, CUSTOM_PKG_UID, false);
+ mTestableLooper.processAllMessages();
+ verify(mDeviceEffectsApplier).apply(eq(zde));
+
+ mZenModeHelper.setAutomaticZenRuleState(ruleId, CONDITION_FALSE, CUSTOM_PKG_UID, false);
+ mTestableLooper.processAllMessages();
+
+ verify(mDeviceEffectsApplier).apply(eq(NO_EFFECTS));
+ }
+
+ @Test
+ public void testDeviceEffects_noChangeToConsolidatedEffects_notApplied() {
+ mSetFlagsRule.enableFlags(android.app.Flags.FLAG_MODES_API);
+ mZenModeHelper.setDeviceEffectsApplier(mDeviceEffectsApplier);
+
+ ZenDeviceEffects zde = new ZenDeviceEffects.Builder().setShouldUseNightMode(true).build();
+ String ruleId = addRuleWithEffects(zde);
+ mZenModeHelper.setAutomaticZenRuleState(ruleId, CONDITION_TRUE, CUSTOM_PKG_UID, false);
+ mTestableLooper.processAllMessages();
+ verify(mDeviceEffectsApplier).apply(eq(zde));
+
+ // Now create and activate a second rule that doesn't add any more effects.
+ String secondRuleId = addRuleWithEffects(zde);
+ mZenModeHelper.setAutomaticZenRuleState(secondRuleId, CONDITION_TRUE, CUSTOM_PKG_UID,
+ false);
+ mTestableLooper.processAllMessages();
+
+ verifyNoMoreInteractions(mDeviceEffectsApplier);
+ }
+
+ @Test
+ public void testDeviceEffects_activeBeforeApplierProvided_appliedWhenProvided() {
+ mSetFlagsRule.enableFlags(android.app.Flags.FLAG_MODES_API);
+
+ ZenDeviceEffects zde = new ZenDeviceEffects.Builder().setShouldUseNightMode(true).build();
+ String ruleId = addRuleWithEffects(zde);
+ verify(mDeviceEffectsApplier, never()).apply(any());
+
+ mZenModeHelper.setAutomaticZenRuleState(ruleId, CONDITION_TRUE, CUSTOM_PKG_UID, false);
+ mTestableLooper.processAllMessages();
+ verify(mDeviceEffectsApplier, never()).apply(any());
+
+ mZenModeHelper.setDeviceEffectsApplier(mDeviceEffectsApplier);
+ verify(mDeviceEffectsApplier).apply(eq(zde));
+ }
+
+ private String addRuleWithEffects(ZenDeviceEffects effects) {
+ AutomaticZenRule rule = new AutomaticZenRule.Builder("Test", CONDITION_ID)
+ .setDeviceEffects(effects)
+ .build();
+ return mZenModeHelper.addAutomaticZenRule("pkg", rule, "", CUSTOM_PKG_UID, FROM_APP);
+ }
+
+ @Test
public void applyGlobalZenModeAsImplicitZenRule_createsImplicitRuleAndActivatesIt() {
mSetFlagsRule.enableFlags(android.app.Flags.FLAG_MODES_API);
mZenModeHelper.mConfig.automaticRules.clear();
diff --git a/services/tests/wmtests/AndroidManifest.xml b/services/tests/wmtests/AndroidManifest.xml
index a8d3fa1..c3074bb 100644
--- a/services/tests/wmtests/AndroidManifest.xml
+++ b/services/tests/wmtests/AndroidManifest.xml
@@ -99,7 +99,7 @@
android:theme="@style/WhiteBackgroundTheme"
android:exported="true"/>
- <activity android:name="com.android.server.wm.TrustedPresentationListenerTest$TestActivity"
+ <activity android:name="com.android.server.wm.TrustedPresentationCallbackTest$TestActivity"
android:exported="true"
android:showWhenLocked="true"
android:turnScreenOn="true" />
diff --git a/services/tests/wmtests/src/com/android/server/policy/ShortcutKeyTestBase.java b/services/tests/wmtests/src/com/android/server/policy/ShortcutKeyTestBase.java
index ab35da6..9cdec25 100644
--- a/services/tests/wmtests/src/com/android/server/policy/ShortcutKeyTestBase.java
+++ b/services/tests/wmtests/src/com/android/server/policy/ShortcutKeyTestBase.java
@@ -64,6 +64,7 @@
@Rule public FakeSettingsProviderRule mSettingsProviderRule = FakeSettingsProvider.rule();
TestPhoneWindowManager mPhoneWindowManager;
+ DispatchedKeyHandler mDispatchedKeyHandler = event -> false;
final Context mContext = spy(getInstrumentation().getTargetContext());
/** Modifier key to meta state */
@@ -102,6 +103,10 @@
mPhoneWindowManager = new TestPhoneWindowManager(mContext, supportSettingsUpdate);
}
+ protected final void setDispatchedKeyHandler(DispatchedKeyHandler keyHandler) {
+ mDispatchedKeyHandler = keyHandler;
+ }
+
@After
public void tearDown() {
if (mPhoneWindowManager != null) {
@@ -174,9 +179,20 @@
int actions = mPhoneWindowManager.interceptKeyBeforeQueueing(keyEvent);
if ((actions & ACTION_PASS_TO_USER) != 0) {
if (0 == mPhoneWindowManager.interceptKeyBeforeDispatching(keyEvent)) {
- mPhoneWindowManager.dispatchUnhandledKey(keyEvent);
+ if (!mDispatchedKeyHandler.onKeyDispatched(keyEvent)) {
+ mPhoneWindowManager.dispatchUnhandledKey(keyEvent);
+ }
}
}
mPhoneWindowManager.dispatchAllPendingEvents();
}
+
+ interface DispatchedKeyHandler {
+ /**
+ * Called when a key event is dispatched to app.
+ *
+ * @return true if the event is consumed by app.
+ */
+ boolean onKeyDispatched(KeyEvent event);
+ }
}
diff --git a/services/tests/wmtests/src/com/android/server/policy/StemKeyGestureTests.java b/services/tests/wmtests/src/com/android/server/policy/StemKeyGestureTests.java
index 912e1d3d..f7ad2a8 100644
--- a/services/tests/wmtests/src/com/android/server/policy/StemKeyGestureTests.java
+++ b/services/tests/wmtests/src/com/android/server/policy/StemKeyGestureTests.java
@@ -97,6 +97,35 @@
}
@Test
+ public void stemSingleKey_appHasOverridePermission_consumedByApp_notOpenAllApp() {
+ overrideBehavior(STEM_PRIMARY_BUTTON_SHORT_PRESS, SHORT_PRESS_PRIMARY_LAUNCH_ALL_APPS);
+ setUpPhoneWindowManager(/* supportSettingsUpdate= */ true);
+ mPhoneWindowManager.overrideStartActivity();
+ mPhoneWindowManager.setKeyguardServiceDelegateIsShowing(false);
+ mPhoneWindowManager.overrideIsUserSetupComplete(true);
+ mPhoneWindowManager.overrideFocusedWindowButtonOverridePermission(true);
+ setDispatchedKeyHandler(keyEvent -> true);
+
+ sendKey(KEYCODE_STEM_PRIMARY);
+
+ mPhoneWindowManager.assertNotOpenAllAppView();
+ }
+
+ @Test
+ public void stemSingleKey_appHasOverridePermission_notConsumedByApp_openAllApp() {
+ overrideBehavior(STEM_PRIMARY_BUTTON_SHORT_PRESS, SHORT_PRESS_PRIMARY_LAUNCH_ALL_APPS);
+ setUpPhoneWindowManager(/* supportSettingsUpdate= */ true);
+ mPhoneWindowManager.overrideStartActivity();
+ mPhoneWindowManager.setKeyguardServiceDelegateIsShowing(false);
+ mPhoneWindowManager.overrideIsUserSetupComplete(true);
+ mPhoneWindowManager.overrideFocusedWindowButtonOverridePermission(true);
+
+ sendKey(KEYCODE_STEM_PRIMARY);
+
+ mPhoneWindowManager.assertOpenAllAppView();
+ }
+
+ @Test
public void stemLongKey_triggerSearchServiceToLaunchAssist() {
overrideBehavior(
STEM_PRIMARY_BUTTON_LONG_PRESS,
@@ -165,6 +194,30 @@
mPhoneWindowManager.assertSwitchToRecent(referenceId);
}
+ @Test
+ public void stemDoubleKey_earlyShortPress_firstPressConsumedByApp_switchToMostRecent()
+ throws RemoteException {
+ overrideBehavior(STEM_PRIMARY_BUTTON_DOUBLE_PRESS, SHORT_PRESS_PRIMARY_LAUNCH_ALL_APPS);
+ setUpPhoneWindowManager(/* supportSettingsUpdate= */ true);
+ mPhoneWindowManager.overrideShouldEarlyShortPressOnStemPrimary(true);
+ mPhoneWindowManager.setKeyguardServiceDelegateIsShowing(false);
+ mPhoneWindowManager.overrideIsUserSetupComplete(true);
+ mPhoneWindowManager.overrideFocusedWindowButtonOverridePermission(true);
+ RecentTaskInfo recentTaskInfo = new RecentTaskInfo();
+ int referenceId = 666;
+ recentTaskInfo.persistentId = referenceId;
+ doReturn(recentTaskInfo).when(
+ mPhoneWindowManager.mActivityTaskManagerInternal).getMostRecentTaskFromBackground();
+
+ setDispatchedKeyHandler(keyEvent -> true);
+ sendKey(KEYCODE_STEM_PRIMARY);
+ setDispatchedKeyHandler(keyEvent -> false);
+ sendKey(KEYCODE_STEM_PRIMARY);
+
+ mPhoneWindowManager.assertNotOpenAllAppView();
+ mPhoneWindowManager.assertSwitchToRecent(referenceId);
+ }
+
private void overrideBehavior(String key, int expectedBehavior) {
Settings.Global.putLong(mContext.getContentResolver(), key, expectedBehavior);
}
diff --git a/services/tests/wmtests/src/com/android/server/policy/TestPhoneWindowManager.java b/services/tests/wmtests/src/com/android/server/policy/TestPhoneWindowManager.java
index 43c4745..d057226 100644
--- a/services/tests/wmtests/src/com/android/server/policy/TestPhoneWindowManager.java
+++ b/services/tests/wmtests/src/com/android/server/policy/TestPhoneWindowManager.java
@@ -90,6 +90,7 @@
import com.android.dx.mockito.inline.extended.StaticMockitoSession;
import com.android.internal.accessibility.AccessibilityShortcutController;
+import com.android.internal.policy.KeyInterceptionInfo;
import com.android.internal.util.FrameworkStatsLog;
import com.android.server.GestureLauncherService;
import com.android.server.LocalServices;
@@ -162,6 +163,9 @@
@Mock private KeyguardServiceDelegate mKeyguardServiceDelegate;
+ @Mock
+ private PhoneWindowManager.ButtonOverridePermissionChecker mButtonOverridePermissionChecker;
+
private StaticMockitoSession mMockitoSession;
private OffsettableClock mClock = new OffsettableClock();
private TestLooper mTestLooper = new TestLooper(() -> mClock.now());
@@ -189,6 +193,10 @@
IActivityManager getActivityManagerService() {
return mActivityManagerService;
}
+
+ PhoneWindowManager.ButtonOverridePermissionChecker getButtonOverridePermissionChecker() {
+ return mButtonOverridePermissionChecker;
+ }
}
TestPhoneWindowManager(Context context, boolean supportSettingsUpdate) {
@@ -304,6 +312,11 @@
doReturn(false).when(mPhoneWindowManager).keyguardOn();
doNothing().when(mContext).startActivityAsUser(any(), any());
doNothing().when(mContext).startActivityAsUser(any(), any(), any());
+
+ KeyInterceptionInfo interceptionInfo = new KeyInterceptionInfo(0, 0, null, 0);
+ doReturn(interceptionInfo)
+ .when(mWindowManagerInternal).getKeyInterceptionInfoFromToken(any());
+
Mockito.reset(mContext);
}
@@ -525,6 +538,11 @@
mPhoneWindowManager.mPrimaryShortPressTargetActivity = component;
}
+ void overrideFocusedWindowButtonOverridePermission(boolean granted) {
+ doReturn(granted)
+ .when(mButtonOverridePermissionChecker).canAppOverrideSystemKey(any(), anyInt());
+ }
+
/**
* Below functions will check the policy behavior could be invoked.
*/
diff --git a/services/tests/wmtests/src/com/android/server/wm/BackNavigationControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/BackNavigationControllerTests.java
index afea811..4d4d397 100644
--- a/services/tests/wmtests/src/com/android/server/wm/BackNavigationControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/BackNavigationControllerTests.java
@@ -242,6 +242,110 @@
}
@Test
+ public void backTypeCrossActivityInTaskFragment() {
+ final Task task = createTask(mDefaultDisplay);
+ final TaskFragment tf1 = createTaskFragmentWithActivity(task);
+ final TaskFragment tf2 = createTaskFragmentWithActivity(task);
+ final ArrayList<ActivityRecord> outPrevActivities = new ArrayList<>();
+
+ ActivityRecord prevAr = tf1.getTopMostActivity();
+ ActivityRecord topAr = tf2.getTopMostActivity();
+ boolean predictable;
+
+ // Stacked + no Companion => predict for previous activity.
+ // TF2
+ // TF1
+ predictable = BackNavigationController.getAnimatablePrevActivities(task, topAr,
+ outPrevActivities);
+ assertTrue(outPrevActivities.contains(prevAr));
+ assertTrue(predictable);
+ outPrevActivities.clear();
+
+ // Stacked + companion => predict for previous task
+ tf2.setCompanionTaskFragment(tf1);
+ predictable = BackNavigationController.getAnimatablePrevActivities(task, topAr,
+ outPrevActivities);
+ assertTrue(outPrevActivities.isEmpty());
+ assertTrue(predictable);
+ tf2.setCompanionTaskFragment(null);
+
+ // Adjacent + no companion => unable to predict
+ // TF1 | TF2
+ tf1.setAdjacentTaskFragment(tf2);
+ tf2.setAdjacentTaskFragment(tf1);
+ predictable = BackNavigationController.getAnimatablePrevActivities(task, topAr,
+ outPrevActivities);
+ assertTrue(outPrevActivities.isEmpty());
+ assertFalse(predictable);
+ predictable = BackNavigationController.getAnimatablePrevActivities(task, prevAr,
+ outPrevActivities);
+ assertTrue(outPrevActivities.isEmpty());
+ assertFalse(predictable);
+
+ // Adjacent + companion => predict for previous task
+ tf1.setCompanionTaskFragment(tf2);
+ tf2.setCompanionTaskFragment(tf1);
+ predictable = BackNavigationController.getAnimatablePrevActivities(task, topAr,
+ outPrevActivities);
+ assertTrue(outPrevActivities.isEmpty());
+ assertTrue(predictable);
+ predictable = BackNavigationController.getAnimatablePrevActivities(task, prevAr,
+ outPrevActivities);
+ assertTrue(outPrevActivities.isEmpty());
+ assertTrue(predictable);
+ // reset
+ tf1.setAdjacentTaskFragment(null);
+ tf2.setAdjacentTaskFragment(null);
+ tf1.setCompanionTaskFragment(null);
+ tf2.setCompanionTaskFragment(null);
+
+ final TaskFragment tf3 = new TaskFragmentBuilder(mAtm)
+ .createActivityCount(2)
+ .setParentTask(task)
+ .build();
+ topAr = tf3.getTopMostActivity();
+ prevAr = tf3.getBottomMostActivity();
+ // Stacked => predict for previous activity.
+ // TF3
+ // TF2
+ // TF1
+ predictable = BackNavigationController.getAnimatablePrevActivities(task, topAr,
+ outPrevActivities);
+ assertTrue(outPrevActivities.contains(prevAr));
+ assertTrue(predictable);
+ // reset
+ outPrevActivities.clear();
+
+ // Adjacent => predict for previous activity.
+ // TF2 | TF3
+ // TF1
+ tf2.setAdjacentTaskFragment(tf3);
+ tf3.setAdjacentTaskFragment(tf2);
+ predictable = BackNavigationController.getAnimatablePrevActivities(task, topAr,
+ outPrevActivities);
+ assertTrue(outPrevActivities.contains(prevAr));
+ assertTrue(predictable);
+ // reset
+ outPrevActivities.clear();
+ tf2.setAdjacentTaskFragment(null);
+ tf3.setAdjacentTaskFragment(null);
+
+ final TaskFragment tf4 = createTaskFragmentWithActivity(task);
+ // Stacked + companion => predict for previous activity below companion.
+ // Tf4
+ // TF3
+ // TF2
+ // TF1
+ tf4.setCompanionTaskFragment(tf3);
+ tf3.setCompanionTaskFragment(tf4);
+ topAr = tf4.getTopMostActivity();
+ predictable = BackNavigationController.getAnimatablePrevActivities(task, topAr,
+ outPrevActivities);
+ assertTrue(outPrevActivities.contains(tf2.getTopMostActivity()));
+ assertTrue(predictable);
+ }
+
+ @Test
public void backTypeDialogCloseWhenBackFromDialog() {
DialogCloseTestCase testCase = createTopTaskWithActivityAndDialog();
IOnBackInvokedCallback callback = withSystemCallback(testCase.task);
diff --git a/services/tests/wmtests/src/com/android/server/wm/TrustedPresentationCallbackTest.java b/services/tests/wmtests/src/com/android/server/wm/TrustedPresentationCallbackTest.java
new file mode 100644
index 0000000..c5dd447
--- /dev/null
+++ b/services/tests/wmtests/src/com/android/server/wm/TrustedPresentationCallbackTest.java
@@ -0,0 +1,154 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm;
+
+import static android.server.wm.ActivityManagerTestBase.createFullscreenActivityScenarioRule;
+import static android.server.wm.BuildUtils.HW_TIMEOUT_MULTIPLIER;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import android.app.Activity;
+import android.platform.test.annotations.Presubmit;
+import android.server.wm.CtsWindowInfoUtils;
+import android.view.SurfaceControl;
+import android.view.SurfaceControl.TrustedPresentationThresholds;
+
+import androidx.annotation.GuardedBy;
+import androidx.test.ext.junit.rules.ActivityScenarioRule;
+
+import com.android.server.wm.utils.CommonUtils;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TestName;
+
+import java.util.function.Consumer;
+
+/**
+ * TODO (b/287076178): Move these tests to
+ * {@link android.view.surfacecontrol.cts.TrustedPresentationCallbackTest} when API is made public
+ */
+@Presubmit
+public class TrustedPresentationCallbackTest {
+ private static final String TAG = "TrustedPresentationCallbackTest";
+ private static final int STABILITY_REQUIREMENT_MS = 500;
+ private static final long WAIT_TIME_MS = HW_TIMEOUT_MULTIPLIER * 2000L;
+
+ private static final float FRACTION_VISIBLE = 0.1f;
+
+ private final Object mResultsLock = new Object();
+ @GuardedBy("mResultsLock")
+ private boolean mResult;
+ @GuardedBy("mResultsLock")
+ private boolean mReceivedResults;
+
+ @Rule
+ public TestName mName = new TestName();
+
+ @Rule
+ public ActivityScenarioRule<TestActivity> mActivityRule = createFullscreenActivityScenarioRule(
+ TestActivity.class);
+
+ private TestActivity mActivity;
+
+ @Before
+ public void setup() {
+ mActivityRule.getScenario().onActivity(activity -> mActivity = activity);
+ }
+
+ @After
+ public void tearDown() {
+ CommonUtils.waitUntilActivityRemoved(mActivity);
+ }
+
+ @Test
+ public void testAddTrustedPresentationListenerOnWindow() throws InterruptedException {
+ TrustedPresentationThresholds thresholds = new TrustedPresentationThresholds(
+ 1 /* minAlpha */, FRACTION_VISIBLE, STABILITY_REQUIREMENT_MS);
+ SurfaceControl.Transaction t = new SurfaceControl.Transaction();
+ mActivity.getWindow().getRootSurfaceControl().addTrustedPresentationCallback(t, thresholds,
+ Runnable::run, inTrustedPresentationState -> {
+ synchronized (mResultsLock) {
+ mResult = inTrustedPresentationState;
+ mReceivedResults = true;
+ mResultsLock.notify();
+ }
+ });
+ t.apply();
+ synchronized (mResultsLock) {
+ assertResults();
+ }
+ }
+
+ @Test
+ public void testRemoveTrustedPresentationListenerOnWindow() throws InterruptedException {
+ TrustedPresentationThresholds thresholds = new TrustedPresentationThresholds(
+ 1 /* minAlpha */, FRACTION_VISIBLE, STABILITY_REQUIREMENT_MS);
+ Consumer<Boolean> trustedPresentationCallback = inTrustedPresentationState -> {
+ synchronized (mResultsLock) {
+ mResult = inTrustedPresentationState;
+ mReceivedResults = true;
+ mResultsLock.notify();
+ }
+ };
+ SurfaceControl.Transaction t = new SurfaceControl.Transaction();
+ mActivity.getWindow().getRootSurfaceControl().addTrustedPresentationCallback(t, thresholds,
+ Runnable::run, trustedPresentationCallback);
+ t.apply();
+
+ synchronized (mResultsLock) {
+ if (!mReceivedResults) {
+ mResultsLock.wait(WAIT_TIME_MS);
+ }
+ assertResults();
+ // reset the state
+ mReceivedResults = false;
+ }
+
+ mActivity.getWindow().getRootSurfaceControl().removeTrustedPresentationCallback(t,
+ trustedPresentationCallback);
+ t.apply();
+
+ synchronized (mResultsLock) {
+ if (!mReceivedResults) {
+ mResultsLock.wait(WAIT_TIME_MS);
+ }
+ // Ensure we waited the full time and never received a notify on the result from the
+ // callback.
+ assertFalse("Should never have received a callback", mReceivedResults);
+ // results shouldn't have changed.
+ assertTrue(mResult);
+ }
+ }
+
+ @GuardedBy("mResultsLock")
+ private void assertResults() throws InterruptedException {
+ mResultsLock.wait(WAIT_TIME_MS);
+
+ if (!mReceivedResults) {
+ CtsWindowInfoUtils.dumpWindowsOnScreen(TAG, "test " + mName.getMethodName());
+ }
+ // Make sure we received the results and not just timed out
+ assertTrue("Timed out waiting for results", mReceivedResults);
+ assertTrue(mResult);
+ }
+
+ public static class TestActivity extends Activity {
+ }
+}
diff --git a/services/tests/wmtests/src/com/android/server/wm/TrustedPresentationListenerTest.java b/services/tests/wmtests/src/com/android/server/wm/TrustedPresentationListenerTest.java
deleted file mode 100644
index 96b66bf..0000000
--- a/services/tests/wmtests/src/com/android/server/wm/TrustedPresentationListenerTest.java
+++ /dev/null
@@ -1,267 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.wm;
-
-import static android.server.wm.ActivityManagerTestBase.createFullscreenActivityScenarioRule;
-import static android.server.wm.BuildUtils.HW_TIMEOUT_MULTIPLIER;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertThrows;
-import static org.junit.Assert.fail;
-
-import android.app.Activity;
-import android.os.SystemClock;
-import android.platform.test.annotations.Presubmit;
-import android.server.wm.CtsWindowInfoUtils;
-import android.util.AndroidRuntimeException;
-import android.util.Log;
-import android.view.SurfaceControl;
-import android.view.SurfaceControlViewHost;
-import android.view.View;
-import android.view.WindowManager;
-import android.window.TrustedPresentationThresholds;
-
-import androidx.annotation.GuardedBy;
-import androidx.annotation.NonNull;
-import androidx.test.ext.junit.rules.ActivityScenarioRule;
-
-import com.android.server.wm.utils.CommonUtils;
-
-import junit.framework.Assert;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.TestName;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
-import java.util.function.Consumer;
-
-/**
- * TODO (b/287076178): Move these tests to
- * {@link android.view.surfacecontrol.cts.TrustedPresentationListenerTest} when API is made public
- */
-@Presubmit
-public class TrustedPresentationListenerTest {
- private static final String TAG = "TrustedPresentationListenerTest";
- private static final int STABILITY_REQUIREMENT_MS = 500;
- private static final long WAIT_TIME_MS = HW_TIMEOUT_MULTIPLIER * 2000L;
-
- private static final float FRACTION_VISIBLE = 0.1f;
-
- private final List<Boolean> mResults = Collections.synchronizedList(new ArrayList<>());
- private CountDownLatch mReceivedResults = new CountDownLatch(1);
-
- private TrustedPresentationThresholds mThresholds = new TrustedPresentationThresholds(
- 1 /* minAlpha */, FRACTION_VISIBLE, STABILITY_REQUIREMENT_MS);
-
- @Rule
- public TestName mName = new TestName();
-
- @Rule
- public ActivityScenarioRule<TestActivity> mActivityRule = createFullscreenActivityScenarioRule(
- TestActivity.class);
-
- private TestActivity mActivity;
-
- private SurfaceControlViewHost.SurfacePackage mSurfacePackage = null;
-
- @Before
- public void setup() {
- mActivityRule.getScenario().onActivity(activity -> mActivity = activity);
- mDefaultListener = new Listener(mReceivedResults);
- }
-
- @After
- public void tearDown() {
- if (mSurfacePackage != null) {
- new SurfaceControl.Transaction().remove(mSurfacePackage.getSurfaceControl()).apply(
- true);
- mSurfacePackage.release();
- }
- CommonUtils.waitUntilActivityRemoved(mActivity);
-
- }
-
- private class Listener implements Consumer<Boolean> {
- final CountDownLatch mLatch;
-
- Listener(CountDownLatch latch) {
- mLatch = latch;
- }
-
- @Override
- public void accept(Boolean inTrustedPresentationState) {
- Log.d(TAG, "onTrustedPresentationChanged " + inTrustedPresentationState);
- mResults.add(inTrustedPresentationState);
- mLatch.countDown();
- }
- }
-
- private Consumer<Boolean> mDefaultListener;
-
- @Test
- public void testAddTrustedPresentationListenerOnWindow() {
- WindowManager windowManager = mActivity.getSystemService(WindowManager.class);
- windowManager.registerTrustedPresentationListener(
- mActivity.getWindow().getDecorView().getWindowToken(), mThresholds, Runnable::run,
- mDefaultListener);
- assertResults(List.of(true));
- }
-
- @Test
- public void testRemoveTrustedPresentationListenerOnWindow() throws InterruptedException {
- WindowManager windowManager = mActivity.getSystemService(WindowManager.class);
- windowManager.registerTrustedPresentationListener(
- mActivity.getWindow().getDecorView().getWindowToken(), mThresholds, Runnable::run,
- mDefaultListener);
- assertResults(List.of(true));
- // reset the latch
- mReceivedResults = new CountDownLatch(1);
-
- windowManager.unregisterTrustedPresentationListener(mDefaultListener);
- mReceivedResults.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS);
- // Ensure we waited the full time and never received a notify on the result from the
- // callback.
- assertEquals("Should never have received a callback", mReceivedResults.getCount(), 1);
- // results shouldn't have changed.
- assertEquals(mResults, List.of(true));
- }
-
- @Test
- public void testRemovingUnknownListenerIsANoop() {
- WindowManager windowManager = mActivity.getSystemService(WindowManager.class);
- assertNotNull(windowManager);
- windowManager.unregisterTrustedPresentationListener(mDefaultListener);
- }
-
- @Test
- public void testAddDuplicateListenerThrowsException() {
- WindowManager windowManager = mActivity.getSystemService(WindowManager.class);
- assertNotNull(windowManager);
- windowManager.registerTrustedPresentationListener(
- mActivity.getWindow().getDecorView().getWindowToken(), mThresholds,
- Runnable::run, mDefaultListener);
- assertThrows(AndroidRuntimeException.class,
- () -> windowManager.registerTrustedPresentationListener(
- mActivity.getWindow().getDecorView().getWindowToken(), mThresholds,
- Runnable::run, mDefaultListener));
- }
-
- @Test
- public void testAddDuplicateThresholds() {
- mReceivedResults = new CountDownLatch(2);
- mDefaultListener = new Listener(mReceivedResults);
- WindowManager windowManager = mActivity.getSystemService(WindowManager.class);
- windowManager.registerTrustedPresentationListener(
- mActivity.getWindow().getDecorView().getWindowToken(), mThresholds,
- Runnable::run, mDefaultListener);
-
- Consumer<Boolean> mNewListener = new Listener(mReceivedResults);
-
- windowManager.registerTrustedPresentationListener(
- mActivity.getWindow().getDecorView().getWindowToken(), mThresholds,
- Runnable::run, mNewListener);
- assertResults(List.of(true, true));
- }
-
- private void waitForViewAttach(View view) {
- final CountDownLatch viewAttached = new CountDownLatch(1);
- view.addOnAttachStateChangeListener(new View.OnAttachStateChangeListener() {
- @Override
- public void onViewAttachedToWindow(@NonNull View v) {
- viewAttached.countDown();
- }
-
- @Override
- public void onViewDetachedFromWindow(@NonNull View v) {
-
- }
- });
- try {
- viewAttached.await(2000, TimeUnit.MILLISECONDS);
- } catch (InterruptedException e) {
- throw new RuntimeException(e);
- }
- if (!wait(viewAttached, 2000 /* waitTimeMs */)) {
- fail("Couldn't attach view=" + view);
- }
- }
-
- @Test
- public void testAddListenerToScvh() {
- WindowManager windowManager = mActivity.getSystemService(WindowManager.class);
-
- var embeddedView = new View(mActivity);
- mActivityRule.getScenario().onActivity(activity -> {
- var attachedSurfaceControl =
- mActivity.getWindow().getDecorView().getRootSurfaceControl();
- var scvh = new SurfaceControlViewHost(mActivity, mActivity.getDisplay(),
- attachedSurfaceControl.getHostToken());
- mSurfacePackage = scvh.getSurfacePackage();
- scvh.setView(embeddedView, mActivity.getWindow().getDecorView().getWidth(),
- mActivity.getWindow().getDecorView().getHeight());
- attachedSurfaceControl.buildReparentTransaction(
- mSurfacePackage.getSurfaceControl());
- });
-
- waitForViewAttach(embeddedView);
- windowManager.registerTrustedPresentationListener(embeddedView.getWindowToken(),
- mThresholds,
- Runnable::run, mDefaultListener);
-
- assertResults(List.of(true));
- }
-
- private boolean wait(CountDownLatch latch, long waitTimeMs) {
- while (true) {
- long now = SystemClock.uptimeMillis();
- try {
- return latch.await(waitTimeMs, TimeUnit.MILLISECONDS);
- } catch (InterruptedException e) {
- long elapsedTime = SystemClock.uptimeMillis() - now;
- waitTimeMs = Math.max(0, waitTimeMs - elapsedTime);
- }
- }
-
- }
-
- @GuardedBy("mResultsLock")
- private void assertResults(List<Boolean> results) {
- if (!wait(mReceivedResults, WAIT_TIME_MS)) {
- try {
- CtsWindowInfoUtils.dumpWindowsOnScreen(TAG, "test " + mName.getMethodName());
- } catch (InterruptedException e) {
- Log.d(TAG, "Couldn't dump windows", e);
- }
- Assert.fail("Timed out waiting for results mReceivedResults.count="
- + mReceivedResults.getCount() + "mReceivedResults=" + mReceivedResults);
- }
-
- // Make sure we received the results
- assertEquals(results.toArray(), mResults.toArray());
- }
-
- public static class TestActivity extends Activity {
- }
-}
diff --git a/services/usb/java/com/android/server/usb/UsbHostManager.java b/services/usb/java/com/android/server/usb/UsbHostManager.java
index b3eb285..8b44579 100644
--- a/services/usb/java/com/android/server/usb/UsbHostManager.java
+++ b/services/usb/java/com/android/server/usb/UsbHostManager.java
@@ -221,9 +221,7 @@
for (int line = 0; line < length / kDumpBytesPerLine; line++) {
StringBuilder sb = new StringBuilder();
for (int offset = 0; offset < kDumpBytesPerLine; offset++) {
- sb.append("0x")
- .append(String.format("0x%02X", mDescriptors[dataOffset++]))
- .append(" ");
+ sb.append(String.format("0x%02X", mDescriptors[dataOffset++])).append(" ");
}
pw.println(sb.toString());
}
@@ -231,9 +229,7 @@
// remainder
StringBuilder sb = new StringBuilder();
while (dataOffset < length) {
- sb.append("0x")
- .append(String.format("0x%02X", mDescriptors[dataOffset++]))
- .append(" ");
+ sb.append(String.format("0x%02X", mDescriptors[dataOffset++])).append(" ");
}
pw.println(sb.toString());
} else {
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
index 7239ba9..b214591 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
@@ -18,6 +18,7 @@
import android.Manifest;
import android.annotation.CallbackExecutor;
+import android.annotation.EnforcePermission;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
@@ -1567,16 +1568,19 @@
}
@Override
- public boolean setSandboxedDetectionTrainingDataOp(int opMode) {
- synchronized (this) {
- enforceIsCallerPreinstalledAssistant();
+ @EnforcePermission(android.Manifest.permission.MANAGE_HOTWORD_DETECTION)
+ public void setIsReceiveSandboxedTrainingDataAllowed(boolean allowed) {
+ super.setIsReceiveSandboxedTrainingDataAllowed_enforcePermission();
+ synchronized (this) {
if (mImpl == null) {
- Slog.w(TAG, "setSandboxedDetectionTrainingDataop without running"
- + " voice interaction service");
- return false;
+ throw new IllegalStateException(
+ "setIsReceiveSandboxedTrainingDataAllowed without running voice "
+ + "interaction service");
}
+ enforceIsCallerPreinstalledAssistant();
+
int callingUid = Binder.getCallingUid();
final long caller = Binder.clearCallingIdentity();
try {
@@ -1584,12 +1588,11 @@
mContext.getSystemService(Context.APP_OPS_SERVICE);
appOpsManager.setUidMode(
AppOpsManager.OP_RECEIVE_SANDBOXED_DETECTION_TRAINING_DATA,
- callingUid, opMode);
+ callingUid, allowed ? AppOpsManager.MODE_ALLOWED :
+ AppOpsManager.MODE_ERRORED);
} finally {
Binder.restoreCallingIdentity(caller);
}
-
- return true;
}
}
diff --git a/tests/FlickerTests/ActivityEmbedding/Android.bp b/tests/FlickerTests/ActivityEmbedding/Android.bp
index 9eeec7c..2cdf542 100644
--- a/tests/FlickerTests/ActivityEmbedding/Android.bp
+++ b/tests/FlickerTests/ActivityEmbedding/Android.bp
@@ -29,6 +29,8 @@
manifest: "AndroidManifest.xml",
package_name: "com.android.server.wm.flicker",
instrumentation_target_package: "com.android.server.wm.flicker",
+ test_config_template: "AndroidTestTemplate.xml",
srcs: ["src/**/*"],
static_libs: ["FlickerTestsBase"],
+ data: ["trace_config/*"],
}
diff --git a/tests/FlickerTests/ActivityEmbedding/AndroidManifest.xml b/tests/FlickerTests/ActivityEmbedding/AndroidManifest.xml
index f867ffb..6f8f008 100644
--- a/tests/FlickerTests/ActivityEmbedding/AndroidManifest.xml
+++ b/tests/FlickerTests/ActivityEmbedding/AndroidManifest.xml
@@ -17,7 +17,7 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
- package="com.android.server.wm.flick">
+ package="com.android.server.wm.flicker">
<uses-sdk android:minSdkVersion="29" android:targetSdkVersion="29"/>
<!-- Read and write traces from external storage -->
diff --git a/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/rotation/RotateSplitNoChangeTest.kt b/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/rotation/RotateSplitNoChangeTest.kt
index e8389d19..0dce870 100644
--- a/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/rotation/RotateSplitNoChangeTest.kt
+++ b/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/rotation/RotateSplitNoChangeTest.kt
@@ -43,8 +43,6 @@
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
open class RotateSplitNoChangeTest(flicker: LegacyFlickerTest) : RotationTransition(flicker) {
-
- override val testApp = ActivityEmbeddingAppHelper(instrumentation)
override val transition: FlickerBuilder.() -> Unit
get() = {
super.transition(this)
diff --git a/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/rotation/RotationTransition.kt b/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/rotation/RotationTransition.kt
index 1123c5b..f6d51f9 100644
--- a/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/rotation/RotationTransition.kt
+++ b/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/rotation/RotationTransition.kt
@@ -18,17 +18,14 @@
import android.platform.test.annotations.Presubmit
import android.tools.common.traces.component.ComponentNameMatcher
-import android.tools.device.apphelpers.StandardAppHelper
import android.tools.device.flicker.legacy.FlickerBuilder
import android.tools.device.flicker.legacy.LegacyFlickerTest
-import com.android.server.wm.flicker.BaseTest
+import com.android.server.wm.flicker.activityembedding.ActivityEmbeddingTestBase
import com.android.server.wm.flicker.helpers.setRotation
import org.junit.Test
/** Base class for app rotation tests */
-abstract class RotationTransition(flicker: LegacyFlickerTest) : BaseTest(flicker) {
- protected abstract val testApp: StandardAppHelper
-
+abstract class RotationTransition(flicker: LegacyFlickerTest) : ActivityEmbeddingTestBase(flicker) {
/** {@inheritDoc} */
override val transition: FlickerBuilder.() -> Unit = {
setup { this.setRotation(flicker.scenario.startRotation) }
diff --git a/tests/FlickerTests/ActivityEmbedding/trace_config/trace_config.textproto b/tests/FlickerTests/ActivityEmbedding/trace_config/trace_config.textproto
index c9a35ac..c4edc1a 100644
--- a/tests/FlickerTests/ActivityEmbedding/trace_config/trace_config.textproto
+++ b/tests/FlickerTests/ActivityEmbedding/trace_config/trace_config.textproto
@@ -62,12 +62,6 @@
atrace_categories: "binder_driver"
atrace_categories: "sched_process_exit"
atrace_apps: "com.android.server.wm.flicker"
- atrace_apps: "com.android.server.wm.flicker.other"
- atrace_apps: "com.android.server.wm.flicker.close"
- atrace_apps: "com.android.server.wm.flicker.ime"
- atrace_apps: "com.android.server.wm.flicker.launch"
- atrace_apps: "com.android.server.wm.flicker.quickswitch"
- atrace_apps: "com.android.server.wm.flicker.rotation"
atrace_apps: "com.android.server.wm.flicker.testapp"
atrace_apps: "com.android.systemui"
atrace_apps: "com.google.android.apps.nexuslauncher"
diff --git a/tests/FlickerTests/Android.bp b/tests/FlickerTests/Android.bp
index 514f895..1d71f95 100644
--- a/tests/FlickerTests/Android.bp
+++ b/tests/FlickerTests/Android.bp
@@ -23,13 +23,6 @@
default_applicable_licenses: ["frameworks_base_license"],
}
-filegroup {
- name: "FlickerServiceTests-src",
- srcs: [
- "src/**/*",
- ],
-}
-
java_defaults {
name: "FlickerTestsDefault",
platform_apis: true,
@@ -49,10 +42,7 @@
"wm-flicker-common-app-helpers",
"wm-shell-flicker-utils",
],
- data: [
- ":FlickerTestApp",
- "trace_config/*",
- ],
+ data: [":FlickerTestApp"],
}
java_library {
diff --git a/tests/FlickerTests/AppClose/Android.bp b/tests/FlickerTests/AppClose/Android.bp
index 151d12f..93fdd65 100644
--- a/tests/FlickerTests/AppClose/Android.bp
+++ b/tests/FlickerTests/AppClose/Android.bp
@@ -30,4 +30,5 @@
test_config_template: "AndroidTestTemplate.xml",
srcs: ["src/**/*"],
static_libs: ["FlickerTestsBase"],
+ data: ["trace_config/*"],
}
diff --git a/tests/FlickerTests/AppClose/trace_config/trace_config.textproto b/tests/FlickerTests/AppClose/trace_config/trace_config.textproto
index c9a35ac..6a0afc6 100644
--- a/tests/FlickerTests/AppClose/trace_config/trace_config.textproto
+++ b/tests/FlickerTests/AppClose/trace_config/trace_config.textproto
@@ -61,13 +61,7 @@
atrace_categories: "input"
atrace_categories: "binder_driver"
atrace_categories: "sched_process_exit"
- atrace_apps: "com.android.server.wm.flicker"
- atrace_apps: "com.android.server.wm.flicker.other"
atrace_apps: "com.android.server.wm.flicker.close"
- atrace_apps: "com.android.server.wm.flicker.ime"
- atrace_apps: "com.android.server.wm.flicker.launch"
- atrace_apps: "com.android.server.wm.flicker.quickswitch"
- atrace_apps: "com.android.server.wm.flicker.rotation"
atrace_apps: "com.android.server.wm.flicker.testapp"
atrace_apps: "com.android.systemui"
atrace_apps: "com.google.android.apps.nexuslauncher"
diff --git a/tests/FlickerTests/AppLaunch/Android.bp b/tests/FlickerTests/AppLaunch/Android.bp
index f33384d..f5e9621 100644
--- a/tests/FlickerTests/AppLaunch/Android.bp
+++ b/tests/FlickerTests/AppLaunch/Android.bp
@@ -50,6 +50,7 @@
"FlickerTestsBase",
"FlickerTestsAppLaunchCommon",
],
+ data: ["trace_config/*"],
}
android_test {
@@ -66,4 +67,5 @@
"FlickerTestsBase",
"FlickerTestsAppLaunchCommon",
],
+ data: ["trace_config/*"],
}
diff --git a/tests/FlickerTests/AppLaunch/trace_config/trace_config.textproto b/tests/FlickerTests/AppLaunch/trace_config/trace_config.textproto
index c9a35ac..f27177f 100644
--- a/tests/FlickerTests/AppLaunch/trace_config/trace_config.textproto
+++ b/tests/FlickerTests/AppLaunch/trace_config/trace_config.textproto
@@ -61,13 +61,7 @@
atrace_categories: "input"
atrace_categories: "binder_driver"
atrace_categories: "sched_process_exit"
- atrace_apps: "com.android.server.wm.flicker"
- atrace_apps: "com.android.server.wm.flicker.other"
- atrace_apps: "com.android.server.wm.flicker.close"
- atrace_apps: "com.android.server.wm.flicker.ime"
atrace_apps: "com.android.server.wm.flicker.launch"
- atrace_apps: "com.android.server.wm.flicker.quickswitch"
- atrace_apps: "com.android.server.wm.flicker.rotation"
atrace_apps: "com.android.server.wm.flicker.testapp"
atrace_apps: "com.android.systemui"
atrace_apps: "com.google.android.apps.nexuslauncher"
diff --git a/tests/FlickerTests/FlickerService/Android.bp b/tests/FlickerTests/FlickerService/Android.bp
index 1a38115..ef74e94 100644
--- a/tests/FlickerTests/FlickerService/Android.bp
+++ b/tests/FlickerTests/FlickerService/Android.bp
@@ -30,4 +30,5 @@
test_config_template: "AndroidTestTemplate.xml",
srcs: ["src/**/*"],
static_libs: ["FlickerTestsBase"],
+ data: ["trace_config/*"],
}
diff --git a/tests/FlickerTests/FlickerService/trace_config/trace_config.textproto b/tests/FlickerTests/FlickerService/trace_config/trace_config.textproto
index c9a35ac..a4f3ecf 100644
--- a/tests/FlickerTests/FlickerService/trace_config/trace_config.textproto
+++ b/tests/FlickerTests/FlickerService/trace_config/trace_config.textproto
@@ -61,13 +61,7 @@
atrace_categories: "input"
atrace_categories: "binder_driver"
atrace_categories: "sched_process_exit"
- atrace_apps: "com.android.server.wm.flicker"
- atrace_apps: "com.android.server.wm.flicker.other"
- atrace_apps: "com.android.server.wm.flicker.close"
- atrace_apps: "com.android.server.wm.flicker.ime"
- atrace_apps: "com.android.server.wm.flicker.launch"
- atrace_apps: "com.android.server.wm.flicker.quickswitch"
- atrace_apps: "com.android.server.wm.flicker.rotation"
+ atrace_apps: "com.android.server.wm.flicker.service"
atrace_apps: "com.android.server.wm.flicker.testapp"
atrace_apps: "com.android.systemui"
atrace_apps: "com.google.android.apps.nexuslauncher"
diff --git a/tests/FlickerTests/IME/Android.bp b/tests/FlickerTests/IME/Android.bp
index 057d9fc..1141e5f 100644
--- a/tests/FlickerTests/IME/Android.bp
+++ b/tests/FlickerTests/IME/Android.bp
@@ -40,6 +40,7 @@
test_config_template: "AndroidTestTemplate.xml",
srcs: ["src/**/*"],
static_libs: ["FlickerTestsBase"],
+ data: ["trace_config/*"],
}
java_library {
@@ -59,6 +60,7 @@
"FlickerTestsBase",
"FlickerTestsImeCommon",
],
+ data: ["trace_config/*"],
}
android_test {
@@ -75,4 +77,5 @@
"FlickerTestsBase",
"FlickerTestsImeCommon",
],
+ data: ["trace_config/*"],
}
diff --git a/tests/FlickerTests/IME/trace_config/trace_config.textproto b/tests/FlickerTests/IME/trace_config/trace_config.textproto
index c9a35ac..b722fe5 100644
--- a/tests/FlickerTests/IME/trace_config/trace_config.textproto
+++ b/tests/FlickerTests/IME/trace_config/trace_config.textproto
@@ -61,13 +61,7 @@
atrace_categories: "input"
atrace_categories: "binder_driver"
atrace_categories: "sched_process_exit"
- atrace_apps: "com.android.server.wm.flicker"
- atrace_apps: "com.android.server.wm.flicker.other"
- atrace_apps: "com.android.server.wm.flicker.close"
atrace_apps: "com.android.server.wm.flicker.ime"
- atrace_apps: "com.android.server.wm.flicker.launch"
- atrace_apps: "com.android.server.wm.flicker.quickswitch"
- atrace_apps: "com.android.server.wm.flicker.rotation"
atrace_apps: "com.android.server.wm.flicker.testapp"
atrace_apps: "com.android.systemui"
atrace_apps: "com.google.android.apps.nexuslauncher"
diff --git a/tests/FlickerTests/Notification/Android.bp b/tests/FlickerTests/Notification/Android.bp
index 5bed568..4648383 100644
--- a/tests/FlickerTests/Notification/Android.bp
+++ b/tests/FlickerTests/Notification/Android.bp
@@ -30,4 +30,5 @@
test_config_template: "AndroidTestTemplate.xml",
srcs: ["src/**/*"],
static_libs: ["FlickerTestsBase"],
+ data: ["trace_config/*"],
}
diff --git a/tests/FlickerTests/Notification/trace_config/trace_config.textproto b/tests/FlickerTests/Notification/trace_config/trace_config.textproto
index c9a35ac..dc8c88c 100644
--- a/tests/FlickerTests/Notification/trace_config/trace_config.textproto
+++ b/tests/FlickerTests/Notification/trace_config/trace_config.textproto
@@ -61,13 +61,7 @@
atrace_categories: "input"
atrace_categories: "binder_driver"
atrace_categories: "sched_process_exit"
- atrace_apps: "com.android.server.wm.flicker"
- atrace_apps: "com.android.server.wm.flicker.other"
- atrace_apps: "com.android.server.wm.flicker.close"
- atrace_apps: "com.android.server.wm.flicker.ime"
- atrace_apps: "com.android.server.wm.flicker.launch"
- atrace_apps: "com.android.server.wm.flicker.quickswitch"
- atrace_apps: "com.android.server.wm.flicker.rotation"
+ atrace_apps: "com.android.server.wm.flicker.notification"
atrace_apps: "com.android.server.wm.flicker.testapp"
atrace_apps: "com.android.systemui"
atrace_apps: "com.google.android.apps.nexuslauncher"
diff --git a/tests/FlickerTests/QuickSwitch/Android.bp b/tests/FlickerTests/QuickSwitch/Android.bp
index 64f7183..8755d0e 100644
--- a/tests/FlickerTests/QuickSwitch/Android.bp
+++ b/tests/FlickerTests/QuickSwitch/Android.bp
@@ -30,4 +30,5 @@
test_config_template: "AndroidTestTemplate.xml",
srcs: ["src/**/*"],
static_libs: ["FlickerTestsBase"],
+ data: ["trace_config/*"],
}
diff --git a/tests/FlickerTests/QuickSwitch/trace_config/trace_config.textproto b/tests/FlickerTests/QuickSwitch/trace_config/trace_config.textproto
index c9a35ac..cd70ad5 100644
--- a/tests/FlickerTests/QuickSwitch/trace_config/trace_config.textproto
+++ b/tests/FlickerTests/QuickSwitch/trace_config/trace_config.textproto
@@ -61,13 +61,7 @@
atrace_categories: "input"
atrace_categories: "binder_driver"
atrace_categories: "sched_process_exit"
- atrace_apps: "com.android.server.wm.flicker"
- atrace_apps: "com.android.server.wm.flicker.other"
- atrace_apps: "com.android.server.wm.flicker.close"
- atrace_apps: "com.android.server.wm.flicker.ime"
- atrace_apps: "com.android.server.wm.flicker.launch"
atrace_apps: "com.android.server.wm.flicker.quickswitch"
- atrace_apps: "com.android.server.wm.flicker.rotation"
atrace_apps: "com.android.server.wm.flicker.testapp"
atrace_apps: "com.android.systemui"
atrace_apps: "com.google.android.apps.nexuslauncher"
diff --git a/tests/FlickerTests/Rotation/Android.bp b/tests/FlickerTests/Rotation/Android.bp
index 8e93b5b..233a276 100644
--- a/tests/FlickerTests/Rotation/Android.bp
+++ b/tests/FlickerTests/Rotation/Android.bp
@@ -30,4 +30,5 @@
test_config_template: "AndroidTestTemplate.xml",
srcs: ["src/**/*"],
static_libs: ["FlickerTestsBase"],
+ data: ["trace_config/*"],
}
diff --git a/tests/FlickerTests/Rotation/trace_config/trace_config.textproto b/tests/FlickerTests/Rotation/trace_config/trace_config.textproto
index c9a35ac..eeb542f 100644
--- a/tests/FlickerTests/Rotation/trace_config/trace_config.textproto
+++ b/tests/FlickerTests/Rotation/trace_config/trace_config.textproto
@@ -61,12 +61,6 @@
atrace_categories: "input"
atrace_categories: "binder_driver"
atrace_categories: "sched_process_exit"
- atrace_apps: "com.android.server.wm.flicker"
- atrace_apps: "com.android.server.wm.flicker.other"
- atrace_apps: "com.android.server.wm.flicker.close"
- atrace_apps: "com.android.server.wm.flicker.ime"
- atrace_apps: "com.android.server.wm.flicker.launch"
- atrace_apps: "com.android.server.wm.flicker.quickswitch"
atrace_apps: "com.android.server.wm.flicker.rotation"
atrace_apps: "com.android.server.wm.flicker.testapp"
atrace_apps: "com.android.systemui"
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/BaseTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/BaseTest.kt
index ad272a0..ce92eac 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/BaseTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/BaseTest.kt
@@ -40,10 +40,9 @@
constructor(
protected val flicker: LegacyFlickerTest,
protected val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation(),
- protected val tapl: LauncherInstrumentation = LauncherInstrumentation()
) {
- init {
- tapl.setExpectedRotationCheckEnabled(true)
+ protected val tapl: LauncherInstrumentation by lazy {
+ LauncherInstrumentation().also { it.expectedRotationCheckEnabled = true }
}
private val logTag = this::class.java.simpleName
diff --git a/tests/HwAccelerationTest/OWNERS b/tests/HwAccelerationTest/OWNERS
deleted file mode 100644
index c88a9f8..0000000
--- a/tests/HwAccelerationTest/OWNERS
+++ /dev/null
@@ -1 +0,0 @@
-include /libs/hwui/OWNERS
diff --git a/tests/InputScreenshotTest/robotests/assets/phone/light_landscape_layout-preview.png b/tests/InputScreenshotTest/robotests/assets/phone/light_landscape_layout-preview.png
index baf204a..a117599d 100644
--- a/tests/InputScreenshotTest/robotests/assets/phone/light_landscape_layout-preview.png
+++ b/tests/InputScreenshotTest/robotests/assets/phone/light_landscape_layout-preview.png
Binary files differ
diff --git a/tests/InputScreenshotTest/robotests/assets/phone/light_portrait_layout-preview.png b/tests/InputScreenshotTest/robotests/assets/phone/light_portrait_layout-preview.png
index deb3cee..538abe8 100644
--- a/tests/InputScreenshotTest/robotests/assets/phone/light_portrait_layout-preview.png
+++ b/tests/InputScreenshotTest/robotests/assets/phone/light_portrait_layout-preview.png
Binary files differ
diff --git a/tests/InputScreenshotTest/robotests/assets/tablet/dark_portrait_layout-preview.png b/tests/InputScreenshotTest/robotests/assets/tablet/dark_portrait_layout-preview.png
index 34e25f7..79a1d6b 100644
--- a/tests/InputScreenshotTest/robotests/assets/tablet/dark_portrait_layout-preview.png
+++ b/tests/InputScreenshotTest/robotests/assets/tablet/dark_portrait_layout-preview.png
Binary files differ
diff --git a/tests/SilkFX/OWNERS b/tests/SilkFX/OWNERS
deleted file mode 100644
index c88a9f8..0000000
--- a/tests/SilkFX/OWNERS
+++ /dev/null
@@ -1 +0,0 @@
-include /libs/hwui/OWNERS
diff --git a/tests/HwAccelerationTest/.classpath b/tests/graphics/HwAccelerationTest/.classpath
similarity index 100%
rename from tests/HwAccelerationTest/.classpath
rename to tests/graphics/HwAccelerationTest/.classpath
diff --git a/tests/HwAccelerationTest/.gitignore b/tests/graphics/HwAccelerationTest/.gitignore
similarity index 100%
rename from tests/HwAccelerationTest/.gitignore
rename to tests/graphics/HwAccelerationTest/.gitignore
diff --git a/tests/HwAccelerationTest/Android.bp b/tests/graphics/HwAccelerationTest/Android.bp
similarity index 100%
rename from tests/HwAccelerationTest/Android.bp
rename to tests/graphics/HwAccelerationTest/Android.bp
diff --git a/tests/HwAccelerationTest/AndroidManifest.xml b/tests/graphics/HwAccelerationTest/AndroidManifest.xml
similarity index 100%
rename from tests/HwAccelerationTest/AndroidManifest.xml
rename to tests/graphics/HwAccelerationTest/AndroidManifest.xml
diff --git a/tests/HwAccelerationTest/default.properties b/tests/graphics/HwAccelerationTest/default.properties
similarity index 100%
rename from tests/HwAccelerationTest/default.properties
rename to tests/graphics/HwAccelerationTest/default.properties
diff --git a/tests/HwAccelerationTest/jni/Android.bp b/tests/graphics/HwAccelerationTest/jni/Android.bp
similarity index 100%
rename from tests/HwAccelerationTest/jni/Android.bp
rename to tests/graphics/HwAccelerationTest/jni/Android.bp
diff --git a/tests/HwAccelerationTest/jni/native-lib.cpp b/tests/graphics/HwAccelerationTest/jni/native-lib.cpp
similarity index 100%
rename from tests/HwAccelerationTest/jni/native-lib.cpp
rename to tests/graphics/HwAccelerationTest/jni/native-lib.cpp
diff --git a/tests/HwAccelerationTest/res/anim/accelerate_interpolator_2.xml b/tests/graphics/HwAccelerationTest/res/anim/accelerate_interpolator_2.xml
similarity index 100%
rename from tests/HwAccelerationTest/res/anim/accelerate_interpolator_2.xml
rename to tests/graphics/HwAccelerationTest/res/anim/accelerate_interpolator_2.xml
diff --git a/tests/HwAccelerationTest/res/anim/fade_in.xml b/tests/graphics/HwAccelerationTest/res/anim/fade_in.xml
similarity index 100%
rename from tests/HwAccelerationTest/res/anim/fade_in.xml
rename to tests/graphics/HwAccelerationTest/res/anim/fade_in.xml
diff --git a/tests/HwAccelerationTest/res/anim/fade_out.xml b/tests/graphics/HwAccelerationTest/res/anim/fade_out.xml
similarity index 100%
rename from tests/HwAccelerationTest/res/anim/fade_out.xml
rename to tests/graphics/HwAccelerationTest/res/anim/fade_out.xml
diff --git a/tests/HwAccelerationTest/res/anim/slide_off_left.xml b/tests/graphics/HwAccelerationTest/res/anim/slide_off_left.xml
similarity index 100%
rename from tests/HwAccelerationTest/res/anim/slide_off_left.xml
rename to tests/graphics/HwAccelerationTest/res/anim/slide_off_left.xml
diff --git a/tests/HwAccelerationTest/res/drawable-hdpi/appwidget_background.xml b/tests/graphics/HwAccelerationTest/res/drawable-hdpi/appwidget_background.xml
similarity index 100%
rename from tests/HwAccelerationTest/res/drawable-hdpi/appwidget_background.xml
rename to tests/graphics/HwAccelerationTest/res/drawable-hdpi/appwidget_background.xml
diff --git a/tests/HwAccelerationTest/res/drawable-hdpi/icon.png b/tests/graphics/HwAccelerationTest/res/drawable-hdpi/icon.png
similarity index 100%
rename from tests/HwAccelerationTest/res/drawable-hdpi/icon.png
rename to tests/graphics/HwAccelerationTest/res/drawable-hdpi/icon.png
Binary files differ
diff --git a/tests/HwAccelerationTest/res/drawable-hdpi/sunset1.jpg b/tests/graphics/HwAccelerationTest/res/drawable-hdpi/sunset1.jpg
similarity index 100%
rename from tests/HwAccelerationTest/res/drawable-hdpi/sunset1.jpg
rename to tests/graphics/HwAccelerationTest/res/drawable-hdpi/sunset1.jpg
Binary files differ
diff --git a/tests/HwAccelerationTest/res/drawable-hdpi/sunset2.png b/tests/graphics/HwAccelerationTest/res/drawable-hdpi/sunset2.png
similarity index 100%
rename from tests/HwAccelerationTest/res/drawable-hdpi/sunset2.png
rename to tests/graphics/HwAccelerationTest/res/drawable-hdpi/sunset2.png
Binary files differ
diff --git a/tests/HwAccelerationTest/res/drawable-hdpi/sunset3.png b/tests/graphics/HwAccelerationTest/res/drawable-hdpi/sunset3.png
similarity index 100%
rename from tests/HwAccelerationTest/res/drawable-hdpi/sunset3.png
rename to tests/graphics/HwAccelerationTest/res/drawable-hdpi/sunset3.png
Binary files differ
diff --git a/tests/HwAccelerationTest/res/drawable-hdpi/widget_header.png b/tests/graphics/HwAccelerationTest/res/drawable-hdpi/widget_header.png
similarity index 100%
rename from tests/HwAccelerationTest/res/drawable-hdpi/widget_header.png
rename to tests/graphics/HwAccelerationTest/res/drawable-hdpi/widget_header.png
Binary files differ
diff --git a/tests/HwAccelerationTest/res/drawable-mdpi/expander_ic_maximized.9.png b/tests/graphics/HwAccelerationTest/res/drawable-mdpi/expander_ic_maximized.9.png
similarity index 100%
rename from tests/HwAccelerationTest/res/drawable-mdpi/expander_ic_maximized.9.png
rename to tests/graphics/HwAccelerationTest/res/drawable-mdpi/expander_ic_maximized.9.png
Binary files differ
diff --git a/tests/HwAccelerationTest/res/drawable-mdpi/expander_ic_minimized.9.png b/tests/graphics/HwAccelerationTest/res/drawable-mdpi/expander_ic_minimized.9.png
similarity index 100%
rename from tests/HwAccelerationTest/res/drawable-mdpi/expander_ic_minimized.9.png
rename to tests/graphics/HwAccelerationTest/res/drawable-mdpi/expander_ic_minimized.9.png
Binary files differ
diff --git a/tests/HwAccelerationTest/res/drawable-nodpi/appwidget_bg.9.png b/tests/graphics/HwAccelerationTest/res/drawable-nodpi/appwidget_bg.9.png
similarity index 100%
rename from tests/HwAccelerationTest/res/drawable-nodpi/appwidget_bg.9.png
rename to tests/graphics/HwAccelerationTest/res/drawable-nodpi/appwidget_bg.9.png
Binary files differ
diff --git a/tests/HwAccelerationTest/res/drawable-nodpi/appwidget_bg_focus.9.png b/tests/graphics/HwAccelerationTest/res/drawable-nodpi/appwidget_bg_focus.9.png
similarity index 100%
rename from tests/HwAccelerationTest/res/drawable-nodpi/appwidget_bg_focus.9.png
rename to tests/graphics/HwAccelerationTest/res/drawable-nodpi/appwidget_bg_focus.9.png
Binary files differ
diff --git a/tests/HwAccelerationTest/res/drawable-nodpi/appwidget_bg_press.9.png b/tests/graphics/HwAccelerationTest/res/drawable-nodpi/appwidget_bg_press.9.png
similarity index 100%
rename from tests/HwAccelerationTest/res/drawable-nodpi/appwidget_bg_press.9.png
rename to tests/graphics/HwAccelerationTest/res/drawable-nodpi/appwidget_bg_press.9.png
Binary files differ
diff --git a/tests/HwAccelerationTest/res/drawable-nodpi/green_gradient.9.png b/tests/graphics/HwAccelerationTest/res/drawable-nodpi/green_gradient.9.png
similarity index 100%
rename from tests/HwAccelerationTest/res/drawable-nodpi/green_gradient.9.png
rename to tests/graphics/HwAccelerationTest/res/drawable-nodpi/green_gradient.9.png
Binary files differ
diff --git a/tests/HwAccelerationTest/res/drawable-nodpi/large_photo.jpg b/tests/graphics/HwAccelerationTest/res/drawable-nodpi/large_photo.jpg
similarity index 100%
rename from tests/HwAccelerationTest/res/drawable-nodpi/large_photo.jpg
rename to tests/graphics/HwAccelerationTest/res/drawable-nodpi/large_photo.jpg
Binary files differ
diff --git a/tests/HwAccelerationTest/res/drawable-nodpi/patch.9.png b/tests/graphics/HwAccelerationTest/res/drawable-nodpi/patch.9.png
similarity index 100%
rename from tests/HwAccelerationTest/res/drawable-nodpi/patch.9.png
rename to tests/graphics/HwAccelerationTest/res/drawable-nodpi/patch.9.png
Binary files differ
diff --git a/tests/HwAccelerationTest/res/drawable-nodpi/patch2.9.png b/tests/graphics/HwAccelerationTest/res/drawable-nodpi/patch2.9.png
similarity index 100%
rename from tests/HwAccelerationTest/res/drawable-nodpi/patch2.9.png
rename to tests/graphics/HwAccelerationTest/res/drawable-nodpi/patch2.9.png
Binary files differ
diff --git a/tests/HwAccelerationTest/res/drawable-nodpi/progress_vertical_bg_holo_dark.9.png b/tests/graphics/HwAccelerationTest/res/drawable-nodpi/progress_vertical_bg_holo_dark.9.png
similarity index 100%
rename from tests/HwAccelerationTest/res/drawable-nodpi/progress_vertical_bg_holo_dark.9.png
rename to tests/graphics/HwAccelerationTest/res/drawable-nodpi/progress_vertical_bg_holo_dark.9.png
Binary files differ
diff --git a/tests/HwAccelerationTest/res/drawable-nodpi/progress_vertical_primary_holo_dark.9.png b/tests/graphics/HwAccelerationTest/res/drawable-nodpi/progress_vertical_primary_holo_dark.9.png
similarity index 100%
rename from tests/HwAccelerationTest/res/drawable-nodpi/progress_vertical_primary_holo_dark.9.png
rename to tests/graphics/HwAccelerationTest/res/drawable-nodpi/progress_vertical_primary_holo_dark.9.png
Binary files differ
diff --git a/tests/HwAccelerationTest/res/drawable-nodpi/progress_vertical_secondary_holo_dark.9.png b/tests/graphics/HwAccelerationTest/res/drawable-nodpi/progress_vertical_secondary_holo_dark.9.png
similarity index 100%
rename from tests/HwAccelerationTest/res/drawable-nodpi/progress_vertical_secondary_holo_dark.9.png
rename to tests/graphics/HwAccelerationTest/res/drawable-nodpi/progress_vertical_secondary_holo_dark.9.png
Binary files differ
diff --git a/tests/HwAccelerationTest/res/drawable-nodpi/scratches.png b/tests/graphics/HwAccelerationTest/res/drawable-nodpi/scratches.png
similarity index 100%
rename from tests/HwAccelerationTest/res/drawable-nodpi/scratches.png
rename to tests/graphics/HwAccelerationTest/res/drawable-nodpi/scratches.png
Binary files differ
diff --git a/tests/HwAccelerationTest/res/drawable-nodpi/scrubber_vertical_primary_holo.9.png b/tests/graphics/HwAccelerationTest/res/drawable-nodpi/scrubber_vertical_primary_holo.9.png
similarity index 100%
rename from tests/HwAccelerationTest/res/drawable-nodpi/scrubber_vertical_primary_holo.9.png
rename to tests/graphics/HwAccelerationTest/res/drawable-nodpi/scrubber_vertical_primary_holo.9.png
Binary files differ
diff --git a/tests/HwAccelerationTest/res/drawable-nodpi/scrubber_vertical_secondary_holo.9.png b/tests/graphics/HwAccelerationTest/res/drawable-nodpi/scrubber_vertical_secondary_holo.9.png
similarity index 100%
rename from tests/HwAccelerationTest/res/drawable-nodpi/scrubber_vertical_secondary_holo.9.png
rename to tests/graphics/HwAccelerationTest/res/drawable-nodpi/scrubber_vertical_secondary_holo.9.png
Binary files differ
diff --git a/tests/HwAccelerationTest/res/drawable-nodpi/scrubber_vertical_track_holo_dark.9.png b/tests/graphics/HwAccelerationTest/res/drawable-nodpi/scrubber_vertical_track_holo_dark.9.png
similarity index 100%
rename from tests/HwAccelerationTest/res/drawable-nodpi/scrubber_vertical_track_holo_dark.9.png
rename to tests/graphics/HwAccelerationTest/res/drawable-nodpi/scrubber_vertical_track_holo_dark.9.png
Binary files differ
diff --git a/tests/HwAccelerationTest/res/drawable-nodpi/scrubber_vertical_track_holo_light.9.png b/tests/graphics/HwAccelerationTest/res/drawable-nodpi/scrubber_vertical_track_holo_light.9.png
similarity index 100%
rename from tests/HwAccelerationTest/res/drawable-nodpi/scrubber_vertical_track_holo_light.9.png
rename to tests/graphics/HwAccelerationTest/res/drawable-nodpi/scrubber_vertical_track_holo_light.9.png
Binary files differ
diff --git a/tests/HwAccelerationTest/res/drawable-nodpi/spot_mask.png b/tests/graphics/HwAccelerationTest/res/drawable-nodpi/spot_mask.png
similarity index 100%
rename from tests/HwAccelerationTest/res/drawable-nodpi/spot_mask.png
rename to tests/graphics/HwAccelerationTest/res/drawable-nodpi/spot_mask.png
Binary files differ
diff --git a/tests/HwAccelerationTest/res/drawable-nodpi/very_large_photo.jpg b/tests/graphics/HwAccelerationTest/res/drawable-nodpi/very_large_photo.jpg
similarity index 100%
rename from tests/HwAccelerationTest/res/drawable-nodpi/very_large_photo.jpg
rename to tests/graphics/HwAccelerationTest/res/drawable-nodpi/very_large_photo.jpg
Binary files differ
diff --git a/tests/HwAccelerationTest/res/drawable-nodpi/weather_2.jpg b/tests/graphics/HwAccelerationTest/res/drawable-nodpi/weather_2.jpg
similarity index 100%
rename from tests/HwAccelerationTest/res/drawable-nodpi/weather_2.jpg
rename to tests/graphics/HwAccelerationTest/res/drawable-nodpi/weather_2.jpg
Binary files differ
diff --git a/tests/HwAccelerationTest/res/drawable-nodpi/widget_title_bg.9.png b/tests/graphics/HwAccelerationTest/res/drawable-nodpi/widget_title_bg.9.png
similarity index 100%
rename from tests/HwAccelerationTest/res/drawable-nodpi/widget_title_bg.9.png
rename to tests/graphics/HwAccelerationTest/res/drawable-nodpi/widget_title_bg.9.png
Binary files differ
diff --git a/tests/HwAccelerationTest/res/drawable/appwidget_background.xml b/tests/graphics/HwAccelerationTest/res/drawable/appwidget_background.xml
similarity index 100%
rename from tests/HwAccelerationTest/res/drawable/appwidget_background.xml
rename to tests/graphics/HwAccelerationTest/res/drawable/appwidget_background.xml
diff --git a/tests/HwAccelerationTest/res/drawable/appwidget_bg.9.png b/tests/graphics/HwAccelerationTest/res/drawable/appwidget_bg.9.png
similarity index 100%
rename from tests/HwAccelerationTest/res/drawable/appwidget_bg.9.png
rename to tests/graphics/HwAccelerationTest/res/drawable/appwidget_bg.9.png
Binary files differ
diff --git a/tests/HwAccelerationTest/res/drawable/appwidget_bg_focus.9.png b/tests/graphics/HwAccelerationTest/res/drawable/appwidget_bg_focus.9.png
similarity index 100%
rename from tests/HwAccelerationTest/res/drawable/appwidget_bg_focus.9.png
rename to tests/graphics/HwAccelerationTest/res/drawable/appwidget_bg_focus.9.png
Binary files differ
diff --git a/tests/HwAccelerationTest/res/drawable/appwidget_bg_press.9.png b/tests/graphics/HwAccelerationTest/res/drawable/appwidget_bg_press.9.png
similarity index 100%
rename from tests/HwAccelerationTest/res/drawable/appwidget_bg_press.9.png
rename to tests/graphics/HwAccelerationTest/res/drawable/appwidget_bg_press.9.png
Binary files differ
diff --git a/tests/HwAccelerationTest/res/drawable/btn_toggle_off.9.png b/tests/graphics/HwAccelerationTest/res/drawable/btn_toggle_off.9.png
similarity index 100%
rename from tests/HwAccelerationTest/res/drawable/btn_toggle_off.9.png
rename to tests/graphics/HwAccelerationTest/res/drawable/btn_toggle_off.9.png
Binary files differ
diff --git a/tests/HwAccelerationTest/res/drawable/btn_toggle_on.9.png b/tests/graphics/HwAccelerationTest/res/drawable/btn_toggle_on.9.png
similarity index 100%
rename from tests/HwAccelerationTest/res/drawable/btn_toggle_on.9.png
rename to tests/graphics/HwAccelerationTest/res/drawable/btn_toggle_on.9.png
Binary files differ
diff --git a/tests/HwAccelerationTest/res/drawable/default_wallpaper.png b/tests/graphics/HwAccelerationTest/res/drawable/default_wallpaper.png
similarity index 100%
rename from tests/HwAccelerationTest/res/drawable/default_wallpaper.png
rename to tests/graphics/HwAccelerationTest/res/drawable/default_wallpaper.png
Binary files differ
diff --git a/tests/HwAccelerationTest/res/drawable/gradient.xml b/tests/graphics/HwAccelerationTest/res/drawable/gradient.xml
similarity index 100%
rename from tests/HwAccelerationTest/res/drawable/gradient.xml
rename to tests/graphics/HwAccelerationTest/res/drawable/gradient.xml
diff --git a/tests/HwAccelerationTest/res/drawable/green_gradient.9.png b/tests/graphics/HwAccelerationTest/res/drawable/green_gradient.9.png
similarity index 100%
rename from tests/HwAccelerationTest/res/drawable/green_gradient.9.png
rename to tests/graphics/HwAccelerationTest/res/drawable/green_gradient.9.png
Binary files differ
diff --git a/tests/HwAccelerationTest/res/drawable/icon.png b/tests/graphics/HwAccelerationTest/res/drawable/icon.png
similarity index 100%
rename from tests/HwAccelerationTest/res/drawable/icon.png
rename to tests/graphics/HwAccelerationTest/res/drawable/icon.png
Binary files differ
diff --git a/tests/HwAccelerationTest/res/drawable/progress_vertical_holo_dark.xml b/tests/graphics/HwAccelerationTest/res/drawable/progress_vertical_holo_dark.xml
similarity index 100%
rename from tests/HwAccelerationTest/res/drawable/progress_vertical_holo_dark.xml
rename to tests/graphics/HwAccelerationTest/res/drawable/progress_vertical_holo_dark.xml
diff --git a/tests/HwAccelerationTest/res/drawable/robot.png b/tests/graphics/HwAccelerationTest/res/drawable/robot.png
similarity index 100%
rename from tests/HwAccelerationTest/res/drawable/robot.png
rename to tests/graphics/HwAccelerationTest/res/drawable/robot.png
Binary files differ
diff --git a/tests/HwAccelerationTest/res/drawable/robot_repeated.xml b/tests/graphics/HwAccelerationTest/res/drawable/robot_repeated.xml
similarity index 100%
rename from tests/HwAccelerationTest/res/drawable/robot_repeated.xml
rename to tests/graphics/HwAccelerationTest/res/drawable/robot_repeated.xml
diff --git a/tests/HwAccelerationTest/res/drawable/round_rect_background.xml b/tests/graphics/HwAccelerationTest/res/drawable/round_rect_background.xml
similarity index 100%
rename from tests/HwAccelerationTest/res/drawable/round_rect_background.xml
rename to tests/graphics/HwAccelerationTest/res/drawable/round_rect_background.xml
diff --git a/tests/HwAccelerationTest/res/drawable/scrubber_progress_vertical_holo_dark.xml b/tests/graphics/HwAccelerationTest/res/drawable/scrubber_progress_vertical_holo_dark.xml
similarity index 100%
rename from tests/HwAccelerationTest/res/drawable/scrubber_progress_vertical_holo_dark.xml
rename to tests/graphics/HwAccelerationTest/res/drawable/scrubber_progress_vertical_holo_dark.xml
diff --git a/tests/HwAccelerationTest/res/drawable/sunset1.jpg b/tests/graphics/HwAccelerationTest/res/drawable/sunset1.jpg
similarity index 100%
rename from tests/HwAccelerationTest/res/drawable/sunset1.jpg
rename to tests/graphics/HwAccelerationTest/res/drawable/sunset1.jpg
Binary files differ
diff --git a/tests/HwAccelerationTest/res/drawable/sunset2.png b/tests/graphics/HwAccelerationTest/res/drawable/sunset2.png
similarity index 100%
rename from tests/HwAccelerationTest/res/drawable/sunset2.png
rename to tests/graphics/HwAccelerationTest/res/drawable/sunset2.png
Binary files differ
diff --git a/tests/HwAccelerationTest/res/drawable/sunset3.png b/tests/graphics/HwAccelerationTest/res/drawable/sunset3.png
similarity index 100%
rename from tests/HwAccelerationTest/res/drawable/sunset3.png
rename to tests/graphics/HwAccelerationTest/res/drawable/sunset3.png
Binary files differ
diff --git a/tests/HwAccelerationTest/res/drawable/widget_header.png b/tests/graphics/HwAccelerationTest/res/drawable/widget_header.png
similarity index 100%
rename from tests/HwAccelerationTest/res/drawable/widget_header.png
rename to tests/graphics/HwAccelerationTest/res/drawable/widget_header.png
Binary files differ
diff --git a/tests/HwAccelerationTest/res/drawable/widget_title_bg.9.png b/tests/graphics/HwAccelerationTest/res/drawable/widget_title_bg.9.png
similarity index 100%
rename from tests/HwAccelerationTest/res/drawable/widget_title_bg.9.png
rename to tests/graphics/HwAccelerationTest/res/drawable/widget_title_bg.9.png
Binary files differ
diff --git a/tests/HwAccelerationTest/res/layout/_advanced_blend.xml b/tests/graphics/HwAccelerationTest/res/layout/_advanced_blend.xml
similarity index 100%
rename from tests/HwAccelerationTest/res/layout/_advanced_blend.xml
rename to tests/graphics/HwAccelerationTest/res/layout/_advanced_blend.xml
diff --git a/tests/HwAccelerationTest/res/layout/_advanced_gradient.xml b/tests/graphics/HwAccelerationTest/res/layout/_advanced_gradient.xml
similarity index 100%
rename from tests/HwAccelerationTest/res/layout/_advanced_gradient.xml
rename to tests/graphics/HwAccelerationTest/res/layout/_advanced_gradient.xml
diff --git a/tests/HwAccelerationTest/res/layout/_layers.xml b/tests/graphics/HwAccelerationTest/res/layout/_layers.xml
similarity index 100%
rename from tests/HwAccelerationTest/res/layout/_layers.xml
rename to tests/graphics/HwAccelerationTest/res/layout/_layers.xml
diff --git a/tests/HwAccelerationTest/res/layout/_lines.xml b/tests/graphics/HwAccelerationTest/res/layout/_lines.xml
similarity index 100%
rename from tests/HwAccelerationTest/res/layout/_lines.xml
rename to tests/graphics/HwAccelerationTest/res/layout/_lines.xml
diff --git a/tests/HwAccelerationTest/res/layout/_newlayers.xml b/tests/graphics/HwAccelerationTest/res/layout/_newlayers.xml
similarity index 100%
rename from tests/HwAccelerationTest/res/layout/_newlayers.xml
rename to tests/graphics/HwAccelerationTest/res/layout/_newlayers.xml
diff --git a/tests/HwAccelerationTest/res/layout/_paths.xml b/tests/graphics/HwAccelerationTest/res/layout/_paths.xml
similarity index 100%
rename from tests/HwAccelerationTest/res/layout/_paths.xml
rename to tests/graphics/HwAccelerationTest/res/layout/_paths.xml
diff --git a/tests/HwAccelerationTest/res/layout/_shaders.xml b/tests/graphics/HwAccelerationTest/res/layout/_shaders.xml
similarity index 100%
rename from tests/HwAccelerationTest/res/layout/_shaders.xml
rename to tests/graphics/HwAccelerationTest/res/layout/_shaders.xml
diff --git a/tests/HwAccelerationTest/res/layout/colored_shadows_activity.xml b/tests/graphics/HwAccelerationTest/res/layout/colored_shadows_activity.xml
similarity index 100%
rename from tests/HwAccelerationTest/res/layout/colored_shadows_activity.xml
rename to tests/graphics/HwAccelerationTest/res/layout/colored_shadows_activity.xml
diff --git a/tests/HwAccelerationTest/res/layout/colored_shadows_row.xml b/tests/graphics/HwAccelerationTest/res/layout/colored_shadows_row.xml
similarity index 100%
rename from tests/HwAccelerationTest/res/layout/colored_shadows_row.xml
rename to tests/graphics/HwAccelerationTest/res/layout/colored_shadows_row.xml
diff --git a/tests/HwAccelerationTest/res/layout/date_picker.xml b/tests/graphics/HwAccelerationTest/res/layout/date_picker.xml
similarity index 100%
rename from tests/HwAccelerationTest/res/layout/date_picker.xml
rename to tests/graphics/HwAccelerationTest/res/layout/date_picker.xml
diff --git a/tests/HwAccelerationTest/res/layout/flipper_item.xml b/tests/graphics/HwAccelerationTest/res/layout/flipper_item.xml
similarity index 100%
rename from tests/HwAccelerationTest/res/layout/flipper_item.xml
rename to tests/graphics/HwAccelerationTest/res/layout/flipper_item.xml
diff --git a/tests/HwAccelerationTest/res/layout/form.xml b/tests/graphics/HwAccelerationTest/res/layout/form.xml
similarity index 100%
rename from tests/HwAccelerationTest/res/layout/form.xml
rename to tests/graphics/HwAccelerationTest/res/layout/form.xml
diff --git a/tests/HwAccelerationTest/res/layout/image_filter_activity.xml b/tests/graphics/HwAccelerationTest/res/layout/image_filter_activity.xml
similarity index 100%
rename from tests/HwAccelerationTest/res/layout/image_filter_activity.xml
rename to tests/graphics/HwAccelerationTest/res/layout/image_filter_activity.xml
diff --git a/tests/HwAccelerationTest/res/layout/labels.xml b/tests/graphics/HwAccelerationTest/res/layout/labels.xml
similarity index 100%
rename from tests/HwAccelerationTest/res/layout/labels.xml
rename to tests/graphics/HwAccelerationTest/res/layout/labels.xml
diff --git a/tests/HwAccelerationTest/res/layout/list_activity.xml b/tests/graphics/HwAccelerationTest/res/layout/list_activity.xml
similarity index 100%
rename from tests/HwAccelerationTest/res/layout/list_activity.xml
rename to tests/graphics/HwAccelerationTest/res/layout/list_activity.xml
diff --git a/tests/HwAccelerationTest/res/layout/pen_stylus.xml b/tests/graphics/HwAccelerationTest/res/layout/pen_stylus.xml
similarity index 100%
rename from tests/HwAccelerationTest/res/layout/pen_stylus.xml
rename to tests/graphics/HwAccelerationTest/res/layout/pen_stylus.xml
diff --git a/tests/HwAccelerationTest/res/layout/projection.xml b/tests/graphics/HwAccelerationTest/res/layout/projection.xml
similarity index 100%
rename from tests/HwAccelerationTest/res/layout/projection.xml
rename to tests/graphics/HwAccelerationTest/res/layout/projection.xml
diff --git a/tests/HwAccelerationTest/res/layout/projection_clipping.xml b/tests/graphics/HwAccelerationTest/res/layout/projection_clipping.xml
similarity index 100%
rename from tests/HwAccelerationTest/res/layout/projection_clipping.xml
rename to tests/graphics/HwAccelerationTest/res/layout/projection_clipping.xml
diff --git a/tests/HwAccelerationTest/res/layout/scrolling_stretch_surfaceview.xml b/tests/graphics/HwAccelerationTest/res/layout/scrolling_stretch_surfaceview.xml
similarity index 100%
rename from tests/HwAccelerationTest/res/layout/scrolling_stretch_surfaceview.xml
rename to tests/graphics/HwAccelerationTest/res/layout/scrolling_stretch_surfaceview.xml
diff --git a/tests/HwAccelerationTest/res/layout/stack.xml b/tests/graphics/HwAccelerationTest/res/layout/stack.xml
similarity index 100%
rename from tests/HwAccelerationTest/res/layout/stack.xml
rename to tests/graphics/HwAccelerationTest/res/layout/stack.xml
diff --git a/tests/HwAccelerationTest/res/layout/stack_item.xml b/tests/graphics/HwAccelerationTest/res/layout/stack_item.xml
similarity index 100%
rename from tests/HwAccelerationTest/res/layout/stack_item.xml
rename to tests/graphics/HwAccelerationTest/res/layout/stack_item.xml
diff --git a/tests/HwAccelerationTest/res/layout/stretch_layout.xml b/tests/graphics/HwAccelerationTest/res/layout/stretch_layout.xml
similarity index 100%
rename from tests/HwAccelerationTest/res/layout/stretch_layout.xml
rename to tests/graphics/HwAccelerationTest/res/layout/stretch_layout.xml
diff --git a/tests/HwAccelerationTest/res/layout/text_fade.xml b/tests/graphics/HwAccelerationTest/res/layout/text_fade.xml
similarity index 100%
rename from tests/HwAccelerationTest/res/layout/text_fade.xml
rename to tests/graphics/HwAccelerationTest/res/layout/text_fade.xml
diff --git a/tests/HwAccelerationTest/res/layout/text_large.xml b/tests/graphics/HwAccelerationTest/res/layout/text_large.xml
similarity index 100%
rename from tests/HwAccelerationTest/res/layout/text_large.xml
rename to tests/graphics/HwAccelerationTest/res/layout/text_large.xml
diff --git a/tests/HwAccelerationTest/res/layout/text_medium.xml b/tests/graphics/HwAccelerationTest/res/layout/text_medium.xml
similarity index 100%
rename from tests/HwAccelerationTest/res/layout/text_medium.xml
rename to tests/graphics/HwAccelerationTest/res/layout/text_medium.xml
diff --git a/tests/HwAccelerationTest/res/layout/text_small.xml b/tests/graphics/HwAccelerationTest/res/layout/text_small.xml
similarity index 100%
rename from tests/HwAccelerationTest/res/layout/text_small.xml
rename to tests/graphics/HwAccelerationTest/res/layout/text_small.xml
diff --git a/tests/HwAccelerationTest/res/layout/transforms_and_animations.xml b/tests/graphics/HwAccelerationTest/res/layout/transforms_and_animations.xml
similarity index 100%
rename from tests/HwAccelerationTest/res/layout/transforms_and_animations.xml
rename to tests/graphics/HwAccelerationTest/res/layout/transforms_and_animations.xml
diff --git a/tests/HwAccelerationTest/res/layout/view_layer_invalidation.xml b/tests/graphics/HwAccelerationTest/res/layout/view_layer_invalidation.xml
similarity index 100%
rename from tests/HwAccelerationTest/res/layout/view_layer_invalidation.xml
rename to tests/graphics/HwAccelerationTest/res/layout/view_layer_invalidation.xml
diff --git a/tests/HwAccelerationTest/res/layout/view_layers.xml b/tests/graphics/HwAccelerationTest/res/layout/view_layers.xml
similarity index 100%
rename from tests/HwAccelerationTest/res/layout/view_layers.xml
rename to tests/graphics/HwAccelerationTest/res/layout/view_layers.xml
diff --git a/tests/HwAccelerationTest/res/layout/view_layers_3.xml b/tests/graphics/HwAccelerationTest/res/layout/view_layers_3.xml
similarity index 100%
rename from tests/HwAccelerationTest/res/layout/view_layers_3.xml
rename to tests/graphics/HwAccelerationTest/res/layout/view_layers_3.xml
diff --git a/tests/HwAccelerationTest/res/layout/view_layers_4.xml b/tests/graphics/HwAccelerationTest/res/layout/view_layers_4.xml
similarity index 100%
rename from tests/HwAccelerationTest/res/layout/view_layers_4.xml
rename to tests/graphics/HwAccelerationTest/res/layout/view_layers_4.xml
diff --git a/tests/HwAccelerationTest/res/layout/view_layers_5.xml b/tests/graphics/HwAccelerationTest/res/layout/view_layers_5.xml
similarity index 100%
rename from tests/HwAccelerationTest/res/layout/view_layers_5.xml
rename to tests/graphics/HwAccelerationTest/res/layout/view_layers_5.xml
diff --git a/tests/HwAccelerationTest/res/layout/view_properties.xml b/tests/graphics/HwAccelerationTest/res/layout/view_properties.xml
similarity index 100%
rename from tests/HwAccelerationTest/res/layout/view_properties.xml
rename to tests/graphics/HwAccelerationTest/res/layout/view_properties.xml
diff --git a/tests/HwAccelerationTest/res/layout/view_runtime_shader.xml b/tests/graphics/HwAccelerationTest/res/layout/view_runtime_shader.xml
similarity index 100%
rename from tests/HwAccelerationTest/res/layout/view_runtime_shader.xml
rename to tests/graphics/HwAccelerationTest/res/layout/view_runtime_shader.xml
diff --git a/tests/HwAccelerationTest/res/layout/widget.xml b/tests/graphics/HwAccelerationTest/res/layout/widget.xml
similarity index 100%
rename from tests/HwAccelerationTest/res/layout/widget.xml
rename to tests/graphics/HwAccelerationTest/res/layout/widget.xml
diff --git a/tests/HwAccelerationTest/res/layout/z_ordering.xml b/tests/graphics/HwAccelerationTest/res/layout/z_ordering.xml
similarity index 100%
rename from tests/HwAccelerationTest/res/layout/z_ordering.xml
rename to tests/graphics/HwAccelerationTest/res/layout/z_ordering.xml
diff --git a/tests/HwAccelerationTest/res/raw/colorgrid_video.mp4 b/tests/graphics/HwAccelerationTest/res/raw/colorgrid_video.mp4
similarity index 100%
rename from tests/HwAccelerationTest/res/raw/colorgrid_video.mp4
rename to tests/graphics/HwAccelerationTest/res/raw/colorgrid_video.mp4
Binary files differ
diff --git a/tests/HwAccelerationTest/res/values/strings.xml b/tests/graphics/HwAccelerationTest/res/values/strings.xml
similarity index 100%
rename from tests/HwAccelerationTest/res/values/strings.xml
rename to tests/graphics/HwAccelerationTest/res/values/strings.xml
diff --git a/tests/HwAccelerationTest/res/values/styles.xml b/tests/graphics/HwAccelerationTest/res/values/styles.xml
similarity index 100%
rename from tests/HwAccelerationTest/res/values/styles.xml
rename to tests/graphics/HwAccelerationTest/res/values/styles.xml
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/AdvancedBlendActivity.java b/tests/graphics/HwAccelerationTest/src/com/android/test/hwui/AdvancedBlendActivity.java
similarity index 100%
rename from tests/HwAccelerationTest/src/com/android/test/hwui/AdvancedBlendActivity.java
rename to tests/graphics/HwAccelerationTest/src/com/android/test/hwui/AdvancedBlendActivity.java
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/AdvancedGradientsActivity.java b/tests/graphics/HwAccelerationTest/src/com/android/test/hwui/AdvancedGradientsActivity.java
similarity index 100%
rename from tests/HwAccelerationTest/src/com/android/test/hwui/AdvancedGradientsActivity.java
rename to tests/graphics/HwAccelerationTest/src/com/android/test/hwui/AdvancedGradientsActivity.java
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/Alpha8BitmapActivity.java b/tests/graphics/HwAccelerationTest/src/com/android/test/hwui/Alpha8BitmapActivity.java
similarity index 100%
rename from tests/HwAccelerationTest/src/com/android/test/hwui/Alpha8BitmapActivity.java
rename to tests/graphics/HwAccelerationTest/src/com/android/test/hwui/Alpha8BitmapActivity.java
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/AlphaLayersActivity.java b/tests/graphics/HwAccelerationTest/src/com/android/test/hwui/AlphaLayersActivity.java
similarity index 100%
rename from tests/HwAccelerationTest/src/com/android/test/hwui/AlphaLayersActivity.java
rename to tests/graphics/HwAccelerationTest/src/com/android/test/hwui/AlphaLayersActivity.java
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/Animated3dActivity.java b/tests/graphics/HwAccelerationTest/src/com/android/test/hwui/Animated3dActivity.java
similarity index 100%
rename from tests/HwAccelerationTest/src/com/android/test/hwui/Animated3dActivity.java
rename to tests/graphics/HwAccelerationTest/src/com/android/test/hwui/Animated3dActivity.java
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/AssetsAtlasActivity.java b/tests/graphics/HwAccelerationTest/src/com/android/test/hwui/AssetsAtlasActivity.java
similarity index 100%
rename from tests/HwAccelerationTest/src/com/android/test/hwui/AssetsAtlasActivity.java
rename to tests/graphics/HwAccelerationTest/src/com/android/test/hwui/AssetsAtlasActivity.java
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/BackdropBlurActivity.java b/tests/graphics/HwAccelerationTest/src/com/android/test/hwui/BackdropBlurActivity.java
similarity index 100%
rename from tests/HwAccelerationTest/src/com/android/test/hwui/BackdropBlurActivity.java
rename to tests/graphics/HwAccelerationTest/src/com/android/test/hwui/BackdropBlurActivity.java
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/BigGradientActivity.java b/tests/graphics/HwAccelerationTest/src/com/android/test/hwui/BigGradientActivity.java
similarity index 100%
rename from tests/HwAccelerationTest/src/com/android/test/hwui/BigGradientActivity.java
rename to tests/graphics/HwAccelerationTest/src/com/android/test/hwui/BigGradientActivity.java
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/BitmapMeshActivity.java b/tests/graphics/HwAccelerationTest/src/com/android/test/hwui/BitmapMeshActivity.java
similarity index 100%
rename from tests/HwAccelerationTest/src/com/android/test/hwui/BitmapMeshActivity.java
rename to tests/graphics/HwAccelerationTest/src/com/android/test/hwui/BitmapMeshActivity.java
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/BitmapMeshLayerActivity.java b/tests/graphics/HwAccelerationTest/src/com/android/test/hwui/BitmapMeshLayerActivity.java
similarity index 100%
rename from tests/HwAccelerationTest/src/com/android/test/hwui/BitmapMeshLayerActivity.java
rename to tests/graphics/HwAccelerationTest/src/com/android/test/hwui/BitmapMeshLayerActivity.java
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/BitmapMutateActivity.java b/tests/graphics/HwAccelerationTest/src/com/android/test/hwui/BitmapMutateActivity.java
similarity index 100%
rename from tests/HwAccelerationTest/src/com/android/test/hwui/BitmapMutateActivity.java
rename to tests/graphics/HwAccelerationTest/src/com/android/test/hwui/BitmapMutateActivity.java
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/BitmapTransitionView.kt b/tests/graphics/HwAccelerationTest/src/com/android/test/hwui/BitmapTransitionView.kt
similarity index 100%
rename from tests/HwAccelerationTest/src/com/android/test/hwui/BitmapTransitionView.kt
rename to tests/graphics/HwAccelerationTest/src/com/android/test/hwui/BitmapTransitionView.kt
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/Bitmaps3dActivity.java b/tests/graphics/HwAccelerationTest/src/com/android/test/hwui/Bitmaps3dActivity.java
similarity index 100%
rename from tests/HwAccelerationTest/src/com/android/test/hwui/Bitmaps3dActivity.java
rename to tests/graphics/HwAccelerationTest/src/com/android/test/hwui/Bitmaps3dActivity.java
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/BitmapsActivity.java b/tests/graphics/HwAccelerationTest/src/com/android/test/hwui/BitmapsActivity.java
similarity index 100%
rename from tests/HwAccelerationTest/src/com/android/test/hwui/BitmapsActivity.java
rename to tests/graphics/HwAccelerationTest/src/com/android/test/hwui/BitmapsActivity.java
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/BitmapsAlphaActivity.java b/tests/graphics/HwAccelerationTest/src/com/android/test/hwui/BitmapsAlphaActivity.java
similarity index 100%
rename from tests/HwAccelerationTest/src/com/android/test/hwui/BitmapsAlphaActivity.java
rename to tests/graphics/HwAccelerationTest/src/com/android/test/hwui/BitmapsAlphaActivity.java
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/BitmapsRectActivity.java b/tests/graphics/HwAccelerationTest/src/com/android/test/hwui/BitmapsRectActivity.java
similarity index 100%
rename from tests/HwAccelerationTest/src/com/android/test/hwui/BitmapsRectActivity.java
rename to tests/graphics/HwAccelerationTest/src/com/android/test/hwui/BitmapsRectActivity.java
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/BitmapsSkewActivity.java b/tests/graphics/HwAccelerationTest/src/com/android/test/hwui/BitmapsSkewActivity.java
similarity index 100%
rename from tests/HwAccelerationTest/src/com/android/test/hwui/BitmapsSkewActivity.java
rename to tests/graphics/HwAccelerationTest/src/com/android/test/hwui/BitmapsSkewActivity.java
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/BlurActivity.java b/tests/graphics/HwAccelerationTest/src/com/android/test/hwui/BlurActivity.java
similarity index 100%
rename from tests/HwAccelerationTest/src/com/android/test/hwui/BlurActivity.java
rename to tests/graphics/HwAccelerationTest/src/com/android/test/hwui/BlurActivity.java
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/CanvasTextureViewActivity.java b/tests/graphics/HwAccelerationTest/src/com/android/test/hwui/CanvasTextureViewActivity.java
similarity index 100%
rename from tests/HwAccelerationTest/src/com/android/test/hwui/CanvasTextureViewActivity.java
rename to tests/graphics/HwAccelerationTest/src/com/android/test/hwui/CanvasTextureViewActivity.java
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/CirclePropActivity.java b/tests/graphics/HwAccelerationTest/src/com/android/test/hwui/CirclePropActivity.java
similarity index 100%
rename from tests/HwAccelerationTest/src/com/android/test/hwui/CirclePropActivity.java
rename to tests/graphics/HwAccelerationTest/src/com/android/test/hwui/CirclePropActivity.java
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/ClearActivity.java b/tests/graphics/HwAccelerationTest/src/com/android/test/hwui/ClearActivity.java
similarity index 100%
rename from tests/HwAccelerationTest/src/com/android/test/hwui/ClearActivity.java
rename to tests/graphics/HwAccelerationTest/src/com/android/test/hwui/ClearActivity.java
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/ClipOutlineActivity.java b/tests/graphics/HwAccelerationTest/src/com/android/test/hwui/ClipOutlineActivity.java
similarity index 100%
rename from tests/HwAccelerationTest/src/com/android/test/hwui/ClipOutlineActivity.java
rename to tests/graphics/HwAccelerationTest/src/com/android/test/hwui/ClipOutlineActivity.java
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/ClipRegion2Activity.java b/tests/graphics/HwAccelerationTest/src/com/android/test/hwui/ClipRegion2Activity.java
similarity index 100%
rename from tests/HwAccelerationTest/src/com/android/test/hwui/ClipRegion2Activity.java
rename to tests/graphics/HwAccelerationTest/src/com/android/test/hwui/ClipRegion2Activity.java
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/ClipRegion3Activity.java b/tests/graphics/HwAccelerationTest/src/com/android/test/hwui/ClipRegion3Activity.java
similarity index 100%
rename from tests/HwAccelerationTest/src/com/android/test/hwui/ClipRegion3Activity.java
rename to tests/graphics/HwAccelerationTest/src/com/android/test/hwui/ClipRegion3Activity.java
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/ClipRegionActivity.java b/tests/graphics/HwAccelerationTest/src/com/android/test/hwui/ClipRegionActivity.java
similarity index 100%
rename from tests/HwAccelerationTest/src/com/android/test/hwui/ClipRegionActivity.java
rename to tests/graphics/HwAccelerationTest/src/com/android/test/hwui/ClipRegionActivity.java
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/ColorBitmapActivity.java b/tests/graphics/HwAccelerationTest/src/com/android/test/hwui/ColorBitmapActivity.java
similarity index 100%
rename from tests/HwAccelerationTest/src/com/android/test/hwui/ColorBitmapActivity.java
rename to tests/graphics/HwAccelerationTest/src/com/android/test/hwui/ColorBitmapActivity.java
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/ColorFiltersActivity.java b/tests/graphics/HwAccelerationTest/src/com/android/test/hwui/ColorFiltersActivity.java
similarity index 100%
rename from tests/HwAccelerationTest/src/com/android/test/hwui/ColorFiltersActivity.java
rename to tests/graphics/HwAccelerationTest/src/com/android/test/hwui/ColorFiltersActivity.java
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/ColorFiltersMutateActivity.java b/tests/graphics/HwAccelerationTest/src/com/android/test/hwui/ColorFiltersMutateActivity.java
similarity index 100%
rename from tests/HwAccelerationTest/src/com/android/test/hwui/ColorFiltersMutateActivity.java
rename to tests/graphics/HwAccelerationTest/src/com/android/test/hwui/ColorFiltersMutateActivity.java
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/ColoredRectsActivity.java b/tests/graphics/HwAccelerationTest/src/com/android/test/hwui/ColoredRectsActivity.java
similarity index 100%
rename from tests/HwAccelerationTest/src/com/android/test/hwui/ColoredRectsActivity.java
rename to tests/graphics/HwAccelerationTest/src/com/android/test/hwui/ColoredRectsActivity.java
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/ColoredShadowsActivity.java b/tests/graphics/HwAccelerationTest/src/com/android/test/hwui/ColoredShadowsActivity.java
similarity index 100%
rename from tests/HwAccelerationTest/src/com/android/test/hwui/ColoredShadowsActivity.java
rename to tests/graphics/HwAccelerationTest/src/com/android/test/hwui/ColoredShadowsActivity.java
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/CustomRenderer.java b/tests/graphics/HwAccelerationTest/src/com/android/test/hwui/CustomRenderer.java
similarity index 100%
rename from tests/HwAccelerationTest/src/com/android/test/hwui/CustomRenderer.java
rename to tests/graphics/HwAccelerationTest/src/com/android/test/hwui/CustomRenderer.java
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/DatePicker.java b/tests/graphics/HwAccelerationTest/src/com/android/test/hwui/DatePicker.java
similarity index 100%
rename from tests/HwAccelerationTest/src/com/android/test/hwui/DatePicker.java
rename to tests/graphics/HwAccelerationTest/src/com/android/test/hwui/DatePicker.java
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/DatePickerActivity.java b/tests/graphics/HwAccelerationTest/src/com/android/test/hwui/DatePickerActivity.java
similarity index 100%
rename from tests/HwAccelerationTest/src/com/android/test/hwui/DatePickerActivity.java
rename to tests/graphics/HwAccelerationTest/src/com/android/test/hwui/DatePickerActivity.java
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/DisplayListLayersActivity.java b/tests/graphics/HwAccelerationTest/src/com/android/test/hwui/DisplayListLayersActivity.java
similarity index 100%
rename from tests/HwAccelerationTest/src/com/android/test/hwui/DisplayListLayersActivity.java
rename to tests/graphics/HwAccelerationTest/src/com/android/test/hwui/DisplayListLayersActivity.java
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/DrawIntoHwBitmapActivity.java b/tests/graphics/HwAccelerationTest/src/com/android/test/hwui/DrawIntoHwBitmapActivity.java
similarity index 100%
rename from tests/HwAccelerationTest/src/com/android/test/hwui/DrawIntoHwBitmapActivity.java
rename to tests/graphics/HwAccelerationTest/src/com/android/test/hwui/DrawIntoHwBitmapActivity.java
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/EdgeEffectStretchActivity.java b/tests/graphics/HwAccelerationTest/src/com/android/test/hwui/EdgeEffectStretchActivity.java
similarity index 100%
rename from tests/HwAccelerationTest/src/com/android/test/hwui/EdgeEffectStretchActivity.java
rename to tests/graphics/HwAccelerationTest/src/com/android/test/hwui/EdgeEffectStretchActivity.java
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/FramebufferBlendActivity.java b/tests/graphics/HwAccelerationTest/src/com/android/test/hwui/FramebufferBlendActivity.java
similarity index 100%
rename from tests/HwAccelerationTest/src/com/android/test/hwui/FramebufferBlendActivity.java
rename to tests/graphics/HwAccelerationTest/src/com/android/test/hwui/FramebufferBlendActivity.java
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/FrontBufferedLayer.kt b/tests/graphics/HwAccelerationTest/src/com/android/test/hwui/FrontBufferedLayer.kt
similarity index 100%
rename from tests/HwAccelerationTest/src/com/android/test/hwui/FrontBufferedLayer.kt
rename to tests/graphics/HwAccelerationTest/src/com/android/test/hwui/FrontBufferedLayer.kt
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/GLDepthTestActivity.java b/tests/graphics/HwAccelerationTest/src/com/android/test/hwui/GLDepthTestActivity.java
similarity index 100%
rename from tests/HwAccelerationTest/src/com/android/test/hwui/GLDepthTestActivity.java
rename to tests/graphics/HwAccelerationTest/src/com/android/test/hwui/GLDepthTestActivity.java
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/GLTextureViewActivity.java b/tests/graphics/HwAccelerationTest/src/com/android/test/hwui/GLTextureViewActivity.java
similarity index 100%
rename from tests/HwAccelerationTest/src/com/android/test/hwui/GLTextureViewActivity.java
rename to tests/graphics/HwAccelerationTest/src/com/android/test/hwui/GLTextureViewActivity.java
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/GetBitmapActivity.java b/tests/graphics/HwAccelerationTest/src/com/android/test/hwui/GetBitmapActivity.java
similarity index 100%
rename from tests/HwAccelerationTest/src/com/android/test/hwui/GetBitmapActivity.java
rename to tests/graphics/HwAccelerationTest/src/com/android/test/hwui/GetBitmapActivity.java
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/GetBitmapSurfaceViewActivity.java b/tests/graphics/HwAccelerationTest/src/com/android/test/hwui/GetBitmapSurfaceViewActivity.java
similarity index 100%
rename from tests/HwAccelerationTest/src/com/android/test/hwui/GetBitmapSurfaceViewActivity.java
rename to tests/graphics/HwAccelerationTest/src/com/android/test/hwui/GetBitmapSurfaceViewActivity.java
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/GlyphCacheActivity.java b/tests/graphics/HwAccelerationTest/src/com/android/test/hwui/GlyphCacheActivity.java
similarity index 100%
rename from tests/HwAccelerationTest/src/com/android/test/hwui/GlyphCacheActivity.java
rename to tests/graphics/HwAccelerationTest/src/com/android/test/hwui/GlyphCacheActivity.java
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/GradientStopsActivity.java b/tests/graphics/HwAccelerationTest/src/com/android/test/hwui/GradientStopsActivity.java
similarity index 100%
rename from tests/HwAccelerationTest/src/com/android/test/hwui/GradientStopsActivity.java
rename to tests/graphics/HwAccelerationTest/src/com/android/test/hwui/GradientStopsActivity.java
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/GradientsActivity.java b/tests/graphics/HwAccelerationTest/src/com/android/test/hwui/GradientsActivity.java
similarity index 100%
rename from tests/HwAccelerationTest/src/com/android/test/hwui/GradientsActivity.java
rename to tests/graphics/HwAccelerationTest/src/com/android/test/hwui/GradientsActivity.java
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/HardwareBufferRendererActivity.java b/tests/graphics/HwAccelerationTest/src/com/android/test/hwui/HardwareBufferRendererActivity.java
similarity index 100%
rename from tests/HwAccelerationTest/src/com/android/test/hwui/HardwareBufferRendererActivity.java
rename to tests/graphics/HwAccelerationTest/src/com/android/test/hwui/HardwareBufferRendererActivity.java
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/HardwareCanvasSurfaceViewActivity.java b/tests/graphics/HwAccelerationTest/src/com/android/test/hwui/HardwareCanvasSurfaceViewActivity.java
similarity index 100%
rename from tests/HwAccelerationTest/src/com/android/test/hwui/HardwareCanvasSurfaceViewActivity.java
rename to tests/graphics/HwAccelerationTest/src/com/android/test/hwui/HardwareCanvasSurfaceViewActivity.java
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/HardwareCanvasTextureViewActivity.java b/tests/graphics/HwAccelerationTest/src/com/android/test/hwui/HardwareCanvasTextureViewActivity.java
similarity index 100%
rename from tests/HwAccelerationTest/src/com/android/test/hwui/HardwareCanvasTextureViewActivity.java
rename to tests/graphics/HwAccelerationTest/src/com/android/test/hwui/HardwareCanvasTextureViewActivity.java
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/HwTests.java b/tests/graphics/HwAccelerationTest/src/com/android/test/hwui/HwTests.java
similarity index 100%
rename from tests/HwAccelerationTest/src/com/android/test/hwui/HwTests.java
rename to tests/graphics/HwAccelerationTest/src/com/android/test/hwui/HwTests.java
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/LabelsActivity.java b/tests/graphics/HwAccelerationTest/src/com/android/test/hwui/LabelsActivity.java
similarity index 100%
rename from tests/HwAccelerationTest/src/com/android/test/hwui/LabelsActivity.java
rename to tests/graphics/HwAccelerationTest/src/com/android/test/hwui/LabelsActivity.java
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/LayersActivity.java b/tests/graphics/HwAccelerationTest/src/com/android/test/hwui/LayersActivity.java
similarity index 100%
rename from tests/HwAccelerationTest/src/com/android/test/hwui/LayersActivity.java
rename to tests/graphics/HwAccelerationTest/src/com/android/test/hwui/LayersActivity.java
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/Lines2Activity.java b/tests/graphics/HwAccelerationTest/src/com/android/test/hwui/Lines2Activity.java
similarity index 100%
rename from tests/HwAccelerationTest/src/com/android/test/hwui/Lines2Activity.java
rename to tests/graphics/HwAccelerationTest/src/com/android/test/hwui/Lines2Activity.java
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/LinesActivity.java b/tests/graphics/HwAccelerationTest/src/com/android/test/hwui/LinesActivity.java
similarity index 100%
rename from tests/HwAccelerationTest/src/com/android/test/hwui/LinesActivity.java
rename to tests/graphics/HwAccelerationTest/src/com/android/test/hwui/LinesActivity.java
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/ListActivity.java b/tests/graphics/HwAccelerationTest/src/com/android/test/hwui/ListActivity.java
similarity index 100%
rename from tests/HwAccelerationTest/src/com/android/test/hwui/ListActivity.java
rename to tests/graphics/HwAccelerationTest/src/com/android/test/hwui/ListActivity.java
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/LooperAcceleration.java b/tests/graphics/HwAccelerationTest/src/com/android/test/hwui/LooperAcceleration.java
similarity index 100%
rename from tests/HwAccelerationTest/src/com/android/test/hwui/LooperAcceleration.java
rename to tests/graphics/HwAccelerationTest/src/com/android/test/hwui/LooperAcceleration.java
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/MarqueeActivity.java b/tests/graphics/HwAccelerationTest/src/com/android/test/hwui/MarqueeActivity.java
similarity index 100%
rename from tests/HwAccelerationTest/src/com/android/test/hwui/MarqueeActivity.java
rename to tests/graphics/HwAccelerationTest/src/com/android/test/hwui/MarqueeActivity.java
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/MatrixActivity.java b/tests/graphics/HwAccelerationTest/src/com/android/test/hwui/MatrixActivity.java
similarity index 100%
rename from tests/HwAccelerationTest/src/com/android/test/hwui/MatrixActivity.java
rename to tests/graphics/HwAccelerationTest/src/com/android/test/hwui/MatrixActivity.java
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/MaxBitmapSizeActivity.java b/tests/graphics/HwAccelerationTest/src/com/android/test/hwui/MaxBitmapSizeActivity.java
similarity index 100%
rename from tests/HwAccelerationTest/src/com/android/test/hwui/MaxBitmapSizeActivity.java
rename to tests/graphics/HwAccelerationTest/src/com/android/test/hwui/MaxBitmapSizeActivity.java
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/MeshActivity.java b/tests/graphics/HwAccelerationTest/src/com/android/test/hwui/MeshActivity.java
similarity index 100%
rename from tests/HwAccelerationTest/src/com/android/test/hwui/MeshActivity.java
rename to tests/graphics/HwAccelerationTest/src/com/android/test/hwui/MeshActivity.java
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/MeshLargeActivity.java b/tests/graphics/HwAccelerationTest/src/com/android/test/hwui/MeshLargeActivity.java
similarity index 100%
rename from tests/HwAccelerationTest/src/com/android/test/hwui/MeshLargeActivity.java
rename to tests/graphics/HwAccelerationTest/src/com/android/test/hwui/MeshLargeActivity.java
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/MipMapActivity.java b/tests/graphics/HwAccelerationTest/src/com/android/test/hwui/MipMapActivity.java
similarity index 100%
rename from tests/HwAccelerationTest/src/com/android/test/hwui/MipMapActivity.java
rename to tests/graphics/HwAccelerationTest/src/com/android/test/hwui/MipMapActivity.java
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/MoreNinePatchesActivity.java b/tests/graphics/HwAccelerationTest/src/com/android/test/hwui/MoreNinePatchesActivity.java
similarity index 100%
rename from tests/HwAccelerationTest/src/com/android/test/hwui/MoreNinePatchesActivity.java
rename to tests/graphics/HwAccelerationTest/src/com/android/test/hwui/MoreNinePatchesActivity.java
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/MoreShadersActivity.java b/tests/graphics/HwAccelerationTest/src/com/android/test/hwui/MoreShadersActivity.java
similarity index 100%
rename from tests/HwAccelerationTest/src/com/android/test/hwui/MoreShadersActivity.java
rename to tests/graphics/HwAccelerationTest/src/com/android/test/hwui/MoreShadersActivity.java
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/MovingSurfaceViewActivity.java b/tests/graphics/HwAccelerationTest/src/com/android/test/hwui/MovingSurfaceViewActivity.java
similarity index 100%
rename from tests/HwAccelerationTest/src/com/android/test/hwui/MovingSurfaceViewActivity.java
rename to tests/graphics/HwAccelerationTest/src/com/android/test/hwui/MovingSurfaceViewActivity.java
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/MultiLayersActivity.java b/tests/graphics/HwAccelerationTest/src/com/android/test/hwui/MultiLayersActivity.java
similarity index 100%
rename from tests/HwAccelerationTest/src/com/android/test/hwui/MultiLayersActivity.java
rename to tests/graphics/HwAccelerationTest/src/com/android/test/hwui/MultiLayersActivity.java
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/MultiProducerActivity.java b/tests/graphics/HwAccelerationTest/src/com/android/test/hwui/MultiProducerActivity.java
similarity index 100%
rename from tests/HwAccelerationTest/src/com/android/test/hwui/MultiProducerActivity.java
rename to tests/graphics/HwAccelerationTest/src/com/android/test/hwui/MultiProducerActivity.java
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/MyLittleTextureView.java b/tests/graphics/HwAccelerationTest/src/com/android/test/hwui/MyLittleTextureView.java
similarity index 100%
rename from tests/HwAccelerationTest/src/com/android/test/hwui/MyLittleTextureView.java
rename to tests/graphics/HwAccelerationTest/src/com/android/test/hwui/MyLittleTextureView.java
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/NewLayersActivity.java b/tests/graphics/HwAccelerationTest/src/com/android/test/hwui/NewLayersActivity.java
similarity index 100%
rename from tests/HwAccelerationTest/src/com/android/test/hwui/NewLayersActivity.java
rename to tests/graphics/HwAccelerationTest/src/com/android/test/hwui/NewLayersActivity.java
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/NinePatchesActivity.java b/tests/graphics/HwAccelerationTest/src/com/android/test/hwui/NinePatchesActivity.java
similarity index 100%
rename from tests/HwAccelerationTest/src/com/android/test/hwui/NinePatchesActivity.java
rename to tests/graphics/HwAccelerationTest/src/com/android/test/hwui/NinePatchesActivity.java
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/NoAATextActivity.java b/tests/graphics/HwAccelerationTest/src/com/android/test/hwui/NoAATextActivity.java
similarity index 100%
rename from tests/HwAccelerationTest/src/com/android/test/hwui/NoAATextActivity.java
rename to tests/graphics/HwAccelerationTest/src/com/android/test/hwui/NoAATextActivity.java
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/OpaqueActivity.java b/tests/graphics/HwAccelerationTest/src/com/android/test/hwui/OpaqueActivity.java
similarity index 100%
rename from tests/HwAccelerationTest/src/com/android/test/hwui/OpaqueActivity.java
rename to tests/graphics/HwAccelerationTest/src/com/android/test/hwui/OpaqueActivity.java
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/PaintDrawFilterActivity.java b/tests/graphics/HwAccelerationTest/src/com/android/test/hwui/PaintDrawFilterActivity.java
similarity index 100%
rename from tests/HwAccelerationTest/src/com/android/test/hwui/PaintDrawFilterActivity.java
rename to tests/graphics/HwAccelerationTest/src/com/android/test/hwui/PaintDrawFilterActivity.java
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/PathDestructionActivity.java b/tests/graphics/HwAccelerationTest/src/com/android/test/hwui/PathDestructionActivity.java
similarity index 100%
rename from tests/HwAccelerationTest/src/com/android/test/hwui/PathDestructionActivity.java
rename to tests/graphics/HwAccelerationTest/src/com/android/test/hwui/PathDestructionActivity.java
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/PathOffsetActivity.java b/tests/graphics/HwAccelerationTest/src/com/android/test/hwui/PathOffsetActivity.java
similarity index 100%
rename from tests/HwAccelerationTest/src/com/android/test/hwui/PathOffsetActivity.java
rename to tests/graphics/HwAccelerationTest/src/com/android/test/hwui/PathOffsetActivity.java
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/PathOpsActivity.java b/tests/graphics/HwAccelerationTest/src/com/android/test/hwui/PathOpsActivity.java
similarity index 100%
rename from tests/HwAccelerationTest/src/com/android/test/hwui/PathOpsActivity.java
rename to tests/graphics/HwAccelerationTest/src/com/android/test/hwui/PathOpsActivity.java
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/PathsActivity.java b/tests/graphics/HwAccelerationTest/src/com/android/test/hwui/PathsActivity.java
similarity index 100%
rename from tests/HwAccelerationTest/src/com/android/test/hwui/PathsActivity.java
rename to tests/graphics/HwAccelerationTest/src/com/android/test/hwui/PathsActivity.java
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/PathsCacheActivity.java b/tests/graphics/HwAccelerationTest/src/com/android/test/hwui/PathsCacheActivity.java
similarity index 100%
rename from tests/HwAccelerationTest/src/com/android/test/hwui/PathsCacheActivity.java
rename to tests/graphics/HwAccelerationTest/src/com/android/test/hwui/PathsCacheActivity.java
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/PenStylusActivity.kt b/tests/graphics/HwAccelerationTest/src/com/android/test/hwui/PenStylusActivity.kt
similarity index 100%
rename from tests/HwAccelerationTest/src/com/android/test/hwui/PenStylusActivity.kt
rename to tests/graphics/HwAccelerationTest/src/com/android/test/hwui/PenStylusActivity.kt
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/PictureCaptureDemo.java b/tests/graphics/HwAccelerationTest/src/com/android/test/hwui/PictureCaptureDemo.java
similarity index 100%
rename from tests/HwAccelerationTest/src/com/android/test/hwui/PictureCaptureDemo.java
rename to tests/graphics/HwAccelerationTest/src/com/android/test/hwui/PictureCaptureDemo.java
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/PixelCopyWindow.java b/tests/graphics/HwAccelerationTest/src/com/android/test/hwui/PixelCopyWindow.java
similarity index 100%
rename from tests/HwAccelerationTest/src/com/android/test/hwui/PixelCopyWindow.java
rename to tests/graphics/HwAccelerationTest/src/com/android/test/hwui/PixelCopyWindow.java
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/PointsActivity.java b/tests/graphics/HwAccelerationTest/src/com/android/test/hwui/PointsActivity.java
similarity index 100%
rename from tests/HwAccelerationTest/src/com/android/test/hwui/PointsActivity.java
rename to tests/graphics/HwAccelerationTest/src/com/android/test/hwui/PointsActivity.java
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/PosTextActivity.java b/tests/graphics/HwAccelerationTest/src/com/android/test/hwui/PosTextActivity.java
similarity index 100%
rename from tests/HwAccelerationTest/src/com/android/test/hwui/PosTextActivity.java
rename to tests/graphics/HwAccelerationTest/src/com/android/test/hwui/PosTextActivity.java
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/PositionListenerActivity.java b/tests/graphics/HwAccelerationTest/src/com/android/test/hwui/PositionListenerActivity.java
similarity index 100%
rename from tests/HwAccelerationTest/src/com/android/test/hwui/PositionListenerActivity.java
rename to tests/graphics/HwAccelerationTest/src/com/android/test/hwui/PositionListenerActivity.java
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/ProjectionActivity.java b/tests/graphics/HwAccelerationTest/src/com/android/test/hwui/ProjectionActivity.java
similarity index 100%
rename from tests/HwAccelerationTest/src/com/android/test/hwui/ProjectionActivity.java
rename to tests/graphics/HwAccelerationTest/src/com/android/test/hwui/ProjectionActivity.java
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/ProjectionClippingActivity.java b/tests/graphics/HwAccelerationTest/src/com/android/test/hwui/ProjectionClippingActivity.java
similarity index 100%
rename from tests/HwAccelerationTest/src/com/android/test/hwui/ProjectionClippingActivity.java
rename to tests/graphics/HwAccelerationTest/src/com/android/test/hwui/ProjectionClippingActivity.java
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/QuickRejectActivity.java b/tests/graphics/HwAccelerationTest/src/com/android/test/hwui/QuickRejectActivity.java
similarity index 100%
rename from tests/HwAccelerationTest/src/com/android/test/hwui/QuickRejectActivity.java
rename to tests/graphics/HwAccelerationTest/src/com/android/test/hwui/QuickRejectActivity.java
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/RenderEffectShaderActivity.java b/tests/graphics/HwAccelerationTest/src/com/android/test/hwui/RenderEffectShaderActivity.java
similarity index 100%
rename from tests/HwAccelerationTest/src/com/android/test/hwui/RenderEffectShaderActivity.java
rename to tests/graphics/HwAccelerationTest/src/com/android/test/hwui/RenderEffectShaderActivity.java
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/RenderEffectViewActivity.kt b/tests/graphics/HwAccelerationTest/src/com/android/test/hwui/RenderEffectViewActivity.kt
similarity index 100%
rename from tests/HwAccelerationTest/src/com/android/test/hwui/RenderEffectViewActivity.kt
rename to tests/graphics/HwAccelerationTest/src/com/android/test/hwui/RenderEffectViewActivity.kt
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/ResizeActivity.java b/tests/graphics/HwAccelerationTest/src/com/android/test/hwui/ResizeActivity.java
similarity index 100%
rename from tests/HwAccelerationTest/src/com/android/test/hwui/ResizeActivity.java
rename to tests/graphics/HwAccelerationTest/src/com/android/test/hwui/ResizeActivity.java
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/RevealActivity.java b/tests/graphics/HwAccelerationTest/src/com/android/test/hwui/RevealActivity.java
similarity index 100%
rename from tests/HwAccelerationTest/src/com/android/test/hwui/RevealActivity.java
rename to tests/graphics/HwAccelerationTest/src/com/android/test/hwui/RevealActivity.java
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/RippleActivity.java b/tests/graphics/HwAccelerationTest/src/com/android/test/hwui/RippleActivity.java
similarity index 100%
rename from tests/HwAccelerationTest/src/com/android/test/hwui/RippleActivity.java
rename to tests/graphics/HwAccelerationTest/src/com/android/test/hwui/RippleActivity.java
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/Rotate3dTextActivity.java b/tests/graphics/HwAccelerationTest/src/com/android/test/hwui/Rotate3dTextActivity.java
similarity index 100%
rename from tests/HwAccelerationTest/src/com/android/test/hwui/Rotate3dTextActivity.java
rename to tests/graphics/HwAccelerationTest/src/com/android/test/hwui/Rotate3dTextActivity.java
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/RotationActivity.java b/tests/graphics/HwAccelerationTest/src/com/android/test/hwui/RotationActivity.java
similarity index 100%
rename from tests/HwAccelerationTest/src/com/android/test/hwui/RotationActivity.java
rename to tests/graphics/HwAccelerationTest/src/com/android/test/hwui/RotationActivity.java
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/ScaledPathsActivity.java b/tests/graphics/HwAccelerationTest/src/com/android/test/hwui/ScaledPathsActivity.java
similarity index 100%
rename from tests/HwAccelerationTest/src/com/android/test/hwui/ScaledPathsActivity.java
rename to tests/graphics/HwAccelerationTest/src/com/android/test/hwui/ScaledPathsActivity.java
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/ScaledTextActivity.java b/tests/graphics/HwAccelerationTest/src/com/android/test/hwui/ScaledTextActivity.java
similarity index 100%
rename from tests/HwAccelerationTest/src/com/android/test/hwui/ScaledTextActivity.java
rename to tests/graphics/HwAccelerationTest/src/com/android/test/hwui/ScaledTextActivity.java
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/ScrollingStretchSurfaceViewActivity.java b/tests/graphics/HwAccelerationTest/src/com/android/test/hwui/ScrollingStretchSurfaceViewActivity.java
similarity index 100%
rename from tests/HwAccelerationTest/src/com/android/test/hwui/ScrollingStretchSurfaceViewActivity.java
rename to tests/graphics/HwAccelerationTest/src/com/android/test/hwui/ScrollingStretchSurfaceViewActivity.java
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/ShadersActivity.java b/tests/graphics/HwAccelerationTest/src/com/android/test/hwui/ShadersActivity.java
similarity index 100%
rename from tests/HwAccelerationTest/src/com/android/test/hwui/ShadersActivity.java
rename to tests/graphics/HwAccelerationTest/src/com/android/test/hwui/ShadersActivity.java
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/ShapesActivity.java b/tests/graphics/HwAccelerationTest/src/com/android/test/hwui/ShapesActivity.java
similarity index 100%
rename from tests/HwAccelerationTest/src/com/android/test/hwui/ShapesActivity.java
rename to tests/graphics/HwAccelerationTest/src/com/android/test/hwui/ShapesActivity.java
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/SimplePatchActivity.java b/tests/graphics/HwAccelerationTest/src/com/android/test/hwui/SimplePatchActivity.java
similarity index 100%
rename from tests/HwAccelerationTest/src/com/android/test/hwui/SimplePatchActivity.java
rename to tests/graphics/HwAccelerationTest/src/com/android/test/hwui/SimplePatchActivity.java
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/SimplePathsActivity.java b/tests/graphics/HwAccelerationTest/src/com/android/test/hwui/SimplePathsActivity.java
similarity index 100%
rename from tests/HwAccelerationTest/src/com/android/test/hwui/SimplePathsActivity.java
rename to tests/graphics/HwAccelerationTest/src/com/android/test/hwui/SimplePathsActivity.java
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/SingleFrameTextureViewTestActivity.java b/tests/graphics/HwAccelerationTest/src/com/android/test/hwui/SingleFrameTextureViewTestActivity.java
similarity index 100%
rename from tests/HwAccelerationTest/src/com/android/test/hwui/SingleFrameTextureViewTestActivity.java
rename to tests/graphics/HwAccelerationTest/src/com/android/test/hwui/SingleFrameTextureViewTestActivity.java
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/SmallCircleActivity.java b/tests/graphics/HwAccelerationTest/src/com/android/test/hwui/SmallCircleActivity.java
similarity index 100%
rename from tests/HwAccelerationTest/src/com/android/test/hwui/SmallCircleActivity.java
rename to tests/graphics/HwAccelerationTest/src/com/android/test/hwui/SmallCircleActivity.java
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/StackActivity.java b/tests/graphics/HwAccelerationTest/src/com/android/test/hwui/StackActivity.java
similarity index 100%
rename from tests/HwAccelerationTest/src/com/android/test/hwui/StackActivity.java
rename to tests/graphics/HwAccelerationTest/src/com/android/test/hwui/StackActivity.java
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/StretchShaderActivity.java b/tests/graphics/HwAccelerationTest/src/com/android/test/hwui/StretchShaderActivity.java
similarity index 100%
rename from tests/HwAccelerationTest/src/com/android/test/hwui/StretchShaderActivity.java
rename to tests/graphics/HwAccelerationTest/src/com/android/test/hwui/StretchShaderActivity.java
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/StretchySurfaceViewActivity.java b/tests/graphics/HwAccelerationTest/src/com/android/test/hwui/StretchySurfaceViewActivity.java
similarity index 100%
rename from tests/HwAccelerationTest/src/com/android/test/hwui/StretchySurfaceViewActivity.java
rename to tests/graphics/HwAccelerationTest/src/com/android/test/hwui/StretchySurfaceViewActivity.java
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/SurfaceViewAlphaActivity.java b/tests/graphics/HwAccelerationTest/src/com/android/test/hwui/SurfaceViewAlphaActivity.java
similarity index 100%
rename from tests/HwAccelerationTest/src/com/android/test/hwui/SurfaceViewAlphaActivity.java
rename to tests/graphics/HwAccelerationTest/src/com/android/test/hwui/SurfaceViewAlphaActivity.java
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/TJunctionActivity.java b/tests/graphics/HwAccelerationTest/src/com/android/test/hwui/TJunctionActivity.java
similarity index 100%
rename from tests/HwAccelerationTest/src/com/android/test/hwui/TJunctionActivity.java
rename to tests/graphics/HwAccelerationTest/src/com/android/test/hwui/TJunctionActivity.java
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/TextActivity.java b/tests/graphics/HwAccelerationTest/src/com/android/test/hwui/TextActivity.java
similarity index 100%
rename from tests/HwAccelerationTest/src/com/android/test/hwui/TextActivity.java
rename to tests/graphics/HwAccelerationTest/src/com/android/test/hwui/TextActivity.java
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/TextFadeActivity.java b/tests/graphics/HwAccelerationTest/src/com/android/test/hwui/TextFadeActivity.java
similarity index 100%
rename from tests/HwAccelerationTest/src/com/android/test/hwui/TextFadeActivity.java
rename to tests/graphics/HwAccelerationTest/src/com/android/test/hwui/TextFadeActivity.java
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/TextGammaActivity.java b/tests/graphics/HwAccelerationTest/src/com/android/test/hwui/TextGammaActivity.java
similarity index 100%
rename from tests/HwAccelerationTest/src/com/android/test/hwui/TextGammaActivity.java
rename to tests/graphics/HwAccelerationTest/src/com/android/test/hwui/TextGammaActivity.java
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/TextOnPathActivity.java b/tests/graphics/HwAccelerationTest/src/com/android/test/hwui/TextOnPathActivity.java
similarity index 100%
rename from tests/HwAccelerationTest/src/com/android/test/hwui/TextOnPathActivity.java
rename to tests/graphics/HwAccelerationTest/src/com/android/test/hwui/TextOnPathActivity.java
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/TextPathActivity.java b/tests/graphics/HwAccelerationTest/src/com/android/test/hwui/TextPathActivity.java
similarity index 100%
rename from tests/HwAccelerationTest/src/com/android/test/hwui/TextPathActivity.java
rename to tests/graphics/HwAccelerationTest/src/com/android/test/hwui/TextPathActivity.java
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/TextureViewActivity.java b/tests/graphics/HwAccelerationTest/src/com/android/test/hwui/TextureViewActivity.java
similarity index 100%
rename from tests/HwAccelerationTest/src/com/android/test/hwui/TextureViewActivity.java
rename to tests/graphics/HwAccelerationTest/src/com/android/test/hwui/TextureViewActivity.java
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/ThinPatchesActivity.java b/tests/graphics/HwAccelerationTest/src/com/android/test/hwui/ThinPatchesActivity.java
similarity index 100%
rename from tests/HwAccelerationTest/src/com/android/test/hwui/ThinPatchesActivity.java
rename to tests/graphics/HwAccelerationTest/src/com/android/test/hwui/ThinPatchesActivity.java
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/TimeDialogActivity.java b/tests/graphics/HwAccelerationTest/src/com/android/test/hwui/TimeDialogActivity.java
similarity index 100%
rename from tests/HwAccelerationTest/src/com/android/test/hwui/TimeDialogActivity.java
rename to tests/graphics/HwAccelerationTest/src/com/android/test/hwui/TimeDialogActivity.java
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/Transform3dActivity.java b/tests/graphics/HwAccelerationTest/src/com/android/test/hwui/Transform3dActivity.java
similarity index 100%
rename from tests/HwAccelerationTest/src/com/android/test/hwui/Transform3dActivity.java
rename to tests/graphics/HwAccelerationTest/src/com/android/test/hwui/Transform3dActivity.java
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/TransformsAndAnimationsActivity.java b/tests/graphics/HwAccelerationTest/src/com/android/test/hwui/TransformsAndAnimationsActivity.java
similarity index 100%
rename from tests/HwAccelerationTest/src/com/android/test/hwui/TransformsAndAnimationsActivity.java
rename to tests/graphics/HwAccelerationTest/src/com/android/test/hwui/TransformsAndAnimationsActivity.java
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/TransparentListActivity.java b/tests/graphics/HwAccelerationTest/src/com/android/test/hwui/TransparentListActivity.java
similarity index 100%
rename from tests/HwAccelerationTest/src/com/android/test/hwui/TransparentListActivity.java
rename to tests/graphics/HwAccelerationTest/src/com/android/test/hwui/TransparentListActivity.java
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/VideoViewCaptureActivity.java b/tests/graphics/HwAccelerationTest/src/com/android/test/hwui/VideoViewCaptureActivity.java
similarity index 100%
rename from tests/HwAccelerationTest/src/com/android/test/hwui/VideoViewCaptureActivity.java
rename to tests/graphics/HwAccelerationTest/src/com/android/test/hwui/VideoViewCaptureActivity.java
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/ViewFlipperActivity.java b/tests/graphics/HwAccelerationTest/src/com/android/test/hwui/ViewFlipperActivity.java
similarity index 100%
rename from tests/HwAccelerationTest/src/com/android/test/hwui/ViewFlipperActivity.java
rename to tests/graphics/HwAccelerationTest/src/com/android/test/hwui/ViewFlipperActivity.java
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/ViewLayerInvalidationActivity.java b/tests/graphics/HwAccelerationTest/src/com/android/test/hwui/ViewLayerInvalidationActivity.java
similarity index 100%
rename from tests/HwAccelerationTest/src/com/android/test/hwui/ViewLayerInvalidationActivity.java
rename to tests/graphics/HwAccelerationTest/src/com/android/test/hwui/ViewLayerInvalidationActivity.java
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/ViewLayersActivity.java b/tests/graphics/HwAccelerationTest/src/com/android/test/hwui/ViewLayersActivity.java
similarity index 100%
rename from tests/HwAccelerationTest/src/com/android/test/hwui/ViewLayersActivity.java
rename to tests/graphics/HwAccelerationTest/src/com/android/test/hwui/ViewLayersActivity.java
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/ViewLayersActivity2.java b/tests/graphics/HwAccelerationTest/src/com/android/test/hwui/ViewLayersActivity2.java
similarity index 100%
rename from tests/HwAccelerationTest/src/com/android/test/hwui/ViewLayersActivity2.java
rename to tests/graphics/HwAccelerationTest/src/com/android/test/hwui/ViewLayersActivity2.java
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/ViewLayersActivity3.java b/tests/graphics/HwAccelerationTest/src/com/android/test/hwui/ViewLayersActivity3.java
similarity index 100%
rename from tests/HwAccelerationTest/src/com/android/test/hwui/ViewLayersActivity3.java
rename to tests/graphics/HwAccelerationTest/src/com/android/test/hwui/ViewLayersActivity3.java
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/ViewLayersActivity4.java b/tests/graphics/HwAccelerationTest/src/com/android/test/hwui/ViewLayersActivity4.java
similarity index 100%
rename from tests/HwAccelerationTest/src/com/android/test/hwui/ViewLayersActivity4.java
rename to tests/graphics/HwAccelerationTest/src/com/android/test/hwui/ViewLayersActivity4.java
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/ViewLayersActivity5.java b/tests/graphics/HwAccelerationTest/src/com/android/test/hwui/ViewLayersActivity5.java
similarity index 100%
rename from tests/HwAccelerationTest/src/com/android/test/hwui/ViewLayersActivity5.java
rename to tests/graphics/HwAccelerationTest/src/com/android/test/hwui/ViewLayersActivity5.java
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/ViewPropertyAlphaActivity.java b/tests/graphics/HwAccelerationTest/src/com/android/test/hwui/ViewPropertyAlphaActivity.java
similarity index 100%
rename from tests/HwAccelerationTest/src/com/android/test/hwui/ViewPropertyAlphaActivity.java
rename to tests/graphics/HwAccelerationTest/src/com/android/test/hwui/ViewPropertyAlphaActivity.java
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/XfermodeActivity.java b/tests/graphics/HwAccelerationTest/src/com/android/test/hwui/XfermodeActivity.java
similarity index 100%
rename from tests/HwAccelerationTest/src/com/android/test/hwui/XfermodeActivity.java
rename to tests/graphics/HwAccelerationTest/src/com/android/test/hwui/XfermodeActivity.java
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/ZOrderingActivity.java b/tests/graphics/HwAccelerationTest/src/com/android/test/hwui/ZOrderingActivity.java
similarity index 100%
rename from tests/HwAccelerationTest/src/com/android/test/hwui/ZOrderingActivity.java
rename to tests/graphics/HwAccelerationTest/src/com/android/test/hwui/ZOrderingActivity.java
diff --git a/tests/graphics/OWNERS b/tests/graphics/OWNERS
new file mode 100644
index 0000000..fb7fc14
--- /dev/null
+++ b/tests/graphics/OWNERS
@@ -0,0 +1,3 @@
+# Bug component: 1075130
+
+include /libs/hwui/OWNERS
diff --git a/tests/RenderThreadTest/Android.bp b/tests/graphics/RenderThreadTest/Android.bp
similarity index 100%
rename from tests/RenderThreadTest/Android.bp
rename to tests/graphics/RenderThreadTest/Android.bp
diff --git a/tests/RenderThreadTest/AndroidManifest.xml b/tests/graphics/RenderThreadTest/AndroidManifest.xml
similarity index 100%
rename from tests/RenderThreadTest/AndroidManifest.xml
rename to tests/graphics/RenderThreadTest/AndroidManifest.xml
diff --git a/tests/RenderThreadTest/res/drawable-hdpi/ic_launcher.png b/tests/graphics/RenderThreadTest/res/drawable-hdpi/ic_launcher.png
similarity index 100%
rename from tests/RenderThreadTest/res/drawable-hdpi/ic_launcher.png
rename to tests/graphics/RenderThreadTest/res/drawable-hdpi/ic_launcher.png
Binary files differ
diff --git a/tests/RenderThreadTest/res/drawable-mdpi/ic_launcher.png b/tests/graphics/RenderThreadTest/res/drawable-mdpi/ic_launcher.png
similarity index 100%
rename from tests/RenderThreadTest/res/drawable-mdpi/ic_launcher.png
rename to tests/graphics/RenderThreadTest/res/drawable-mdpi/ic_launcher.png
Binary files differ
diff --git a/tests/RenderThreadTest/res/drawable-xhdpi/ic_launcher.png b/tests/graphics/RenderThreadTest/res/drawable-xhdpi/ic_launcher.png
similarity index 100%
rename from tests/RenderThreadTest/res/drawable-xhdpi/ic_launcher.png
rename to tests/graphics/RenderThreadTest/res/drawable-xhdpi/ic_launcher.png
Binary files differ
diff --git a/tests/RenderThreadTest/res/drawable-xhdpi/starry_night_bg.jpg b/tests/graphics/RenderThreadTest/res/drawable-xhdpi/starry_night_bg.jpg
similarity index 100%
rename from tests/RenderThreadTest/res/drawable-xhdpi/starry_night_bg.jpg
rename to tests/graphics/RenderThreadTest/res/drawable-xhdpi/starry_night_bg.jpg
Binary files differ
diff --git a/tests/RenderThreadTest/res/layout/activity_main.xml b/tests/graphics/RenderThreadTest/res/layout/activity_main.xml
similarity index 100%
rename from tests/RenderThreadTest/res/layout/activity_main.xml
rename to tests/graphics/RenderThreadTest/res/layout/activity_main.xml
diff --git a/tests/RenderThreadTest/res/layout/activity_sub.xml b/tests/graphics/RenderThreadTest/res/layout/activity_sub.xml
similarity index 100%
rename from tests/RenderThreadTest/res/layout/activity_sub.xml
rename to tests/graphics/RenderThreadTest/res/layout/activity_sub.xml
diff --git a/tests/RenderThreadTest/res/layout/item_layout.xml b/tests/graphics/RenderThreadTest/res/layout/item_layout.xml
similarity index 100%
rename from tests/RenderThreadTest/res/layout/item_layout.xml
rename to tests/graphics/RenderThreadTest/res/layout/item_layout.xml
diff --git a/tests/RenderThreadTest/res/values/strings.xml b/tests/graphics/RenderThreadTest/res/values/strings.xml
similarity index 100%
rename from tests/RenderThreadTest/res/values/strings.xml
rename to tests/graphics/RenderThreadTest/res/values/strings.xml
diff --git a/tests/RenderThreadTest/res/values/styles.xml b/tests/graphics/RenderThreadTest/res/values/styles.xml
similarity index 100%
rename from tests/RenderThreadTest/res/values/styles.xml
rename to tests/graphics/RenderThreadTest/res/values/styles.xml
diff --git a/tests/RenderThreadTest/src/com/example/renderthread/MainActivity.java b/tests/graphics/RenderThreadTest/src/com/example/renderthread/MainActivity.java
similarity index 100%
rename from tests/RenderThreadTest/src/com/example/renderthread/MainActivity.java
rename to tests/graphics/RenderThreadTest/src/com/example/renderthread/MainActivity.java
diff --git a/tests/RenderThreadTest/src/com/example/renderthread/SubActivity.java b/tests/graphics/RenderThreadTest/src/com/example/renderthread/SubActivity.java
similarity index 100%
rename from tests/RenderThreadTest/src/com/example/renderthread/SubActivity.java
rename to tests/graphics/RenderThreadTest/src/com/example/renderthread/SubActivity.java
diff --git a/tests/SilkFX/Android.bp b/tests/graphics/SilkFX/Android.bp
similarity index 100%
rename from tests/SilkFX/Android.bp
rename to tests/graphics/SilkFX/Android.bp
diff --git a/tests/SilkFX/AndroidManifest.xml b/tests/graphics/SilkFX/AndroidManifest.xml
similarity index 100%
rename from tests/SilkFX/AndroidManifest.xml
rename to tests/graphics/SilkFX/AndroidManifest.xml
diff --git a/tests/SilkFX/assets/gainmaps/city_night.jpg b/tests/graphics/SilkFX/assets/gainmaps/city_night.jpg
similarity index 100%
rename from tests/SilkFX/assets/gainmaps/city_night.jpg
rename to tests/graphics/SilkFX/assets/gainmaps/city_night.jpg
Binary files differ
diff --git a/tests/SilkFX/assets/gainmaps/desert_palms.jpg b/tests/graphics/SilkFX/assets/gainmaps/desert_palms.jpg
similarity index 100%
rename from tests/SilkFX/assets/gainmaps/desert_palms.jpg
rename to tests/graphics/SilkFX/assets/gainmaps/desert_palms.jpg
Binary files differ
diff --git a/tests/SilkFX/assets/gainmaps/desert_sunset.jpg b/tests/graphics/SilkFX/assets/gainmaps/desert_sunset.jpg
similarity index 100%
rename from tests/SilkFX/assets/gainmaps/desert_sunset.jpg
rename to tests/graphics/SilkFX/assets/gainmaps/desert_sunset.jpg
Binary files differ
diff --git a/tests/SilkFX/assets/gainmaps/desert_wanda.jpg b/tests/graphics/SilkFX/assets/gainmaps/desert_wanda.jpg
similarity index 100%
rename from tests/SilkFX/assets/gainmaps/desert_wanda.jpg
rename to tests/graphics/SilkFX/assets/gainmaps/desert_wanda.jpg
Binary files differ
diff --git a/tests/SilkFX/assets/gainmaps/fountain_night.jpg b/tests/graphics/SilkFX/assets/gainmaps/fountain_night.jpg
similarity index 100%
rename from tests/SilkFX/assets/gainmaps/fountain_night.jpg
rename to tests/graphics/SilkFX/assets/gainmaps/fountain_night.jpg
Binary files differ
diff --git a/tests/SilkFX/assets/gainmaps/grand_canyon.jpg b/tests/graphics/SilkFX/assets/gainmaps/grand_canyon.jpg
similarity index 100%
rename from tests/SilkFX/assets/gainmaps/grand_canyon.jpg
rename to tests/graphics/SilkFX/assets/gainmaps/grand_canyon.jpg
Binary files differ
diff --git a/tests/SilkFX/assets/gainmaps/lamps.jpg b/tests/graphics/SilkFX/assets/gainmaps/lamps.jpg
similarity index 100%
rename from tests/SilkFX/assets/gainmaps/lamps.jpg
rename to tests/graphics/SilkFX/assets/gainmaps/lamps.jpg
Binary files differ
diff --git a/tests/SilkFX/assets/gainmaps/mountain_lake.jpg b/tests/graphics/SilkFX/assets/gainmaps/mountain_lake.jpg
similarity index 100%
rename from tests/SilkFX/assets/gainmaps/mountain_lake.jpg
rename to tests/graphics/SilkFX/assets/gainmaps/mountain_lake.jpg
Binary files differ
diff --git a/tests/SilkFX/assets/gainmaps/mountains.jpg b/tests/graphics/SilkFX/assets/gainmaps/mountains.jpg
similarity index 100%
rename from tests/SilkFX/assets/gainmaps/mountains.jpg
rename to tests/graphics/SilkFX/assets/gainmaps/mountains.jpg
Binary files differ
diff --git a/tests/SilkFX/assets/gainmaps/sunflower.jpg b/tests/graphics/SilkFX/assets/gainmaps/sunflower.jpg
similarity index 100%
rename from tests/SilkFX/assets/gainmaps/sunflower.jpg
rename to tests/graphics/SilkFX/assets/gainmaps/sunflower.jpg
Binary files differ
diff --git a/tests/SilkFX/assets/gainmaps/train_station_night.jpg b/tests/graphics/SilkFX/assets/gainmaps/train_station_night.jpg
similarity index 100%
rename from tests/SilkFX/assets/gainmaps/train_station_night.jpg
rename to tests/graphics/SilkFX/assets/gainmaps/train_station_night.jpg
Binary files differ
diff --git a/tests/SilkFX/res/drawable-hdpi/background1.jpeg b/tests/graphics/SilkFX/res/drawable-hdpi/background1.jpeg
similarity index 100%
rename from tests/SilkFX/res/drawable-hdpi/background1.jpeg
rename to tests/graphics/SilkFX/res/drawable-hdpi/background1.jpeg
Binary files differ
diff --git a/tests/SilkFX/res/drawable-hdpi/background2.jpeg b/tests/graphics/SilkFX/res/drawable-hdpi/background2.jpeg
similarity index 100%
rename from tests/SilkFX/res/drawable-hdpi/background2.jpeg
rename to tests/graphics/SilkFX/res/drawable-hdpi/background2.jpeg
Binary files differ
diff --git a/tests/SilkFX/res/drawable-hdpi/background3.jpeg b/tests/graphics/SilkFX/res/drawable-hdpi/background3.jpeg
similarity index 100%
rename from tests/SilkFX/res/drawable-hdpi/background3.jpeg
rename to tests/graphics/SilkFX/res/drawable-hdpi/background3.jpeg
Binary files differ
diff --git a/tests/SilkFX/res/drawable-hdpi/noise.png b/tests/graphics/SilkFX/res/drawable-hdpi/noise.png
similarity index 100%
rename from tests/SilkFX/res/drawable-hdpi/noise.png
rename to tests/graphics/SilkFX/res/drawable-hdpi/noise.png
Binary files differ
diff --git a/tests/SilkFX/res/drawable-nodpi/blue_sweep_gradient.xml b/tests/graphics/SilkFX/res/drawable-nodpi/blue_sweep_gradient.xml
similarity index 100%
rename from tests/SilkFX/res/drawable-nodpi/blue_sweep_gradient.xml
rename to tests/graphics/SilkFX/res/drawable-nodpi/blue_sweep_gradient.xml
diff --git a/tests/SilkFX/res/drawable-nodpi/dark_gradient.xml b/tests/graphics/SilkFX/res/drawable-nodpi/dark_gradient.xml
similarity index 100%
rename from tests/SilkFX/res/drawable-nodpi/dark_gradient.xml
rename to tests/graphics/SilkFX/res/drawable-nodpi/dark_gradient.xml
diff --git a/tests/SilkFX/res/drawable-nodpi/dark_notification.png b/tests/graphics/SilkFX/res/drawable-nodpi/dark_notification.png
similarity index 100%
rename from tests/SilkFX/res/drawable-nodpi/dark_notification.png
rename to tests/graphics/SilkFX/res/drawable-nodpi/dark_notification.png
Binary files differ
diff --git a/tests/SilkFX/res/drawable-nodpi/green_sweep_gradient.xml b/tests/graphics/SilkFX/res/drawable-nodpi/green_sweep_gradient.xml
similarity index 100%
rename from tests/SilkFX/res/drawable-nodpi/green_sweep_gradient.xml
rename to tests/graphics/SilkFX/res/drawable-nodpi/green_sweep_gradient.xml
diff --git a/tests/SilkFX/res/drawable-nodpi/grey_sweep_gradient.xml b/tests/graphics/SilkFX/res/drawable-nodpi/grey_sweep_gradient.xml
similarity index 100%
rename from tests/SilkFX/res/drawable-nodpi/grey_sweep_gradient.xml
rename to tests/graphics/SilkFX/res/drawable-nodpi/grey_sweep_gradient.xml
diff --git a/tests/SilkFX/res/drawable-nodpi/light_gradient.xml b/tests/graphics/SilkFX/res/drawable-nodpi/light_gradient.xml
similarity index 100%
rename from tests/SilkFX/res/drawable-nodpi/light_gradient.xml
rename to tests/graphics/SilkFX/res/drawable-nodpi/light_gradient.xml
diff --git a/tests/SilkFX/res/drawable-nodpi/light_notification.png b/tests/graphics/SilkFX/res/drawable-nodpi/light_notification.png
similarity index 100%
rename from tests/SilkFX/res/drawable-nodpi/light_notification.png
rename to tests/graphics/SilkFX/res/drawable-nodpi/light_notification.png
Binary files differ
diff --git a/tests/SilkFX/res/drawable-nodpi/red_sweep_gradient.xml b/tests/graphics/SilkFX/res/drawable-nodpi/red_sweep_gradient.xml
similarity index 100%
rename from tests/SilkFX/res/drawable-nodpi/red_sweep_gradient.xml
rename to tests/graphics/SilkFX/res/drawable-nodpi/red_sweep_gradient.xml
diff --git a/tests/SilkFX/res/drawable/background_blur_drawable.xml b/tests/graphics/SilkFX/res/drawable/background_blur_drawable.xml
similarity index 100%
rename from tests/SilkFX/res/drawable/background_blur_drawable.xml
rename to tests/graphics/SilkFX/res/drawable/background_blur_drawable.xml
diff --git a/tests/SilkFX/res/drawable/blur_activity_background_drawable_white.xml b/tests/graphics/SilkFX/res/drawable/blur_activity_background_drawable_white.xml
similarity index 100%
rename from tests/SilkFX/res/drawable/blur_activity_background_drawable_white.xml
rename to tests/graphics/SilkFX/res/drawable/blur_activity_background_drawable_white.xml
diff --git a/tests/SilkFX/res/layout-television/activity_glass.xml b/tests/graphics/SilkFX/res/layout-television/activity_glass.xml
similarity index 100%
rename from tests/SilkFX/res/layout-television/activity_glass.xml
rename to tests/graphics/SilkFX/res/layout-television/activity_glass.xml
diff --git a/tests/SilkFX/res/layout/activity_background_blur.xml b/tests/graphics/SilkFX/res/layout/activity_background_blur.xml
similarity index 100%
rename from tests/SilkFX/res/layout/activity_background_blur.xml
rename to tests/graphics/SilkFX/res/layout/activity_background_blur.xml
diff --git a/tests/SilkFX/res/layout/activity_glass.xml b/tests/graphics/SilkFX/res/layout/activity_glass.xml
similarity index 100%
rename from tests/SilkFX/res/layout/activity_glass.xml
rename to tests/graphics/SilkFX/res/layout/activity_glass.xml
diff --git a/tests/SilkFX/res/layout/bling_notifications.xml b/tests/graphics/SilkFX/res/layout/bling_notifications.xml
similarity index 100%
rename from tests/SilkFX/res/layout/bling_notifications.xml
rename to tests/graphics/SilkFX/res/layout/bling_notifications.xml
diff --git a/tests/SilkFX/res/layout/color_grid.xml b/tests/graphics/SilkFX/res/layout/color_grid.xml
similarity index 100%
rename from tests/SilkFX/res/layout/color_grid.xml
rename to tests/graphics/SilkFX/res/layout/color_grid.xml
diff --git a/tests/SilkFX/res/layout/color_mode_controls.xml b/tests/graphics/SilkFX/res/layout/color_mode_controls.xml
similarity index 100%
rename from tests/SilkFX/res/layout/color_mode_controls.xml
rename to tests/graphics/SilkFX/res/layout/color_mode_controls.xml
diff --git a/tests/SilkFX/res/layout/common_base.xml b/tests/graphics/SilkFX/res/layout/common_base.xml
similarity index 100%
rename from tests/SilkFX/res/layout/common_base.xml
rename to tests/graphics/SilkFX/res/layout/common_base.xml
diff --git a/tests/SilkFX/res/layout/gainmap_decode_test.xml b/tests/graphics/SilkFX/res/layout/gainmap_decode_test.xml
similarity index 100%
rename from tests/SilkFX/res/layout/gainmap_decode_test.xml
rename to tests/graphics/SilkFX/res/layout/gainmap_decode_test.xml
diff --git a/tests/SilkFX/res/layout/gainmap_image.xml b/tests/graphics/SilkFX/res/layout/gainmap_image.xml
similarity index 100%
rename from tests/SilkFX/res/layout/gainmap_image.xml
rename to tests/graphics/SilkFX/res/layout/gainmap_image.xml
diff --git a/tests/SilkFX/res/layout/gainmap_metadata.xml b/tests/graphics/SilkFX/res/layout/gainmap_metadata.xml
similarity index 100%
rename from tests/SilkFX/res/layout/gainmap_metadata.xml
rename to tests/graphics/SilkFX/res/layout/gainmap_metadata.xml
diff --git a/tests/SilkFX/res/layout/gainmap_transform_test.xml b/tests/graphics/SilkFX/res/layout/gainmap_transform_test.xml
similarity index 100%
rename from tests/SilkFX/res/layout/gainmap_transform_test.xml
rename to tests/graphics/SilkFX/res/layout/gainmap_transform_test.xml
diff --git a/tests/SilkFX/res/layout/gradient_sweep.xml b/tests/graphics/SilkFX/res/layout/gradient_sweep.xml
similarity index 100%
rename from tests/SilkFX/res/layout/gradient_sweep.xml
rename to tests/graphics/SilkFX/res/layout/gradient_sweep.xml
diff --git a/tests/SilkFX/res/layout/hdr_glows.xml b/tests/graphics/SilkFX/res/layout/hdr_glows.xml
similarity index 100%
rename from tests/SilkFX/res/layout/hdr_glows.xml
rename to tests/graphics/SilkFX/res/layout/hdr_glows.xml
diff --git a/tests/SilkFX/res/layout/hdr_image_viewer.xml b/tests/graphics/SilkFX/res/layout/hdr_image_viewer.xml
similarity index 100%
rename from tests/SilkFX/res/layout/hdr_image_viewer.xml
rename to tests/graphics/SilkFX/res/layout/hdr_image_viewer.xml
diff --git a/tests/SilkFX/res/values/style.xml b/tests/graphics/SilkFX/res/values/style.xml
similarity index 100%
rename from tests/SilkFX/res/values/style.xml
rename to tests/graphics/SilkFX/res/values/style.xml
diff --git a/tests/SilkFX/src/com/android/test/silkfx/Main.kt b/tests/graphics/SilkFX/src/com/android/test/silkfx/Main.kt
similarity index 100%
rename from tests/SilkFX/src/com/android/test/silkfx/Main.kt
rename to tests/graphics/SilkFX/src/com/android/test/silkfx/Main.kt
diff --git a/tests/SilkFX/src/com/android/test/silkfx/app/BaseDemoActivity.kt b/tests/graphics/SilkFX/src/com/android/test/silkfx/app/BaseDemoActivity.kt
similarity index 100%
rename from tests/SilkFX/src/com/android/test/silkfx/app/BaseDemoActivity.kt
rename to tests/graphics/SilkFX/src/com/android/test/silkfx/app/BaseDemoActivity.kt
diff --git a/tests/SilkFX/src/com/android/test/silkfx/app/CommonDemoActivity.kt b/tests/graphics/SilkFX/src/com/android/test/silkfx/app/CommonDemoActivity.kt
similarity index 100%
rename from tests/SilkFX/src/com/android/test/silkfx/app/CommonDemoActivity.kt
rename to tests/graphics/SilkFX/src/com/android/test/silkfx/app/CommonDemoActivity.kt
diff --git a/tests/SilkFX/src/com/android/test/silkfx/app/HdrImageViewer.kt b/tests/graphics/SilkFX/src/com/android/test/silkfx/app/HdrImageViewer.kt
similarity index 100%
rename from tests/SilkFX/src/com/android/test/silkfx/app/HdrImageViewer.kt
rename to tests/graphics/SilkFX/src/com/android/test/silkfx/app/HdrImageViewer.kt
diff --git a/tests/SilkFX/src/com/android/test/silkfx/app/WindowObserver.kt b/tests/graphics/SilkFX/src/com/android/test/silkfx/app/WindowObserver.kt
similarity index 100%
rename from tests/SilkFX/src/com/android/test/silkfx/app/WindowObserver.kt
rename to tests/graphics/SilkFX/src/com/android/test/silkfx/app/WindowObserver.kt
diff --git a/tests/SilkFX/src/com/android/test/silkfx/common/BaseDrawingView.kt b/tests/graphics/SilkFX/src/com/android/test/silkfx/common/BaseDrawingView.kt
similarity index 100%
rename from tests/SilkFX/src/com/android/test/silkfx/common/BaseDrawingView.kt
rename to tests/graphics/SilkFX/src/com/android/test/silkfx/common/BaseDrawingView.kt
diff --git a/tests/SilkFX/src/com/android/test/silkfx/common/ColorModeControls.kt b/tests/graphics/SilkFX/src/com/android/test/silkfx/common/ColorModeControls.kt
similarity index 100%
rename from tests/SilkFX/src/com/android/test/silkfx/common/ColorModeControls.kt
rename to tests/graphics/SilkFX/src/com/android/test/silkfx/common/ColorModeControls.kt
diff --git a/tests/SilkFX/src/com/android/test/silkfx/common/HDRIndicator.kt b/tests/graphics/SilkFX/src/com/android/test/silkfx/common/HDRIndicator.kt
similarity index 100%
rename from tests/SilkFX/src/com/android/test/silkfx/common/HDRIndicator.kt
rename to tests/graphics/SilkFX/src/com/android/test/silkfx/common/HDRIndicator.kt
diff --git a/tests/SilkFX/src/com/android/test/silkfx/hdr/BlingyNotification.kt b/tests/graphics/SilkFX/src/com/android/test/silkfx/hdr/BlingyNotification.kt
similarity index 100%
rename from tests/SilkFX/src/com/android/test/silkfx/hdr/BlingyNotification.kt
rename to tests/graphics/SilkFX/src/com/android/test/silkfx/hdr/BlingyNotification.kt
diff --git a/tests/SilkFX/src/com/android/test/silkfx/hdr/ColorGrid.kt b/tests/graphics/SilkFX/src/com/android/test/silkfx/hdr/ColorGrid.kt
similarity index 100%
rename from tests/SilkFX/src/com/android/test/silkfx/hdr/ColorGrid.kt
rename to tests/graphics/SilkFX/src/com/android/test/silkfx/hdr/ColorGrid.kt
diff --git a/tests/SilkFX/src/com/android/test/silkfx/hdr/GainmapDecodeTest.kt b/tests/graphics/SilkFX/src/com/android/test/silkfx/hdr/GainmapDecodeTest.kt
similarity index 100%
rename from tests/SilkFX/src/com/android/test/silkfx/hdr/GainmapDecodeTest.kt
rename to tests/graphics/SilkFX/src/com/android/test/silkfx/hdr/GainmapDecodeTest.kt
diff --git a/tests/SilkFX/src/com/android/test/silkfx/hdr/GainmapImage.kt b/tests/graphics/SilkFX/src/com/android/test/silkfx/hdr/GainmapImage.kt
similarity index 100%
rename from tests/SilkFX/src/com/android/test/silkfx/hdr/GainmapImage.kt
rename to tests/graphics/SilkFX/src/com/android/test/silkfx/hdr/GainmapImage.kt
diff --git a/tests/SilkFX/src/com/android/test/silkfx/hdr/GainmapMetadataEditor.kt b/tests/graphics/SilkFX/src/com/android/test/silkfx/hdr/GainmapMetadataEditor.kt
similarity index 100%
rename from tests/SilkFX/src/com/android/test/silkfx/hdr/GainmapMetadataEditor.kt
rename to tests/graphics/SilkFX/src/com/android/test/silkfx/hdr/GainmapMetadataEditor.kt
diff --git a/tests/SilkFX/src/com/android/test/silkfx/hdr/GainmapTransformsTest.kt b/tests/graphics/SilkFX/src/com/android/test/silkfx/hdr/GainmapTransformsTest.kt
similarity index 100%
rename from tests/SilkFX/src/com/android/test/silkfx/hdr/GainmapTransformsTest.kt
rename to tests/graphics/SilkFX/src/com/android/test/silkfx/hdr/GainmapTransformsTest.kt
diff --git a/tests/SilkFX/src/com/android/test/silkfx/hdr/GlowActivity.kt b/tests/graphics/SilkFX/src/com/android/test/silkfx/hdr/GlowActivity.kt
similarity index 100%
rename from tests/SilkFX/src/com/android/test/silkfx/hdr/GlowActivity.kt
rename to tests/graphics/SilkFX/src/com/android/test/silkfx/hdr/GlowActivity.kt
diff --git a/tests/SilkFX/src/com/android/test/silkfx/hdr/GlowingCard.kt b/tests/graphics/SilkFX/src/com/android/test/silkfx/hdr/GlowingCard.kt
similarity index 100%
rename from tests/SilkFX/src/com/android/test/silkfx/hdr/GlowingCard.kt
rename to tests/graphics/SilkFX/src/com/android/test/silkfx/hdr/GlowingCard.kt
diff --git a/tests/SilkFX/src/com/android/test/silkfx/hdr/RadialGlow.kt b/tests/graphics/SilkFX/src/com/android/test/silkfx/hdr/RadialGlow.kt
similarity index 100%
rename from tests/SilkFX/src/com/android/test/silkfx/hdr/RadialGlow.kt
rename to tests/graphics/SilkFX/src/com/android/test/silkfx/hdr/RadialGlow.kt
diff --git a/tests/SilkFX/src/com/android/test/silkfx/materials/BackgroundBlurActivity.kt b/tests/graphics/SilkFX/src/com/android/test/silkfx/materials/BackgroundBlurActivity.kt
similarity index 100%
rename from tests/SilkFX/src/com/android/test/silkfx/materials/BackgroundBlurActivity.kt
rename to tests/graphics/SilkFX/src/com/android/test/silkfx/materials/BackgroundBlurActivity.kt
diff --git a/tests/SilkFX/src/com/android/test/silkfx/materials/GlassActivity.kt b/tests/graphics/SilkFX/src/com/android/test/silkfx/materials/GlassActivity.kt
similarity index 100%
rename from tests/SilkFX/src/com/android/test/silkfx/materials/GlassActivity.kt
rename to tests/graphics/SilkFX/src/com/android/test/silkfx/materials/GlassActivity.kt
diff --git a/tests/SilkFX/src/com/android/test/silkfx/materials/GlassView.kt b/tests/graphics/SilkFX/src/com/android/test/silkfx/materials/GlassView.kt
similarity index 100%
rename from tests/SilkFX/src/com/android/test/silkfx/materials/GlassView.kt
rename to tests/graphics/SilkFX/src/com/android/test/silkfx/materials/GlassView.kt
diff --git a/tests/VectorDrawableTest/Android.bp b/tests/graphics/VectorDrawableTest/Android.bp
similarity index 100%
rename from tests/VectorDrawableTest/Android.bp
rename to tests/graphics/VectorDrawableTest/Android.bp
diff --git a/tests/VectorDrawableTest/AndroidManifest.xml b/tests/graphics/VectorDrawableTest/AndroidManifest.xml
similarity index 100%
rename from tests/VectorDrawableTest/AndroidManifest.xml
rename to tests/graphics/VectorDrawableTest/AndroidManifest.xml
diff --git a/tests/VectorDrawableTest/OWNERS b/tests/graphics/VectorDrawableTest/OWNERS
similarity index 100%
rename from tests/VectorDrawableTest/OWNERS
rename to tests/graphics/VectorDrawableTest/OWNERS
diff --git a/tests/VectorDrawableTest/res/anim/alpha_animation_progress_bar.xml b/tests/graphics/VectorDrawableTest/res/anim/alpha_animation_progress_bar.xml
similarity index 100%
rename from tests/VectorDrawableTest/res/anim/alpha_animation_progress_bar.xml
rename to tests/graphics/VectorDrawableTest/res/anim/alpha_animation_progress_bar.xml
diff --git a/tests/VectorDrawableTest/res/anim/animation_favorite.xml b/tests/graphics/VectorDrawableTest/res/anim/animation_favorite.xml
similarity index 100%
rename from tests/VectorDrawableTest/res/anim/animation_favorite.xml
rename to tests/graphics/VectorDrawableTest/res/anim/animation_favorite.xml
diff --git a/tests/VectorDrawableTest/res/anim/animation_favorite02.xml b/tests/graphics/VectorDrawableTest/res/anim/animation_favorite02.xml
similarity index 100%
rename from tests/VectorDrawableTest/res/anim/animation_favorite02.xml
rename to tests/graphics/VectorDrawableTest/res/anim/animation_favorite02.xml
diff --git a/tests/VectorDrawableTest/res/anim/animation_grouping_1_01.xml b/tests/graphics/VectorDrawableTest/res/anim/animation_grouping_1_01.xml
similarity index 100%
rename from tests/VectorDrawableTest/res/anim/animation_grouping_1_01.xml
rename to tests/graphics/VectorDrawableTest/res/anim/animation_grouping_1_01.xml
diff --git a/tests/VectorDrawableTest/res/anim/animation_grouping_1_02.xml b/tests/graphics/VectorDrawableTest/res/anim/animation_grouping_1_02.xml
similarity index 100%
rename from tests/VectorDrawableTest/res/anim/animation_grouping_1_02.xml
rename to tests/graphics/VectorDrawableTest/res/anim/animation_grouping_1_02.xml
diff --git a/tests/VectorDrawableTest/res/anim/animation_linear_progress_bar_rect1_scale.xml b/tests/graphics/VectorDrawableTest/res/anim/animation_linear_progress_bar_rect1_scale.xml
similarity index 100%
rename from tests/VectorDrawableTest/res/anim/animation_linear_progress_bar_rect1_scale.xml
rename to tests/graphics/VectorDrawableTest/res/anim/animation_linear_progress_bar_rect1_scale.xml
diff --git a/tests/VectorDrawableTest/res/anim/animation_linear_progress_bar_rect1_translate.xml b/tests/graphics/VectorDrawableTest/res/anim/animation_linear_progress_bar_rect1_translate.xml
similarity index 100%
rename from tests/VectorDrawableTest/res/anim/animation_linear_progress_bar_rect1_translate.xml
rename to tests/graphics/VectorDrawableTest/res/anim/animation_linear_progress_bar_rect1_translate.xml
diff --git a/tests/VectorDrawableTest/res/anim/animation_linear_progress_bar_rect2_scale.xml b/tests/graphics/VectorDrawableTest/res/anim/animation_linear_progress_bar_rect2_scale.xml
similarity index 100%
rename from tests/VectorDrawableTest/res/anim/animation_linear_progress_bar_rect2_scale.xml
rename to tests/graphics/VectorDrawableTest/res/anim/animation_linear_progress_bar_rect2_scale.xml
diff --git a/tests/VectorDrawableTest/res/anim/animation_linear_progress_bar_rect2_translate.xml b/tests/graphics/VectorDrawableTest/res/anim/animation_linear_progress_bar_rect2_translate.xml
similarity index 100%
rename from tests/VectorDrawableTest/res/anim/animation_linear_progress_bar_rect2_translate.xml
rename to tests/graphics/VectorDrawableTest/res/anim/animation_linear_progress_bar_rect2_translate.xml
diff --git a/tests/VectorDrawableTest/res/anim/blink.xml b/tests/graphics/VectorDrawableTest/res/anim/blink.xml
similarity index 100%
rename from tests/VectorDrawableTest/res/anim/blink.xml
rename to tests/graphics/VectorDrawableTest/res/anim/blink.xml
diff --git a/tests/VectorDrawableTest/res/anim/ic_hourglass_animation_fill_outlines.xml b/tests/graphics/VectorDrawableTest/res/anim/ic_hourglass_animation_fill_outlines.xml
similarity index 100%
rename from tests/VectorDrawableTest/res/anim/ic_hourglass_animation_fill_outlines.xml
rename to tests/graphics/VectorDrawableTest/res/anim/ic_hourglass_animation_fill_outlines.xml
diff --git a/tests/VectorDrawableTest/res/anim/ic_hourglass_animation_hourglass_frame.xml b/tests/graphics/VectorDrawableTest/res/anim/ic_hourglass_animation_hourglass_frame.xml
similarity index 100%
rename from tests/VectorDrawableTest/res/anim/ic_hourglass_animation_hourglass_frame.xml
rename to tests/graphics/VectorDrawableTest/res/anim/ic_hourglass_animation_hourglass_frame.xml
diff --git a/tests/VectorDrawableTest/res/anim/ic_hourglass_animation_mask_1.xml b/tests/graphics/VectorDrawableTest/res/anim/ic_hourglass_animation_mask_1.xml
similarity index 100%
rename from tests/VectorDrawableTest/res/anim/ic_hourglass_animation_mask_1.xml
rename to tests/graphics/VectorDrawableTest/res/anim/ic_hourglass_animation_mask_1.xml
diff --git a/tests/VectorDrawableTest/res/anim/ic_rotate_2_portrait_v2_animation_arrows_1.xml b/tests/graphics/VectorDrawableTest/res/anim/ic_rotate_2_portrait_v2_animation_arrows_1.xml
similarity index 100%
rename from tests/VectorDrawableTest/res/anim/ic_rotate_2_portrait_v2_animation_arrows_1.xml
rename to tests/graphics/VectorDrawableTest/res/anim/ic_rotate_2_portrait_v2_animation_arrows_1.xml
diff --git a/tests/VectorDrawableTest/res/anim/ic_rotate_2_portrait_v2_animation_device_1.xml b/tests/graphics/VectorDrawableTest/res/anim/ic_rotate_2_portrait_v2_animation_device_1.xml
similarity index 100%
rename from tests/VectorDrawableTest/res/anim/ic_rotate_2_portrait_v2_animation_device_1.xml
rename to tests/graphics/VectorDrawableTest/res/anim/ic_rotate_2_portrait_v2_animation_device_1.xml
diff --git a/tests/VectorDrawableTest/res/anim/ic_rotate_2_portrait_v2_animation_device_2.xml b/tests/graphics/VectorDrawableTest/res/anim/ic_rotate_2_portrait_v2_animation_device_2.xml
similarity index 100%
rename from tests/VectorDrawableTest/res/anim/ic_rotate_2_portrait_v2_animation_device_2.xml
rename to tests/graphics/VectorDrawableTest/res/anim/ic_rotate_2_portrait_v2_animation_device_2.xml
diff --git a/tests/VectorDrawableTest/res/anim/ic_signal_airplane_v2_animation_cross_1.xml b/tests/graphics/VectorDrawableTest/res/anim/ic_signal_airplane_v2_animation_cross_1.xml
similarity index 100%
rename from tests/VectorDrawableTest/res/anim/ic_signal_airplane_v2_animation_cross_1.xml
rename to tests/graphics/VectorDrawableTest/res/anim/ic_signal_airplane_v2_animation_cross_1.xml
diff --git a/tests/VectorDrawableTest/res/anim/ic_signal_airplane_v2_animation_ic_signal_airplane.xml b/tests/graphics/VectorDrawableTest/res/anim/ic_signal_airplane_v2_animation_ic_signal_airplane.xml
similarity index 100%
rename from tests/VectorDrawableTest/res/anim/ic_signal_airplane_v2_animation_ic_signal_airplane.xml
rename to tests/graphics/VectorDrawableTest/res/anim/ic_signal_airplane_v2_animation_ic_signal_airplane.xml
diff --git a/tests/VectorDrawableTest/res/anim/ic_signal_airplane_v2_animation_mask_2.xml b/tests/graphics/VectorDrawableTest/res/anim/ic_signal_airplane_v2_animation_mask_2.xml
similarity index 100%
rename from tests/VectorDrawableTest/res/anim/ic_signal_airplane_v2_animation_mask_2.xml
rename to tests/graphics/VectorDrawableTest/res/anim/ic_signal_airplane_v2_animation_mask_2.xml
diff --git a/tests/VectorDrawableTest/res/anim/ic_signal_airplane_v2_animation_path_1_1.xml b/tests/graphics/VectorDrawableTest/res/anim/ic_signal_airplane_v2_animation_path_1_1.xml
similarity index 100%
rename from tests/VectorDrawableTest/res/anim/ic_signal_airplane_v2_animation_path_1_1.xml
rename to tests/graphics/VectorDrawableTest/res/anim/ic_signal_airplane_v2_animation_path_1_1.xml
diff --git a/tests/VectorDrawableTest/res/anim/trim_path_animation01.xml b/tests/graphics/VectorDrawableTest/res/anim/trim_path_animation01.xml
similarity index 100%
rename from tests/VectorDrawableTest/res/anim/trim_path_animation01.xml
rename to tests/graphics/VectorDrawableTest/res/anim/trim_path_animation01.xml
diff --git a/tests/VectorDrawableTest/res/anim/trim_path_animation02.xml b/tests/graphics/VectorDrawableTest/res/anim/trim_path_animation02.xml
similarity index 100%
rename from tests/VectorDrawableTest/res/anim/trim_path_animation02.xml
rename to tests/graphics/VectorDrawableTest/res/anim/trim_path_animation02.xml
diff --git a/tests/VectorDrawableTest/res/anim/trim_path_animation03.xml b/tests/graphics/VectorDrawableTest/res/anim/trim_path_animation03.xml
similarity index 100%
rename from tests/VectorDrawableTest/res/anim/trim_path_animation03.xml
rename to tests/graphics/VectorDrawableTest/res/anim/trim_path_animation03.xml
diff --git a/tests/VectorDrawableTest/res/anim/trim_path_animation04.xml b/tests/graphics/VectorDrawableTest/res/anim/trim_path_animation04.xml
similarity index 100%
rename from tests/VectorDrawableTest/res/anim/trim_path_animation04.xml
rename to tests/graphics/VectorDrawableTest/res/anim/trim_path_animation04.xml
diff --git a/tests/VectorDrawableTest/res/anim/trim_path_animation05.xml b/tests/graphics/VectorDrawableTest/res/anim/trim_path_animation05.xml
similarity index 100%
rename from tests/VectorDrawableTest/res/anim/trim_path_animation05.xml
rename to tests/graphics/VectorDrawableTest/res/anim/trim_path_animation05.xml
diff --git a/tests/VectorDrawableTest/res/anim/trim_path_animation06.xml b/tests/graphics/VectorDrawableTest/res/anim/trim_path_animation06.xml
similarity index 100%
rename from tests/VectorDrawableTest/res/anim/trim_path_animation06.xml
rename to tests/graphics/VectorDrawableTest/res/anim/trim_path_animation06.xml
diff --git a/tests/VectorDrawableTest/res/anim/trim_path_animation_progress_bar.xml b/tests/graphics/VectorDrawableTest/res/anim/trim_path_animation_progress_bar.xml
similarity index 100%
rename from tests/VectorDrawableTest/res/anim/trim_path_animation_progress_bar.xml
rename to tests/graphics/VectorDrawableTest/res/anim/trim_path_animation_progress_bar.xml
diff --git a/tests/VectorDrawableTest/res/color/fill_gradient_linear.xml b/tests/graphics/VectorDrawableTest/res/color/fill_gradient_linear.xml
similarity index 100%
rename from tests/VectorDrawableTest/res/color/fill_gradient_linear.xml
rename to tests/graphics/VectorDrawableTest/res/color/fill_gradient_linear.xml
diff --git a/tests/VectorDrawableTest/res/color/fill_gradient_linear_clamp.xml b/tests/graphics/VectorDrawableTest/res/color/fill_gradient_linear_clamp.xml
similarity index 100%
rename from tests/VectorDrawableTest/res/color/fill_gradient_linear_clamp.xml
rename to tests/graphics/VectorDrawableTest/res/color/fill_gradient_linear_clamp.xml
diff --git a/tests/VectorDrawableTest/res/color/fill_gradient_linear_item.xml b/tests/graphics/VectorDrawableTest/res/color/fill_gradient_linear_item.xml
similarity index 100%
rename from tests/VectorDrawableTest/res/color/fill_gradient_linear_item.xml
rename to tests/graphics/VectorDrawableTest/res/color/fill_gradient_linear_item.xml
diff --git a/tests/VectorDrawableTest/res/color/fill_gradient_linear_item_overlap.xml b/tests/graphics/VectorDrawableTest/res/color/fill_gradient_linear_item_overlap.xml
similarity index 100%
rename from tests/VectorDrawableTest/res/color/fill_gradient_linear_item_overlap.xml
rename to tests/graphics/VectorDrawableTest/res/color/fill_gradient_linear_item_overlap.xml
diff --git a/tests/VectorDrawableTest/res/color/fill_gradient_linear_item_overlap_mirror.xml b/tests/graphics/VectorDrawableTest/res/color/fill_gradient_linear_item_overlap_mirror.xml
similarity index 100%
rename from tests/VectorDrawableTest/res/color/fill_gradient_linear_item_overlap_mirror.xml
rename to tests/graphics/VectorDrawableTest/res/color/fill_gradient_linear_item_overlap_mirror.xml
diff --git a/tests/VectorDrawableTest/res/color/fill_gradient_linear_item_repeat.xml b/tests/graphics/VectorDrawableTest/res/color/fill_gradient_linear_item_repeat.xml
similarity index 100%
rename from tests/VectorDrawableTest/res/color/fill_gradient_linear_item_repeat.xml
rename to tests/graphics/VectorDrawableTest/res/color/fill_gradient_linear_item_repeat.xml
diff --git a/tests/VectorDrawableTest/res/color/fill_gradient_radial.xml b/tests/graphics/VectorDrawableTest/res/color/fill_gradient_radial.xml
similarity index 100%
rename from tests/VectorDrawableTest/res/color/fill_gradient_radial.xml
rename to tests/graphics/VectorDrawableTest/res/color/fill_gradient_radial.xml
diff --git a/tests/VectorDrawableTest/res/color/fill_gradient_radial_clamp.xml b/tests/graphics/VectorDrawableTest/res/color/fill_gradient_radial_clamp.xml
similarity index 100%
rename from tests/VectorDrawableTest/res/color/fill_gradient_radial_clamp.xml
rename to tests/graphics/VectorDrawableTest/res/color/fill_gradient_radial_clamp.xml
diff --git a/tests/VectorDrawableTest/res/color/fill_gradient_radial_item.xml b/tests/graphics/VectorDrawableTest/res/color/fill_gradient_radial_item.xml
similarity index 100%
rename from tests/VectorDrawableTest/res/color/fill_gradient_radial_item.xml
rename to tests/graphics/VectorDrawableTest/res/color/fill_gradient_radial_item.xml
diff --git a/tests/VectorDrawableTest/res/color/fill_gradient_radial_item_repeat.xml b/tests/graphics/VectorDrawableTest/res/color/fill_gradient_radial_item_repeat.xml
similarity index 100%
rename from tests/VectorDrawableTest/res/color/fill_gradient_radial_item_repeat.xml
rename to tests/graphics/VectorDrawableTest/res/color/fill_gradient_radial_item_repeat.xml
diff --git a/tests/VectorDrawableTest/res/color/fill_gradient_radial_item_short.xml b/tests/graphics/VectorDrawableTest/res/color/fill_gradient_radial_item_short.xml
similarity index 100%
rename from tests/VectorDrawableTest/res/color/fill_gradient_radial_item_short.xml
rename to tests/graphics/VectorDrawableTest/res/color/fill_gradient_radial_item_short.xml
diff --git a/tests/VectorDrawableTest/res/color/fill_gradient_radial_item_short_mirror.xml b/tests/graphics/VectorDrawableTest/res/color/fill_gradient_radial_item_short_mirror.xml
similarity index 100%
rename from tests/VectorDrawableTest/res/color/fill_gradient_radial_item_short_mirror.xml
rename to tests/graphics/VectorDrawableTest/res/color/fill_gradient_radial_item_short_mirror.xml
diff --git a/tests/VectorDrawableTest/res/color/fill_gradient_sweep.xml b/tests/graphics/VectorDrawableTest/res/color/fill_gradient_sweep.xml
similarity index 100%
rename from tests/VectorDrawableTest/res/color/fill_gradient_sweep.xml
rename to tests/graphics/VectorDrawableTest/res/color/fill_gradient_sweep.xml
diff --git a/tests/VectorDrawableTest/res/color/fill_gradient_sweep_clamp.xml b/tests/graphics/VectorDrawableTest/res/color/fill_gradient_sweep_clamp.xml
similarity index 100%
rename from tests/VectorDrawableTest/res/color/fill_gradient_sweep_clamp.xml
rename to tests/graphics/VectorDrawableTest/res/color/fill_gradient_sweep_clamp.xml
diff --git a/tests/VectorDrawableTest/res/color/fill_gradient_sweep_item.xml b/tests/graphics/VectorDrawableTest/res/color/fill_gradient_sweep_item.xml
similarity index 100%
rename from tests/VectorDrawableTest/res/color/fill_gradient_sweep_item.xml
rename to tests/graphics/VectorDrawableTest/res/color/fill_gradient_sweep_item.xml
diff --git a/tests/VectorDrawableTest/res/color/fill_gradient_sweep_item_long.xml b/tests/graphics/VectorDrawableTest/res/color/fill_gradient_sweep_item_long.xml
similarity index 100%
rename from tests/VectorDrawableTest/res/color/fill_gradient_sweep_item_long.xml
rename to tests/graphics/VectorDrawableTest/res/color/fill_gradient_sweep_item_long.xml
diff --git a/tests/VectorDrawableTest/res/color/fill_gradient_sweep_item_long_mirror.xml b/tests/graphics/VectorDrawableTest/res/color/fill_gradient_sweep_item_long_mirror.xml
similarity index 100%
rename from tests/VectorDrawableTest/res/color/fill_gradient_sweep_item_long_mirror.xml
rename to tests/graphics/VectorDrawableTest/res/color/fill_gradient_sweep_item_long_mirror.xml
diff --git a/tests/VectorDrawableTest/res/color/fill_gradient_sweep_item_repeat.xml b/tests/graphics/VectorDrawableTest/res/color/fill_gradient_sweep_item_repeat.xml
similarity index 100%
rename from tests/VectorDrawableTest/res/color/fill_gradient_sweep_item_repeat.xml
rename to tests/graphics/VectorDrawableTest/res/color/fill_gradient_sweep_item_repeat.xml
diff --git a/tests/VectorDrawableTest/res/color/stroke_gradient.xml b/tests/graphics/VectorDrawableTest/res/color/stroke_gradient.xml
similarity index 100%
rename from tests/VectorDrawableTest/res/color/stroke_gradient.xml
rename to tests/graphics/VectorDrawableTest/res/color/stroke_gradient.xml
diff --git a/tests/VectorDrawableTest/res/color/stroke_gradient_clamp.xml b/tests/graphics/VectorDrawableTest/res/color/stroke_gradient_clamp.xml
similarity index 100%
rename from tests/VectorDrawableTest/res/color/stroke_gradient_clamp.xml
rename to tests/graphics/VectorDrawableTest/res/color/stroke_gradient_clamp.xml
diff --git a/tests/VectorDrawableTest/res/color/stroke_gradient_item.xml b/tests/graphics/VectorDrawableTest/res/color/stroke_gradient_item.xml
similarity index 100%
rename from tests/VectorDrawableTest/res/color/stroke_gradient_item.xml
rename to tests/graphics/VectorDrawableTest/res/color/stroke_gradient_item.xml
diff --git a/tests/VectorDrawableTest/res/color/stroke_gradient_item_alpha.xml b/tests/graphics/VectorDrawableTest/res/color/stroke_gradient_item_alpha.xml
similarity index 100%
rename from tests/VectorDrawableTest/res/color/stroke_gradient_item_alpha.xml
rename to tests/graphics/VectorDrawableTest/res/color/stroke_gradient_item_alpha.xml
diff --git a/tests/VectorDrawableTest/res/color/stroke_gradient_item_alpha_mirror.xml b/tests/graphics/VectorDrawableTest/res/color/stroke_gradient_item_alpha_mirror.xml
similarity index 100%
rename from tests/VectorDrawableTest/res/color/stroke_gradient_item_alpha_mirror.xml
rename to tests/graphics/VectorDrawableTest/res/color/stroke_gradient_item_alpha_mirror.xml
diff --git a/tests/VectorDrawableTest/res/color/stroke_gradient_item_repeat.xml b/tests/graphics/VectorDrawableTest/res/color/stroke_gradient_item_repeat.xml
similarity index 100%
rename from tests/VectorDrawableTest/res/color/stroke_gradient_item_repeat.xml
rename to tests/graphics/VectorDrawableTest/res/color/stroke_gradient_item_repeat.xml
diff --git a/tests/VectorDrawableTest/res/color/vector_icon_fill_state_list.xml b/tests/graphics/VectorDrawableTest/res/color/vector_icon_fill_state_list.xml
similarity index 100%
rename from tests/VectorDrawableTest/res/color/vector_icon_fill_state_list.xml
rename to tests/graphics/VectorDrawableTest/res/color/vector_icon_fill_state_list.xml
diff --git a/tests/VectorDrawableTest/res/color/vector_icon_fill_state_list_simple.xml b/tests/graphics/VectorDrawableTest/res/color/vector_icon_fill_state_list_simple.xml
similarity index 100%
rename from tests/VectorDrawableTest/res/color/vector_icon_fill_state_list_simple.xml
rename to tests/graphics/VectorDrawableTest/res/color/vector_icon_fill_state_list_simple.xml
diff --git a/tests/VectorDrawableTest/res/color/vector_icon_stroke_state_list.xml b/tests/graphics/VectorDrawableTest/res/color/vector_icon_stroke_state_list.xml
similarity index 100%
rename from tests/VectorDrawableTest/res/color/vector_icon_stroke_state_list.xml
rename to tests/graphics/VectorDrawableTest/res/color/vector_icon_stroke_state_list.xml
diff --git a/tests/VectorDrawableTest/res/color/vector_icon_stroke_state_list_simple.xml b/tests/graphics/VectorDrawableTest/res/color/vector_icon_stroke_state_list_simple.xml
similarity index 100%
rename from tests/VectorDrawableTest/res/color/vector_icon_stroke_state_list_simple.xml
rename to tests/graphics/VectorDrawableTest/res/color/vector_icon_stroke_state_list_simple.xml
diff --git a/tests/VectorDrawableTest/res/drawable-hdpi/icon.png b/tests/graphics/VectorDrawableTest/res/drawable-hdpi/icon.png
similarity index 100%
rename from tests/VectorDrawableTest/res/drawable-hdpi/icon.png
rename to tests/graphics/VectorDrawableTest/res/drawable-hdpi/icon.png
Binary files differ
diff --git a/tests/VectorDrawableTest/res/drawable-nodpi/bitmap_drawable01.jpg b/tests/graphics/VectorDrawableTest/res/drawable-nodpi/bitmap_drawable01.jpg
similarity index 100%
rename from tests/VectorDrawableTest/res/drawable-nodpi/bitmap_drawable01.jpg
rename to tests/graphics/VectorDrawableTest/res/drawable-nodpi/bitmap_drawable01.jpg
Binary files differ
diff --git a/tests/VectorDrawableTest/res/drawable/animated_vector_drawable_attr_icon.xml b/tests/graphics/VectorDrawableTest/res/drawable/animated_vector_drawable_attr_icon.xml
similarity index 100%
rename from tests/VectorDrawableTest/res/drawable/animated_vector_drawable_attr_icon.xml
rename to tests/graphics/VectorDrawableTest/res/drawable/animated_vector_drawable_attr_icon.xml
diff --git a/tests/VectorDrawableTest/res/drawable/animated_vector_drawable_attr_icon_animated.xml b/tests/graphics/VectorDrawableTest/res/drawable/animated_vector_drawable_attr_icon_animated.xml
similarity index 100%
rename from tests/VectorDrawableTest/res/drawable/animated_vector_drawable_attr_icon_animated.xml
rename to tests/graphics/VectorDrawableTest/res/drawable/animated_vector_drawable_attr_icon_animated.xml
diff --git a/tests/VectorDrawableTest/res/drawable/animation_drawable_vector.xml b/tests/graphics/VectorDrawableTest/res/drawable/animation_drawable_vector.xml
similarity index 100%
rename from tests/VectorDrawableTest/res/drawable/animation_drawable_vector.xml
rename to tests/graphics/VectorDrawableTest/res/drawable/animation_drawable_vector.xml
diff --git a/tests/VectorDrawableTest/res/drawable/animation_vector_drawable01.xml b/tests/graphics/VectorDrawableTest/res/drawable/animation_vector_drawable01.xml
similarity index 100%
rename from tests/VectorDrawableTest/res/drawable/animation_vector_drawable01.xml
rename to tests/graphics/VectorDrawableTest/res/drawable/animation_vector_drawable01.xml
diff --git a/tests/VectorDrawableTest/res/drawable/animation_vector_drawable_favorite.xml b/tests/graphics/VectorDrawableTest/res/drawable/animation_vector_drawable_favorite.xml
similarity index 100%
rename from tests/VectorDrawableTest/res/drawable/animation_vector_drawable_favorite.xml
rename to tests/graphics/VectorDrawableTest/res/drawable/animation_vector_drawable_favorite.xml
diff --git a/tests/VectorDrawableTest/res/drawable/animation_vector_drawable_grouping_1.xml b/tests/graphics/VectorDrawableTest/res/drawable/animation_vector_drawable_grouping_1.xml
similarity index 100%
rename from tests/VectorDrawableTest/res/drawable/animation_vector_drawable_grouping_1.xml
rename to tests/graphics/VectorDrawableTest/res/drawable/animation_vector_drawable_grouping_1.xml
diff --git a/tests/VectorDrawableTest/res/drawable/animation_vector_linear_progress_bar.xml b/tests/graphics/VectorDrawableTest/res/drawable/animation_vector_linear_progress_bar.xml
similarity index 100%
rename from tests/VectorDrawableTest/res/drawable/animation_vector_linear_progress_bar.xml
rename to tests/graphics/VectorDrawableTest/res/drawable/animation_vector_linear_progress_bar.xml
diff --git a/tests/VectorDrawableTest/res/drawable/animation_vector_progress_bar.xml b/tests/graphics/VectorDrawableTest/res/drawable/animation_vector_progress_bar.xml
similarity index 100%
rename from tests/VectorDrawableTest/res/drawable/animation_vector_progress_bar.xml
rename to tests/graphics/VectorDrawableTest/res/drawable/animation_vector_progress_bar.xml
diff --git a/tests/VectorDrawableTest/res/drawable/btn_radio_on_to_off_bundle.xml b/tests/graphics/VectorDrawableTest/res/drawable/btn_radio_on_to_off_bundle.xml
similarity index 100%
rename from tests/VectorDrawableTest/res/drawable/btn_radio_on_to_off_bundle.xml
rename to tests/graphics/VectorDrawableTest/res/drawable/btn_radio_on_to_off_bundle.xml
diff --git a/tests/VectorDrawableTest/res/drawable/ic_hourglass.xml b/tests/graphics/VectorDrawableTest/res/drawable/ic_hourglass.xml
similarity index 100%
rename from tests/VectorDrawableTest/res/drawable/ic_hourglass.xml
rename to tests/graphics/VectorDrawableTest/res/drawable/ic_hourglass.xml
diff --git a/tests/VectorDrawableTest/res/drawable/ic_hourglass_animation.xml b/tests/graphics/VectorDrawableTest/res/drawable/ic_hourglass_animation.xml
similarity index 100%
rename from tests/VectorDrawableTest/res/drawable/ic_hourglass_animation.xml
rename to tests/graphics/VectorDrawableTest/res/drawable/ic_hourglass_animation.xml
diff --git a/tests/VectorDrawableTest/res/drawable/ic_rotate_2_portrait_v2.xml b/tests/graphics/VectorDrawableTest/res/drawable/ic_rotate_2_portrait_v2.xml
similarity index 100%
rename from tests/VectorDrawableTest/res/drawable/ic_rotate_2_portrait_v2.xml
rename to tests/graphics/VectorDrawableTest/res/drawable/ic_rotate_2_portrait_v2.xml
diff --git a/tests/VectorDrawableTest/res/drawable/ic_rotate_2_portrait_v2_animation.xml b/tests/graphics/VectorDrawableTest/res/drawable/ic_rotate_2_portrait_v2_animation.xml
similarity index 100%
rename from tests/VectorDrawableTest/res/drawable/ic_rotate_2_portrait_v2_animation.xml
rename to tests/graphics/VectorDrawableTest/res/drawable/ic_rotate_2_portrait_v2_animation.xml
diff --git a/tests/VectorDrawableTest/res/drawable/ic_signal_airplane_v2.xml b/tests/graphics/VectorDrawableTest/res/drawable/ic_signal_airplane_v2.xml
similarity index 100%
rename from tests/VectorDrawableTest/res/drawable/ic_signal_airplane_v2.xml
rename to tests/graphics/VectorDrawableTest/res/drawable/ic_signal_airplane_v2.xml
diff --git a/tests/VectorDrawableTest/res/drawable/ic_signal_airplane_v2_animation.xml b/tests/graphics/VectorDrawableTest/res/drawable/ic_signal_airplane_v2_animation.xml
similarity index 100%
rename from tests/VectorDrawableTest/res/drawable/ic_signal_airplane_v2_animation.xml
rename to tests/graphics/VectorDrawableTest/res/drawable/ic_signal_airplane_v2_animation.xml
diff --git a/tests/VectorDrawableTest/res/drawable/icon.png b/tests/graphics/VectorDrawableTest/res/drawable/icon.png
similarity index 100%
rename from tests/VectorDrawableTest/res/drawable/icon.png
rename to tests/graphics/VectorDrawableTest/res/drawable/icon.png
Binary files differ
diff --git a/tests/VectorDrawableTest/res/drawable/state_animation_drawable04.xml b/tests/graphics/VectorDrawableTest/res/drawable/state_animation_drawable04.xml
similarity index 100%
rename from tests/VectorDrawableTest/res/drawable/state_animation_drawable04.xml
rename to tests/graphics/VectorDrawableTest/res/drawable/state_animation_drawable04.xml
diff --git a/tests/VectorDrawableTest/res/drawable/state_animation_drawable04_false.xml b/tests/graphics/VectorDrawableTest/res/drawable/state_animation_drawable04_false.xml
similarity index 100%
rename from tests/VectorDrawableTest/res/drawable/state_animation_drawable04_false.xml
rename to tests/graphics/VectorDrawableTest/res/drawable/state_animation_drawable04_false.xml
diff --git a/tests/VectorDrawableTest/res/drawable/state_animation_vector_drawable01.xml b/tests/graphics/VectorDrawableTest/res/drawable/state_animation_vector_drawable01.xml
similarity index 100%
rename from tests/VectorDrawableTest/res/drawable/state_animation_vector_drawable01.xml
rename to tests/graphics/VectorDrawableTest/res/drawable/state_animation_vector_drawable01.xml
diff --git a/tests/VectorDrawableTest/res/drawable/state_animation_vector_drawable01_false.xml b/tests/graphics/VectorDrawableTest/res/drawable/state_animation_vector_drawable01_false.xml
similarity index 100%
rename from tests/VectorDrawableTest/res/drawable/state_animation_vector_drawable01_false.xml
rename to tests/graphics/VectorDrawableTest/res/drawable/state_animation_vector_drawable01_false.xml
diff --git a/tests/VectorDrawableTest/res/drawable/state_animation_vector_drawable02.xml b/tests/graphics/VectorDrawableTest/res/drawable/state_animation_vector_drawable02.xml
similarity index 100%
rename from tests/VectorDrawableTest/res/drawable/state_animation_vector_drawable02.xml
rename to tests/graphics/VectorDrawableTest/res/drawable/state_animation_vector_drawable02.xml
diff --git a/tests/VectorDrawableTest/res/drawable/state_animation_vector_drawable02_false.xml b/tests/graphics/VectorDrawableTest/res/drawable/state_animation_vector_drawable02_false.xml
similarity index 100%
rename from tests/VectorDrawableTest/res/drawable/state_animation_vector_drawable02_false.xml
rename to tests/graphics/VectorDrawableTest/res/drawable/state_animation_vector_drawable02_false.xml
diff --git a/tests/VectorDrawableTest/res/drawable/state_animation_vector_drawable03.xml b/tests/graphics/VectorDrawableTest/res/drawable/state_animation_vector_drawable03.xml
similarity index 100%
rename from tests/VectorDrawableTest/res/drawable/state_animation_vector_drawable03.xml
rename to tests/graphics/VectorDrawableTest/res/drawable/state_animation_vector_drawable03.xml
diff --git a/tests/VectorDrawableTest/res/drawable/state_animation_vector_drawable03_false.xml b/tests/graphics/VectorDrawableTest/res/drawable/state_animation_vector_drawable03_false.xml
similarity index 100%
rename from tests/VectorDrawableTest/res/drawable/state_animation_vector_drawable03_false.xml
rename to tests/graphics/VectorDrawableTest/res/drawable/state_animation_vector_drawable03_false.xml
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable01.xml b/tests/graphics/VectorDrawableTest/res/drawable/vector_drawable01.xml
similarity index 100%
rename from tests/VectorDrawableTest/res/drawable/vector_drawable01.xml
rename to tests/graphics/VectorDrawableTest/res/drawable/vector_drawable01.xml
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable02.xml b/tests/graphics/VectorDrawableTest/res/drawable/vector_drawable02.xml
similarity index 100%
rename from tests/VectorDrawableTest/res/drawable/vector_drawable02.xml
rename to tests/graphics/VectorDrawableTest/res/drawable/vector_drawable02.xml
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable03.xml b/tests/graphics/VectorDrawableTest/res/drawable/vector_drawable03.xml
similarity index 100%
rename from tests/VectorDrawableTest/res/drawable/vector_drawable03.xml
rename to tests/graphics/VectorDrawableTest/res/drawable/vector_drawable03.xml
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable04.xml b/tests/graphics/VectorDrawableTest/res/drawable/vector_drawable04.xml
similarity index 100%
rename from tests/VectorDrawableTest/res/drawable/vector_drawable04.xml
rename to tests/graphics/VectorDrawableTest/res/drawable/vector_drawable04.xml
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable05.xml b/tests/graphics/VectorDrawableTest/res/drawable/vector_drawable05.xml
similarity index 100%
rename from tests/VectorDrawableTest/res/drawable/vector_drawable05.xml
rename to tests/graphics/VectorDrawableTest/res/drawable/vector_drawable05.xml
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable06.xml b/tests/graphics/VectorDrawableTest/res/drawable/vector_drawable06.xml
similarity index 100%
rename from tests/VectorDrawableTest/res/drawable/vector_drawable06.xml
rename to tests/graphics/VectorDrawableTest/res/drawable/vector_drawable06.xml
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable07.xml b/tests/graphics/VectorDrawableTest/res/drawable/vector_drawable07.xml
similarity index 100%
rename from tests/VectorDrawableTest/res/drawable/vector_drawable07.xml
rename to tests/graphics/VectorDrawableTest/res/drawable/vector_drawable07.xml
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable08.xml b/tests/graphics/VectorDrawableTest/res/drawable/vector_drawable08.xml
similarity index 100%
rename from tests/VectorDrawableTest/res/drawable/vector_drawable08.xml
rename to tests/graphics/VectorDrawableTest/res/drawable/vector_drawable08.xml
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable09.xml b/tests/graphics/VectorDrawableTest/res/drawable/vector_drawable09.xml
similarity index 100%
rename from tests/VectorDrawableTest/res/drawable/vector_drawable09.xml
rename to tests/graphics/VectorDrawableTest/res/drawable/vector_drawable09.xml
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable10.xml b/tests/graphics/VectorDrawableTest/res/drawable/vector_drawable10.xml
similarity index 100%
rename from tests/VectorDrawableTest/res/drawable/vector_drawable10.xml
rename to tests/graphics/VectorDrawableTest/res/drawable/vector_drawable10.xml
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable11.xml b/tests/graphics/VectorDrawableTest/res/drawable/vector_drawable11.xml
similarity index 100%
rename from tests/VectorDrawableTest/res/drawable/vector_drawable11.xml
rename to tests/graphics/VectorDrawableTest/res/drawable/vector_drawable11.xml
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable12.xml b/tests/graphics/VectorDrawableTest/res/drawable/vector_drawable12.xml
similarity index 100%
rename from tests/VectorDrawableTest/res/drawable/vector_drawable12.xml
rename to tests/graphics/VectorDrawableTest/res/drawable/vector_drawable12.xml
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable13.xml b/tests/graphics/VectorDrawableTest/res/drawable/vector_drawable13.xml
similarity index 100%
rename from tests/VectorDrawableTest/res/drawable/vector_drawable13.xml
rename to tests/graphics/VectorDrawableTest/res/drawable/vector_drawable13.xml
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable14.xml b/tests/graphics/VectorDrawableTest/res/drawable/vector_drawable14.xml
similarity index 100%
rename from tests/VectorDrawableTest/res/drawable/vector_drawable14.xml
rename to tests/graphics/VectorDrawableTest/res/drawable/vector_drawable14.xml
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable15.xml b/tests/graphics/VectorDrawableTest/res/drawable/vector_drawable15.xml
similarity index 100%
rename from tests/VectorDrawableTest/res/drawable/vector_drawable15.xml
rename to tests/graphics/VectorDrawableTest/res/drawable/vector_drawable15.xml
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable16.xml b/tests/graphics/VectorDrawableTest/res/drawable/vector_drawable16.xml
similarity index 100%
rename from tests/VectorDrawableTest/res/drawable/vector_drawable16.xml
rename to tests/graphics/VectorDrawableTest/res/drawable/vector_drawable16.xml
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable17.xml b/tests/graphics/VectorDrawableTest/res/drawable/vector_drawable17.xml
similarity index 100%
rename from tests/VectorDrawableTest/res/drawable/vector_drawable17.xml
rename to tests/graphics/VectorDrawableTest/res/drawable/vector_drawable17.xml
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable18.xml b/tests/graphics/VectorDrawableTest/res/drawable/vector_drawable18.xml
similarity index 100%
rename from tests/VectorDrawableTest/res/drawable/vector_drawable18.xml
rename to tests/graphics/VectorDrawableTest/res/drawable/vector_drawable18.xml
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable19.xml b/tests/graphics/VectorDrawableTest/res/drawable/vector_drawable19.xml
similarity index 100%
rename from tests/VectorDrawableTest/res/drawable/vector_drawable19.xml
rename to tests/graphics/VectorDrawableTest/res/drawable/vector_drawable19.xml
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable20.xml b/tests/graphics/VectorDrawableTest/res/drawable/vector_drawable20.xml
similarity index 100%
rename from tests/VectorDrawableTest/res/drawable/vector_drawable20.xml
rename to tests/graphics/VectorDrawableTest/res/drawable/vector_drawable20.xml
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable21.xml b/tests/graphics/VectorDrawableTest/res/drawable/vector_drawable21.xml
similarity index 100%
rename from tests/VectorDrawableTest/res/drawable/vector_drawable21.xml
rename to tests/graphics/VectorDrawableTest/res/drawable/vector_drawable21.xml
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable22.xml b/tests/graphics/VectorDrawableTest/res/drawable/vector_drawable22.xml
similarity index 100%
rename from tests/VectorDrawableTest/res/drawable/vector_drawable22.xml
rename to tests/graphics/VectorDrawableTest/res/drawable/vector_drawable22.xml
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable23.xml b/tests/graphics/VectorDrawableTest/res/drawable/vector_drawable23.xml
similarity index 100%
rename from tests/VectorDrawableTest/res/drawable/vector_drawable23.xml
rename to tests/graphics/VectorDrawableTest/res/drawable/vector_drawable23.xml
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable24.xml b/tests/graphics/VectorDrawableTest/res/drawable/vector_drawable24.xml
similarity index 100%
rename from tests/VectorDrawableTest/res/drawable/vector_drawable24.xml
rename to tests/graphics/VectorDrawableTest/res/drawable/vector_drawable24.xml
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable25.xml b/tests/graphics/VectorDrawableTest/res/drawable/vector_drawable25.xml
similarity index 100%
rename from tests/VectorDrawableTest/res/drawable/vector_drawable25.xml
rename to tests/graphics/VectorDrawableTest/res/drawable/vector_drawable25.xml
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable26.xml b/tests/graphics/VectorDrawableTest/res/drawable/vector_drawable26.xml
similarity index 100%
rename from tests/VectorDrawableTest/res/drawable/vector_drawable26.xml
rename to tests/graphics/VectorDrawableTest/res/drawable/vector_drawable26.xml
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable27.xml b/tests/graphics/VectorDrawableTest/res/drawable/vector_drawable27.xml
similarity index 100%
rename from tests/VectorDrawableTest/res/drawable/vector_drawable27.xml
rename to tests/graphics/VectorDrawableTest/res/drawable/vector_drawable27.xml
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable28.xml b/tests/graphics/VectorDrawableTest/res/drawable/vector_drawable28.xml
similarity index 100%
rename from tests/VectorDrawableTest/res/drawable/vector_drawable28.xml
rename to tests/graphics/VectorDrawableTest/res/drawable/vector_drawable28.xml
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable29.xml b/tests/graphics/VectorDrawableTest/res/drawable/vector_drawable29.xml
similarity index 100%
rename from tests/VectorDrawableTest/res/drawable/vector_drawable29.xml
rename to tests/graphics/VectorDrawableTest/res/drawable/vector_drawable29.xml
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable30.xml b/tests/graphics/VectorDrawableTest/res/drawable/vector_drawable30.xml
similarity index 100%
rename from tests/VectorDrawableTest/res/drawable/vector_drawable30.xml
rename to tests/graphics/VectorDrawableTest/res/drawable/vector_drawable30.xml
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable_favorite.xml b/tests/graphics/VectorDrawableTest/res/drawable/vector_drawable_favorite.xml
similarity index 100%
rename from tests/VectorDrawableTest/res/drawable/vector_drawable_favorite.xml
rename to tests/graphics/VectorDrawableTest/res/drawable/vector_drawable_favorite.xml
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable_group_clip.xml b/tests/graphics/VectorDrawableTest/res/drawable/vector_drawable_group_clip.xml
similarity index 100%
rename from tests/VectorDrawableTest/res/drawable/vector_drawable_group_clip.xml
rename to tests/graphics/VectorDrawableTest/res/drawable/vector_drawable_group_clip.xml
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable_grouping_1.xml b/tests/graphics/VectorDrawableTest/res/drawable/vector_drawable_grouping_1.xml
similarity index 100%
rename from tests/VectorDrawableTest/res/drawable/vector_drawable_grouping_1.xml
rename to tests/graphics/VectorDrawableTest/res/drawable/vector_drawable_grouping_1.xml
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable_linear_progress_bar.xml b/tests/graphics/VectorDrawableTest/res/drawable/vector_drawable_linear_progress_bar.xml
similarity index 100%
rename from tests/VectorDrawableTest/res/drawable/vector_drawable_linear_progress_bar.xml
rename to tests/graphics/VectorDrawableTest/res/drawable/vector_drawable_linear_progress_bar.xml
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable_progress_bar.xml b/tests/graphics/VectorDrawableTest/res/drawable/vector_drawable_progress_bar.xml
similarity index 100%
rename from tests/VectorDrawableTest/res/drawable/vector_drawable_progress_bar.xml
rename to tests/graphics/VectorDrawableTest/res/drawable/vector_drawable_progress_bar.xml
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable_scale0.xml b/tests/graphics/VectorDrawableTest/res/drawable/vector_drawable_scale0.xml
similarity index 100%
rename from tests/VectorDrawableTest/res/drawable/vector_drawable_scale0.xml
rename to tests/graphics/VectorDrawableTest/res/drawable/vector_drawable_scale0.xml
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable_scale1.xml b/tests/graphics/VectorDrawableTest/res/drawable/vector_drawable_scale1.xml
similarity index 100%
rename from tests/VectorDrawableTest/res/drawable/vector_drawable_scale1.xml
rename to tests/graphics/VectorDrawableTest/res/drawable/vector_drawable_scale1.xml
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable_scale2.xml b/tests/graphics/VectorDrawableTest/res/drawable/vector_drawable_scale2.xml
similarity index 100%
rename from tests/VectorDrawableTest/res/drawable/vector_drawable_scale2.xml
rename to tests/graphics/VectorDrawableTest/res/drawable/vector_drawable_scale2.xml
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable_scale3.xml b/tests/graphics/VectorDrawableTest/res/drawable/vector_drawable_scale3.xml
similarity index 100%
rename from tests/VectorDrawableTest/res/drawable/vector_drawable_scale3.xml
rename to tests/graphics/VectorDrawableTest/res/drawable/vector_drawable_scale3.xml
diff --git a/tests/VectorDrawableTest/res/drawable/vector_icon_create.xml b/tests/graphics/VectorDrawableTest/res/drawable/vector_icon_create.xml
similarity index 100%
rename from tests/VectorDrawableTest/res/drawable/vector_icon_create.xml
rename to tests/graphics/VectorDrawableTest/res/drawable/vector_icon_create.xml
diff --git a/tests/VectorDrawableTest/res/drawable/vector_icon_delete.xml b/tests/graphics/VectorDrawableTest/res/drawable/vector_icon_delete.xml
similarity index 100%
rename from tests/VectorDrawableTest/res/drawable/vector_icon_delete.xml
rename to tests/graphics/VectorDrawableTest/res/drawable/vector_icon_delete.xml
diff --git a/tests/VectorDrawableTest/res/drawable/vector_icon_filltype_evenodd.xml b/tests/graphics/VectorDrawableTest/res/drawable/vector_icon_filltype_evenodd.xml
similarity index 100%
rename from tests/VectorDrawableTest/res/drawable/vector_icon_filltype_evenodd.xml
rename to tests/graphics/VectorDrawableTest/res/drawable/vector_icon_filltype_evenodd.xml
diff --git a/tests/VectorDrawableTest/res/drawable/vector_icon_filltype_nonzero.xml b/tests/graphics/VectorDrawableTest/res/drawable/vector_icon_filltype_nonzero.xml
similarity index 100%
rename from tests/VectorDrawableTest/res/drawable/vector_icon_filltype_nonzero.xml
rename to tests/graphics/VectorDrawableTest/res/drawable/vector_icon_filltype_nonzero.xml
diff --git a/tests/VectorDrawableTest/res/drawable/vector_icon_gradient_1.xml b/tests/graphics/VectorDrawableTest/res/drawable/vector_icon_gradient_1.xml
similarity index 100%
rename from tests/VectorDrawableTest/res/drawable/vector_icon_gradient_1.xml
rename to tests/graphics/VectorDrawableTest/res/drawable/vector_icon_gradient_1.xml
diff --git a/tests/VectorDrawableTest/res/drawable/vector_icon_gradient_1_clamp.xml b/tests/graphics/VectorDrawableTest/res/drawable/vector_icon_gradient_1_clamp.xml
similarity index 100%
rename from tests/VectorDrawableTest/res/drawable/vector_icon_gradient_1_clamp.xml
rename to tests/graphics/VectorDrawableTest/res/drawable/vector_icon_gradient_1_clamp.xml
diff --git a/tests/VectorDrawableTest/res/drawable/vector_icon_gradient_2.xml b/tests/graphics/VectorDrawableTest/res/drawable/vector_icon_gradient_2.xml
similarity index 100%
rename from tests/VectorDrawableTest/res/drawable/vector_icon_gradient_2.xml
rename to tests/graphics/VectorDrawableTest/res/drawable/vector_icon_gradient_2.xml
diff --git a/tests/VectorDrawableTest/res/drawable/vector_icon_gradient_2_repeat.xml b/tests/graphics/VectorDrawableTest/res/drawable/vector_icon_gradient_2_repeat.xml
similarity index 100%
rename from tests/VectorDrawableTest/res/drawable/vector_icon_gradient_2_repeat.xml
rename to tests/graphics/VectorDrawableTest/res/drawable/vector_icon_gradient_2_repeat.xml
diff --git a/tests/VectorDrawableTest/res/drawable/vector_icon_gradient_3.xml b/tests/graphics/VectorDrawableTest/res/drawable/vector_icon_gradient_3.xml
similarity index 100%
rename from tests/VectorDrawableTest/res/drawable/vector_icon_gradient_3.xml
rename to tests/graphics/VectorDrawableTest/res/drawable/vector_icon_gradient_3.xml
diff --git a/tests/VectorDrawableTest/res/drawable/vector_icon_gradient_3_mirror.xml b/tests/graphics/VectorDrawableTest/res/drawable/vector_icon_gradient_3_mirror.xml
similarity index 100%
rename from tests/VectorDrawableTest/res/drawable/vector_icon_gradient_3_mirror.xml
rename to tests/graphics/VectorDrawableTest/res/drawable/vector_icon_gradient_3_mirror.xml
diff --git a/tests/VectorDrawableTest/res/drawable/vector_icon_heart.xml b/tests/graphics/VectorDrawableTest/res/drawable/vector_icon_heart.xml
similarity index 100%
rename from tests/VectorDrawableTest/res/drawable/vector_icon_heart.xml
rename to tests/graphics/VectorDrawableTest/res/drawable/vector_icon_heart.xml
diff --git a/tests/VectorDrawableTest/res/drawable/vector_icon_schedule.xml b/tests/graphics/VectorDrawableTest/res/drawable/vector_icon_schedule.xml
similarity index 100%
rename from tests/VectorDrawableTest/res/drawable/vector_icon_schedule.xml
rename to tests/graphics/VectorDrawableTest/res/drawable/vector_icon_schedule.xml
diff --git a/tests/VectorDrawableTest/res/drawable/vector_icon_settings.xml b/tests/graphics/VectorDrawableTest/res/drawable/vector_icon_settings.xml
similarity index 100%
rename from tests/VectorDrawableTest/res/drawable/vector_icon_settings.xml
rename to tests/graphics/VectorDrawableTest/res/drawable/vector_icon_settings.xml
diff --git a/tests/VectorDrawableTest/res/drawable/vector_icon_state_list_simple.xml b/tests/graphics/VectorDrawableTest/res/drawable/vector_icon_state_list_simple.xml
similarity index 100%
rename from tests/VectorDrawableTest/res/drawable/vector_icon_state_list_simple.xml
rename to tests/graphics/VectorDrawableTest/res/drawable/vector_icon_state_list_simple.xml
diff --git a/tests/VectorDrawableTest/res/drawable/vector_icon_state_list_theme.xml b/tests/graphics/VectorDrawableTest/res/drawable/vector_icon_state_list_theme.xml
similarity index 100%
rename from tests/VectorDrawableTest/res/drawable/vector_icon_state_list_theme.xml
rename to tests/graphics/VectorDrawableTest/res/drawable/vector_icon_state_list_theme.xml
diff --git a/tests/VectorDrawableTest/res/drawable/vector_test01.xml b/tests/graphics/VectorDrawableTest/res/drawable/vector_test01.xml
similarity index 100%
rename from tests/VectorDrawableTest/res/drawable/vector_test01.xml
rename to tests/graphics/VectorDrawableTest/res/drawable/vector_test01.xml
diff --git a/tests/VectorDrawableTest/res/drawable/vector_test02.xml b/tests/graphics/VectorDrawableTest/res/drawable/vector_test02.xml
similarity index 100%
rename from tests/VectorDrawableTest/res/drawable/vector_test02.xml
rename to tests/graphics/VectorDrawableTest/res/drawable/vector_test02.xml
diff --git a/tests/VectorDrawableTest/res/interpolator/btn_radio_to_off_mtrl_animation_interpolator_0.xml b/tests/graphics/VectorDrawableTest/res/interpolator/btn_radio_to_off_mtrl_animation_interpolator_0.xml
similarity index 100%
rename from tests/VectorDrawableTest/res/interpolator/btn_radio_to_off_mtrl_animation_interpolator_0.xml
rename to tests/graphics/VectorDrawableTest/res/interpolator/btn_radio_to_off_mtrl_animation_interpolator_0.xml
diff --git a/tests/VectorDrawableTest/res/interpolator/custom_path_interpolator.xml b/tests/graphics/VectorDrawableTest/res/interpolator/custom_path_interpolator.xml
similarity index 100%
rename from tests/VectorDrawableTest/res/interpolator/custom_path_interpolator.xml
rename to tests/graphics/VectorDrawableTest/res/interpolator/custom_path_interpolator.xml
diff --git a/tests/VectorDrawableTest/res/interpolator/custom_path_interpolator_favorite.xml b/tests/graphics/VectorDrawableTest/res/interpolator/custom_path_interpolator_favorite.xml
similarity index 100%
rename from tests/VectorDrawableTest/res/interpolator/custom_path_interpolator_favorite.xml
rename to tests/graphics/VectorDrawableTest/res/interpolator/custom_path_interpolator_favorite.xml
diff --git a/tests/VectorDrawableTest/res/interpolator/custom_path_interpolator_grouping_1_01.xml b/tests/graphics/VectorDrawableTest/res/interpolator/custom_path_interpolator_grouping_1_01.xml
similarity index 100%
rename from tests/VectorDrawableTest/res/interpolator/custom_path_interpolator_grouping_1_01.xml
rename to tests/graphics/VectorDrawableTest/res/interpolator/custom_path_interpolator_grouping_1_01.xml
diff --git a/tests/VectorDrawableTest/res/interpolator/ic_rotate_2_portrait_v2_arrows_1_rotation_interpolator.xml b/tests/graphics/VectorDrawableTest/res/interpolator/ic_rotate_2_portrait_v2_arrows_1_rotation_interpolator.xml
similarity index 100%
rename from tests/VectorDrawableTest/res/interpolator/ic_rotate_2_portrait_v2_arrows_1_rotation_interpolator.xml
rename to tests/graphics/VectorDrawableTest/res/interpolator/ic_rotate_2_portrait_v2_arrows_1_rotation_interpolator.xml
diff --git a/tests/VectorDrawableTest/res/interpolator/ic_rotate_2_portrait_v2_arrows_1_scalex_interpolator.xml b/tests/graphics/VectorDrawableTest/res/interpolator/ic_rotate_2_portrait_v2_arrows_1_scalex_interpolator.xml
similarity index 100%
rename from tests/VectorDrawableTest/res/interpolator/ic_rotate_2_portrait_v2_arrows_1_scalex_interpolator.xml
rename to tests/graphics/VectorDrawableTest/res/interpolator/ic_rotate_2_portrait_v2_arrows_1_scalex_interpolator.xml
diff --git a/tests/VectorDrawableTest/res/interpolator/ic_rotate_2_portrait_v2_device_1_rotation_interpolator.xml b/tests/graphics/VectorDrawableTest/res/interpolator/ic_rotate_2_portrait_v2_device_1_rotation_interpolator.xml
similarity index 100%
rename from tests/VectorDrawableTest/res/interpolator/ic_rotate_2_portrait_v2_device_1_rotation_interpolator.xml
rename to tests/graphics/VectorDrawableTest/res/interpolator/ic_rotate_2_portrait_v2_device_1_rotation_interpolator.xml
diff --git a/tests/VectorDrawableTest/res/interpolator/ic_rotate_2_portrait_v2_device_2_pathdata_interpolator.xml b/tests/graphics/VectorDrawableTest/res/interpolator/ic_rotate_2_portrait_v2_device_2_pathdata_interpolator.xml
similarity index 100%
rename from tests/VectorDrawableTest/res/interpolator/ic_rotate_2_portrait_v2_device_2_pathdata_interpolator.xml
rename to tests/graphics/VectorDrawableTest/res/interpolator/ic_rotate_2_portrait_v2_device_2_pathdata_interpolator.xml
diff --git a/tests/VectorDrawableTest/res/interpolator/ic_signal_airplane_v2_path_1_1_pathdata_interpolator.xml b/tests/graphics/VectorDrawableTest/res/interpolator/ic_signal_airplane_v2_path_1_1_pathdata_interpolator.xml
similarity index 100%
rename from tests/VectorDrawableTest/res/interpolator/ic_signal_airplane_v2_path_1_1_pathdata_interpolator.xml
rename to tests/graphics/VectorDrawableTest/res/interpolator/ic_signal_airplane_v2_path_1_1_pathdata_interpolator.xml
diff --git a/tests/VectorDrawableTest/res/interpolator/trim_end_interpolator.xml b/tests/graphics/VectorDrawableTest/res/interpolator/trim_end_interpolator.xml
similarity index 100%
rename from tests/VectorDrawableTest/res/interpolator/trim_end_interpolator.xml
rename to tests/graphics/VectorDrawableTest/res/interpolator/trim_end_interpolator.xml
diff --git a/tests/VectorDrawableTest/res/interpolator/trim_start_interpolator.xml b/tests/graphics/VectorDrawableTest/res/interpolator/trim_start_interpolator.xml
similarity index 100%
rename from tests/VectorDrawableTest/res/interpolator/trim_start_interpolator.xml
rename to tests/graphics/VectorDrawableTest/res/interpolator/trim_start_interpolator.xml
diff --git a/tests/VectorDrawableTest/res/layout/activity_animated_vector_drawable_attr.xml b/tests/graphics/VectorDrawableTest/res/layout/activity_animated_vector_drawable_attr.xml
similarity index 100%
rename from tests/VectorDrawableTest/res/layout/activity_animated_vector_drawable_attr.xml
rename to tests/graphics/VectorDrawableTest/res/layout/activity_animated_vector_drawable_attr.xml
diff --git a/tests/VectorDrawableTest/res/values/attrs.xml b/tests/graphics/VectorDrawableTest/res/values/attrs.xml
similarity index 100%
rename from tests/VectorDrawableTest/res/values/attrs.xml
rename to tests/graphics/VectorDrawableTest/res/values/attrs.xml
diff --git a/tests/VectorDrawableTest/res/values/colors.xml b/tests/graphics/VectorDrawableTest/res/values/colors.xml
similarity index 100%
rename from tests/VectorDrawableTest/res/values/colors.xml
rename to tests/graphics/VectorDrawableTest/res/values/colors.xml
diff --git a/tests/VectorDrawableTest/res/values/strings.xml b/tests/graphics/VectorDrawableTest/res/values/strings.xml
similarity index 100%
rename from tests/VectorDrawableTest/res/values/strings.xml
rename to tests/graphics/VectorDrawableTest/res/values/strings.xml
diff --git a/tests/VectorDrawableTest/res/values/styles.xml b/tests/graphics/VectorDrawableTest/res/values/styles.xml
similarity index 100%
rename from tests/VectorDrawableTest/res/values/styles.xml
rename to tests/graphics/VectorDrawableTest/res/values/styles.xml
diff --git a/tests/VectorDrawableTest/src/com/android/test/dynamic/AnimatedStateVectorDrawableTest.java b/tests/graphics/VectorDrawableTest/src/com/android/test/dynamic/AnimatedStateVectorDrawableTest.java
similarity index 100%
rename from tests/VectorDrawableTest/src/com/android/test/dynamic/AnimatedStateVectorDrawableTest.java
rename to tests/graphics/VectorDrawableTest/src/com/android/test/dynamic/AnimatedStateVectorDrawableTest.java
diff --git a/tests/VectorDrawableTest/src/com/android/test/dynamic/AnimatedVectorDrawableAttr.java b/tests/graphics/VectorDrawableTest/src/com/android/test/dynamic/AnimatedVectorDrawableAttr.java
similarity index 100%
rename from tests/VectorDrawableTest/src/com/android/test/dynamic/AnimatedVectorDrawableAttr.java
rename to tests/graphics/VectorDrawableTest/src/com/android/test/dynamic/AnimatedVectorDrawableAttr.java
diff --git a/tests/VectorDrawableTest/src/com/android/test/dynamic/AnimatedVectorDrawableDupPerf.java b/tests/graphics/VectorDrawableTest/src/com/android/test/dynamic/AnimatedVectorDrawableDupPerf.java
similarity index 100%
rename from tests/VectorDrawableTest/src/com/android/test/dynamic/AnimatedVectorDrawableDupPerf.java
rename to tests/graphics/VectorDrawableTest/src/com/android/test/dynamic/AnimatedVectorDrawableDupPerf.java
diff --git a/tests/VectorDrawableTest/src/com/android/test/dynamic/AnimatedVectorDrawableTest.java b/tests/graphics/VectorDrawableTest/src/com/android/test/dynamic/AnimatedVectorDrawableTest.java
similarity index 100%
rename from tests/VectorDrawableTest/src/com/android/test/dynamic/AnimatedVectorDrawableTest.java
rename to tests/graphics/VectorDrawableTest/src/com/android/test/dynamic/AnimatedVectorDrawableTest.java
diff --git a/tests/VectorDrawableTest/src/com/android/test/dynamic/BitmapDrawableDupe.java b/tests/graphics/VectorDrawableTest/src/com/android/test/dynamic/BitmapDrawableDupe.java
similarity index 100%
rename from tests/VectorDrawableTest/src/com/android/test/dynamic/BitmapDrawableDupe.java
rename to tests/graphics/VectorDrawableTest/src/com/android/test/dynamic/BitmapDrawableDupe.java
diff --git a/tests/VectorDrawableTest/src/com/android/test/dynamic/BoundsCheckTest.java b/tests/graphics/VectorDrawableTest/src/com/android/test/dynamic/BoundsCheckTest.java
similarity index 100%
rename from tests/VectorDrawableTest/src/com/android/test/dynamic/BoundsCheckTest.java
rename to tests/graphics/VectorDrawableTest/src/com/android/test/dynamic/BoundsCheckTest.java
diff --git a/tests/VectorDrawableTest/src/com/android/test/dynamic/ScaleDrawableTests.java b/tests/graphics/VectorDrawableTest/src/com/android/test/dynamic/ScaleDrawableTests.java
similarity index 100%
rename from tests/VectorDrawableTest/src/com/android/test/dynamic/ScaleDrawableTests.java
rename to tests/graphics/VectorDrawableTest/src/com/android/test/dynamic/ScaleDrawableTests.java
diff --git a/tests/VectorDrawableTest/src/com/android/test/dynamic/VectorCheckbox.java b/tests/graphics/VectorDrawableTest/src/com/android/test/dynamic/VectorCheckbox.java
similarity index 100%
rename from tests/VectorDrawableTest/src/com/android/test/dynamic/VectorCheckbox.java
rename to tests/graphics/VectorDrawableTest/src/com/android/test/dynamic/VectorCheckbox.java
diff --git a/tests/VectorDrawableTest/src/com/android/test/dynamic/VectorDrawable01.java b/tests/graphics/VectorDrawableTest/src/com/android/test/dynamic/VectorDrawable01.java
similarity index 100%
rename from tests/VectorDrawableTest/src/com/android/test/dynamic/VectorDrawable01.java
rename to tests/graphics/VectorDrawableTest/src/com/android/test/dynamic/VectorDrawable01.java
diff --git a/tests/VectorDrawableTest/src/com/android/test/dynamic/VectorDrawableAnimation.java b/tests/graphics/VectorDrawableTest/src/com/android/test/dynamic/VectorDrawableAnimation.java
similarity index 100%
rename from tests/VectorDrawableTest/src/com/android/test/dynamic/VectorDrawableAnimation.java
rename to tests/graphics/VectorDrawableTest/src/com/android/test/dynamic/VectorDrawableAnimation.java
diff --git a/tests/VectorDrawableTest/src/com/android/test/dynamic/VectorDrawableDupPerf.java b/tests/graphics/VectorDrawableTest/src/com/android/test/dynamic/VectorDrawableDupPerf.java
similarity index 100%
rename from tests/VectorDrawableTest/src/com/android/test/dynamic/VectorDrawableDupPerf.java
rename to tests/graphics/VectorDrawableTest/src/com/android/test/dynamic/VectorDrawableDupPerf.java
diff --git a/tests/VectorDrawableTest/src/com/android/test/dynamic/VectorDrawablePerformance.java b/tests/graphics/VectorDrawableTest/src/com/android/test/dynamic/VectorDrawablePerformance.java
similarity index 100%
rename from tests/VectorDrawableTest/src/com/android/test/dynamic/VectorDrawablePerformance.java
rename to tests/graphics/VectorDrawableTest/src/com/android/test/dynamic/VectorDrawablePerformance.java
diff --git a/tests/VectorDrawableTest/src/com/android/test/dynamic/VectorDrawableStaticPerf.java b/tests/graphics/VectorDrawableTest/src/com/android/test/dynamic/VectorDrawableStaticPerf.java
similarity index 100%
rename from tests/VectorDrawableTest/src/com/android/test/dynamic/VectorDrawableStaticPerf.java
rename to tests/graphics/VectorDrawableTest/src/com/android/test/dynamic/VectorDrawableStaticPerf.java
diff --git a/tests/VectorDrawableTest/src/com/android/test/dynamic/VectorDrawableTest.java b/tests/graphics/VectorDrawableTest/src/com/android/test/dynamic/VectorDrawableTest.java
similarity index 100%
rename from tests/VectorDrawableTest/src/com/android/test/dynamic/VectorDrawableTest.java
rename to tests/graphics/VectorDrawableTest/src/com/android/test/dynamic/VectorDrawableTest.java
diff --git a/tests/VectorDrawableTest/src/com/android/test/dynamic/VectorPathChecking.java b/tests/graphics/VectorDrawableTest/src/com/android/test/dynamic/VectorPathChecking.java
similarity index 100%
rename from tests/VectorDrawableTest/src/com/android/test/dynamic/VectorPathChecking.java
rename to tests/graphics/VectorDrawableTest/src/com/android/test/dynamic/VectorPathChecking.java
diff --git a/tools/aapt2/cmd/Link.cpp b/tools/aapt2/cmd/Link.cpp
index 9ca546f..45dd02c 100644
--- a/tools/aapt2/cmd/Link.cpp
+++ b/tools/aapt2/cmd/Link.cpp
@@ -389,7 +389,7 @@
// Build up the rules for degrading newer attributes to older ones.
// NOTE(adamlesinski): These rules are hardcoded right now, but they should be
// generated from the attribute definitions themselves (b/62028956).
- if (const SymbolTable::Symbol* s = symm->FindById(R::attr::paddingHorizontal)) {
+ if (symm->FindById(R::attr::paddingHorizontal)) {
std::vector<ReplacementAttr> replacements{
{"paddingLeft", R::attr::paddingLeft, Attribute(android::ResTable_map::TYPE_DIMENSION)},
{"paddingRight", R::attr::paddingRight, Attribute(android::ResTable_map::TYPE_DIMENSION)},
@@ -398,7 +398,7 @@
util::make_unique<DegradeToManyRule>(std::move(replacements));
}
- if (const SymbolTable::Symbol* s = symm->FindById(R::attr::paddingVertical)) {
+ if (symm->FindById(R::attr::paddingVertical)) {
std::vector<ReplacementAttr> replacements{
{"paddingTop", R::attr::paddingTop, Attribute(android::ResTable_map::TYPE_DIMENSION)},
{"paddingBottom", R::attr::paddingBottom, Attribute(android::ResTable_map::TYPE_DIMENSION)},
@@ -407,7 +407,7 @@
util::make_unique<DegradeToManyRule>(std::move(replacements));
}
- if (const SymbolTable::Symbol* s = symm->FindById(R::attr::layout_marginHorizontal)) {
+ if (symm->FindById(R::attr::layout_marginHorizontal)) {
std::vector<ReplacementAttr> replacements{
{"layout_marginLeft", R::attr::layout_marginLeft,
Attribute(android::ResTable_map::TYPE_DIMENSION)},
@@ -418,7 +418,7 @@
util::make_unique<DegradeToManyRule>(std::move(replacements));
}
- if (const SymbolTable::Symbol* s = symm->FindById(R::attr::layout_marginVertical)) {
+ if (symm->FindById(R::attr::layout_marginVertical)) {
std::vector<ReplacementAttr> replacements{
{"layout_marginTop", R::attr::layout_marginTop,
Attribute(android::ResTable_map::TYPE_DIMENSION)},
diff --git a/tools/aapt2/link/ManifestFixer.cpp b/tools/aapt2/link/ManifestFixer.cpp
index c4f6e70..0b16e2c 100644
--- a/tools/aapt2/link/ManifestFixer.cpp
+++ b/tools/aapt2/link/ManifestFixer.cpp
@@ -338,7 +338,7 @@
}
bool has_gl_es_version = false;
- if (xml::Attribute* attr = el->FindAttribute(xml::kSchemaAndroid, "glEsVersion")) {
+ if (el->FindAttribute(xml::kSchemaAndroid, "glEsVersion")) {
if (has_name) {
diag->Error(android::DiagMessage(el->line_number)
<< "cannot define both android:name and android:glEsVersion in <uses-feature>");
diff --git a/tools/hoststubgen/hoststubgen/helper-framework-runtime-src/libcore-fake/libcore/util/HexEncoding.java b/tools/hoststubgen/hoststubgen/helper-framework-runtime-src/libcore-fake/libcore/util/HexEncoding.java
new file mode 100644
index 0000000..cc2fb7b
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/helper-framework-runtime-src/libcore-fake/libcore/util/HexEncoding.java
@@ -0,0 +1,240 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 libcore.util;
+
+/**
+ * Hexadecimal encoding where each byte is represented by two hexadecimal digits.
+ * @hide
+ */
+public class HexEncoding {
+
+ private static final char[] LOWER_CASE_DIGITS = {
+ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'
+ };
+
+ private static final char[] UPPER_CASE_DIGITS = {
+ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
+ };
+
+ /** Hidden constructor to prevent instantiation. */
+ private HexEncoding() {}
+
+ /**
+ * Encodes the provided byte as a two-digit hexadecimal String value.
+ *
+ * @param b byte to encode
+ * @param upperCase {@code true} to use uppercase letters, {@code false}
+ * for lowercase
+ * @return the encoded string
+ *
+ * @hide
+ */
+ public static String encodeToString(byte b, boolean upperCase) {
+ char[] digits = upperCase ? UPPER_CASE_DIGITS : LOWER_CASE_DIGITS;
+ char[] buf = new char[2]; // We always want two digits.
+ buf[0] = digits[(b >> 4) & 0xf];
+ buf[1] = digits[b & 0xf];
+ return new String(buf, 0, 2);
+ }
+
+ /**
+ * Encodes the provided data as a sequence of hexadecimal characters.
+ *
+ * @param data byte array to encode
+ * @return the encoded data, using uppercase letters
+ *
+ * @hide
+ */
+ public static char[] encode(byte[] data) {
+ return encode(data, 0, data.length, true /* upperCase */);
+ }
+
+ /**
+ * Encodes the provided data as a sequence of hexadecimal characters.
+ *
+ * @param data byte array to encode
+ * @param upperCase {@code true} to use uppercase letters, {@code false}
+ * for lowercase
+ * @return the encoded data
+ *
+ * @hide
+ */
+ public static char[] encode(byte[] data, boolean upperCase) {
+ return encode(data, 0, data.length, upperCase);
+ }
+
+ /**
+ * Encodes the provided data as a sequence of hexadecimal characters.
+ *
+ * @param data byte array containing the data to encode
+ * @param offset offset of the data to encode in the {@code data} array
+ * @param len length of the data to encode in the {@code data} array
+ * @return the encoded data, using uppercase letters
+ *
+ * @hide
+ */
+ public static char[] encode(byte[] data, int offset, int len) {
+ return encode(data, offset, len, true /* upperCase */);
+ }
+
+ /**
+ * Encodes the provided data as a sequence of hexadecimal characters.
+ */
+ private static char[] encode(byte[] data, int offset, int len, boolean upperCase) {
+ char[] digits = upperCase ? UPPER_CASE_DIGITS : LOWER_CASE_DIGITS;
+ char[] result = new char[len * 2];
+ for (int i = 0; i < len; i++) {
+ byte b = data[offset + i];
+ int resultIndex = 2 * i;
+ result[resultIndex] = (digits[(b >> 4) & 0x0f]);
+ result[resultIndex + 1] = (digits[b & 0x0f]);
+ }
+
+ return result;
+ }
+
+ /**
+ * Encodes the provided data as a sequence of hexadecimal characters.
+ *
+ * @param data byte array to encode
+ * @return the encoded data, using uppercase letters
+ *
+ * @hide
+ */
+ public static String encodeToString(byte[] data) {
+ return encodeToString(data, true /* upperCase */);
+ }
+
+ /**
+ * Encodes the provided data as a sequence of hexadecimal characters.
+ *
+ * @param data byte array to encode.
+ * @param upperCase {@code true} to use uppercase letters, {@code false}
+ * for lowercase
+ * @return the encoded data
+ *
+ * @hide
+ */
+ public static String encodeToString(byte[] data, boolean upperCase) {
+ return new String(encode(data, upperCase));
+ }
+
+ /**
+ * Decodes the provided hexadecimal sequence. Odd-length inputs are not
+ * allowed.
+ *
+ * @param encoded string of hexadecimal characters to decode. Letters
+ * can be either uppercase or lowercase.
+ * @return the decoded data
+ * @throws IllegalArgumentException if the input is malformed
+ *
+ * @hide
+ */
+ public static byte[] decode(String encoded) throws IllegalArgumentException {
+ return decode(encoded.toCharArray());
+ }
+
+ /**
+ * Decodes the provided hexadecimal sequence.
+ *
+ * @param encoded string of hexadecimal characters to decode. Letters
+ * can be either uppercase or lowercase.
+ * @param allowSingleChar If {@code true} odd-length inputs are allowed and
+ * the first character is interpreted as the lower bits of the first
+ * result byte. If {@code false} odd-length inputs are not allowed.
+ * @return the decoded data
+ * @throws IllegalArgumentException if the input is malformed
+ *
+ * @hide
+ */
+ public static byte[] decode(String encoded, boolean allowSingleChar)
+ throws IllegalArgumentException {
+ return decode(encoded.toCharArray(), allowSingleChar);
+ }
+
+ /**
+ * Decodes the provided hexadecimal sequence. Odd-length inputs are not
+ * allowed.
+ *
+ * @param encoded char array of hexadecimal characters to decode. Letters
+ * can be either uppercase or lowercase.
+ * @return the decoded data
+ * @throws IllegalArgumentException if the input is malformed
+ *
+ * @hide
+ */
+ public static byte[] decode(char[] encoded) throws IllegalArgumentException {
+ return decode(encoded, false);
+ }
+
+ /**
+ * Decodes the provided hexadecimal sequence.
+ *
+ * @param encoded char array of hexadecimal characters to decode. Letters
+ * can be either uppercase or lowercase.
+ * @param allowSingleChar If {@code true} odd-length inputs are allowed and
+ * the first character is interpreted as the lower bits of the first
+ * result byte. If {@code false} odd-length inputs are not allowed.
+ * @return the decoded data
+ * @throws IllegalArgumentException if the input is malformed
+ *
+ * @hide
+ */
+ public static byte[] decode(char[] encoded, boolean allowSingleChar)
+ throws IllegalArgumentException {
+ int encodedLength = encoded.length;
+ int resultLengthBytes = (encodedLength + 1) / 2;
+ byte[] result = new byte[resultLengthBytes];
+
+ int resultOffset = 0;
+ int i = 0;
+ if (allowSingleChar) {
+ if ((encodedLength % 2) != 0) {
+ // Odd number of digits -- the first digit is the lower 4 bits of the first result
+ // byte.
+ result[resultOffset++] = (byte) toDigit(encoded, i);
+ i++;
+ }
+ } else {
+ if ((encodedLength % 2) != 0) {
+ throw new IllegalArgumentException("Invalid input length: " + encodedLength);
+ }
+ }
+
+ for (; i < encodedLength; i += 2) {
+ result[resultOffset++] = (byte) ((toDigit(encoded, i) << 4) | toDigit(encoded, i + 1));
+ }
+
+ return result;
+ }
+
+ private static int toDigit(char[] str, int offset) throws IllegalArgumentException {
+ // NOTE: that this isn't really a code point in the traditional sense, since we're
+ // just rejecting surrogate pairs outright.
+ int pseudoCodePoint = str[offset];
+
+ if ('0' <= pseudoCodePoint && pseudoCodePoint <= '9') {
+ return pseudoCodePoint - '0';
+ } else if ('a' <= pseudoCodePoint && pseudoCodePoint <= 'f') {
+ return 10 + (pseudoCodePoint - 'a');
+ } else if ('A' <= pseudoCodePoint && pseudoCodePoint <= 'F') {
+ return 10 + (pseudoCodePoint - 'A');
+ }
+
+ throw new IllegalArgumentException("Illegal char: " + str[offset] + " at offset " + offset);
+ }
+}