diff options
248 files changed, 6572 insertions, 1864 deletions
diff --git a/Android.bp b/Android.bp index 7903742a0fbe..4485682f9435 100644 --- a/Android.bp +++ b/Android.bp @@ -760,6 +760,46 @@ cc_library { }, } +filegroup { + name: "incremental_aidl", + srcs: [ + "core/java/android/os/incremental/IIncrementalService.aidl", + "core/java/android/os/incremental/IIncrementalServiceProxy.aidl", + "core/java/android/os/incremental/IncrementalDataLoaderParamsParcel.aidl", + "core/java/android/os/incremental/IncrementalFileSystemControlParcel.aidl", + "core/java/android/os/incremental/NamedParcelFileDescriptor.aidl", + ], + path: "core/java", +} + +filegroup { + name: "incremental_data_loader_aidl", + srcs: [ + "core/java/android/service/incremental/IIncrementalDataLoaderStatusListener.aidl", + "core/java/android/service/incremental/IIncrementalDataLoaderService.aidl", + ], + path: "core/java", +} + +aidl_interface { + name: "libincremental_aidl", + srcs: [ + ":incremental_aidl", + ":incremental_data_loader_aidl", + ], + backend: { + java: { + sdk_version: "28", + }, + cpp: { + enabled: true, + }, + ndk: { + enabled: true, + }, + }, + api_dir: "aidl/incremental", +} gensrcs { name: "gen-platform-proto-constants", 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 4e96f5e0a205..593e49490e94 100644 --- a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java +++ b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java @@ -57,7 +57,6 @@ import android.os.Binder; import android.os.Handler; import android.os.Looper; import android.os.Message; -import android.os.ParcelFileDescriptor; import android.os.Process; import android.os.RemoteException; import android.os.ServiceManager; @@ -2689,12 +2688,10 @@ public class JobSchedulerService extends com.android.server.SystemService } @Override - protected int handleShellCommand(@NonNull ParcelFileDescriptor in, - @NonNull ParcelFileDescriptor out, @NonNull ParcelFileDescriptor err, - @NonNull String[] args) { + protected int handleShellCommand(@NonNull FileDescriptor in, @NonNull FileDescriptor out, + @NonNull FileDescriptor err, @NonNull String[] args) { return (new JobSchedulerShellCommand(JobSchedulerService.this)).exec( - this, in.getFileDescriptor(), out.getFileDescriptor(), err.getFileDescriptor(), - args); + this, in, out, err, args); } diff --git a/apex/jobscheduler/service/java/com/android/server/usage/AppIdleHistory.java b/apex/jobscheduler/service/java/com/android/server/usage/AppIdleHistory.java index 1e4861a89694..82292cfeea09 100644 --- a/apex/jobscheduler/service/java/com/android/server/usage/AppIdleHistory.java +++ b/apex/jobscheduler/service/java/com/android/server/usage/AppIdleHistory.java @@ -578,7 +578,7 @@ public class AppIdleHistory { } } } catch (IOException | XmlPullParserException e) { - Slog.e(TAG, "Unable to read app idle file for user " + userId); + Slog.e(TAG, "Unable to read app idle file for user " + userId, e); } finally { IoUtils.closeQuietly(fis); } @@ -608,6 +608,11 @@ public class AppIdleHistory { final int N = userHistory.size(); for (int i = 0; i < N; i++) { String packageName = userHistory.keyAt(i); + // Skip any unexpected null package names + if (packageName == null) { + Slog.w(TAG, "Skipping App Idle write for unexpected null package"); + continue; + } AppUsageHistory history = userHistory.valueAt(i); xml.startTag(null, TAG_PACKAGE); xml.attribute(null, ATTR_NAME, packageName); @@ -641,7 +646,7 @@ public class AppIdleHistory { appIdleFile.finishWrite(fos); } catch (Exception e) { appIdleFile.failWrite(fos); - Slog.e(TAG, "Error writing app idle file for user " + userId); + Slog.e(TAG, "Error writing app idle file for user " + userId, e); } } diff --git a/apex/statsd/service/java/com/android/server/stats/StatsCompanionService.java b/apex/statsd/service/java/com/android/server/stats/StatsCompanionService.java index 518a29c2017a..d879273df3bc 100644 --- a/apex/statsd/service/java/com/android/server/stats/StatsCompanionService.java +++ b/apex/statsd/service/java/com/android/server/stats/StatsCompanionService.java @@ -18,7 +18,6 @@ package com.android.server.stats; import static android.app.AppOpsManager.OP_FLAGS_ALL_TRUSTED; import static android.content.pm.PackageInfo.REQUESTED_PERMISSION_GRANTED; import static android.content.pm.PermissionInfo.PROTECTION_DANGEROUS; -import static android.os.Process.getPidsForCommands; import static android.os.Process.getUidForPid; import static android.os.storage.VolumeInfo.TYPE_PRIVATE; import static android.os.storage.VolumeInfo.TYPE_PUBLIC; @@ -27,6 +26,7 @@ import static com.android.internal.util.Preconditions.checkNotNull; import static com.android.server.am.MemoryStatUtil.readMemoryStatFromFilesystem; import static com.android.server.stats.IonMemoryUtil.readProcessSystemIonHeapSizesFromDebugfs; import static com.android.server.stats.IonMemoryUtil.readSystemIonHeapSizeFromDebugfs; +import static com.android.server.stats.ProcfsMemoryUtil.forEachPid; import static com.android.server.stats.ProcfsMemoryUtil.readCmdlineFromProcfs; import static com.android.server.stats.ProcfsMemoryUtil.readMemorySnapshotFromProcfs; @@ -144,6 +144,8 @@ import com.android.server.stats.ProcfsMemoryUtil.MemorySnapshot; import com.android.server.storage.DiskStatsFileLogger; import com.android.server.storage.DiskStatsLoggingService; +import com.google.android.collect.Sets; + import libcore.io.IoUtils; import org.json.JSONArray; @@ -163,6 +165,7 @@ import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Map.Entry; +import java.util.Set; import java.util.UUID; import java.util.concurrent.CompletableFuture; import java.util.concurrent.TimeUnit; @@ -216,7 +219,7 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { * <p>Processes are matched by their cmdline in procfs. Example: cat /proc/pid/cmdline returns * /system/bin/statsd for the stats daemon. */ - private static final String[] MEMORY_INTERESTING_NATIVE_PROCESSES = new String[]{ + private static final Set<String> MEMORY_INTERESTING_NATIVE_PROCESSES = Sets.newHashSet( "/system/bin/statsd", // Stats daemon. "/system/bin/surfaceflinger", "/system/bin/apexd", // APEX daemon. @@ -239,8 +242,7 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { "/system/bin/traced_probes", // Perfetto. "webview_zygote", "zygote", - "zygote64", - }; + "zygote64"); /** * Lowest available uid for apps. * @@ -1220,27 +1222,28 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { e.writeInt(snapshot.rssHighWaterMarkInKilobytes); pulledData.add(e); } - int[] pids = getPidsForCommands(MEMORY_INTERESTING_NATIVE_PROCESSES); - for (int pid : pids) { - final String processName = readCmdlineFromProcfs(pid); + forEachPid((pid, cmdLine) -> { + if (!MEMORY_INTERESTING_NATIVE_PROCESSES.contains(cmdLine)) { + return; + } final MemorySnapshot snapshot = readMemorySnapshotFromProcfs(pid); if (snapshot == null) { - continue; + return; } // Sometimes we get here a process that is not included in the whitelist. It comes // from forking the zygote for an app. We can ignore that sample because this process // is collected by ProcessMemoryState. if (isAppUid(snapshot.uid)) { - continue; + return; } StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, elapsedNanos, wallClockNanos); e.writeInt(snapshot.uid); - e.writeString(processName); + e.writeString(cmdLine); // RSS high-water mark in bytes. e.writeLong((long) snapshot.rssHighWaterMarkInKilobytes * 1024L); e.writeInt(snapshot.rssHighWaterMarkInKilobytes); pulledData.add(e); - } + }); // Invoke rss_hwm_reset binary to reset RSS HWM counters for all processes. SystemProperties.set("sys.rss_hwm_reset.on", "1"); } @@ -1267,22 +1270,23 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { e.writeInt(snapshot.anonRssInKilobytes + snapshot.swapInKilobytes); pulledData.add(e); } - int[] pids = getPidsForCommands(MEMORY_INTERESTING_NATIVE_PROCESSES); - for (int pid : pids) { - final String processName = readCmdlineFromProcfs(pid); + forEachPid((pid, cmdLine) -> { + if (!MEMORY_INTERESTING_NATIVE_PROCESSES.contains(cmdLine)) { + return; + } final MemorySnapshot snapshot = readMemorySnapshotFromProcfs(pid); if (snapshot == null) { - continue; + return; } // Sometimes we get here a process that is not included in the whitelist. It comes // from forking the zygote for an app. We can ignore that sample because this process // is collected by ProcessMemoryState. if (isAppUid(snapshot.uid)) { - continue; + return; } StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, elapsedNanos, wallClockNanos); e.writeInt(snapshot.uid); - e.writeString(processName); + e.writeString(cmdLine); e.writeInt(pid); e.writeInt(-1001); // Placeholder for native processes, OOM_SCORE_ADJ_MIN - 1. e.writeInt(snapshot.rssInKilobytes); @@ -1290,7 +1294,7 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { e.writeInt(snapshot.swapInKilobytes); e.writeInt(snapshot.anonRssInKilobytes + snapshot.swapInKilobytes); pulledData.add(e); - } + }); } private static boolean isAppUid(int uid) { diff --git a/api/current.txt b/api/current.txt index f9a295784248..d5ad60cfee9e 100644 --- a/api/current.txt +++ b/api/current.txt @@ -23164,6 +23164,7 @@ package android.location { public class LocationManager { method @Deprecated @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public boolean addGpsStatusListener(android.location.GpsStatus.Listener); + method @Deprecated @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public boolean addNmeaListener(@NonNull android.location.GpsStatus.NmeaListener); method @Deprecated @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public boolean addNmeaListener(@NonNull android.location.OnNmeaMessageListener); method @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public boolean addNmeaListener(@NonNull android.location.OnNmeaMessageListener, @Nullable android.os.Handler); method @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public boolean addNmeaListener(@NonNull java.util.concurrent.Executor, @NonNull android.location.OnNmeaMessageListener); @@ -23194,6 +23195,7 @@ package android.location { method @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public boolean registerGnssStatusCallback(@NonNull android.location.GnssStatus.Callback, @Nullable android.os.Handler); method @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public boolean registerGnssStatusCallback(@NonNull java.util.concurrent.Executor, @NonNull android.location.GnssStatus.Callback); method @Deprecated public void removeGpsStatusListener(android.location.GpsStatus.Listener); + method @Deprecated public void removeNmeaListener(@NonNull android.location.GpsStatus.NmeaListener); method public void removeNmeaListener(@NonNull android.location.OnNmeaMessageListener); method @RequiresPermission(anyOf={"android.permission.ACCESS_COARSE_LOCATION", "android.permission.ACCESS_FINE_LOCATION"}, apis="..22") public void removeProximityAlert(@NonNull android.app.PendingIntent); method public void removeTestProvider(@NonNull String); @@ -23500,6 +23502,7 @@ package android.media { method @Deprecated public boolean isBluetoothA2dpOn(); method public boolean isBluetoothScoAvailableOffCall(); method public boolean isBluetoothScoOn(); + method public boolean isCallScreeningModeSupported(); method public static boolean isHapticPlaybackSupported(); method public boolean isMicrophoneMute(); method public boolean isMusicActive(); @@ -23598,6 +23601,7 @@ package android.media { field public static final int GET_DEVICES_ALL = 3; // 0x3 field public static final int GET_DEVICES_INPUTS = 1; // 0x1 field public static final int GET_DEVICES_OUTPUTS = 2; // 0x2 + field public static final int MODE_CALL_SCREENING = 4; // 0x4 field public static final int MODE_CURRENT = -1; // 0xffffffff field public static final int MODE_INVALID = -2; // 0xfffffffe field public static final int MODE_IN_CALL = 2; // 0x2 diff --git a/api/removed.txt b/api/removed.txt index c348ed910bc6..e0e26f7d65a7 100644 --- a/api/removed.txt +++ b/api/removed.txt @@ -217,11 +217,6 @@ package android.location { method @Deprecated public void removeVerticalAccuracy(); } - public class LocationManager { - method @Deprecated @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public boolean addNmeaListener(android.location.GpsStatus.NmeaListener); - method @Deprecated public void removeNmeaListener(android.location.GpsStatus.NmeaListener); - } - } package android.media { diff --git a/cmds/am/src/com/android/commands/am/Am.java b/cmds/am/src/com/android/commands/am/Am.java index 41d546f6d603..22e1d0187f01 100644 --- a/cmds/am/src/com/android/commands/am/Am.java +++ b/cmds/am/src/com/android/commands/am/Am.java @@ -174,6 +174,8 @@ public class Am extends BaseCommand { instrument.noWindowAnimation = true; } else if (opt.equals("--no-hidden-api-checks")) { instrument.disableHiddenApiChecks = true; + } else if (opt.equals("--no-test-api-checks")) { + instrument.disableTestApiChecks = true; } else if (opt.equals("--no-isolated-storage")) { instrument.disableIsolatedStorage = true; } else if (opt.equals("--user")) { diff --git a/cmds/am/src/com/android/commands/am/Instrument.java b/cmds/am/src/com/android/commands/am/Instrument.java index 4d7b5a79b4f7..6afd7c40c1c1 100644 --- a/cmds/am/src/com/android/commands/am/Instrument.java +++ b/cmds/am/src/com/android/commands/am/Instrument.java @@ -17,6 +17,7 @@ package com.android.commands.am; import static android.app.ActivityManager.INSTR_FLAG_DISABLE_HIDDEN_API_CHECKS; +import static android.app.ActivityManager.INSTR_FLAG_DISABLE_TEST_API_CHECKS; import static android.app.ActivityManager.INSTR_FLAG_MOUNT_EXTERNAL_STORAGE_FULL; import android.app.IActivityManager; @@ -85,6 +86,7 @@ public class Instrument { String logPath = null; public boolean noWindowAnimation = false; public boolean disableHiddenApiChecks = false; + public boolean disableTestApiChecks = false; public boolean disableIsolatedStorage = false; public String abi = null; public int userId = UserHandle.USER_CURRENT; @@ -506,6 +508,9 @@ public class Instrument { if (disableHiddenApiChecks) { flags |= INSTR_FLAG_DISABLE_HIDDEN_API_CHECKS; } + if (disableTestApiChecks) { + flags |= INSTR_FLAG_DISABLE_TEST_API_CHECKS; + } if (disableIsolatedStorage) { flags |= INSTR_FLAG_MOUNT_EXTERNAL_STORAGE_FULL; } diff --git a/cmds/statsd/src/HashableDimensionKey.cpp b/cmds/statsd/src/HashableDimensionKey.cpp index 5e156bb26caa..f9f11b267d5e 100644 --- a/cmds/statsd/src/HashableDimensionKey.cpp +++ b/cmds/statsd/src/HashableDimensionKey.cpp @@ -59,10 +59,11 @@ android::hash_t hashDimension(const HashableDimensionKey& value) { return JenkinsHashWhiten(hash); } -bool filterValues(const Matcher& matcherField, const vector<FieldValue>& values, Value* output) { +bool filterValues(const Matcher& matcherField, const vector<FieldValue>& values, + FieldValue* output) { for (const auto& value : values) { if (value.mField.matches(matcherField)) { - (*output) = value.mValue; + (*output) = value; return true; } } @@ -106,15 +107,34 @@ void getDimensionForCondition(const std::vector<FieldValue>& eventValues, size_t count = conditionDimension->getValues().size(); if (count != links.conditionFields.size()) { - // ALOGE("WTF condition link is bad"); return; } for (size_t i = 0; i < count; i++) { conditionDimension->mutableValue(i)->mField.setField( - links.conditionFields[i].mMatcher.getField()); + links.conditionFields[i].mMatcher.getField()); conditionDimension->mutableValue(i)->mField.setTag( - links.conditionFields[i].mMatcher.getTag()); + links.conditionFields[i].mMatcher.getTag()); + } +} + +void getDimensionForState(const std::vector<FieldValue>& eventValues, const Metric2State& link, + HashableDimensionKey* statePrimaryKey) { + // First, get the dimension from the event using the "what" fields from the + // MetricStateLinks. + filterValues(link.metricFields, eventValues, statePrimaryKey); + + // Then check that the statePrimaryKey size equals the number of state fields + size_t count = statePrimaryKey->getValues().size(); + if (count != link.stateFields.size()) { + return; + } + + // For each dimension Value in the statePrimaryKey, set the field and tag + // using the state atom fields from MetricStateLinks. + for (size_t i = 0; i < count; i++) { + statePrimaryKey->mutableValue(i)->mField.setField(link.stateFields[i].mMatcher.getField()); + statePrimaryKey->mutableValue(i)->mField.setTag(link.stateFields[i].mMatcher.getTag()); } } @@ -185,11 +205,11 @@ string HashableDimensionKey::toString() const { bool MetricDimensionKey::operator==(const MetricDimensionKey& that) const { return mDimensionKeyInWhat == that.getDimensionKeyInWhat() && - mDimensionKeyInCondition == that.getDimensionKeyInCondition(); + mStateValuesKey == that.getStateValuesKey(); }; string MetricDimensionKey::toString() const { - return mDimensionKeyInWhat.toString() + mDimensionKeyInCondition.toString(); + return mDimensionKeyInWhat.toString() + mStateValuesKey.toString(); } bool MetricDimensionKey::operator<(const MetricDimensionKey& that) const { @@ -199,7 +219,7 @@ bool MetricDimensionKey::operator<(const MetricDimensionKey& that) const { return false; } - return mDimensionKeyInCondition < that.getDimensionKeyInCondition(); + return mStateValuesKey < that.getStateValuesKey(); } } // namespace statsd diff --git a/cmds/statsd/src/HashableDimensionKey.h b/cmds/statsd/src/HashableDimensionKey.h index a12385057585..b9b86ce13c8b 100644 --- a/cmds/statsd/src/HashableDimensionKey.h +++ b/cmds/statsd/src/HashableDimensionKey.h @@ -34,6 +34,12 @@ struct Metric2Condition { std::vector<Matcher> conditionFields; }; +struct Metric2State { + int32_t stateAtomId; + std::vector<Matcher> metricFields; + std::vector<Matcher> stateFields; +}; + class HashableDimensionKey { public: explicit HashableDimensionKey(const std::vector<FieldValue>& values) { @@ -76,17 +82,16 @@ private: }; class MetricDimensionKey { - public: +public: explicit MetricDimensionKey(const HashableDimensionKey& dimensionKeyInWhat, - const HashableDimensionKey& dimensionKeyInCondition) - : mDimensionKeyInWhat(dimensionKeyInWhat), - mDimensionKeyInCondition(dimensionKeyInCondition) {}; + const HashableDimensionKey& stateValuesKey) + : mDimensionKeyInWhat(dimensionKeyInWhat), mStateValuesKey(stateValuesKey){}; MetricDimensionKey(){}; MetricDimensionKey(const MetricDimensionKey& that) : mDimensionKeyInWhat(that.getDimensionKeyInWhat()), - mDimensionKeyInCondition(that.getDimensionKeyInCondition()) {}; + mStateValuesKey(that.getStateValuesKey()){}; MetricDimensionKey& operator=(const MetricDimensionKey& from) = default; @@ -96,25 +101,25 @@ class MetricDimensionKey { return mDimensionKeyInWhat; } - inline const HashableDimensionKey& getDimensionKeyInCondition() const { - return mDimensionKeyInCondition; + inline const HashableDimensionKey& getStateValuesKey() const { + return mStateValuesKey; } - inline void setDimensionKeyInCondition(const HashableDimensionKey& key) { - mDimensionKeyInCondition = key; + inline void setStateValuesKey(const HashableDimensionKey& key) { + mStateValuesKey = key; } - bool hasDimensionKeyInCondition() const { - return mDimensionKeyInCondition.getValues().size() > 0; + bool hasStateValuesKey() const { + return mStateValuesKey.getValues().size() > 0; } bool operator==(const MetricDimensionKey& that) const; bool operator<(const MetricDimensionKey& that) const; - private: - HashableDimensionKey mDimensionKeyInWhat; - HashableDimensionKey mDimensionKeyInCondition; +private: + HashableDimensionKey mDimensionKeyInWhat; + HashableDimensionKey mStateValuesKey; }; android::hash_t hashDimension(const HashableDimensionKey& key); @@ -124,7 +129,7 @@ android::hash_t hashDimension(const HashableDimensionKey& key); * The value of the FieldValue is output. */ bool filterValues(const Matcher& matcherField, const std::vector<FieldValue>& values, - Value* output); + FieldValue* output); /** * Creating HashableDimensionKeys from FieldValues using matcher. @@ -152,6 +157,13 @@ void getDimensionForCondition(const std::vector<FieldValue>& eventValues, const Metric2Condition& links, HashableDimensionKey* conditionDimension); +/** + * Get dimension values using metric's "what" fields and fill statePrimaryKey's + * mField information using "state" fields. + */ +void getDimensionForState(const std::vector<FieldValue>& eventValues, const Metric2State& link, + HashableDimensionKey* statePrimaryKey); + } // namespace statsd } // namespace os } // namespace android @@ -172,7 +184,7 @@ template <> struct hash<MetricDimensionKey> { std::size_t operator()(const MetricDimensionKey& key) const { android::hash_t hash = hashDimension(key.getDimensionKeyInWhat()); - hash = android::JenkinsHashMix(hash, hashDimension(key.getDimensionKeyInCondition())); + hash = android::JenkinsHashMix(hash, hashDimension(key.getStateValuesKey())); return android::JenkinsHashWhiten(hash); } }; diff --git a/cmds/statsd/src/StatsLogProcessor.h b/cmds/statsd/src/StatsLogProcessor.h index 17f27708bf5b..b41771decc7b 100644 --- a/cmds/statsd/src/StatsLogProcessor.h +++ b/cmds/statsd/src/StatsLogProcessor.h @@ -263,9 +263,10 @@ private: FRIEND_TEST(MetricActivationE2eTest, TestCountMetricWithSameDeactivation); FRIEND_TEST(MetricActivationE2eTest, TestCountMetricWithTwoMetricsTwoDeactivations); - FRIEND_TEST(CountMetricE2eTest, TestWithSimpleState); - FRIEND_TEST(CountMetricE2eTest, TestWithMappedState); - FRIEND_TEST(CountMetricE2eTest, TestWithMultipleStates); + FRIEND_TEST(CountMetricE2eTest, TestSlicedState); + FRIEND_TEST(CountMetricE2eTest, TestSlicedStateWithMap); + FRIEND_TEST(CountMetricE2eTest, TestMultipleSlicedStates); + FRIEND_TEST(CountMetricE2eTest, TestSlicedStateWithPrimaryFields); FRIEND_TEST(DurationMetricE2eTest, TestOneBucket); FRIEND_TEST(DurationMetricE2eTest, TestTwoBuckets); diff --git a/cmds/statsd/src/metrics/CountMetricProducer.cpp b/cmds/statsd/src/metrics/CountMetricProducer.cpp index 4a06387e357f..c29b32c5d1c0 100644 --- a/cmds/statsd/src/metrics/CountMetricProducer.cpp +++ b/cmds/statsd/src/metrics/CountMetricProducer.cpp @@ -57,10 +57,9 @@ const int FIELD_ID_IS_ACTIVE = 14; const int FIELD_ID_DATA = 1; // for CountMetricData const int FIELD_ID_DIMENSION_IN_WHAT = 1; -const int FIELD_ID_DIMENSION_IN_CONDITION = 2; +const int FIELD_ID_SLICE_BY_STATE = 6; const int FIELD_ID_BUCKET_INFO = 3; const int FIELD_ID_DIMENSION_LEAF_IN_WHAT = 4; -const int FIELD_ID_DIMENSION_LEAF_IN_CONDITION = 5; // for CountBucketInfo const int FIELD_ID_COUNT = 3; const int FIELD_ID_BUCKET_NUM = 4; @@ -102,7 +101,13 @@ CountMetricProducer::CountMetricProducer( mConditionSliced = true; } - // TODO(tsaichristine): b/142124705 handle metric state links + for (const auto& stateLink : metric.state_link()) { + Metric2State ms; + ms.stateAtomId = stateLink.state_atom_id(); + translateFieldMatcher(stateLink.fields_in_what(), &ms.metricFields); + translateFieldMatcher(stateLink.fields_in_state(), &ms.stateFields); + mMetric2StateLinks.push_back(ms); + } flushIfNeededLocked(startTimeNs); // Adjust start for partial bucket @@ -132,10 +137,9 @@ void CountMetricProducer::dumpStatesLocked(FILE* out, bool verbose) const { (unsigned long)mCurrentSlicedCounter->size()); if (verbose) { for (const auto& it : *mCurrentSlicedCounter) { - fprintf(out, "\t(what)%s\t(condition)%s %lld\n", - it.first.getDimensionKeyInWhat().toString().c_str(), - it.first.getDimensionKeyInCondition().toString().c_str(), - (unsigned long long)it.second); + fprintf(out, "\t(what)%s\t(state)%s %lld\n", + it.first.getDimensionKeyInWhat().toString().c_str(), + it.first.getStateValuesKey().toString().c_str(), (unsigned long long)it.second); } } } @@ -196,22 +200,16 @@ void CountMetricProducer::onDumpReportLocked(const int64_t dumpTimeNs, FIELD_TYPE_MESSAGE | FIELD_ID_DIMENSION_IN_WHAT); writeDimensionToProto(dimensionKey.getDimensionKeyInWhat(), str_set, protoOutput); protoOutput->end(dimensionToken); - - if (dimensionKey.hasDimensionKeyInCondition()) { - uint64_t dimensionInConditionToken = protoOutput->start( - FIELD_TYPE_MESSAGE | FIELD_ID_DIMENSION_IN_CONDITION); - writeDimensionToProto(dimensionKey.getDimensionKeyInCondition(), - str_set, protoOutput); - protoOutput->end(dimensionInConditionToken); - } } else { writeDimensionLeafNodesToProto(dimensionKey.getDimensionKeyInWhat(), FIELD_ID_DIMENSION_LEAF_IN_WHAT, str_set, protoOutput); - if (dimensionKey.hasDimensionKeyInCondition()) { - writeDimensionLeafNodesToProto(dimensionKey.getDimensionKeyInCondition(), - FIELD_ID_DIMENSION_LEAF_IN_CONDITION, - str_set, protoOutput); - } + } + // Then fill slice_by_state. + for (auto state : dimensionKey.getStateValuesKey().getValues()) { + uint64_t stateToken = protoOutput->start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | + FIELD_ID_SLICE_BY_STATE); + writeStateToProto(state, protoOutput); + protoOutput->end(stateToken); } // Then fill bucket_info (CountBucketInfo). for (const auto& bucket : counter.second) { @@ -282,7 +280,7 @@ void CountMetricProducer::onMatchedLogEventInternalLocked( int64_t eventTimeNs = event.GetElapsedTimestampNs(); flushIfNeededLocked(eventTimeNs); - if (condition == false) { + if (!condition) { return; } diff --git a/cmds/statsd/src/metrics/CountMetricProducer.h b/cmds/statsd/src/metrics/CountMetricProducer.h index 61e0892d50a9..8b17d88e0177 100644 --- a/cmds/statsd/src/metrics/CountMetricProducer.h +++ b/cmds/statsd/src/metrics/CountMetricProducer.h @@ -52,7 +52,7 @@ public: virtual ~CountMetricProducer(); - void onStateChanged(int atomId, const HashableDimensionKey& primaryKey, int oldState, + void onStateChanged(int32_t atomId, const HashableDimensionKey& primaryKey, int oldState, int newState) override; protected: diff --git a/cmds/statsd/src/metrics/DurationMetricProducer.cpp b/cmds/statsd/src/metrics/DurationMetricProducer.cpp index ab2a1c3bd65c..fee5e6e3cb46 100644 --- a/cmds/statsd/src/metrics/DurationMetricProducer.cpp +++ b/cmds/statsd/src/metrics/DurationMetricProducer.cpp @@ -53,10 +53,8 @@ const int FIELD_ID_IS_ACTIVE = 14; const int FIELD_ID_DATA = 1; // for DurationMetricData const int FIELD_ID_DIMENSION_IN_WHAT = 1; -const int FIELD_ID_DIMENSION_IN_CONDITION = 2; const int FIELD_ID_BUCKET_INFO = 3; const int FIELD_ID_DIMENSION_LEAF_IN_WHAT = 4; -const int FIELD_ID_DIMENSION_LEAF_IN_CONDITION = 5; // for DurationBucketInfo const int FIELD_ID_DURATION = 3; const int FIELD_ID_BUCKET_NUM = 4; @@ -120,9 +118,8 @@ DurationMetricProducer::DurationMetricProducer( mUseWhatDimensionAsInternalDimension = equalDimensions(mDimensionsInWhat, mInternalDimensions); if (mWizard != nullptr && mConditionTrackerIndex >= 0 && mMetric2ConditionLinks.size() == 1) { - mHasLinksToAllConditionDimensionsInTracker = - mWizard->equalOutputDimensions(mConditionTrackerIndex, - mMetric2ConditionLinks.begin()->conditionFields); + mHasLinksToAllConditionDimensionsInTracker = mWizard->equalOutputDimensions( + mConditionTrackerIndex, mMetric2ConditionLinks.begin()->conditionFields); } flushIfNeededLocked(startTimeNs); // Adjust start for partial bucket @@ -206,8 +203,7 @@ void DurationMetricProducer::onSlicedConditionMayChangeLocked_opt1(bool conditio mWizard->getTrueSlicedDimensions(mConditionTrackerIndex, &trueConditionDimensions); for (auto& whatIt : mCurrentSlicedDurationTrackerMap) { HashableDimensionKey linkedConditionDimensionKey; - getDimensionForCondition(whatIt.first.getValues(), - mMetric2ConditionLinks[0], + getDimensionForCondition(whatIt.first.getValues(), mMetric2ConditionLinks[0], &linkedConditionDimensionKey); if (trueConditionDimensions.find(linkedConditionDimensionKey) != trueConditionDimensions.end()) { @@ -222,8 +218,7 @@ void DurationMetricProducer::onSlicedConditionMayChangeLocked_opt1(bool conditio if (currentUnSlicedPartCondition) { for (auto& whatIt : mCurrentSlicedDurationTrackerMap) { HashableDimensionKey linkedConditionDimensionKey; - getDimensionForCondition(whatIt.first.getValues(), - mMetric2ConditionLinks[0], + getDimensionForCondition(whatIt.first.getValues(), mMetric2ConditionLinks[0], &linkedConditionDimensionKey); if (dimensionsChangedToTrue->find(linkedConditionDimensionKey) != dimensionsChangedToTrue->end()) { @@ -380,22 +375,9 @@ void DurationMetricProducer::onDumpReportLocked(const int64_t dumpTimeNs, FIELD_TYPE_MESSAGE | FIELD_ID_DIMENSION_IN_WHAT); writeDimensionToProto(dimensionKey.getDimensionKeyInWhat(), str_set, protoOutput); protoOutput->end(dimensionToken); - - if (dimensionKey.hasDimensionKeyInCondition()) { - uint64_t dimensionInConditionToken = protoOutput->start( - FIELD_TYPE_MESSAGE | FIELD_ID_DIMENSION_IN_CONDITION); - writeDimensionToProto(dimensionKey.getDimensionKeyInCondition(), - str_set, protoOutput); - protoOutput->end(dimensionInConditionToken); - } } else { writeDimensionLeafNodesToProto(dimensionKey.getDimensionKeyInWhat(), FIELD_ID_DIMENSION_LEAF_IN_WHAT, str_set, protoOutput); - if (dimensionKey.hasDimensionKeyInCondition()) { - writeDimensionLeafNodesToProto(dimensionKey.getDimensionKeyInCondition(), - FIELD_ID_DIMENSION_LEAF_IN_CONDITION, - str_set, protoOutput); - } } // Then fill bucket_info (DurationBucketInfo). for (const auto& bucket : pair.second) { @@ -472,7 +454,7 @@ void DurationMetricProducer::dumpStatesLocked(FILE* out, bool verbose) const { if (verbose) { for (const auto& whatIt : mCurrentSlicedDurationTrackerMap) { for (const auto& slice : whatIt.second) { - fprintf(out, "\t(what)%s\t(condition)%s\n", whatIt.first.toString().c_str(), + fprintf(out, "\t(what)%s\t(states)%s\n", whatIt.first.toString().c_str(), slice.first.toString().c_str()); slice.second->dumpStates(out, verbose); } @@ -483,8 +465,8 @@ void DurationMetricProducer::dumpStatesLocked(FILE* out, bool verbose) const { bool DurationMetricProducer::hitGuardRailLocked(const MetricDimensionKey& newKey) { auto whatIt = mCurrentSlicedDurationTrackerMap.find(newKey.getDimensionKeyInWhat()); if (whatIt != mCurrentSlicedDurationTrackerMap.end()) { - auto condIt = whatIt->second.find(newKey.getDimensionKeyInCondition()); - if (condIt != whatIt->second.end()) { + auto stateIt = whatIt->second.find(newKey.getStateValuesKey()); + if (stateIt != whatIt->second.end()) { return false; } if (whatIt->second.size() > StatsdStats::kDimensionKeySizeSoftLimit - 1) { @@ -493,8 +475,8 @@ bool DurationMetricProducer::hitGuardRailLocked(const MetricDimensionKey& newKey mConfigKey, mMetricId, newTupleCount); // 2. Don't add more tuples, we are above the allowed threshold. Drop the data. if (newTupleCount > StatsdStats::kDimensionKeySizeHardLimit) { - ALOGE("DurationMetric %lld dropping data for condition dimension key %s", - (long long)mMetricId, newKey.getDimensionKeyInCondition().toString().c_str()); + ALOGE("DurationMetric %lld dropping data for state values key %s", + (long long)mMetricId, newKey.getStateValuesKey().toString().c_str()); StatsdStats::getInstance().noteHardDimensionLimitReached(mMetricId); return true; } @@ -521,24 +503,24 @@ void DurationMetricProducer::handleStartEvent(const MetricDimensionKey& eventKey const ConditionKey& conditionKeys, bool condition, const LogEvent& event) { const auto& whatKey = eventKey.getDimensionKeyInWhat(); - const auto& condKey = eventKey.getDimensionKeyInCondition(); + const auto& stateKey = eventKey.getStateValuesKey(); auto whatIt = mCurrentSlicedDurationTrackerMap.find(whatKey); if (whatIt == mCurrentSlicedDurationTrackerMap.end()) { if (hitGuardRailLocked(eventKey)) { return; } - mCurrentSlicedDurationTrackerMap[whatKey][condKey] = createDurationTracker(eventKey); + mCurrentSlicedDurationTrackerMap[whatKey][stateKey] = createDurationTracker(eventKey); } else { - if (whatIt->second.find(condKey) == whatIt->second.end()) { + if (whatIt->second.find(stateKey) == whatIt->second.end()) { if (hitGuardRailLocked(eventKey)) { return; } - mCurrentSlicedDurationTrackerMap[whatKey][condKey] = createDurationTracker(eventKey); + mCurrentSlicedDurationTrackerMap[whatKey][stateKey] = createDurationTracker(eventKey); } } - auto it = mCurrentSlicedDurationTrackerMap.find(whatKey)->second.find(condKey); + auto it = mCurrentSlicedDurationTrackerMap.find(whatKey)->second.find(stateKey); if (mUseWhatDimensionAsInternalDimension) { it->second->noteStart(whatKey, condition, event.GetElapsedTimestampNs(), conditionKeys); @@ -597,8 +579,8 @@ void DurationMetricProducer::onMatchedLogEventLocked(const size_t matcherIndex, if (mUseWhatDimensionAsInternalDimension) { auto whatIt = mCurrentSlicedDurationTrackerMap.find(dimensionInWhat); if (whatIt != mCurrentSlicedDurationTrackerMap.end()) { - for (const auto& condIt : whatIt->second) { - condIt.second->noteStop(dimensionInWhat, event.GetElapsedTimestampNs(), false); + for (const auto& stateIt : whatIt->second) { + stateIt.second->noteStop(dimensionInWhat, event.GetElapsedTimestampNs(), false); } } return; @@ -611,9 +593,9 @@ void DurationMetricProducer::onMatchedLogEventLocked(const size_t matcherIndex, auto whatIt = mCurrentSlicedDurationTrackerMap.find(dimensionInWhat); if (whatIt != mCurrentSlicedDurationTrackerMap.end()) { - for (const auto& condIt : whatIt->second) { - condIt.second->noteStop( - internalDimensionKey, event.GetElapsedTimestampNs(), false); + for (const auto& stateIt : whatIt->second) { + stateIt.second->noteStop(internalDimensionKey, event.GetElapsedTimestampNs(), + false); } } return; diff --git a/cmds/statsd/src/metrics/GaugeMetricProducer.cpp b/cmds/statsd/src/metrics/GaugeMetricProducer.cpp index d0f88a867da7..64344e837a51 100644 --- a/cmds/statsd/src/metrics/GaugeMetricProducer.cpp +++ b/cmds/statsd/src/metrics/GaugeMetricProducer.cpp @@ -56,10 +56,8 @@ const int FIELD_ID_SKIPPED_START_MILLIS = 3; const int FIELD_ID_SKIPPED_END_MILLIS = 4; // for GaugeMetricData const int FIELD_ID_DIMENSION_IN_WHAT = 1; -const int FIELD_ID_DIMENSION_IN_CONDITION = 2; const int FIELD_ID_BUCKET_INFO = 3; const int FIELD_ID_DIMENSION_LEAF_IN_WHAT = 4; -const int FIELD_ID_DIMENSION_LEAF_IN_CONDITION = 5; // for GaugeBucketInfo const int FIELD_ID_ATOM = 3; const int FIELD_ID_ELAPSED_ATOM_TIMESTAMP = 4; @@ -166,10 +164,9 @@ void GaugeMetricProducer::dumpStatesLocked(FILE* out, bool verbose) const { (unsigned long)mCurrentSlicedBucket->size()); if (verbose) { for (const auto& it : *mCurrentSlicedBucket) { - fprintf(out, "\t(what)%s\t(condition)%s %d atoms\n", - it.first.getDimensionKeyInWhat().toString().c_str(), - it.first.getDimensionKeyInCondition().toString().c_str(), - (int)it.second.size()); + fprintf(out, "\t(what)%s\t(states)%s %d atoms\n", + it.first.getDimensionKeyInWhat().toString().c_str(), + it.first.getStateValuesKey().toString().c_str(), (int)it.second.size()); } } } @@ -238,22 +235,9 @@ void GaugeMetricProducer::onDumpReportLocked(const int64_t dumpTimeNs, FIELD_TYPE_MESSAGE | FIELD_ID_DIMENSION_IN_WHAT); writeDimensionToProto(dimensionKey.getDimensionKeyInWhat(), str_set, protoOutput); protoOutput->end(dimensionToken); - - if (dimensionKey.hasDimensionKeyInCondition()) { - uint64_t dimensionInConditionToken = protoOutput->start( - FIELD_TYPE_MESSAGE | FIELD_ID_DIMENSION_IN_CONDITION); - writeDimensionToProto(dimensionKey.getDimensionKeyInCondition(), - str_set, protoOutput); - protoOutput->end(dimensionInConditionToken); - } } else { writeDimensionLeafNodesToProto(dimensionKey.getDimensionKeyInWhat(), FIELD_ID_DIMENSION_LEAF_IN_WHAT, str_set, protoOutput); - if (dimensionKey.hasDimensionKeyInCondition()) { - writeDimensionLeafNodesToProto(dimensionKey.getDimensionKeyInCondition(), - FIELD_ID_DIMENSION_LEAF_IN_CONDITION, - str_set, protoOutput); - } } // Then fill bucket_info (GaugeBucketInfo). diff --git a/cmds/statsd/src/metrics/MetricProducer.cpp b/cmds/statsd/src/metrics/MetricProducer.cpp index 2a700efe3d37..2c8f0e3d545f 100644 --- a/cmds/statsd/src/metrics/MetricProducer.cpp +++ b/cmds/statsd/src/metrics/MetricProducer.cpp @@ -16,8 +16,11 @@ #define DEBUG false // STOPSHIP if true #include "Log.h" + #include "MetricProducer.h" +#include "state/StateTracker.h" + using android::util::FIELD_COUNT_REPEATED; using android::util::FIELD_TYPE_ENUM; using android::util::FIELD_TYPE_INT32; @@ -92,9 +95,43 @@ void MetricProducer::onMatchedLogEventLocked(const size_t matcherIndex, const Lo condition = mCondition == ConditionState::kTrue; } + // Stores atom id to primary key pairs for each state atom that the metric is + // sliced by. + std::map<int, HashableDimensionKey> statePrimaryKeys; + + // For states with primary fields, use MetricStateLinks to get the primary + // field values from the log event. These values will form a primary key + // that will be used to query StateTracker for the correct state value. + for (const auto& stateLink : mMetric2StateLinks) { + getDimensionForState(event.getValues(), stateLink, + &statePrimaryKeys[stateLink.stateAtomId]); + } + + // For each sliced state, query StateTracker for the state value using + // either the primary key from the previous step or the DEFAULT_DIMENSION_KEY. + // + // Expected functionality: for any case where the MetricStateLinks are + // initialized incorrectly (ex. # of state links != # of primary fields, no + // links are provided for a state with primary fields, links are provided + // in the wrong order, etc.), StateTracker will simply return kStateUnknown + // when queried using an incorrect key. + HashableDimensionKey stateValuesKey; + for (auto atomId : mSlicedStateAtoms) { + FieldValue value; + if (statePrimaryKeys.find(atomId) != statePrimaryKeys.end()) { + // found a primary key for this state, query using the key + getMappedStateValue(atomId, statePrimaryKeys[atomId], &value); + } else { + // if no MetricStateLinks exist for this state atom, + // query using the default dimension key (empty HashableDimensionKey) + getMappedStateValue(atomId, DEFAULT_DIMENSION_KEY, &value); + } + stateValuesKey.addValue(value); + } + HashableDimensionKey dimensionInWhat; filterValues(mDimensionsInWhat, event.getValues(), &dimensionInWhat); - MetricDimensionKey metricKey(dimensionInWhat, DEFAULT_DIMENSION_KEY); + MetricDimensionKey metricKey(dimensionInWhat, stateValuesKey); onMatchedLogEventInternalLocked( matcherIndex, metricKey, conditionKey, condition, event); } @@ -227,6 +264,31 @@ void MetricProducer::writeActiveMetricToProtoOutputStream( } } +void MetricProducer::getMappedStateValue(const int32_t atomId, const HashableDimensionKey& queryKey, + FieldValue* value) { + if (!StateManager::getInstance().getStateValue(atomId, queryKey, value)) { + value->mValue = Value(StateTracker::kStateUnknown); + ALOGW("StateTracker not found for state atom %d", atomId); + return; + } + + // check if there is a state map for this atom + auto atomIt = mStateGroupMap.find(atomId); + if (atomIt == mStateGroupMap.end()) { + return; + } + auto valueIt = atomIt->second.find(value->mValue.int_value); + if (valueIt == atomIt->second.end()) { + // state map exists, but value was not put in a state group + // so set mValue to kStateUnknown + // TODO(tsaichristine): handle incomplete state maps + value->mValue.setInt(StateTracker::kStateUnknown); + } else { + // set mValue to group_id + value->mValue.setLong(valueIt->second); + } +} + } // namespace statsd } // namespace os } // namespace android diff --git a/cmds/statsd/src/metrics/MetricProducer.h b/cmds/statsd/src/metrics/MetricProducer.h index a72de22bd433..d7cbcc8aa6f5 100644 --- a/cmds/statsd/src/metrics/MetricProducer.h +++ b/cmds/statsd/src/metrics/MetricProducer.h @@ -30,6 +30,7 @@ #include "matchers/matcher_util.h" #include "packages/PackageInfoListener.h" #include "state/StateListener.h" +#include "state/StateManager.h" namespace android { namespace os { @@ -340,6 +341,12 @@ protected: return (endNs - mTimeBaseNs) / mBucketSizeNs - 1; } + // Query StateManager for original state value. + // If no state map exists for this atom, return the original value. + // Otherwise, return the group_id mapped to the atom and original value. + void getMappedStateValue(const int32_t atomId, const HashableDimensionKey& queryKey, + FieldValue* value); + const int64_t mMetricId; const ConfigKey mConfigKey; @@ -392,14 +399,19 @@ protected: bool mIsActive; // The slice_by_state atom ids defined in statsd_config. - std::vector<int> mSlicedStateAtoms; + std::vector<int32_t> mSlicedStateAtoms; // Maps atom ids and state values to group_ids (<atom_id, <value, group_id>>). - std::unordered_map<int, std::unordered_map<int, int64_t>> mStateGroupMap; + std::unordered_map<int32_t, std::unordered_map<int, int64_t>> mStateGroupMap; + + // MetricStateLinks defined in statsd_config that link fields in the state + // atom to fields in the "what" atom. + std::vector<Metric2State> mMetric2StateLinks; - FRIEND_TEST(CountMetricE2eTest, TestWithSimpleState); - FRIEND_TEST(CountMetricE2eTest, TestWithMappedState); - FRIEND_TEST(CountMetricE2eTest, TestWithMultipleStates); + FRIEND_TEST(CountMetricE2eTest, TestSlicedState); + FRIEND_TEST(CountMetricE2eTest, TestSlicedStateWithMap); + FRIEND_TEST(CountMetricE2eTest, TestMultipleSlicedStates); + FRIEND_TEST(CountMetricE2eTest, TestSlicedStateWithPrimaryFields); FRIEND_TEST(DurationMetricE2eTest, TestOneBucket); FRIEND_TEST(DurationMetricE2eTest, TestTwoBuckets); diff --git a/cmds/statsd/src/metrics/MetricsManager.h b/cmds/statsd/src/metrics/MetricsManager.h index d184121f5ba0..286610ae1f48 100644 --- a/cmds/statsd/src/metrics/MetricsManager.h +++ b/cmds/statsd/src/metrics/MetricsManager.h @@ -282,9 +282,10 @@ private: TestActivationOnBootMultipleActivationsDifferentActivationTypes); FRIEND_TEST(StatsLogProcessorTest, TestActivationsPersistAcrossSystemServerRestart); - FRIEND_TEST(CountMetricE2eTest, TestWithSimpleState); - FRIEND_TEST(CountMetricE2eTest, TestWithMappedState); - FRIEND_TEST(CountMetricE2eTest, TestWithMultipleStates); + FRIEND_TEST(CountMetricE2eTest, TestSlicedState); + FRIEND_TEST(CountMetricE2eTest, TestSlicedStateWithMap); + FRIEND_TEST(CountMetricE2eTest, TestMultipleSlicedStates); + FRIEND_TEST(CountMetricE2eTest, TestSlicedStateWithPrimaryFields); FRIEND_TEST(DurationMetricE2eTest, TestOneBucket); FRIEND_TEST(DurationMetricE2eTest, TestTwoBuckets); diff --git a/cmds/statsd/src/metrics/ValueMetricProducer.cpp b/cmds/statsd/src/metrics/ValueMetricProducer.cpp index 0ee156b07c55..eb78ebc521e1 100644 --- a/cmds/statsd/src/metrics/ValueMetricProducer.cpp +++ b/cmds/statsd/src/metrics/ValueMetricProducer.cpp @@ -59,10 +59,8 @@ const int FIELD_ID_SKIPPED_START_MILLIS = 3; const int FIELD_ID_SKIPPED_END_MILLIS = 4; // for ValueMetricData const int FIELD_ID_DIMENSION_IN_WHAT = 1; -const int FIELD_ID_DIMENSION_IN_CONDITION = 2; const int FIELD_ID_BUCKET_INFO = 3; const int FIELD_ID_DIMENSION_LEAF_IN_WHAT = 4; -const int FIELD_ID_DIMENSION_LEAF_IN_CONDITION = 5; // for ValueBucketInfo const int FIELD_ID_VALUE_INDEX = 1; const int FIELD_ID_VALUE_LONG = 2; @@ -129,6 +127,7 @@ ValueMetricProducer::ValueMetricProducer( if (metric.has_dimensions_in_what()) { translateFieldMatcher(metric.dimensions_in_what(), &mDimensionsInWhat); mContainANYPositionInDimensionsInWhat = HasPositionANY(metric.dimensions_in_what()); + mSliceByPositionALL = HasPositionALL(metric.dimensions_in_what()); } if (metric.links().size() > 0) { @@ -142,8 +141,6 @@ ValueMetricProducer::ValueMetricProducer( mConditionSliced = true; } - mSliceByPositionALL = HasPositionALL(metric.dimensions_in_what()); - int64_t numBucketsForward = calcBucketsForwardCount(startTimeNs); mCurrentBucketNum += numBucketsForward; @@ -267,21 +264,9 @@ void ValueMetricProducer::onDumpReportLocked(const int64_t dumpTimeNs, protoOutput->start(FIELD_TYPE_MESSAGE | FIELD_ID_DIMENSION_IN_WHAT); writeDimensionToProto(dimensionKey.getDimensionKeyInWhat(), str_set, protoOutput); protoOutput->end(dimensionToken); - if (dimensionKey.hasDimensionKeyInCondition()) { - uint64_t dimensionInConditionToken = - protoOutput->start(FIELD_TYPE_MESSAGE | FIELD_ID_DIMENSION_IN_CONDITION); - writeDimensionToProto(dimensionKey.getDimensionKeyInCondition(), str_set, - protoOutput); - protoOutput->end(dimensionInConditionToken); - } } else { writeDimensionLeafNodesToProto(dimensionKey.getDimensionKeyInWhat(), FIELD_ID_DIMENSION_LEAF_IN_WHAT, str_set, protoOutput); - if (dimensionKey.hasDimensionKeyInCondition()) { - writeDimensionLeafNodesToProto(dimensionKey.getDimensionKeyInCondition(), - FIELD_ID_DIMENSION_LEAF_IN_CONDITION, str_set, - protoOutput); - } } // Then fill bucket_info (ValueBucketInfo). @@ -366,7 +351,7 @@ void ValueMetricProducer::resetBase() { // - ConditionTimer tracks changes based on AND of condition and active state. void ValueMetricProducer::onActiveStateChangedLocked(const int64_t& eventTimeNs) { bool isEventTooLate = eventTimeNs < mCurrentBucketStartTimeNs; - if (ConditionState::kTrue == mCondition && isEventTooLate) { + if (isEventTooLate) { // Drop bucket because event arrived too late, ie. we are missing data for this bucket. invalidateCurrentBucket(); } @@ -401,53 +386,61 @@ void ValueMetricProducer::onConditionChangedLocked(const bool condition, ConditionState newCondition = condition ? ConditionState::kTrue : ConditionState::kFalse; bool isEventTooLate = eventTimeNs < mCurrentBucketStartTimeNs; - if (mIsActive) { - if (isEventTooLate) { - VLOG("Skip event due to late arrival: %lld vs %lld", (long long)eventTimeNs, - (long long)mCurrentBucketStartTimeNs); - StatsdStats::getInstance().noteConditionChangeInNextBucket(mMetricId); - invalidateCurrentBucket(); - } else { - if (mCondition == ConditionState::kUnknown) { - // If the condition was unknown, we mark the bucket as invalid since the bucket will - // contain partial data. For instance, the condition change might happen close to - // the end of the bucket and we might miss lots of data. - // - // We still want to pull to set the base. - invalidateCurrentBucket(); - } + // If the config is not active, skip the event. + if (!mIsActive) { + mCondition = isEventTooLate ? ConditionState::kUnknown : newCondition; + return; + } - // Pull on condition changes. - bool conditionChanged = - (mCondition == ConditionState::kTrue && newCondition == ConditionState::kFalse) - || (mCondition == ConditionState::kFalse && - newCondition == ConditionState::kTrue); - // We do not need to pull when we go from unknown to false. - // - // We also pull if the condition was already true in order to be able to flush the - // bucket at the end if needed. - // - // onConditionChangedLocked might happen on bucket boundaries if this is called before - // #onDataPulled. - if (mIsPulled && (conditionChanged || condition)) { - pullAndMatchEventsLocked(eventTimeNs, newCondition); - } + // If the event arrived late, mark the bucket as invalid and skip the event. + if (isEventTooLate) { + VLOG("Skip event due to late arrival: %lld vs %lld", (long long)eventTimeNs, + (long long)mCurrentBucketStartTimeNs); + StatsdStats::getInstance().noteConditionChangeInNextBucket(mMetricId); + invalidateCurrentBucket(); + mCondition = ConditionState::kUnknown; + mConditionTimer.onConditionChanged(mCondition, eventTimeNs); + return; + } - // When condition change from true to false, clear diff base but don't - // reset other counters as we may accumulate more value in the bucket. - if (mUseDiff && mCondition == ConditionState::kTrue - && newCondition == ConditionState::kFalse) { - resetBase(); - } - } + // If the previous condition was unknown, mark the bucket as invalid + // because the bucket will contain partial data. For example, the condition + // change might happen close to the end of the bucket and we might miss a + // lot of data. + // + // We still want to pull to set the base. + if (mCondition == ConditionState::kUnknown) { + invalidateCurrentBucket(); } - mCondition = isEventTooLate ? initialCondition(mConditionTrackerIndex) : newCondition; + // Pull and match for the following condition change cases: + // unknown/false -> true - condition changed + // true -> false - condition changed + // true -> true - old condition was true so we can flush the bucket at the + // end if needed. + // + // We don’t need to pull for unknown -> false or false -> false. + // + // onConditionChangedLocked might happen on bucket boundaries if this is + // called before #onDataPulled. + if (mIsPulled && + (newCondition == ConditionState::kTrue || mCondition == ConditionState::kTrue)) { + pullAndMatchEventsLocked(eventTimeNs, newCondition); + } - if (mIsActive) { - flushIfNeededLocked(eventTimeNs); - mConditionTimer.onConditionChanged(mCondition, eventTimeNs); + // For metrics that use diff, when condition changes from true to false, + // clear diff base but don't reset other counts because we may accumulate + // more value in the bucket. + if (mUseDiff && + (mCondition == ConditionState::kTrue && newCondition == ConditionState::kFalse)) { + resetBase(); } + + // Update condition state after pulling. + mCondition = newCondition; + + flushIfNeededLocked(eventTimeNs); + mConditionTimer.onConditionChanged(mCondition, eventTimeNs); } void ValueMetricProducer::pullAndMatchEventsLocked(const int64_t timestampNs, @@ -472,33 +465,33 @@ int64_t ValueMetricProducer::calcPreviousBucketEndTime(const int64_t currentTime void ValueMetricProducer::onDataPulled(const std::vector<std::shared_ptr<LogEvent>>& allData, bool pullSuccess, int64_t originalPullTimeNs) { std::lock_guard<std::mutex> lock(mMutex); - if (mCondition == ConditionState::kTrue) { - // If the pull failed, we won't be able to compute a diff. - if (!pullSuccess) { - invalidateCurrentBucket(); + if (mCondition == ConditionState::kTrue) { + // If the pull failed, we won't be able to compute a diff. + if (!pullSuccess) { + invalidateCurrentBucket(); + } else { + bool isEventLate = originalPullTimeNs < getCurrentBucketEndTimeNs(); + if (isEventLate) { + // If the event is late, we are in the middle of a bucket. Just + // process the data without trying to snap the data to the nearest bucket. + accumulateEvents(allData, originalPullTimeNs, originalPullTimeNs, mCondition); } else { - bool isEventLate = originalPullTimeNs < getCurrentBucketEndTimeNs(); - if (isEventLate) { - // If the event is late, we are in the middle of a bucket. Just - // process the data without trying to snap the data to the nearest bucket. - accumulateEvents(allData, originalPullTimeNs, originalPullTimeNs, mCondition); - } else { - // For scheduled pulled data, the effective event time is snap to the nearest - // bucket end. In the case of waking up from a deep sleep state, we will - // attribute to the previous bucket end. If the sleep was long but not very - // long, we will be in the immediate next bucket. Previous bucket may get a - // larger number as we pull at a later time than real bucket end. - // - // If the sleep was very long, we skip more than one bucket before sleep. In - // this case, if the diff base will be cleared and this new data will serve as - // new diff base. - int64_t bucketEndTime = calcPreviousBucketEndTime(originalPullTimeNs) - 1; - StatsdStats::getInstance().noteBucketBoundaryDelayNs( - mMetricId, originalPullTimeNs - bucketEndTime); - accumulateEvents(allData, originalPullTimeNs, bucketEndTime, mCondition); - } + // For scheduled pulled data, the effective event time is snap to the nearest + // bucket end. In the case of waking up from a deep sleep state, we will + // attribute to the previous bucket end. If the sleep was long but not very + // long, we will be in the immediate next bucket. Previous bucket may get a + // larger number as we pull at a later time than real bucket end. + // + // If the sleep was very long, we skip more than one bucket before sleep. In + // this case, if the diff base will be cleared and this new data will serve as + // new diff base. + int64_t bucketEndTime = calcPreviousBucketEndTime(originalPullTimeNs) - 1; + StatsdStats::getInstance().noteBucketBoundaryDelayNs( + mMetricId, originalPullTimeNs - bucketEndTime); + accumulateEvents(allData, originalPullTimeNs, bucketEndTime, mCondition); } } + } // We can probably flush the bucket. Since we used bucketEndTime when calling // #onMatchedLogEventInternalLocked, the current bucket will not have been flushed. @@ -579,10 +572,10 @@ void ValueMetricProducer::dumpStatesLocked(FILE* out, bool verbose) const { if (verbose) { for (const auto& it : mCurrentSlicedBucket) { for (const auto& interval : it.second) { - fprintf(out, "\t(what)%s\t(condition)%s (value)%s\n", - it.first.getDimensionKeyInWhat().toString().c_str(), - it.first.getDimensionKeyInCondition().toString().c_str(), - interval.value.toString().c_str()); + fprintf(out, "\t(what)%s\t(states)%s (value)%s\n", + it.first.getDimensionKeyInWhat().toString().c_str(), + it.first.getStateValuesKey().toString().c_str(), + interval.value.toString().c_str()); } } } @@ -821,7 +814,7 @@ void ValueMetricProducer::onMatchedLogEventInternalLocked(const size_t matcherIn void ValueMetricProducer::flushIfNeededLocked(const int64_t& eventTimeNs) { int64_t currentBucketEndTimeNs = getCurrentBucketEndTimeNs(); if (eventTimeNs < currentBucketEndTimeNs) { - VLOG("eventTime is %lld, less than next bucket start time %lld", (long long)eventTimeNs, + VLOG("eventTime is %lld, less than current bucket end time %lld", (long long)eventTimeNs, (long long)(currentBucketEndTimeNs)); return; } diff --git a/cmds/statsd/src/metrics/metrics_manager_util.cpp b/cmds/statsd/src/metrics/metrics_manager_util.cpp index 33e162ec2d24..6e767175caba 100644 --- a/cmds/statsd/src/metrics/metrics_manager_util.cpp +++ b/cmds/statsd/src/metrics/metrics_manager_util.cpp @@ -472,11 +472,13 @@ bool initMetrics(const ConfigKey& key, const StatsdConfig& config, const int64_t allStateGroupMaps, slicedStateAtoms, stateGroupMap)) { return false; } + } else { + if (metric.state_link_size() > 0) { + ALOGW("CountMetric has a MetricStateLink but doesn't have a slice_by_state"); + return false; + } } - // TODO(tsaichristine): add check for unequal number of MetricStateLinks - // and slice_by_states - unordered_map<int, shared_ptr<Activation>> eventActivationMap; unordered_map<int, vector<shared_ptr<Activation>>> eventDeactivationMap; bool success = handleMetricActivation(config, metric.id(), metricIndex, diff --git a/cmds/statsd/src/state/StateListener.h b/cmds/statsd/src/state/StateListener.h index a31690a102ed..f2b9a6b9b89f 100644 --- a/cmds/statsd/src/state/StateListener.h +++ b/cmds/statsd/src/state/StateListener.h @@ -43,8 +43,8 @@ public: * [oldState]: Previous state value before state change * [newState]: Current state value after state change */ - virtual void onStateChanged(int atomId, const HashableDimensionKey& primaryKey, int oldState, - int newState) = 0; + virtual void onStateChanged(int32_t atomId, const HashableDimensionKey& primaryKey, + int oldState, int newState) = 0; }; } // namespace statsd diff --git a/cmds/statsd/src/state/StateManager.cpp b/cmds/statsd/src/state/StateManager.cpp index 95b2c7691803..2fa28c9846fd 100644 --- a/cmds/statsd/src/state/StateManager.cpp +++ b/cmds/statsd/src/state/StateManager.cpp @@ -35,7 +35,7 @@ void StateManager::onLogEvent(const LogEvent& event) { } } -bool StateManager::registerListener(int atomId, wp<StateListener> listener) { +bool StateManager::registerListener(int32_t atomId, wp<StateListener> listener) { std::lock_guard<std::mutex> lock(mMutex); // Check if state tracker already exists @@ -53,7 +53,7 @@ bool StateManager::registerListener(int atomId, wp<StateListener> listener) { return true; } -void StateManager::unregisterListener(int atomId, wp<StateListener> listener) { +void StateManager::unregisterListener(int32_t atomId, wp<StateListener> listener) { std::unique_lock<std::mutex> lock(mMutex); // Hold the sp<> until the lock is released so that ~StateTracker() is @@ -77,13 +77,15 @@ void StateManager::unregisterListener(int atomId, wp<StateListener> listener) { lock.unlock(); } -int StateManager::getStateValue(int atomId, const HashableDimensionKey& key) { +bool StateManager::getStateValue(int32_t atomId, const HashableDimensionKey& key, + FieldValue* output) const { std::lock_guard<std::mutex> lock(mMutex); - if (mStateTrackers.find(atomId) != mStateTrackers.end()) { - return mStateTrackers[atomId]->getStateValue(key); - } - return StateTracker::kStateUnknown; + auto it = mStateTrackers.find(atomId); + if (it != mStateTrackers.end()) { + return it->second->getStateValue(key, output); + } + return false; } } // namespace statsd diff --git a/cmds/statsd/src/state/StateManager.h b/cmds/statsd/src/state/StateManager.h index 89ee6c04b922..272724ceeb08 100644 --- a/cmds/statsd/src/state/StateManager.h +++ b/cmds/statsd/src/state/StateManager.h @@ -42,26 +42,30 @@ public: // Returns true if atomId is being tracked and is associated with a state // atom. StateManager notifies the correct StateTracker to register listener. // If the correct StateTracker does not exist, a new StateTracker is created. - bool registerListener(int atomId, wp<StateListener> listener); + bool registerListener(int32_t atomId, wp<StateListener> listener); // Notifies the correct StateTracker to unregister a listener // and removes the tracker if it no longer has any listeners. - void unregisterListener(int atomId, wp<StateListener> listener); + void unregisterListener(int32_t atomId, wp<StateListener> listener); - // Queries the correct StateTracker for the original/un-mapped state value - // that is mapped to the given query key. - // If the StateTracker doesn't exist, returns StateTracker::kStateUnknown. - int getStateValue(int atomId, const HashableDimensionKey& queryKey); + // Returns true if the StateTracker exists and queries for the + // original state value mapped to the given query key. The state value is + // stored and output in a FieldValue class. + // Returns false if the StateTracker doesn't exist. + bool getStateValue(int32_t atomId, const HashableDimensionKey& queryKey, + FieldValue* output) const; - inline int getStateTrackersCount() { + inline int getStateTrackersCount() const { std::lock_guard<std::mutex> lock(mMutex); return mStateTrackers.size(); } - inline int getListenersCount(int atomId) { + inline int getListenersCount(int32_t atomId) const { std::lock_guard<std::mutex> lock(mMutex); - if (mStateTrackers.find(atomId) != mStateTrackers.end()) { - return mStateTrackers[atomId]->getListenersCount(); + + auto it = mStateTrackers.find(atomId); + if (it != mStateTrackers.end()) { + return it->second->getListenersCount(); } return -1; } @@ -70,7 +74,7 @@ private: mutable std::mutex mMutex; // Maps state atom ids to StateTrackers - std::unordered_map<int, sp<StateTracker>> mStateTrackers; + std::unordered_map<int32_t, sp<StateTracker>> mStateTrackers; }; } // namespace statsd diff --git a/cmds/statsd/src/state/StateTracker.cpp b/cmds/statsd/src/state/StateTracker.cpp index 323fc0e94ab2..e6f61226018e 100644 --- a/cmds/statsd/src/state/StateTracker.cpp +++ b/cmds/statsd/src/state/StateTracker.cpp @@ -25,10 +25,8 @@ namespace android { namespace os { namespace statsd { -StateTracker::StateTracker(const int atomId, - const util::StateAtomFieldOptions& stateAtomInfo) - : mAtomId(atomId), - mStateField(getSimpleMatcher(atomId, stateAtomInfo.exclusiveField)) { +StateTracker::StateTracker(const int32_t atomId, const util::StateAtomFieldOptions& stateAtomInfo) + : mAtomId(atomId), mStateField(getSimpleMatcher(atomId, stateAtomInfo.exclusiveField)) { // create matcher for each primary field // TODO(tsaichristine): b/142108433 handle when primary field is first uid in chain for (const auto& primary : stateAtomInfo.primaryFields) { @@ -55,24 +53,26 @@ void StateTracker::onLogEvent(const LogEvent& event) { } // parse event for state value - Value state; - int32_t stateValue; - if (!filterValues(mStateField, event.getValues(), &state) || state.getType() != INT) { - ALOGE("StateTracker error extracting state from log event. Type: %d", state.getType()); + FieldValue stateValue; + int32_t state; + if (!filterValues(mStateField, event.getValues(), &stateValue) || + stateValue.mValue.getType() != INT) { + ALOGE("StateTracker error extracting state from log event. Type: %d", + stateValue.mValue.getType()); handlePartialReset(primaryKey); return; } - stateValue = state.int_value; + state = stateValue.mValue.int_value; - if (stateValue == mResetState) { - VLOG("StateTracker Reset state: %s", state.toString().c_str()); + if (state == mResetState) { + VLOG("StateTracker Reset state: %s", stateValue.mValue.toString().c_str()); handleReset(); } // track and update state int32_t oldState = 0; int32_t newState = 0; - updateState(primaryKey, stateValue, &oldState, &newState); + updateState(primaryKey, state, &oldState, &newState); // notify all listeners if state has changed if (oldState != newState) { @@ -96,18 +96,27 @@ void StateTracker::unregisterListener(wp<StateListener> listener) { mListeners.erase(listener); } -int StateTracker::getStateValue(const HashableDimensionKey& queryKey) const { +bool StateTracker::getStateValue(const HashableDimensionKey& queryKey, FieldValue* output) const { + output->mField = mStateField.mMatcher; + + // Check that the query key has the correct number of primary fields. if (queryKey.getValues().size() == mPrimaryFields.size()) { auto it = mStateMap.find(queryKey); if (it != mStateMap.end()) { - return it->second.state; + output->mValue = it->second.state; + return true; } } else if (queryKey.getValues().size() > mPrimaryFields.size()) { ALOGE("StateTracker query key size > primary key size is illegal"); } else { ALOGE("StateTracker query key size < primary key size is not supported"); } - return mDefaultState; + + // Set the state value to unknown if: + // - query key size is incorrect + // - query key is not found in state map + output->mValue = StateTracker::kStateUnknown; + return false; } void StateTracker::handleReset() { diff --git a/cmds/statsd/src/state/StateTracker.h b/cmds/statsd/src/state/StateTracker.h index cfa9fd8f6272..450412d4ec3b 100644 --- a/cmds/statsd/src/state/StateTracker.h +++ b/cmds/statsd/src/state/StateTracker.h @@ -30,7 +30,7 @@ namespace statsd { class StateTracker : public virtual RefBase { public: - StateTracker(const int atomId, const util::StateAtomFieldOptions& stateAtomInfo); + StateTracker(const int32_t atomId, const util::StateAtomFieldOptions& stateAtomInfo); virtual ~StateTracker(){}; @@ -45,10 +45,12 @@ public: void unregisterListener(wp<StateListener> listener); - // Returns the state value mapped to the given query key. + // The output is a FieldValue object that has mStateField as the field and + // the original state value (found using the given query key) as the value. + // // If the key isn't mapped to a state or the key size doesn't match the - // primary key size, the default state is returned. - int getStateValue(const HashableDimensionKey& queryKey) const; + // number of primary fields, the output value is set to kStateUnknown. + bool getStateValue(const HashableDimensionKey& queryKey, FieldValue* output) const; inline int getListenersCount() const { return mListeners.size(); diff --git a/cmds/statsd/src/stats_log_util.cpp b/cmds/statsd/src/stats_log_util.cpp index c22e3cc07a3b..76c193679eef 100644 --- a/cmds/statsd/src/stats_log_util.cpp +++ b/cmds/statsd/src/stats_log_util.cpp @@ -53,6 +53,11 @@ const int DIMENSIONS_VALUE_VALUE_STR_HASH = 8; const int DIMENSIONS_VALUE_TUPLE_VALUE = 1; +// for StateValue Proto +const int STATE_VALUE_ATOM_ID = 1; +const int STATE_VALUE_CONTENTS_GROUP_ID = 2; +const int STATE_VALUE_CONTENTS_VALUE = 3; + // for PulledAtomStats proto const int FIELD_ID_PULLED_ATOM_STATS = 10; const int FIELD_ID_PULL_ATOM_ID = 1; @@ -416,6 +421,23 @@ void writeFieldValueTreeToStream(int tagId, const std::vector<FieldValue>& value protoOutput->end(atomToken); } +void writeStateToProto(const FieldValue& state, util::ProtoOutputStream* protoOutput) { + protoOutput->write(FIELD_TYPE_INT32 | STATE_VALUE_ATOM_ID, state.mField.getTag()); + + switch (state.mValue.getType()) { + case INT: + protoOutput->write(FIELD_TYPE_INT32 | STATE_VALUE_CONTENTS_VALUE, + state.mValue.int_value); + break; + case LONG: + protoOutput->write(FIELD_TYPE_INT64 | STATE_VALUE_CONTENTS_GROUP_ID, + state.mValue.long_value); + break; + default: + break; + } +} + int64_t TimeUnitToBucketSizeInMillisGuardrailed(int uid, TimeUnit unit) { int64_t bucketSizeMillis = TimeUnitToBucketSizeInMillis(unit); if (bucketSizeMillis > 1000 && bucketSizeMillis < 5 * 60 * 1000LL && uid != AID_SHELL && diff --git a/cmds/statsd/src/stats_log_util.h b/cmds/statsd/src/stats_log_util.h index bfb84cf4d1b9..0a86363a7090 100644 --- a/cmds/statsd/src/stats_log_util.h +++ b/cmds/statsd/src/stats_log_util.h @@ -40,6 +40,8 @@ void writeDimensionLeafNodesToProto(const HashableDimensionKey& dimension, void writeDimensionPathToProto(const std::vector<Matcher>& fieldMatchers, util::ProtoOutputStream* protoOutput); +void writeStateToProto(const FieldValue& state, util::ProtoOutputStream* protoOutput); + // Convert the TimeUnit enum to the bucket size in millis with a guardrail on // bucket size. int64_t TimeUnitToBucketSizeInMillisGuardrailed(int uid, TimeUnit unit); diff --git a/cmds/statsd/src/statsd_config.proto b/cmds/statsd/src/statsd_config.proto index 0664867aa866..a22805b6b525 100644 --- a/cmds/statsd/src/statsd_config.proto +++ b/cmds/statsd/src/statsd_config.proto @@ -178,7 +178,7 @@ message MetricConditionLink { } message MetricStateLink { - optional int64 state = 1; + optional int32 state_atom_id = 1; optional FieldMatcher fields_in_what = 2; diff --git a/cmds/statsd/src/subscriber/IncidentdReporter.cpp b/cmds/statsd/src/subscriber/IncidentdReporter.cpp index f2c6f1ad6759..f1320c2f746d 100644 --- a/cmds/statsd/src/subscriber/IncidentdReporter.cpp +++ b/cmds/statsd/src/subscriber/IncidentdReporter.cpp @@ -52,7 +52,6 @@ const int FIELD_ID_TRIGGER_DETAILS = 4; const int FIELD_ID_TRIGGER_DETAILS_TRIGGER_METRIC = 1; const int FIELD_ID_METRIC_VALUE_METRIC_ID = 1; const int FIELD_ID_METRIC_VALUE_DIMENSION_IN_WHAT = 2; -const int FIELD_ID_METRIC_VALUE_DIMENSION_IN_CONDITION = 3; const int FIELD_ID_METRIC_VALUE_VALUE = 4; const int FIELD_ID_PACKAGE_INFO = 3; @@ -84,10 +83,8 @@ void getProtoData(const int64_t& rule_id, int64_t metricId, const MetricDimensio writeDimensionToProto(dimensionKey.getDimensionKeyInWhat(), nullptr, &headerProto); headerProto.end(dimToken); + // deprecated field // optional DimensionsValue dimension_in_condition = 3; - dimToken = headerProto.start(FIELD_TYPE_MESSAGE | FIELD_ID_METRIC_VALUE_DIMENSION_IN_CONDITION); - writeDimensionToProto(dimensionKey.getDimensionKeyInCondition(), nullptr, &headerProto); - headerProto.end(dimToken); // optional int64 value = 4; headerProto.write(FIELD_TYPE_INT64 | FIELD_ID_METRIC_VALUE_VALUE, (long long)metricValue); @@ -106,13 +103,6 @@ void getProtoData(const int64_t& rule_id, int64_t metricId, const MetricDimensio } } - for (const auto& dim : dimensionKey.getDimensionKeyInCondition().getValues()) { - int uid = getUidIfExists(dim); - if (uid > 2000) { - uids.insert(uid); - } - } - if (!uids.empty()) { uint64_t token = headerProto.start(FIELD_TYPE_MESSAGE | FIELD_ID_PACKAGE_INFO); UidMap::getInstance()->writeUidMapSnapshot(getElapsedRealtimeNs(), true, true, uids, diff --git a/cmds/statsd/tests/e2e/CountMetric_e2e_test.cpp b/cmds/statsd/tests/e2e/CountMetric_e2e_test.cpp index 6591d69cdc1a..0f51c1b5a4ce 100644 --- a/cmds/statsd/tests/e2e/CountMetric_e2e_test.cpp +++ b/cmds/statsd/tests/e2e/CountMetric_e2e_test.cpp @@ -18,6 +18,7 @@ #include "src/StatsLogProcessor.h" #include "src/state/StateManager.h" +#include "src/state/StateTracker.h" #include "tests/statsd_test_util.h" namespace android { @@ -26,8 +27,20 @@ namespace statsd { #ifdef __ANDROID__ -TEST(CountMetricE2eTest, TestWithSimpleState) { - // Initialize config +const int SCREEN_STATE_ATOM_ID = android::util::SCREEN_STATE_CHANGED; +const int UID_PROCESS_STATE_ATOM_ID = android::util::UID_PROCESS_STATE_CHANGED; + +/** + * Test a count metric that has one slice_by_state with no primary fields. + * + * Once the CountMetricProducer is initialized, it has one atom id in + * mSlicedStateAtoms and no entries in mStateGroupMap. + + * One StateTracker tracks the state atom, and it has one listener which is the + * CountMetricProducer that was initialized. + */ +TEST(CountMetricE2eTest, TestSlicedState) { + // Initialize config. StatsdConfig config; config.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root. @@ -37,30 +50,22 @@ TEST(CountMetricE2eTest, TestWithSimpleState) { auto state = CreateScreenState(); *config.add_state() = state; - // Create count metric that slices by screen state + // Create count metric that slices by screen state. int64_t metricId = 123456; auto countMetric = config.add_count_metric(); countMetric->set_id(metricId); countMetric->set_what(syncStartMatcher.id()); - countMetric->set_bucket(TimeUnit::ONE_MINUTE); + countMetric->set_bucket(TimeUnit::FIVE_MINUTES); countMetric->add_slice_by_state(state.id()); - // Initialize StatsLogProcessor - const int64_t baseTimeNs = 0; // 0:00 - const int64_t configAddedTimeNs = baseTimeNs + 1 * NS_PER_SEC; // 0:01 - const int64_t bucketSizeNs = - TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000LL * 1000LL; - + // Initialize StatsLogProcessor. + const uint64_t bucketStartTimeNs = 10000000000; // 0:10 + const uint64_t bucketSizeNs = + TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000000LL; int uid = 12345; int64_t cfgId = 98765; ConfigKey cfgKey(uid, cfgId); - - auto processor = CreateStatsLogProcessor(baseTimeNs, configAddedTimeNs, config, cfgKey); - - // Check that StateTrackers were properly initialized. - EXPECT_EQ(1, StateManager::getInstance().getStateTrackersCount()); - EXPECT_EQ(1, - StateManager::getInstance().getListenersCount(android::util::SCREEN_STATE_CHANGED)); + auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey); // Check that CountMetricProducer was initialized correctly. EXPECT_EQ(processor->mMetricsManagers.size(), 1u); @@ -69,12 +74,118 @@ TEST(CountMetricE2eTest, TestWithSimpleState) { EXPECT_EQ(metricsManager->mAllMetricProducers.size(), 1); sp<MetricProducer> metricProducer = metricsManager->mAllMetricProducers[0]; EXPECT_EQ(metricProducer->mSlicedStateAtoms.size(), 1); - EXPECT_EQ(metricProducer->mSlicedStateAtoms.at(0), android::util::SCREEN_STATE_CHANGED); + EXPECT_EQ(metricProducer->mSlicedStateAtoms.at(0), SCREEN_STATE_ATOM_ID); EXPECT_EQ(metricProducer->mStateGroupMap.size(), 0); + + // Check that StateTrackers were initialized correctly. + EXPECT_EQ(1, StateManager::getInstance().getStateTrackersCount()); + EXPECT_EQ(1, StateManager::getInstance().getListenersCount(SCREEN_STATE_ATOM_ID)); + + /* + bucket #1 bucket #2 + | 1 2 3 4 5 6 7 8 9 10 (minutes) + |-----------------------------|-----------------------------|-- + x x x x x x (syncStartEvents) + | | (ScreenIsOnEvent) + | | (ScreenIsOffEvent) + | (ScreenUnknownEvent) + */ + // Initialize log events - first bucket. + int appUid = 123; + std::vector<AttributionNodeInternal> attributions1 = {CreateAttribution(appUid, "App1")}; + std::vector<std::unique_ptr<LogEvent>> events; + events.push_back( + CreateScreenStateChangedEvent(android::view::DisplayStateEnum::DISPLAY_STATE_ON, + bucketStartTimeNs + 50 * NS_PER_SEC)); // 1:00 + events.push_back(CreateSyncStartEvent(attributions1, "sync_name", + bucketStartTimeNs + 75 * NS_PER_SEC)); // 1:25 + events.push_back( + CreateScreenStateChangedEvent(android::view::DisplayStateEnum::DISPLAY_STATE_OFF, + bucketStartTimeNs + 150 * NS_PER_SEC)); // 2:40 + events.push_back( + CreateScreenStateChangedEvent(android::view::DisplayStateEnum::DISPLAY_STATE_OFF, + bucketStartTimeNs + 200 * NS_PER_SEC)); // 3:30 + events.push_back(CreateSyncStartEvent(attributions1, "sync_name", + bucketStartTimeNs + 250 * NS_PER_SEC)); // 4:20 + + // Initialize log events - second bucket. + events.push_back(CreateSyncStartEvent(attributions1, "sync_name", + bucketStartTimeNs + 350 * NS_PER_SEC)); // 6:00 + events.push_back(CreateSyncStartEvent(attributions1, "sync_name", + bucketStartTimeNs + 400 * NS_PER_SEC)); // 6:50 + events.push_back( + CreateScreenStateChangedEvent(android::view::DisplayStateEnum::DISPLAY_STATE_ON, + bucketStartTimeNs + 450 * NS_PER_SEC)); // 7:40 + events.push_back(CreateSyncStartEvent(attributions1, "sync_name", + bucketStartTimeNs + 475 * NS_PER_SEC)); // 8:05 + events.push_back( + CreateScreenStateChangedEvent(android::view::DisplayStateEnum::DISPLAY_STATE_UNKNOWN, + bucketStartTimeNs + 500 * NS_PER_SEC)); // 8:30 + events.push_back(CreateSyncStartEvent(attributions1, "sync_name", + bucketStartTimeNs + 520 * NS_PER_SEC)); // 8:50 + + // Send log events to StatsLogProcessor. + for (auto& event : events) { + processor->OnLogEvent(event.get()); + } + + // Check dump report. + vector<uint8_t> buffer; + ConfigMetricsReportList reports; + processor->onDumpReport(cfgKey, bucketStartTimeNs + bucketSizeNs * 2 + 1, false, true, ADB_DUMP, + FAST, &buffer); + EXPECT_GT(buffer.size(), 0); + EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size())); + backfillDimensionPath(&reports); + backfillStringInReport(&reports); + backfillStartEndTimestamp(&reports); + + EXPECT_EQ(1, reports.reports_size()); + EXPECT_EQ(1, reports.reports(0).metrics_size()); + EXPECT_TRUE(reports.reports(0).metrics(0).has_count_metrics()); + EXPECT_EQ(3, reports.reports(0).metrics(0).count_metrics().data_size()); + + // For each CountMetricData, check StateValue info is correct and buckets + // have correct counts. + auto data = reports.reports(0).metrics(0).count_metrics().data(0); + EXPECT_EQ(1, data.slice_by_state_size()); + EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id()); + EXPECT_TRUE(data.slice_by_state(0).has_value()); + EXPECT_EQ(android::view::DisplayStateEnum::DISPLAY_STATE_ON, data.slice_by_state(0).value()); + EXPECT_EQ(2, data.bucket_info_size()); + EXPECT_EQ(1, data.bucket_info(0).count()); + EXPECT_EQ(1, data.bucket_info(1).count()); + + data = reports.reports(0).metrics(0).count_metrics().data(1); + EXPECT_EQ(1, data.slice_by_state_size()); + EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id()); + EXPECT_TRUE(data.slice_by_state(0).has_value()); + EXPECT_EQ(android::view::DisplayStateEnum::DISPLAY_STATE_UNKNOWN, data.slice_by_state(0).value()); + EXPECT_EQ(1, data.bucket_info_size()); + EXPECT_EQ(1, data.bucket_info(0).count()); + + data = reports.reports(0).metrics(0).count_metrics().data(2); + EXPECT_EQ(1, data.slice_by_state_size()); + EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id()); + EXPECT_TRUE(data.slice_by_state(0).has_value()); + EXPECT_EQ(android::view::DisplayStateEnum::DISPLAY_STATE_OFF, data.slice_by_state(0).value()); + EXPECT_EQ(2, data.bucket_info_size()); + EXPECT_EQ(1, data.bucket_info(0).count()); + EXPECT_EQ(2, data.bucket_info(1).count()); } -TEST(CountMetricE2eTest, TestWithMappedState) { - // Initialize config +/** + * Test a count metric that has one slice_by_state with a mapping and no + * primary fields. + * + * Once the CountMetricProducer is initialized, it has one atom id in + * mSlicedStateAtoms and has one entry per state value in mStateGroupMap. + * + * One StateTracker tracks the state atom, and it has one listener which is the + * CountMetricProducer that was initialized. + */ +TEST(CountMetricE2eTest, TestSlicedStateWithMap) { + // Initialize config. StatsdConfig config; config.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root. @@ -84,30 +195,26 @@ TEST(CountMetricE2eTest, TestWithMappedState) { auto state = CreateScreenStateWithOnOffMap(); *config.add_state() = state; - // Create count metric that slices by screen state with on/off map + // Create count metric that slices by screen state with on/off map. int64_t metricId = 123456; auto countMetric = config.add_count_metric(); countMetric->set_id(metricId); countMetric->set_what(syncStartMatcher.id()); - countMetric->set_bucket(TimeUnit::ONE_MINUTE); + countMetric->set_bucket(TimeUnit::FIVE_MINUTES); countMetric->add_slice_by_state(state.id()); - // Initialize StatsLogProcessor - const int64_t baseTimeNs = 0; // 0:00 - const int64_t configAddedTimeNs = baseTimeNs + 1 * NS_PER_SEC; // 0:01 - const int64_t bucketSizeNs = - TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000LL * 1000LL; - + // Initialize StatsLogProcessor. + const uint64_t bucketStartTimeNs = 10000000000; // 0:10 + const uint64_t bucketSizeNs = + TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000000LL; int uid = 12345; int64_t cfgId = 98765; ConfigKey cfgKey(uid, cfgId); + auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey); - auto processor = CreateStatsLogProcessor(baseTimeNs, configAddedTimeNs, config, cfgKey); - - // Check that StateTrackers were properly initialized. + // Check that StateTrackers were initialized correctly. EXPECT_EQ(1, StateManager::getInstance().getStateTrackersCount()); - EXPECT_EQ(1, - StateManager::getInstance().getListenersCount(android::util::SCREEN_STATE_CHANGED)); + EXPECT_EQ(1, StateManager::getInstance().getListenersCount(SCREEN_STATE_ATOM_ID)); // Check that CountMetricProducer was initialized correctly. EXPECT_EQ(processor->mMetricsManagers.size(), 1u); @@ -116,58 +223,371 @@ TEST(CountMetricE2eTest, TestWithMappedState) { EXPECT_EQ(metricsManager->mAllMetricProducers.size(), 1); sp<MetricProducer> metricProducer = metricsManager->mAllMetricProducers[0]; EXPECT_EQ(metricProducer->mSlicedStateAtoms.size(), 1); - EXPECT_EQ(metricProducer->mSlicedStateAtoms.at(0), android::util::SCREEN_STATE_CHANGED); + EXPECT_EQ(metricProducer->mSlicedStateAtoms.at(0), SCREEN_STATE_ATOM_ID); EXPECT_EQ(metricProducer->mStateGroupMap.size(), 1); StateMap map = state.map(); for (auto group : map.group()) { for (auto value : group.value()) { - EXPECT_EQ(metricProducer->mStateGroupMap[android::util::SCREEN_STATE_CHANGED][value], + EXPECT_EQ(metricProducer->mStateGroupMap[SCREEN_STATE_ATOM_ID][value], group.group_id()); } } + + /* + bucket #1 bucket #2 + | 1 2 3 4 5 6 7 8 9 10 (minutes) + |-----------------------------|-----------------------------|-- + x x x x x x x x x (syncStartEvents) + -----------------------------------------------------------SCREEN_OFF events + | (ScreenStateUnknownEvent = 0) + | | (ScreenStateOffEvent = 1) + | (ScreenStateDozeEvent = 3) + | (ScreenStateDozeSuspendEvent = 4) + -----------------------------------------------------------SCREEN_ON events + | | (ScreenStateOnEvent = 2) + | (ScreenStateVrEvent = 5) + | (ScreenStateOnSuspendEvent = 6) + */ + // Initialize log events - first bucket. + int appUid = 123; + std::vector<AttributionNodeInternal> attributions1 = {CreateAttribution(appUid, "App1")}; + + std::vector<std::unique_ptr<LogEvent>> events; + events.push_back(CreateSyncStartEvent(attributions1, "sync_name", + bucketStartTimeNs + 20 * NS_PER_SEC)); // 0:30 + events.push_back( + CreateScreenStateChangedEvent(android::view::DisplayStateEnum::DISPLAY_STATE_UNKNOWN, + bucketStartTimeNs + 30 * NS_PER_SEC)); // 0:40 + events.push_back(CreateSyncStartEvent(attributions1, "sync_name", + bucketStartTimeNs + 60 * NS_PER_SEC)); // 1:10 + events.push_back( + CreateScreenStateChangedEvent(android::view::DisplayStateEnum::DISPLAY_STATE_OFF, + bucketStartTimeNs + 90 * NS_PER_SEC)); // 1:40 + events.push_back(CreateSyncStartEvent(attributions1, "sync_name", + bucketStartTimeNs + 120 * NS_PER_SEC)); // 2:10 + events.push_back( + CreateScreenStateChangedEvent(android::view::DisplayStateEnum::DISPLAY_STATE_ON, + bucketStartTimeNs + 150 * NS_PER_SEC)); // 2:40 + events.push_back( + CreateScreenStateChangedEvent(android::view::DisplayStateEnum::DISPLAY_STATE_VR, + bucketStartTimeNs + 180 * NS_PER_SEC)); // 3:10 + events.push_back(CreateSyncStartEvent(attributions1, "sync_name", + bucketStartTimeNs + 200 * NS_PER_SEC)); // 3:30 + events.push_back( + CreateScreenStateChangedEvent(android::view::DisplayStateEnum::DISPLAY_STATE_DOZE, + bucketStartTimeNs + 210 * NS_PER_SEC)); // 3:40 + events.push_back(CreateSyncStartEvent(attributions1, "sync_name", + bucketStartTimeNs + 250 * NS_PER_SEC)); // 4:20 + events.push_back( + CreateScreenStateChangedEvent(android::view::DisplayStateEnum::DISPLAY_STATE_OFF, + bucketStartTimeNs + 280 * NS_PER_SEC)); // 4:50 + events.push_back(CreateSyncStartEvent(attributions1, "sync_name", + bucketStartTimeNs + 285 * NS_PER_SEC)); // 4:55 + + // Initialize log events - second bucket. + events.push_back(CreateSyncStartEvent(attributions1, "sync_name", + bucketStartTimeNs + 360 * NS_PER_SEC)); // 6:10 + events.push_back( + CreateScreenStateChangedEvent(android::view::DisplayStateEnum::DISPLAY_STATE_ON_SUSPEND, + bucketStartTimeNs + 390 * NS_PER_SEC)); // 6:40 + events.push_back(CreateScreenStateChangedEvent( + android::view::DisplayStateEnum::DISPLAY_STATE_DOZE_SUSPEND, + bucketStartTimeNs + 430 * NS_PER_SEC)); // 7:20 + events.push_back(CreateSyncStartEvent(attributions1, "sync_name", + bucketStartTimeNs + 440 * NS_PER_SEC)); // 7:30 + events.push_back( + CreateScreenStateChangedEvent(android::view::DisplayStateEnum::DISPLAY_STATE_ON, + bucketStartTimeNs + 540 * NS_PER_SEC)); // 9:10 + events.push_back(CreateSyncStartEvent(attributions1, "sync_name", + bucketStartTimeNs + 570 * NS_PER_SEC)); // 9:40 + + // Send log events to StatsLogProcessor. + for (auto& event : events) { + processor->OnLogEvent(event.get()); + } + + // Check dump report. + vector<uint8_t> buffer; + ConfigMetricsReportList reports; + processor->onDumpReport(cfgKey, bucketStartTimeNs + bucketSizeNs * 2 + 1, false, true, ADB_DUMP, + FAST, &buffer); + EXPECT_GT(buffer.size(), 0); + EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size())); + backfillDimensionPath(&reports); + backfillStringInReport(&reports); + backfillStartEndTimestamp(&reports); + + EXPECT_EQ(1, reports.reports_size()); + EXPECT_EQ(1, reports.reports(0).metrics_size()); + EXPECT_TRUE(reports.reports(0).metrics(0).has_count_metrics()); + EXPECT_EQ(3, reports.reports(0).metrics(0).count_metrics().data_size()); + + // For each CountMetricData, check StateValue info is correct and buckets + // have correct counts. + auto data = reports.reports(0).metrics(0).count_metrics().data(0); + EXPECT_EQ(1, data.slice_by_state_size()); + EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id()); + EXPECT_TRUE(data.slice_by_state(0).has_value()); + EXPECT_EQ(-1 /* StateTracker::kStateUnknown */, data.slice_by_state(0).value()); + EXPECT_EQ(1, data.bucket_info_size()); + EXPECT_EQ(1, data.bucket_info(0).count()); + + data = reports.reports(0).metrics(0).count_metrics().data(1); + EXPECT_EQ(1, data.slice_by_state_size()); + EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id()); + EXPECT_TRUE(data.slice_by_state(0).has_group_id()); + EXPECT_EQ(StringToId("SCREEN_OFF"), data.slice_by_state(0).group_id()); + EXPECT_EQ(2, data.bucket_info_size()); + EXPECT_EQ(4, data.bucket_info(0).count()); + EXPECT_EQ(2, data.bucket_info(1).count()); + + data = reports.reports(0).metrics(0).count_metrics().data(2); + EXPECT_EQ(1, data.slice_by_state_size()); + EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id()); + EXPECT_TRUE(data.slice_by_state(0).has_group_id()); + EXPECT_EQ(StringToId("SCREEN_ON"), data.slice_by_state(0).group_id()); + EXPECT_EQ(2, data.bucket_info_size()); + EXPECT_EQ(1, data.bucket_info(0).count()); + EXPECT_EQ(1, data.bucket_info(1).count()); } -TEST(CountMetricE2eTest, TestWithMultipleStates) { - // Initialize config +/** + * Test a count metric that has one slice_by_state with a primary field. + + * Once the CountMetricProducer is initialized, it should have one + * MetricStateLink stored. State querying using a non-empty primary key + * should also work as intended. + */ +TEST(CountMetricE2eTest, TestSlicedStateWithPrimaryFields) { + // Initialize config. StatsdConfig config; config.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root. - auto syncStartMatcher = CreateSyncStartAtomMatcher(); - *config.add_atom_matcher() = syncStartMatcher; + auto appCrashMatcher = + CreateSimpleAtomMatcher("APP_CRASH_OCCURRED", android::util::APP_CRASH_OCCURRED); + *config.add_atom_matcher() = appCrashMatcher; + + auto state = CreateUidProcessState(); + *config.add_state() = state; + + // Create count metric that slices by uid process state. + int64_t metricId = 123456; + auto countMetric = config.add_count_metric(); + countMetric->set_id(metricId); + countMetric->set_what(appCrashMatcher.id()); + countMetric->set_bucket(TimeUnit::FIVE_MINUTES); + countMetric->add_slice_by_state(state.id()); + MetricStateLink* stateLink = countMetric->add_state_link(); + stateLink->set_state_atom_id(UID_PROCESS_STATE_ATOM_ID); + auto fieldsInWhat = stateLink->mutable_fields_in_what(); + *fieldsInWhat = CreateDimensions(android::util::APP_CRASH_OCCURRED, {1 /* uid */}); + auto fieldsInState = stateLink->mutable_fields_in_state(); + *fieldsInState = CreateDimensions(UID_PROCESS_STATE_ATOM_ID, {1 /* uid */}); + + // Initialize StatsLogProcessor. + const uint64_t bucketStartTimeNs = 10000000000; // 0:10 + const uint64_t bucketSizeNs = + TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000000LL; + int uid = 12345; + int64_t cfgId = 98765; + ConfigKey cfgKey(uid, cfgId); + auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey); + + // Check that StateTrackers were initialized correctly. + EXPECT_EQ(1, StateManager::getInstance().getStateTrackersCount()); + EXPECT_EQ(1, StateManager::getInstance().getListenersCount(UID_PROCESS_STATE_ATOM_ID)); + + // Check that CountMetricProducer was initialized correctly. + EXPECT_EQ(processor->mMetricsManagers.size(), 1u); + sp<MetricsManager> metricsManager = processor->mMetricsManagers.begin()->second; + EXPECT_TRUE(metricsManager->isConfigValid()); + EXPECT_EQ(metricsManager->mAllMetricProducers.size(), 1); + sp<MetricProducer> metricProducer = metricsManager->mAllMetricProducers[0]; + EXPECT_EQ(metricProducer->mSlicedStateAtoms.size(), 1); + EXPECT_EQ(metricProducer->mSlicedStateAtoms.at(0), UID_PROCESS_STATE_ATOM_ID); + EXPECT_EQ(metricProducer->mStateGroupMap.size(), 0); + EXPECT_EQ(metricProducer->mMetric2StateLinks.size(), 1); + + /* + NOTE: "1" or "2" represents the uid associated with the state/app crash event + bucket #1 bucket #2 + | 1 2 3 4 5 6 7 8 9 10 + |-----------------------------|-----------------------------|-- + 1 1 1 1 1 2 1 1 2 (AppCrashEvents) + -----------------------------------------------------------PROCESS STATE events + 1 2 (ProcessStateTopEvent = 1002) + 1 1 (ProcessStateForegroundServiceEvent = 1003) + 2 (ProcessStateImportantBackgroundEvent = 1006) + 1 1 1 (ProcessStateImportantForegroundEvent = 1005) + + Based on the diagram above, an AppCrashEvent querying for process state value would return: + - StateTracker::kStateUnknown + - Important foreground + - Top + - Important foreground + - Foreground service + - Top (both the app crash and state still have matching uid = 2) + + - Foreground service + - Foreground service + - Important background + */ + // Initialize log events - first bucket. + std::vector<std::unique_ptr<LogEvent>> events; + events.push_back( + CreateAppCrashOccurredEvent(1 /* uid */, bucketStartTimeNs + 20 * NS_PER_SEC)); // 0:30 + events.push_back(CreateUidProcessStateChangedEvent( + 1 /* uid */, android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_FOREGROUND, + bucketStartTimeNs + 30 * NS_PER_SEC)); // 0:40 + events.push_back( + CreateAppCrashOccurredEvent(1 /* uid */, bucketStartTimeNs + 60 * NS_PER_SEC)); // 1:10 + events.push_back(CreateUidProcessStateChangedEvent( + 1 /* uid */, android::app::ProcessStateEnum::PROCESS_STATE_TOP, + bucketStartTimeNs + 90 * NS_PER_SEC)); // 1:40 + events.push_back(CreateAppCrashOccurredEvent(1 /* uid */, + bucketStartTimeNs + 120 * NS_PER_SEC)); // 2:10 + events.push_back(CreateUidProcessStateChangedEvent( + 1 /* uid */, android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_FOREGROUND, + bucketStartTimeNs + 150 * NS_PER_SEC)); // 2:40 + events.push_back(CreateAppCrashOccurredEvent(1 /* uid */, + bucketStartTimeNs + 200 * NS_PER_SEC)); // 3:30 + events.push_back(CreateUidProcessStateChangedEvent( + 1 /* uid */, android::app::ProcessStateEnum::PROCESS_STATE_FOREGROUND_SERVICE, + bucketStartTimeNs + 210 * NS_PER_SEC)); // 3:40 + events.push_back(CreateAppCrashOccurredEvent(1 /* uid */, + bucketStartTimeNs + 250 * NS_PER_SEC)); // 4:20 + events.push_back(CreateUidProcessStateChangedEvent( + 2 /* uid */, android::app::ProcessStateEnum::PROCESS_STATE_TOP, + bucketStartTimeNs + 280 * NS_PER_SEC)); // 4:50 + events.push_back(CreateAppCrashOccurredEvent(2 /* uid */, + bucketStartTimeNs + 285 * NS_PER_SEC)); // 4:55 + + // Initialize log events - second bucket. + events.push_back(CreateAppCrashOccurredEvent(1 /* uid */, + bucketStartTimeNs + 360 * NS_PER_SEC)); // 6:10 + events.push_back(CreateUidProcessStateChangedEvent( + 1 /* uid */, android::app::ProcessStateEnum::PROCESS_STATE_FOREGROUND_SERVICE, + bucketStartTimeNs + 390 * NS_PER_SEC)); // 6:40 + events.push_back(CreateUidProcessStateChangedEvent( + 2 /* uid */, android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_BACKGROUND, + bucketStartTimeNs + 430 * NS_PER_SEC)); // 7:20 + events.push_back(CreateAppCrashOccurredEvent(1 /* uid */, + bucketStartTimeNs + 440 * NS_PER_SEC)); // 7:30 + events.push_back(CreateUidProcessStateChangedEvent( + 1 /* uid */, android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_FOREGROUND, + bucketStartTimeNs + 540 * NS_PER_SEC)); // 9:10 + events.push_back(CreateAppCrashOccurredEvent(2 /* uid */, + bucketStartTimeNs + 570 * NS_PER_SEC)); // 9:40 + + // Send log events to StatsLogProcessor. + for (auto& event : events) { + processor->OnLogEvent(event.get()); + } + + // Check dump report. + vector<uint8_t> buffer; + ConfigMetricsReportList reports; + processor->onDumpReport(cfgKey, bucketStartTimeNs + bucketSizeNs * 2 + 1, false, true, ADB_DUMP, + FAST, &buffer); + EXPECT_GT(buffer.size(), 0); + EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size())); + backfillDimensionPath(&reports); + backfillStringInReport(&reports); + backfillStartEndTimestamp(&reports); + + EXPECT_EQ(1, reports.reports_size()); + EXPECT_EQ(1, reports.reports(0).metrics_size()); + EXPECT_TRUE(reports.reports(0).metrics(0).has_count_metrics()); + EXPECT_EQ(5, reports.reports(0).metrics(0).count_metrics().data_size()); + + // For each CountMetricData, check StateValue info is correct and buckets + // have correct counts. + auto data = reports.reports(0).metrics(0).count_metrics().data(0); + EXPECT_EQ(1, data.slice_by_state_size()); + EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(0).atom_id()); + EXPECT_TRUE(data.slice_by_state(0).has_value()); + EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_BACKGROUND, data.slice_by_state(0).value()); + EXPECT_EQ(1, data.bucket_info_size()); + EXPECT_EQ(1, data.bucket_info(0).count()); + + data = reports.reports(0).metrics(0).count_metrics().data(1); + EXPECT_EQ(1, data.slice_by_state_size()); + EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(0).atom_id()); + EXPECT_TRUE(data.slice_by_state(0).has_value()); + EXPECT_EQ(-1 /* StateTracker::kStateUnknown */, data.slice_by_state(0).value()); + EXPECT_EQ(1, data.bucket_info_size()); + EXPECT_EQ(1, data.bucket_info(0).count()); + + data = reports.reports(0).metrics(0).count_metrics().data(2); + EXPECT_EQ(1, data.slice_by_state_size()); + EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(0).atom_id()); + EXPECT_TRUE(data.slice_by_state(0).has_value()); + EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_FOREGROUND, data.slice_by_state(0).value()); + EXPECT_EQ(1, data.bucket_info_size()); + EXPECT_EQ(2, data.bucket_info(0).count()); + + data = reports.reports(0).metrics(0).count_metrics().data(3); + EXPECT_EQ(1, data.slice_by_state_size()); + EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(0).atom_id()); + EXPECT_TRUE(data.slice_by_state(0).has_value()); + EXPECT_EQ(android::app::PROCESS_STATE_TOP, data.slice_by_state(0).value()); + EXPECT_EQ(1, data.bucket_info_size()); + EXPECT_EQ(2, data.bucket_info(0).count()); + + data = reports.reports(0).metrics(0).count_metrics().data(4); + EXPECT_EQ(1, data.slice_by_state_size()); + EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(0).atom_id()); + EXPECT_TRUE(data.slice_by_state(0).has_value()); + EXPECT_EQ(android::app::PROCESS_STATE_FOREGROUND_SERVICE, data.slice_by_state(0).value()); + EXPECT_EQ(2, data.bucket_info_size()); + EXPECT_EQ(1, data.bucket_info(0).count()); + EXPECT_EQ(2, data.bucket_info(1).count()); +} + +TEST(CountMetricE2eTest, TestMultipleSlicedStates) { + // Initialize config. + StatsdConfig config; + config.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root. + + auto appCrashMatcher = + CreateSimpleAtomMatcher("APP_CRASH_OCCURRED", android::util::APP_CRASH_OCCURRED); + *config.add_atom_matcher() = appCrashMatcher; auto state1 = CreateScreenStateWithOnOffMap(); *config.add_state() = state1; auto state2 = CreateUidProcessState(); *config.add_state() = state2; - // Create count metric that slices by screen state with on/off map + // Create count metric that slices by screen state with on/off map and + // slices by uid process state. int64_t metricId = 123456; auto countMetric = config.add_count_metric(); countMetric->set_id(metricId); - countMetric->set_what(syncStartMatcher.id()); - countMetric->set_bucket(TimeUnit::ONE_MINUTE); + countMetric->set_what(appCrashMatcher.id()); + countMetric->set_bucket(TimeUnit::FIVE_MINUTES); countMetric->add_slice_by_state(state1.id()); countMetric->add_slice_by_state(state2.id()); - - // Initialize StatsLogProcessor - const int64_t baseTimeNs = 0; // 0:00 - const int64_t configAddedTimeNs = baseTimeNs + 1 * NS_PER_SEC; // 0:01 - const int64_t bucketSizeNs = - TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000LL * 1000LL; - + MetricStateLink* stateLink = countMetric->add_state_link(); + stateLink->set_state_atom_id(UID_PROCESS_STATE_ATOM_ID); + auto fieldsInWhat = stateLink->mutable_fields_in_what(); + *fieldsInWhat = CreateDimensions(android::util::APP_CRASH_OCCURRED, {1 /* uid */}); + auto fieldsInState = stateLink->mutable_fields_in_state(); + *fieldsInState = CreateDimensions(UID_PROCESS_STATE_ATOM_ID, {1 /* uid */}); + + // Initialize StatsLogProcessor. + const uint64_t bucketStartTimeNs = 10000000000; // 0:10 + const uint64_t bucketSizeNs = + TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000000LL; int uid = 12345; int64_t cfgId = 98765; ConfigKey cfgKey(uid, cfgId); - - auto processor = CreateStatsLogProcessor(baseTimeNs, configAddedTimeNs, config, cfgKey); + auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey); // Check that StateTrackers were properly initialized. EXPECT_EQ(2, StateManager::getInstance().getStateTrackersCount()); - EXPECT_EQ(1, - StateManager::getInstance().getListenersCount(android::util::SCREEN_STATE_CHANGED)); - EXPECT_EQ(1, StateManager::getInstance().getListenersCount( - android::util::UID_PROCESS_STATE_CHANGED)); + EXPECT_EQ(1, StateManager::getInstance().getListenersCount(SCREEN_STATE_ATOM_ID)); + EXPECT_EQ(1, StateManager::getInstance().getListenersCount(UID_PROCESS_STATE_ATOM_ID)); // Check that CountMetricProducer was initialized correctly. EXPECT_EQ(processor->mMetricsManagers.size(), 1u); @@ -176,17 +596,205 @@ TEST(CountMetricE2eTest, TestWithMultipleStates) { EXPECT_EQ(metricsManager->mAllMetricProducers.size(), 1); sp<MetricProducer> metricProducer = metricsManager->mAllMetricProducers[0]; EXPECT_EQ(metricProducer->mSlicedStateAtoms.size(), 2); - EXPECT_EQ(metricProducer->mSlicedStateAtoms.at(0), android::util::SCREEN_STATE_CHANGED); - EXPECT_EQ(metricProducer->mSlicedStateAtoms.at(1), android::util::UID_PROCESS_STATE_CHANGED); + EXPECT_EQ(metricProducer->mSlicedStateAtoms.at(0), SCREEN_STATE_ATOM_ID); + EXPECT_EQ(metricProducer->mSlicedStateAtoms.at(1), UID_PROCESS_STATE_ATOM_ID); EXPECT_EQ(metricProducer->mStateGroupMap.size(), 1); + EXPECT_EQ(metricProducer->mMetric2StateLinks.size(), 1); StateMap map = state1.map(); for (auto group : map.group()) { for (auto value : group.value()) { - EXPECT_EQ(metricProducer->mStateGroupMap[android::util::SCREEN_STATE_CHANGED][value], + EXPECT_EQ(metricProducer->mStateGroupMap[SCREEN_STATE_ATOM_ID][value], group.group_id()); } } + + /* + bucket #1 bucket #2 + | 1 2 3 4 5 6 7 8 9 10 (minutes) + |-----------------------------|-----------------------------|-- + 1 1 1 1 1 2 1 1 2 (AppCrashEvents) + -----------------------------------------------------------SCREEN_OFF events + | (ScreenStateUnknownEvent = 0) + | | (ScreenStateOffEvent = 1) + | (ScreenStateDozeEvent = 3) + -----------------------------------------------------------SCREEN_ON events + | | (ScreenStateOnEvent = 2) + | (ScreenStateOnSuspendEvent = 6) + -----------------------------------------------------------PROCESS STATE events + 1 2 (ProcessStateTopEvent = 1002) + 1 (ProcessStateForegroundServiceEvent = 1003) + 2 (ProcessStateImportantBackgroundEvent = 1006) + 1 1 1 (ProcessStateImportantForegroundEvent = 1005) + + Based on the diagram above, Screen State / Process State pairs for each + AppCrashEvent are: + - StateTracker::kStateUnknown / important foreground + - off / important foreground + - off / Top + - on / important foreground + - off / important foreground + - off / top + + - off / important foreground + - off / foreground service + - on / important background + + */ + // Initialize log events - first bucket. + std::vector<std::unique_ptr<LogEvent>> events; + events.push_back(CreateUidProcessStateChangedEvent( + 1 /* uid */, android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_FOREGROUND, + bucketStartTimeNs + 5 * NS_PER_SEC)); // 0:15 + events.push_back( + CreateAppCrashOccurredEvent(1 /* uid */, bucketStartTimeNs + 20 * NS_PER_SEC)); // 0:30 + events.push_back( + CreateScreenStateChangedEvent(android::view::DisplayStateEnum::DISPLAY_STATE_UNKNOWN, + bucketStartTimeNs + 30 * NS_PER_SEC)); // 0:40 + events.push_back( + CreateAppCrashOccurredEvent(1 /* uid */, bucketStartTimeNs + 60 * NS_PER_SEC)); // 1:10 + events.push_back(CreateUidProcessStateChangedEvent( + 1 /* uid */, android::app::ProcessStateEnum::PROCESS_STATE_TOP, + bucketStartTimeNs + 90 * NS_PER_SEC)); // 1:40 + events.push_back( + CreateScreenStateChangedEvent(android::view::DisplayStateEnum::DISPLAY_STATE_OFF, + bucketStartTimeNs + 90 * NS_PER_SEC)); // 1:40 + events.push_back(CreateAppCrashOccurredEvent(1 /* uid */, + bucketStartTimeNs + 120 * NS_PER_SEC)); // 2:10 + events.push_back(CreateUidProcessStateChangedEvent( + 1 /* uid */, android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_FOREGROUND, + bucketStartTimeNs + 150 * NS_PER_SEC)); // 2:40 + events.push_back( + CreateScreenStateChangedEvent(android::view::DisplayStateEnum::DISPLAY_STATE_ON, + bucketStartTimeNs + 160 * NS_PER_SEC)); // 2:50 + events.push_back(CreateAppCrashOccurredEvent(1 /* uid */, + bucketStartTimeNs + 200 * NS_PER_SEC)); // 3:30 + events.push_back( + CreateScreenStateChangedEvent(android::view::DisplayStateEnum::DISPLAY_STATE_DOZE, + bucketStartTimeNs + 210 * NS_PER_SEC)); // 3:40 + events.push_back(CreateAppCrashOccurredEvent(1 /* uid */, + bucketStartTimeNs + 250 * NS_PER_SEC)); // 4:20 + events.push_back(CreateUidProcessStateChangedEvent( + 2 /* uid */, android::app::ProcessStateEnum::PROCESS_STATE_TOP, + bucketStartTimeNs + 280 * NS_PER_SEC)); // 4:50 + events.push_back(CreateAppCrashOccurredEvent(2 /* uid */, + bucketStartTimeNs + 285 * NS_PER_SEC)); // 4:55 + + // Initialize log events - second bucket. + events.push_back(CreateAppCrashOccurredEvent(1 /* uid */, + bucketStartTimeNs + 360 * NS_PER_SEC)); // 6:10 + events.push_back(CreateUidProcessStateChangedEvent( + 1 /* uid */, android::app::ProcessStateEnum::PROCESS_STATE_FOREGROUND_SERVICE, + bucketStartTimeNs + 380 * NS_PER_SEC)); // 6:30 + events.push_back( + CreateScreenStateChangedEvent(android::view::DisplayStateEnum::DISPLAY_STATE_ON_SUSPEND, + bucketStartTimeNs + 390 * NS_PER_SEC)); // 6:40 + events.push_back(CreateUidProcessStateChangedEvent( + 2 /* uid */, android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_BACKGROUND, + bucketStartTimeNs + 420 * NS_PER_SEC)); // 7:10 + events.push_back( + CreateScreenStateChangedEvent(android::view::DisplayStateEnum::DISPLAY_STATE_OFF, + bucketStartTimeNs + 440 * NS_PER_SEC)); // 7:30 + events.push_back(CreateAppCrashOccurredEvent(1 /* uid */, + bucketStartTimeNs + 450 * NS_PER_SEC)); // 7:40 + events.push_back( + CreateScreenStateChangedEvent(android::view::DisplayStateEnum::DISPLAY_STATE_ON, + bucketStartTimeNs + 520 * NS_PER_SEC)); // 8:50 + events.push_back(CreateUidProcessStateChangedEvent( + 1 /* uid */, android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_FOREGROUND, + bucketStartTimeNs + 540 * NS_PER_SEC)); // 9:10 + events.push_back(CreateAppCrashOccurredEvent(2 /* uid */, + bucketStartTimeNs + 570 * NS_PER_SEC)); // 9:40 + + // Send log events to StatsLogProcessor. + for (auto& event : events) { + processor->OnLogEvent(event.get()); + } + + // Check dump report. + vector<uint8_t> buffer; + ConfigMetricsReportList reports; + processor->onDumpReport(cfgKey, bucketStartTimeNs + bucketSizeNs * 2 + 1, false, true, ADB_DUMP, + FAST, &buffer); + EXPECT_GT(buffer.size(), 0); + EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size())); + backfillDimensionPath(&reports); + backfillStringInReport(&reports); + backfillStartEndTimestamp(&reports); + + EXPECT_EQ(1, reports.reports_size()); + EXPECT_EQ(1, reports.reports(0).metrics_size()); + EXPECT_TRUE(reports.reports(0).metrics(0).has_count_metrics()); + EXPECT_EQ(6, reports.reports(0).metrics(0).count_metrics().data_size()); + + // For each CountMetricData, check StateValue info is correct and buckets + // have correct counts. + auto data = reports.reports(0).metrics(0).count_metrics().data(0); + EXPECT_EQ(2, data.slice_by_state_size()); + EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id()); + EXPECT_TRUE(data.slice_by_state(0).has_group_id()); + EXPECT_EQ(StringToId("SCREEN_OFF"), data.slice_by_state(0).group_id()); + EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(1).atom_id()); + EXPECT_TRUE(data.slice_by_state(1).has_value()); + EXPECT_EQ(android::app::PROCESS_STATE_FOREGROUND_SERVICE, data.slice_by_state(1).value()); + EXPECT_EQ(1, data.bucket_info_size()); + EXPECT_EQ(1, data.bucket_info(0).count()); + + data = reports.reports(0).metrics(0).count_metrics().data(1); + EXPECT_EQ(2, data.slice_by_state_size()); + EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id()); + EXPECT_TRUE(data.slice_by_state(0).has_value()); + EXPECT_EQ(-1, data.slice_by_state(0).value()); + EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(1).atom_id()); + EXPECT_TRUE(data.slice_by_state(1).has_value()); + EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_FOREGROUND, data.slice_by_state(1).value()); + EXPECT_EQ(1, data.bucket_info_size()); + EXPECT_EQ(1, data.bucket_info(0).count()); + + data = reports.reports(0).metrics(0).count_metrics().data(2); + EXPECT_EQ(2, data.slice_by_state_size()); + EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id()); + EXPECT_TRUE(data.slice_by_state(0).has_group_id()); + EXPECT_EQ(StringToId("SCREEN_OFF"), data.slice_by_state(0).group_id()); + EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(1).atom_id()); + EXPECT_TRUE(data.slice_by_state(1).has_value()); + EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_FOREGROUND, data.slice_by_state(1).value()); + EXPECT_EQ(2, data.bucket_info_size()); + EXPECT_EQ(2, data.bucket_info(0).count()); + EXPECT_EQ(1, data.bucket_info(1).count()); + + data = reports.reports(0).metrics(0).count_metrics().data(3); + EXPECT_EQ(2, data.slice_by_state_size()); + EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id()); + EXPECT_TRUE(data.slice_by_state(0).has_group_id()); + EXPECT_EQ(StringToId("SCREEN_ON"), data.slice_by_state(0).group_id()); + EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(1).atom_id()); + EXPECT_TRUE(data.slice_by_state(1).has_value()); + EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_FOREGROUND, data.slice_by_state(1).value()); + EXPECT_EQ(1, data.bucket_info_size()); + EXPECT_EQ(1, data.bucket_info(0).count()); + + data = reports.reports(0).metrics(0).count_metrics().data(4); + EXPECT_EQ(2, data.slice_by_state_size()); + EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id()); + EXPECT_TRUE(data.slice_by_state(0).has_group_id()); + EXPECT_EQ(StringToId("SCREEN_ON"), data.slice_by_state(0).group_id()); + EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(1).atom_id()); + EXPECT_TRUE(data.slice_by_state(1).has_value()); + EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_BACKGROUND, data.slice_by_state(1).value()); + EXPECT_EQ(1, data.bucket_info_size()); + EXPECT_EQ(1, data.bucket_info(0).count()); + + data = reports.reports(0).metrics(0).count_metrics().data(5); + EXPECT_EQ(2, data.slice_by_state_size()); + EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id()); + EXPECT_TRUE(data.slice_by_state(0).has_group_id()); + EXPECT_EQ(StringToId("SCREEN_OFF"), data.slice_by_state(0).group_id()); + EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(1).atom_id()); + EXPECT_TRUE(data.slice_by_state(1).has_value()); + EXPECT_EQ(android::app::PROCESS_STATE_TOP, data.slice_by_state(1).value()); + EXPECT_EQ(1, data.bucket_info_size()); + EXPECT_EQ(2, data.bucket_info(0).count()); } } // namespace statsd diff --git a/cmds/statsd/tests/metrics/metrics_test_helper.cpp b/cmds/statsd/tests/metrics/metrics_test_helper.cpp index 7b9c0d6ab28e..108df04b45cb 100644 --- a/cmds/statsd/tests/metrics/metrics_test_helper.cpp +++ b/cmds/statsd/tests/metrics/metrics_test_helper.cpp @@ -26,10 +26,23 @@ HashableDimensionKey getMockedDimensionKey(int tagId, int key, string value) { return dimension; } +HashableDimensionKey getMockedDimensionKeyLongValue(int tagId, int key, int64_t value) { + HashableDimensionKey dimension; + int pos[] = {key, 0, 0}; + dimension.addValue(FieldValue(Field(tagId, pos, 0), Value(value))); + + return dimension; +} + MetricDimensionKey getMockedMetricDimensionKey(int tagId, int key, string value) { return MetricDimensionKey(getMockedDimensionKey(tagId, key, value), DEFAULT_DIMENSION_KEY); } +MetricDimensionKey getMockedStateDimensionKey(int tagId, int key, int64_t value) { + return MetricDimensionKey(DEFAULT_DIMENSION_KEY, + getMockedDimensionKeyLongValue(tagId, key, value)); +} + void buildSimpleAtomFieldMatcher(const int tagId, FieldMatcher* matcher) { matcher->set_field(tagId); } @@ -41,4 +54,4 @@ void buildSimpleAtomFieldMatcher(const int tagId, const int fieldNum, FieldMatch } // namespace statsd } // namespace os -} // namespace android
\ No newline at end of file +} // namespace android diff --git a/cmds/statsd/tests/metrics/metrics_test_helper.h b/cmds/statsd/tests/metrics/metrics_test_helper.h index 329e39fc4eff..09c4d9e41fc2 100644 --- a/cmds/statsd/tests/metrics/metrics_test_helper.h +++ b/cmds/statsd/tests/metrics/metrics_test_helper.h @@ -47,6 +47,9 @@ class MockUidMap : public UidMap { HashableDimensionKey getMockedDimensionKey(int tagId, int key, std::string value); MetricDimensionKey getMockedMetricDimensionKey(int tagId, int key, std::string value); +HashableDimensionKey getMockedDimensionKeyLongValue(int tagId, int key, int64_t value); +MetricDimensionKey getMockedStateDimensionKey(int tagId, int key, int64_t value); + // Utils to build FieldMatcher proto for simple one-depth atoms. void buildSimpleAtomFieldMatcher(const int tagId, const int atomFieldNum, FieldMatcher* matcher); void buildSimpleAtomFieldMatcher(const int tagId, FieldMatcher* matcher); diff --git a/cmds/statsd/tests/state/StateTracker_test.cpp b/cmds/statsd/tests/state/StateTracker_test.cpp index 8d380006a8ab..4208fef3860e 100644 --- a/cmds/statsd/tests/state/StateTracker_test.cpp +++ b/cmds/statsd/tests/state/StateTracker_test.cpp @@ -50,6 +50,12 @@ public: } }; +int getStateInt(StateManager& mgr, int atomId, const HashableDimensionKey& queryKey) { + FieldValue output; + mgr.getStateValue(atomId, queryKey, &output); + return output.mValue.int_value; +} + // START: build event functions. // State with no primary fields - ScreenStateChanged std::shared_ptr<LogEvent> buildScreenEvent(int state) { @@ -240,7 +246,7 @@ TEST(StateTrackerTest, TestStateChangeNoPrimaryFields) { // check StateTracker was updated by querying for state HashableDimensionKey queryKey = DEFAULT_DIMENSION_KEY; - EXPECT_EQ(2, mgr.getStateValue(android::util::SCREEN_STATE_CHANGED, queryKey)); + EXPECT_EQ(2, getStateInt(mgr, android::util::SCREEN_STATE_CHANGED, queryKey)); } /** @@ -265,7 +271,7 @@ TEST(StateTrackerTest, TestStateChangeOnePrimaryField) { // check StateTracker was updated by querying for state HashableDimensionKey queryKey; getUidProcessKey(1000 /* uid */, &queryKey); - EXPECT_EQ(1002, mgr.getStateValue(android::util::UID_PROCESS_STATE_CHANGED, queryKey)); + EXPECT_EQ(1002, getStateInt(mgr, android::util::UID_PROCESS_STATE_CHANGED, queryKey)); } /** @@ -290,7 +296,7 @@ TEST(StateTrackerTest, TestStateChangeMultiplePrimaryFields) { // check StateTracker was updated by querying for state HashableDimensionKey queryKey; getOverlayKey(1000 /* uid */, "package1", &queryKey); - EXPECT_EQ(1, mgr.getStateValue(android::util::OVERLAY_STATE_CHANGED, queryKey)); + EXPECT_EQ(1, getStateInt(mgr, android::util::OVERLAY_STATE_CHANGED, queryKey)); } /** @@ -353,25 +359,25 @@ TEST(StateTrackerTest, TestStateQuery) { // Query for UidProcessState of uid 1001 HashableDimensionKey queryKey1; getUidProcessKey(1001, &queryKey1); - EXPECT_EQ(1003, mgr.getStateValue(android::util::UID_PROCESS_STATE_CHANGED, queryKey1)); + EXPECT_EQ(1003, getStateInt(mgr, android::util::UID_PROCESS_STATE_CHANGED, queryKey1)); // Query for UidProcessState of uid 1004 - not in state map HashableDimensionKey queryKey2; getUidProcessKey(1004, &queryKey2); - EXPECT_EQ(-1, mgr.getStateValue(android::util::UID_PROCESS_STATE_CHANGED, - queryKey2)); // default state + EXPECT_EQ(-1, getStateInt(mgr, android::util::UID_PROCESS_STATE_CHANGED, + queryKey2)); // default state // Query for UidProcessState of uid 1001 - after change in state mgr.onLogEvent(*event4); - EXPECT_EQ(1002, mgr.getStateValue(android::util::UID_PROCESS_STATE_CHANGED, queryKey1)); + EXPECT_EQ(1002, getStateInt(mgr, android::util::UID_PROCESS_STATE_CHANGED, queryKey1)); // Query for ScreenState - EXPECT_EQ(2, mgr.getStateValue(android::util::SCREEN_STATE_CHANGED, DEFAULT_DIMENSION_KEY)); + EXPECT_EQ(2, getStateInt(mgr, android::util::SCREEN_STATE_CHANGED, DEFAULT_DIMENSION_KEY)); // Query for OverlayState of uid 1000, package name "package2" HashableDimensionKey queryKey3; getOverlayKey(1000, "package2", &queryKey3); - EXPECT_EQ(2, mgr.getStateValue(android::util::OVERLAY_STATE_CHANGED, queryKey3)); + EXPECT_EQ(2, getStateInt(mgr, android::util::OVERLAY_STATE_CHANGED, queryKey3)); } } // namespace statsd diff --git a/cmds/statsd/tests/statsd_test_util.cpp b/cmds/statsd/tests/statsd_test_util.cpp index 38c22ab5d253..d154b1b9cad9 100644 --- a/cmds/statsd/tests/statsd_test_util.cpp +++ b/cmds/statsd/tests/statsd_test_util.cpp @@ -254,28 +254,28 @@ Predicate CreateIsInBackgroundPredicate() { State CreateScreenState() { State state; state.set_id(StringToId("ScreenState")); - state.set_atom_id(29); + state.set_atom_id(android::util::SCREEN_STATE_CHANGED); return state; } State CreateUidProcessState() { State state; state.set_id(StringToId("UidProcessState")); - state.set_atom_id(27); + state.set_atom_id(android::util::UID_PROCESS_STATE_CHANGED); return state; } State CreateOverlayState() { State state; state.set_id(StringToId("OverlayState")); - state.set_atom_id(59); + state.set_atom_id(android::util::OVERLAY_STATE_CHANGED); return state; } State CreateScreenStateWithOnOffMap() { State state; state.set_id(StringToId("ScreenStateOnOff")); - state.set_atom_id(29); + state.set_atom_id(android::util::SCREEN_STATE_CHANGED); auto map = CreateScreenStateOnOffMap(); *state.mutable_map() = map; @@ -286,7 +286,7 @@ State CreateScreenStateWithOnOffMap() { State CreateScreenStateWithInDozeMap() { State state; state.set_id(StringToId("ScreenStateInDoze")); - state.set_atom_id(29); + state.set_atom_id(android::util::SCREEN_STATE_CHANGED); auto map = CreateScreenStateInDozeMap(); *state.mutable_map() = map; @@ -533,6 +533,15 @@ std::unique_ptr<LogEvent> CreateAppCrashEvent(const int uid, uint64_t timestampN uid, ProcessLifeCycleStateChanged::CRASHED, timestampNs); } +std::unique_ptr<LogEvent> CreateAppCrashOccurredEvent(const int uid, uint64_t timestampNs) { + auto event = std::make_unique<LogEvent>(android::util::APP_CRASH_OCCURRED, timestampNs); + event->write(uid); + event->write("eventType"); + event->write("processName"); + event->init(); + return event; +} + std::unique_ptr<LogEvent> CreateIsolatedUidChangedEvent( int isolatedUid, int hostUid, bool is_create, uint64_t timestampNs) { auto logEvent = std::make_unique<LogEvent>( @@ -544,6 +553,15 @@ std::unique_ptr<LogEvent> CreateIsolatedUidChangedEvent( return logEvent; } +std::unique_ptr<LogEvent> CreateUidProcessStateChangedEvent( + int uid, const android::app::ProcessStateEnum state, uint64_t timestampNs) { + auto event = std::make_unique<LogEvent>(android::util::UID_PROCESS_STATE_CHANGED, timestampNs); + event->write(uid); + event->write(state); + event->init(); + return event; +} + sp<StatsLogProcessor> CreateStatsLogProcessor(const int64_t timeBaseNs, const int64_t currentTimeNs, const StatsdConfig& config, const ConfigKey& key) { sp<UidMap> uidMap = new UidMap(); diff --git a/cmds/statsd/tests/statsd_test_util.h b/cmds/statsd/tests/statsd_test_util.h index c02610540cf0..e1e134be6b81 100644 --- a/cmds/statsd/tests/statsd_test_util.h +++ b/cmds/statsd/tests/statsd_test_util.h @@ -192,6 +192,9 @@ std::unique_ptr<LogEvent> CreateSyncEndEvent( std::unique_ptr<LogEvent> CreateAppCrashEvent( const int uid, uint64_t timestampNs); +// Create log event for an app crash. +std::unique_ptr<LogEvent> CreateAppCrashOccurredEvent(const int uid, uint64_t timestampNs); + // Create log event for acquiring wakelock. std::unique_ptr<LogEvent> CreateAcquireWakelockEvent( const std::vector<AttributionNodeInternal>& attributions, const string& wakelockName, @@ -206,6 +209,10 @@ std::unique_ptr<LogEvent> CreateReleaseWakelockEvent( std::unique_ptr<LogEvent> CreateIsolatedUidChangedEvent( int isolatedUid, int hostUid, bool is_create, uint64_t timestampNs); +// Create log event for uid process state change. +std::unique_ptr<LogEvent> CreateUidProcessStateChangedEvent( + int uid, const android::app::ProcessStateEnum state, uint64_t timestampNs); + // Helper function to create an AttributionNodeInternal proto. AttributionNodeInternal CreateAttribution(const int& uid, const string& tag); diff --git a/core/java/android/annotation/UserHandleAware.java b/core/java/android/annotation/UserHandleAware.java new file mode 100644 index 000000000000..7d3d20b31b2a --- /dev/null +++ b/core/java/android/annotation/UserHandleAware.java @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package android.annotation; + +import static java.lang.annotation.ElementType.CONSTRUCTOR; +import static java.lang.annotation.ElementType.METHOD; +import static java.lang.annotation.ElementType.PACKAGE; +import static java.lang.annotation.ElementType.TYPE; +import static java.lang.annotation.RetentionPolicy.SOURCE; + +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +/** + * Indicates an API that uses {@code context.getUser} or {@code context.getUserId} + * to operate across users (as the user associated with the context) + * <p> + * To create a {@link android.content.Context} associated with a different user, + * use {@link android.content.Context#createContextAsUser} or + * {@link android.content.Context#createPackageContextAsUser} + * <p> + * Example: + * <pre>{@code + * {@literal @}UserHandleAware + * public abstract PackageInfo getPackageInfo({@literal @}NonNull String packageName, + * {@literal @}PackageInfoFlags int flags) throws NameNotFoundException; + * }</pre> + * + * @memberDoc This method uses {@linkplain android.content.Context#getUser} + * or {@linkplain android.content.Context#getUserId} to execute across users. + * @hide + */ +@Retention(SOURCE) +@Target({TYPE, METHOD, CONSTRUCTOR, PACKAGE}) +public @interface UserHandleAware { +} diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java index 2e9b2afcc37a..e2da3bae003e 100644 --- a/core/java/android/app/ActivityManager.java +++ b/core/java/android/app/ActivityManager.java @@ -155,6 +155,12 @@ public class ActivityManager { */ public static final int INSTR_FLAG_MOUNT_EXTERNAL_STORAGE_FULL = 1 << 1; + /** + * Disable test API access for the newly started instrumentation. + * @hide + */ + public static final int INSTR_FLAG_DISABLE_TEST_API_CHECKS = 1 << 2; + static final class UidObserver extends IUidObserver.Stub { final OnUidImportanceListener mListener; final Context mContext; diff --git a/core/java/android/app/ActivityView.java b/core/java/android/app/ActivityView.java index 79ab67ac148c..91f8a3c7be85 100644 --- a/core/java/android/app/ActivityView.java +++ b/core/java/android/app/ActivityView.java @@ -412,8 +412,8 @@ public class ActivityView extends ViewGroup implements TaskEmbedder.Host { return; } mSurfaceView.getHolder().removeCallback(mSurfaceCallback); - mTaskEmbedder.setListener(null); mTaskEmbedder.release(); + mTaskEmbedder.setListener(null); mGuard.close(); mOpened = false; diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java index 2931f33e4cc4..fce74496d9c4 100644 --- a/core/java/android/app/Notification.java +++ b/core/java/android/app/Notification.java @@ -3204,6 +3204,14 @@ public class Notification implements Parcelable } /** + * Sets the {@link BubbleMetadata} for this notification. + * @hide + */ + public void setBubbleMetadata(BubbleMetadata data) { + mBubbleMetadata = data; + } + + /** * Returns whether the platform is allowed (by the app developer) to generate contextual actions * for this notification. */ diff --git a/core/java/android/content/SyncStatusInfo.java b/core/java/android/content/SyncStatusInfo.java index 3f6451577258..0eea47a248af 100644 --- a/core/java/android/content/SyncStatusInfo.java +++ b/core/java/android/content/SyncStatusInfo.java @@ -20,6 +20,9 @@ import android.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.os.Parcelable; import android.util.Log; +import android.util.Pair; + +import com.android.internal.util.ArrayUtils; import java.util.ArrayList; import java.util.Calendar; @@ -139,10 +142,10 @@ public class SyncStatusInfo implements Parcelable { public final long[] perSourceLastSuccessTimes = new long[SOURCE_COUNT]; public final long[] perSourceLastFailureTimes = new long[SOURCE_COUNT]; - // Warning: It is up to the external caller to ensure there are - // no race conditions when accessing this list - @UnsupportedAppUsage - private ArrayList<Long> periodicSyncTimes; + // Warning: It is up to the external caller to ensure there are + // no race conditions when accessing this list + @UnsupportedAppUsage + private ArrayList<Long> periodicSyncTimes; private final ArrayList<Long> mLastEventTimes = new ArrayList<>(); private final ArrayList<String> mLastEvents = new ArrayList<>(); @@ -292,9 +295,28 @@ public class SyncStatusInfo implements Parcelable { } } + /** + * Copies all data from the given SyncStatusInfo object. + * + * @param other the SyncStatusInfo object to copy data from + */ public SyncStatusInfo(SyncStatusInfo other) { authorityId = other.authorityId; + copyFrom(other); + } + + /** + * Copies all data from the given SyncStatusInfo object except for its authority id. + * + * @param authorityId the new authority id + * @param other the SyncStatusInfo object to copy data from + */ + public SyncStatusInfo(int authorityId, SyncStatusInfo other) { + this.authorityId = authorityId; + copyFrom(other); + } + private void copyFrom(SyncStatusInfo other) { other.totalStats.copyTo(totalStats); other.todayStats.copyTo(todayStats); other.yesterdayStats.copyTo(yesterdayStats); @@ -323,6 +345,14 @@ public class SyncStatusInfo implements Parcelable { System.arraycopy(from, 0, to, 0, to.length); } + public int getPeriodicSyncTimesSize() { + return periodicSyncTimes == null ? 0 : periodicSyncTimes.size(); + } + + public void addPeriodicSyncTime(long time) { + periodicSyncTimes = ArrayUtils.add(periodicSyncTimes, time); + } + @UnsupportedAppUsage public void setPeriodicSyncTime(int index, long when) { // The list is initialized lazily when scheduling occurs so we need to make sure @@ -347,6 +377,24 @@ public class SyncStatusInfo implements Parcelable { } } + /** + * Populates {@code mLastEventTimes} and {@code mLastEvents} with the given list. <br> + * <i>Note: This method is mainly used to repopulate the event info from disk and it will clear + * both {@code mLastEventTimes} and {@code mLastEvents} before populating.</i> + * + * @param lastEventInformation the list to populate with + */ + public void populateLastEventsInformation(ArrayList<Pair<Long, String>> lastEventInformation) { + mLastEventTimes.clear(); + mLastEvents.clear(); + final int size = lastEventInformation.size(); + for (int i = 0; i < size; i++) { + final Pair<Long, String> lastEventInfo = lastEventInformation.get(i); + mLastEventTimes.add(lastEventInfo.first); + mLastEvents.add(lastEventInfo.second); + } + } + /** */ public void addEvent(String message) { if (mLastEventTimes.size() >= MAX_EVENT_COUNT) { diff --git a/core/java/android/net/SSLCertificateSocketFactory.java b/core/java/android/net/SSLCertificateSocketFactory.java index 95d66bb87064..39cb323d0662 100644 --- a/core/java/android/net/SSLCertificateSocketFactory.java +++ b/core/java/android/net/SSLCertificateSocketFactory.java @@ -304,7 +304,8 @@ public class SSLCertificateSocketFactory extends SSLSocketFactory { } /** - * Sets the <a href="http://technotes.googlecode.com/git/nextprotoneg.html">Next + * Sets the + * <a class="external" href="https://tools.ietf.org/id/draft-agl-tls-nextprotoneg-03.html">Next * Protocol Negotiation (NPN)</a> protocols that this peer is interested in. * * <p>For servers this is the sequence of protocols to advertise as diff --git a/core/java/android/os/Binder.java b/core/java/android/os/Binder.java index fda1539b59f5..a856975e2501 100644 --- a/core/java/android/os/Binder.java +++ b/core/java/android/os/Binder.java @@ -933,8 +933,7 @@ public class Binder implements IBinder { int result = -1; try { - result = handleShellCommand(new ParcelFileDescriptor(in), - new ParcelFileDescriptor(out), new ParcelFileDescriptor(err), args); + result = handleShellCommand(in, out, err, args); } finally { resultReceiver.send(result, null); } @@ -955,10 +954,9 @@ public class Binder implements IBinder { * @hide */ // @SystemApi TODO Make it a system API. - protected int handleShellCommand(@NonNull ParcelFileDescriptor in, - @NonNull ParcelFileDescriptor out, @NonNull ParcelFileDescriptor err, - @NonNull String[] args) { - FileOutputStream ferr = new FileOutputStream(err.getFileDescriptor()); + protected int handleShellCommand(@NonNull FileDescriptor in, @NonNull FileDescriptor out, + @NonNull FileDescriptor err, @NonNull String[] args) { + FileOutputStream ferr = new FileOutputStream(err); PrintWriter pw = new FastPrintWriter(ferr); pw.println("No shell command implementation."); pw.flush(); diff --git a/core/java/android/os/incremental/IIncrementalService.aidl b/core/java/android/os/incremental/IIncrementalService.aidl new file mode 100644 index 000000000000..1c832ca9e6db --- /dev/null +++ b/core/java/android/os/incremental/IIncrementalService.aidl @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.os.incremental; + +import android.os.incremental.IncrementalDataLoaderParamsParcel; + +/** @hide */ +interface IIncrementalService { + /** + * A set of flags for the |createMode| parameters when creating a new Incremental storage. + */ + const int CREATE_MODE_TEMPORARY_BIND = 1; + const int CREATE_MODE_PERMANENT_BIND = 2; + const int CREATE_MODE_CREATE = 4; + const int CREATE_MODE_OPEN_EXISTING = 8; + + /** + * Opens or creates a storage given a target path and data loader params. Returns the storage ID. + */ + int openStorage(in @utf8InCpp String path); + int createStorage(in @utf8InCpp String path, in IncrementalDataLoaderParamsParcel params, int createMode); + int createLinkedStorage(in @utf8InCpp String path, int otherStorageId, int createMode); + + /** + * Bind-mounts a path under a storage to a full path. Can be permanent or temporary. + */ + const int BIND_TEMPORARY = 0; + const int BIND_PERMANENT = 1; + int makeBindMount(int storageId, in @utf8InCpp String pathUnderStorage, in @utf8InCpp String targetFullPath, int bindType); + + /** + * Deletes an existing bind mount on a path under a storage. Returns 0 on success, and -errno on failure. + */ + int deleteBindMount(int storageId, in @utf8InCpp String targetFullPath); + + /** + * Creates a directory under a storage. The target directory is specified by its relative path under the storage. + */ + int makeDirectory(int storageId, in @utf8InCpp String pathUnderStorage); + + /** + * Creates a file under a storage, specifying its name, size and metadata. + */ + int makeFile(int storageId, in @utf8InCpp String pathUnderStorage, long size, in byte[] metadata); + + /** + * Creates a file under a storage. Content of the file is from a range inside another file. + * Both files are specified by relative paths under storage. + */ + int makeFileFromRange(int storageId, in @utf8InCpp String targetPathUnderStorage, in @utf8InCpp String sourcePathUnderStorage, long start, long end); + + /** + * Creates a hard link between two files in a storage. + * Both source and destination are specified by relative paths under storage. + */ + int makeLink(int storageId, in @utf8InCpp String sourcePathUnderStorage, in @utf8InCpp String destPathUnderStorage); + + /** + * Deletes a hard link in a storage, specified by the relative path of the link target under storage. + */ + int unlink(int storageId, in @utf8InCpp String pathUnderStorage); + + /** + * Checks if a file's certain range is loaded. File is specified by relative file path under storage. + */ + boolean isFileRangeLoaded(int storageId, in @utf8InCpp String pathUnderStorage, long start, long end); + + /** + * Reads the metadata of a file. File is specified by relative path under storage. + */ + byte[] getFileMetadata(int storageId, in @utf8InCpp String pathUnderStorage); + + /** + * Returns the list of file paths under a storage. + */ + @utf8InCpp String[] getFileList(int storageId); + + /** + * Starts loading data for a storage. + */ + boolean startLoading(int storageId); +} diff --git a/core/java/android/os/incremental/IIncrementalServiceProxy.aidl b/core/java/android/os/incremental/IIncrementalServiceProxy.aidl new file mode 100644 index 000000000000..12740eaf3425 --- /dev/null +++ b/core/java/android/os/incremental/IIncrementalServiceProxy.aidl @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.os.incremental; + +import android.os.incremental.IncrementalFileSystemControlParcel; +import android.os.incremental.IncrementalDataLoaderParamsParcel; +import android.service.incremental.IIncrementalDataLoaderStatusListener; + +/** + * Binder service to receive calls from native Incremental Service and handle Java tasks such as + * looking up data loader service package names, binding and talking to the data loader service. + * @hide + */ +interface IIncrementalServiceProxy { + boolean prepareDataLoader(int mountId, + in IncrementalFileSystemControlParcel control, + in IncrementalDataLoaderParamsParcel params, + in IIncrementalDataLoaderStatusListener listener); + boolean startDataLoader(int mountId); + void showHealthBlockedUI(int mountId); + void destroyDataLoader(int mountId); + void newFileForDataLoader(int mountId, long inode, in byte[] metadata); +} diff --git a/core/java/android/os/incremental/IncrementalDataLoaderParamsParcel.aidl b/core/java/android/os/incremental/IncrementalDataLoaderParamsParcel.aidl new file mode 100644 index 000000000000..50c28f0a4c17 --- /dev/null +++ b/core/java/android/os/incremental/IncrementalDataLoaderParamsParcel.aidl @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.os.incremental; + +import android.os.incremental.NamedParcelFileDescriptor; + +/** + * Class for holding data loader configuration parameters. + * @hide + */ +parcelable IncrementalDataLoaderParamsParcel { + @utf8InCpp String staticUri; + @utf8InCpp String packageName; + NamedParcelFileDescriptor[] dynamicArgs; +} diff --git a/core/java/android/os/incremental/IncrementalFileSystemControlParcel.aidl b/core/java/android/os/incremental/IncrementalFileSystemControlParcel.aidl new file mode 100644 index 000000000000..0ae353d2741f --- /dev/null +++ b/core/java/android/os/incremental/IncrementalFileSystemControlParcel.aidl @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.os.incremental; + +/** + * Wraps two file descriptors that Incremental Service uses to communicate + * with Incremental FileSystem. + * @hide + */ +parcelable IncrementalFileSystemControlParcel { + @nullable ParcelFileDescriptor cmd; + @nullable ParcelFileDescriptor log; +} diff --git a/core/java/android/os/incremental/NamedParcelFileDescriptor.aidl b/core/java/android/os/incremental/NamedParcelFileDescriptor.aidl new file mode 100644 index 000000000000..038ced1744a1 --- /dev/null +++ b/core/java/android/os/incremental/NamedParcelFileDescriptor.aidl @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.os.incremental; + +import android.os.ParcelFileDescriptor; + +/** + * A named ParcelFileDescriptor. + * @hide + */ +parcelable NamedParcelFileDescriptor { + @utf8InCpp String name; + ParcelFileDescriptor fd; +} diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index 381d4921932f..1b1e8b4659e8 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -836,9 +836,9 @@ public final class Settings { * In some cases, a matching Activity may not exist, so ensure you * safeguard against this. * <p> - * Input: Optionally, the Intent's data URI can specify the application package name to - * directly invoke the management GUI specific to the package name. For example - * "package:com.my.app". + * Input: Optionally, in versions of Android prior to 11, the Intent's data URI can specify the + * application package name to directly invoke the management GUI specific to the package name. + * For example "package:com.my.app". * <p> * Output: Nothing. */ diff --git a/core/java/android/service/incremental/IIncrementalDataLoaderService.aidl b/core/java/android/service/incremental/IIncrementalDataLoaderService.aidl new file mode 100644 index 000000000000..723fc594bd72 --- /dev/null +++ b/core/java/android/service/incremental/IIncrementalDataLoaderService.aidl @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.service.incremental; + +import android.os.incremental.IncrementalDataLoaderParamsParcel; +import android.os.incremental.IncrementalFileSystemControlParcel; +import android.service.incremental.IIncrementalDataLoaderStatusListener; + +/** @hide */ +oneway interface IIncrementalDataLoaderService { + void createDataLoader(in int storageId, + in IncrementalFileSystemControlParcel control, + in IncrementalDataLoaderParamsParcel params, + in IIncrementalDataLoaderStatusListener listener, + in boolean start); + void startDataLoader(in int storageId); + void stopDataLoader(in int storageId); + void destroyDataLoader(in int storageId); + void onFileCreated(in int storageId, in long inode, in byte[] metadata); +} diff --git a/core/java/android/service/incremental/IIncrementalDataLoaderStatusListener.aidl b/core/java/android/service/incremental/IIncrementalDataLoaderStatusListener.aidl new file mode 100644 index 000000000000..f04242dc6c02 --- /dev/null +++ b/core/java/android/service/incremental/IIncrementalDataLoaderStatusListener.aidl @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.service.incremental; + +/** + * Callbacks from DataLoaderService to IncrementalService to report data loader status. + * @hide + */ +oneway interface IIncrementalDataLoaderStatusListener { + /** Data loader status */ + const int DATA_LOADER_READY = 0; + const int DATA_LOADER_NOT_READY = 1; + const int DATA_LOADER_RUNNING = 2; + const int DATA_LOADER_STOPPED = 3; + const int DATA_LOADER_SLOW_CONNECTION = 4; + const int DATA_LOADER_NO_CONNECTION = 5; + const int DATA_LOADER_CONNECTION_OK = 6; + + /** Data loader status callback */ + void onStatusChanged(in int storageId, in int status); +} + diff --git a/core/java/android/util/DisplayMetrics.java b/core/java/android/util/DisplayMetrics.java index c40c1238b690..451a669d98fd 100755 --- a/core/java/android/util/DisplayMetrics.java +++ b/core/java/android/util/DisplayMetrics.java @@ -23,9 +23,8 @@ import android.os.SystemProperties; /** * A structure describing general information about a display, such as its * size, density, and font scaling. - * <p>To access the DisplayMetrics members, initialize an object like this:</p> - * <pre> DisplayMetrics metrics = new DisplayMetrics(); - * getWindowManager().getDefaultDisplay().getMetrics(metrics);</pre> + * <p>To access the DisplayMetrics members, retrieve display metrics like this:</p> + * <pre>context.getResources().getDisplayMetrics();</pre> */ public class DisplayMetrics { /** diff --git a/core/java/android/util/FeatureFlagUtils.java b/core/java/android/util/FeatureFlagUtils.java index af1a51f68d71..12a55c74bd3e 100644 --- a/core/java/android/util/FeatureFlagUtils.java +++ b/core/java/android/util/FeatureFlagUtils.java @@ -56,6 +56,7 @@ public class FeatureFlagUtils { DEFAULT_FLAGS.put("settings_skip_direction_mutable", "true"); DEFAULT_FLAGS.put(SETTINGS_WIFITRACKER2, "false"); DEFAULT_FLAGS.put("settings_work_profile", "false"); + DEFAULT_FLAGS.put("settings_controller_loading_enhancement", "false"); } /** diff --git a/core/java/android/util/StatsEvent.java b/core/java/android/util/StatsEvent.java index a21f9e09ced5..d6ffd38e98e8 100644 --- a/core/java/android/util/StatsEvent.java +++ b/core/java/android/util/StatsEvent.java @@ -63,7 +63,7 @@ public final class StatsEvent { * Returns a new StatsEvent.Builder for building StatsEvent object. **/ @NonNull - public StatsEvent.Builder newBuilder() { + public static StatsEvent.Builder newBuilder() { return new StatsEvent.Builder(Buffer.obtain()); } diff --git a/core/java/android/view/IDisplayWindowListener.aidl b/core/java/android/view/IDisplayWindowListener.aidl new file mode 100644 index 000000000000..725cd6f38aaa --- /dev/null +++ b/core/java/android/view/IDisplayWindowListener.aidl @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.view; + +/** + * Interface to listen for changes to display window-containers. + * + * This differs from DisplayManager's DisplayListener: + * - onDisplayAdded is always called after the display is actually added to the WM hierarchy. + * This corresponds to the DisplayContent and not the raw Dislay from DisplayManager. + * + * @hide + */ +oneway interface IDisplayWindowListener { + + /** + * Called when a display is added to the WM hierarchy. + */ + void onDisplayAdded(int displayId); + + /** + * Called when a display is removed from the hierarchy. + */ + void onDisplayRemoved(int displayId); + +} diff --git a/core/java/android/view/IDisplayWindowRotationCallback.aidl b/core/java/android/view/IDisplayWindowRotationCallback.aidl new file mode 100644 index 000000000000..79a15ad746b3 --- /dev/null +++ b/core/java/android/view/IDisplayWindowRotationCallback.aidl @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package android.view; + +import android.view.WindowContainerTransaction; + +/** + * Interface to be invoked by the controller when it has finished preparing for a display rotation. + * + * @see IDisplayWindowRotationController + * @hide + */ +interface IDisplayWindowRotationCallback { + void continueRotateDisplay(int targetRotation, in WindowContainerTransaction t); +} diff --git a/core/java/android/view/IDisplayWindowRotationController.aidl b/core/java/android/view/IDisplayWindowRotationController.aidl new file mode 100644 index 000000000000..c1c7464c3168 --- /dev/null +++ b/core/java/android/view/IDisplayWindowRotationController.aidl @@ -0,0 +1,52 @@ +/** + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.view; + +import android.view.IDisplayWindowRotationCallback; + +/** + * Singular controller of a "remote" display rotation. When a display rotation is started, WM + * freezes the screen. It will then call into this controller and wait for a response via the + * callback. + * + * This needs to provide configuration changes because those changes need to be applied in sync + * with the actual display rotation to prevent relayouts with mismatched information. + * + * The flow is like this: + * 1. DisplayContent/Rotation freezes the screen + * 2. This controller is notified of a rotation and provided a callback. + * 3. This controller is responsible for collecting a set of configuration changes to go along with + * the rotation. + * 4. The callback is fired which tells DisplayContent/Rotation to apply the provided configuration + * changes and continue the rotation. + * + * @hide + */ +oneway interface IDisplayWindowRotationController { + + /** + * Called when WM needs to know how to update tasks in response to a display rotation. + * If this isn't called, a timeout will continue the rotation in WM. + * + * @param displayId the display that is rotating. + * @param fromRotation the rotation the display is rotating from. + * @param toRotation the rotation the display is rotating to. + * @param callback A callback to be called when this has calculated updated configs. + */ + void onRotateDisplay(int displayId, int fromRotation, int toRotation, + in IDisplayWindowRotationCallback callback); +} diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl index 7f717a72b0f9..0bc8b4eb155d 100644 --- a/core/java/android/view/IWindowManager.aidl +++ b/core/java/android/view/IWindowManager.aidl @@ -35,7 +35,9 @@ import android.os.ParcelFileDescriptor; import android.view.IApplicationToken; import android.view.IAppTransitionAnimationSpecsFuture; import android.view.IDockedStackListener; +import android.view.IDisplayWindowListener; import android.view.IDisplayFoldListener; +import android.view.IDisplayWindowRotationController; import android.view.IOnKeyguardExitResult; import android.view.IPinnedStackListener; import android.view.RemoteAnimationAdapter; @@ -97,6 +99,13 @@ interface IWindowManager void prepareAppTransition(int transit, boolean alwaysKeepCurrent); /** + * Sets a singular remote controller of display rotations. There can only be one. The + * controller is called after the display has "frozen" for a rotation and display rotation will + * only continue once the controller has finished calculating associated configurations. + */ + void setDisplayWindowRotationController(IDisplayWindowRotationController controller); + + /** * Like overridePendingAppTransitionMultiThumb, but uses a future to supply the specs. This is * used for recents, where generating the thumbnails of the specs takes a non-trivial amount of * time, so we want to move that off the critical path for starting the new activity. @@ -476,6 +485,16 @@ interface IWindowManager void unregisterDisplayFoldListener(IDisplayFoldListener listener); /** + * Registers an IDisplayContainerListener + */ + void registerDisplayWindowListener(IDisplayWindowListener listener); + + /** + * Unregisters an IDisplayContainerListener. + */ + void unregisterDisplayWindowListener(IDisplayWindowListener listener); + + /** * Starts a window trace. */ void startWindowTrace(); diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java index 8dd475e0c306..b815c641ff25 100644 --- a/core/java/android/view/SurfaceControl.java +++ b/core/java/android/view/SurfaceControl.java @@ -196,6 +196,8 @@ public final class SurfaceControl implements Parcelable { float brightness); private static native long nativeReadTransactionFromParcel(Parcel in); private static native void nativeWriteTransactionToParcel(long nativeObject, Parcel out); + private static native void nativeSetShadowRadius(long transactionObj, long nativeObject, + float shadowRadius); private final CloseGuard mCloseGuard = CloseGuard.get(); private String mName; @@ -2545,6 +2547,29 @@ public final class SurfaceControl implements Parcelable { return this; } + /** + * Draws shadows of length {@code shadowRadius} around the surface {@link SurfaceControl}. + * If the length is 0.0f then the shadows will not be drawn. + * + * Shadows are drawn around the screen bounds, these are the post transformed cropped + * bounds. They can draw over their parent bounds and will be occluded by layers with a + * higher z-order. The shadows will respect the surface's corner radius if the + * rounded corner bounds (transformed source bounds) are within the screen bounds. + * + * A shadow will only be drawn on buffer and color layers. If the radius is applied on a + * container layer, it will be passed down the hierarchy to be applied on buffer and color + * layers but not its children. A scenario where this is useful is when SystemUI animates + * a task by controlling a leash to it, can draw a shadow around the app surface by + * setting a shadow on the leash. This is similar to how rounded corners are set. + * + * @hide + */ + public Transaction setShadowRadius(SurfaceControl sc, float shadowRadius) { + sc.checkNotReleased(); + nativeSetShadowRadius(mNativeObject, sc.mNativeObject, shadowRadius); + return this; + } + /** * Merge the other transaction into this transaction, clearing the * other transaction as if it had been applied. diff --git a/core/java/android/widget/NumberPicker.java b/core/java/android/widget/NumberPicker.java index a428feac8806..882e81a823c7 100644 --- a/core/java/android/widget/NumberPicker.java +++ b/core/java/android/widget/NumberPicker.java @@ -1267,12 +1267,12 @@ public class NumberPicker extends LinearLayout { * current value is set to the {@link NumberPicker#getMaxValue()} value. * </p> * <p> - * If the argument is less than the {@link NumberPicker#getMaxValue()} and + * If the argument is more than the {@link NumberPicker#getMaxValue()} and * {@link NumberPicker#getWrapSelectorWheel()} is <code>false</code> the * current value is set to the {@link NumberPicker#getMaxValue()} value. * </p> * <p> - * If the argument is less than the {@link NumberPicker#getMaxValue()} and + * If the argument is more than the {@link NumberPicker#getMaxValue()} and * {@link NumberPicker#getWrapSelectorWheel()} is <code>true</code> the * current value is set to the {@link NumberPicker#getMinValue()} value. * </p> diff --git a/core/jni/android_media_AudioSystem.cpp b/core/jni/android_media_AudioSystem.cpp index 541b937860c3..01f9d0b0cde5 100644 --- a/core/jni/android_media_AudioSystem.cpp +++ b/core/jni/android_media_AudioSystem.cpp @@ -2264,6 +2264,12 @@ android_media_AudioSystem_setAudioHalPids(JNIEnv *env, jobject clazz, jintArray return jStatus; } +static jboolean +android_media_AudioSystem_isCallScreeningModeSupported(JNIEnv *env, jobject thiz) +{ + return AudioSystem::isCallScreenModeSupported(); +} + // ---------------------------------------------------------------------------- static const JNINativeMethod gMethods[] = { @@ -2343,6 +2349,7 @@ static const JNINativeMethod gMethods[] = { {"setAllowedCapturePolicy", "(II)I", (void *)android_media_AudioSystem_setAllowedCapturePolicy}, {"setRttEnabled", "(Z)I", (void *)android_media_AudioSystem_setRttEnabled}, {"setAudioHalPids", "([I)I", (void *)android_media_AudioSystem_setAudioHalPids}, + {"isCallScreeningModeSupported", "()Z", (void *)android_media_AudioSystem_isCallScreeningModeSupported}, }; static const JNINativeMethod gEventHandlerMethods[] = { diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp index d5cd278063c0..c807e90d5ad4 100644 --- a/core/jni/android_view_SurfaceControl.cpp +++ b/core/jni/android_view_SurfaceControl.cpp @@ -545,6 +545,14 @@ static void nativeSetLayerStack(JNIEnv* env, jclass clazz, jlong transactionObj, transaction->setLayerStack(ctrl, layerStack); } +static void nativeSetShadowRadius(JNIEnv* env, jclass clazz, jlong transactionObj, + jlong nativeObject, jfloat shadowRadius) { + auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionObj); + + const auto ctrl = reinterpret_cast<SurfaceControl *>(nativeObject); + transaction->setShadowRadius(ctrl, shadowRadius); +} + static jlongArray nativeGetPhysicalDisplayIds(JNIEnv* env, jclass clazz) { const auto displayIds = SurfaceComposerClient::getPhysicalDisplayIds(); jlongArray array = env->NewLongArray(displayIds.size()); @@ -1308,6 +1316,8 @@ static const JNINativeMethod sSurfaceControlMethods[] = { (void*)nativeSetCornerRadius }, {"nativeSetLayerStack", "(JJI)V", (void*)nativeSetLayerStack }, + {"nativeSetShadowRadius", "(JJF)V", + (void*)nativeSetShadowRadius }, {"nativeGetPhysicalDisplayIds", "()[J", (void*)nativeGetPhysicalDisplayIds }, {"nativeGetPhysicalDisplayToken", "(J)Landroid/os/IBinder;", diff --git a/core/proto/android/server/activitymanagerservice.proto b/core/proto/android/server/activitymanagerservice.proto index 8f084abe71a7..ce2717bb2779 100644 --- a/core/proto/android/server/activitymanagerservice.proto +++ b/core/proto/android/server/activitymanagerservice.proto @@ -126,11 +126,12 @@ message ActivityRecordProto { optional .com.android.server.wm.ConfigurationContainerProto configuration_container = 1 [deprecated=true]; optional .com.android.server.wm.IdentifierProto identifier = 2; optional string state = 3; - optional bool visible = 4; + optional bool visible_requested = 4; optional bool front_of_task = 5; optional int32 proc_id = 6; optional bool translucent = 7; optional .com.android.server.wm.AppWindowTokenProto app_window_token = 8; + optional bool visible = 9; } message KeyguardControllerProto { diff --git a/core/proto/android/server/syncstorageengine.proto b/core/proto/android/server/syncstorageengine.proto new file mode 100644 index 000000000000..87eb1b3c5d95 --- /dev/null +++ b/core/proto/android/server/syncstorageengine.proto @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +syntax = "proto2"; +package com.android.server.content; +import "frameworks/base/core/proto/android/privacy.proto"; + +option java_multiple_files = true; + +/** + * Stores relevant information from a DayStats object in SyncStorageEngine. + */ +message SyncStatisticsProto { + + message DayStats { + optional int32 day = 1; // day of the year - defined by SyncStorageEngine#getCurrentDayLocked() + optional int32 success_count = 2; + optional int64 success_time = 3; // time since epoch + optional int32 failure_count = 4; + optional int64 failure_time = 5; // time since epoch + } + + repeated DayStats stats = 1; +} + +/** + * Stores relevant information from a SyncStatusInfo object. + */ +message SyncStatusProto { + + message StatusInfo { + + message Stats { + optional int64 total_elapsed_time = 1; // time since epoch + optional int32 num_syncs = 2; + optional int32 num_failures = 3; + optional int32 num_cancels = 4; + optional int32 num_source_other = 5; + optional int32 num_source_local = 6; + optional int32 num_source_poll = 7; + optional int32 num_source_user = 8; + optional int32 num_source_periodic = 9; + optional int32 num_source_feed = 10; + } + + message LastEventInfo { + optional int64 last_event_time = 1; // time since epoch + optional string last_event = 2; + } + + // Note: version doesn't need to be stored in proto because of how protos store information but + // leaving field number 1 open in case we find a usage for it in the future. + optional int32 authority_id = 2; + optional int64 last_success_time = 3; // time since epoch + optional int32 last_success_source = 4; + optional int64 last_failure_time = 5; // time since epoch + optional int32 last_failure_source = 6; + optional string last_failure_message = 7; + optional int64 initial_failure_time = 8; // time since epoch + optional bool pending = 9; + optional bool initialize = 10; + repeated int64 periodic_sync_times = 11; // times since epoch + repeated LastEventInfo last_event_info = 12; + optional int64 last_today_reset_time = 13; // time since epoch + optional Stats total_stats = 14; + optional Stats today_stats = 15; + optional Stats yesterday_stats = 16; + repeated int64 per_source_last_success_times = 17; // times since epoch + repeated int64 per_source_last_failure_times = 18; // times since epoch + } + + repeated StatusInfo status = 1; +} diff --git a/core/proto/android/server/windowmanagerservice.proto b/core/proto/android/server/windowmanagerservice.proto index c9a18296a292..c876944207c6 100644 --- a/core/proto/android/server/windowmanagerservice.proto +++ b/core/proto/android/server/windowmanagerservice.proto @@ -235,7 +235,7 @@ message AppWindowTokenProto { optional WindowContainerThumbnailProto thumbnail = 6; optional bool fills_parent = 7; optional bool app_stopped = 8; - optional bool hidden_requested = 9; + optional bool visible_requested = 9; optional bool client_hidden = 10; optional bool defer_hiding_client = 11; optional bool reported_drawn = 12; @@ -248,8 +248,9 @@ message AppWindowTokenProto { optional IdentifierProto starting_window = 19; optional bool starting_displayed = 20; optional bool starting_moved = 21; - optional bool hidden_set_from_transferred_starting_window = 22; + optional bool visible_set_from_transferred_starting_window = 22; repeated .android.graphics.RectProto frozen_bounds = 23; + optional bool visible = 24; } /* represents WindowToken */ @@ -259,7 +260,6 @@ message WindowTokenProto { optional WindowContainerProto window_container = 1; optional int32 hash_code = 2; repeated WindowStateProto windows = 3; - optional bool hidden = 4; optional bool waiting_to_show = 5; optional bool paused = 6; } diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index 7d70fbcd5fde..9f77407b2391 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -2007,7 +2007,7 @@ <eat-comment /> <!-- @SystemApi Allows granting runtime permissions to telephony related components. - @hide Used internally. --> + @hide --> <permission android:name="android.permission.GRANT_RUNTIME_PERMISSIONS_TO_TELEPHONY_DEFAULTS" android:protectionLevel="signature|telephony" /> diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml index 2b20a6b0360a..485162c13112 100644 --- a/core/res/res/values-af/strings.xml +++ b/core/res/res/values-af/strings.xml @@ -1771,10 +1771,8 @@ <string name="package_updated_device_owner" msgid="1847154566357862089">"Opgedateer deur jou administrateur"</string> <string name="package_deleted_device_owner" msgid="2307122077550236438">"Uitgevee deur jou administrateur"</string> <string name="confirm_battery_saver" msgid="639106420541753635">"OK"</string> - <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) --> - <skip /> - <!-- no translation found for battery_saver_description (2307555792915978653) --> - <skip /> + <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"Batterybespaarder doen die volgende om die batterylewe te verleng:\n·Skakel Donker-tema aan\n·Skakel agtergrondaktiwiteit, sommige visuele effekte en ander kenmerke, soos \"Hey Google\", af of beperk hulle\n\n"<annotation id="url">"Kom meer te wete"</annotation></string> + <string name="battery_saver_description" msgid="2307555792915978653">"Batterybespaarder doen die volgende om die batterylewe te verleng:\n·Skakel Donker-tema aan\n·Skakel agtergrondaktiwiteit, sommige visuele effekte en ander kenmerke, soos \"Hey Google\", af of beperk hulle"</string> <string name="data_saver_description" msgid="6015391409098303235">"Databespaarder verhoed sommige programme om data in die agtergrond te stuur of te aanvaar om datagebruik te help verminder. \'n Program wat jy tans gebruik kan by data ingaan, maar sal dit dalk minder gereeld doen. Dit kan byvoorbeeld beteken dat prente nie wys totdat jy op hulle tik nie."</string> <string name="data_saver_enable_title" msgid="4674073932722787417">"Skakel Databespaarder aan?"</string> <string name="data_saver_enable_button" msgid="7147735965247211818">"Skakel aan"</string> @@ -2008,4 +2006,22 @@ <string name="chooser_no_direct_share_targets" msgid="997970693708458895">"Regstreekse deling is nie beskikbaar nie"</string> <string name="chooser_all_apps_button_label" msgid="3631524352936289457">"Programmelys"</string> <string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"Opneemtoestemming is nie aan hierdie program verleen nie, maar dit kan oudio deur hierdie USB-toestel opneem."</string> + <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) --> + <skip /> + <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) --> + <skip /> + <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) --> + <skip /> + <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) --> + <skip /> + <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) --> + <skip /> + <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) --> + <skip /> + <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) --> + <skip /> + <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) --> + <skip /> + <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) --> + <skip /> </resources> diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml index 2588814e7ef3..f0a4307cc9d1 100644 --- a/core/res/res/values-am/strings.xml +++ b/core/res/res/values-am/strings.xml @@ -1771,10 +1771,8 @@ <string name="package_updated_device_owner" msgid="1847154566357862089">"በእርስዎ አስተዳዳሪ ተዘምኗል"</string> <string name="package_deleted_device_owner" msgid="2307122077550236438">"በእርስዎ አስተዳዳሪ ተሰርዟል"</string> <string name="confirm_battery_saver" msgid="639106420541753635">"እሺ"</string> - <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) --> - <skip /> - <!-- no translation found for battery_saver_description (2307555792915978653) --> - <skip /> + <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"የባትሪ ዕድሜን ለማራዘም፣ የባትሪ ቆጣቢ፦\n·ጨለማ ገጽታን ያበራል\n·የበስተጀርባ እንቅስቃሴን፣ አንዳንድ የሚታዩ ማሳመሪያዎችን፣ እና ሌሎች እንደ “Hey Google” ያሉ ባህሪያትን ያጠፋል ወይም ይገድባል\n\n"<annotation id="url">"የበለጠ ለመረዳት"</annotation></string> + <string name="battery_saver_description" msgid="2307555792915978653">"የባትሪ ዕድሜን ለማራዘም፣ የባትሪ ቆጣቢ፦\n·ጨለማ ገጽታን ያበራል\n·የበስተጀርባ እንቅስቃሴን፣ አንዳንድ የሚታዩ ማሳመሪያዎችን፣ እና ሌሎች እንደ “Hey Google” ያሉ ባህሪያትን ያጠፋል ወይም ይገድባል"</string> <string name="data_saver_description" msgid="6015391409098303235">"የውሂብ አጠቃቀም እንዲቀንስ ለማገዝ ውሂብ ቆጣቢ አንዳንድ መተግበሪያዎች ከበስተጀርባ ሆነው ውሂብ እንዳይልኩ ወይም እንዳይቀበሉ ይከለክላቸዋል። በአሁኑ ጊዜ እየተጠቀሙበት ያለ መተግበሪያ ውሂብ ሊደርስ ይችላል፣ ነገር ግን ባነሰ ተደጋጋሚነት ሊሆን ይችላል። ይሄ ማለት ለምሳሌ ምስሎችን መታ እስኪያደርጓቸው ድረስ ላይታዩ ይችላሉ ማለት ነው።"</string> <string name="data_saver_enable_title" msgid="4674073932722787417">"ውሂብ ቆጣቢ ይጥፋ?"</string> <string name="data_saver_enable_button" msgid="7147735965247211818">"አብራ"</string> @@ -2008,4 +2006,22 @@ <string name="chooser_no_direct_share_targets" msgid="997970693708458895">"ቀጥታ ማጋራት አይገኝም"</string> <string name="chooser_all_apps_button_label" msgid="3631524352936289457">"የመተግበሪያዎች ዝርዝር"</string> <string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"ይህ መተግበሪያ የመቅረጽ ፈቃድ አልተሰጠውም፣ ነገር ግን በዚህ ዩኤስቢ መሣሪያ በኩል ኦዲዮን መቅረጽ ይችላል።"</string> + <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) --> + <skip /> + <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) --> + <skip /> + <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) --> + <skip /> + <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) --> + <skip /> + <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) --> + <skip /> + <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) --> + <skip /> + <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) --> + <skip /> + <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) --> + <skip /> + <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) --> + <skip /> </resources> diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml index 162c066e8203..4ecf6e7099b6 100644 --- a/core/res/res/values-ar/strings.xml +++ b/core/res/res/values-ar/strings.xml @@ -1863,10 +1863,8 @@ <string name="package_updated_device_owner" msgid="1847154566357862089">"تم التحديث بواسطة المشرف"</string> <string name="package_deleted_device_owner" msgid="2307122077550236438">"تم الحذف بواسطة المشرف"</string> <string name="confirm_battery_saver" msgid="639106420541753635">"موافق"</string> - <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) --> - <skip /> - <!-- no translation found for battery_saver_description (2307555792915978653) --> - <skip /> + <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"لإطالة عمر البطارية، \"توفير شحن البطارية\":\n·تفعيل \"التصميم الداكن\"\n إيقاف النشاط في الخلفية أو تقييده وأيضًا بعض التأثيرات المرئية والميزات الأخرى، مثلاً \"Ok Google\"\n\n"<annotation id="url">"مزيد من المعلومات"</annotation></string> + <string name="battery_saver_description" msgid="2307555792915978653">"لإطالة عمر البطارية، \"توفير شحن البطارية\":\n·تفعيل \"التصميم الداكن\"\n إيقاف النشاط في الخلفية أو تقييده وأيضًا بعض التأثيرات المرئية والميزات الأخرى، مثلاً \"Ok Google\"."</string> <string name="data_saver_description" msgid="6015391409098303235">"للمساعدة في خفض استخدام البيانات، تمنع ميزة \"توفير البيانات\" بعض التطبيقات من إرسال البيانات وتلقّيها في الخلفية. يمكن للتطبيق الذي تستخدمه الآن الوصول إلى البيانات، ولكن لا يمكنه تنفيذ ذلك كثيرًا. وهذا يعني أن الصور مثلاً لا تظهر حتى تنقر عليها."</string> <string name="data_saver_enable_title" msgid="4674073932722787417">"هل تريد تشغيل توفير البيانات؟"</string> <string name="data_saver_enable_button" msgid="7147735965247211818">"تشغيل"</string> @@ -2144,4 +2142,22 @@ <string name="chooser_no_direct_share_targets" msgid="997970693708458895">"لا تتوفّر إمكانية المشاركة المباشرة."</string> <string name="chooser_all_apps_button_label" msgid="3631524352936289457">"قائمة التطبيقات"</string> <string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"لم يتم منح هذا التطبيق إذن تسجيل، ولكن يمكنه تسجيل الصوت من خلال جهاز USB هذا."</string> + <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) --> + <skip /> + <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) --> + <skip /> + <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) --> + <skip /> + <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) --> + <skip /> + <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) --> + <skip /> + <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) --> + <skip /> + <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) --> + <skip /> + <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) --> + <skip /> + <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) --> + <skip /> </resources> diff --git a/core/res/res/values-as/strings.xml b/core/res/res/values-as/strings.xml index 2ae2ad4d4094..81a04b7d83a0 100644 --- a/core/res/res/values-as/strings.xml +++ b/core/res/res/values-as/strings.xml @@ -2008,4 +2008,22 @@ <string name="chooser_no_direct_share_targets" msgid="997970693708458895">"পোনপটীয়া শ্বেয়াৰৰ সুবিধা নাই"</string> <string name="chooser_all_apps_button_label" msgid="3631524352936289457">"এপ্সমূহৰ সূচী"</string> <string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"এই এপ্টোক ৰেকর্ড কৰাৰ অনুমতি দিয়া হোৱা নাই কিন্তু ই এই ইউএছবি ডিভাইচটোৰ জৰিয়তে অডিঅ\' ৰেকর্ড কৰিব পাৰে।"</string> + <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) --> + <skip /> + <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) --> + <skip /> + <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) --> + <skip /> + <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) --> + <skip /> + <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) --> + <skip /> + <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) --> + <skip /> + <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) --> + <skip /> + <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) --> + <skip /> + <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) --> + <skip /> </resources> diff --git a/core/res/res/values-az/strings.xml b/core/res/res/values-az/strings.xml index 2f8cd996f565..9f43c36876c0 100644 --- a/core/res/res/values-az/strings.xml +++ b/core/res/res/values-az/strings.xml @@ -1771,10 +1771,8 @@ <string name="package_updated_device_owner" msgid="1847154566357862089">"Admin tərəfindən yeniləndi"</string> <string name="package_deleted_device_owner" msgid="2307122077550236438">"Admin tərəfindən silindi"</string> <string name="confirm_battery_saver" msgid="639106420541753635">"OK"</string> - <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) --> - <skip /> - <!-- no translation found for battery_saver_description (2307555792915978653) --> - <skip /> + <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"Batareyanın ömrünü artırmaq üçün Enerjiyə Qənaət xüsusiyyəti:\n·Qaranlıq temanı aktiv edir\n·Arxa fondakı fəaliyyəti, bəzi vizual effektləri və “Hey Google” kimi digər xüsusiyyətləri deaktiv edir və ya məhdudlaşdırır\n\n"<annotation id="url">"Ətraflı məlumat"</annotation></string> + <string name="battery_saver_description" msgid="2307555792915978653">"Batareyanın ömrünü artırmaq üçün Enerjiyə Qənaət xüsusiyyəti:\n·Qaranlıq temanı aktiv edir\n·Arxa fondakı fəaliyyəti, bəzi vizual effektləri və “Hey Google” kimi digər xüsusiyyətləri deaktiv edir və ya məhdudlaşdırır"</string> <string name="data_saver_description" msgid="6015391409098303235">"Data istifadəsini azalatmaq üçün, Data Qanaəti bəzi tətbiqlərin arxafonda data göndərməsini və qəbulunun qarşısını alır. Hazırda istifadə etdiyiniz tətbiq dataya daxil ola bilər, lakin bunu tez-tez edə bilməz. Bu o deməkdir ki, məsələn, Siz üzərinə tıklamadıqca o şəkillər göstərilməyəcək."</string> <string name="data_saver_enable_title" msgid="4674073932722787417">"Data Qənaəti aktiv edilsin?"</string> <string name="data_saver_enable_button" msgid="7147735965247211818">"Aktivləşdirin"</string> @@ -2008,4 +2006,22 @@ <string name="chooser_no_direct_share_targets" msgid="997970693708458895">"Birbaşa paylaşım əlçatan deyil"</string> <string name="chooser_all_apps_button_label" msgid="3631524352936289457">"Tətbiq siyahısı"</string> <string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"Bu tətbiqə yazmaq icazəsi verilməyib, lakin, bu USB vasitəsilə səs yaza bilər."</string> + <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) --> + <skip /> + <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) --> + <skip /> + <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) --> + <skip /> + <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) --> + <skip /> + <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) --> + <skip /> + <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) --> + <skip /> + <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) --> + <skip /> + <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) --> + <skip /> + <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) --> + <skip /> </resources> diff --git a/core/res/res/values-b+sr+Latn/strings.xml b/core/res/res/values-b+sr+Latn/strings.xml index 9c1375822d12..a6ad7331c1d9 100644 --- a/core/res/res/values-b+sr+Latn/strings.xml +++ b/core/res/res/values-b+sr+Latn/strings.xml @@ -1794,10 +1794,8 @@ <string name="package_updated_device_owner" msgid="1847154566357862089">"Ažurirao je administrator"</string> <string name="package_deleted_device_owner" msgid="2307122077550236438">"Izbrisao je administrator"</string> <string name="confirm_battery_saver" msgid="639106420541753635">"Potvrdi"</string> - <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) --> - <skip /> - <!-- no translation found for battery_saver_description (2307555792915978653) --> - <skip /> + <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"Radi dužeg trajanja baterije, ušteda baterije:\n·uključuje tamnu temu\n·isključuje ili ograničava aktivnosti u pozadini, neke vizuelne efekte i druge funkcije, na primer, „Ok Google“\n\n"<annotation id="url">"Saznajte više"</annotation></string> + <string name="battery_saver_description" msgid="2307555792915978653">"Radi dužeg trajanja baterije, ušteda baterije:\n·uključuje tamnu temu\n·isključuje ili ograničava aktivnosti u pozadini, neke vizuelne efekte i druge funkcije, na primer, „Ok Google“"</string> <string name="data_saver_description" msgid="6015391409098303235">"Da bi se smanjila potrošnja podataka, Ušteda podataka sprečava neke aplikacije da šalju ili primaju podatke u pozadini. Aplikacija koju trenutno koristite može da pristupa podacima, ali će to činiti ređe. Na primer, slike se neće prikazivati dok ih ne dodirnete."</string> <string name="data_saver_enable_title" msgid="4674073932722787417">"Uključiti Uštedu podataka?"</string> <string name="data_saver_enable_button" msgid="7147735965247211818">"Uključi"</string> @@ -2042,4 +2040,22 @@ <string name="chooser_no_direct_share_targets" msgid="997970693708458895">"Direktno deljenje nije dostupno"</string> <string name="chooser_all_apps_button_label" msgid="3631524352936289457">"Lista aplikacija"</string> <string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"Ova aplikacija nema dozvolu za snimanje, ali bi mogla da snima zvuk pomoću ovog USB uređaja."</string> + <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) --> + <skip /> + <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) --> + <skip /> + <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) --> + <skip /> + <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) --> + <skip /> + <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) --> + <skip /> + <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) --> + <skip /> + <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) --> + <skip /> + <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) --> + <skip /> + <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) --> + <skip /> </resources> diff --git a/core/res/res/values-be/strings.xml b/core/res/res/values-be/strings.xml index 48ca6df7526d..92cad08ad093 100644 --- a/core/res/res/values-be/strings.xml +++ b/core/res/res/values-be/strings.xml @@ -1817,10 +1817,8 @@ <string name="package_updated_device_owner" msgid="1847154566357862089">"Абноўлены вашым адміністратарам"</string> <string name="package_deleted_device_owner" msgid="2307122077550236438">"Выдалены вашым адміністратарам"</string> <string name="confirm_battery_saver" msgid="639106420541753635">"ОК"</string> - <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) --> - <skip /> - <!-- no translation found for battery_saver_description (2307555792915978653) --> - <skip /> + <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"Каб павялічыць тэрмін службы акумулятара, рэжым эканоміі зараду:\n·уключае цёмную тэму;\n·выключае ці абмяжоўвае дзеянні ў фонавым рэжыме, некаторыя візуальныя эфекты і іншыя функцыі, напрыклад \"Ok Google\"\n\n"<annotation id="url">"Даведацца больш"</annotation></string> + <string name="battery_saver_description" msgid="2307555792915978653">"Каб павялічыць тэрмін службы акумулятара, рэжым эканоміі зараду:\n·уключае цёмную тэму;\n·выключае ці абмяжоўвае дзеянні ў фонавым рэжыме, некаторыя візуальныя эфекты і іншыя функцыі, напрыклад \"Ok Google\""</string> <string name="data_saver_description" msgid="6015391409098303235">"У рэжыме Эканомія трафіка фонавая перадача для некаторых праграмам адключана. Праграма, якую вы зараз выкарыстоўваеце, можа атрымліваць доступ да даных, але радзей, чым звычайна. Напрыклад, відарысы могуць не загружацца, пакуль вы не націсніце на іх."</string> <string name="data_saver_enable_title" msgid="4674073932722787417">"Уключыць Эканомію трафіка?"</string> <string name="data_saver_enable_button" msgid="7147735965247211818">"Уключыць"</string> @@ -2076,4 +2074,22 @@ <string name="chooser_no_direct_share_targets" msgid="997970693708458895">"Непасрэднае абагульванне недаступнае"</string> <string name="chooser_all_apps_button_label" msgid="3631524352936289457">"Спіс праграм"</string> <string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"У гэтай праграмы няма дазволу на запіс, аднак яна зможа запісваць аўдыя праз гэту USB-прыладу."</string> + <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) --> + <skip /> + <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) --> + <skip /> + <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) --> + <skip /> + <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) --> + <skip /> + <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) --> + <skip /> + <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) --> + <skip /> + <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) --> + <skip /> + <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) --> + <skip /> + <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) --> + <skip /> </resources> diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml index 1d6e7f1324f7..9a4ca0cff046 100644 --- a/core/res/res/values-bg/strings.xml +++ b/core/res/res/values-bg/strings.xml @@ -1771,10 +1771,8 @@ <string name="package_updated_device_owner" msgid="1847154566357862089">"Актуализирано от администратора ви"</string> <string name="package_deleted_device_owner" msgid="2307122077550236438">"Изтрито от администратора ви"</string> <string name="confirm_battery_saver" msgid="639106420541753635">"ОК"</string> - <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) --> - <skip /> - <!-- no translation found for battery_saver_description (2307555792915978653) --> - <skip /> + <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"С цел удължаване на живота на батерията режимът за запазването й:\n·включва тъмната тема;\n·изключва или ограничава активността на заден план, някои визуални ефекти и други функции, като например „Ok Google“.\n\n"<annotation id="url">"Научете повече"</annotation></string> + <string name="battery_saver_description" msgid="2307555792915978653">"С цел удължаване на живота на батерията режимът за запазването й:\n·включва тъмната тема;\n·изключва или ограничава активността на заден план, някои визуални ефекти и други функции, като например „Ok Google“."</string> <string name="data_saver_description" msgid="6015391409098303235">"С цел намаляване на преноса на данни функцията за икономия на данни не позволява на някои приложения да изпращат или получават данни на заден план. Понастоящем използвано от вас приложение може да използва данни, но по-рядко. Това например може да означава, че изображенията не се показват, докато не ги докоснете."</string> <string name="data_saver_enable_title" msgid="4674073932722787417">"Ще вкл. ли Икономия на данни?"</string> <string name="data_saver_enable_button" msgid="7147735965247211818">"Включване"</string> @@ -2008,4 +2006,22 @@ <string name="chooser_no_direct_share_targets" msgid="997970693708458895">"Няма възможност за директно споделяне"</string> <string name="chooser_all_apps_button_label" msgid="3631524352936289457">"Списък с приложения"</string> <string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"Приложението няма разрешение за записване, но може да записва звук чрез това USB устройство."</string> + <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) --> + <skip /> + <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) --> + <skip /> + <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) --> + <skip /> + <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) --> + <skip /> + <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) --> + <skip /> + <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) --> + <skip /> + <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) --> + <skip /> + <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) --> + <skip /> + <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) --> + <skip /> </resources> diff --git a/core/res/res/values-bn/strings.xml b/core/res/res/values-bn/strings.xml index bdb5572450b6..4dc5f5c897ce 100644 --- a/core/res/res/values-bn/strings.xml +++ b/core/res/res/values-bn/strings.xml @@ -1771,10 +1771,8 @@ <string name="package_updated_device_owner" msgid="1847154566357862089">"আপনার প্রশাসক আপডেট করেছেন"</string> <string name="package_deleted_device_owner" msgid="2307122077550236438">"আপনার প্রশাসক মুছে দিয়েছেন"</string> <string name="confirm_battery_saver" msgid="639106420541753635">"ঠিক আছে"</string> - <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) --> - <skip /> - <!-- no translation found for battery_saver_description (2307555792915978653) --> - <skip /> + <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"ব্যাটারি আরও বেশিক্ষণ চালাতে, ব্যাটারি সেভার:\n·গাঢ় থিম চালু করে\n·ব্যাকগ্রাউন্ড অ্যাক্টিভিটি, কিছু ভিজ্যুয়াল এফেক্ট, এবং “হ্যালো Google”-এর মতো অন্যান্য ফিচার বন্ধ বা সীমাবদ্ধ করে\n\n"<annotation id="url">"আরও জানুন"</annotation></string> + <string name="battery_saver_description" msgid="2307555792915978653">"ব্যাটারি আরও বেশিক্ষণ চালাতে, ব্যাটারি সেভার:\n·গাঢ় থিম চালু করে\n·ব্যাকগ্রাউন্ড অ্যাক্টিভিটি, কিছু ভিজ্যুয়াল এফেক্ট, এবং “হ্যালো Google”-এর মতো অন্যান্য ফিচার বন্ধ বা সীমাবদ্ধ করে"</string> <string name="data_saver_description" msgid="6015391409098303235">"ডেটার ব্যবহার কমাতে সহায়তা করার জন্য, ডেটা সেভার ব্যাকগ্রাউন্ডে কিছু অ্যাপ্লিকেশনকে ডেটা পাঠাতে বা গ্রহণ করতে বাধা দেয়৷ আপনি বর্তমানে এমন একটি অ্যাপ্লিকেশন ব্যবহার করছেন যেটি ডেটা অ্যাক্সেস করতে পারে, তবে সেটি কমই করে৷ এর ফলে যা হতে পারে, উদাহরণস্বরূপ, আপনি ছবির উপর ট্যাপ না করা পর্যন্ত সেগুলি দেখানো হবে না৷"</string> <string name="data_saver_enable_title" msgid="4674073932722787417">"ডেটা সেভার চালু করবেন?"</string> <string name="data_saver_enable_button" msgid="7147735965247211818">"চালু করুন"</string> @@ -2008,4 +2006,22 @@ <string name="chooser_no_direct_share_targets" msgid="997970693708458895">"সরাসরি শেয়ার করার সুবিধা নেই"</string> <string name="chooser_all_apps_button_label" msgid="3631524352936289457">"অ্যাপের তালিকা"</string> <string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"এই অ্যাপকে রেকর্ড করার অনুমতি দেওয়া হয়নি কিন্তু USB ডিভাইসের মাধ্যমে সেটি অডিও রেকর্ড করতে পারে।"</string> + <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) --> + <skip /> + <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) --> + <skip /> + <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) --> + <skip /> + <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) --> + <skip /> + <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) --> + <skip /> + <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) --> + <skip /> + <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) --> + <skip /> + <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) --> + <skip /> + <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) --> + <skip /> </resources> diff --git a/core/res/res/values-bs/strings.xml b/core/res/res/values-bs/strings.xml index 03a4cc5a7457..ea4d20965f29 100644 --- a/core/res/res/values-bs/strings.xml +++ b/core/res/res/values-bs/strings.xml @@ -1796,10 +1796,8 @@ <string name="package_updated_device_owner" msgid="1847154566357862089">"Ažurirao je vaš administrator"</string> <string name="package_deleted_device_owner" msgid="2307122077550236438">"Izbrisao je vaš administrator"</string> <string name="confirm_battery_saver" msgid="639106420541753635">"Uredu"</string> - <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) --> - <skip /> - <!-- no translation found for battery_saver_description (2307555792915978653) --> - <skip /> + <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"Da bi se produljilo trajanje baterije, Štednja baterije:\n·Uključuje Tamnu temu.\n·Isključuje ili ograničava aktivnosti u pozadini, neke vizualne efekte i druge značajke kao što je \"Hey Google\".\n\n"<annotation id="url">"Saznajte više"</annotation></string> + <string name="battery_saver_description" msgid="2307555792915978653">"Da bi se produljilo trajanje baterije, Štednja baterije:\n·Uključuje Tamnu temu.\n·Isključuje ili ograničava aktivnosti u pozadini, neke vizualne efekte i druge značajke kao što je \"Hey Google\"."</string> <string name="data_saver_description" msgid="6015391409098303235">"Da bi se smanjio prijenos podataka, Ušteda podataka sprečava da neke aplikacije šalju ili primaju podatke u pozadini. Aplikacija koju trenutno koristite može pristupiti podacima, ali će to činiti rjeđe. To može značiti, naprimjer, da se slike ne prikazuju sve dok ih ne dodirnete."</string> <string name="data_saver_enable_title" msgid="4674073932722787417">"Uključiti Uštedu podataka?"</string> <string name="data_saver_enable_button" msgid="7147735965247211818">"Uključi"</string> @@ -2044,4 +2042,22 @@ <string name="chooser_no_direct_share_targets" msgid="997970693708458895">"Direktno dijeljenje nije dostupno"</string> <string name="chooser_all_apps_button_label" msgid="3631524352936289457">"Spisak aplikacija"</string> <string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"Ovoj aplikaciji nije dato odobrenje za snimanje, ali može snimati zvuk putem ovog USB uređaja."</string> + <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) --> + <skip /> + <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) --> + <skip /> + <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) --> + <skip /> + <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) --> + <skip /> + <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) --> + <skip /> + <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) --> + <skip /> + <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) --> + <skip /> + <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) --> + <skip /> + <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) --> + <skip /> </resources> diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml index fd076686089a..4f9eeb8108ee 100644 --- a/core/res/res/values-ca/strings.xml +++ b/core/res/res/values-ca/strings.xml @@ -1771,10 +1771,8 @@ <string name="package_updated_device_owner" msgid="1847154566357862089">"Actualitzat per l\'administrador"</string> <string name="package_deleted_device_owner" msgid="2307122077550236438">"Suprimit per l\'administrador"</string> <string name="confirm_battery_saver" msgid="639106420541753635">"D\'acord"</string> - <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) --> - <skip /> - <!-- no translation found for battery_saver_description (2307555792915978653) --> - <skip /> + <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"Per allargar la durada de la bateria, el mode Estalvi de bateria fa el següent:\n Activa el tema fosc\n Desactiva o restringeix l\'activitat en segon pla, alguns efectes visuals i altres funcions com \"Ok Google\"\n\n"<annotation id="url">"Més informació"</annotation></string> + <string name="battery_saver_description" msgid="2307555792915978653">"Per allargar la durada de la bateria, el mode Estalvi de bateria fa el següent:\n Activa el tema fosc\n Desactiva o restringeix l\'activitat en segon pla, alguns efectes visuals i altres funcions com \"Ok Google\""</string> <string name="data_saver_description" msgid="6015391409098303235">"Per reduir l\'ús de dades, la funció Economitzador de dades evita que determinades aplicacions enviïn o rebin dades en segon pla. L\'aplicació que estiguis fent servir podrà accedir a les dades, però menys sovint. Això vol dir, per exemple, que les imatges no es mostraran fins que no les toquis."</string> <string name="data_saver_enable_title" msgid="4674073932722787417">"Activar Economitzador de dades?"</string> <string name="data_saver_enable_button" msgid="7147735965247211818">"Activa"</string> @@ -2008,4 +2006,22 @@ <string name="chooser_no_direct_share_targets" msgid="997970693708458895">"La compartició directa no està disponible"</string> <string name="chooser_all_apps_button_label" msgid="3631524352936289457">"Llista d\'aplicacions"</string> <string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"Aquesta aplicació no té permís de gravació, però pot capturar àudio a través d\'aquest dispositiu USB."</string> + <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) --> + <skip /> + <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) --> + <skip /> + <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) --> + <skip /> + <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) --> + <skip /> + <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) --> + <skip /> + <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) --> + <skip /> + <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) --> + <skip /> + <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) --> + <skip /> + <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) --> + <skip /> </resources> diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml index e2f03df8ad25..502a7a8d1961 100644 --- a/core/res/res/values-cs/strings.xml +++ b/core/res/res/values-cs/strings.xml @@ -1817,10 +1817,8 @@ <string name="package_updated_device_owner" msgid="1847154566357862089">"Aktualizováno administrátorem"</string> <string name="package_deleted_device_owner" msgid="2307122077550236438">"Smazáno administrátorem"</string> <string name="confirm_battery_saver" msgid="639106420541753635">"OK"</string> - <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) --> - <skip /> - <!-- no translation found for battery_saver_description (2307555792915978653) --> - <skip /> + <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"Spořič baterie za účelem úspory energie:\n·zapne tmavý motiv,\n·vypne nebo omezí aktivitu na pozadí, některé vizuální efekty a další funkce jako „Hej Google“\n\n"<annotation id="url">"Další informace"</annotation></string> + <string name="battery_saver_description" msgid="2307555792915978653">"Spořič baterie za účelem úspory energie:\n·zapne tmavý motiv,\n·vypne nebo omezí aktivitu na pozadí, některé vizuální efekty a další funkce jako „Hej Google“"</string> <string name="data_saver_description" msgid="6015391409098303235">"Spořič dat z důvodu snížení využití dat některým aplikacím brání v odesílání nebo příjmu dat na pozadí. Aplikace, kterou právě používáte, data přenášet může, ale může tak činit méně často. V důsledku toho se například obrázky nemusejí zobrazit, dokud na ně neklepnete."</string> <string name="data_saver_enable_title" msgid="4674073932722787417">"Chcete zapnout Spořič dat?"</string> <string name="data_saver_enable_button" msgid="7147735965247211818">"Zapnout"</string> @@ -2076,4 +2074,22 @@ <string name="chooser_no_direct_share_targets" msgid="997970693708458895">"Přímé sdílení není k dispozici"</string> <string name="chooser_all_apps_button_label" msgid="3631524352936289457">"Seznam aplikací"</string> <string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"Tato aplikace nemá oprávnění k nahrávání, ale může zaznamenávat zvuk prostřednictvím tohoto zařízení USB."</string> + <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) --> + <skip /> + <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) --> + <skip /> + <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) --> + <skip /> + <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) --> + <skip /> + <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) --> + <skip /> + <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) --> + <skip /> + <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) --> + <skip /> + <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) --> + <skip /> + <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) --> + <skip /> </resources> diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml index 3916f1e1523f..d347e357c4ae 100644 --- a/core/res/res/values-da/strings.xml +++ b/core/res/res/values-da/strings.xml @@ -1771,10 +1771,8 @@ <string name="package_updated_device_owner" msgid="1847154566357862089">"Opdateret af din administrator"</string> <string name="package_deleted_device_owner" msgid="2307122077550236438">"Slettet af din administrator"</string> <string name="confirm_battery_saver" msgid="639106420541753635">"OK"</string> - <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) --> - <skip /> - <!-- no translation found for battery_saver_description (2307555792915978653) --> - <skip /> + <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"Batterisparefunktionen gør følgende for at spare på batteriet:\n·Aktiverer Mørkt tema\n·Deaktiverer eller begrænser aktivitet i baggrunden, visse visuelle effekter og andre funktioner som f.eks. \"Hey Google\"\n\n"<annotation id="url">"Få flere oplysninger"</annotation></string> + <string name="battery_saver_description" msgid="2307555792915978653">"Batterisparefunktionen gør følgende for at spare på batteriet:\n·Aktiverer Mørkt tema\n·Deaktiverer eller begrænser aktivitet i baggrunden, visse visuelle effekter og andre funktioner som f.eks. \"Hey Google\""</string> <string name="data_saver_description" msgid="6015391409098303235">"Datasparefunktionen forhindrer nogle apps i at sende eller modtage data i baggrunden for at reducere dataforbruget. En app, der er i brug, kan få adgang til data, men gør det måske ikke så ofte. Dette kan f.eks. betyde, at billeder ikke vises, før du trykker på dem."</string> <string name="data_saver_enable_title" msgid="4674073932722787417">"Vil du slå Datasparefunktion til?"</string> <string name="data_saver_enable_button" msgid="7147735965247211818">"Slå til"</string> @@ -2008,4 +2006,22 @@ <string name="chooser_no_direct_share_targets" msgid="997970693708458895">"Det er ikke muligt at dele direkte"</string> <string name="chooser_all_apps_button_label" msgid="3631524352936289457">"Liste over apps"</string> <string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"Denne app har ikke fået tilladelse til at optage, men optager muligvis lyd via denne USB-enhed."</string> + <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) --> + <skip /> + <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) --> + <skip /> + <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) --> + <skip /> + <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) --> + <skip /> + <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) --> + <skip /> + <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) --> + <skip /> + <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) --> + <skip /> + <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) --> + <skip /> + <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) --> + <skip /> </resources> diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml index 9635b2db35c7..b4b40eabd859 100644 --- a/core/res/res/values-de/strings.xml +++ b/core/res/res/values-de/strings.xml @@ -2008,4 +2008,22 @@ <string name="chooser_no_direct_share_targets" msgid="997970693708458895">"Direct Share nicht verfügbar"</string> <string name="chooser_all_apps_button_label" msgid="3631524352936289457">"Liste der Apps"</string> <string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"Diese App hat noch keine Berechtigung zum Aufnehmen erhalten, könnte aber Audioaufnahmen über dieses USB-Gerät machen."</string> + <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) --> + <skip /> + <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) --> + <skip /> + <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) --> + <skip /> + <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) --> + <skip /> + <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) --> + <skip /> + <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) --> + <skip /> + <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) --> + <skip /> + <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) --> + <skip /> + <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) --> + <skip /> </resources> diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml index 2766ce4de52b..73828a1296df 100644 --- a/core/res/res/values-el/strings.xml +++ b/core/res/res/values-el/strings.xml @@ -1771,10 +1771,8 @@ <string name="package_updated_device_owner" msgid="1847154566357862089">"Ενημερώθηκε από τον διαχειριστή σας"</string> <string name="package_deleted_device_owner" msgid="2307122077550236438">"Διαγράφηκε από τον διαχειριστή σας"</string> <string name="confirm_battery_saver" msgid="639106420541753635">"OK"</string> - <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) --> - <skip /> - <!-- no translation found for battery_saver_description (2307555792915978653) --> - <skip /> + <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"Για την επέκταση της διάρκειας ζωής της μπαταρίας σας, η Εξοικονόμηση μπαταρίας:\n·Ενεργοποιεί το Σκούρο θέμα\n·Απενεργοποιεί ή περιορίζει τη δραστηριότητα παρασκηνίου, ορισμένα οπτικά εφέ και άλλες λειτουργίες όπως την εντολή \"Hey Google\".\n\n"<annotation id="url">"Μάθετε περισσότερα"</annotation></string> + <string name="battery_saver_description" msgid="2307555792915978653">"Για την επέκταση της διάρκειας ζωής της μπαταρίας σας, η Εξοικονόμηση μπαταρίας:\n·Ενεργοποιεί το Σκούρο θέμα\n·Απενεργοποιεί ή περιορίζει τη δραστηριότητα παρασκηνίου, ορισμένα οπτικά εφέ και άλλες λειτουργίες όπως την εντολή \"Hey Google\"."</string> <string name="data_saver_description" msgid="6015391409098303235">"Προκειμένου να μειωθεί η χρήση δεδομένων, η Εξοικονόμηση δεδομένων αποτρέπει την αποστολή ή λήψη δεδομένων από ορισμένες εφαρμογές στο παρασκήνιο. Μια εφαρμογή που χρησιμοποιείτε αυτήν τη στιγμή μπορεί να χρησιμοποιήσει δεδομένα αλλά με μικρότερη συχνότητα. Για παράδειγμα, οι εικόνες μπορεί να μην εμφανίζονται μέχρι να τις πατήσετε."</string> <string name="data_saver_enable_title" msgid="4674073932722787417">"Ενεργ.Εξοικονόμησης δεδομένων;"</string> <string name="data_saver_enable_button" msgid="7147735965247211818">"Ενεργοποίηση"</string> @@ -2008,4 +2006,22 @@ <string name="chooser_no_direct_share_targets" msgid="997970693708458895">"Η άμεση κοινοποίηση δεν είναι διαθέσιμη"</string> <string name="chooser_all_apps_button_label" msgid="3631524352936289457">"Λίστα εφαρμογών"</string> <string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"Δεν έχει εκχωρηθεί άδεια εγγραφής σε αυτήν την εφαρμογή, αλλά μέσω αυτής της συσκευής USB θα μπορεί να εγγράφει ήχο."</string> + <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) --> + <skip /> + <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) --> + <skip /> + <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) --> + <skip /> + <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) --> + <skip /> + <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) --> + <skip /> + <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) --> + <skip /> + <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) --> + <skip /> + <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) --> + <skip /> + <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) --> + <skip /> </resources> diff --git a/core/res/res/values-en-rAU/strings.xml b/core/res/res/values-en-rAU/strings.xml index dba13539b799..9163214f0204 100644 --- a/core/res/res/values-en-rAU/strings.xml +++ b/core/res/res/values-en-rAU/strings.xml @@ -2006,4 +2006,22 @@ <string name="chooser_no_direct_share_targets" msgid="997970693708458895">"Direct share not available"</string> <string name="chooser_all_apps_button_label" msgid="3631524352936289457">"Apps list"</string> <string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"This app has not been granted record permission but could capture audio through this USB device."</string> + <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) --> + <skip /> + <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) --> + <skip /> + <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) --> + <skip /> + <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) --> + <skip /> + <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) --> + <skip /> + <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) --> + <skip /> + <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) --> + <skip /> + <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) --> + <skip /> + <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) --> + <skip /> </resources> diff --git a/core/res/res/values-en-rCA/strings.xml b/core/res/res/values-en-rCA/strings.xml index 4ecafc99f51d..dff558f545c3 100644 --- a/core/res/res/values-en-rCA/strings.xml +++ b/core/res/res/values-en-rCA/strings.xml @@ -2006,4 +2006,22 @@ <string name="chooser_no_direct_share_targets" msgid="997970693708458895">"Direct share not available"</string> <string name="chooser_all_apps_button_label" msgid="3631524352936289457">"Apps list"</string> <string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"This app has not been granted record permission but could capture audio through this USB device."</string> + <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) --> + <skip /> + <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) --> + <skip /> + <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) --> + <skip /> + <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) --> + <skip /> + <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) --> + <skip /> + <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) --> + <skip /> + <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) --> + <skip /> + <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) --> + <skip /> + <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) --> + <skip /> </resources> diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml index dba13539b799..9163214f0204 100644 --- a/core/res/res/values-en-rGB/strings.xml +++ b/core/res/res/values-en-rGB/strings.xml @@ -2006,4 +2006,22 @@ <string name="chooser_no_direct_share_targets" msgid="997970693708458895">"Direct share not available"</string> <string name="chooser_all_apps_button_label" msgid="3631524352936289457">"Apps list"</string> <string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"This app has not been granted record permission but could capture audio through this USB device."</string> + <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) --> + <skip /> + <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) --> + <skip /> + <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) --> + <skip /> + <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) --> + <skip /> + <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) --> + <skip /> + <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) --> + <skip /> + <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) --> + <skip /> + <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) --> + <skip /> + <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) --> + <skip /> </resources> diff --git a/core/res/res/values-en-rIN/strings.xml b/core/res/res/values-en-rIN/strings.xml index dba13539b799..9163214f0204 100644 --- a/core/res/res/values-en-rIN/strings.xml +++ b/core/res/res/values-en-rIN/strings.xml @@ -2006,4 +2006,22 @@ <string name="chooser_no_direct_share_targets" msgid="997970693708458895">"Direct share not available"</string> <string name="chooser_all_apps_button_label" msgid="3631524352936289457">"Apps list"</string> <string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"This app has not been granted record permission but could capture audio through this USB device."</string> + <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) --> + <skip /> + <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) --> + <skip /> + <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) --> + <skip /> + <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) --> + <skip /> + <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) --> + <skip /> + <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) --> + <skip /> + <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) --> + <skip /> + <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) --> + <skip /> + <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) --> + <skip /> </resources> diff --git a/core/res/res/values-en-rXC/strings.xml b/core/res/res/values-en-rXC/strings.xml index 331133a17778..7519ad62b9f3 100644 --- a/core/res/res/values-en-rXC/strings.xml +++ b/core/res/res/values-en-rXC/strings.xml @@ -2006,4 +2006,13 @@ <string name="chooser_no_direct_share_targets" msgid="997970693708458895">"Direct share not available"</string> <string name="chooser_all_apps_button_label" msgid="3631524352936289457">"Apps list"</string> <string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"This app has not been granted record permission but could capture audio through this USB device."</string> + <string name="accessibility_system_action_home_label" msgid="6089400419441597916">"Home"</string> + <string name="accessibility_system_action_back_label" msgid="8986628898117178971">"Back"</string> + <string name="accessibility_system_action_recents_label" msgid="7607601657790855723">"Recent Apps"</string> + <string name="accessibility_system_action_notifications_label" msgid="1578681904050072545">"Notifications"</string> + <string name="accessibility_system_action_quick_settings_label" msgid="3885565587471448947">"Quick Settings"</string> + <string name="accessibility_system_action_power_dialog_label" msgid="2299530700682199873">"Power Dialog"</string> + <string name="accessibility_system_action_toggle_split_screen_label" msgid="2853334443686935668">"Toggle Split Screen"</string> + <string name="accessibility_system_action_lock_screen_label" msgid="2377933717780192594">"Lock Screen"</string> + <string name="accessibility_system_action_screenshot_label" msgid="1933564892301816480">"Screenshot"</string> </resources> diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml index f5fc14532acd..038124993179 100644 --- a/core/res/res/values-es-rUS/strings.xml +++ b/core/res/res/values-es-rUS/strings.xml @@ -1771,10 +1771,8 @@ <string name="package_updated_device_owner" msgid="1847154566357862089">"Tu administrador actualizó este paquete"</string> <string name="package_deleted_device_owner" msgid="2307122077550236438">"Tu administrador borró este paquete"</string> <string name="confirm_battery_saver" msgid="639106420541753635">"Aceptar"</string> - <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) --> - <skip /> - <!-- no translation found for battery_saver_description (2307555792915978653) --> - <skip /> + <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"Para extender la duración de batería, el Ahorro de batería hace lo siguiente:\n·Activa el Tema oscuro.\n·Desactiva o restringe la actividad en segundo plano, algunos efectos visuales y otras funciones, como \"Ok Google\".\n\n"<annotation id="url">"Más información"</annotation></string> + <string name="battery_saver_description" msgid="2307555792915978653">"Para extender la duración de batería, el Ahorro de batería hace lo siguiente:\n·Activa el Tema oscuro.\n·Desactiva o restringe la actividad en segundo plano, algunos efectos visuales y otras funciones, como \"Ok Google\"."</string> <string name="data_saver_description" msgid="6015391409098303235">"Para reducir el uso de datos, Ahorro de datos evita que algunas apps envíen y reciban datos en segundo plano. La app que estés usando podrá acceder a los datos, pero con menor frecuencia. De esta forma, por ejemplo, las imágenes no se mostrarán hasta que las presiones."</string> <string name="data_saver_enable_title" msgid="4674073932722787417">"¿Activar Ahorro de datos?"</string> <string name="data_saver_enable_button" msgid="7147735965247211818">"Activar"</string> @@ -2008,4 +2006,22 @@ <string name="chooser_no_direct_share_targets" msgid="997970693708458895">"No está disponible el uso compartido directo"</string> <string name="chooser_all_apps_button_label" msgid="3631524352936289457">"Lista de apps"</string> <string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"Aunque no se le otorgó permiso de grabación a esta app, puede capturar audio con este dispositivo USB."</string> + <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) --> + <skip /> + <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) --> + <skip /> + <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) --> + <skip /> + <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) --> + <skip /> + <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) --> + <skip /> + <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) --> + <skip /> + <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) --> + <skip /> + <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) --> + <skip /> + <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) --> + <skip /> </resources> diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml index cfac5dc97add..7f152e1e4e1c 100644 --- a/core/res/res/values-es/strings.xml +++ b/core/res/res/values-es/strings.xml @@ -1771,10 +1771,8 @@ <string name="package_updated_device_owner" msgid="1847154566357862089">"Actualizado por el administrador"</string> <string name="package_deleted_device_owner" msgid="2307122077550236438">"Eliminado por el administrador"</string> <string name="confirm_battery_saver" msgid="639106420541753635">"Aceptar"</string> - <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) --> - <skip /> - <!-- no translation found for battery_saver_description (2307555792915978653) --> - <skip /> + <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"Para que la batería dure más, Ahorro de batería:\nActiva el tema oscuro\nDesactiva o restringe actividad en segundo plano, algunos efectos visuales y otras funciones como \"Ok Google\"\n\n"<annotation id="url">"Más información"</annotation></string> + <string name="battery_saver_description" msgid="2307555792915978653">"Para que la batería dure más, Ahorro de batería:\nActiva el tema oscuro\nDesactiva o restringe actividad en segundo plano, algunos efectos visuales y otras funciones como \"Ok Google\""</string> <string name="data_saver_description" msgid="6015391409098303235">"El ahorro de datos evita que algunas aplicaciones envíen o reciban datos en segundo plano, lo que permite reducir el uso de datos. Una aplicación activa podrá acceder a los datos, aunque con menos frecuencia. Esto significa que, por ejemplo, algunas imágenes no se mostrarán hasta que las toques."</string> <string name="data_saver_enable_title" msgid="4674073932722787417">"¿Activar ahorro de datos?"</string> <string name="data_saver_enable_button" msgid="7147735965247211818">"Activar"</string> @@ -2008,4 +2006,22 @@ <string name="chooser_no_direct_share_targets" msgid="997970693708458895">"No se puede compartir directamente"</string> <string name="chooser_all_apps_button_label" msgid="3631524352936289457">"Lista de aplicaciones"</string> <string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"Esta aplicación no tiene permiso para grabar, pero podría registrar audio con este dispositivo USB."</string> + <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) --> + <skip /> + <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) --> + <skip /> + <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) --> + <skip /> + <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) --> + <skip /> + <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) --> + <skip /> + <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) --> + <skip /> + <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) --> + <skip /> + <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) --> + <skip /> + <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) --> + <skip /> </resources> diff --git a/core/res/res/values-et/strings.xml b/core/res/res/values-et/strings.xml index 8193339615ae..a48c4829b30c 100644 --- a/core/res/res/values-et/strings.xml +++ b/core/res/res/values-et/strings.xml @@ -1771,10 +1771,8 @@ <string name="package_updated_device_owner" msgid="1847154566357862089">"Administraator on seda värskendanud"</string> <string name="package_deleted_device_owner" msgid="2307122077550236438">"Administraator on selle kustutanud"</string> <string name="confirm_battery_saver" msgid="639106420541753635">"OK"</string> - <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) --> - <skip /> - <!-- no translation found for battery_saver_description (2307555792915978653) --> - <skip /> + <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"Aku tööea pikendamiseks teeb akusäästja järgmist.\n·Lülitab sisse tumeda teema.\n·Lülitab välja akusäästja taustategevused, mõned visuaalsed efektid ja muud funktsioonid (nt „Hei Google”) või piirab neid.\n\n"<annotation id="url">"Lisateave"</annotation></string> + <string name="battery_saver_description" msgid="2307555792915978653">"Aku tööea pikendamiseks teeb akusäästja järgmist.\n·Lülitab sisse tumeda teema.\n·Lülitab välja akusäästja taustategevused, mõned visuaalsed efektid ja muud funktsioonid (nt „Hei Google”) või piirab neid."</string> <string name="data_saver_description" msgid="6015391409098303235">"Andmekasutuse vähendamiseks keelab andmemahu säästja mõne rakenduse puhul andmete taustal saatmise ja vastuvõtmise. Rakendus, mida praegu kasutate, pääseb andmesidele juurde, kuid võib seda teha väiksema sagedusega. Seetõttu võidakse näiteks pildid kuvada alles siis, kui neid puudutate."</string> <string name="data_saver_enable_title" msgid="4674073932722787417">"Lül. andmemahu säästja sisse?"</string> <string name="data_saver_enable_button" msgid="7147735965247211818">"Lülita sisse"</string> @@ -2008,4 +2006,22 @@ <string name="chooser_no_direct_share_targets" msgid="997970693708458895">"Vahetu jagamine ei ole saadaval"</string> <string name="chooser_all_apps_button_label" msgid="3631524352936289457">"Rakenduste loend"</string> <string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"Sellele rakendusele pole antud salvestamise luba, kuid see saab heli jäädvustada selle USB-seadme kaudu."</string> + <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) --> + <skip /> + <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) --> + <skip /> + <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) --> + <skip /> + <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) --> + <skip /> + <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) --> + <skip /> + <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) --> + <skip /> + <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) --> + <skip /> + <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) --> + <skip /> + <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) --> + <skip /> </resources> diff --git a/core/res/res/values-eu/strings.xml b/core/res/res/values-eu/strings.xml index ca79d0525cfa..805df6e97847 100644 --- a/core/res/res/values-eu/strings.xml +++ b/core/res/res/values-eu/strings.xml @@ -70,7 +70,7 @@ <string name="ThreeWCMmi" msgid="9051047170321190368">"Hiru hizlaritako deiak"</string> <string name="RuacMmi" msgid="7827887459138308886">"Nahigabeko dei gogaikarriak ukatzea"</string> <string name="CndMmi" msgid="3116446237081575808">"Deitzailearen zenbakia ematea"</string> - <string name="DndMmi" msgid="1265478932418334331">"Ez molestatu"</string> + <string name="DndMmi" msgid="1265478932418334331">"Ez molestatzeko modua"</string> <string name="CLIRDefaultOnNextCallOn" msgid="429415409145781923">"Deien identifikazio-zerbitzuaren balio lehenetsiak murriztapenak ezartzen ditu. Hurrengo deia: murriztapenekin"</string> <string name="CLIRDefaultOnNextCallOff" msgid="3092918006077864624">"Deien identifikazio-zerbitzuaren balio lehenetsiak murriztapenak ezartzen ditu. Hurrengo deia: murriztapenik gabe"</string> <string name="CLIRDefaultOffNextCallOn" msgid="6179425182856418465">"Deien identifikazio-zerbitzuaren balio lehenetsiak ez du murriztapenik ezartzen. Hurrengo deia: murriztapenekin"</string> @@ -653,8 +653,8 @@ <string name="permdesc_bindCarrierMessagingService" msgid="2762882888502113944">"Operadore baten mezularitza-zerbitzuaren goi-mailako interfazeari lotzea baimentzen die erabiltzaileei. Aplikazio normalek ez lukete inoiz beharko."</string> <string name="permlab_bindCarrierServices" msgid="3233108656245526783">"lotu operadorearen zerbitzuei"</string> <string name="permdesc_bindCarrierServices" msgid="1391552602551084192">"Operadorearen zerbitzuei lotzea baimentzen die titularrei. Aplikazio normalek ez dute baimen hau behar."</string> - <string name="permlab_access_notification_policy" msgid="4247510821662059671">"atzitu \"Ez molestatu\" egoera"</string> - <string name="permdesc_access_notification_policy" msgid="3296832375218749580">"\"Ez molestatu\" konfigurazioa irakurtzeko eta bertan idazteko baimena ematen die aplikazioei."</string> + <string name="permlab_access_notification_policy" msgid="4247510821662059671">"atzitu ez molestatzeko modua"</string> + <string name="permdesc_access_notification_policy" msgid="3296832375218749580">"Ez molestatzeko moduaren konfigurazioa irakurtzeko eta bertan idazteko baimena ematen die aplikazioei."</string> <string name="permlab_startViewPermissionUsage" msgid="5484728591597709944">"hasi ikusteko baimena erabiltzen"</string> <string name="permdesc_startViewPermissionUsage" msgid="4808345878203594428">"Aplikazioaren baimena erabiltzen hasteko baimena ematen die titularrei. Aplikazio normalek ez lukete beharko."</string> <string name="policylab_limitPassword" msgid="4497420728857585791">"Ezarri pasahitzen arauak"</string> @@ -1771,10 +1771,8 @@ <string name="package_updated_device_owner" msgid="1847154566357862089">"Administratzaileak eguneratu du"</string> <string name="package_deleted_device_owner" msgid="2307122077550236438">"Administratzaileak ezabatu du"</string> <string name="confirm_battery_saver" msgid="639106420541753635">"Ados"</string> - <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) --> - <skip /> - <!-- no translation found for battery_saver_description (2307555792915978653) --> - <skip /> + <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"Bateriaren iraupena luzatzeko, erabili Bateria-aurrezlea:\n·Gai iluna aktibatzen du\n Desaktibatu edo murriztu egiten ditu atzeko planoko jarduerak, zenbait efektu bisual eta beste eginbide batzuk, hala nola \"Ok Google\"\n\n"<annotation id="url">"Lortu informazio gehiago"</annotation></string> + <string name="battery_saver_description" msgid="2307555792915978653">"Bateriaren iraupena luzatzeko, erabili Bateria-aurrezlea:\n·Gai iluna aktibatzen du\n Desaktibatu edo murriztu egiten ditu atzeko planoko jarduerak, zenbait efektu bisual eta beste eginbide batzuk, hala nola \"Ok Google\""</string> <string name="data_saver_description" msgid="6015391409098303235">"Datuen erabilera murrizteko, atzeko planoan datuak bidaltzea eta jasotzea galarazten die datu-aurrezleak aplikazio batzuei. Unean erabiltzen ari zaren aplikazioak atzitu egin ahal izango ditu datuak, baina baliteke maiztasun txikiagoarekin atzitzea. Horrela, adibidez, baliteke irudiak ez erakustea haiek sakatu arte."</string> <string name="data_saver_enable_title" msgid="4674073932722787417">"Datu-aurrezlea aktibatu?"</string> <string name="data_saver_enable_button" msgid="7147735965247211818">"Aktibatu"</string> @@ -1813,10 +1811,10 @@ <string name="zen_mode_until" msgid="7336308492289875088">"<xliff:g id="FORMATTEDTIME">%1$s</xliff:g> arte"</string> <string name="zen_mode_alarm" msgid="9128205721301330797">"<xliff:g id="FORMATTEDTIME">%1$s</xliff:g> arte (hurrengo alarma)"</string> <string name="zen_mode_forever" msgid="931849471004038757">"Zuk desaktibatu arte"</string> - <string name="zen_mode_forever_dnd" msgid="3792132696572189081">"\"Ez molestatu\" desaktibatzen duzun arte"</string> + <string name="zen_mode_forever_dnd" msgid="3792132696572189081">"Ez molestatzeko modua desaktibatzen duzun arte"</string> <string name="zen_mode_rule_name_combination" msgid="191109939968076477">"<xliff:g id="FIRST">%1$s</xliff:g> / <xliff:g id="REST">%2$s</xliff:g>"</string> <string name="toolbar_collapse_description" msgid="2821479483960330739">"Tolestu"</string> - <string name="zen_mode_feature_name" msgid="5254089399895895004">"Ez molestatu"</string> + <string name="zen_mode_feature_name" msgid="5254089399895895004">"Ez molestatzeko modua"</string> <string name="zen_mode_downtime_feature_name" msgid="2626974636779860146">"Jarduerarik gabeko denbora"</string> <string name="zen_mode_default_weeknights_name" msgid="3081318299464998143">"Lanegunetako gaua"</string> <string name="zen_mode_default_weekends_name" msgid="2786495801019345244">"Asteburua"</string> @@ -1958,10 +1956,10 @@ <string name="volume_dialog_ringer_guidance_vibrate" msgid="8902050240801159042">"Dar-dar egingo du deiak eta jakinarazpenak jasotzean"</string> <string name="volume_dialog_ringer_guidance_silent" msgid="2128975224280276122">"Ez da joko tonurik deiak eta jakinarazpenak jasotzean"</string> <string name="notification_channel_system_changes" msgid="5072715579030948646">"Sistema-aldaketak"</string> - <string name="notification_channel_do_not_disturb" msgid="6766940333105743037">"Ez molestatu"</string> - <string name="zen_upgrade_notification_visd_title" msgid="3288313883409759733">"Berria: \"Ez molestatu\" modua jakinarazpenak ezkutatzen ari da"</string> + <string name="notification_channel_do_not_disturb" msgid="6766940333105743037">"Ez molestatzeko modua"</string> + <string name="zen_upgrade_notification_visd_title" msgid="3288313883409759733">"Berria: Ez molestatzeko modua jakinarazpenak ezkutatzen ari da"</string> <string name="zen_upgrade_notification_visd_content" msgid="5533674060311631165">"Sakatu informazio gehiago lortzeko eta portaera aldatzeko."</string> - <string name="zen_upgrade_notification_title" msgid="3799603322910377294">"\"Ez molestatu\" modua aldatu da"</string> + <string name="zen_upgrade_notification_title" msgid="3799603322910377294">"Ez molestatzeko modua aldatu da"</string> <string name="zen_upgrade_notification_content" msgid="1794994264692424562">"Sakatu zer dagoen blokeatuta ikusteko."</string> <string name="notification_app_name_system" msgid="4205032194610042794">"Sistema"</string> <string name="notification_app_name_settings" msgid="7751445616365753381">"Ezarpenak"</string> @@ -2008,4 +2006,22 @@ <string name="chooser_no_direct_share_targets" msgid="997970693708458895">"Zuzenean partekatzeko aukera ez dago erabilgarri"</string> <string name="chooser_all_apps_button_label" msgid="3631524352936289457">"Aplikazioen zerrenda"</string> <string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"Aplikazioak ez du grabatzeko baimenik, baina baliteke audioa grabatzea USB bidezko gailu horren bidez."</string> + <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) --> + <skip /> + <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) --> + <skip /> + <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) --> + <skip /> + <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) --> + <skip /> + <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) --> + <skip /> + <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) --> + <skip /> + <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) --> + <skip /> + <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) --> + <skip /> + <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) --> + <skip /> </resources> diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml index a9231e99c5c9..98044c60eaee 100644 --- a/core/res/res/values-fa/strings.xml +++ b/core/res/res/values-fa/strings.xml @@ -1771,10 +1771,8 @@ <string name="package_updated_device_owner" msgid="1847154566357862089">"توسط سرپرست سیستم بهروزرسانی شد"</string> <string name="package_deleted_device_owner" msgid="2307122077550236438">"توسط سرپرست سیستم حذف شد"</string> <string name="confirm_battery_saver" msgid="639106420541753635">"تأیید"</string> - <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) --> - <skip /> - <!-- no translation found for battery_saver_description (2307555792915978653) --> - <skip /> + <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"برای افزایش عمر باتری، «بهینهسازی باتری»:\n «طرح زمینه تیره» را روشن میکند\n فعالیت پسزمینه، برخی جلوههای بصری، و دیگر ویژگیها مانند «Ok Google» را خاموش یا محدود میکند\n\n"<annotation id="url">"بیشتر بدانید"</annotation></string> + <string name="battery_saver_description" msgid="2307555792915978653">"برای افزایش عمر باتری، «بهینهسازی باتری»:\n «طرح زمینه تیره» را روشن میکند\n فعالیت پسزمینه، برخی جلوههای بصری، و دیگر ویژگیها مانند «Ok Google» را خاموش یا محدود میکند"</string> <string name="data_saver_description" msgid="6015391409098303235">"برای کمک به کاهش مصرف داده، «صرفهجویی داده» از ارسال و دریافت داده در پسزمینه ازطرف بعضی برنامهها جلوگیری میکند. برنامهای که درحالحاضر استفاده میکنید میتواند به دادهها دسترسی داشته باشد اما دفعات دسترسی آن محدود است.این یعنی، برای مثال، تصاویر تا زمانی که روی آنها ضربه نزنید نشان داده نمیشوند."</string> <string name="data_saver_enable_title" msgid="4674073932722787417">"صرفهجویی داده روشن شود؟"</string> <string name="data_saver_enable_button" msgid="7147735965247211818">"روشن کردن"</string> @@ -2008,4 +2006,22 @@ <string name="chooser_no_direct_share_targets" msgid="997970693708458895">"اشتراکگذاری مستقیم دردسترس نیست"</string> <string name="chooser_all_apps_button_label" msgid="3631524352936289457">"فهرست برنامهها"</string> <string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"مجوز ضبط به این برنامه داده نشده است اما میتواند صدا را ازطریق این دستگاه USB ضبط کند."</string> + <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) --> + <skip /> + <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) --> + <skip /> + <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) --> + <skip /> + <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) --> + <skip /> + <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) --> + <skip /> + <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) --> + <skip /> + <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) --> + <skip /> + <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) --> + <skip /> + <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) --> + <skip /> </resources> diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml index 14ed7b7f8d6f..3476bf52fef3 100644 --- a/core/res/res/values-fi/strings.xml +++ b/core/res/res/values-fi/strings.xml @@ -1771,10 +1771,8 @@ <string name="package_updated_device_owner" msgid="1847154566357862089">"Järjestelmänvalvoja päivitti tämän."</string> <string name="package_deleted_device_owner" msgid="2307122077550236438">"Järjestelmänvalvoja poisti tämän."</string> <string name="confirm_battery_saver" msgid="639106420541753635">"OK"</string> - <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) --> - <skip /> - <!-- no translation found for battery_saver_description (2307555792915978653) --> - <skip /> + <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"Parantaakseen akunkestoa virransäästö\n·ottaa tumman teeman käyttöön\n·poistaa käytöstä tai rajoittaa taustatoimintoja, joitakin visuaalisia tehosteita ja muita ominaisuuksia (esim. Hei Google).\n\n"<annotation id="url">"Lue lisää"</annotation></string> + <string name="battery_saver_description" msgid="2307555792915978653">"Parantaakseen akunkestoa virransäästö\n·ottaa tumman teeman käyttöön\n·poistaa käytöstä tai rajoittaa taustatoimintoja, joitakin visuaalisia tehosteita ja muita ominaisuuksia (esim. Hei Google)."</string> <string name="data_saver_description" msgid="6015391409098303235">"Data Saver estää joitakin sovelluksia lähettämästä tai vastaanottamasta tietoja taustalla, jotta datan käyttöä voidaan vähentää. Käytössäsi oleva sovellus voi yhä käyttää dataa, mutta se saattaa tehdä niin tavallista harvemmin. Tämä voi tarkoittaa esimerkiksi sitä, että kuva ladataan vasta, kun kosketat sitä."</string> <string name="data_saver_enable_title" msgid="4674073932722787417">"Otetaanko Data Saver käyttöön?"</string> <string name="data_saver_enable_button" msgid="7147735965247211818">"Ota käyttöön"</string> @@ -2008,4 +2006,22 @@ <string name="chooser_no_direct_share_targets" msgid="997970693708458895">"Suora jakaminen ei käytettävissä"</string> <string name="chooser_all_apps_button_label" msgid="3631524352936289457">"Sovellusluettelo"</string> <string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"Sovellus ei ole saanut tallennuslupaa mutta voi tallentaa ääntä tämän USB-laitteen avulla."</string> + <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) --> + <skip /> + <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) --> + <skip /> + <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) --> + <skip /> + <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) --> + <skip /> + <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) --> + <skip /> + <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) --> + <skip /> + <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) --> + <skip /> + <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) --> + <skip /> + <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) --> + <skip /> </resources> diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml index 2c4362d91911..702ecc022932 100644 --- a/core/res/res/values-fr-rCA/strings.xml +++ b/core/res/res/values-fr-rCA/strings.xml @@ -1771,10 +1771,8 @@ <string name="package_updated_device_owner" msgid="1847154566357862089">"Mise à jour par votre administrateur"</string> <string name="package_deleted_device_owner" msgid="2307122077550236438">"Supprimé par votre administrateur"</string> <string name="confirm_battery_saver" msgid="639106420541753635">"OK"</string> - <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) --> - <skip /> - <!-- no translation found for battery_saver_description (2307555792915978653) --> - <skip /> + <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"Pour prolonger l\'autonomie de la pile, l\'économiseur de pile effectue les actions suivantes :\n·Activer le thème sombre\n·Désactiver ou limiter l\'activité en arrière-plan, certains effets visuels et d\'autres fonctionnalités, comme « Hey Google »\n\n"<annotation id="url">"En savoir plus"</annotation></string> + <string name="battery_saver_description" msgid="2307555792915978653">"Pour prolonger l\'autonomie de la pile, l\'économiseur de pile effectue les actions suivantes :\n·Activer le thème sombre\n·Désactiver ou limiter l\'activité en arrière-plan, certains effets visuels et d\'autres fonctionnalités, comme « Hey Google »"</string> <string name="data_saver_description" msgid="6015391409098303235">"Pour aider à diminuer l\'utilisation des données, la fonction Économiseur de données empêche certaines applications d\'envoyer ou de recevoir des données en arrière-plan. Une application que vous utilisez actuellement peut accéder à des données, mais peut le faire moins souvent. Cela peut signifier, par exemple, que les images ne s\'affichent pas jusqu\'à ce que vous les touchiez."</string> <string name="data_saver_enable_title" msgid="4674073932722787417">"Activer l\'Économiseur de données?"</string> <string name="data_saver_enable_button" msgid="7147735965247211818">"Activer"</string> @@ -2008,4 +2006,22 @@ <string name="chooser_no_direct_share_targets" msgid="997970693708458895">"Le partage direct n\'est pas disponible"</string> <string name="chooser_all_apps_button_label" msgid="3631524352936289457">"Liste des applications"</string> <string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"Cette application n\'a pas été autorisée à effectuer des enregistrements, mais elle pourrait capturer du contenu audio par l\'intermédiaire de cet appareil USB."</string> + <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) --> + <skip /> + <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) --> + <skip /> + <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) --> + <skip /> + <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) --> + <skip /> + <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) --> + <skip /> + <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) --> + <skip /> + <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) --> + <skip /> + <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) --> + <skip /> + <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) --> + <skip /> </resources> diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml index cbb64e6826a6..eb199ded51f1 100644 --- a/core/res/res/values-fr/strings.xml +++ b/core/res/res/values-fr/strings.xml @@ -2008,4 +2008,22 @@ <string name="chooser_no_direct_share_targets" msgid="997970693708458895">"Le partage direct n\'est pas disponible"</string> <string name="chooser_all_apps_button_label" msgid="3631524352936289457">"Liste des applications"</string> <string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"Cette application n\'a pas reçu l\'autorisation d\'enregistrer des contenus audio, mais peut le faire via ce périphérique USB."</string> + <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) --> + <skip /> + <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) --> + <skip /> + <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) --> + <skip /> + <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) --> + <skip /> + <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) --> + <skip /> + <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) --> + <skip /> + <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) --> + <skip /> + <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) --> + <skip /> + <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) --> + <skip /> </resources> diff --git a/core/res/res/values-gl/strings.xml b/core/res/res/values-gl/strings.xml index 848cd0b0455a..965997317969 100644 --- a/core/res/res/values-gl/strings.xml +++ b/core/res/res/values-gl/strings.xml @@ -1771,10 +1771,8 @@ <string name="package_updated_device_owner" msgid="1847154566357862089">"Actualizado polo teu administrador"</string> <string name="package_deleted_device_owner" msgid="2307122077550236438">"Eliminado polo teu administrador"</string> <string name="confirm_battery_saver" msgid="639106420541753635">"Aceptar"</string> - <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) --> - <skip /> - <!-- no translation found for battery_saver_description (2307555792915978653) --> - <skip /> + <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"Para aumentar a duración da batería, a función Aforro de batería fai o seguinte:\n·Activa o tema escuro\n·Desactiva ou restrinxe a actividade en segundo plano, algúns efectos visuais e outras funcións, como \"Ok Google\"\n\n"<annotation id="url">"Máis información"</annotation></string> + <string name="battery_saver_description" msgid="2307555792915978653">"Para aumentar a duración da batería, a función Aforro de batería fai o seguinte:\n·Activa o tema escuro\n·Desactiva ou restrinxe a actividade en segundo plano, algúns efectos visuais e outras funcións, como \"Ok Google\""</string> <string name="data_saver_description" msgid="6015391409098303235">"Para contribuír a reducir o uso de datos, o Economizador de datos impide que algunhas aplicacións envíen ou reciban datos en segundo plano. Cando esteas utilizando unha aplicación, esta poderá acceder aos datos, pero é posible que o faga con menos frecuencia. Por exemplo, é posible que as imaxes non se mostren ata que as toques."</string> <string name="data_saver_enable_title" msgid="4674073932722787417">"Queres activar o economizador de datos?"</string> <string name="data_saver_enable_button" msgid="7147735965247211818">"Activar"</string> @@ -2008,4 +2006,22 @@ <string name="chooser_no_direct_share_targets" msgid="997970693708458895">"Non está dispoñible a función de compartir directamente"</string> <string name="chooser_all_apps_button_label" msgid="3631524352936289457">"Lista de aplicacións"</string> <string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"Esta aplicación non está autorizada a realizar gravacións, pero pode capturar audio a través deste dispositivo USB."</string> + <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) --> + <skip /> + <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) --> + <skip /> + <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) --> + <skip /> + <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) --> + <skip /> + <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) --> + <skip /> + <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) --> + <skip /> + <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) --> + <skip /> + <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) --> + <skip /> + <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) --> + <skip /> </resources> diff --git a/core/res/res/values-gu/strings.xml b/core/res/res/values-gu/strings.xml index 2a5536f31c04..6dab622a29ae 100644 --- a/core/res/res/values-gu/strings.xml +++ b/core/res/res/values-gu/strings.xml @@ -1771,10 +1771,8 @@ <string name="package_updated_device_owner" msgid="1847154566357862089">"તમારા વ્યવસ્થાપક દ્વારા અપડેટ કરવામાં આવેલ છે"</string> <string name="package_deleted_device_owner" msgid="2307122077550236438">"તમારા વ્યવસ્થાપક દ્વારા કાઢી નાખવામાં આવેલ છે"</string> <string name="confirm_battery_saver" msgid="639106420541753635">"ઓકે"</string> - <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) --> - <skip /> - <!-- no translation found for battery_saver_description (2307555792915978653) --> - <skip /> + <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"બૅટરીની આવરદા વધારવા માટે, બૅટરી સેવર:\n·ઘેરી થીમ ચાલુ કરે છે\n·બૅકગ્રાઉન્ડ પ્રવૃત્તિ, અમુક વિઝ્યુઅલ ઇફેક્ટ અને “હેય Google” જેવી અન્ય સુવિધાઓ બંધ અથવા પ્રતિબંધિત કરે છે\n\n"<annotation id="url">"વધુ જાણો"</annotation></string> + <string name="battery_saver_description" msgid="2307555792915978653">"બૅટરીની આવરદા વધારવા માટે, બૅટરી સેવર:\n·ઘેરી થીમ ચાલુ કરે છે\n·બૅકગ્રાઉન્ડ પ્રવૃત્તિ, અમુક વિઝ્યુઅલ ઇફેક્ટ અને “હેય Google” જેવી અન્ય સુવિધાઓ બંધ અથવા પ્રતિબંધિત કરે છે"</string> <string name="data_saver_description" msgid="6015391409098303235">"ડેટા વપરાશને ઘટાડવામાં સહાય માટે, ડેટા સેવર કેટલીક ઍપ્લિકેશનોને પૃષ્ઠભૂમિમાં ડેટા મોકલવા અથવા પ્રાપ્ત કરવાથી અટકાવે છે. તમે હાલમાં ઉપયોગ કરી રહ્યાં છો તે ઍપ્લિકેશન ડેટાને ઍક્સેસ કરી શકે છે, પરંતુ તે આ ક્યારેક જ કરી શકે છે. આનો અર્થ એ હોઈ શકે છે, ઉદાહરણ તરીકે, છબીઓ ત્યાં સુધી પ્રદર્શિત થશે નહીં જ્યાં સુધી તમે તેને ટૅપ નહીં કરો."</string> <string name="data_saver_enable_title" msgid="4674073932722787417">"ડેટા સેવર ચાલુ કરીએ?"</string> <string name="data_saver_enable_button" msgid="7147735965247211818">"ચાલુ કરો"</string> @@ -2008,4 +2006,22 @@ <string name="chooser_no_direct_share_targets" msgid="997970693708458895">"ડાયરેક્ટ શેર કરવાનું ઉપલબ્ધ નથી"</string> <string name="chooser_all_apps_button_label" msgid="3631524352936289457">"ઍપની સૂચિ"</string> <string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"આ ઍપને રેકૉર્ડ કરવાની પરવાનગી આપવામાં આવી નથી પરંતુ તે આ USB ડિવાઇસ મારફતે ઑડિયો કૅપ્ચર કરી શકે છે."</string> + <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) --> + <skip /> + <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) --> + <skip /> + <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) --> + <skip /> + <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) --> + <skip /> + <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) --> + <skip /> + <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) --> + <skip /> + <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) --> + <skip /> + <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) --> + <skip /> + <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) --> + <skip /> </resources> diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml index 698a6a749c44..1a082b90f954 100644 --- a/core/res/res/values-hi/strings.xml +++ b/core/res/res/values-hi/strings.xml @@ -1771,10 +1771,8 @@ <string name="package_updated_device_owner" msgid="1847154566357862089">"आपके व्यवस्थापक ने अपडेट किया है"</string> <string name="package_deleted_device_owner" msgid="2307122077550236438">"आपके व्यवस्थापक ने हटा दिया है"</string> <string name="confirm_battery_saver" msgid="639106420541753635">"ठीक है"</string> - <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) --> - <skip /> - <!-- no translation found for battery_saver_description (2307555792915978653) --> - <skip /> + <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"बैटरी लाइफ़ बढ़ाने के लिए बैटरी सेवर:\n·गहरे रंग वाली थीम चालू करता है\n·बैकग्राउंड की गतिविधि, कुछ विज़ुअल इफ़ेक्ट, और दूसरी सुविधाएं, जैसे कि \"Hey Google\" को इस्तेमाल करने से रोकता है या बंद करता है\n\n"<annotation id="url">"ज़्यादा जानें"</annotation></string> + <string name="battery_saver_description" msgid="2307555792915978653">"बैटरी लाइफ़ बढ़ाने के लिए बैटरी सेवर:\n गहरे रंग वाली थीम चालू करता है\nबैकग्राउंड की गतिविधि, कुछ विज़ुअल इफ़ेक्ट, और दूसरी सुविधाएं, जैसे कि \"Hey Google\" को इस्तेमाल करने से रोकता है या बंद करता है"</string> <string name="data_saver_description" msgid="6015391409098303235">"डेटा खर्च, कम करने के लिए डेटा सेवर कुछ ऐप्लिकेशन को बैकग्राउंड में डेटा भेजने या डेटा पाने से रोकता है. आप फ़िलहाल जिस ऐप्लिकेशन का इस्तेमाल कर रहे हैं वह डेटा तक पहुंच सकता है लेकिन ऐसा कभी-कभी ही हो पाएगा. उदाहरण के लिए, इमेज तब तक दिखाई नहीं देंगी जब तक कि आप उन्हें टैप नहीं करते."</string> <string name="data_saver_enable_title" msgid="4674073932722787417">"डेटा बचाने की सेटिंग चालू करें?"</string> <string name="data_saver_enable_button" msgid="7147735965247211818">"चालू करें"</string> @@ -2008,4 +2006,22 @@ <string name="chooser_no_direct_share_targets" msgid="997970693708458895">"सीधे शेयर नहीं किया जा सकता"</string> <string name="chooser_all_apps_button_label" msgid="3631524352936289457">"ऐप्लिकेशन की सूची"</string> <string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"इस ऐप्लिकेशन को रिकॉर्ड करने की अनुमति नहीं दी गई है. हालांकि, ऐप्लिकेशन इस यूएसबी डिवाइस से ऐसा कर सकता है."</string> + <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) --> + <skip /> + <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) --> + <skip /> + <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) --> + <skip /> + <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) --> + <skip /> + <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) --> + <skip /> + <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) --> + <skip /> + <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) --> + <skip /> + <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) --> + <skip /> + <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) --> + <skip /> </resources> diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml index 6a134dcf90fa..56d5b2006a95 100644 --- a/core/res/res/values-hr/strings.xml +++ b/core/res/res/values-hr/strings.xml @@ -1794,10 +1794,8 @@ <string name="package_updated_device_owner" msgid="1847154566357862089">"Ažurirao administrator"</string> <string name="package_deleted_device_owner" msgid="2307122077550236438">"Izbrisao administrator"</string> <string name="confirm_battery_saver" msgid="639106420541753635">"U redu"</string> - <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) --> - <skip /> - <!-- no translation found for battery_saver_description (2307555792915978653) --> - <skip /> + <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"Da bi se produljilo trajanje baterije, Štednja baterije:\n·Uključuje Tamnu temu.\n·Isključuje ili ograničava aktivnosti u pozadini, neke vizualne efekte i druge značajke kao što je \"Hey Google\".\n\n"<annotation id="url">"Saznajte više"</annotation></string> + <string name="battery_saver_description" msgid="2307555792915978653">"Da bi se produljilo trajanje baterije, Štednja baterije:\n·Uključuje Tamnu temu.\n·Isključuje ili ograničava aktivnosti u pozadini, neke vizualne efekte i druge značajke kao što je \"Hey Google\"."</string> <string name="data_saver_description" msgid="6015391409098303235">"Da bi se smanjio podatkovni promet, značajka Štednja podatkovnog prometa onemogućuje nekim aplikacijama slanje ili primanje podataka u pozadini. Aplikacija koju trenutačno upotrebljavate može pristupiti podacima, no možda će to činiti rjeđe. To može značiti da se, na primjer, slike neće prikazivati dok ih ne dodirnete."</string> <string name="data_saver_enable_title" msgid="4674073932722787417">"Uključiti Uštedu podataka?"</string> <string name="data_saver_enable_button" msgid="7147735965247211818">"Uključi"</string> @@ -2042,4 +2040,22 @@ <string name="chooser_no_direct_share_targets" msgid="997970693708458895">"Izravno dijeljenje nije dostupno"</string> <string name="chooser_all_apps_button_label" msgid="3631524352936289457">"Popis aplikacija"</string> <string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"Ta aplikacija nema dopuštenje za snimanje, no mogla bi primati zvuk putem ovog USB uređaja."</string> + <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) --> + <skip /> + <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) --> + <skip /> + <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) --> + <skip /> + <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) --> + <skip /> + <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) --> + <skip /> + <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) --> + <skip /> + <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) --> + <skip /> + <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) --> + <skip /> + <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) --> + <skip /> </resources> diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml index 0cd3fec3c2b7..184b66ae54bb 100644 --- a/core/res/res/values-hu/strings.xml +++ b/core/res/res/values-hu/strings.xml @@ -1771,10 +1771,8 @@ <string name="package_updated_device_owner" msgid="1847154566357862089">"A rendszergazda által frissítve"</string> <string name="package_deleted_device_owner" msgid="2307122077550236438">"A rendszergazda által törölve"</string> <string name="confirm_battery_saver" msgid="639106420541753635">"OK"</string> - <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) --> - <skip /> - <!-- no translation found for battery_saver_description (2307555792915978653) --> - <skip /> + <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"Az Akkumulátorkímélő mód az akkumulátor üzemidejének növelése érdekében a következőket teszi:\n Bekapcsolja a sötét témát.\n Kikapcsolja vagy korlátozza a háttérben futó tevékenységeket, egyes vizuális effekteket, az „Ok Google” parancsot és egyéb funkciókat.\n\n"<annotation id="url">"További információ"</annotation>"."</string> + <string name="battery_saver_description" msgid="2307555792915978653">"Az Akkumulátorkímélő mód az akkumulátor üzemidejének növelése érdekében a következőket teszi:\n Bekapcsolja a sötét témát.\n Kikapcsolja vagy korlátozza a háttérben futó tevékenységeket, egyes vizuális effekteket, az „Ok Google” parancsot és egyéb funkciókat."</string> <string name="data_saver_description" msgid="6015391409098303235">"Az adatforgalom csökkentése érdekében az Adatforgalom-csökkentő megakadályozza, hogy egyes alkalmazások adatokat küldjenek vagy fogadjanak a háttérben. Az Ön által aktuálisan használt alkalmazások hozzáférhetnek az adatokhoz, de csak ritkábban. Ez például azt jelentheti, hogy a képek csak rákoppintás után jelennek meg."</string> <string name="data_saver_enable_title" msgid="4674073932722787417">"Bekapcsolja az Adatforgalom-csökkentőt?"</string> <string name="data_saver_enable_button" msgid="7147735965247211818">"Bekapcsolás"</string> @@ -2008,4 +2006,22 @@ <string name="chooser_no_direct_share_targets" msgid="997970693708458895">"A közvetlen megosztás nem áll rendelkezésre"</string> <string name="chooser_all_apps_button_label" msgid="3631524352936289457">"Alkalmazások listája"</string> <string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"Ez az alkalmazás nem rendelkezik rögzítési engedéllyel, de ezzel az USB-eszközzel képes a hangfelvételre."</string> + <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) --> + <skip /> + <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) --> + <skip /> + <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) --> + <skip /> + <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) --> + <skip /> + <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) --> + <skip /> + <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) --> + <skip /> + <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) --> + <skip /> + <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) --> + <skip /> + <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) --> + <skip /> </resources> diff --git a/core/res/res/values-hy/strings.xml b/core/res/res/values-hy/strings.xml index a923814c4740..fef6f4e0dc20 100644 --- a/core/res/res/values-hy/strings.xml +++ b/core/res/res/values-hy/strings.xml @@ -2006,4 +2006,22 @@ <string name="chooser_no_direct_share_targets" msgid="997970693708458895">"Direct Share գործառույթը հասանելի չէ"</string> <string name="chooser_all_apps_button_label" msgid="3631524352936289457">"Հավելվածների ցանկ"</string> <string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"Հավելվածը ձայնագրելու թույլտվություն չունի, սակայն կկարողանա գրանցել ձայնն այս USB սարքի միջոցով։"</string> + <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) --> + <skip /> + <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) --> + <skip /> + <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) --> + <skip /> + <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) --> + <skip /> + <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) --> + <skip /> + <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) --> + <skip /> + <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) --> + <skip /> + <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) --> + <skip /> + <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) --> + <skip /> </resources> diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml index b25b643e31fb..87a88043d337 100644 --- a/core/res/res/values-in/strings.xml +++ b/core/res/res/values-in/strings.xml @@ -1771,10 +1771,8 @@ <string name="package_updated_device_owner" msgid="1847154566357862089">"Diupdate oleh admin Anda"</string> <string name="package_deleted_device_owner" msgid="2307122077550236438">"Dihapus oleh admin Anda"</string> <string name="confirm_battery_saver" msgid="639106420541753635">"Oke"</string> - <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) --> - <skip /> - <!-- no translation found for battery_saver_description (2307555792915978653) --> - <skip /> + <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"Untuk memperpanjang masa pakai baterai, Penghemat Baterai:\n·Mengaktifkan Tema gelap\n·Menonaktifkan atau membatasi aktivitas di latar belakang, beberapa efek visual, dan fitur lain seperti “Ok Google”\n\n"<annotation id="url">"Pelajari lebih lanjut"</annotation></string> + <string name="battery_saver_description" msgid="2307555792915978653">"Untuk memperpanjang masa pakai baterai, Penghemat Baterai:\n·Mengaktifkan Tema gelap\n·Menonaktifkan atau membatasi aktivitas di latar belakang, beberapa efek visual, dan fitur lain seperti “Ok Google”"</string> <string name="data_saver_description" msgid="6015391409098303235">"Untuk membantu mengurangi penggunaan kuota, Penghemat Kuota Internet mencegah beberapa aplikasi mengirim atau menerima data di latar belakang. Aplikasi yang sedang digunakan dapat mengakses data, tetapi frekuensinya agak lebih jarang. Misalnya saja, gambar hanya akan ditampilkan setelah diketuk."</string> <string name="data_saver_enable_title" msgid="4674073932722787417">"Aktifkan Penghemat Kuota?"</string> <string name="data_saver_enable_button" msgid="7147735965247211818">"Aktifkan"</string> @@ -2008,4 +2006,22 @@ <string name="chooser_no_direct_share_targets" msgid="997970693708458895">"Berbagi langsung tidak tersedia"</string> <string name="chooser_all_apps_button_label" msgid="3631524352936289457">"Daftar aplikasi"</string> <string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"Aplikasi ini tidak diberi izin merekam, tetapi dapat merekam audio melalui perangkat USB ini."</string> + <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) --> + <skip /> + <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) --> + <skip /> + <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) --> + <skip /> + <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) --> + <skip /> + <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) --> + <skip /> + <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) --> + <skip /> + <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) --> + <skip /> + <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) --> + <skip /> + <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) --> + <skip /> </resources> diff --git a/core/res/res/values-is/strings.xml b/core/res/res/values-is/strings.xml index c2ffddf69bca..a37eda695c88 100644 --- a/core/res/res/values-is/strings.xml +++ b/core/res/res/values-is/strings.xml @@ -2008,4 +2008,22 @@ <string name="chooser_no_direct_share_targets" msgid="997970693708458895">"Bein deiling er ekki tiltæk"</string> <string name="chooser_all_apps_button_label" msgid="3631524352936289457">"Forritalisti"</string> <string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"Þetta forrit hefur ekki fengið heimild fyrir upptöku en gæti tekið upp hljóð í gegnum þetta USB-tæki."</string> + <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) --> + <skip /> + <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) --> + <skip /> + <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) --> + <skip /> + <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) --> + <skip /> + <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) --> + <skip /> + <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) --> + <skip /> + <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) --> + <skip /> + <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) --> + <skip /> + <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) --> + <skip /> </resources> diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml index 2e672dc039d4..2b780d0fb4e8 100644 --- a/core/res/res/values-it/strings.xml +++ b/core/res/res/values-it/strings.xml @@ -1771,10 +1771,8 @@ <string name="package_updated_device_owner" msgid="1847154566357862089">"Aggiornato dall\'amministratore"</string> <string name="package_deleted_device_owner" msgid="2307122077550236438">"Eliminato dall\'amministratore"</string> <string name="confirm_battery_saver" msgid="639106420541753635">"OK"</string> - <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) --> - <skip /> - <!-- no translation found for battery_saver_description (2307555792915978653) --> - <skip /> + <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"Per estendere la durata della batteria, Risparmio energetico:\n·Attiva il Tema scuro\n·Disattiva o limita le attività in background, alcuni effetti visivi e altre funzionalità come \"Ok Google\"\n\n"<annotation id="url">"Ulteriori informazioni"</annotation></string> + <string name="battery_saver_description" msgid="2307555792915978653">"Per estendere la durata della batteria, Risparmio energetico:\n·Attiva il Tema scuro\n·Disattiva o limita le attività in background, alcuni effetti visivi e altre funzionalità come \"Ok Google\""</string> <string name="data_saver_description" msgid="6015391409098303235">"Per contribuire a ridurre l\'utilizzo dei dati, la funzione Risparmio dati impedisce ad alcune app di inviare o ricevere dati in background. Un\'app in uso può accedere ai dati, ma potrebbe farlo con meno frequenza. Esempio: le immagini non vengono visualizzate finché non le tocchi."</string> <string name="data_saver_enable_title" msgid="4674073932722787417">"Attivare Risparmio dati?"</string> <string name="data_saver_enable_button" msgid="7147735965247211818">"Attiva"</string> @@ -2008,4 +2006,22 @@ <string name="chooser_no_direct_share_targets" msgid="997970693708458895">"Condivisione diretta non disponibile"</string> <string name="chooser_all_apps_button_label" msgid="3631524352936289457">"Elenco di app"</string> <string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"A questa app non è stata concessa l\'autorizzazione di registrazione, ma l\'app potrebbe acquisire l\'audio tramite questo dispositivo USB."</string> + <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) --> + <skip /> + <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) --> + <skip /> + <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) --> + <skip /> + <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) --> + <skip /> + <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) --> + <skip /> + <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) --> + <skip /> + <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) --> + <skip /> + <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) --> + <skip /> + <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) --> + <skip /> </resources> diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml index fdf34e0898cc..dfbf834a4138 100644 --- a/core/res/res/values-iw/strings.xml +++ b/core/res/res/values-iw/strings.xml @@ -1817,10 +1817,8 @@ <string name="package_updated_device_owner" msgid="1847154566357862089">"עודכנה על ידי מנהל המערכת"</string> <string name="package_deleted_device_owner" msgid="2307122077550236438">"נמחקה על ידי מנהל המערכת"</string> <string name="confirm_battery_saver" msgid="639106420541753635">"אישור"</string> - <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) --> - <skip /> - <!-- no translation found for battery_saver_description (2307555792915978653) --> - <skip /> + <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"התכונה \'חיסכון בסוללה\':\n·מפעילה עיצוב כהה\n·מכבה או מגבילה פעילות ברקע, חלק מהאפקטים החזותיים ותכונות אחרות כמו \"Ok Google\", כדי להאריך את חיי הסוללה\n\n"<annotation id="url">"מידע נוסף"</annotation></string> + <string name="battery_saver_description" msgid="2307555792915978653">"התכונה \'חיסכון בסוללה\':\n·מפעילה עיצוב כהה\n·מכבה או מגבילה פעילות ברקע, חלק מהאפקטים החזותיים ותכונות אחרות כמו \"Ok Google\", כדי להאריך את חיי הסוללה"</string> <string name="data_saver_description" msgid="6015391409098303235">"כדי לסייע בהפחתת השימוש בנתונים, חוסך הנתונים (Data Saver) מונע מאפליקציות מסוימות שליחה או קבלה של נתונים ברקע. אפליקציה שבה נעשה שימוש כרגע יכולה לגשת לנתונים, אבל בתדירות נמוכה יותר. המשמעות היא, למשל, שתמונות יוצגו רק לאחר שמקישים עליהן."</string> <string name="data_saver_enable_title" msgid="4674073932722787417">"האם להפעיל את חוסך הנתונים (Data Saver)?"</string> <string name="data_saver_enable_button" msgid="7147735965247211818">"הפעל"</string> @@ -2076,4 +2074,22 @@ <string name="chooser_no_direct_share_targets" msgid="997970693708458895">"שיתוף ישיר אינו זמין"</string> <string name="chooser_all_apps_button_label" msgid="3631524352936289457">"רשימת האפליקציות"</string> <string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"לאפליקציה זו לא ניתנה הרשאת הקלטה, אבל אפשר להקליט אודיו באמצעות התקן ה-USB הזה."</string> + <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) --> + <skip /> + <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) --> + <skip /> + <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) --> + <skip /> + <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) --> + <skip /> + <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) --> + <skip /> + <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) --> + <skip /> + <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) --> + <skip /> + <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) --> + <skip /> + <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) --> + <skip /> </resources> diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml index 07c8107e1e05..477698021ea3 100644 --- a/core/res/res/values-ja/strings.xml +++ b/core/res/res/values-ja/strings.xml @@ -1771,10 +1771,8 @@ <string name="package_updated_device_owner" msgid="1847154566357862089">"管理者により更新されています"</string> <string name="package_deleted_device_owner" msgid="2307122077550236438">"管理者により削除されています"</string> <string name="confirm_battery_saver" msgid="639106420541753635">"OK"</string> - <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) --> - <skip /> - <!-- no translation found for battery_saver_description (2307555792915978653) --> - <skip /> + <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"電池を長持ちさせるためにバッテリー セーバーが行う操作:\n·ダークテーマをオンにする\n·バックグラウンド アクティビティ、一部の視覚効果や、「OK Google」などの機能をオフにする、または制限する\n\n"<annotation id="url">"詳細"</annotation></string> + <string name="battery_saver_description" msgid="2307555792915978653">"電池を長持ちさせるためにバッテリー セーバーが行う操作:\n·ダークテーマをオンにする\n·バックグラウンド アクティビティ、一部の視覚効果や、「OK Google」などの機能をオフにする、または制限する"</string> <string name="data_saver_description" msgid="6015391409098303235">"データセーバーは、一部のアプリによるバックグラウンドでのデータ送受信を停止することでデータ使用量を抑制します。使用中のアプリからデータにアクセスすることはできますが、その頻度は低くなる場合があります。この影響として、たとえば画像はタップしないと表示されないようになります。"</string> <string name="data_saver_enable_title" msgid="4674073932722787417">"データセーバーを ON にしますか?"</string> <string name="data_saver_enable_button" msgid="7147735965247211818">"ON にする"</string> @@ -2008,4 +2006,22 @@ <string name="chooser_no_direct_share_targets" msgid="997970693708458895">"ダイレクト シェアは利用できません"</string> <string name="chooser_all_apps_button_label" msgid="3631524352936289457">"アプリのリスト"</string> <string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"このアプリに録音権限は付与されていませんが、この USB デバイスから音声を収集できるようになります。"</string> + <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) --> + <skip /> + <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) --> + <skip /> + <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) --> + <skip /> + <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) --> + <skip /> + <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) --> + <skip /> + <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) --> + <skip /> + <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) --> + <skip /> + <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) --> + <skip /> + <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) --> + <skip /> </resources> diff --git a/core/res/res/values-ka/strings.xml b/core/res/res/values-ka/strings.xml index 87bd222a9b6f..7f06b0135366 100644 --- a/core/res/res/values-ka/strings.xml +++ b/core/res/res/values-ka/strings.xml @@ -2008,4 +2008,22 @@ <string name="chooser_no_direct_share_targets" msgid="997970693708458895">"პირდაპირი გაზიარება მიუწვდომელია"</string> <string name="chooser_all_apps_button_label" msgid="3631524352936289457">"აპების სია"</string> <string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"ამ აპს არ აქვს მინიჭებული ჩაწერის ნებართვა, მაგრამ შეუძლია ჩაიწეროს აუდიო ამ USB მოწყობილობის მეშვეობით."</string> + <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) --> + <skip /> + <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) --> + <skip /> + <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) --> + <skip /> + <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) --> + <skip /> + <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) --> + <skip /> + <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) --> + <skip /> + <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) --> + <skip /> + <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) --> + <skip /> + <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) --> + <skip /> </resources> diff --git a/core/res/res/values-kk/strings.xml b/core/res/res/values-kk/strings.xml index b3395dfb3bf6..65da546df2b4 100644 --- a/core/res/res/values-kk/strings.xml +++ b/core/res/res/values-kk/strings.xml @@ -1771,10 +1771,8 @@ <string name="package_updated_device_owner" msgid="1847154566357862089">"Әкімші жаңартқан"</string> <string name="package_deleted_device_owner" msgid="2307122077550236438">"Әкімші жойған"</string> <string name="confirm_battery_saver" msgid="639106420541753635">"Жарайды"</string> - <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) --> - <skip /> - <!-- no translation found for battery_saver_description (2307555792915978653) --> - <skip /> + <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"Батарея жұмысының ұзақтығын арттыру үшін Battery Saver:\n·Қараңғы тақырыпты іске қосады\n·фондық әрекеттерді, кейбір көрнекі әсерлерді және \"Ok Google\" сияқты басқа да функцияларды өшіреді немесе шектейді.\n\n"<annotation id="url">"Толығырақ"</annotation></string> + <string name="battery_saver_description" msgid="2307555792915978653">"Батарея жұмысының ұзақтығын арттыру үшін Battery Saver:\n·Қараңғы тақырыпты іске қосады\n·фондық әрекеттерді, кейбір көрнекі әсерлерді және \"Ok Google\" сияқты басқа да функцияларды өшіреді немесе шектейді."</string> <string name="data_saver_description" msgid="6015391409098303235">"Дерек шығынын азайту үшін Data Saver функциясы кейбір қолданбаларға деректерді фондық режимде жіберуге және алуға жол бермейді. Ашық тұрған қолданба деректерді пайдаланады, бірақ шектеулі шамада (мысалы, кескіндер оларды түрткенге дейін көрсетілмейді)."</string> <string name="data_saver_enable_title" msgid="4674073932722787417">"Data Saver функциясын қосу керек пе?"</string> <string name="data_saver_enable_button" msgid="7147735965247211818">"Қосу"</string> @@ -2008,4 +2006,22 @@ <string name="chooser_no_direct_share_targets" msgid="997970693708458895">"Тікелей бөлісу мүмкін емес."</string> <string name="chooser_all_apps_button_label" msgid="3631524352936289457">"Қолданбалар тізімі"</string> <string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"Қолданбаға жазу рұқсаты берілмеді, бірақ ол осы USB құрылғысы арқылы дыбыс жаза алады."</string> + <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) --> + <skip /> + <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) --> + <skip /> + <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) --> + <skip /> + <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) --> + <skip /> + <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) --> + <skip /> + <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) --> + <skip /> + <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) --> + <skip /> + <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) --> + <skip /> + <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) --> + <skip /> </resources> diff --git a/core/res/res/values-km/strings.xml b/core/res/res/values-km/strings.xml index 3eb71f685abd..32b3ee13c439 100644 --- a/core/res/res/values-km/strings.xml +++ b/core/res/res/values-km/strings.xml @@ -1773,10 +1773,8 @@ <string name="package_updated_device_owner" msgid="1847154566357862089">"ធ្វើបច្ចុប្បន្នភាពដោយអ្នកគ្រប់គ្រងរបស់អ្នក"</string> <string name="package_deleted_device_owner" msgid="2307122077550236438">"លុបដោយអ្នកគ្រប់គ្រងរបស់អ្នក"</string> <string name="confirm_battery_saver" msgid="639106420541753635">"យល់ព្រម"</string> - <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) --> - <skip /> - <!-- no translation found for battery_saver_description (2307555792915978653) --> - <skip /> + <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"ដើម្បីបង្កើនកម្រិតថាមពលថ្ម កម្មវិធីសន្សំថ្ម៖\n·បើករចនាប័ទ្មងងឹត\n·បិទ ឬដាក់កំហិតលើសកម្មភាពផ្ទៃខាងក្រោយ ឥទ្ធិពលជារូបភាពមួយចំនួន និងមុខងារផ្សេងទៀតដូចជា “Hey Google” ជាដើម\n\n"<annotation id="url">"ស្វែងយល់បន្ថែម"</annotation></string> + <string name="battery_saver_description" msgid="2307555792915978653">"ដើម្បីបង្កើនកម្រិតថាមពលថ្ម កម្មវិធីសន្សំថ្ម៖\n·បើករចនាប័ទ្មងងឹត\n·បិទ ឬដាក់កំហិតលើសកម្មភាពផ្ទៃខាងក្រោយ ឥទ្ធិពលជារូបភាពមួយចំនួន និងមុខងារផ្សេងទៀតដូចជា “Hey Google” ជាដើម"</string> <string name="data_saver_description" msgid="6015391409098303235">"ដើម្បីជួយកាត់បន្ថយការប្រើប្រាស់ទិន្នន័យ កម្មវិធីសន្សំសំចៃទិន្នន័យរារាំងកម្មវិធីមួយចំនួនមិនឲ្យបញ្ជូន ឬទទួលទិន្នន័យនៅផ្ទៃខាងក្រោយទេ។ កម្មវិធីដែលអ្នកកំពុងប្រើនាពេលបច្ចុប្បន្នអាចចូលប្រើប្រាស់ទិន្នន័យបាន ប៉ុន្តែអាចនឹងមិនញឹកញាប់ដូចមុនទេ។ ឧទាហរណ៍ រូបភាពមិនបង្ហាញទេ លុះត្រាតែអ្នកប៉ះរូបភាពទាំងនោះ។"</string> <string name="data_saver_enable_title" msgid="4674073932722787417">"បើកកម្មវិធីសន្សំសំចៃទិន្នន័យឬ?"</string> <string name="data_saver_enable_button" msgid="7147735965247211818">"បើក"</string> @@ -2010,4 +2008,22 @@ <string name="chooser_no_direct_share_targets" msgid="997970693708458895">"មិនមានការចែករំលែកដោយផ្ទាល់ទេ"</string> <string name="chooser_all_apps_button_label" msgid="3631524352936289457">"បញ្ជីកម្មវិធី"</string> <string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"កម្មវិធីនេះមិនទាន់បានទទួលសិទ្ធិថតសំឡេងនៅឡើយទេ ប៉ុន្តែអាចថតសំឡេងតាមរយៈឧបករណ៍ USB នេះបាន។"</string> + <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) --> + <skip /> + <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) --> + <skip /> + <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) --> + <skip /> + <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) --> + <skip /> + <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) --> + <skip /> + <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) --> + <skip /> + <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) --> + <skip /> + <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) --> + <skip /> + <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) --> + <skip /> </resources> diff --git a/core/res/res/values-kn/strings.xml b/core/res/res/values-kn/strings.xml index a1d993d9341b..0fab683d3fde 100644 --- a/core/res/res/values-kn/strings.xml +++ b/core/res/res/values-kn/strings.xml @@ -1771,10 +1771,8 @@ <string name="package_updated_device_owner" msgid="1847154566357862089">"ನಿಮ್ಮ ನಿರ್ವಾಹಕರಿಂದ ಅಪ್ಡೇಟ್ ಮಾಡಲ್ಪಟ್ಟಿದೆ"</string> <string name="package_deleted_device_owner" msgid="2307122077550236438">"ನಿಮ್ಮ ನಿರ್ವಾಹಕರು ಅಳಿಸಿದ್ದಾರೆ"</string> <string name="confirm_battery_saver" msgid="639106420541753635">"ಸರಿ"</string> - <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) --> - <skip /> - <!-- no translation found for battery_saver_description (2307555792915978653) --> - <skip /> + <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"ಬ್ಯಾಟರಿ ಬಾಳಿಕೆಯನ್ನು ವಿಸ್ತರಿಸಲು, ಬ್ಯಾಟರಿ ಸೇವರ್:\n·ಡಾರ್ಕ್ ಥೀಮ್ ಅನ್ನು ಆನ್ ಮಾಡುತ್ತದೆ\n·ಹಿನ್ನೆಲೆ ಚಟುವಟಿಕೆ, ಕೆಲವು ದೃಶ್ಯಾತ್ಮಕ ಎಫೆಕ್ಟ್ಗಳು ಮತ್ತು “ಹೇ Google” ನಂತಹ ಇತರ ವೈಶಿಷ್ಟ್ಯಗಳನ್ನು ಆಫ್ ಮಾಡುತ್ತದೆ ಅಥವಾ ನಿರ್ಬಂಧಿಸುತ್ತದೆ\n\n"<annotation id="url">"ಇನ್ನಷ್ಟು ತಿಳಿಯಿರಿ"</annotation></string> + <string name="battery_saver_description" msgid="2307555792915978653">"ಬ್ಯಾಟರಿ ಬಾಳಿಕೆಯನ್ನು ವಿಸ್ತರಿಸಲು, ಬ್ಯಾಟರಿ ಸೇವರ್:\n·ಡಾರ್ಕ್ ಥೀಮ್ ಅನ್ನು ಆನ್ ಮಾಡುತ್ತದೆ\n·ಹಿನ್ನೆಲೆ ಚಟುವಟಿಕೆ, ಕೆಲವು ವಿಷುವಲ್ ಎಫೆಕ್ಟ್ಗಳು ಮತ್ತು “ಹೇ Google” ನಂತಹ ಇತರ ವೈಶಿಷ್ಟ್ಯಗಳನ್ನು ಆಫ್ ಮಾಡುತ್ತದೆ ಅಥವಾ ನಿರ್ಬಂಧಿಸುತ್ತದೆ"</string> <string name="data_saver_description" msgid="6015391409098303235">"ಡೇಟಾ ಬಳಕೆ ಕಡಿಮೆ ಮಾಡುವ ನಿಟ್ಟಿನಲ್ಲಿ, ಡೇಟಾ ಸೇವರ್ ಕೆಲವು ಅಪ್ಲಿಕೇಶನ್ಗಳು ಹಿನ್ನೆಲೆಯಲ್ಲಿ ಡೇಟಾ ಕಳುಹಿಸುವುದನ್ನು ಅಥವಾ ಸ್ವೀಕರಿಸುವುದನ್ನು ತಡೆಯುತ್ತದೆ. ನೀವು ಪ್ರಸ್ತುತ ಬಳಸುತ್ತಿರುವ ಅಪ್ಲಿಕೇಶನ್ ಡೇಟಾವನ್ನು ಪ್ರವೇಶಿಸಬಹುದು ಆದರೆ ಪದೇ ಪದೇ ಪ್ರವೇಶಿಸಲು ಸಾಧ್ಯವಾಗುವುದಿಲ್ಲ. ಇದರರ್ಥ, ಉದಾಹರಣೆಗೆ, ನೀವು ಅವುಗಳನ್ನು ಟ್ಯಾಪ್ ಮಾಡುವವರೆಗೆ ಆ ಚಿತ್ರಗಳು ಕಾಣಿಸಿಕೊಳ್ಳುವುದಿಲ್ಲ."</string> <string name="data_saver_enable_title" msgid="4674073932722787417">"ಡೇಟಾ ಉಳಿಸುವಿಕೆಯನ್ನು ಆನ್ ಮಾಡುವುದೇ?"</string> <string name="data_saver_enable_button" msgid="7147735965247211818">"ಆನ್ ಮಾಡಿ"</string> @@ -2008,4 +2006,22 @@ <string name="chooser_no_direct_share_targets" msgid="997970693708458895">"ನೇರ ಹಂಚಿಕೆ ಲಭ್ಯವಿಲ್ಲ"</string> <string name="chooser_all_apps_button_label" msgid="3631524352936289457">"ಆ್ಯಪ್ಗಳ ಪಟ್ಟಿ"</string> <string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"ಈ ಆ್ಯಪ್ಗೆ ರೆಕಾರ್ಡ್ ಅನುಮತಿಯನ್ನು ನೀಡಲಾಗಿಲ್ಲ, ಆದರೆ ಈ USB ಸಾಧನದ ಮೂಲಕ ಆಡಿಯೊವನ್ನು ಸೆರೆಹಿಡಿಯಬಲ್ಲದು."</string> + <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) --> + <skip /> + <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) --> + <skip /> + <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) --> + <skip /> + <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) --> + <skip /> + <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) --> + <skip /> + <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) --> + <skip /> + <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) --> + <skip /> + <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) --> + <skip /> + <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) --> + <skip /> </resources> diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml index bb1c1e7f4efe..f42a92873694 100644 --- a/core/res/res/values-ko/strings.xml +++ b/core/res/res/values-ko/strings.xml @@ -1771,10 +1771,8 @@ <string name="package_updated_device_owner" msgid="1847154566357862089">"관리자에 의해 업데이트되었습니다."</string> <string name="package_deleted_device_owner" msgid="2307122077550236438">"관리자에 의해 삭제되었습니다."</string> <string name="confirm_battery_saver" msgid="639106420541753635">"확인"</string> - <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) --> - <skip /> - <!-- no translation found for battery_saver_description (2307555792915978653) --> - <skip /> + <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"배터리 수명을 늘리기 위해 절전 모드가 다음과 같이 작동합니다.\n·어두운 테마를 사용 설정합니다.\n·백그라운드 활동, 일부 시각 효과 및 \'Hey Google\'과 같은 기타 기능을 사용 중지하거나 제한합니다.\n\n"<annotation id="url">"자세히 알아보기"</annotation></string> + <string name="battery_saver_description" msgid="2307555792915978653">"배터리 수명을 늘리기 위해 절전 모드가 다음과 같이 작동합니다.\n·어두운 테마를 사용 설정합니다.\n·백그라운드 활동, 일부 시각 효과 및 \'Hey Google\'과 같은 기타 기능을 사용 중지하거나 제한합니다."</string> <string name="data_saver_description" msgid="6015391409098303235">"데이터 사용량을 줄이기 위해 데이터 절약 모드는 일부 앱이 백그라운드에서 데이터를 전송하거나 수신하지 못하도록 합니다. 현재 사용 중인 앱에서 데이터에 액세스할 수 있지만 빈도가 줄어듭니다. 예를 들면, 이미지를 탭하기 전에는 이미지가 표시되지 않습니다."</string> <string name="data_saver_enable_title" msgid="4674073932722787417">"데이터 절약 모드를 사용할까요?"</string> <string name="data_saver_enable_button" msgid="7147735965247211818">"사용 설정"</string> @@ -2008,4 +2006,22 @@ <string name="chooser_no_direct_share_targets" msgid="997970693708458895">"직접 공유가 지원되지 않음"</string> <string name="chooser_all_apps_button_label" msgid="3631524352936289457">"앱 목록"</string> <string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"이 앱에는 녹음 권한이 부여되지 않았지만, 이 USB 기기를 통해 오디오를 녹음할 수 있습니다."</string> + <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) --> + <skip /> + <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) --> + <skip /> + <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) --> + <skip /> + <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) --> + <skip /> + <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) --> + <skip /> + <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) --> + <skip /> + <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) --> + <skip /> + <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) --> + <skip /> + <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) --> + <skip /> </resources> diff --git a/core/res/res/values-ky/strings.xml b/core/res/res/values-ky/strings.xml index f8191de31af7..82064b2687d4 100644 --- a/core/res/res/values-ky/strings.xml +++ b/core/res/res/values-ky/strings.xml @@ -1772,10 +1772,8 @@ <string name="package_updated_device_owner" msgid="1847154566357862089">"Администраторуңуз жаңыртып койгон"</string> <string name="package_deleted_device_owner" msgid="2307122077550236438">"Администраторуңуз жок кылып салган"</string> <string name="confirm_battery_saver" msgid="639106420541753635">"ЖАРАЙТ"</string> - <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) --> - <skip /> - <!-- no translation found for battery_saver_description (2307555792915978653) --> - <skip /> + <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"Батареянын кубатынын мөөнөтүн узартуу үчүн Батареяны үнөмдөгүч режими төмөнкүлөрдү аткарат:\n·Түнкү режимди күйгүзөт\n·Фондогу аракеттерди, айрым визуалдык эффекттерди жана \"Окей Google\" сыяктуу башка функцияларды өчүрөт же чектейт\n\n"<annotation id="url">"Кеңири маалымат"</annotation></string> + <string name="battery_saver_description" msgid="2307555792915978653">"Батареянын кубатынын мөөнөтүн узартуу үчүн Батареяны үнөмдөгүч режими төмөнкүлөрдү аткарат:\n·Түнкү режимди күйгүзөт\n·Фондогу аракеттерди, айрым визуалдык эффекттерди жана \"Окей Google\" сыяктуу башка функцияларды өчүрөт же чектейт"</string> <string name="data_saver_description" msgid="6015391409098303235">"Трафикти үнөмдөө режиминде айрым колдонмолор дайындарды фондо өткөрө алышпайт. Учурда сиз пайдаланып жаткан колдонмо дайындарды жөнөтүп/ала алат, бирок адаттагыдан азыраак өткөргөндүктөн, анын айрым функциялары талаптагыдай иштебей коюшу мүмкүн. Мисалы, сүрөттөр басылмайынча жүктөлбөйт."</string> <string name="data_saver_enable_title" msgid="4674073932722787417">"Трафикти үнөмдөө режимин иштетесизби?"</string> <string name="data_saver_enable_button" msgid="7147735965247211818">"Күйгүзүү"</string> @@ -2009,4 +2007,22 @@ <string name="chooser_no_direct_share_targets" msgid="997970693708458895">"Түздөн-түз бөлүшүүгө болбойт"</string> <string name="chooser_all_apps_button_label" msgid="3631524352936289457">"Колдонмолордун тизмеси"</string> <string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"Бул колдонмонун жаздырууга уруксаты жок, бирок бул USB түзмөгү аркылуу аудиону жаздыра алат."</string> + <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) --> + <skip /> + <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) --> + <skip /> + <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) --> + <skip /> + <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) --> + <skip /> + <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) --> + <skip /> + <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) --> + <skip /> + <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) --> + <skip /> + <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) --> + <skip /> + <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) --> + <skip /> </resources> diff --git a/core/res/res/values-lo/strings.xml b/core/res/res/values-lo/strings.xml index d6150cb47cbd..3aa786e44ecc 100644 --- a/core/res/res/values-lo/strings.xml +++ b/core/res/res/values-lo/strings.xml @@ -2006,4 +2006,22 @@ <string name="chooser_no_direct_share_targets" msgid="997970693708458895">"ບໍ່ສາມາດແບ່ງປັນໂດຍກົງໄດ້"</string> <string name="chooser_all_apps_button_label" msgid="3631524352936289457">"ລາຍຊື່ແອັບ"</string> <string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"ແອັບນີ້ບໍ່ໄດ້ຮັບສິດອະນຸຍາດໃນການບັນທຶກ ແຕ່ສາມາດບັນທຶກສຽງໄດ້ຜ່ານອຸປະກອນ USB ນີ້."</string> + <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) --> + <skip /> + <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) --> + <skip /> + <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) --> + <skip /> + <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) --> + <skip /> + <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) --> + <skip /> + <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) --> + <skip /> + <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) --> + <skip /> + <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) --> + <skip /> + <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) --> + <skip /> </resources> diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml index 8bcb000c0939..d4d19f4de063 100644 --- a/core/res/res/values-lt/strings.xml +++ b/core/res/res/values-lt/strings.xml @@ -1817,10 +1817,8 @@ <string name="package_updated_device_owner" msgid="1847154566357862089">"Atnaujino administratorius"</string> <string name="package_deleted_device_owner" msgid="2307122077550236438">"Ištrynė administratorius"</string> <string name="confirm_battery_saver" msgid="639106420541753635">"Gerai"</string> - <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) --> - <skip /> - <!-- no translation found for battery_saver_description (2307555792915978653) --> - <skip /> + <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"Kad akumuliatorius veiktų ilgiau, akumuliatoriaus tausojimo priemonė:\n·įjungia tamsiąją temą;\n·išjungia arba apriboja veiklą fone, kai kuriuos vaizdinius efektus ir kitas funkcijas, pvz., „Hey Google“.\n\n"<annotation id="url">"Sužinokite daugiau"</annotation></string> + <string name="battery_saver_description" msgid="2307555792915978653">"Kad akumuliatorius veiktų ilgiau, akumuliatoriaus tausojimo priemonė:\n·įjungia tamsiąją temą;\n·išjungia arba apriboja veiklą fone, kai kuriuos vaizdinius efektus ir kitas funkcijas, pvz., „Hey Google“."</string> <string name="data_saver_description" msgid="6015391409098303235">"Kad padėtų sumažinti duomenų naudojimą, Duomenų taupymo priemonė neleidžia kai kurioms programoms siųsti ar gauti duomenų fone. Šiuo metu naudojama programa gali pasiekti duomenis, bet tai bus daroma rečiau. Tai gali reikšti, kad, pvz., vaizdai nebus pateikiami, jei jų nepaliesite."</string> <string name="data_saver_enable_title" msgid="4674073932722787417">"Įj. Duomenų taupymo priemonę?"</string> <string name="data_saver_enable_button" msgid="7147735965247211818">"Įjungti"</string> @@ -2076,4 +2074,22 @@ <string name="chooser_no_direct_share_targets" msgid="997970693708458895">"Tiesioginio bendrinimo funkcija nepasiekiama"</string> <string name="chooser_all_apps_button_label" msgid="3631524352936289457">"Programų sąrašas"</string> <string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"Šiai programai nebuvo suteiktas leidimas įrašyti, bet ji gali užfiksuoti garsą per šį USB įrenginį."</string> + <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) --> + <skip /> + <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) --> + <skip /> + <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) --> + <skip /> + <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) --> + <skip /> + <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) --> + <skip /> + <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) --> + <skip /> + <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) --> + <skip /> + <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) --> + <skip /> + <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) --> + <skip /> </resources> diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml index a936bcc5af79..89a98dd57fdc 100644 --- a/core/res/res/values-lv/strings.xml +++ b/core/res/res/values-lv/strings.xml @@ -1794,10 +1794,8 @@ <string name="package_updated_device_owner" msgid="1847154566357862089">"Atjaunināja administrators"</string> <string name="package_deleted_device_owner" msgid="2307122077550236438">"Dzēsa administrators"</string> <string name="confirm_battery_saver" msgid="639106420541753635">"Labi"</string> - <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) --> - <skip /> - <!-- no translation found for battery_saver_description (2307555792915978653) --> - <skip /> + <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"Lai pagarinātu akumulatora darbības ilgumu, akumulatora jaudas taupīšanas režīmā tiek veiktas tālāk norādītās darbības.\n·Tiek ieslēgts tumšais motīvs.\n·Tiek izslēgtas vai ierobežotas darbības fonā, daži vizuālie efekti un citas funkcijas, piemēram, “Hey Google”.\n\n"<annotation id="url">"Uzzināt vairāk"</annotation></string> + <string name="battery_saver_description" msgid="2307555792915978653">"Lai pagarinātu akumulatora darbības ilgumu, akumulatora jaudas taupīšanas režīmā tiek veiktas tālāk norādītās darbības.\n·Tiek ieslēgts tumšais motīvs.\n·Tiek izslēgtas vai ierobežotas darbības fonā, daži vizuālie efekti un citas funkcijas, piemēram, “Hey Google”."</string> <string name="data_saver_description" msgid="6015391409098303235">"Lai samazinātu datu lietojumu, datu lietojuma samazinātājs neļauj dažām lietotnēm fonā nosūtīt vai saņemt datus. Lietotne, kuru pašlaik izmantojat, var piekļūt datiem, bet, iespējams, piekļūs tiem retāk (piemēram, attēli tiks parādīti tikai tad, kad tiem pieskarsieties)."</string> <string name="data_saver_enable_title" msgid="4674073932722787417">"Vai ieslēgt datu lietojuma samazinātāju?"</string> <string name="data_saver_enable_button" msgid="7147735965247211818">"Ieslēgt"</string> @@ -2042,4 +2040,22 @@ <string name="chooser_no_direct_share_targets" msgid="997970693708458895">"Tiešā kopīgošana nav pieejama"</string> <string name="chooser_all_apps_button_label" msgid="3631524352936289457">"Lietotņu saraksts"</string> <string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"Šai lietotnei nav piešķirta ierakstīšanas atļauja, taču tā varētu tvert audio, izmantojot šo USB ierīci."</string> + <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) --> + <skip /> + <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) --> + <skip /> + <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) --> + <skip /> + <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) --> + <skip /> + <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) --> + <skip /> + <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) --> + <skip /> + <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) --> + <skip /> + <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) --> + <skip /> + <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) --> + <skip /> </resources> diff --git a/core/res/res/values-mk/strings.xml b/core/res/res/values-mk/strings.xml index e4bfdf474003..4396c086feed 100644 --- a/core/res/res/values-mk/strings.xml +++ b/core/res/res/values-mk/strings.xml @@ -1773,10 +1773,8 @@ <string name="package_updated_device_owner" msgid="1847154566357862089">"Ажурирано од администраторот"</string> <string name="package_deleted_device_owner" msgid="2307122077550236438">"Избришано од администраторот"</string> <string name="confirm_battery_saver" msgid="639106420541753635">"Во ред"</string> - <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) --> - <skip /> - <!-- no translation found for battery_saver_description (2307555792915978653) --> - <skip /> + <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"За да го продолжи траењето на батеријата, „Штедачот на батерија“:\n·вклучува темна тема\n·исклучува или ограничува активност во заднина, некои визуелни ефекти и други функции како „Hey Google“\n\n"<annotation id="url">"Дознајте повеќе"</annotation></string> + <string name="battery_saver_description" msgid="2307555792915978653">"За да го продолжи траењето на батеријата, „Штедачот на батерија“:\n·вклучува темна тема\n·исклучува или ограничува активност во заднина, некои визуелни ефекти и други функции како „Hey Google“"</string> <string name="data_saver_description" msgid="6015391409098303235">"За да се намали користењето интернет, „Штедачот на интернет“ спречува дел од апликациите да испраќаат или да примаат податоци во заднина. Апликацијата што ја користите во моментов можеби ќе пристапува до интернет, но тоа ќе го прави поретко. Ова значи, на пример, дека сликите нема да се прикажат додека не ги допрете."</string> <string name="data_saver_enable_title" msgid="4674073932722787417">"Вклучете Штедач на интернет?"</string> <string name="data_saver_enable_button" msgid="7147735965247211818">"Вклучи"</string> @@ -2010,4 +2008,22 @@ <string name="chooser_no_direct_share_targets" msgid="997970693708458895">"Не е достапно директно споделување"</string> <string name="chooser_all_apps_button_label" msgid="3631524352936289457">"Список со апликации"</string> <string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"На апликацијава не ѝ е доделена дозвола за снимање, но може да снима аудио преку овој USB-уред."</string> + <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) --> + <skip /> + <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) --> + <skip /> + <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) --> + <skip /> + <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) --> + <skip /> + <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) --> + <skip /> + <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) --> + <skip /> + <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) --> + <skip /> + <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) --> + <skip /> + <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) --> + <skip /> </resources> diff --git a/core/res/res/values-ml/strings.xml b/core/res/res/values-ml/strings.xml index 695787955d99..0b3397105c13 100644 --- a/core/res/res/values-ml/strings.xml +++ b/core/res/res/values-ml/strings.xml @@ -1771,10 +1771,8 @@ <string name="package_updated_device_owner" msgid="1847154566357862089">"നിങ്ങളുടെ അഡ്മിൻ അപ്ഡേറ്റ് ചെയ്യുന്നത്"</string> <string name="package_deleted_device_owner" msgid="2307122077550236438">"നിങ്ങളുടെ അഡ്മിൻ ഇല്ലാതാക്കുന്നത്"</string> <string name="confirm_battery_saver" msgid="639106420541753635">"ശരി"</string> - <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) --> - <skip /> - <!-- no translation found for battery_saver_description (2307555792915978653) --> - <skip /> + <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"ബാറ്ററി ലെെഫ് വികസിപ്പിക്കാൻ, \'ബാറ്ററി ലാഭിക്കൽ\':\n ഡാർക്ക് തീം ഓണാക്കും\nപശ്ചാത്തല പ്രവർത്തനം, ചില വിഷ്വൽ ഇഫക്റ്റുകൾ, “ഹേയ് Google” പോലുള്ള മറ്റ് ഫീച്ചറുകൾ എന്നിവ ഓഫാക്കുകയോ നിയന്ത്രിക്കുകയോ ചെയ്യും\n\n"<annotation id="url">"കൂടുതലറിയുക"</annotation></string> + <string name="battery_saver_description" msgid="2307555792915978653">"ബാറ്ററി ലെെഫ് വികസിപ്പിക്കാൻ, \'ബാറ്ററി ലാഭിക്കൽ\':\n ഡാർക്ക് തീം ഓണാക്കും\nപശ്ചാത്തല പ്രവർത്തനം, ചില വിഷ്വൽ ഇഫക്റ്റുകൾ, “ഹേയ് Google” പോലുള്ള മറ്റ് ഫീച്ചറുകൾ എന്നിവ ഓഫാക്കുകയോ നിയന്ത്രിക്കുകയോ ചെയ്യും"</string> <string name="data_saver_description" msgid="6015391409098303235">"ഡാറ്റാ ഉപയോഗം കുറയ്ക്കാൻ സഹായിക്കുന്നതിനായി പശ്ചാത്തലത്തിൽ ഡാറ്റ അയയ്ക്കുകയോ സ്വീകരിക്കുകയോ ചെയ്യുന്നതിൽ നിന്ന് ചില ആപ്പുകളെ ഡാറ്റാ സേവർ തടയുന്നു. നിങ്ങൾ നിലവിൽ ഉപയോഗിക്കുന്ന ഒരു ആപ്പിന് ഡാറ്റ ആക്സസ് ചെയ്യാനാകും, എന്നാൽ വല്ലപ്പോഴും മാത്രമെ സംഭവിക്കുന്നുള്ളു. ഇതിനർത്ഥം, ഉദാഹരണമായി നിങ്ങൾ ടാപ്പ് ചെയ്യുന്നത് വരെ ചിത്രങ്ങൾ പ്രദർശിപ്പിക്കുകയില്ല എന്നാണ്."</string> <string name="data_saver_enable_title" msgid="4674073932722787417">"ഡാറ്റ സേവർ ഓണാക്കണോ?"</string> <string name="data_saver_enable_button" msgid="7147735965247211818">"ഓണാക്കുക"</string> @@ -2008,4 +2006,22 @@ <string name="chooser_no_direct_share_targets" msgid="997970693708458895">"നേരിട്ടുള്ള പങ്കിടൽ ലഭ്യമല്ല"</string> <string name="chooser_all_apps_button_label" msgid="3631524352936289457">"ആപ്പുകളുടെ ലിസ്റ്റ്"</string> <string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"ഈ ആപ്പിന് റെക്കോർഡ് അനുമതി നൽകിയിട്ടില്ല, എന്നാൽ ഈ USB ഉപകരണത്തിലൂടെ ഓഡിയോ ക്യാപ്ചർ ചെയ്യാനാവും."</string> + <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) --> + <skip /> + <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) --> + <skip /> + <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) --> + <skip /> + <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) --> + <skip /> + <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) --> + <skip /> + <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) --> + <skip /> + <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) --> + <skip /> + <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) --> + <skip /> + <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) --> + <skip /> </resources> diff --git a/core/res/res/values-mn/strings.xml b/core/res/res/values-mn/strings.xml index f1077c56dbd3..990a4d0dc21a 100644 --- a/core/res/res/values-mn/strings.xml +++ b/core/res/res/values-mn/strings.xml @@ -1771,10 +1771,8 @@ <string name="package_updated_device_owner" msgid="1847154566357862089">"Таны админ шинэчилсэн"</string> <string name="package_deleted_device_owner" msgid="2307122077550236438">"Таны админ устгасан"</string> <string name="confirm_battery_saver" msgid="639106420541753635">"ОК"</string> - <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) --> - <skip /> - <!-- no translation found for battery_saver_description (2307555792915978653) --> - <skip /> + <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"Батарейны ажиллах хугацааг уртасгахын тулд Батарей хэмнэгч нь:\n·Бараан загварыг асаадаг\n·Арын үйл ажиллагаа, зарим визуал эффект болон “Hey Google” зэрэг бусад онцлогийг унтрааж эсвэл хязгаарладаг\n\n"<annotation id="url">"Нэмэлт мэдээлэл авах"</annotation></string> + <string name="battery_saver_description" msgid="2307555792915978653">"Батарейны ажиллах хугацааг уртасгахын тулд Батарей хэмнэгч нь:\n·Бараан загварыг асаадаг\n·Арын үйл ажиллагаа, зарим визуал эффект болон “Hey Google” зэрэг бусад онцлогийг унтрааж эсвэл хязгаарладаг"</string> <string name="data_saver_description" msgid="6015391409098303235">"Дата ашиглалтыг багасгахын тулд дата хэмнэгч нь зарим апп-н өгөгдлийг дэвсгэрт илгээх болон авахаас сэргийлдэг. Таны одоогийн ашиглаж буй апп нь өгөгдөлд хандах боломжтой хэдий ч тогтмол хандахгүй. Жишээлбэл зургийг товших хүртэл харагдахгүй."</string> <string name="data_saver_enable_title" msgid="4674073932722787417">"Дата хэмнэгчийг асаах уу?"</string> <string name="data_saver_enable_button" msgid="7147735965247211818">"Асаах"</string> @@ -2008,4 +2006,22 @@ <string name="chooser_no_direct_share_targets" msgid="997970693708458895">"Шууд хуваалцах боломжгүй"</string> <string name="chooser_all_apps_button_label" msgid="3631524352936289457">"Аппын жагсаалт"</string> <string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"Энэ апликейшнд бичих зөвшөөрөл олгогдоогүй ч энэ USB төхөөрөмжөөр дамжуулан аудио бичиж чадсан."</string> + <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) --> + <skip /> + <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) --> + <skip /> + <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) --> + <skip /> + <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) --> + <skip /> + <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) --> + <skip /> + <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) --> + <skip /> + <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) --> + <skip /> + <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) --> + <skip /> + <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) --> + <skip /> </resources> diff --git a/core/res/res/values-mr/strings.xml b/core/res/res/values-mr/strings.xml index 6b17e277c739..edc89a428286 100644 --- a/core/res/res/values-mr/strings.xml +++ b/core/res/res/values-mr/strings.xml @@ -1771,10 +1771,8 @@ <string name="package_updated_device_owner" msgid="1847154566357862089">"आपल्या प्रशासकाने अपडेट केले"</string> <string name="package_deleted_device_owner" msgid="2307122077550236438">"आपल्या प्रशासकाने हटवले"</string> <string name="confirm_battery_saver" msgid="639106420541753635">"ओके"</string> - <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) --> - <skip /> - <!-- no translation found for battery_saver_description (2307555792915978653) --> - <skip /> + <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"बॅटरी सेव्हर हे बॅटरीचे आयुष्य वाढवते:\n·गडद थीम सुरू करते \n· बॅकग्राउंड अॅक्टिव्हिटी, काही व्हिज्युअल इफेक्ट आणि \"Ok Google\" यासारखी वैशिष्ट्ये बंद किंवा मर्यादित करते.\n\n"<annotation id="url">"अधिक जाणून घ्या"</annotation></string> + <string name="battery_saver_description" msgid="2307555792915978653">"बॅटरी सेव्हर हे बॅटरीचे आयुष्य वाढवते:\n·गडद थीम सुरू करते \n· बॅकग्राउंड अॅक्टिव्हिटी, काही व्हिज्युअल इफेक्ट आणि \"Ok Google\" यासारखी वैशिष्ट्ये बंद किंवा मर्यादित करते."</string> <string name="data_saver_description" msgid="6015391409098303235">"डेटा सर्व्हर डेटाचा वापर कमी करण्यात मदत करण्यासाठी काही अॅप्सना पार्श्वभूमीमध्ये डेटा पाठवण्यास किंवा मिळवण्यास प्रतिबंध करतो. तुम्ही सध्या वापरत असलेले अॅप डेटा अॅक्सेस करू शकते, पण तसे खूप कमी वेळा होते. याचाच अर्थ असा की, तुम्ही इमेजवर टॅप करेपर्यंत त्या डिस्प्ले होणार नाहीत असा असू शकतो."</string> <string name="data_saver_enable_title" msgid="4674073932722787417">"डेटा सेव्हर चालू करायचा?"</string> <string name="data_saver_enable_button" msgid="7147735965247211818">"चालू करा"</string> @@ -2008,4 +2006,22 @@ <string name="chooser_no_direct_share_targets" msgid="997970693708458895">"थेट शेअर करणे उपलब्ध नाही"</string> <string name="chooser_all_apps_button_label" msgid="3631524352936289457">"अॅप्स सूची"</string> <string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"या अॅपला रेकॉर्ड करण्याची परवानगी दिली गेली नाही पण हे USB डिव्हाइस वापरून ऑडिओ कॅप्चर केला जाऊ शकतो."</string> + <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) --> + <skip /> + <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) --> + <skip /> + <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) --> + <skip /> + <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) --> + <skip /> + <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) --> + <skip /> + <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) --> + <skip /> + <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) --> + <skip /> + <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) --> + <skip /> + <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) --> + <skip /> </resources> diff --git a/core/res/res/values-ms/strings.xml b/core/res/res/values-ms/strings.xml index 37d5ef12f09f..0c881c50baf8 100644 --- a/core/res/res/values-ms/strings.xml +++ b/core/res/res/values-ms/strings.xml @@ -1771,10 +1771,8 @@ <string name="package_updated_device_owner" msgid="1847154566357862089">"Dikemas kini oleh pentadbir anda"</string> <string name="package_deleted_device_owner" msgid="2307122077550236438">"Dipadamkan oleh pentadbir anda"</string> <string name="confirm_battery_saver" msgid="639106420541753635">"OK"</string> - <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) --> - <skip /> - <!-- no translation found for battery_saver_description (2307555792915978653) --> - <skip /> + <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"Untuk melanjutkan hayat bateri, Penjimat Bateri:\n·Menghidupkan Tema gelap\n·Mematikan atau mengehadkan aktiviti latar belakang, sesetengah kesan visual dan ciri lain seperti “Hey Google”\n\n"<annotation id="url">"Ketahui lebih lanjut"</annotation></string> + <string name="battery_saver_description" msgid="2307555792915978653">"Untuk melanjutkan hayat bateri, Penjimat Bateri:\n·Menghidupkan Tema gelap\n·Mematikan atau mengehadkan aktiviti latar belakang, sesetengah kesan visual dan ciri lain seperti “Hey Google”"</string> <string name="data_saver_description" msgid="6015391409098303235">"Untuk membantu mengurangkan penggunaan data, Penjimat Data menghalang sesetengah apl daripada menghantar atau menerima data di latar. Apl yang sedang digunakan boleh mengakses data tetapi mungkin tidak secara kerap. Perkara ini mungkin bermaksud bahawa imej tidak dipaparkan sehingga anda mengetik pada imej itu, contohnya."</string> <string name="data_saver_enable_title" msgid="4674073932722787417">"Hidupkan Penjimat Data?"</string> <string name="data_saver_enable_button" msgid="7147735965247211818">"Hidupkan"</string> @@ -2008,4 +2006,22 @@ <string name="chooser_no_direct_share_targets" msgid="997970693708458895">"Perkongsian langsung tidak tersedia"</string> <string name="chooser_all_apps_button_label" msgid="3631524352936289457">"Senarai apl"</string> <string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"Apl ini belum diberikan kebenaran merakam tetapi dapat merakam audio melalui peranti USB ini."</string> + <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) --> + <skip /> + <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) --> + <skip /> + <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) --> + <skip /> + <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) --> + <skip /> + <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) --> + <skip /> + <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) --> + <skip /> + <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) --> + <skip /> + <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) --> + <skip /> + <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) --> + <skip /> </resources> diff --git a/core/res/res/values-my/strings.xml b/core/res/res/values-my/strings.xml index 8e154b92af93..f5745b519af8 100644 --- a/core/res/res/values-my/strings.xml +++ b/core/res/res/values-my/strings.xml @@ -1771,10 +1771,8 @@ <string name="package_updated_device_owner" msgid="1847154566357862089">"သင်၏ စီမံခန့်ခွဲသူက အပ်ဒိတ်လုပ်ထားသည်"</string> <string name="package_deleted_device_owner" msgid="2307122077550236438">"သင်၏ စီမံခန့်ခွဲသူက ဖျက်လိုက်ပါပြီ"</string> <string name="confirm_battery_saver" msgid="639106420541753635">"OK"</string> - <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) --> - <skip /> - <!-- no translation found for battery_saver_description (2307555792915978653) --> - <skip /> + <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"ဘက်ထရီသက်တမ်း ပိုရှည်စေရန် \'ဘက်ထရီအားထိန်း\' က \n·မှောင်သည့် အပြင်အဆင်ကို ဖွင့်သည် \n·နောက်ခံလုပ်ဆောင်ချက် အချို့ အမြင်အာရုံဆိုင်ရာ အထူးပြုလုပ်ချက်များနှင့် “Hey Google” ကဲ့သို့ အခြား ဝန်ဆောင်မှုများကို ပိတ်ခြင်း သို့မဟုတ် ကန့်သတ်ခြင်းတို့ ပြုလုပ်သည်။\n\n"<annotation id="url">"ပိုမိုလေ့လာရန်"</annotation></string> + <string name="battery_saver_description" msgid="2307555792915978653">"ဘက်ထရီသက်တမ်း ပိုရှည်စေရန် \'ဘက်ထရီအားထိန်း\' က \n·မှောင်သည့် အပြင်အဆင်ကို ဖွင့်သည် \n·နောက်ခံလုပ်ဆောင်ချက် အချို့ အမြင်အာရုံဆိုင်ရာ အထူးပြုလုပ်ချက်များနှင့် “Hey Google” ကဲ့သို့ အခြား ဝန်ဆောင်မှုများကို ပိတ်ခြင်း သို့မဟုတ် ကန့်သတ်ခြင်းတို့ ပြုလုပ်သည်။"</string> <string name="data_saver_description" msgid="6015391409098303235">"ဒေတာအသုံးလျှော့ချနိုင်ရန်အတွက် အက်ပ်များကို နောက်ခံတွင် ဒေတာပို့ခြင်းနှင့် လက်ခံခြင်းမပြုရန် \'ဒေတာချွေတာမှု\' စနစ်က တားဆီးထားပါသည်။ ယခုအက်ပ်ဖြင့် ဒေတာအသုံးပြုနိုင်သော်လည်း အကြိမ်လျှော့၍သုံးရပါမည်။ ဥပမာ၊ သင်က မတို့မချင်း ပုံများပေါ်လာမည် မဟုတ်ပါ။"</string> <string name="data_saver_enable_title" msgid="4674073932722787417">"ဒေတာအသုံးပြုမှု ချွေတာမှုစနစ်ကို ဖွင့်မလား။"</string> <string name="data_saver_enable_button" msgid="7147735965247211818">"ဖွင့်ပါ"</string> @@ -2008,4 +2006,22 @@ <string name="chooser_no_direct_share_targets" msgid="997970693708458895">"တိုက်ရိုက်မျှဝေ၍ မရပါ"</string> <string name="chooser_all_apps_button_label" msgid="3631524352936289457">"အက်ပ်စာရင်း"</string> <string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"ဤအက်ပ်ကို အသံဖမ်းခွင့် ပေးမထားသော်လည်း ၎င်းသည် ဤ USB စက်ပစ္စည်းမှတစ်ဆင့် အသံများကို ဖမ်းယူနိုင်ပါသည်။"</string> + <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) --> + <skip /> + <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) --> + <skip /> + <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) --> + <skip /> + <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) --> + <skip /> + <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) --> + <skip /> + <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) --> + <skip /> + <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) --> + <skip /> + <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) --> + <skip /> + <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) --> + <skip /> </resources> diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml index d9d59ea2e094..03597793c0dc 100644 --- a/core/res/res/values-nb/strings.xml +++ b/core/res/res/values-nb/strings.xml @@ -1771,10 +1771,8 @@ <string name="package_updated_device_owner" msgid="1847154566357862089">"Oppdatert av administratoren din"</string> <string name="package_deleted_device_owner" msgid="2307122077550236438">"Slettet av administratoren din"</string> <string name="confirm_battery_saver" msgid="639106420541753635">"OK"</string> - <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) --> - <skip /> - <!-- no translation found for battery_saver_description (2307555792915978653) --> - <skip /> + <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"For å forlenge batterilevetiden slår Batterisparing\n·på mørkt tema\n·av eller begrenser bakgrunnsaktivitet, enkelte visuelle effekter og andre funksjoner, for eksempel «Hey Google»\n\n"<annotation id="url">"Finn ut mer"</annotation></string> + <string name="battery_saver_description" msgid="2307555792915978653">"For å forlenge batterilevetiden slår Batterisparing\n·på mørkt tema\n·av eller begrenser bakgrunnsaktivitet, enkelte visuelle effekter og andre funksjoner, for eksempel «Hey Google»"</string> <string name="data_saver_description" msgid="6015391409098303235">"Datasparing hindrer noen apper fra å sende og motta data i bakgrunnen, for å redusere dataforbruket. Aktive apper kan bruke data, men kanskje ikke så mye som ellers – for eksempel vises ikke bilder før du trykker på dem."</string> <string name="data_saver_enable_title" msgid="4674073932722787417">"Vil du slå på Datasparing?"</string> <string name="data_saver_enable_button" msgid="7147735965247211818">"Slå på"</string> @@ -2008,4 +2006,22 @@ <string name="chooser_no_direct_share_targets" msgid="997970693708458895">"Direktedeling er ikke tilgjengelig"</string> <string name="chooser_all_apps_button_label" msgid="3631524352936289457">"Appliste"</string> <string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"Denne appen har ikke fått tillatelse til å spille inn, men kan ta opp lyd med denne USB-enheten."</string> + <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) --> + <skip /> + <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) --> + <skip /> + <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) --> + <skip /> + <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) --> + <skip /> + <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) --> + <skip /> + <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) --> + <skip /> + <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) --> + <skip /> + <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) --> + <skip /> + <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) --> + <skip /> </resources> diff --git a/core/res/res/values-ne/strings.xml b/core/res/res/values-ne/strings.xml index 2b61999b2a4a..2617086bcbd4 100644 --- a/core/res/res/values-ne/strings.xml +++ b/core/res/res/values-ne/strings.xml @@ -2014,4 +2014,22 @@ <string name="chooser_no_direct_share_targets" msgid="997970693708458895">"सीधै आदान प्रदान गर्ने सुविधा उपलब्ध छैन"</string> <string name="chooser_all_apps_button_label" msgid="3631524352936289457">"अनुप्रयोगहरूको सूची"</string> <string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"यो अनुप्रयोगलाई रेकर्ड गर्ने अनुमति प्रदान गरिएको छैन तर यसले यो USB यन्त्रमार्फत अडियो क्याप्चर गर्न सक्छ।"</string> + <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) --> + <skip /> + <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) --> + <skip /> + <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) --> + <skip /> + <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) --> + <skip /> + <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) --> + <skip /> + <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) --> + <skip /> + <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) --> + <skip /> + <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) --> + <skip /> + <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) --> + <skip /> </resources> diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml index 5922388a232a..43b4edecb509 100644 --- a/core/res/res/values-nl/strings.xml +++ b/core/res/res/values-nl/strings.xml @@ -1771,10 +1771,8 @@ <string name="package_updated_device_owner" msgid="1847154566357862089">"Geüpdatet door je beheerder"</string> <string name="package_deleted_device_owner" msgid="2307122077550236438">"Verwijderd door je beheerder"</string> <string name="confirm_battery_saver" msgid="639106420541753635">"OK"</string> - <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) --> - <skip /> - <!-- no translation found for battery_saver_description (2307555792915978653) --> - <skip /> + <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"Batterijbesparing doet het volgende om de batterijduur te verlengen:\n·Het donkere thema inschakelen\n·Achtergrondactiviteit, bepaalde visuele effecten en andere functies (zoals \'Hey Google\') uitschakelen of beperken\n\n"<annotation id="url">"Meer informatie"</annotation></string> + <string name="battery_saver_description" msgid="2307555792915978653">"Batterijbesparing doet het volgende om de batterijduur te verlengen:\n Het donkere thema inschakelen\n·Achtergrondactiviteit, bepaalde visuele effecten en andere functies (zoals \'Hey Google\') uitschakelen of beperken"</string> <string name="data_saver_description" msgid="6015391409098303235">"Databesparing beperkt het datagebruik door te voorkomen dat sommige apps gegevens verzenden of ontvangen op de achtergrond. De apps die je open hebt, kunnen nog steeds data verbruiken, maar doen dit minder vaak. Afbeeldingen worden dan bijvoorbeeld niet weergegeven totdat je erop tikt."</string> <string name="data_saver_enable_title" msgid="4674073932722787417">"Databesparing inschakelen?"</string> <string name="data_saver_enable_button" msgid="7147735965247211818">"Inschakelen"</string> @@ -2008,4 +2006,22 @@ <string name="chooser_no_direct_share_targets" msgid="997970693708458895">"Rechtstreeks delen is niet beschikbaar"</string> <string name="chooser_all_apps_button_label" msgid="3631524352936289457">"Lijst met apps"</string> <string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"Deze app heeft geen opnamerechten gekregen, maar zou audio kunnen vastleggen via dit USB-apparaat."</string> + <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) --> + <skip /> + <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) --> + <skip /> + <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) --> + <skip /> + <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) --> + <skip /> + <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) --> + <skip /> + <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) --> + <skip /> + <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) --> + <skip /> + <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) --> + <skip /> + <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) --> + <skip /> </resources> diff --git a/core/res/res/values-or/strings.xml b/core/res/res/values-or/strings.xml index 04d56524def5..68b76c839540 100644 --- a/core/res/res/values-or/strings.xml +++ b/core/res/res/values-or/strings.xml @@ -2008,4 +2008,22 @@ <string name="chooser_no_direct_share_targets" msgid="997970693708458895">"ସିଧାସଳଖ ସେୟାର୍ ସୁବିଧା ଉପଲବ୍ଧ ନାହିଁ"</string> <string name="chooser_all_apps_button_label" msgid="3631524352936289457">"ଆପ୍ସ ତାଲିକା"</string> <string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"ଏହି ଆପ୍କୁ ରେକର୍ଡ କରିବାକୁ ଅନୁମତି ଦିଆଯାଇ ନାହିଁ କିନ୍ତୁ ଏହି USB ଡିଭାଇସ୍ ଜରିଆରେ ଅଡିଓ କ୍ୟାପ୍ଚର୍ କରିପାରିବ।"</string> + <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) --> + <skip /> + <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) --> + <skip /> + <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) --> + <skip /> + <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) --> + <skip /> + <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) --> + <skip /> + <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) --> + <skip /> + <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) --> + <skip /> + <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) --> + <skip /> + <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) --> + <skip /> </resources> diff --git a/core/res/res/values-pa/strings.xml b/core/res/res/values-pa/strings.xml index 2cc004c8bcd6..63b5f53e074d 100644 --- a/core/res/res/values-pa/strings.xml +++ b/core/res/res/values-pa/strings.xml @@ -1771,10 +1771,8 @@ <string name="package_updated_device_owner" msgid="1847154566357862089">"ਤੁਹਾਡੇ ਪ੍ਰਸ਼ਾਸਕ ਵੱਲੋਂ ਅੱਪਡੇਟ ਕੀਤਾ ਗਿਆ"</string> <string name="package_deleted_device_owner" msgid="2307122077550236438">"ਤੁਹਾਡੇ ਪ੍ਰਸ਼ਾਸਕ ਵੱਲੋਂ ਮਿਟਾਇਆ ਗਿਆ"</string> <string name="confirm_battery_saver" msgid="639106420541753635">"ਠੀਕ ਹੈ"</string> - <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) --> - <skip /> - <!-- no translation found for battery_saver_description (2307555792915978653) --> - <skip /> + <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"ਬੈਟਰੀ ਲਾਈਫ਼ ਵਧਾਉਣ ਲਈ, ਬੈਟਰੀ ਸੇਵਰ:\n ਗੂੜ੍ਹਾ ਥੀਮ ਚਾਲੂ ਕਰਦਾ ਹੈ\n ਬੈਕਗ੍ਰਾਊਂਡ ਸਰਗਰਮੀ, ਕੁਝ ਦ੍ਰਿਸ਼ ਪ੍ਰਭਾਵਾਂ, ਅਤੇ \"Hey Google\" ਵਰਗੀਆਂ ਹੋਰ ਵਿਸ਼ੇਸ਼ਤਾਵਾਂ ਨੂੰ ਬੰਦ ਕਰਦਾ ਹੈ ਜਾਂ ਉਹਨਾਂ \'ਤੇ ਪਾਬੰਦੀ ਲਗਾਉਂਦਾ ਹੈ\n\n"<annotation id="url">"ਹੋਰ ਜਾਣੋ"</annotation></string> + <string name="battery_saver_description" msgid="2307555792915978653">"ਬੈਟਰੀ ਲਾਈਫ਼ ਵਧਾਉਣ ਲਈ, ਬੈਟਰੀ ਸੇਵਰ:\n ਗੂੜ੍ਹਾ ਥੀਮ ਚਾਲੂ ਕਰਦਾ ਹੈ\n ਬੈਕਗ੍ਰਾਊਂਡ ਸਰਗਰਮੀ, ਕੁਝ ਦ੍ਰਿਸ਼ ਪ੍ਰਭਾਵਾਂ, ਅਤੇ \"Hey Google\" ਵਰਗੀਆਂ ਹੋਰ ਵਿਸ਼ੇਸ਼ਤਾਵਾਂ ਨੂੰ ਬੰਦ ਕਰਦਾ ਹੈ ਜਾਂ ਉਹਨਾਂ \'ਤੇ ਪਾਬੰਦੀ ਲਗਾਉਂਦਾ ਹੈ"</string> <string name="data_saver_description" msgid="6015391409098303235">"ਡਾਟਾ ਵਰਤੋਂ ਘਟਾਉਣ ਵਿੱਚ ਮਦਦ ਲਈ, ਡਾਟਾ ਸੇਵਰ ਕੁਝ ਐਪਾਂ ਨੂੰ ਬੈਕਗ੍ਰਾਊਂਡ ਵਿੱਚ ਡਾਟਾ ਭੇਜਣ ਜਾਂ ਪ੍ਰਾਪਤ ਕਰਨ ਤੋਂ ਰੋਕਦਾ ਹੈ। ਤੁਹਾਡੇ ਵੱਲੋਂ ਵਰਤਮਾਨ ਤੌਰ \'ਤੇ ਵਰਤੀ ਜਾ ਰਹੀ ਐਪ ਡਾਟਾ \'ਤੇ ਪਹੁੰਚ ਕਰ ਸਕਦੀ ਹੈ, ਪਰ ਉਹ ਇੰਝ ਕਦੇ-ਕਦਾਈਂ ਕਰ ਸਕਦੀ ਹੈ। ਉਦਾਹਰਨ ਲਈ, ਇਸ ਦਾ ਮਤਲਬ ਇਹ ਹੋ ਸਕਦਾ ਹੈ ਕਿ ਚਿੱਤਰ ਤਦ ਤੱਕ ਨਹੀਂ ਪ੍ਰਦਰਸ਼ਿਤ ਕੀਤੇ ਜਾਂਦੇ, ਜਦੋਂ ਤੱਕ ਤੁਸੀਂ ਉਹਨਾਂ \'ਤੇ ਟੈਪ ਨਹੀਂ ਕਰਦੇ।"</string> <string name="data_saver_enable_title" msgid="4674073932722787417">"ਕੀ ਡਾਟਾ ਸੇਵਰ ਚਾਲੂ ਕਰਨਾ ਹੈ?"</string> <string name="data_saver_enable_button" msgid="7147735965247211818">"ਚਾਲੂ ਕਰੋ"</string> @@ -2008,4 +2006,22 @@ <string name="chooser_no_direct_share_targets" msgid="997970693708458895">"ਸਿੱਧਾ ਸਾਂਝਾ ਕਰਨ ਦੀ ਸੁਵਿਧਾ ਉਪਲਬਧ ਨਹੀਂ ਹੈ"</string> <string name="chooser_all_apps_button_label" msgid="3631524352936289457">"ਐਪ ਸੂਚੀ"</string> <string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"ਇਸ ਐਪ ਨੂੰ ਰਿਕਾਰਡ ਕਰਨ ਦੀ ਇਜਾਜ਼ਤ ਨਹੀਂ ਦਿੱਤੀ ਗਈ ਪਰ ਇਹ USB ਡੀਵਾਈਸ ਰਾਹੀਂ ਆਡੀਓ ਕੈਪਚਰ ਕਰ ਸਕਦੀ ਹੈ।"</string> + <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) --> + <skip /> + <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) --> + <skip /> + <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) --> + <skip /> + <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) --> + <skip /> + <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) --> + <skip /> + <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) --> + <skip /> + <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) --> + <skip /> + <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) --> + <skip /> + <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) --> + <skip /> </resources> diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml index a5d8125e694d..bd695a9b17e2 100644 --- a/core/res/res/values-pl/strings.xml +++ b/core/res/res/values-pl/strings.xml @@ -1817,10 +1817,8 @@ <string name="package_updated_device_owner" msgid="1847154566357862089">"Zaktualizowany przez administratora"</string> <string name="package_deleted_device_owner" msgid="2307122077550236438">"Usunięty przez administratora"</string> <string name="confirm_battery_saver" msgid="639106420541753635">"OK"</string> - <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) --> - <skip /> - <!-- no translation found for battery_saver_description (2307555792915978653) --> - <skip /> + <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"Aby wydłużyć czas pracy na baterii, Oszczędzanie baterii:\n włącza tryb ciemny, \nwyłącza lub ogranicza aktywność w tle, niektóre efekty wizualne oraz inne funkcje, np. „OK Google”.\n\n"<annotation id="url">"Więcej informacji"</annotation></string> + <string name="battery_saver_description" msgid="2307555792915978653">"Aby wydłużyć czas pracy na baterii, Oszczędzanie baterii:\n włącza tryb ciemny,\n wyłącza lub ogranicza aktywność w tle, niektóre efekty wizualne oraz inne funkcje, np. „OK Google”."</string> <string name="data_saver_description" msgid="6015391409098303235">"Oszczędzanie danych uniemożliwia niektórym aplikacjom wysyłanie i odbieranie danych w tle, zmniejszając w ten sposób ich użycie. Aplikacja, z której w tej chwili korzystasz, może uzyskiwać dostęp do danych, ale rzadziej. Może to powodować, że obrazy będą się wyświetlać dopiero po kliknięciu."</string> <string name="data_saver_enable_title" msgid="4674073932722787417">"Włączyć Oszczędzanie danych?"</string> <string name="data_saver_enable_button" msgid="7147735965247211818">"Włącz"</string> @@ -2076,4 +2074,22 @@ <string name="chooser_no_direct_share_targets" msgid="997970693708458895">"Udostępnianie bezpośrednie jest niedostępne"</string> <string name="chooser_all_apps_button_label" msgid="3631524352936289457">"Lista aplikacji"</string> <string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"Ta aplikacja nie ma uprawnień do nagrywania, ale może rejestrować dźwięk za pomocą tego urządzenia USB."</string> + <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) --> + <skip /> + <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) --> + <skip /> + <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) --> + <skip /> + <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) --> + <skip /> + <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) --> + <skip /> + <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) --> + <skip /> + <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) --> + <skip /> + <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) --> + <skip /> + <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) --> + <skip /> </resources> diff --git a/core/res/res/values-pt-rBR/strings.xml b/core/res/res/values-pt-rBR/strings.xml index 9c44862be565..45a2abd26749 100644 --- a/core/res/res/values-pt-rBR/strings.xml +++ b/core/res/res/values-pt-rBR/strings.xml @@ -1771,10 +1771,8 @@ <string name="package_updated_device_owner" msgid="1847154566357862089">"Atualizado pelo seu administrador"</string> <string name="package_deleted_device_owner" msgid="2307122077550236438">"Excluído pelo seu administrador"</string> <string name="confirm_battery_saver" msgid="639106420541753635">"OK"</string> - <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) --> - <skip /> - <!-- no translation found for battery_saver_description (2307555792915978653) --> - <skip /> + <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"Para aumentar a duração da bateria, a \"Economia de bateria: \n ativa o tema escuro;\n·desativa ou restringe atividades em segundo plano, alguns efeitos visuais e outros recursos, como o \"Ok Google\".\n\n"<annotation id="url">"Saiba mais"</annotation></string> + <string name="battery_saver_description" msgid="2307555792915978653">"Para aumentar a duração da bateria, a \"Economia de bateria\": \n ativa o tema escuro;\n desativa ou restringe atividades em segundo plano, alguns efeitos visuais e outros recursos, como o \"Ok Google\"."</string> <string name="data_saver_description" msgid="6015391409098303235">"Para ajudar a reduzir o uso de dados, a Economia de dados impede que alguns apps enviem ou recebam dados em segundo plano. Um app que você esteja usando no momento pode acessar dados, mas com menos frequência. Isso pode fazer com que imagens não sejam exibidas até que você toque nelas."</string> <string name="data_saver_enable_title" msgid="4674073932722787417">"Ativar Economia de dados?"</string> <string name="data_saver_enable_button" msgid="7147735965247211818">"Ativar"</string> @@ -2008,4 +2006,22 @@ <string name="chooser_no_direct_share_targets" msgid="997970693708458895">"Compartilhamento direto indisponível"</string> <string name="chooser_all_apps_button_label" msgid="3631524352936289457">"Lista de apps"</string> <string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"Este app não tem permissão de gravação, mas pode capturar áudio pelo dispositivo USB."</string> + <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) --> + <skip /> + <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) --> + <skip /> + <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) --> + <skip /> + <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) --> + <skip /> + <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) --> + <skip /> + <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) --> + <skip /> + <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) --> + <skip /> + <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) --> + <skip /> + <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) --> + <skip /> </resources> diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml index 6a695a797bdd..0fd303fdeedd 100644 --- a/core/res/res/values-pt-rPT/strings.xml +++ b/core/res/res/values-pt-rPT/strings.xml @@ -1771,10 +1771,8 @@ <string name="package_updated_device_owner" msgid="1847154566357862089">"Atualizado pelo seu gestor"</string> <string name="package_deleted_device_owner" msgid="2307122077550236438">"Eliminado pelo seu gestor"</string> <string name="confirm_battery_saver" msgid="639106420541753635">"OK"</string> - <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) --> - <skip /> - <!-- no translation found for battery_saver_description (2307555792915978653) --> - <skip /> + <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"Para prolongar a autonomia da bateria, a Poupança de bateria:\n·Ativa o tema escuro.\n·Desativa ou restringe a atividade em segundo plano, alguns efeitos visuais e outras funcionalidades como \"Ok Google\".\n\n"<annotation id="url">"Saber mais"</annotation></string> + <string name="battery_saver_description" msgid="2307555792915978653">"Para prolongar a autonomia da bateria, a Poupança de bateria:\n·Ativa o tema escuro.\n·Desativa ou restringe a atividade em segundo plano, alguns efeitos visuais e outras funcionalidades como \"Ok Google\"."</string> <string name="data_saver_description" msgid="6015391409098303235">"Para ajudar a reduzir a utilização de dados, a Poupança de dados impede que algumas aplicações enviem ou recebam dados em segundo plano. Uma determinada aplicação que esteja a utilizar atualmente pode aceder aos dados, mas é possível que o faça com menos frequência. Isto pode significar, por exemplo, que as imagens não são apresentadas até que toque nas mesmas."</string> <string name="data_saver_enable_title" msgid="4674073932722787417">"Ativar a Poupança de dados?"</string> <string name="data_saver_enable_button" msgid="7147735965247211818">"Ativar"</string> @@ -2008,4 +2006,22 @@ <string name="chooser_no_direct_share_targets" msgid="997970693708458895">"A partilha direta não está disponível."</string> <string name="chooser_all_apps_button_label" msgid="3631524352936289457">"Lista de aplicações"</string> <string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"Esta aplicação não recebeu autorização de gravação, mas pode capturar áudio através deste dispositivo USB."</string> + <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) --> + <skip /> + <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) --> + <skip /> + <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) --> + <skip /> + <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) --> + <skip /> + <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) --> + <skip /> + <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) --> + <skip /> + <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) --> + <skip /> + <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) --> + <skip /> + <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) --> + <skip /> </resources> diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml index 9c44862be565..45a2abd26749 100644 --- a/core/res/res/values-pt/strings.xml +++ b/core/res/res/values-pt/strings.xml @@ -1771,10 +1771,8 @@ <string name="package_updated_device_owner" msgid="1847154566357862089">"Atualizado pelo seu administrador"</string> <string name="package_deleted_device_owner" msgid="2307122077550236438">"Excluído pelo seu administrador"</string> <string name="confirm_battery_saver" msgid="639106420541753635">"OK"</string> - <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) --> - <skip /> - <!-- no translation found for battery_saver_description (2307555792915978653) --> - <skip /> + <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"Para aumentar a duração da bateria, a \"Economia de bateria: \n ativa o tema escuro;\n·desativa ou restringe atividades em segundo plano, alguns efeitos visuais e outros recursos, como o \"Ok Google\".\n\n"<annotation id="url">"Saiba mais"</annotation></string> + <string name="battery_saver_description" msgid="2307555792915978653">"Para aumentar a duração da bateria, a \"Economia de bateria\": \n ativa o tema escuro;\n desativa ou restringe atividades em segundo plano, alguns efeitos visuais e outros recursos, como o \"Ok Google\"."</string> <string name="data_saver_description" msgid="6015391409098303235">"Para ajudar a reduzir o uso de dados, a Economia de dados impede que alguns apps enviem ou recebam dados em segundo plano. Um app que você esteja usando no momento pode acessar dados, mas com menos frequência. Isso pode fazer com que imagens não sejam exibidas até que você toque nelas."</string> <string name="data_saver_enable_title" msgid="4674073932722787417">"Ativar Economia de dados?"</string> <string name="data_saver_enable_button" msgid="7147735965247211818">"Ativar"</string> @@ -2008,4 +2006,22 @@ <string name="chooser_no_direct_share_targets" msgid="997970693708458895">"Compartilhamento direto indisponível"</string> <string name="chooser_all_apps_button_label" msgid="3631524352936289457">"Lista de apps"</string> <string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"Este app não tem permissão de gravação, mas pode capturar áudio pelo dispositivo USB."</string> + <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) --> + <skip /> + <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) --> + <skip /> + <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) --> + <skip /> + <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) --> + <skip /> + <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) --> + <skip /> + <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) --> + <skip /> + <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) --> + <skip /> + <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) --> + <skip /> + <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) --> + <skip /> </resources> diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml index 35ce5d63a4d5..a878628cce10 100644 --- a/core/res/res/values-ro/strings.xml +++ b/core/res/res/values-ro/strings.xml @@ -1794,10 +1794,8 @@ <string name="package_updated_device_owner" msgid="1847154566357862089">"Actualizat de administratorul dvs."</string> <string name="package_deleted_device_owner" msgid="2307122077550236438">"Șters de administratorul dvs."</string> <string name="confirm_battery_saver" msgid="639106420541753635">"OK"</string> - <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) --> - <skip /> - <!-- no translation found for battery_saver_description (2307555792915978653) --> - <skip /> + <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"Pentru a prelungi autonomia bateriei, Economisirea bateriei:\n·activează tema întunecată;\n·activează sau restricționează activitatea în fundal, unele efecte vizuale și alte funcții, cum ar fi „Ok Google”.\n\n"<annotation id="url">"Aflați mai multe"</annotation></string> + <string name="battery_saver_description" msgid="2307555792915978653">"Pentru a prelungi autonomia bateriei, Economisirea bateriei:\n·activează tema întunecată;\n·activează sau restricționează activitatea în fundal, unele efecte vizuale și alte funcții, cum ar fi „Ok Google”."</string> <string name="data_saver_description" msgid="6015391409098303235">"Pentru a contribui la reducerea utilizării de date, Economizorul de date împiedică unele aplicații să trimită sau să primească date în fundal. O aplicație pe care o folosiți poate accesa datele, însă mai rar. Aceasta poate însemna, de exemplu, că imaginile se afișează numai după ce le atingeți."</string> <string name="data_saver_enable_title" msgid="4674073932722787417">"Activați Economizorul de date?"</string> <string name="data_saver_enable_button" msgid="7147735965247211818">"Activați"</string> @@ -2042,4 +2040,22 @@ <string name="chooser_no_direct_share_targets" msgid="997970693708458895">"Trimiterea directă nu este disponibilă"</string> <string name="chooser_all_apps_button_label" msgid="3631524352936289457">"Lista de aplicații"</string> <string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"Permisiunea de înregistrare nu a fost acordată aplicației, dar aceasta poate să înregistreze conținut audio prin intermediul acestui dispozitiv USB."</string> + <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) --> + <skip /> + <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) --> + <skip /> + <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) --> + <skip /> + <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) --> + <skip /> + <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) --> + <skip /> + <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) --> + <skip /> + <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) --> + <skip /> + <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) --> + <skip /> + <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) --> + <skip /> </resources> diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml index 0fcb4c9a400f..aa94aa6f2bc0 100644 --- a/core/res/res/values-ru/strings.xml +++ b/core/res/res/values-ru/strings.xml @@ -1817,10 +1817,8 @@ <string name="package_updated_device_owner" msgid="1847154566357862089">"Обновлено администратором"</string> <string name="package_deleted_device_owner" msgid="2307122077550236438">"Удалено администратором"</string> <string name="confirm_battery_saver" msgid="639106420541753635">"ОК"</string> - <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) --> - <skip /> - <!-- no translation found for battery_saver_description (2307555792915978653) --> - <skip /> + <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"Чтобы продлить время работы от батареи, в режиме энергосбережения:\nвключается тёмная тема;\nотключаются или ограничиваются фоновые процессы, некоторые визуальные эффекты и другие функции (например, распознавание команды \"Окей, Google\").\n\n"<annotation id="url">"Подробнее…"</annotation></string> + <string name="battery_saver_description" msgid="2307555792915978653">"Чтобы продлить время работы от батареи, в режиме энергосбережения:\nвключается тёмная тема;\nотключаются или ограничиваются фоновые процессы, некоторые визуальные эффекты и другие функции (например, распознавание команды \"Окей, Google\")."</string> <string name="data_saver_description" msgid="6015391409098303235">"В режиме экономии трафика фоновая передача для некоторых приложений отключена. Приложение, которым вы пользуетесь, может получать и отправлять данные, но реже, чем обычно. Например, изображения могут не загружаться, пока вы не нажмете на них."</string> <string name="data_saver_enable_title" msgid="4674073932722787417">"Включить экономию трафика?"</string> <string name="data_saver_enable_button" msgid="7147735965247211818">"Включить"</string> @@ -2076,4 +2074,22 @@ <string name="chooser_no_direct_share_targets" msgid="997970693708458895">"Функция Direct Share недоступна."</string> <string name="chooser_all_apps_button_label" msgid="3631524352936289457">"Список приложений"</string> <string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"Приложению не разрешено записывать звук, однако оно может делать это с помощью этого USB-устройства."</string> + <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) --> + <skip /> + <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) --> + <skip /> + <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) --> + <skip /> + <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) --> + <skip /> + <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) --> + <skip /> + <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) --> + <skip /> + <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) --> + <skip /> + <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) --> + <skip /> + <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) --> + <skip /> </resources> diff --git a/core/res/res/values-si/strings.xml b/core/res/res/values-si/strings.xml index aaff63f9e63d..ee261a54ea95 100644 --- a/core/res/res/values-si/strings.xml +++ b/core/res/res/values-si/strings.xml @@ -1773,10 +1773,8 @@ <string name="package_updated_device_owner" msgid="1847154566357862089">"ඔබගේ පරිපාලක මඟින් යාවත්කාලීන කර ඇත"</string> <string name="package_deleted_device_owner" msgid="2307122077550236438">"ඔබගේ පරිපාලක මඟින් මකා දමා ඇත"</string> <string name="confirm_battery_saver" msgid="639106420541753635">"හරි"</string> - <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) --> - <skip /> - <!-- no translation found for battery_saver_description (2307555792915978653) --> - <skip /> + <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"බැටරියේ ජීව කාලය දික් කිරීමට, බැටරි සුරැකුම:\n·අඳුරු තේමාව ක්රියාත්මක කරයි\n·පසුබිමේ ක්රියාකාරකම, සමහර දෘෂ්ය ප්රයෝග සහ “Hey Google” වැනි වෙනත් විශේෂාංග ක්රියාවිරහිත කරයි නැතහොත් අවහිර කරයි\n\n"<annotation id="url">"තව දැන ගන්න"</annotation></string> + <string name="battery_saver_description" msgid="2307555792915978653">"බැටරියේ ජීව කාලය දික් කිරීමට, බැටරි සුරැකුම:\n·අඳුරු තේමාව ක්රියාත්මක කරයි\n·පසුබිමේ ක්රියාකාරකම, සමහර දෘෂ්ය ප්රයෝග සහ “Hey Google” වැනි වෙනත් විශේෂාංග ක්රියාවිරහිත කරයි නැතහොත් අවහිර කරයි"</string> <string name="data_saver_description" msgid="6015391409098303235">"දත්ත භාවිතය අඩු කිරීමට උදවු වීමට, දත්ත සුරැකුම සමහර යෙදුම් පසුබිමින් දත්ත යැවීම සහ ලබා ගැනීම වළක්වයි. ඔබ දැනට භාවිත කරන යෙදුමකට දත්ත වෙත පිවිසීමට හැකිය, නමුත් එසේ කරන්නේ කලාතුරකින් විය හැකිය. මෙයින් අදහස් වන්නේ, උදාහරණයක් ලෙස, එම රූප ඔබ ඒවාට තට්ටු කරන තෙක් සංදර්ශනය නොවන බවය."</string> <string name="data_saver_enable_title" msgid="4674073932722787417">"දත්ත සුරැකුම ක්රියාත්මක කරන්නද?"</string> <string name="data_saver_enable_button" msgid="7147735965247211818">"ක්රියාත්මක කරන්න"</string> @@ -2010,4 +2008,22 @@ <string name="chooser_no_direct_share_targets" msgid="997970693708458895">"ඍජු බෙදා ගැනීම නොලැබේ"</string> <string name="chooser_all_apps_button_label" msgid="3631524352936289457">"යෙදුම් ලැයිස්තුව"</string> <string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"මෙම යෙදුමට පටිගත කිරීම් අවසරයක් ලබා දී නොමැති නමුත් මෙම USB උපාංගය හරහා ශ්රව්ය ග්රහණය කර ගත හැකිය."</string> + <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) --> + <skip /> + <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) --> + <skip /> + <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) --> + <skip /> + <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) --> + <skip /> + <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) --> + <skip /> + <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) --> + <skip /> + <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) --> + <skip /> + <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) --> + <skip /> + <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) --> + <skip /> </resources> diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml index 84b2874ec178..ed4f68c91b99 100644 --- a/core/res/res/values-sk/strings.xml +++ b/core/res/res/values-sk/strings.xml @@ -1817,10 +1817,8 @@ <string name="package_updated_device_owner" msgid="1847154566357862089">"Aktualizoval správca"</string> <string name="package_deleted_device_owner" msgid="2307122077550236438">"Odstránil správca"</string> <string name="confirm_battery_saver" msgid="639106420541753635">"OK"</string> - <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) --> - <skip /> - <!-- no translation found for battery_saver_description (2307555792915978653) --> - <skip /> + <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"Šetrič batérie predlžuje výdrž batérie:\n·zapnutím tmavého motívu;\n·vypnutím alebo obmedzením aktivity na pozadí, niektorých vizuálnych efektov a ďalších funkcií, ako napríklad „Hej Google“.\n\n"<annotation id="url">"Ďalšie informácie"</annotation></string> + <string name="battery_saver_description" msgid="2307555792915978653">"Šetrič batérie predlžuje výdrž batérie:\n·zapnutím tmavého motívu;\n·vypnutím alebo obmedzením aktivity na pozadí, niektorých vizuálnych efektov a ďalších funkcií, ako napríklad „Hej Google“."</string> <string name="data_saver_description" msgid="6015391409098303235">"S cieľom znížiť spotrebu dát bráni šetrič dát niektorým aplikáciám odosielať alebo prijímať dáta na pozadí. Aplikácia, ktorú práve používate, môže využívať dáta, ale možno to bude robiť menej často. Znamená to napríklad, že sa nezobrazia obrázky, kým na ne neklepnete."</string> <string name="data_saver_enable_title" msgid="4674073932722787417">"Chcete zapnúť šetrič dát?"</string> <string name="data_saver_enable_button" msgid="7147735965247211818">"Zapnúť"</string> @@ -2076,4 +2074,22 @@ <string name="chooser_no_direct_share_targets" msgid="997970693708458895">"Priame zdieľanie nie je k dispozícii"</string> <string name="chooser_all_apps_button_label" msgid="3631524352936289457">"Zoznam aplikácií"</string> <string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"Tejto aplikácii nebolo udelené povolenie na nahrávanie, ale môže nasnímať zvuk cez toto zariadenie USB."</string> + <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) --> + <skip /> + <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) --> + <skip /> + <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) --> + <skip /> + <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) --> + <skip /> + <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) --> + <skip /> + <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) --> + <skip /> + <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) --> + <skip /> + <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) --> + <skip /> + <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) --> + <skip /> </resources> diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml index 4657001ad8be..dc162a88fa08 100644 --- a/core/res/res/values-sl/strings.xml +++ b/core/res/res/values-sl/strings.xml @@ -1817,10 +1817,8 @@ <string name="package_updated_device_owner" msgid="1847154566357862089">"Posodobil skrbnik"</string> <string name="package_deleted_device_owner" msgid="2307122077550236438">"Izbrisal skrbnik"</string> <string name="confirm_battery_saver" msgid="639106420541753635">"V redu"</string> - <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) --> - <skip /> - <!-- no translation found for battery_saver_description (2307555792915978653) --> - <skip /> + <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"Funkcija varčevanja z energijo baterije tako podaljša čas delovanja baterije:\n·Vklopi temno temo,\n·izklopi ali omeji izvajanje dejavnosti v ozadju, nekaterih vizualnih učinkov in drugih funkcij, kot je »Hey Google«.\n\n"<annotation id="url">"Več o tem"</annotation></string> + <string name="battery_saver_description" msgid="2307555792915978653">"Funkcija varčevanja z energijo baterije tako podaljša čas delovanja baterije:\n·Vklopi temno temo,\n·izklopi ali omeji izvajanje dejavnosti v ozadju, nekaterih vizualnih učinkov in drugih funkcij, kot je »Hey Google«."</string> <string name="data_saver_description" msgid="6015391409098303235">"Zaradi zmanjševanja prenesene količine podatkov varčevanje s podatki nekaterim aplikacijam preprečuje, da bi v ozadju pošiljale ali prejemale podatke. Aplikacija, ki jo trenutno uporabljate, lahko prenaša podatke, vendar to morda počne manj pogosto. To na primer pomeni, da se slike ne prikažejo, dokler se jih ne dotaknete."</string> <string name="data_saver_enable_title" msgid="4674073932722787417">"Vklop varčevanja s podatki?"</string> <string name="data_saver_enable_button" msgid="7147735965247211818">"Vklop"</string> @@ -2076,4 +2074,22 @@ <string name="chooser_no_direct_share_targets" msgid="997970693708458895">"Neposredna skupna raba ni na voljo"</string> <string name="chooser_all_apps_button_label" msgid="3631524352936289457">"Seznam aplikacij"</string> <string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"Ta aplikacija sicer nima dovoljenja za snemanje, vendar bi lahko zajemala zvok prek te naprave USB."</string> + <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) --> + <skip /> + <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) --> + <skip /> + <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) --> + <skip /> + <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) --> + <skip /> + <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) --> + <skip /> + <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) --> + <skip /> + <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) --> + <skip /> + <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) --> + <skip /> + <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) --> + <skip /> </resources> diff --git a/core/res/res/values-sq/strings.xml b/core/res/res/values-sq/strings.xml index cdef310be9d6..4973f9f1d112 100644 --- a/core/res/res/values-sq/strings.xml +++ b/core/res/res/values-sq/strings.xml @@ -2008,4 +2008,22 @@ <string name="chooser_no_direct_share_targets" msgid="997970693708458895">"Ndarja e drejtpërdrejtë nuk ofrohet"</string> <string name="chooser_all_apps_button_label" msgid="3631524352936289457">"Lista e aplikacioneve"</string> <string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"Këtij aplikacioni nuk i është dhënë leje për regjistrim, por mund të regjistrojë audio përmes kësaj pajisjeje USB."</string> + <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) --> + <skip /> + <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) --> + <skip /> + <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) --> + <skip /> + <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) --> + <skip /> + <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) --> + <skip /> + <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) --> + <skip /> + <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) --> + <skip /> + <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) --> + <skip /> + <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) --> + <skip /> </resources> diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml index c953e5ebeb1d..48658bb4922a 100644 --- a/core/res/res/values-sr/strings.xml +++ b/core/res/res/values-sr/strings.xml @@ -1794,10 +1794,8 @@ <string name="package_updated_device_owner" msgid="1847154566357862089">"Ажурирао је администратор"</string> <string name="package_deleted_device_owner" msgid="2307122077550236438">"Избрисао је администратор"</string> <string name="confirm_battery_saver" msgid="639106420541753635">"Потврди"</string> - <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) --> - <skip /> - <!-- no translation found for battery_saver_description (2307555792915978653) --> - <skip /> + <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"Ради дужег трајања батерије, уштеда батерије:\n·укључује тамну тему\n·искључује или ограничава активности у позадини, неке визуелне ефекте и друге функције, на пример, „Ок Google“\n\n"<annotation id="url">"Сазнајте више"</annotation></string> + <string name="battery_saver_description" msgid="2307555792915978653">"Ради дужег трајања батерије, уштеда батерије:\n·укључује тамну тему\n·искључује или ограничава активности у позадини, неке визуелне ефекте и друге функције, на пример, „Ок Google“"</string> <string name="data_saver_description" msgid="6015391409098303235">"Да би се смањила потрошња података, Уштеда података спречава неке апликације да шаљу или примају податке у позадини. Апликација коју тренутно користите може да приступа подацима, али ће то чинити ређе. На пример, слике се неће приказивати док их не додирнете."</string> <string name="data_saver_enable_title" msgid="4674073932722787417">"Укључити Уштеду података?"</string> <string name="data_saver_enable_button" msgid="7147735965247211818">"Укључи"</string> @@ -2042,4 +2040,22 @@ <string name="chooser_no_direct_share_targets" msgid="997970693708458895">"Директно дељење није доступно"</string> <string name="chooser_all_apps_button_label" msgid="3631524352936289457">"Листа апликација"</string> <string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"Ова апликација нема дозволу за снимање, али би могла да снима звук помоћу овог USB уређаја."</string> + <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) --> + <skip /> + <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) --> + <skip /> + <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) --> + <skip /> + <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) --> + <skip /> + <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) --> + <skip /> + <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) --> + <skip /> + <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) --> + <skip /> + <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) --> + <skip /> + <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) --> + <skip /> </resources> diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml index 32cd87893f1c..09a25132ca6e 100644 --- a/core/res/res/values-sv/strings.xml +++ b/core/res/res/values-sv/strings.xml @@ -1414,7 +1414,7 @@ <string name="permission_request_notification_title" msgid="6486759795926237907">"Begärd behörighet"</string> <string name="permission_request_notification_with_subtitle" msgid="8530393139639560189">"Begärd behörighet\nför kontot <xliff:g id="ACCOUNT">%s</xliff:g>."</string> <string name="forward_intent_to_owner" msgid="1207197447013960896">"Du använder den här appen i din arbetsprofil"</string> - <string name="forward_intent_to_work" msgid="621480743856004612">"Du använder den här appen i din profil"</string> + <string name="forward_intent_to_work" msgid="621480743856004612">"Du använder den här appen i din jobbprofil"</string> <string name="input_method_binding_label" msgid="1283557179944992649">"Indatametod"</string> <string name="sync_binding_label" msgid="3687969138375092423">"Synkronisera"</string> <string name="accessibility_binding_label" msgid="4148120742096474641">"Tillgänglighet"</string> @@ -1771,10 +1771,8 @@ <string name="package_updated_device_owner" msgid="1847154566357862089">"Administratören uppdaterade paketet"</string> <string name="package_deleted_device_owner" msgid="2307122077550236438">"Administratören raderade paketet"</string> <string name="confirm_battery_saver" msgid="639106420541753635">"OK"</string> - <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) --> - <skip /> - <!-- no translation found for battery_saver_description (2307555792915978653) --> - <skip /> + <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"I syfte att förlänga batteritiden sker följande i batterisparläget:\n·mörkt tema aktiveras\n·aktivitet i bakgrunden, vissa visuella effekter och andra funktioner, som ”Hey Google”, inaktiveras eller begränsas\n\n"<annotation id="url">"Läs mer"</annotation></string> + <string name="battery_saver_description" msgid="2307555792915978653">"I syfte att förlänga batteritiden sker följande i batterisparläget:\n·mörkt tema aktiveras\n·aktivitet i bakgrunden, vissa visuella effekter och andra funktioner, som ”Hey Google”, inaktiveras eller begränsas"</string> <string name="data_saver_description" msgid="6015391409098303235">"Med databesparing kan du minska dataanvändningen genom att hindra en del appar från att skicka eller ta emot data i bakgrunden. Appar som du använder kan komma åt data, men det sker kanske inte lika ofta. Detta innebär t.ex. att bilder inte visas förrän du trycker på dem."</string> <string name="data_saver_enable_title" msgid="4674073932722787417">"Aktivera Databesparing?"</string> <string name="data_saver_enable_button" msgid="7147735965247211818">"Aktivera"</string> @@ -2008,4 +2006,22 @@ <string name="chooser_no_direct_share_targets" msgid="997970693708458895">"Dela direkt är inte tillgängligt"</string> <string name="chooser_all_apps_button_label" msgid="3631524352936289457">"Applista"</string> <string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"Appen har inte fått inspelningsbehörighet men kan spela in ljud via denna USB-enhet."</string> + <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) --> + <skip /> + <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) --> + <skip /> + <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) --> + <skip /> + <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) --> + <skip /> + <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) --> + <skip /> + <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) --> + <skip /> + <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) --> + <skip /> + <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) --> + <skip /> + <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) --> + <skip /> </resources> diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml index 15bb4bffc5c8..483c39f81e6c 100644 --- a/core/res/res/values-sw/strings.xml +++ b/core/res/res/values-sw/strings.xml @@ -1771,10 +1771,8 @@ <string name="package_updated_device_owner" msgid="1847154566357862089">"Imesasishwa na msimamizi wako"</string> <string name="package_deleted_device_owner" msgid="2307122077550236438">"Imefutwa na msimamizi wako"</string> <string name="confirm_battery_saver" msgid="639106420541753635">"Sawa"</string> - <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) --> - <skip /> - <!-- no translation found for battery_saver_description (2307555792915978653) --> - <skip /> + <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"Ili kuongeza muda wa matumizi ya betri, Kiokoa Betri:\n.Huwasha Mandhari meusi\n. Huzima au kuzuia shughuli za chinichini, baadhi ya madoido yanayoonekana na vipengele vingine kama vile \"Ok Google\"\n\n"<annotation id="url">"Pata maelezo zaidi"</annotation></string> + <string name="battery_saver_description" msgid="2307555792915978653">"Ili kuongeza muda wa matumizi ya betri, Kiokoa Betri:\n.Huwasha Mandhari meusi\n. Huzima au kuzuia shughuli za chinichini, baadhi ya madoido yanayoonekana na vipengele vingine kama vile \"Ok Google\""</string> <string name="data_saver_description" msgid="6015391409098303235">"Ili kusaidia kupunguza matumizi ya data, Kiokoa Data huzuia baadhi ya programu kupokea na kutuma data chinichini. Programu ambayo unatumia sasa inaweza kufikia data, lakini si kila wakati. Kwa mfano, haitaonyesha picha hadi utakapozifungua."</string> <string name="data_saver_enable_title" msgid="4674073932722787417">"Ungependa Kuwasha Kiokoa Data?"</string> <string name="data_saver_enable_button" msgid="7147735965247211818">"Washa"</string> @@ -2008,4 +2006,22 @@ <string name="chooser_no_direct_share_targets" msgid="997970693708458895">"Huwezi kushiriki moja kwa moja"</string> <string name="chooser_all_apps_button_label" msgid="3631524352936289457">"Orodha ya programu"</string> <string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"Programu hii haijapewa ruhusa ya kurekodi lakini inaweza kurekodi sauti kupitia kifaa hiki cha USB."</string> + <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) --> + <skip /> + <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) --> + <skip /> + <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) --> + <skip /> + <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) --> + <skip /> + <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) --> + <skip /> + <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) --> + <skip /> + <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) --> + <skip /> + <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) --> + <skip /> + <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) --> + <skip /> </resources> diff --git a/core/res/res/values-ta/strings.xml b/core/res/res/values-ta/strings.xml index e2629df345ed..0c4e20ee6c1a 100644 --- a/core/res/res/values-ta/strings.xml +++ b/core/res/res/values-ta/strings.xml @@ -1771,10 +1771,8 @@ <string name="package_updated_device_owner" msgid="1847154566357862089">"உங்கள் நிர்வாகி புதுப்பித்துள்ளார்"</string> <string name="package_deleted_device_owner" msgid="2307122077550236438">"உங்கள் நிர்வாகி நீக்கியுள்ளார்"</string> <string name="confirm_battery_saver" msgid="639106420541753635">"சரி"</string> - <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) --> - <skip /> - <!-- no translation found for battery_saver_description (2307555792915978653) --> - <skip /> + <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"பேட்டரி நிலையை நீட்டிப்பதற்காக, பேட்டரி சேமிப்பான்:\n·டார்க் தீமினை ஆன் செய்யும்\n·“Hey Google” போன்ற பிற அம்சங்கள், பின்னணி செயல்பாடுகள், சில விஷுவல் எஃபெக்ட்கள், ஆகியவற்றை ஆஃப் செய்யும் அல்லது கட்டுப்படுத்தும்\n\n"<annotation id="url">"மேலும் அறிக"</annotation></string> + <string name="battery_saver_description" msgid="2307555792915978653">"பேட்டரி நிலையை நீட்டிப்பதற்காக, பேட்டரி சேமிப்பான்:\n·டார்க் தீமினை ஆன் செய்யும்\n·“Hey Google” போன்ற பிற அம்சங்கள், பின்னணி செயல்பாடுகள், சில விஷுவல் எஃபெக்ட்கள், ஆகியவற்றை ஆஃப் செய்யும் அல்லது கட்டுப்படுத்தும்"</string> <string name="data_saver_description" msgid="6015391409098303235">"டேட்டா உபயோகத்தைக் குறைப்பதற்கு உதவ, பின்புலத்தில் டேட்டாவை அனுப்புவது அல்லது பெறுவதிலிருந்து சில ஆப்ஸை டேட்டா சேமிப்பான் தடுக்கும். தற்போது பயன்படுத்தும் ஆப்ஸானது எப்போதாவது டேட்டாவை அணுகலாம். எடுத்துக்காட்டாக, படங்களை நீங்கள் தட்டும் வரை அவை காட்டப்படாது."</string> <string name="data_saver_enable_title" msgid="4674073932722787417">"டேட்டா சேமிப்பானை இயக்கவா?"</string> <string name="data_saver_enable_button" msgid="7147735965247211818">"இயக்கு"</string> @@ -2008,4 +2006,22 @@ <string name="chooser_no_direct_share_targets" msgid="997970693708458895">"நேரடிப் பகிர்வு இல்லை"</string> <string name="chooser_all_apps_button_label" msgid="3631524352936289457">"ஆப்ஸ் பட்டியல்"</string> <string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"இந்த ஆப்ஸிற்கு ரெக்கார்டு செய்வதற்கான அனுமதி வழங்கப்படவில்லை, எனினும் இந்த USB சாதனம் மூலம் ஆடியோவைப் பதிவுசெய்ய முடியும்."</string> + <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) --> + <skip /> + <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) --> + <skip /> + <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) --> + <skip /> + <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) --> + <skip /> + <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) --> + <skip /> + <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) --> + <skip /> + <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) --> + <skip /> + <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) --> + <skip /> + <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) --> + <skip /> </resources> diff --git a/core/res/res/values-te/strings.xml b/core/res/res/values-te/strings.xml index 6718470024f2..1b3df6e5f7c9 100644 --- a/core/res/res/values-te/strings.xml +++ b/core/res/res/values-te/strings.xml @@ -2008,4 +2008,22 @@ <string name="chooser_no_direct_share_targets" msgid="997970693708458895">"డైరెక్ట్ షేర్ అందుబాటులో లేదు"</string> <string name="chooser_all_apps_button_label" msgid="3631524352936289457">"యాప్ల జాబితా"</string> <string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"ఈ యాప్కు రికార్డ్ చేసే అనుమతి మంజూరు కాలేదు, అయినా ఈ USB పరికరం ద్వారా ఆడియోను క్యాప్చర్ చేయగలదు."</string> + <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) --> + <skip /> + <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) --> + <skip /> + <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) --> + <skip /> + <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) --> + <skip /> + <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) --> + <skip /> + <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) --> + <skip /> + <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) --> + <skip /> + <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) --> + <skip /> + <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) --> + <skip /> </resources> diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml index 2f59711b594d..ff1ea21e3c30 100644 --- a/core/res/res/values-th/strings.xml +++ b/core/res/res/values-th/strings.xml @@ -1771,10 +1771,8 @@ <string name="package_updated_device_owner" msgid="1847154566357862089">"อัปเดตโดยผู้ดูแลระบบ"</string> <string name="package_deleted_device_owner" msgid="2307122077550236438">"ลบโดยผู้ดูแลระบบ"</string> <string name="confirm_battery_saver" msgid="639106420541753635">"ตกลง"</string> - <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) --> - <skip /> - <!-- no translation found for battery_saver_description (2307555792915978653) --> - <skip /> + <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"โหมดประหยัดแบตเตอรี่จะดำเนินการดังต่อไปนี้เพื่อยืดอายุการใช้งานแบตเตอรี่\n·เปิดธีมมืด\n·ปิดหรือจำกัดกิจกรรมในเบื้องหลัง เอฟเฟกต์ภาพบางอย่าง และฟีเจอร์อื่นๆ อย่างเช่น “Hey Google”\n\n"<annotation id="url">"ดูข้อมูลเพิ่มเติม"</annotation></string> + <string name="battery_saver_description" msgid="2307555792915978653">"โหมดประหยัดแบตเตอรี่จะดำเนินการดังต่อไปนี้เพื่อยืดอายุการใช้งานแบตเตอรี่\n·เปิดธีมมืด\n·ปิดหรือจำกัดกิจกรรมในเบื้องหลัง เอฟเฟกต์ภาพบางอย่าง และฟีเจอร์อื่นๆ อย่างเช่น “Hey Google”"</string> <string name="data_saver_description" msgid="6015391409098303235">"เพื่อช่วยลดปริมาณการใช้อินเทอร์เน็ต โปรแกรมประหยัดอินเทอร์เน็ตจะช่วยป้องกันไม่ให้บางแอปส่งหรือรับข้อมูลโดยการใช้อินเทอร์เน็ตอยู่เบื้องหลัง แอปที่คุณกำลังใช้งานสามารถเข้าถึงอินเทอร์เน็ตได้ แต่อาจไม่บ่อยเท่าเดิม ตัวอย่างเช่น ภาพต่างๆ จะไม่แสดงจนกว่าคุณจะแตะที่ภาพเหล่านั้น"</string> <string name="data_saver_enable_title" msgid="4674073932722787417">"เปิดการประหยัดอินเทอร์เน็ตไหม"</string> <string name="data_saver_enable_button" msgid="7147735965247211818">"เปิด"</string> @@ -2008,4 +2006,22 @@ <string name="chooser_no_direct_share_targets" msgid="997970693708458895">"การแชร์โดยตรงไม่พร้อมใช้งาน"</string> <string name="chooser_all_apps_button_label" msgid="3631524352936289457">"รายชื่อแอป"</string> <string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"แอปนี้ไม่ได้รับอนุญาตให้บันทึกเสียงแต่จะบันทึกเสียงผ่านอุปกรณ์ USB นี้ได้"</string> + <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) --> + <skip /> + <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) --> + <skip /> + <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) --> + <skip /> + <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) --> + <skip /> + <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) --> + <skip /> + <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) --> + <skip /> + <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) --> + <skip /> + <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) --> + <skip /> + <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) --> + <skip /> </resources> diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml index 0fc10142c645..79c040f36d57 100644 --- a/core/res/res/values-tl/strings.xml +++ b/core/res/res/values-tl/strings.xml @@ -1771,10 +1771,8 @@ <string name="package_updated_device_owner" msgid="1847154566357862089">"Na-update ng iyong admin"</string> <string name="package_deleted_device_owner" msgid="2307122077550236438">"Na-delete ng iyong admin"</string> <string name="confirm_battery_saver" msgid="639106420541753635">"OK"</string> - <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) --> - <skip /> - <!-- no translation found for battery_saver_description (2307555792915978653) --> - <skip /> + <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"Para patagalin ang baterya, ginagawa ng Pangtipid sa Baterya na:\n·I-on ang Madilim na tema\n·I-off o paghigpitan ang aktibidad sa background, ilang visual effect, at iba pang feature gaya ng “Hey Google”\n\n"<annotation id="url">"Matuto pa"</annotation></string> + <string name="battery_saver_description" msgid="2307555792915978653">"Para patagalin ang baterya, ginagawa ng Pangtipid sa Baterya na:\n·I-on ang Madilim na tema\n·I-off o paghigpitan ang aktibidad sa background, ilang visual effect, at iba pang feature gaya ng “Hey Google”"</string> <string name="data_saver_description" msgid="6015391409098303235">"Upang makatulong na mabawasan ang paggamit ng data, pinipigilan ng Data Saver ang ilang app na magpadala o makatanggap ng data sa background. Maaaring mag-access ng data ang isang app na ginagamit mo sa kasalukuyan, ngunit mas bihira na nito magagawa iyon. Halimbawa, maaaring hindi lumabas ang mga larawan hangga\'t hindi mo nata-tap ang mga ito."</string> <string name="data_saver_enable_title" msgid="4674073932722787417">"I-on ang Data Saver?"</string> <string name="data_saver_enable_button" msgid="7147735965247211818">"I-on"</string> @@ -2008,4 +2006,22 @@ <string name="chooser_no_direct_share_targets" msgid="997970693708458895">"Hindi available ang direktang pagbabahagi"</string> <string name="chooser_all_apps_button_label" msgid="3631524352936289457">"Listahan ng mga app"</string> <string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"Hindi nabigyan ng pahintulot ang app na ito para mag-record pero nakakapag-capture ito ng audio sa pamamagitan ng USB device na ito."</string> + <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) --> + <skip /> + <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) --> + <skip /> + <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) --> + <skip /> + <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) --> + <skip /> + <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) --> + <skip /> + <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) --> + <skip /> + <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) --> + <skip /> + <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) --> + <skip /> + <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) --> + <skip /> </resources> diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml index f95d8360aae3..d6841f0ac9f3 100644 --- a/core/res/res/values-tr/strings.xml +++ b/core/res/res/values-tr/strings.xml @@ -1771,10 +1771,8 @@ <string name="package_updated_device_owner" msgid="1847154566357862089">"Yöneticiniz tarafından güncellendi"</string> <string name="package_deleted_device_owner" msgid="2307122077550236438">"Yöneticiniz tarafından silindi"</string> <string name="confirm_battery_saver" msgid="639106420541753635">"Tamam"</string> - <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) --> - <skip /> - <!-- no translation found for battery_saver_description (2307555792915978653) --> - <skip /> + <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"Pil ömrünü uzatmak için Pil Tasarrufu:\n·Koyu temayı açar\n·Arka plan etkinliğini, bazı görsel efektleri ve \"Hey Google\" gibi diğer özellikleri kapatır veya kısıtlar\n\n"<annotation id="url">"Daha fazla bilgi"</annotation></string> + <string name="battery_saver_description" msgid="2307555792915978653">"Pil ömrünü uzatmak için Pil Tasarrufu:\n·Koyu temayı açar\n·Arka plan etkinliğini, bazı görsel efektleri ve \"Hey Google\" gibi diğer özellikleri kapatır veya kısıtlar"</string> <string name="data_saver_description" msgid="6015391409098303235">"Veri kullanımını azaltmaya yardımcı olması için Veri Tasarrufu, bazı uygulamaların arka planda veri göndermesini veya almasını engeller. Şu anda kullandığınız bir uygulama veri bağlantısına erişebilir, ancak bunu daha seyrek yapabilir. Bu durumda örneğin, siz resimlere dokunmadan resimler görüntülenmez."</string> <string name="data_saver_enable_title" msgid="4674073932722787417">"Veri Tasarrufu açılsın mı?"</string> <string name="data_saver_enable_button" msgid="7147735965247211818">"Aç"</string> @@ -2008,4 +2006,22 @@ <string name="chooser_no_direct_share_targets" msgid="997970693708458895">"Doğrudan paylaşım mevcut değil"</string> <string name="chooser_all_apps_button_label" msgid="3631524352936289457">"Uygulama listesi"</string> <string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"Bu uygulamaya ses kaydetme izni verilmedi ancak bu USB cihazı üzerinden sesleri yakalayabilir."</string> + <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) --> + <skip /> + <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) --> + <skip /> + <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) --> + <skip /> + <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) --> + <skip /> + <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) --> + <skip /> + <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) --> + <skip /> + <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) --> + <skip /> + <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) --> + <skip /> + <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) --> + <skip /> </resources> diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml index d5cdb32de5c0..3412eb2dcc96 100644 --- a/core/res/res/values-uk/strings.xml +++ b/core/res/res/values-uk/strings.xml @@ -1817,10 +1817,8 @@ <string name="package_updated_device_owner" msgid="1847154566357862089">"Оновлено адміністратором"</string> <string name="package_deleted_device_owner" msgid="2307122077550236438">"Видалено адміністратором"</string> <string name="confirm_battery_saver" msgid="639106420541753635">"ОК"</string> - <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) --> - <skip /> - <!-- no translation found for battery_saver_description (2307555792915978653) --> - <skip /> + <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"Щоб подовжити час роботи акумулятора, режим енергозбереження:\n·вмикає темну тему;\n·припиняє або обмежує фонову активність, вимикає деякі візуальні ефекти й інші енергозатратні функції, зокрема Ok Google.\n\n"<annotation id="url">"Докладніше"</annotation></string> + <string name="battery_saver_description" msgid="2307555792915978653">"Щоб подовжити час роботи акумулятора, режим енергозбереження:\n·вмикає темну тему;\n·припиняє або обмежує фонову активність, вимикає деякі візуальні ефекти й інші енергозатратні функції, зокрема Ok Google."</string> <string name="data_saver_description" msgid="6015391409098303235">"Щоб зменшити використання трафіку, функція \"Заощадження трафіку\" не дозволяє деяким додаткам надсилати чи отримувати дані у фоновому режимі. Поточний додаток зможе отримувати доступ до таких даних, але рідше. Наприклад, зображення не відображатиметься, доки ви не торкнетеся його."</string> <string name="data_saver_enable_title" msgid="4674073932722787417">"Увімкнути Заощадження трафіку?"</string> <string name="data_saver_enable_button" msgid="7147735965247211818">"Увімкнути"</string> @@ -2076,4 +2074,22 @@ <string name="chooser_no_direct_share_targets" msgid="997970693708458895">"Прямий обмін даними недоступний"</string> <string name="chooser_all_apps_button_label" msgid="3631524352936289457">"Список додатків"</string> <string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"Цей додаток не має дозволу на запис, але він може фіксувати звук через цей USB-пристрій."</string> + <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) --> + <skip /> + <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) --> + <skip /> + <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) --> + <skip /> + <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) --> + <skip /> + <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) --> + <skip /> + <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) --> + <skip /> + <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) --> + <skip /> + <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) --> + <skip /> + <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) --> + <skip /> </resources> diff --git a/core/res/res/values-ur/strings.xml b/core/res/res/values-ur/strings.xml index ab2a83cf7304..003fd54e6812 100644 --- a/core/res/res/values-ur/strings.xml +++ b/core/res/res/values-ur/strings.xml @@ -1771,10 +1771,8 @@ <string name="package_updated_device_owner" msgid="1847154566357862089">"آپ کے منتظم کے ذریعے اپ ڈیٹ کیا گیا"</string> <string name="package_deleted_device_owner" msgid="2307122077550236438">"آپ کے منتظم کے ذریعے حذف کیا گیا"</string> <string name="confirm_battery_saver" msgid="639106420541753635">"ٹھیک ہے"</string> - <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) --> - <skip /> - <!-- no translation found for battery_saver_description (2307555792915978653) --> - <skip /> + <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"بیٹری لائف کو بڑھانے کے لیے، بیٹری سیور:\n گہری تھیم کو آن کرتی ہے\n پس منظر کی سرگرمی، کچھ بصری اثرات اور دیگر خصوصیات جیسے کہ \"Ok Google\" کو آف یا محدود کرتی ہے\n\n"<annotation id="url">"مزید جانیں"</annotation></string> + <string name="battery_saver_description" msgid="2307555792915978653">"بیٹری لائف کو بڑھانے کے لیے، بیٹری سیور:\n گہری تھیم کو آن کرتی ہے\n پس منظر کی سرگرمی، کچھ بصری اثرات اور دیگر خصوصیات جیسے کہ \"Ok Google\" کو آف یا محدود کرتی ہے"</string> <string name="data_saver_description" msgid="6015391409098303235">"ڈیٹا کے استعمال کو کم کرنے میں مدد کیلئے، ڈیٹا سیور پس منظر میں کچھ ایپس کو ڈیٹا بھیجنے یا موصول کرنے سے روکتا ہے۔ آپ جو ایپ فی الحال استعمال کر رہے ہیں وہ ڈیٹا پر رسائی کر سکتی ہے مگر ہو سکتا ہے ایسا زیادہ نہ ہو۔ اس کا مطلب مثال کے طور پر یہ ہو سکتا ہے کہ تصاویر تھپتھپانے تک ظاہر نہ ہوں۔"</string> <string name="data_saver_enable_title" msgid="4674073932722787417">"ڈیٹا سیور آن کریں؟"</string> <string name="data_saver_enable_button" msgid="7147735965247211818">"آن کریں"</string> @@ -2008,4 +2006,22 @@ <string name="chooser_no_direct_share_targets" msgid="997970693708458895">"بلاواسطہ اشتراک دستیاب نہیں ہے"</string> <string name="chooser_all_apps_button_label" msgid="3631524352936289457">"ایپس کی فہرست"</string> <string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"اس ایپ کو ریکارڈ کرنے کی اجازت عطا نہیں کی گئی ہے مگر اس USB آلہ کے ذریعے آڈیو کیپچر کر سکتی ہے۔"</string> + <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) --> + <skip /> + <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) --> + <skip /> + <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) --> + <skip /> + <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) --> + <skip /> + <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) --> + <skip /> + <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) --> + <skip /> + <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) --> + <skip /> + <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) --> + <skip /> + <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) --> + <skip /> </resources> diff --git a/core/res/res/values-uz/strings.xml b/core/res/res/values-uz/strings.xml index d618d999cdfa..83e99b9abaaa 100644 --- a/core/res/res/values-uz/strings.xml +++ b/core/res/res/values-uz/strings.xml @@ -1771,10 +1771,8 @@ <string name="package_updated_device_owner" msgid="1847154566357862089">"Administrator tomonidan yangilangan"</string> <string name="package_deleted_device_owner" msgid="2307122077550236438">"Administrator tomonidan o‘chirilgan"</string> <string name="confirm_battery_saver" msgid="639106420541753635">"OK"</string> - <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) --> - <skip /> - <!-- no translation found for battery_saver_description (2307555792915978653) --> - <skip /> + <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"Batareya quvvatini uzaytirish uchun Quvvat tejash funksiyasi:\n·Tungi mavzuni yoqadi\n·Fondagi harakatlar, vizual effektlar va “Hey Google” kabi boshqa funksiyalarni faolsizlantiradi\n\n"<annotation id="url">"Batafsil"</annotation></string> + <string name="battery_saver_description" msgid="2307555792915978653">"Batareya quvvatini uzaytirish uchun Quvvat tejash funksiyasi:\n·Tungi mavzuni yoqadi\n·Fondagi harakatlar, vizual effektlar va “Hey Google” kabi boshqa funksiyalarni faolsizlantiradi"</string> <string name="data_saver_description" msgid="6015391409098303235">"Trafik tejash rejimida ayrim ilovalar uchun orqa fonda internetdan foydalanish imkoniyati cheklanadi. Siz ishlatayotgan ilova zaruratga qarab internet-trafik sarflashi mumkin, biroq cheklangan miqdorda. Masalan, rasmlar ustiga bosmaguningizcha ular yuklanmaydi."</string> <string name="data_saver_enable_title" msgid="4674073932722787417">"Trafik tejash yoqilsinmi?"</string> <string name="data_saver_enable_button" msgid="7147735965247211818">"Yoqish"</string> @@ -2008,4 +2006,22 @@ <string name="chooser_no_direct_share_targets" msgid="997970693708458895">"Bevosita ulashuv ishlamaydi"</string> <string name="chooser_all_apps_button_label" msgid="3631524352936289457">"Ilovalar roʻyxati"</string> <string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"Bu ilovaga yozib olish ruxsati berilmagan, lekin shu USB orqali ovozlarni yozib olishi mumkin."</string> + <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) --> + <skip /> + <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) --> + <skip /> + <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) --> + <skip /> + <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) --> + <skip /> + <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) --> + <skip /> + <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) --> + <skip /> + <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) --> + <skip /> + <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) --> + <skip /> + <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) --> + <skip /> </resources> diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml index 9880890e5e29..7b17de7d0b83 100644 --- a/core/res/res/values-vi/strings.xml +++ b/core/res/res/values-vi/strings.xml @@ -1771,10 +1771,8 @@ <string name="package_updated_device_owner" msgid="1847154566357862089">"Do quản trị viên của bạn cập nhật"</string> <string name="package_deleted_device_owner" msgid="2307122077550236438">"Do quản trị viên của bạn xóa"</string> <string name="confirm_battery_saver" msgid="639106420541753635">"OK"</string> - <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) --> - <skip /> - <!-- no translation found for battery_saver_description (2307555792915978653) --> - <skip /> + <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"Để tăng thời lượng pin, Trình tiết kiệm pin:\n·Bật Giao diện tối\n·Tắt hoặc hạn chế hoạt động chạy trong nền, một số hiệu ứng hình ảnh và các tính năng khác như lệnh “Ok Google”\n\n"<annotation id="url">"Tìm hiểu thêm"</annotation></string> + <string name="battery_saver_description" msgid="2307555792915978653">"Để tăng thời lượng pin, Trình tiết kiệm pin:\n·Bật Giao diện tối\n·Tắt hoặc hạn chế hoạt động chạy trong nền, một số hiệu ứng hình ảnh và các tính năng khác như lệnh “Ok Google”"</string> <string name="data_saver_description" msgid="6015391409098303235">"Để giúp giảm mức sử dụng dữ liệu, Trình tiết kiệm dữ liệu sẽ chặn một số ứng dụng gửi hoặc nhận dữ liệu trong nền. Ứng dụng mà bạn hiện sử dụng có thể dùng dữ liệu nhưng tần suất sẽ giảm. Ví dụ: hình ảnh sẽ không hiển thị cho đến khi bạn nhấn vào hình ảnh đó."</string> <string name="data_saver_enable_title" msgid="4674073932722787417">"Bật Trình tiết kiệm dữ liệu?"</string> <string name="data_saver_enable_button" msgid="7147735965247211818">"Bật"</string> @@ -2008,4 +2006,22 @@ <string name="chooser_no_direct_share_targets" msgid="997970693708458895">"Không thể chia sẻ trực tiếp"</string> <string name="chooser_all_apps_button_label" msgid="3631524352936289457">"Danh sách ứng dụng"</string> <string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"Ứng dụng này chưa được cấp quyền ghi âm nhưng vẫn có thể ghi âm thông qua thiết bị USB này."</string> + <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) --> + <skip /> + <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) --> + <skip /> + <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) --> + <skip /> + <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) --> + <skip /> + <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) --> + <skip /> + <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) --> + <skip /> + <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) --> + <skip /> + <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) --> + <skip /> + <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) --> + <skip /> </resources> diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml index 1a9eec8d1bfe..e29898fc9fa4 100644 --- a/core/res/res/values-zh-rCN/strings.xml +++ b/core/res/res/values-zh-rCN/strings.xml @@ -2008,4 +2008,22 @@ <string name="chooser_no_direct_share_targets" msgid="997970693708458895">"无法使用直接分享功能"</string> <string name="chooser_all_apps_button_label" msgid="3631524352936289457">"应用列表"</string> <string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"此应用未获得录音权限,但能通过此 USB 设备录制音频。"</string> + <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) --> + <skip /> + <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) --> + <skip /> + <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) --> + <skip /> + <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) --> + <skip /> + <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) --> + <skip /> + <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) --> + <skip /> + <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) --> + <skip /> + <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) --> + <skip /> + <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) --> + <skip /> </resources> diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml index a69e357e7c35..40f0c9403a10 100644 --- a/core/res/res/values-zh-rHK/strings.xml +++ b/core/res/res/values-zh-rHK/strings.xml @@ -1771,10 +1771,8 @@ <string name="package_updated_device_owner" msgid="1847154566357862089">"已由您的管理員更新"</string> <string name="package_deleted_device_owner" msgid="2307122077550236438">"已由您的管理員刪除"</string> <string name="confirm_battery_saver" msgid="639106420541753635">"好"</string> - <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) --> - <skip /> - <!-- no translation found for battery_saver_description (2307555792915978653) --> - <skip /> + <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"為延長電池壽命,「省電模式」會:\n開啟深色主題背景\n關閉或限制背景活動、某些視覺效果和其他功能 (例如「Hey Google」)\n\n"<annotation id="url">"瞭解詳情"</annotation></string> + <string name="battery_saver_description" msgid="2307555792915978653">"為延長電池壽命,「省電模式」會:\n開啟深色主題背景\n關閉或限制背景活動、某些視覺效果和其他功能 (例如「Hey Google」)"</string> <string name="data_saver_description" msgid="6015391409098303235">"「數據節省模式」可防止部分應用程式在背景收發資料,以節省數據用量。您正在使用的應用程式可存取資料,但次數可能會減少。例如,圖片可能需要輕按才會顯示。"</string> <string name="data_saver_enable_title" msgid="4674073932722787417">"要開啟「數據節省模式」嗎?"</string> <string name="data_saver_enable_button" msgid="7147735965247211818">"開啟"</string> @@ -2008,4 +2006,22 @@ <string name="chooser_no_direct_share_targets" msgid="997970693708458895">"無法直接分享"</string> <string name="chooser_all_apps_button_label" msgid="3631524352936289457">"應用程式清單"</string> <string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"此應用程式尚未獲授予錄音權限,但可透過此 USB 裝置記錄音訊。"</string> + <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) --> + <skip /> + <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) --> + <skip /> + <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) --> + <skip /> + <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) --> + <skip /> + <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) --> + <skip /> + <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) --> + <skip /> + <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) --> + <skip /> + <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) --> + <skip /> + <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) --> + <skip /> </resources> diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml index 507f6967c931..2fb155e5aed5 100644 --- a/core/res/res/values-zh-rTW/strings.xml +++ b/core/res/res/values-zh-rTW/strings.xml @@ -1771,10 +1771,8 @@ <string name="package_updated_device_owner" msgid="1847154566357862089">"已由你的管理員更新"</string> <string name="package_deleted_device_owner" msgid="2307122077550236438">"已由你的管理員刪除"</string> <string name="confirm_battery_saver" msgid="639106420541753635">"確定"</string> - <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) --> - <skip /> - <!-- no translation found for battery_saver_description (2307555792915978653) --> - <skip /> + <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"為了延長電池續航力,節約耗電量功能會執行以下動作:\n開啟深色主題\n關閉或限制背景活動、部分視覺效果和其他功能,例如「Hey Google」\n\n"<annotation id="url">"瞭解詳情"</annotation></string> + <string name="battery_saver_description" msgid="2307555792915978653">"為了延長電池續航力,節約耗電量功能會執行以下動作:\n開啟深色主題\n關閉或限制背景活動、部分視覺效果和其他功能,例如「Hey Google」"</string> <string name="data_saver_description" msgid="6015391409098303235">"「數據節省模式」可防止部分應用程式在背景收發資料,以節省數據用量。你目前使用的某個應用程式可以存取資料,但存取頻率可能不如平時高。舉例來說,圖片可能不會自動顯示,在你輕觸後才會顯示。"</string> <string name="data_saver_enable_title" msgid="4674073932722787417">"要開啟數據節省模式嗎?"</string> <string name="data_saver_enable_button" msgid="7147735965247211818">"開啟"</string> @@ -2008,4 +2006,22 @@ <string name="chooser_no_direct_share_targets" msgid="997970693708458895">"無法使用直接分享功能"</string> <string name="chooser_all_apps_button_label" msgid="3631524352936289457">"應用程式清單"</string> <string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"這個應用程式未取得錄製內容的權限,但可以透過這部 USB 裝置錄製音訊。"</string> + <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) --> + <skip /> + <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) --> + <skip /> + <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) --> + <skip /> + <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) --> + <skip /> + <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) --> + <skip /> + <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) --> + <skip /> + <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) --> + <skip /> + <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) --> + <skip /> + <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) --> + <skip /> </resources> diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml index c15224a81755..2ecc83518318 100644 --- a/core/res/res/values-zu/strings.xml +++ b/core/res/res/values-zu/strings.xml @@ -1771,10 +1771,8 @@ <string name="package_updated_device_owner" msgid="1847154566357862089">"Kubuyekezwe umlawuli wakho"</string> <string name="package_deleted_device_owner" msgid="2307122077550236438">"Kususwe umlawuli wakho"</string> <string name="confirm_battery_saver" msgid="639106420541753635">"KULUNGILE"</string> - <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) --> - <skip /> - <!-- no translation found for battery_saver_description (2307555792915978653) --> - <skip /> + <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"Ukuze unwebise impilo yebhethri, Isilondolozi Sebhethri:\n·Sivula itimu emnyama\n·Sivala noma sikhawulela umsebenzi wangasemuva, eminye imithelela yokubuka, nezinye izici ezifana nokuthi “Hey Google”\n\n"<annotation id="url">"Funda kabanzi"</annotation></string> + <string name="battery_saver_description" msgid="2307555792915978653">"Ukuze unwebise impilo yebhethri, Isilondolozi sebhethri:\n·Vula itimu emnyama\n·Vala noma ukhawulele umsebenzi wangasemuva, eminye imithelela yokubuka, nezinye izici ezifana nokuthi “Hey Google”"</string> <string name="data_saver_description" msgid="6015391409098303235">"Ukusiza ukwehlisa ukusetshenziswa kwedatha, iseva yedatha igwema ezinye izinhlelo zokusebenza ukuthi zithumele noma zamukele idatha ngasemuva. Uhlelo lokusebenza olisebenzisa okwamanje lingafinyelela idatha, kodwa lingenza kanjalo kancane. Lokhu kungachaza, isibonelo, ukuthi izithombe azibonisi uze uzithephe."</string> <string name="data_saver_enable_title" msgid="4674073932722787417">"Vula iseva yedatha?"</string> <string name="data_saver_enable_button" msgid="7147735965247211818">"Vula"</string> @@ -2008,4 +2006,22 @@ <string name="chooser_no_direct_share_targets" msgid="997970693708458895">"Ukwabelana okuqondile akutholakali"</string> <string name="chooser_all_apps_button_label" msgid="3631524352936289457">"Uhlu lwezinhlelo zokusebenza"</string> <string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"Lolu hlelo lokusebenza alunikeziwe imvume yokurekhoda kodwa lungathwebula umsindo ngale divayisi ye-USB."</string> + <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) --> + <skip /> + <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) --> + <skip /> + <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) --> + <skip /> + <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) --> + <skip /> + <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) --> + <skip /> + <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) --> + <skip /> + <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) --> + <skip /> + <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) --> + <skip /> + <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) --> + <skip /> </resources> diff --git a/data/etc/services.core.protolog.json b/data/etc/services.core.protolog.json index 753f8a05cbe3..b9a1346b7227 100644 --- a/data/etc/services.core.protolog.json +++ b/data/etc/services.core.protolog.json @@ -73,18 +73,18 @@ "group": "WM_ERROR", "at": "com\/android\/server\/wm\/WindowManagerService.java" }, + "-1976550065": { + "message": "commitVisibility: %s: visible=%b visibleRequested=%b", + "level": "VERBOSE", + "group": "WM_DEBUG_APP_TRANSITIONS", + "at": "com\/android\/server\/wm\/ActivityRecord.java" + }, "-1963461591": { "message": "Removing %s from %s", "level": "VERBOSE", "group": "WM_DEBUG_ADD_REMOVE", "at": "com\/android\/server\/wm\/WindowManagerService.java" }, - "-1958209312": { - "message": "Clear freezing of %s: hidden=%b freezing=%b", - "level": "VERBOSE", - "group": "WM_DEBUG_ORIENTATION", - "at": "com\/android\/server\/wm\/ActivityRecord.java" - }, "-1953668890": { "message": "Can't start recents animation, nextAppTransition=%s", "level": "DEBUG", @@ -547,12 +547,6 @@ "group": "WM_DEBUG_STARTING_WINDOW", "at": "com\/android\/server\/wm\/WindowState.java" }, - "-931184679": { - "message": "Changing app %s hidden=%b performLayout=%b", - "level": "VERBOSE", - "group": "WM_DEBUG_APP_TRANSITIONS", - "at": "com\/android\/server\/wm\/ActivityRecord.java" - }, "-928291778": { "message": "applyAnimation: anim=%s nextAppTransition=%d transit=%s Callers=%s", "level": "VERBOSE", @@ -841,6 +835,12 @@ "group": "WM_DEBUG_APP_TRANSITIONS", "at": "com\/android\/server\/wm\/AppTransitionController.java" }, + "-374767836": { + "message": "setAppVisibility(%s, visible=%b): %s visible=%b mVisibleRequested=%b Callers=%s", + "level": "VERBOSE", + "group": "WM_DEBUG_APP_TRANSITIONS", + "at": "com\/android\/server\/wm\/ActivityRecord.java" + }, "-371630969": { "message": "New wallpaper target=%s, oldWallpaper=%s, openingApps=%s, closingApps=%s", "level": "VERBOSE", @@ -1207,12 +1207,6 @@ "group": "WM_DEBUG_ORIENTATION", "at": "com\/android\/server\/wm\/WindowManagerService.java" }, - "358613119": { - "message": "setAppVisibility(%s, visible=%b): %s hidden=%b hiddenRequested=%b Callers=%s", - "level": "VERBOSE", - "group": "WM_DEBUG_APP_TRANSITIONS", - "at": "com\/android\/server\/wm\/ActivityRecord.java" - }, "371641947": { "message": "Window Manager Crash %s", "level": "WTF", @@ -1273,6 +1267,12 @@ "group": "WM_DEBUG_SCREEN_ON", "at": "com\/android\/server\/wm\/WindowManagerService.java" }, + "466506262": { + "message": "Clear freezing of %s: visible=%b freezing=%b", + "level": "VERBOSE", + "group": "WM_DEBUG_ORIENTATION", + "at": "com\/android\/server\/wm\/ActivityRecord.java" + }, "474000473": { "message": "No stack above target stack=%s", "level": "DEBUG", @@ -1489,6 +1489,12 @@ "group": "WM_DEBUG_REMOTE_ANIMATIONS", "at": "com\/android\/server\/wm\/RemoteAnimationController.java" }, + "841702299": { + "message": "Changing app %s visible=%b performLayout=%b", + "level": "VERBOSE", + "group": "WM_DEBUG_APP_TRANSITIONS", + "at": "com\/android\/server\/wm\/ActivityRecord.java" + }, "845234215": { "message": "App is requesting an orientation, return %d for display id=%d", "level": "VERBOSE", @@ -1501,12 +1507,6 @@ "group": "WM_DEBUG_RECENTS_ANIMATIONS", "at": "com\/android\/server\/wm\/RecentsAnimation.java" }, - "857751535": { - "message": "commitVisibility: %s: hidden=%b hiddenRequested=%b", - "level": "VERBOSE", - "group": "WM_DEBUG_APP_TRANSITIONS", - "at": "com\/android\/server\/wm\/ActivityRecord.java" - }, "873914452": { "message": "goodToGo()", "level": "DEBUG", @@ -1903,6 +1903,12 @@ "group": "WM_DEBUG_STARTING_WINDOW", "at": "com\/android\/server\/wm\/ActivityRecord.java" }, + "1746778201": { + "message": "Set freezing of %s: visible=%b freezing=%b visibleRequested=%b. %s", + "level": "INFO", + "group": "WM_DEBUG_ORIENTATION", + "at": "com\/android\/server\/wm\/ActivityRecord.java" + }, "1747941491": { "message": "SURFACE controller=%s alpha=%f matrix=[%f*%f,%f*%f][%f*%f,%f*%f]: %s", "level": "INFO", @@ -1993,12 +1999,6 @@ "group": "WM_DEBUG_REMOTE_ANIMATIONS", "at": "com\/android\/server\/wm\/RemoteAnimationController.java" }, - "1966564525": { - "message": "Set freezing of %s: hidden=%b freezing=%b hiddenRequested=%b. %s", - "level": "INFO", - "group": "WM_DEBUG_ORIENTATION", - "at": "com\/android\/server\/wm\/ActivityRecord.java" - }, "1984470582": { "message": "Creating TaskScreenshotAnimatable: task: %s width: %d height: %d", "level": "DEBUG", diff --git a/location/TEST_MAPPING b/location/TEST_MAPPING deleted file mode 100644 index 2f386271dcb7..000000000000 --- a/location/TEST_MAPPING +++ /dev/null @@ -1,10 +0,0 @@ -{ - "presubmit": [ - { - "name": "CtsLocationCoarseTestCases" - }, - { - "name": "CtsLocationNoneTestCases" - } - ] -} diff --git a/location/java/android/location/GnssStatus.java b/location/java/android/location/GnssStatus.java index 211a0cb5852d..b363686c2df5 100644 --- a/location/java/android/location/GnssStatus.java +++ b/location/java/android/location/GnssStatus.java @@ -27,7 +27,11 @@ import java.lang.annotation.RetentionPolicy; * This class is used in conjunction with the {@link GnssStatus.Callback}. */ public final class GnssStatus { + // these must match the definitions in gps.h + // + // Note: these constants are also duplicated in GnssStatusCompat.java in the androidx support + // library. if adding a constellation, please update that file as well. /** Unknown constellation type. */ public static final int CONSTELLATION_UNKNOWN = 0; diff --git a/location/java/android/location/LocationManager.java b/location/java/android/location/LocationManager.java index c48f6e83ff20..39a7e25cb68b 100644 --- a/location/java/android/location/LocationManager.java +++ b/location/java/android/location/LocationManager.java @@ -435,7 +435,7 @@ public class LocationManager { * {@link SecurityException} if the location permissions were not sufficient to use the * specified provider. * - * @param provider the name of the provider + * @param provider a provider listed by {@link #getAllProviders()} * @return true if the provider exists and is enabled * * @throws IllegalArgumentException if provider is null @@ -453,7 +453,7 @@ public class LocationManager { * {@link SecurityException} if the location permissions were not sufficient to use the * specified provider. * - * @param provider the name of the provider + * @param provider a provider listed by {@link #getAllProviders()} * @param userHandle the user to query * @return true if the provider exists and is enabled * @@ -477,8 +477,8 @@ public class LocationManager { * functions as a best effort. It should not be relied on in any meaningful sense as providers * may no longer be enabled or disabled by clients. * - * @param provider the name of the provider - * @param enabled true to enable the provider. false to disable the provider + * @param provider a provider listed by {@link #getAllProviders()} + * @param enabled whether to enable or disable the provider * @param userHandle the user to set * @return true if the value was set, false otherwise * @@ -534,7 +534,7 @@ public class LocationManager { * will always attempt to return a current location, but will potentially use additional power * in the course of the attempt as compared to this method. * - * @param provider the name of the provider + * @param provider a provider listed by {@link #getAllProviders()} * @return the last known location for the given provider, or null if not available * @throws SecurityException if no suitable permission is present * @throws IllegalArgumentException if provider is null or doesn't exist @@ -587,7 +587,7 @@ public class LocationManager { * determine a valid location fix more often than while in the foreground. Background * applications may be throttled in their location accesses to some degree. * - * @param provider the name of the provider with which to register + * @param provider a provider listed by {@link #getAllProviders()} * @param cancellationSignal an optional signal that allows for cancelling this call * @param executor the callback will take place on this {@link Executor} * @param consumer the callback invoked with either a {@link Location} or null @@ -667,7 +667,7 @@ public class LocationManager { * <p>See {@link #requestLocationUpdates(String, long, float, LocationListener, Looper)} for * more detail on how to use this method. * - * @param provider the name of the provider with which to register + * @param provider a provider listed by {@link #getAllProviders()} * @param listener the listener to receive location updates * @param looper the looper handling listener callbacks, or null to use the looper of the * calling thread @@ -729,7 +729,7 @@ public class LocationManager { * <p>See {@link #requestLocationUpdates(long, float, Criteria, PendingIntent)} for more detail * on how to use this method. * - * @param provider the name of the provider with which to register + * @param provider a provider listed by {@link #getAllProviders()} * @param pendingIntent the pending intent to send location updates * * @throws IllegalArgumentException if provider is null or doesn't exist @@ -829,10 +829,10 @@ public class LocationManager { * * <p>To unregister for location updates, use {@link #removeUpdates(LocationListener)}. * - * @param provider the name of the provider with which to register - * @param minTimeMs minimum time interval between location updates in milliseconds + * @param provider a provider listed by {@link #getAllProviders()} + * @param minTimeMs minimum time interval between location updates in milliseconds * @param minDistanceM minimum distance between location updates in meters - * @param listener the listener to receive location updates + * @param listener the listener to receive location updates * * @throws IllegalArgumentException if provider is null or doesn't exist * @throws IllegalArgumentException if listener is null @@ -857,12 +857,12 @@ public class LocationManager { * <p>See {@link #requestLocationUpdates(String, long, float, LocationListener)} * for more detail on how this method works. * - * @param provider the name of the provider with which to register - * @param minTimeMs minimum time interval between location updates in milliseconds + * @param provider a provider listed by {@link #getAllProviders()} + * @param minTimeMs minimum time interval between location updates in milliseconds * @param minDistanceM minimum distance between location updates in meters - * @param listener the listener to receive location updates - * @param looper the looper handling listener callbacks, or null to use the looper of the - * calling thread + * @param listener the listener to receive location updates + * @param looper the looper handling listener callbacks, or null to use the looper of the + * calling thread * * @throws IllegalArgumentException if provider is null or doesn't exist * @throws IllegalArgumentException if listener is null @@ -886,11 +886,11 @@ public class LocationManager { * <p>See {@link #requestLocationUpdates(String, long, float, LocationListener)} * for more detail on how this method works. * - * @param provider the name of the provider with which to register - * @param minTimeMs minimum time interval between location updates in milliseconds + * @param provider a provider listed by {@link #getAllProviders()} + * @param minTimeMs minimum time interval between location updates in milliseconds * @param minDistanceM minimum distance between location updates in meters - * @param executor the executor handling listener callbacks - * @param listener the listener to receive location updates + * @param executor the executor handling listener callbacks + * @param listener the listener to receive location updates * * @throws IllegalArgumentException if provider is null or doesn't exist * @throws IllegalArgumentException if executor is null @@ -980,9 +980,9 @@ public class LocationManager { * <p>See {@link #requestLocationUpdates(String, long, float, LocationListener)} * for more detail on how this method works. * - * @param provider the name of the provider with which to register - * @param minTimeMs minimum time interval between location updates in milliseconds - * @param minDistanceM minimum distance between location updates in meters + * @param provider a provider listed by {@link #getAllProviders()} + * @param minTimeMs minimum time interval between location updates in milliseconds + * @param minDistanceM minimum distance between location updates in meters * @param pendingIntent the pending intent to send location updates * * @throws IllegalArgumentException if provider is null or doesn't exist @@ -1317,7 +1317,7 @@ public class LocationManager { * Returns the information about the location provider with the given name, or null if no * provider exists by that name. * - * @param provider the provider name + * @param provider a provider listed by {@link #getAllProviders()} * @return location provider information, or null if provider does not exist * * @throws IllegalArgumentException if provider is null @@ -1374,7 +1374,7 @@ public class LocationManager { * Sends additional commands to a location provider. Can be used to support provider specific * extensions to the Location Manager API. * - * @param provider name of the location provider + * @param provider a provider listed by {@link #getAllProviders()} * @param command name of the command to send to the provider * @param extras optional arguments for the command, or null * @return true always, the return value may be ignored @@ -1810,6 +1810,14 @@ public class LocationManager { @Deprecated @RequiresPermission(ACCESS_FINE_LOCATION) public @Nullable GpsStatus getGpsStatus(@Nullable GpsStatus status) { + UnsupportedOperationException ex = new UnsupportedOperationException( + "GpsStatus APIs not supported in S and above, use GnssStatus APIs instead"); + if (mContext.getApplicationInfo().targetSdkVersion > Build.VERSION_CODES.R) { + throw ex; + } else { + Log.w(TAG, ex); + } + if (status == null) { status = new GpsStatus(); } @@ -1837,8 +1845,8 @@ public class LocationManager { @RequiresPermission(ACCESS_FINE_LOCATION) public boolean addGpsStatusListener(GpsStatus.Listener listener) { UnsupportedOperationException ex = new UnsupportedOperationException( - "GpsStatus APIs not supported in R and above, use GnssStatus APIs instead"); - if (mContext.getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.R) { + "GpsStatus APIs not supported in S and above, use GnssStatus APIs instead"); + if (mContext.getApplicationInfo().targetSdkVersion > Build.VERSION_CODES.R) { throw ex; } else { Log.w(TAG, ex); @@ -1862,8 +1870,8 @@ public class LocationManager { @Deprecated public void removeGpsStatusListener(GpsStatus.Listener listener) { UnsupportedOperationException ex = new UnsupportedOperationException( - "GpsStatus APIs not supported in R and above, use GnssStatus APIs instead"); - if (mContext.getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.R) { + "GpsStatus APIs not supported in S and above, use GnssStatus APIs instead"); + if (mContext.getApplicationInfo().targetSdkVersion > Build.VERSION_CODES.R) { throw ex; } else { Log.w(TAG, ex); @@ -1955,23 +1963,21 @@ public class LocationManager { /** * No-op method to keep backward-compatibility. * - * @deprecated use {@link #addNmeaListener(OnNmeaMessageListener)} instead. - * @removed + * @deprecated Use {@link #addNmeaListener} instead. */ @Deprecated @RequiresPermission(ACCESS_FINE_LOCATION) - public boolean addNmeaListener(GpsStatus.NmeaListener listener) { + public boolean addNmeaListener(@NonNull GpsStatus.NmeaListener listener) { return false; } /** * No-op method to keep backward-compatibility. * - * @deprecated use {@link #removeNmeaListener(OnNmeaMessageListener)} instead. - * @removed + * @deprecated Use {@link #removeNmeaListener(OnNmeaMessageListener)} instead. */ @Deprecated - public void removeNmeaListener(GpsStatus.NmeaListener listener) {} + public void removeNmeaListener(@NonNull GpsStatus.NmeaListener listener) {} /** * Adds an NMEA listener. diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java index 9ad7f2a7dcc6..d5524915f423 100644 --- a/media/java/android/media/AudioManager.java +++ b/media/java/android/media/AudioManager.java @@ -1,4 +1,5 @@ /* +/* * Copyright (C) 2007 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -1931,12 +1932,11 @@ public class AudioManager { * application when it places a phone call, as it will cause signals from the radio layer * to feed the platform mixer. * - * @param mode the requested audio mode ({@link #MODE_NORMAL}, {@link #MODE_RINGTONE}, - * {@link #MODE_IN_CALL} or {@link #MODE_IN_COMMUNICATION}). + * @param mode the requested audio mode. * Informs the HAL about the current audio state so that * it can route the audio appropriately. */ - public void setMode(int mode) { + public void setMode(@AudioMode int mode) { final IAudioService service = getService(); try { service.setMode(mode, mICallBack, mApplicationContext.getOpPackageName()); @@ -1948,14 +1948,47 @@ public class AudioManager { /** * Returns the current audio mode. * - * @return the current audio mode ({@link #MODE_NORMAL}, {@link #MODE_RINGTONE}, - * {@link #MODE_IN_CALL} or {@link #MODE_IN_COMMUNICATION}). - * Returns the current current audio state from the HAL. + * @return the current audio mode. */ + @AudioMode public int getMode() { final IAudioService service = getService(); try { - return service.getMode(); + int mode = service.getMode(); + int sdk; + try { + sdk = getContext().getApplicationInfo().targetSdkVersion; + } catch (NullPointerException e) { + // some tests don't have a Context + sdk = Build.VERSION.SDK_INT; + } + if (mode == MODE_CALL_SCREENING && sdk <= Build.VERSION_CODES.Q) { + mode = MODE_IN_CALL; + } + return mode; + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Indicates if the platform supports a special call screening and call monitoring mode. + * <p> + * When this mode is supported, it is possible to perform call screening and monitoring + * functions while other use cases like music or movie playback are active. + * <p> + * Use {@link #setMode(int)} with mode {@link #MODE_CALL_SCREENING} to place the platform in + * call screening mode. + * <p> + * If call screening mode is not supported, setting mode to + * MODE_CALL_SCREENING will be ignored and will not change current mode reported by + * {@link #getMode()}. + * @return true if call screening mode is supported, false otherwise. + */ + public boolean isCallScreeningModeSupported() { + final IAudioService service = getService(); + try { + return service.isCallScreeningModeSupported(); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -1989,6 +2022,22 @@ public class AudioManager { * In communication audio mode. An audio/video chat or VoIP call is established. */ public static final int MODE_IN_COMMUNICATION = AudioSystem.MODE_IN_COMMUNICATION; + /** + * Call screening in progress. Call is connected and audio is accessible to call + * screening applications but other audio use cases are still possible. + */ + public static final int MODE_CALL_SCREENING = AudioSystem.MODE_CALL_SCREENING; + + /** @hide */ + @IntDef(flag = false, prefix = "MODE_", value = { + MODE_NORMAL, + MODE_RINGTONE, + MODE_IN_CALL, + MODE_IN_COMMUNICATION, + MODE_CALL_SCREENING } + ) + @Retention(RetentionPolicy.SOURCE) + public @interface AudioMode {} /* Routing bits for setRouting/getRouting API */ /** diff --git a/media/java/android/media/AudioSystem.java b/media/java/android/media/AudioSystem.java index 900572dabc94..a3a87774483b 100644 --- a/media/java/android/media/AudioSystem.java +++ b/media/java/android/media/AudioSystem.java @@ -132,7 +132,8 @@ public class AudioSystem public static final int MODE_RINGTONE = 1; public static final int MODE_IN_CALL = 2; public static final int MODE_IN_COMMUNICATION = 3; - public static final int NUM_MODES = 4; + public static final int MODE_CALL_SCREENING = 4; + public static final int NUM_MODES = 5; public static String modeToString(int mode) { switch (mode) { @@ -142,6 +143,7 @@ public class AudioSystem case MODE_INVALID: return "MODE_INVALID"; case MODE_NORMAL: return "MODE_NORMAL"; case MODE_RINGTONE: return "MODE_RINGTONE"; + case MODE_CALL_SCREENING: return "MODE_CALL_SCREENING"; default: return "unknown mode (" + mode + ")"; } } @@ -1130,6 +1132,11 @@ public class AudioSystem */ public static native int setAudioHalPids(int[] pids); + /** + * @see AudioManager#isCallScreeningModeSupported() + */ + public static native boolean isCallScreeningModeSupported(); + // Items shared with audio service /** diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl index fc056109baa4..ef451ce401e6 100644 --- a/media/java/android/media/IAudioService.aidl +++ b/media/java/android/media/IAudioService.aidl @@ -263,6 +263,8 @@ interface IAudioService { boolean hasHapticChannels(in Uri uri); + boolean isCallScreeningModeSupported(); + // WARNING: read warning at top of file, new methods that need to be used by native // code via IAudioManager.h need to be added to the top section. } diff --git a/media/jni/android_media_MediaDrm.cpp b/media/jni/android_media_MediaDrm.cpp index 99394adec27d..3833c6bfb676 100644 --- a/media/jni/android_media_MediaDrm.cpp +++ b/media/jni/android_media_MediaDrm.cpp @@ -211,48 +211,6 @@ static fields_t gFields; namespace { -// Helper function to convert a native PersistableBundle to a Java -// PersistableBundle. -jobject nativeToJavaPersistableBundle(JNIEnv *env, jobject thiz, - PersistableBundle* nativeBundle) { - if (env == NULL || thiz == NULL || nativeBundle == NULL) { - ALOGE("Unexpected NULL parmeter"); - return NULL; - } - - // Create a Java parcel with the native parcel data. - // Then create a new PersistableBundle with that parcel as a parameter. - jobject jParcel = android::createJavaParcelObject(env); - if (jParcel == NULL) { - ALOGE("Failed to create a Java Parcel."); - return NULL; - } - - android::Parcel* nativeParcel = android::parcelForJavaObject(env, jParcel); - if (nativeParcel == NULL) { - ALOGE("Failed to get the native Parcel."); - return NULL; - } - - android::status_t result = nativeBundle->writeToParcel(nativeParcel); - nativeParcel->setDataPosition(0); - if (result != android::OK) { - ALOGE("Failed to write nativeBundle to Parcel: %d.", result); - return NULL; - } - - jobject newBundle = env->CallObjectMethod(gFields.bundleCreator, - gFields.createFromParcelId, - jParcel); - if (newBundle == NULL) { - ALOGE("Failed to create a new PersistableBundle " - "from the createFromParcel call."); - } - - return newBundle; -} - - jbyteArray hidlVectorToJByteArray(const hardware::hidl_vec<uint8_t> &vector) { JNIEnv *env = AndroidRuntime::getJNIEnv(); size_t length = vector.size(); @@ -1937,7 +1895,7 @@ android_media_MediaDrm_native_getMetrics(JNIEnv *env, jobject thiz) return (jobject) NULL; } - return nativeToJavaPersistableBundle(env, thiz, &metrics); + return MediaMetricsJNI::nativeToJavaPersistableBundle(env, &metrics); } static jbyteArray android_media_MediaDrm_signRSANative( diff --git a/media/jni/android_media_MediaMetricsJNI.cpp b/media/jni/android_media_MediaMetricsJNI.cpp index e7487c3cbc67..5ddfcfce072e 100644 --- a/media/jni/android_media_MediaMetricsJNI.cpp +++ b/media/jni/android_media_MediaMetricsJNI.cpp @@ -20,7 +20,9 @@ #include <nativehelper/JNIHelp.h> #include "android_media_MediaMetricsJNI.h" +#include "android_os_Parcel.h" #include <media/MediaAnalyticsItem.h> +#include <binder/Parcel.h> // This source file is compiled and linked into: @@ -223,5 +225,72 @@ jobject MediaMetricsJNI::writeAttributesToBundle(JNIEnv* env, jobject mybundle, return NULL; } +// Helper function to convert a native PersistableBundle to a Java +// PersistableBundle. +jobject MediaMetricsJNI::nativeToJavaPersistableBundle(JNIEnv *env, + os::PersistableBundle* nativeBundle) { + if (env == NULL || nativeBundle == NULL) { + ALOGE("Unexpected NULL parmeter"); + return NULL; + } + + // Create a Java parcel with the native parcel data. + // Then create a new PersistableBundle with that parcel as a parameter. + jobject jParcel = android::createJavaParcelObject(env); + if (jParcel == NULL) { + ALOGE("Failed to create a Java Parcel."); + return NULL; + } + + android::Parcel* nativeParcel = android::parcelForJavaObject(env, jParcel); + if (nativeParcel == NULL) { + ALOGE("Failed to get the native Parcel."); + return NULL; + } + + android::status_t result = nativeBundle->writeToParcel(nativeParcel); + nativeParcel->setDataPosition(0); + if (result != android::OK) { + ALOGE("Failed to write nativeBundle to Parcel: %d.", result); + return NULL; + } + +#define STATIC_INIT_JNI(T, obj, method, globalref, ...) \ + static T obj{};\ + if (obj == NULL) { \ + obj = method(__VA_ARGS__); \ + if (obj == NULL) { \ + ALOGE("%s can't find " #obj, __func__); \ + return NULL; \ + } else { \ + obj = globalref; \ + }\ + } \ + + STATIC_INIT_JNI(jclass, clazzBundle, env->FindClass, + static_cast<jclass>(env->NewGlobalRef(clazzBundle)), + "android/os/PersistableBundle"); + STATIC_INIT_JNI(jfieldID, bundleCreatorId, env->GetStaticFieldID, + bundleCreatorId, + clazzBundle, "CREATOR", "Landroid/os/Parcelable$Creator;"); + STATIC_INIT_JNI(jobject, bundleCreator, env->GetStaticObjectField, + env->NewGlobalRef(bundleCreator), + clazzBundle, bundleCreatorId); + STATIC_INIT_JNI(jclass, clazzCreator, env->FindClass, + static_cast<jclass>(env->NewGlobalRef(clazzCreator)), + "android/os/Parcelable$Creator"); + STATIC_INIT_JNI(jmethodID, createFromParcelId, env->GetMethodID, + createFromParcelId, + clazzCreator, "createFromParcel", "(Landroid/os/Parcel;)Ljava/lang/Object;"); + + jobject newBundle = env->CallObjectMethod(bundleCreator, createFromParcelId, jParcel); + if (newBundle == NULL) { + ALOGE("Failed to create a new PersistableBundle " + "from the createFromParcel call."); + } + + return newBundle; +} + }; // namespace android diff --git a/media/jni/android_media_MediaMetricsJNI.h b/media/jni/android_media_MediaMetricsJNI.h index a10780f5c5c3..e879da01c6ef 100644 --- a/media/jni/android_media_MediaMetricsJNI.h +++ b/media/jni/android_media_MediaMetricsJNI.h @@ -20,6 +20,7 @@ #include <jni.h> #include <nativehelper/JNIHelp.h> #include <media/MediaAnalyticsItem.h> +#include <binder/PersistableBundle.h> // Copeid from core/jni/ (libandroid_runtime.so) namespace android { @@ -28,6 +29,7 @@ class MediaMetricsJNI { public: static jobject writeMetricsToBundle(JNIEnv* env, MediaAnalyticsItem *item, jobject mybundle); static jobject writeAttributesToBundle(JNIEnv* env, jobject mybundle, char *buffer, size_t length); + static jobject nativeToJavaPersistableBundle(JNIEnv*, os::PersistableBundle*); }; }; // namespace android diff --git a/media/lib/tvremote/OWNERS b/media/lib/tvremote/OWNERS new file mode 100644 index 000000000000..81d52e1d72db --- /dev/null +++ b/media/lib/tvremote/OWNERS @@ -0,0 +1,2 @@ +nutka@google.com +skill@google.com diff --git a/native/android/libandroid_net.map.txt b/native/android/libandroid_net.map.txt index be3531da462d..8d4e9009cc56 100644 --- a/native/android/libandroid_net.map.txt +++ b/native/android/libandroid_net.map.txt @@ -1,15 +1,19 @@ -# They are also all available to vendor code. +# The following symbols marked with # llndk are available to vendor code. +# Unlike other VNDK libraries where keeping backwards compatibility is required +# only within a platform release, these symbols need much longer suppport +# because the same LLNDK library serves for both system and vendor partition +# which might be a few years old. LIBANDROID_NET { global: # These functions have been part of the NDK since API 24. - android_getaddrinfofornetwork; # vndk - android_setsocknetwork; # vndk - android_setprocnetwork; # vndk + android_getaddrinfofornetwork; # llndk + android_setsocknetwork; # llndk + android_setprocnetwork; # llndk # These functions have been part of the NDK since API 29. - android_res_cancel; # vndk - android_res_nquery; # vndk - android_res_nresult; # vndk - android_res_nsend; # vndk + android_res_cancel; # llndk + android_res_nquery; # llndk + android_res_nresult; # llndk + android_res_nsend; # llndk local: *; }; diff --git a/packages/CarSystemUI/src/com/android/systemui/car/CarServiceProvider.java b/packages/CarSystemUI/src/com/android/systemui/car/CarServiceProvider.java new file mode 100644 index 000000000000..f8bfeec6df2d --- /dev/null +++ b/packages/CarSystemUI/src/com/android/systemui/car/CarServiceProvider.java @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.car; + +import android.car.Car; +import android.content.Context; + +import java.util.ArrayList; +import java.util.List; + +import javax.inject.Inject; +import javax.inject.Singleton; + +/** Provides a common connection to the car service that can be shared. */ +@Singleton +public class CarServiceProvider { + + private final Context mContext; + private final List<CarServiceOnConnectedListener> mListeners = new ArrayList<>(); + private Car mCar; + + @Inject + public CarServiceProvider(Context context) { + mContext = context; + mCar = Car.createCar(mContext, /* handler= */ null, Car.CAR_WAIT_TIMEOUT_DO_NOT_WAIT, + (car, ready) -> { + mCar = car; + + synchronized (mListeners) { + for (CarServiceOnConnectedListener listener : mListeners) { + if (ready) { + listener.onConnected(mCar); + } + } + } + }); + } + + /** + * Let's other components hook into the connection to the car service. If we're already + * connected to the car service, the callback is immediately triggered. + */ + public void addListener(CarServiceOnConnectedListener listener) { + if (mCar.isConnected()) { + listener.onConnected(mCar); + } + mListeners.add(listener); + } + + /** + * Listener which is triggered when Car Service is connected. + */ + public interface CarServiceOnConnectedListener { + /** This will be called when the car service has successfully been connected. */ + void onConnected(Car car); + } +} diff --git a/packages/CarSystemUI/src/com/android/systemui/navigationbar/car/CarNavigationBar.java b/packages/CarSystemUI/src/com/android/systemui/navigationbar/car/CarNavigationBar.java index af92767efc49..08ab4928adfe 100644 --- a/packages/CarSystemUI/src/com/android/systemui/navigationbar/car/CarNavigationBar.java +++ b/packages/CarSystemUI/src/com/android/systemui/navigationbar/car/CarNavigationBar.java @@ -37,6 +37,7 @@ import com.android.systemui.dagger.qualifiers.MainHandler; import com.android.systemui.shared.system.ActivityManagerWrapper; import com.android.systemui.statusbar.CommandQueue; import com.android.systemui.statusbar.NavigationBarController; +import com.android.systemui.statusbar.SuperStatusBarViewFactory; import com.android.systemui.statusbar.policy.DeviceProvisionedController; import com.android.systemui.statusbar.policy.KeyguardStateController; @@ -54,10 +55,12 @@ public class CarNavigationBar extends SystemUI implements CommandQueue.Callbacks private final WindowManager mWindowManager; private final DeviceProvisionedController mDeviceProvisionedController; private final CommandQueue mCommandQueue; - private final Lazy<FacetButtonTaskStackListener> mFacetButtonTaskStackListener; + private final Lazy<FacetButtonTaskStackListener> mFacetButtonTaskStackListenerLazy; private final Handler mMainHandler; - private final Lazy<KeyguardStateController> mKeyguardStateController; - private final Lazy<NavigationBarController> mNavigationBarController; + private final Lazy<KeyguardStateController> mKeyguardStateControllerLazy; + private final Lazy<NavigationBarController> mNavigationBarControllerLazy; + private final SuperStatusBarViewFactory mSuperStatusBarViewFactory; + private final Lazy<CarFacetButtonController> mCarFacetButtonControllerLazy; private IStatusBarService mBarService; private ActivityManagerWrapper mActivityManagerWrapper; @@ -67,10 +70,12 @@ public class CarNavigationBar extends SystemUI implements CommandQueue.Callbacks private boolean mBottomNavBarVisible; // Nav bar views. - private ViewGroup mNavigationBarWindow; + private ViewGroup mTopNavigationBarWindow; + private ViewGroup mBottomNavigationBarWindow; private ViewGroup mLeftNavigationBarWindow; private ViewGroup mRightNavigationBarWindow; - private CarNavigationBarView mNavigationBarView; + private CarNavigationBarView mTopNavigationBarView; + private CarNavigationBarView mBottomNavigationBarView; private CarNavigationBarView mLeftNavigationBarView; private CarNavigationBarView mRightNavigationBarView; @@ -84,19 +89,23 @@ public class CarNavigationBar extends SystemUI implements CommandQueue.Callbacks WindowManager windowManager, DeviceProvisionedController deviceProvisionedController, CommandQueue commandQueue, - Lazy<FacetButtonTaskStackListener> facetButtonTaskStackListener, + Lazy<FacetButtonTaskStackListener> facetButtonTaskStackListenerLazy, @MainHandler Handler mainHandler, - Lazy<KeyguardStateController> keyguardStateController, - Lazy<NavigationBarController> navigationBarController) { + Lazy<KeyguardStateController> keyguardStateControllerLazy, + Lazy<NavigationBarController> navigationBarControllerLazy, + SuperStatusBarViewFactory superStatusBarViewFactory, + Lazy<CarFacetButtonController> carFacetButtonControllerLazy) { super(context); mCarNavigationBarController = carNavigationBarController; mWindowManager = windowManager; mDeviceProvisionedController = deviceProvisionedController; mCommandQueue = commandQueue; - mFacetButtonTaskStackListener = facetButtonTaskStackListener; + mFacetButtonTaskStackListenerLazy = facetButtonTaskStackListenerLazy; mMainHandler = mainHandler; - mKeyguardStateController = keyguardStateController; - mNavigationBarController = navigationBarController; + mKeyguardStateControllerLazy = keyguardStateControllerLazy; + mNavigationBarControllerLazy = navigationBarControllerLazy; + mSuperStatusBarViewFactory = superStatusBarViewFactory; + mCarFacetButtonControllerLazy = carFacetButtonControllerLazy; } @Override @@ -137,7 +146,7 @@ public class CarNavigationBar extends SystemUI implements CommandQueue.Callbacks createNavigationBar(result); mActivityManagerWrapper = ActivityManagerWrapper.getInstance(); - mActivityManagerWrapper.registerTaskStackListener(mFacetButtonTaskStackListener.get()); + mActivityManagerWrapper.registerTaskStackListener(mFacetButtonTaskStackListenerLazy.get()); mCarNavigationBarController.connectToHvac(); } @@ -158,10 +167,16 @@ public class CarNavigationBar extends SystemUI implements CommandQueue.Callbacks // remove and reattach all hvac components such that we don't keep a reference to unused // ui elements mCarNavigationBarController.removeAllFromHvac(); + mCarFacetButtonControllerLazy.get().removeAll(); - if (mNavigationBarWindow != null) { - mNavigationBarWindow.removeAllViews(); - mNavigationBarView = null; + if (mTopNavigationBarWindow != null) { + mTopNavigationBarWindow.removeAllViews(); + mTopNavigationBarView = null; + } + + if (mBottomNavigationBarWindow != null) { + mBottomNavigationBarWindow.removeAllViews(); + mBottomNavigationBarView = null; } if (mLeftNavigationBarWindow != null) { @@ -177,8 +192,8 @@ public class CarNavigationBar extends SystemUI implements CommandQueue.Callbacks buildNavBarContent(); // If the UI was rebuilt (day/night change) while the keyguard was up we need to // correctly respect that state. - if (mKeyguardStateController.get().isShowing()) { - updateNavBarForKeyguardContent(); + if (mKeyguardStateControllerLazy.get().isShowing()) { + mCarNavigationBarController.showAllKeyguardButtons(mDeviceIsSetUpForUser); } } @@ -196,20 +211,28 @@ public class CarNavigationBar extends SystemUI implements CommandQueue.Callbacks // There has been a car customized nav bar on the default display, so just create nav bars // on external displays. - mNavigationBarController.get().createNavigationBars(/* includeDefaultDisplay= */ false, + mNavigationBarControllerLazy.get().createNavigationBars(/* includeDefaultDisplay= */ false, result); } private void buildNavBarWindows() { - mNavigationBarWindow = mCarNavigationBarController.getBottomWindow(); + mTopNavigationBarWindow = mSuperStatusBarViewFactory + .getStatusBarWindowView() + .findViewById(R.id.car_top_navigation_bar_container); + mBottomNavigationBarWindow = mCarNavigationBarController.getBottomWindow(); mLeftNavigationBarWindow = mCarNavigationBarController.getLeftWindow(); mRightNavigationBarWindow = mCarNavigationBarController.getRightWindow(); } private void buildNavBarContent() { - mNavigationBarView = mCarNavigationBarController.getBottomBar(mDeviceIsSetUpForUser); - if (mNavigationBarView != null) { - mNavigationBarWindow.addView(mNavigationBarView); + mTopNavigationBarView = mCarNavigationBarController.getTopBar(mDeviceIsSetUpForUser); + if (mTopNavigationBarView != null) { + mTopNavigationBarWindow.addView(mTopNavigationBarView); + } + + mBottomNavigationBarView = mCarNavigationBarController.getBottomBar(mDeviceIsSetUpForUser); + if (mBottomNavigationBarView != null) { + mBottomNavigationBarWindow.addView(mBottomNavigationBarView); } mLeftNavigationBarView = mCarNavigationBarController.getLeftBar(mDeviceIsSetUpForUser); @@ -224,7 +247,7 @@ public class CarNavigationBar extends SystemUI implements CommandQueue.Callbacks } private void attachNavBarWindows() { - if (mNavigationBarWindow != null && !mBottomNavBarVisible) { + if (mBottomNavigationBarWindow != null && !mBottomNavBarVisible) { mBottomNavBarVisible = true; WindowManager.LayoutParams lp = new WindowManager.LayoutParams( @@ -237,7 +260,7 @@ public class CarNavigationBar extends SystemUI implements CommandQueue.Callbacks PixelFormat.TRANSLUCENT); lp.setTitle("CarNavigationBar"); lp.windowAnimations = 0; - mWindowManager.addView(mNavigationBarWindow, lp); + mWindowManager.addView(mBottomNavigationBarWindow, lp); } if (mLeftNavigationBarWindow != null) { @@ -297,23 +320,11 @@ public class CarNavigationBar extends SystemUI implements CommandQueue.Callbacks isKeyboardVisible ? View.GONE : View.VISIBLE); } - private void updateNavBarForKeyguardContent() { - if (mNavigationBarView != null) { - mNavigationBarView.showKeyguardButtons(); - } - if (mLeftNavigationBarView != null) { - mLeftNavigationBarView.showKeyguardButtons(); - } - if (mRightNavigationBarView != null) { - mRightNavigationBarView.showKeyguardButtons(); - } - } - @Override public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { pw.print(" mTaskStackListener="); - pw.println(mFacetButtonTaskStackListener.get()); - pw.print(" mNavigationBarView="); - pw.println(mNavigationBarView); + pw.println(mFacetButtonTaskStackListenerLazy.get()); + pw.print(" mBottomNavigationBarView="); + pw.println(mBottomNavigationBarView); } } diff --git a/packages/CarSystemUI/src/com/android/systemui/navigationbar/car/CarNavigationBarController.java b/packages/CarSystemUI/src/com/android/systemui/navigationbar/car/CarNavigationBarController.java index 6bed69bdee88..6f288439ddeb 100644 --- a/packages/CarSystemUI/src/com/android/systemui/navigationbar/car/CarNavigationBarController.java +++ b/packages/CarSystemUI/src/com/android/systemui/navigationbar/car/CarNavigationBarController.java @@ -24,8 +24,7 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; import com.android.systemui.R; -import com.android.systemui.statusbar.car.hvac.HvacController; -import com.android.systemui.statusbar.car.hvac.TemperatureView; +import com.android.systemui.navigationbar.car.hvac.HvacController; import javax.inject.Inject; import javax.inject.Singleton; @@ -38,6 +37,7 @@ public class CarNavigationBarController { private final Context mContext; private final NavigationBarViewFactory mNavigationBarViewFactory; + private final Lazy<CarFacetButtonController> mCarFacetButtonControllerLazy; private final Lazy<HvacController> mHvacControllerLazy; private boolean mShowBottom; @@ -58,9 +58,11 @@ public class CarNavigationBarController { @Inject public CarNavigationBarController(Context context, NavigationBarViewFactory navigationBarViewFactory, + Lazy<CarFacetButtonController> carFacetButtonControllerLazy, Lazy<HvacController> hvacControllerLazy) { mContext = context; mNavigationBarViewFactory = navigationBarViewFactory; + mCarFacetButtonControllerLazy = carFacetButtonControllerLazy; mHvacControllerLazy = hvacControllerLazy; // Read configuration. @@ -129,9 +131,7 @@ public class CarNavigationBarController { @NonNull public CarNavigationBarView getTopBar(boolean isSetUp) { mTopView = mNavigationBarViewFactory.getTopBar(isSetUp); - mTopView.setStatusBarWindowTouchListener(mTopBarTouchListener); - mTopView.setNotificationsPanelController(mNotificationsShadeController); - addTemperatureViewToController(mTopView); + setupBar(mTopView, mTopBarTouchListener, mNotificationsShadeController); return mTopView; } @@ -143,9 +143,7 @@ public class CarNavigationBarController { } mBottomView = mNavigationBarViewFactory.getBottomBar(isSetUp); - mBottomView.setStatusBarWindowTouchListener(mBottomBarTouchListener); - mBottomView.setNotificationsPanelController(mNotificationsShadeController); - addTemperatureViewToController(mBottomView); + setupBar(mBottomView, mBottomBarTouchListener, mNotificationsShadeController); return mBottomView; } @@ -157,9 +155,7 @@ public class CarNavigationBarController { } mLeftView = mNavigationBarViewFactory.getLeftBar(isSetUp); - mLeftView.setStatusBarWindowTouchListener(mLeftBarTouchListener); - mLeftView.setNotificationsPanelController(mNotificationsShadeController); - addTemperatureViewToController(mLeftView); + setupBar(mLeftView, mLeftBarTouchListener, mNotificationsShadeController); return mLeftView; } @@ -171,12 +167,18 @@ public class CarNavigationBarController { } mRightView = mNavigationBarViewFactory.getRightBar(isSetUp); - mRightView.setStatusBarWindowTouchListener(mRightBarTouchListener); - mRightView.setNotificationsPanelController(mNotificationsShadeController); - addTemperatureViewToController(mRightView); + setupBar(mRightView, mRightBarTouchListener, mNotificationsShadeController); return mRightView; } + private void setupBar(CarNavigationBarView view, View.OnTouchListener statusBarTouchListener, + NotificationsShadeController notifShadeController) { + view.setStatusBarWindowTouchListener(statusBarTouchListener); + view.setNotificationsPanelController(notifShadeController); + mCarFacetButtonControllerLazy.get().addAllFacetButtons(view); + mHvacControllerLazy.get().addTemperatureViewToController(view); + } + /** Sets a touch listener for the top navigation bar. */ public void registerTopBarTouchListener(View.OnTouchListener listener) { mTopBarTouchListener = listener; @@ -290,17 +292,6 @@ public class CarNavigationBarController { void togglePanel(); } - private void addTemperatureViewToController(View v) { - if (v instanceof TemperatureView) { - mHvacControllerLazy.get().addHvacTextView((TemperatureView) v); - } else if (v instanceof ViewGroup) { - ViewGroup viewGroup = (ViewGroup) v; - for (int i = 0; i < viewGroup.getChildCount(); i++) { - addTemperatureViewToController(viewGroup.getChildAt(i)); - } - } - } - private void checkAllBars(boolean isSetUp) { mTopView = getTopBar(isSetUp); mBottomView = getBottomBar(isSetUp); diff --git a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/hvac/HvacController.java b/packages/CarSystemUI/src/com/android/systemui/navigationbar/car/hvac/HvacController.java index 41914d212ee9..af2cb0ab5950 100644 --- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/hvac/HvacController.java +++ b/packages/CarSystemUI/src/com/android/systemui/navigationbar/car/hvac/HvacController.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2018 The Android Open Source Project + * Copyright (C) 2019 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,20 +14,21 @@ * limitations under the License. */ -package com.android.systemui.statusbar.car.hvac; +package com.android.systemui.navigationbar.car.hvac; import static android.car.VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL; import static android.car.VehiclePropertyIds.HVAC_TEMPERATURE_DISPLAY_UNITS; import android.car.Car; -import android.car.Car.CarServiceLifecycleListener; import android.car.VehicleUnit; import android.car.hardware.CarPropertyValue; import android.car.hardware.hvac.CarHvacManager; import android.car.hardware.hvac.CarHvacManager.CarHvacEventCallback; -import android.content.Context; -import android.os.Handler; import android.util.Log; +import android.view.View; +import android.view.ViewGroup; + +import com.android.systemui.car.CarServiceProvider; import java.util.ArrayList; import java.util.HashMap; @@ -37,19 +38,18 @@ import java.util.Map; import java.util.Objects; import javax.inject.Inject; +import javax.inject.Singleton; /** * Manages the connection to the Car service and delegates value changes to the registered * {@link TemperatureView}s */ +@Singleton public class HvacController { - public static final String TAG = "HvacController"; - public static final int BIND_TO_HVAC_RETRY_DELAY = 5000; - private Context mContext; - private Handler mHandler; - private Car mCar; + private final CarServiceProvider mCarServiceProvider; + private CarHvacManager mHvacManager; private HashMap<HvacKey, List<TemperatureView>> mTempComponents = new HashMap<>(); @@ -85,22 +85,20 @@ public class HvacController { } }; - private final CarServiceLifecycleListener mCarServiceLifecycleListener = (car, ready) -> { - if (!ready) { - return; - } - try { - mHvacManager = (CarHvacManager) car.getCarManager(Car.HVAC_SERVICE); - mHvacManager.registerCallback(mHardwareCallback); - initComponents(); - } catch (Exception e) { - Log.e(TAG, "Failed to correctly connect to HVAC", e); - } - }; + private final CarServiceProvider.CarServiceOnConnectedListener mCarServiceLifecycleListener = + car -> { + try { + mHvacManager = (CarHvacManager) car.getCarManager(Car.HVAC_SERVICE); + mHvacManager.registerCallback(mHardwareCallback); + initComponents(); + } catch (Exception e) { + Log.e(TAG, "Failed to correctly connect to HVAC", e); + } + }; @Inject - public HvacController(Context context) { - mContext = context; + public HvacController(CarServiceProvider carServiceProvider) { + mCarServiceProvider = carServiceProvider; } /** @@ -108,9 +106,7 @@ public class HvacController { * ({@link CarHvacManager}) will happen on the same thread this method was called from. */ public void connectToCarService() { - mHandler = new Handler(); - mCar = Car.createCar(mContext, /* handler= */ mHandler, Car.CAR_WAIT_TIMEOUT_DO_NOT_WAIT, - mCarServiceLifecycleListener); + mCarServiceProvider.addListener(mCarServiceLifecycleListener); } /** @@ -172,6 +168,21 @@ public class HvacController { } /** + * Iterate through a view, looking for {@link TemperatureView} instances and add them to the + * controller if found. + */ + public void addTemperatureViewToController(View v) { + if (v instanceof TemperatureView) { + addHvacTextView((TemperatureView) v); + } else if (v instanceof ViewGroup) { + ViewGroup viewGroup = (ViewGroup) v; + for (int i = 0; i < viewGroup.getChildCount(); i++) { + addTemperatureViewToController(viewGroup.getChildAt(i)); + } + } + } + + /** * Key for storing {@link TemperatureView}s in a hash map */ private static class HvacKey { diff --git a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/hvac/TemperatureTextView.java b/packages/CarSystemUI/src/com/android/systemui/navigationbar/car/hvac/TemperatureTextView.java index 17ef3c0204af..ad4fcd9b67da 100644 --- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/hvac/TemperatureTextView.java +++ b/packages/CarSystemUI/src/com/android/systemui/navigationbar/car/hvac/TemperatureTextView.java @@ -1,5 +1,5 @@ /* - * Copyright 2018 The Android Open Source Project + * Copyright (C) 2019 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.systemui.statusbar.car.hvac; +package com.android.systemui.navigationbar.car.hvac; import android.content.Context; import android.content.res.TypedArray; diff --git a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/hvac/TemperatureView.java b/packages/CarSystemUI/src/com/android/systemui/navigationbar/car/hvac/TemperatureView.java index c17da1848a8f..963f3184c40d 100644 --- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/hvac/TemperatureView.java +++ b/packages/CarSystemUI/src/com/android/systemui/navigationbar/car/hvac/TemperatureView.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2018 The Android Open Source Project + * Copyright (C) 2019 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.systemui.statusbar.car.hvac; +package com.android.systemui.navigationbar.car.hvac; /** * Interface for Views that display temperature HVAC properties diff --git a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java index 78ac96020bae..10527b231169 100644 --- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java +++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java @@ -57,15 +57,14 @@ import com.android.internal.statusbar.RegisterStatusBarResult; import com.android.keyguard.KeyguardUpdateMonitor; import com.android.keyguard.ViewMediatorCallback; import com.android.systemui.BatteryMeterView; -import com.android.systemui.CarSystemUIFactory; import com.android.systemui.Dependency; import com.android.systemui.Prefs; import com.android.systemui.R; -import com.android.systemui.SystemUIFactory; import com.android.systemui.UiOffloadThread; import com.android.systemui.assist.AssistManager; import com.android.systemui.broadcast.BroadcastDispatcher; import com.android.systemui.bubbles.BubbleController; +import com.android.systemui.car.CarServiceProvider; import com.android.systemui.classifier.FalsingLog; import com.android.systemui.colorextraction.SysuiColorExtractor; import com.android.systemui.fragments.FragmentHostManager; @@ -73,9 +72,7 @@ import com.android.systemui.keyguard.DismissCallbackRegistry; import com.android.systemui.keyguard.KeyguardViewMediator; import com.android.systemui.keyguard.ScreenLifecycle; import com.android.systemui.keyguard.WakefulnessLifecycle; -import com.android.systemui.navigationbar.car.CarFacetButtonController; import com.android.systemui.navigationbar.car.CarNavigationBarController; -import com.android.systemui.navigationbar.car.CarNavigationBarView; import com.android.systemui.plugins.FalsingManager; import com.android.systemui.plugins.qs.QS; import com.android.systemui.qs.car.CarQSFragment; @@ -164,20 +161,20 @@ public class CarStatusBar extends StatusBar implements CarBatteryController.Batt private float mBackgroundAlphaDiff; private float mInitialBackgroundAlpha; + private final Lazy<FullscreenUserSwitcher> mFullscreenUserSwitcherLazy; private FullscreenUserSwitcher mFullscreenUserSwitcher; private CarBatteryController mCarBatteryController; private BatteryMeterView mBatteryMeterView; private Drawable mNotificationPanelBackground; - private ViewGroup mTopNavigationBarContainer; - private CarNavigationBarView mTopNavigationBarView; - private final Object mQueueLock = new Object(); private final CarNavigationBarController mCarNavigationBarController; - private CarFacetButtonController mCarFacetButtonController; + private final Lazy<DrivingStateHelper> mDrivingStateHelperLazy; + private final Lazy<PowerManagerHelper> mPowerManagerHelperLazy; + private final CarServiceProvider mCarServiceProvider; + private DeviceProvisionedController mDeviceProvisionedController; - private boolean mDeviceIsSetUpForUser = true; private DrivingStateHelper mDrivingStateHelper; private PowerManagerHelper mPowerManagerHelper; private FlingAnimationUtils mFlingAnimationUtils; @@ -311,6 +308,10 @@ public class CarStatusBar extends StatusBar implements CarBatteryController.Batt ViewMediatorCallback viewMediatorCallback, DismissCallbackRegistry dismissCallbackRegistry, /* Car Settings injected components. */ + CarServiceProvider carServiceProvider, + Lazy<DrivingStateHelper> drivingStateHelperLazy, + Lazy<PowerManagerHelper> powerManagerHelperLazy, + Lazy<FullscreenUserSwitcher> fullscreenUserSwitcherLazy, CarNavigationBarController carNavigationBarController) { super( context, @@ -384,16 +385,16 @@ public class CarStatusBar extends StatusBar implements CarBatteryController.Batt viewMediatorCallback, dismissCallbackRegistry); mScrimController = scrimController; + mDeviceProvisionedController = deviceProvisionedController; + mCarServiceProvider = carServiceProvider; + mDrivingStateHelperLazy = drivingStateHelperLazy; + mPowerManagerHelperLazy = powerManagerHelperLazy; + mFullscreenUserSwitcherLazy = fullscreenUserSwitcherLazy; mCarNavigationBarController = carNavigationBarController; } @Override public void start() { - // get the provisioned state before calling the parent class since it's that flow that - // builds the nav bar - mDeviceProvisionedController = Dependency.get(DeviceProvisionedController.class); - mDeviceIsSetUpForUser = mDeviceProvisionedController.isCurrentUserSetup(); - // Need to initialize screen lifecycle before calling super.start - before switcher is // created. mScreenLifecycle = Dependency.get(ScreenLifecycle.class); @@ -431,52 +432,20 @@ public class CarStatusBar extends StatusBar implements CarBatteryController.Batt createBatteryController(); mCarBatteryController.startListening(); - mDeviceProvisionedController.addCallback( - new DeviceProvisionedController.DeviceProvisionedListener() { - @Override - public void onUserSetupChanged() { - mHandler.post(() -> resetSystemBarsIfNecessary()); - } - - @Override - public void onUserSwitched() { - mHandler.post(() -> resetSystemBarsIfNecessary()); - } - }); - // Used by onDrivingStateChanged and it can be called inside // DrivingStateHelper.connectToCarService() mSwitchToGuestTimer = new SwitchToGuestTimer(mContext); // Register a listener for driving state changes. - mDrivingStateHelper = new DrivingStateHelper(mContext, this::onDrivingStateChanged); + mDrivingStateHelper = mDrivingStateHelperLazy.get(); + mDrivingStateHelper.setCarDrivingStateEventListener(this::onDrivingStateChanged); mDrivingStateHelper.connectToCarService(); - mPowerManagerHelper = new PowerManagerHelper(mContext, mCarPowerStateListener); + mPowerManagerHelper = mPowerManagerHelperLazy.get(); + mPowerManagerHelper.setCarPowerStateListener(mCarPowerStateListener); mPowerManagerHelper.connectToCarService(); } - private void resetSystemBarsIfNecessary() { - boolean currentUserSetup = mDeviceProvisionedController.isCurrentUserSetup(); - if (mDeviceIsSetUpForUser != currentUserSetup) { - mDeviceIsSetUpForUser = currentUserSetup; - resetSystemBars(); - } - } - - /** - * Remove all content from navbars and rebuild them. Used to allow for different nav bars - * before and after the device is provisioned. . Also for change of density and font size. - */ - private void resetSystemBars() { - mCarFacetButtonController.removeAll(); - - buildNavBarContent(); - // CarFacetButtonController was reset therefore we need to re-add the status bar elements - // to the controller. - mCarFacetButtonController.addAllFacetButtons(mStatusBarWindow); - } - /** * Allows for showing or hiding just the navigation bars. This is indented to be used when * the full screen user selector is shown. @@ -490,23 +459,22 @@ public class CarStatusBar extends StatusBar implements CarBatteryController.Batt @Override public boolean hideKeyguard() { boolean result = super.hideKeyguard(); - mCarNavigationBarController.hideAllKeyguardButtons(mDeviceIsSetUpForUser); + mCarNavigationBarController.hideAllKeyguardButtons( + mDeviceProvisionedController.isCurrentUserSetup()); return result; } @Override public void showKeyguard() { super.showKeyguard(); - mCarNavigationBarController.showAllKeyguardButtons(mDeviceIsSetUpForUser); + mCarNavigationBarController.showAllKeyguardButtons( + mDeviceProvisionedController.isCurrentUserSetup()); } @Override protected void makeStatusBarView(@Nullable RegisterStatusBarResult result) { super.makeStatusBarView(result); - CarSystemUIFactory factory = SystemUIFactory.getInstance(); - mCarFacetButtonController = factory.getCarDependencyComponent() - .getCarFacetButtonController(); mNotificationPanelBackground = getDefaultWallpaper(); mScrimController.setScrimBehindDrawable(mNotificationPanelBackground); @@ -562,7 +530,7 @@ public class CarStatusBar extends StatusBar implements CarBatteryController.Batt new HandleBarCloseNotificationGestureListener()); mTopNavBarNotificationTouchListener = (v, event) -> { - if (!mDeviceIsSetUpForUser) { + if (!mDeviceProvisionedController.isCurrentUserSetup()) { return true; } boolean consumed = openGestureDetector.onTouchEvent(event); @@ -592,20 +560,13 @@ public class CarStatusBar extends StatusBar implements CarBatteryController.Batt }); CarNotificationListener carNotificationListener = new CarNotificationListener(); mCarUxRestrictionManagerWrapper = new CarUxRestrictionManagerWrapper(); - // This can take time if car service is not ready up to this time. - // TODO(b/142808072) Refactor CarUxRestrictionManagerWrapper to allow setting - // CarUxRestrictionsManager later and switch to Car.CAR_WAIT_TIMEOUT_DO_NOT_WAIT. - Car.createCar(mContext, /* handler= */ null, Car.CAR_WAIT_TIMEOUT_WAIT_FOREVER, - (car, ready) -> { - if (!ready) { - return; - } - CarUxRestrictionsManager carUxRestrictionsManager = - (CarUxRestrictionsManager) - car.getCarManager(Car.CAR_UX_RESTRICTION_SERVICE); - mCarUxRestrictionManagerWrapper.setCarUxRestrictionsManager( - carUxRestrictionsManager); - }); + mCarServiceProvider.addListener(car -> { + CarUxRestrictionsManager carUxRestrictionsManager = + (CarUxRestrictionsManager) + car.getCarManager(Car.CAR_UX_RESTRICTION_SERVICE); + mCarUxRestrictionManagerWrapper.setCarUxRestrictionsManager( + carUxRestrictionsManager); + }); mNotificationDataManager = new NotificationDataManager(); mNotificationDataManager.setOnUnseenCountUpdateListener( @@ -614,7 +575,7 @@ public class CarStatusBar extends StatusBar implements CarBatteryController.Batt boolean hasUnseen = mNotificationDataManager.getUnseenNotificationCount() > 0; mCarNavigationBarController.toggleAllNotificationsUnseenIndicator( - mDeviceIsSetUpForUser, hasUnseen); + mDeviceProvisionedController.isCurrentUserSetup(), hasUnseen); } }); @@ -868,14 +829,14 @@ public class CarStatusBar extends StatusBar implements CarBatteryController.Batt @Override protected void createNavigationBar(@Nullable RegisterStatusBarResult result) { - mTopNavigationBarContainer = mStatusBarWindow - .findViewById(R.id.car_top_navigation_bar_container); - - buildNavBarContent(); + registerNavBarListeners(); } - private void buildNavBarContent() { - buildTopBar(); + private void registerNavBarListeners() { + // In CarStatusBar, navigation bars are built by NavigationBar.java + // Instead, we register necessary callbacks to the navigation bar controller. + mCarNavigationBarController.registerTopBarTouchListener( + mTopNavBarNotificationTouchListener); mCarNavigationBarController.registerBottomBarTouchListener( mNavBarNotificationTouchListener); @@ -889,14 +850,6 @@ public class CarStatusBar extends StatusBar implements CarBatteryController.Batt mCarNavigationBarController.registerNotificationController(() -> togglePanel()); } - private void buildTopBar() { - mTopNavigationBarContainer.removeAllViews(); - mTopNavigationBarView = mCarNavigationBarController.getTopBar(mDeviceIsSetUpForUser); - mCarNavigationBarController.registerTopBarTouchListener( - mTopNavBarNotificationTouchListener); - mTopNavigationBarContainer.addView(mTopNavigationBarView); - } - @Override public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { //When executing dump() function simultaneously, we need to serialize them @@ -908,8 +861,6 @@ public class CarStatusBar extends StatusBar implements CarBatteryController.Batt + "," + mStackScroller.getScrollY()); } - pw.print(" mCarFacetButtonController="); - pw.println(mCarFacetButtonController); pw.print(" mFullscreenUserSwitcher="); pw.println(mFullscreenUserSwitcher); pw.print(" mCarBatteryController="); @@ -974,8 +925,10 @@ public class CarStatusBar extends StatusBar implements CarBatteryController.Batt UserSwitcherController userSwitcherController = Dependency.get(UserSwitcherController.class); if (userSwitcherController.useFullscreenUserSwitcher()) { - mFullscreenUserSwitcher = new FullscreenUserSwitcher(this, - mStatusBarWindow.findViewById(R.id.fullscreen_user_switcher_stub), mContext); + mFullscreenUserSwitcher = mFullscreenUserSwitcherLazy.get(); + mFullscreenUserSwitcher.setStatusBar(this); + mFullscreenUserSwitcher.setContainer( + mStatusBarWindow.findViewById(R.id.fullscreen_user_switcher_stub)); } else { super.createUserSwitcher(); } @@ -1058,7 +1011,7 @@ public class CarStatusBar extends StatusBar implements CarBatteryController.Batt @Override public void onDensityOrFontScaleChanged() { super.onDensityOrFontScaleChanged(); - resetSystemBars(); + registerNavBarListeners(); // Need to update the background on density changed in case the change was due to night // mode. mNotificationPanelBackground = getDefaultWallpaper(); diff --git a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBarModule.java b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBarModule.java index b9dacc0ded3e..5418ebe5b8de 100644 --- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBarModule.java +++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBarModule.java @@ -29,6 +29,7 @@ import com.android.systemui.UiOffloadThread; import com.android.systemui.assist.AssistManager; import com.android.systemui.broadcast.BroadcastDispatcher; import com.android.systemui.bubbles.BubbleController; +import com.android.systemui.car.CarServiceProvider; import com.android.systemui.colorextraction.SysuiColorExtractor; import com.android.systemui.keyguard.DismissCallbackRegistry; import com.android.systemui.keyguard.KeyguardViewMediator; @@ -179,6 +180,10 @@ public class CarStatusBarModule { StatusBarKeyguardViewManager statusBarKeyguardViewManager, ViewMediatorCallback viewMediatorCallback, DismissCallbackRegistry dismissCallbackRegistry, + CarServiceProvider carServiceProvider, + Lazy<DrivingStateHelper> drivingStateHelperLazy, + Lazy<PowerManagerHelper> powerManagerHelperLazy, + Lazy<FullscreenUserSwitcher> fullscreenUserSwitcherLazy, CarNavigationBarController carNavigationBarController) { return new CarStatusBar( context, @@ -250,6 +255,10 @@ public class CarStatusBarModule { statusBarKeyguardViewManager, viewMediatorCallback, dismissCallbackRegistry, + carServiceProvider, + drivingStateHelperLazy, + powerManagerHelperLazy, + fullscreenUserSwitcherLazy, carNavigationBarController); } } diff --git a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarTrustAgentUnlockDialogHelper.java b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarTrustAgentUnlockDialogHelper.java index ec72ee74f59a..ec4643302a05 100644 --- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarTrustAgentUnlockDialogHelper.java +++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarTrustAgentUnlockDialogHelper.java @@ -22,6 +22,7 @@ import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; +import android.content.res.Resources; import android.graphics.PixelFormat; import android.os.Handler; import android.os.UserHandle; @@ -36,15 +37,21 @@ import android.widget.TextView; import com.android.internal.widget.LockPatternUtils; import com.android.systemui.R; +import com.android.systemui.dagger.qualifiers.MainResources; + +import javax.inject.Inject; +import javax.inject.Singleton; /** * A helper class displays an unlock dialog and receives broadcast about detecting trusted device * & unlocking state to show the appropriate message on the dialog. */ +@Singleton class CarTrustAgentUnlockDialogHelper extends BroadcastReceiver{ private static final String TAG = CarTrustAgentUnlockDialogHelper.class.getSimpleName(); private final Context mContext; + private final Resources mResources; private final WindowManager mWindowManager; private final UserManager mUserManager; private final WindowManager.LayoutParams mParams; @@ -60,10 +67,13 @@ class CarTrustAgentUnlockDialogHelper extends BroadcastReceiver{ private boolean mIsDialogShowing; private OnHideListener mOnHideListener; - CarTrustAgentUnlockDialogHelper(Context context) { + @Inject + CarTrustAgentUnlockDialogHelper(Context context, @MainResources Resources resources, + UserManager userManager, WindowManager windowManager) { mContext = context; - mUserManager = mContext.getSystemService(UserManager.class); - mWindowManager = mContext.getSystemService(WindowManager.class); + mResources = resources; + mUserManager = userManager; + mWindowManager = windowManager; mParams = createLayoutParams(); mFilter = getIntentFilter(); @@ -125,7 +135,7 @@ class CarTrustAgentUnlockDialogHelper extends BroadcastReceiver{ * @param listener listener that listens to dialog hide */ void showUnlockDialogAfterDelay(int uid, OnHideListener listener) { - long delayMillis = mContext.getResources().getInteger(R.integer.unlock_dialog_delay_ms); + long delayMillis = mResources.getInteger(R.integer.unlock_dialog_delay_ms); showUnlockDialogAfterDelay(uid, delayMillis, listener); } diff --git a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/DrivingStateHelper.java b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/DrivingStateHelper.java index cd87e78e4be9..60934ab11532 100644 --- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/DrivingStateHelper.java +++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/DrivingStateHelper.java @@ -17,31 +17,43 @@ package com.android.systemui.statusbar.car; import android.car.Car; -import android.car.Car.CarServiceLifecycleListener; import android.car.drivingstate.CarDrivingStateEvent; import android.car.drivingstate.CarDrivingStateManager; import android.car.drivingstate.CarDrivingStateManager.CarDrivingStateEventListener; -import android.content.Context; import android.util.Log; import androidx.annotation.NonNull; +import com.android.systemui.car.CarServiceProvider; + +import javax.inject.Inject; +import javax.inject.Singleton; + /** * Helper class for connecting to the {@link CarDrivingStateManager} and listening for driving state * changes. */ +@Singleton public class DrivingStateHelper { public static final String TAG = "DrivingStateHelper"; - private final Context mContext; + private final CarServiceProvider mCarServiceProvider; + private CarDrivingStateManager mDrivingStateManager; - private Car mCar; private CarDrivingStateEventListener mDrivingStateHandler; - public DrivingStateHelper(Context context, - @NonNull CarDrivingStateEventListener drivingStateHandler) { - mContext = context; - mDrivingStateHandler = drivingStateHandler; + @Inject + public DrivingStateHelper(CarServiceProvider carServiceProvider) { + mCarServiceProvider = carServiceProvider; + } + + /** + * Sets the {@link CarDrivingStateEventListener}. Should be set before calling {@link + * #connectToCarService()}. + */ + public void setCarDrivingStateEventListener( + @NonNull CarDrivingStateEventListener carDrivingStateEventListener) { + mDrivingStateHandler = carDrivingStateEventListener; } /** @@ -64,25 +76,22 @@ public class DrivingStateHelper { * Establishes connection with the Car service. */ public void connectToCarService() { - mCar = Car.createCar(mContext, /* handler= */ null, Car.CAR_WAIT_TIMEOUT_DO_NOT_WAIT, - mCarServiceLifecycleListener); + mCarServiceProvider.addListener(mCarServiceLifecycleListener); } - private final CarServiceLifecycleListener mCarServiceLifecycleListener = (car, ready) -> { - if (!ready) { - return; - } - logD("Car Service connected"); - mDrivingStateManager = (CarDrivingStateManager) car.getCarManager( - Car.CAR_DRIVING_STATE_SERVICE); - if (mDrivingStateManager != null) { - mDrivingStateManager.registerListener(mDrivingStateHandler); - mDrivingStateHandler.onDrivingStateChanged( - mDrivingStateManager.getCurrentCarDrivingState()); - } else { - Log.e(TAG, "CarDrivingStateService service not available"); - } - }; + private final CarServiceProvider.CarServiceOnConnectedListener mCarServiceLifecycleListener = + car -> { + logD("Car Service connected"); + mDrivingStateManager = (CarDrivingStateManager) car.getCarManager( + Car.CAR_DRIVING_STATE_SERVICE); + if (mDrivingStateManager != null) { + mDrivingStateManager.registerListener(mDrivingStateHandler); + mDrivingStateHandler.onDrivingStateChanged( + mDrivingStateManager.getCurrentCarDrivingState()); + } else { + Log.e(TAG, "CarDrivingStateService service not available"); + } + }; private void logD(String message) { if (Log.isLoggable(TAG, Log.DEBUG)) { diff --git a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/FullscreenUserSwitcher.java b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/FullscreenUserSwitcher.java index 31aced02b15e..b188dc3949f2 100644 --- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/FullscreenUserSwitcher.java +++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/FullscreenUserSwitcher.java @@ -26,6 +26,7 @@ import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.pm.UserInfo; +import android.content.res.Resources; import android.os.UserHandle; import android.os.UserManager; import android.util.Log; @@ -35,24 +36,34 @@ import android.view.ViewStub; import androidx.recyclerview.widget.GridLayoutManager; import com.android.systemui.R; +import com.android.systemui.car.CarServiceProvider; +import com.android.systemui.dagger.qualifiers.MainResources; import com.android.systemui.statusbar.car.CarTrustAgentUnlockDialogHelper.OnHideListener; import com.android.systemui.statusbar.car.UserGridRecyclerView.UserRecord; +import javax.inject.Inject; +import javax.inject.Singleton; + /** * Manages the fullscreen user switcher. */ +@Singleton public class FullscreenUserSwitcher { private static final String TAG = FullscreenUserSwitcher.class.getSimpleName(); // Because user 0 is headless, user count for single user is 2 private static final int NUMBER_OF_BACKGROUND_USERS = 1; - private final UserGridRecyclerView mUserGridView; - private final View mParent; - private final int mShortAnimDuration; - private final CarStatusBar mStatusBar; + private final Context mContext; + private final Resources mResources; private final UserManager mUserManager; + private final CarServiceProvider mCarServiceProvider; + private final CarTrustAgentUnlockDialogHelper mUnlockDialogHelper; + private final int mShortAnimDuration; + + private CarStatusBar mStatusBar; + private View mParent; + private UserGridRecyclerView mUserGridView; private CarTrustAgentEnrollmentManager mEnrollmentManager; - private CarTrustAgentUnlockDialogHelper mUnlockDialogHelper; private UserGridRecyclerView.UserRecord mSelectedUser; private CarUserManagerHelper mCarUserManagerHelper; private final BroadcastReceiver mUserUnlockReceiver = new BroadcastReceiver() { @@ -65,37 +76,46 @@ public class FullscreenUserSwitcher { mContext.unregisterReceiver(mUserUnlockReceiver); } }; - private final Car mCar; - public FullscreenUserSwitcher(CarStatusBar statusBar, ViewStub containerStub, Context context) { + @Inject + public FullscreenUserSwitcher( + Context context, + @MainResources Resources resources, + UserManager userManager, + CarServiceProvider carServiceProvider, + CarTrustAgentUnlockDialogHelper carTrustAgentUnlockDialogHelper) { + mContext = context; + mResources = resources; + mUserManager = userManager; + mCarServiceProvider = carServiceProvider; + mUnlockDialogHelper = carTrustAgentUnlockDialogHelper; + + mShortAnimDuration = mResources.getInteger(android.R.integer.config_shortAnimTime); + } + + /** Sets the status bar which controls the keyguard. */ + public void setStatusBar(CarStatusBar statusBar) { mStatusBar = statusBar; + } + + /** Sets the {@link ViewStub} to show the user switcher. */ + public void setContainer(ViewStub containerStub) { mParent = containerStub.inflate(); - mContext = context; View container = mParent.findViewById(R.id.container); // Initialize user grid. mUserGridView = container.findViewById(R.id.user_grid); - GridLayoutManager layoutManager = new GridLayoutManager(context, - context.getResources().getInteger(R.integer.user_fullscreen_switcher_num_col)); + GridLayoutManager layoutManager = new GridLayoutManager(mContext, + mResources.getInteger(R.integer.user_fullscreen_switcher_num_col)); mUserGridView.setLayoutManager(layoutManager); mUserGridView.buildAdapter(); mUserGridView.setUserSelectionListener(this::onUserSelected); - mCarUserManagerHelper = new CarUserManagerHelper(context); - mUnlockDialogHelper = new CarTrustAgentUnlockDialogHelper(mContext); - mUserManager = mContext.getSystemService(UserManager.class); - - mCar = Car.createCar(mContext, /* handler= */ null, Car.CAR_WAIT_TIMEOUT_DO_NOT_WAIT, - (car, ready) -> { - if (!ready) { - return; - } - mEnrollmentManager = (CarTrustAgentEnrollmentManager) car - .getCarManager(Car.CAR_TRUST_AGENT_ENROLLMENT_SERVICE); - }); + mCarUserManagerHelper = new CarUserManagerHelper(mContext); + mCarServiceProvider.addListener( + car -> mEnrollmentManager = (CarTrustAgentEnrollmentManager) car.getCarManager( + Car.CAR_TRUST_AGENT_ENROLLMENT_SERVICE)); - mShortAnimDuration = container.getResources() - .getInteger(android.R.integer.config_shortAnimTime); IntentFilter filter = new IntentFilter(Intent.ACTION_USER_UNLOCKED); if (mUserManager.isUserUnlocked(UserHandle.USER_SYSTEM)) { // User0 is unlocked, switched to the initial user diff --git a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/PowerManagerHelper.java b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/PowerManagerHelper.java index a27dd341d449..71847bbac9fd 100644 --- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/PowerManagerHelper.java +++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/PowerManagerHelper.java @@ -18,33 +18,33 @@ package com.android.systemui.statusbar.car; import android.annotation.NonNull; import android.car.Car; -import android.car.Car.CarServiceLifecycleListener; import android.car.hardware.power.CarPowerManager; import android.car.hardware.power.CarPowerManager.CarPowerStateListener; -import android.content.Context; import android.util.Log; +import com.android.systemui.car.CarServiceProvider; + +import javax.inject.Inject; +import javax.inject.Singleton; + /** * Helper class for connecting to the {@link CarPowerManager} and listening for power state changes. */ +@Singleton public class PowerManagerHelper { public static final String TAG = "PowerManagerHelper"; - private final Context mContext; - private final CarPowerStateListener mCarPowerStateListener; + private final CarServiceProvider mCarServiceProvider; - private Car mCar; private CarPowerManager mCarPowerManager; + private CarPowerStateListener mCarPowerStateListener; - private final CarServiceLifecycleListener mCarServiceLifecycleListener; + private final CarServiceProvider.CarServiceOnConnectedListener mCarServiceLifecycleListener; - PowerManagerHelper(Context context, @NonNull CarPowerStateListener listener) { - mContext = context; - mCarPowerStateListener = listener; - mCarServiceLifecycleListener = (car, ready) -> { - if (!ready) { - return; - } + @Inject + PowerManagerHelper(CarServiceProvider carServiceProvider) { + mCarServiceProvider = carServiceProvider; + mCarServiceLifecycleListener = car -> { Log.d(TAG, "Car Service connected"); mCarPowerManager = (CarPowerManager) car.getCarManager(Car.POWER_SERVICE); if (mCarPowerManager != null) { @@ -56,10 +56,16 @@ public class PowerManagerHelper { } /** + * Sets a {@link CarPowerStateListener}. Should be set before {@link #connectToCarService()}. + */ + void setCarPowerStateListener(@NonNull CarPowerStateListener listener) { + mCarPowerStateListener = listener; + } + + /** * Connect to Car service. */ void connectToCarService() { - mCar = Car.createCar(mContext, /* handler= */ null, Car.CAR_WAIT_TIMEOUT_DO_NOT_WAIT, - mCarServiceLifecycleListener); + mCarServiceProvider.addListener(mCarServiceLifecycleListener); } } diff --git a/packages/CarSystemUI/src/com/android/systemui/statusbar/hvac/AnimatedTemperatureView.java b/packages/CarSystemUI/src/com/android/systemui/statusbar/hvac/AnimatedTemperatureView.java index 76126fcd949c..908aaad71893 100644 --- a/packages/CarSystemUI/src/com/android/systemui/statusbar/hvac/AnimatedTemperatureView.java +++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/hvac/AnimatedTemperatureView.java @@ -35,7 +35,7 @@ import android.widget.TextSwitcher; import android.widget.TextView; import com.android.systemui.R; -import com.android.systemui.statusbar.car.hvac.TemperatureView; +import com.android.systemui.navigationbar.car.hvac.TemperatureView; /** * Simple text display of HVAC properties, It is designed to show mTemperature and is configured in diff --git a/packages/CarSystemUI/src/com/android/systemui/volume/CarVolumeDialogComponent.java b/packages/CarSystemUI/src/com/android/systemui/volume/CarVolumeDialogComponent.java index 9d39684bf796..5a3443674cf4 100644 --- a/packages/CarSystemUI/src/com/android/systemui/volume/CarVolumeDialogComponent.java +++ b/packages/CarSystemUI/src/com/android/systemui/volume/CarVolumeDialogComponent.java @@ -18,6 +18,7 @@ package com.android.systemui.volume; import android.content.Context; +import com.android.systemui.car.CarServiceProvider; import com.android.systemui.keyguard.KeyguardViewMediator; import com.android.systemui.plugins.VolumeDialog; @@ -30,13 +31,20 @@ import javax.inject.Singleton; @Singleton public class CarVolumeDialogComponent extends VolumeDialogComponent { + private CarVolumeDialogImpl mCarVolumeDialog; + @Inject public CarVolumeDialogComponent(Context context, KeyguardViewMediator keyguardViewMediator, - VolumeDialogControllerImpl volumeDialogController) { + VolumeDialogControllerImpl volumeDialogController, + CarServiceProvider carServiceProvider) { super(context, keyguardViewMediator, volumeDialogController); + mCarVolumeDialog.setCarServiceProvider(carServiceProvider); } + /** This method is called while calling the super constructor. */ + @Override protected VolumeDialog createDefault() { - return new CarVolumeDialogImpl(mContext); + mCarVolumeDialog = new CarVolumeDialogImpl(mContext); + return mCarVolumeDialog; } } diff --git a/packages/CarSystemUI/src/com/android/systemui/volume/CarVolumeDialogImpl.java b/packages/CarSystemUI/src/com/android/systemui/volume/CarVolumeDialogImpl.java index 09223e8ff4c3..367959ec4972 100644 --- a/packages/CarSystemUI/src/com/android/systemui/volume/CarVolumeDialogImpl.java +++ b/packages/CarSystemUI/src/com/android/systemui/volume/CarVolumeDialogImpl.java @@ -24,7 +24,6 @@ import android.annotation.Nullable; import android.app.Dialog; import android.app.KeyguardManager; import android.car.Car; -import android.car.Car.CarServiceLifecycleListener; import android.car.media.CarAudioManager; import android.content.Context; import android.content.DialogInterface; @@ -56,6 +55,7 @@ import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; import com.android.systemui.R; +import com.android.systemui.car.CarServiceProvider; import com.android.systemui.plugins.VolumeDialog; import org.xmlpull.v1.XmlPullParserException; @@ -95,7 +95,6 @@ public class CarVolumeDialogImpl implements VolumeDialog { private CustomDialog mDialog; private RecyclerView mListView; private CarVolumeItemAdapter mVolumeItemsAdapter; - private Car mCar; private CarAudioManager mCarAudioManager; private boolean mHovering; private int mCurrentlyDisplayingGroupId; @@ -147,30 +146,28 @@ public class CarVolumeDialogImpl implements VolumeDialog { } }; - private final CarServiceLifecycleListener mCarServiceLifecycleListener = (car, ready) -> { - if (!ready) { - return; - } - mExpanded = false; - mCarAudioManager = (CarAudioManager) car.getCarManager(Car.AUDIO_SERVICE); - int volumeGroupCount = mCarAudioManager.getVolumeGroupCount(); - // Populates volume slider items from volume groups to UI. - for (int groupId = 0; groupId < volumeGroupCount; groupId++) { - VolumeItem volumeItem = getVolumeItemForUsages( - mCarAudioManager.getUsagesForVolumeGroupId(groupId)); - mAvailableVolumeItems.add(volumeItem); - // The first one is the default item. - if (groupId == 0) { - clearAllAndSetupDefaultCarVolumeLineItem(0); - } - } + private final CarServiceProvider.CarServiceOnConnectedListener mCarServiceOnConnectedListener = + car -> { + mExpanded = false; + mCarAudioManager = (CarAudioManager) car.getCarManager(Car.AUDIO_SERVICE); + int volumeGroupCount = mCarAudioManager.getVolumeGroupCount(); + // Populates volume slider items from volume groups to UI. + for (int groupId = 0; groupId < volumeGroupCount; groupId++) { + VolumeItem volumeItem = getVolumeItemForUsages( + mCarAudioManager.getUsagesForVolumeGroupId(groupId)); + mAvailableVolumeItems.add(volumeItem); + // The first one is the default item. + if (groupId == 0) { + clearAllAndSetupDefaultCarVolumeLineItem(0); + } + } - // If list is already initiated, update its content. - if (mVolumeItemsAdapter != null) { - mVolumeItemsAdapter.notifyDataSetChanged(); - } - mCarAudioManager.registerCarVolumeCallback(mVolumeChangeCallback); - }; + // If list is already initiated, update its content. + if (mVolumeItemsAdapter != null) { + mVolumeItemsAdapter.notifyDataSetChanged(); + } + mCarAudioManager.registerCarVolumeCallback(mVolumeChangeCallback); + }; public CarVolumeDialogImpl(Context context) { mContext = context; @@ -181,6 +178,11 @@ public class CarVolumeDialogImpl implements VolumeDialog { R.integer.car_volume_dialog_display_hovering_timeout); } + /** Sets a {@link CarServiceProvider} which connects to the audio service. */ + public void setCarServiceProvider(CarServiceProvider carServiceProvider) { + carServiceProvider.addListener(mCarServiceOnConnectedListener); + } + private static int getSeekbarValue(CarAudioManager carAudioManager, int volumeGroupId) { return carAudioManager.getGroupVolume(volumeGroupId); } @@ -196,8 +198,6 @@ public class CarVolumeDialogImpl implements VolumeDialog { @Override public void init(int windowType, Callback callback) { initDialog(); - mCar = Car.createCar(mContext, /* handler= */ null, Car.CAR_WAIT_TIMEOUT_DO_NOT_WAIT, - mCarServiceLifecycleListener); } @Override @@ -205,12 +205,6 @@ public class CarVolumeDialogImpl implements VolumeDialog { mHandler.removeCallbacksAndMessages(/* token= */ null); cleanupAudioManager(); - // unregisterVolumeCallback is not being called when disconnect car, so we manually cleanup - // audio manager beforehand. - if (mCar != null) { - mCar.disconnect(); - mCar = null; - } } private void initDialog() { diff --git a/packages/CarSystemUI/tests/src/com/android/systemui/navigationbar/car/CarNavigationBarControllerTest.java b/packages/CarSystemUI/tests/src/com/android/systemui/navigationbar/car/CarNavigationBarControllerTest.java index 901d2006eb12..642b1145cb94 100644 --- a/packages/CarSystemUI/tests/src/com/android/systemui/navigationbar/car/CarNavigationBarControllerTest.java +++ b/packages/CarSystemUI/tests/src/com/android/systemui/navigationbar/car/CarNavigationBarControllerTest.java @@ -31,8 +31,8 @@ import androidx.test.filters.SmallTest; import com.android.systemui.R; import com.android.systemui.SysuiTestCase; +import com.android.systemui.navigationbar.car.hvac.HvacController; import com.android.systemui.plugins.DarkIconDispatcher; -import com.android.systemui.statusbar.car.hvac.HvacController; import com.android.systemui.statusbar.phone.StatusBarIconController; import org.junit.Before; @@ -41,8 +41,6 @@ import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; -import dagger.Lazy; - @RunWith(AndroidTestingRunner.class) @TestableLooper.RunWithLooper @SmallTest @@ -50,17 +48,17 @@ public class CarNavigationBarControllerTest extends SysuiTestCase { private CarNavigationBarController mCarNavigationBar; private NavigationBarViewFactory mNavigationBarViewFactory; - private Lazy<HvacController> mHvacControllerLazy; private TestableResources mTestableResources; @Mock + private CarFacetButtonController mCarFacetButtonController; + @Mock private HvacController mHvacController; @Before public void setUp() throws Exception { MockitoAnnotations.initMocks(this); mNavigationBarViewFactory = new NavigationBarViewFactory(mContext); - mHvacControllerLazy = () -> mHvacController; mTestableResources = mContext.getOrCreateTestableResources(); // Needed to inflate top navigation bar. @@ -71,7 +69,7 @@ public class CarNavigationBarControllerTest extends SysuiTestCase { @Test public void testConnectToHvac_callsConnect() { mCarNavigationBar = new CarNavigationBarController(mContext, mNavigationBarViewFactory, - mHvacControllerLazy); + () -> mCarFacetButtonController, () -> mHvacController); mCarNavigationBar.connectToHvac(); @@ -81,7 +79,7 @@ public class CarNavigationBarControllerTest extends SysuiTestCase { @Test public void testRemoveAllFromHvac_callsRemoveAll() { mCarNavigationBar = new CarNavigationBarController(mContext, mNavigationBarViewFactory, - mHvacControllerLazy); + () -> mCarFacetButtonController, () -> mHvacController); mCarNavigationBar.removeAllFromHvac(); @@ -92,7 +90,7 @@ public class CarNavigationBarControllerTest extends SysuiTestCase { public void testGetBottomWindow_bottomDisabled_returnsNull() { mTestableResources.addOverride(R.bool.config_enableBottomNavigationBar, false); mCarNavigationBar = new CarNavigationBarController(mContext, mNavigationBarViewFactory, - mHvacControllerLazy); + () -> mCarFacetButtonController, () -> mHvacController); ViewGroup window = mCarNavigationBar.getBottomWindow(); @@ -103,7 +101,7 @@ public class CarNavigationBarControllerTest extends SysuiTestCase { public void testGetBottomWindow_bottomEnabled_returnsWindow() { mTestableResources.addOverride(R.bool.config_enableBottomNavigationBar, true); mCarNavigationBar = new CarNavigationBarController(mContext, mNavigationBarViewFactory, - mHvacControllerLazy); + () -> mCarFacetButtonController, () -> mHvacController); ViewGroup window = mCarNavigationBar.getBottomWindow(); @@ -114,7 +112,7 @@ public class CarNavigationBarControllerTest extends SysuiTestCase { public void testGetBottomWindow_bottomEnabled_calledTwice_returnsSameWindow() { mTestableResources.addOverride(R.bool.config_enableBottomNavigationBar, true); mCarNavigationBar = new CarNavigationBarController(mContext, mNavigationBarViewFactory, - mHvacControllerLazy); + () -> mCarFacetButtonController, () -> mHvacController); ViewGroup window1 = mCarNavigationBar.getBottomWindow(); ViewGroup window2 = mCarNavigationBar.getBottomWindow(); @@ -126,7 +124,7 @@ public class CarNavigationBarControllerTest extends SysuiTestCase { public void testGetLeftWindow_leftDisabled_returnsNull() { mTestableResources.addOverride(R.bool.config_enableLeftNavigationBar, false); mCarNavigationBar = new CarNavigationBarController(mContext, mNavigationBarViewFactory, - mHvacControllerLazy); + () -> mCarFacetButtonController, () -> mHvacController); ViewGroup window = mCarNavigationBar.getLeftWindow(); assertThat(window).isNull(); } @@ -135,7 +133,7 @@ public class CarNavigationBarControllerTest extends SysuiTestCase { public void testGetLeftWindow_leftEnabled_returnsWindow() { mTestableResources.addOverride(R.bool.config_enableLeftNavigationBar, true); mCarNavigationBar = new CarNavigationBarController(mContext, mNavigationBarViewFactory, - mHvacControllerLazy); + () -> mCarFacetButtonController, () -> mHvacController); ViewGroup window = mCarNavigationBar.getLeftWindow(); @@ -146,7 +144,7 @@ public class CarNavigationBarControllerTest extends SysuiTestCase { public void testGetLeftWindow_leftEnabled_calledTwice_returnsSameWindow() { mTestableResources.addOverride(R.bool.config_enableLeftNavigationBar, true); mCarNavigationBar = new CarNavigationBarController(mContext, mNavigationBarViewFactory, - mHvacControllerLazy); + () -> mCarFacetButtonController, () -> mHvacController); ViewGroup window1 = mCarNavigationBar.getLeftWindow(); ViewGroup window2 = mCarNavigationBar.getLeftWindow(); @@ -158,7 +156,7 @@ public class CarNavigationBarControllerTest extends SysuiTestCase { public void testGetRightWindow_rightDisabled_returnsNull() { mTestableResources.addOverride(R.bool.config_enableRightNavigationBar, false); mCarNavigationBar = new CarNavigationBarController(mContext, mNavigationBarViewFactory, - mHvacControllerLazy); + () -> mCarFacetButtonController, () -> mHvacController); ViewGroup window = mCarNavigationBar.getRightWindow(); @@ -169,7 +167,7 @@ public class CarNavigationBarControllerTest extends SysuiTestCase { public void testGetRightWindow_rightEnabled_returnsWindow() { mTestableResources.addOverride(R.bool.config_enableRightNavigationBar, true); mCarNavigationBar = new CarNavigationBarController(mContext, mNavigationBarViewFactory, - mHvacControllerLazy); + () -> mCarFacetButtonController, () -> mHvacController); ViewGroup window = mCarNavigationBar.getRightWindow(); @@ -180,7 +178,7 @@ public class CarNavigationBarControllerTest extends SysuiTestCase { public void testGetRightWindow_rightEnabled_calledTwice_returnsSameWindow() { mTestableResources.addOverride(R.bool.config_enableRightNavigationBar, true); mCarNavigationBar = new CarNavigationBarController(mContext, mNavigationBarViewFactory, - mHvacControllerLazy); + () -> mCarFacetButtonController, () -> mHvacController); ViewGroup window1 = mCarNavigationBar.getRightWindow(); ViewGroup window2 = mCarNavigationBar.getRightWindow(); @@ -192,7 +190,7 @@ public class CarNavigationBarControllerTest extends SysuiTestCase { public void testSetBottomWindowVisibility_setTrue_isVisible() { mTestableResources.addOverride(R.bool.config_enableBottomNavigationBar, true); mCarNavigationBar = new CarNavigationBarController(mContext, mNavigationBarViewFactory, - mHvacControllerLazy); + () -> mCarFacetButtonController, () -> mHvacController); ViewGroup window = mCarNavigationBar.getBottomWindow(); mCarNavigationBar.setBottomWindowVisibility(View.VISIBLE); @@ -204,7 +202,7 @@ public class CarNavigationBarControllerTest extends SysuiTestCase { public void testSetBottomWindowVisibility_setFalse_isGone() { mTestableResources.addOverride(R.bool.config_enableBottomNavigationBar, true); mCarNavigationBar = new CarNavigationBarController(mContext, mNavigationBarViewFactory, - mHvacControllerLazy); + () -> mCarFacetButtonController, () -> mHvacController); ViewGroup window = mCarNavigationBar.getBottomWindow(); mCarNavigationBar.setBottomWindowVisibility(View.GONE); @@ -216,7 +214,7 @@ public class CarNavigationBarControllerTest extends SysuiTestCase { public void testSetLeftWindowVisibility_setTrue_isVisible() { mTestableResources.addOverride(R.bool.config_enableLeftNavigationBar, true); mCarNavigationBar = new CarNavigationBarController(mContext, mNavigationBarViewFactory, - mHvacControllerLazy); + () -> mCarFacetButtonController, () -> mHvacController); ViewGroup window = mCarNavigationBar.getLeftWindow(); mCarNavigationBar.setLeftWindowVisibility(View.VISIBLE); @@ -228,7 +226,7 @@ public class CarNavigationBarControllerTest extends SysuiTestCase { public void testSetLeftWindowVisibility_setFalse_isGone() { mTestableResources.addOverride(R.bool.config_enableLeftNavigationBar, true); mCarNavigationBar = new CarNavigationBarController(mContext, mNavigationBarViewFactory, - mHvacControllerLazy); + () -> mCarFacetButtonController, () -> mHvacController); ViewGroup window = mCarNavigationBar.getLeftWindow(); mCarNavigationBar.setLeftWindowVisibility(View.GONE); @@ -240,7 +238,7 @@ public class CarNavigationBarControllerTest extends SysuiTestCase { public void testSetRightWindowVisibility_setTrue_isVisible() { mTestableResources.addOverride(R.bool.config_enableRightNavigationBar, true); mCarNavigationBar = new CarNavigationBarController(mContext, mNavigationBarViewFactory, - mHvacControllerLazy); + () -> mCarFacetButtonController, () -> mHvacController); ViewGroup window = mCarNavigationBar.getRightWindow(); mCarNavigationBar.setRightWindowVisibility(View.VISIBLE); @@ -252,7 +250,7 @@ public class CarNavigationBarControllerTest extends SysuiTestCase { public void testSetRightWindowVisibility_setFalse_isGone() { mTestableResources.addOverride(R.bool.config_enableRightNavigationBar, true); mCarNavigationBar = new CarNavigationBarController(mContext, mNavigationBarViewFactory, - mHvacControllerLazy); + () -> mCarFacetButtonController, () -> mHvacController); ViewGroup window = mCarNavigationBar.getRightWindow(); mCarNavigationBar.setRightWindowVisibility(View.GONE); @@ -264,7 +262,7 @@ public class CarNavigationBarControllerTest extends SysuiTestCase { public void testRegisterBottomBarTouchListener_createViewFirst_registrationSuccessful() { mTestableResources.addOverride(R.bool.config_enableBottomNavigationBar, true); mCarNavigationBar = new CarNavigationBarController(mContext, mNavigationBarViewFactory, - mHvacControllerLazy); + () -> mCarFacetButtonController, () -> mHvacController); CarNavigationBarView bottomBar = mCarNavigationBar.getBottomBar(/* isSetUp= */ true); View.OnTouchListener controller = bottomBar.getStatusBarWindowTouchListener(); @@ -279,7 +277,7 @@ public class CarNavigationBarControllerTest extends SysuiTestCase { public void testRegisterBottomBarTouchListener_registerFirst_registrationSuccessful() { mTestableResources.addOverride(R.bool.config_enableBottomNavigationBar, true); mCarNavigationBar = new CarNavigationBarController(mContext, mNavigationBarViewFactory, - mHvacControllerLazy); + () -> mCarFacetButtonController, () -> mHvacController); mCarNavigationBar.registerBottomBarTouchListener(mock(View.OnTouchListener.class)); CarNavigationBarView bottomBar = mCarNavigationBar.getBottomBar(/* isSetUp= */ true); @@ -292,7 +290,7 @@ public class CarNavigationBarControllerTest extends SysuiTestCase { public void testRegisterNotificationController_createViewFirst_registrationSuccessful() { mTestableResources.addOverride(R.bool.config_enableBottomNavigationBar, true); mCarNavigationBar = new CarNavigationBarController(mContext, mNavigationBarViewFactory, - mHvacControllerLazy); + () -> mCarFacetButtonController, () -> mHvacController); CarNavigationBarView bottomBar = mCarNavigationBar.getBottomBar(/* isSetUp= */ true); CarNavigationBarController.NotificationsShadeController controller = @@ -309,7 +307,7 @@ public class CarNavigationBarControllerTest extends SysuiTestCase { public void testRegisterNotificationController_registerFirst_registrationSuccessful() { mTestableResources.addOverride(R.bool.config_enableBottomNavigationBar, true); mCarNavigationBar = new CarNavigationBarController(mContext, mNavigationBarViewFactory, - mHvacControllerLazy); + () -> mCarFacetButtonController, () -> mHvacController); mCarNavigationBar.registerNotificationController( mock(CarNavigationBarController.NotificationsShadeController.class)); @@ -324,7 +322,7 @@ public class CarNavigationBarControllerTest extends SysuiTestCase { public void testShowAllKeyguardButtons_bottomEnabled_bottomKeyguardButtonsVisible() { mTestableResources.addOverride(R.bool.config_enableBottomNavigationBar, true); mCarNavigationBar = new CarNavigationBarController(mContext, mNavigationBarViewFactory, - mHvacControllerLazy); + () -> mCarFacetButtonController, () -> mHvacController); CarNavigationBarView bottomBar = mCarNavigationBar.getBottomBar(/* isSetUp= */ true); View bottomKeyguardButtons = bottomBar.findViewById(R.id.lock_screen_nav_buttons); @@ -337,7 +335,7 @@ public class CarNavigationBarControllerTest extends SysuiTestCase { public void testShowAllKeyguardButtons_bottomEnabled_bottomNavButtonsGone() { mTestableResources.addOverride(R.bool.config_enableBottomNavigationBar, true); mCarNavigationBar = new CarNavigationBarController(mContext, mNavigationBarViewFactory, - mHvacControllerLazy); + () -> mCarFacetButtonController, () -> mHvacController); CarNavigationBarView bottomBar = mCarNavigationBar.getBottomBar(/* isSetUp= */ true); View bottomButtons = bottomBar.findViewById(R.id.nav_buttons); @@ -350,7 +348,7 @@ public class CarNavigationBarControllerTest extends SysuiTestCase { public void testHideAllKeyguardButtons_bottomEnabled_bottomKeyguardButtonsGone() { mTestableResources.addOverride(R.bool.config_enableBottomNavigationBar, true); mCarNavigationBar = new CarNavigationBarController(mContext, mNavigationBarViewFactory, - mHvacControllerLazy); + () -> mCarFacetButtonController, () -> mHvacController); CarNavigationBarView bottomBar = mCarNavigationBar.getBottomBar(/* isSetUp= */ true); View bottomKeyguardButtons = bottomBar.findViewById(R.id.lock_screen_nav_buttons); @@ -365,7 +363,7 @@ public class CarNavigationBarControllerTest extends SysuiTestCase { public void testHideAllKeyguardButtons_bottomEnabled_bottomNavButtonsVisible() { mTestableResources.addOverride(R.bool.config_enableBottomNavigationBar, true); mCarNavigationBar = new CarNavigationBarController(mContext, mNavigationBarViewFactory, - mHvacControllerLazy); + () -> mCarFacetButtonController, () -> mHvacController); CarNavigationBarView bottomBar = mCarNavigationBar.getBottomBar(/* isSetUp= */ true); View bottomButtons = bottomBar.findViewById(R.id.nav_buttons); @@ -380,7 +378,7 @@ public class CarNavigationBarControllerTest extends SysuiTestCase { public void testToggleAllNotificationsUnseenIndicator_bottomEnabled_hasUnseen_setCorrectly() { mTestableResources.addOverride(R.bool.config_enableBottomNavigationBar, true); mCarNavigationBar = new CarNavigationBarController(mContext, mNavigationBarViewFactory, - mHvacControllerLazy); + () -> mCarFacetButtonController, () -> mHvacController); CarNavigationBarView bottomBar = mCarNavigationBar.getBottomBar(/* isSetUp= */ true); CarNavigationButton notifications = bottomBar.findViewById(R.id.notifications); @@ -395,7 +393,7 @@ public class CarNavigationBarControllerTest extends SysuiTestCase { public void testToggleAllNotificationsUnseenIndicator_bottomEnabled_noUnseen_setCorrectly() { mTestableResources.addOverride(R.bool.config_enableBottomNavigationBar, true); mCarNavigationBar = new CarNavigationBarController(mContext, mNavigationBarViewFactory, - mHvacControllerLazy); + () -> mCarFacetButtonController, () -> mHvacController); CarNavigationBarView bottomBar = mCarNavigationBar.getBottomBar(/* isSetUp= */ true); CarNavigationButton notifications = bottomBar.findViewById(R.id.notifications); diff --git a/packages/SystemUI/res/drawable/ic_create_bubble.xml b/packages/SystemUI/res/drawable/ic_create_bubble.xml new file mode 100644 index 000000000000..1947f58f8f5e --- /dev/null +++ b/packages/SystemUI/res/drawable/ic_create_bubble.xml @@ -0,0 +1,29 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright (C) 2019 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> + <path + android:pathData="M12,3c-4.97,0 -9,4.03 -9,9c0,1.39 0.32,2.69 0.88,3.86l1.53,-1.53C5.15,13.6 5,12.82 5,12c0,-3.86 3.14,-7 7,-7s7,3.14 7,7s-3.14,7 -7,7c-0.83,0 -1.62,-0.15 -2.35,-0.42l-1.53,1.53C9.3,20.67 10.61,21 12,21c4.97,0 9,-4.03 9,-9C21,7.03 16.97,3 12,3z" + android:fillColor="#000000"/> + <path + android:pathData="M12.99,15.99l2,0l0,-7l-7,0l0,2l3.59,0l-8.79,8.8l1.41,1.41l8.79,-8.79z" + android:fillColor="#000000"/> +</vector> diff --git a/packages/SystemUI/res/layout/notification_info.xml b/packages/SystemUI/res/layout/notification_info.xml index 87de9d4d3b51..964a59170d35 100644 --- a/packages/SystemUI/res/layout/notification_info.xml +++ b/packages/SystemUI/res/layout/notification_info.xml @@ -220,6 +220,58 @@ asked for it --> android:orientation="vertical"> <com.android.systemui.statusbar.notification.row.ButtonLinearLayout + android:id="@+id/bubble" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:padding="@dimen/notification_importance_button_padding" + android:layout_marginBottom="@dimen/notification_importance_button_separation" + android:clickable="true" + android:focusable="true" + android:background="@drawable/notification_guts_priority_button_bg" + android:orientation="vertical"> + <LinearLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="horizontal" + android:gravity="center" + > + <ImageView + android:id="@+id/bubble_icon" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:src="@drawable/ic_create_bubble" + android:background="@android:color/transparent" + android:tint="@color/notification_guts_priority_contents" + android:clickable="false" + android:focusable="false"/> + <TextView + android:id="@+id/bubble_label" + android:layout_width="0dp" + android:layout_height="wrap_content" + android:layout_marginStart="@dimen/notification_importance_drawable_padding" + android:layout_weight="1" + android:ellipsize="end" + android:maxLines="1" + android:clickable="false" + android:focusable="false" + android:textAppearance="@style/TextAppearance.NotificationImportanceButton" + android:text="@string/notification_bubble_title"/> + </LinearLayout> + <TextView + android:id="@+id/bubble_summary" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="@dimen/notification_importance_button_description_top_margin" + android:visibility="gone" + android:text="@string/notification_channel_summary_bubble" + android:clickable="false" + android:focusable="false" + android:ellipsize="end" + android:maxLines="2" + android:textAppearance="@style/TextAppearance.NotificationImportanceDetail"/> + </com.android.systemui.statusbar.notification.row.ButtonLinearLayout> + + <com.android.systemui.statusbar.notification.row.ButtonLinearLayout android:id="@+id/alert" android:layout_width="match_parent" android:layout_height="wrap_content" diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml index 008294980d94..19daa9039f55 100644 --- a/packages/SystemUI/res/values/strings.xml +++ b/packages/SystemUI/res/values/strings.xml @@ -1717,12 +1717,18 @@ <!-- [CHAR LIMIT=100] Notification Importance title --> <string name="notification_alert_title">Alerting</string> + <!-- [CHAR LIMIT=100] Notification Importance title --> + <string name="notification_bubble_title">Bubble</string> + <!-- [CHAR LIMIT=150] Notification Importance title: low importance level summary --> <string name="notification_channel_summary_low">Helps you focus without sound or vibration.</string> <!-- [CHAR LIMIT=150] Notification Importance title: normal importance level summary --> <string name="notification_channel_summary_default">Gets your attention with sound or vibration.</string> + <!-- [CHAR LIMIT=150] Notification Importance title: bubble level summary --> + <string name="notification_channel_summary_bubble">Keeps your attention with a floating shortcut to this content.</string> + <!-- Notification: Control panel: Label that displays when the app's notifications cannot be blocked. --> <string name="notification_unblockable_desc">These notifications can\'t be modified.</string> diff --git a/packages/SystemUI/src/com/android/systemui/Dependency.java b/packages/SystemUI/src/com/android/systemui/Dependency.java index 91ee1b91fd9e..dca5c8a5a36f 100644 --- a/packages/SystemUI/src/com/android/systemui/Dependency.java +++ b/packages/SystemUI/src/com/android/systemui/Dependency.java @@ -125,6 +125,7 @@ import com.android.systemui.util.leak.GarbageMonitor; import com.android.systemui.util.leak.LeakDetector; import com.android.systemui.util.leak.LeakReporter; import com.android.systemui.util.sensors.AsyncSensorManager; +import com.android.systemui.wm.DisplayWindowController; import java.io.FileDescriptor; import java.io.PrintWriter; @@ -332,6 +333,7 @@ public class Dependency { @Inject Lazy<CommandQueue> mCommandQueue; @Inject Lazy<Recents> mRecents; @Inject Lazy<StatusBar> mStatusBar; + @Inject Lazy<DisplayWindowController> mDisplayWindowController; @Inject public Dependency() { @@ -523,6 +525,7 @@ public class Dependency { mProviders.put(CommandQueue.class, mCommandQueue::get); mProviders.put(Recents.class, mRecents::get); mProviders.put(StatusBar.class, mStatusBar::get); + mProviders.put(DisplayWindowController.class, mDisplayWindowController::get); // TODO(b/118592525): to support multi-display , we start to add something which is // per-display, while others may be global. I think it's time to add diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSMediaPlayer.java b/packages/SystemUI/src/com/android/systemui/qs/QSMediaPlayer.java index 694964075032..1a4c327b4405 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSMediaPlayer.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSMediaPlayer.java @@ -47,7 +47,9 @@ import android.widget.TextView; import androidx.core.graphics.drawable.RoundedBitmapDrawable; import androidx.core.graphics.drawable.RoundedBitmapDrawableFactory; +import com.android.settingslib.media.MediaDevice; import com.android.settingslib.media.MediaOutputSliceConstants; +import com.android.settingslib.widget.AdaptiveIcon; import com.android.systemui.Dependency; import com.android.systemui.R; import com.android.systemui.plugins.ActivityStarter; @@ -61,10 +63,13 @@ public class QSMediaPlayer { private Context mContext; private LinearLayout mMediaNotifView; + private View mSeamless; private MediaSession.Token mToken; private MediaController mController; private int mWidth; private int mHeight; + private int mForegroundColor; + private int mBackgroundColor; /** * @@ -93,15 +98,17 @@ public class QSMediaPlayer { * @param iconColor foreground color (for text, icons) * @param bgColor background color * @param actionsContainer a LinearLayout containing the media action buttons - * @param notif + * @param notif reference to original notification + * @param device current playback device */ public void setMediaSession(MediaSession.Token token, Icon icon, int iconColor, int bgColor, - View actionsContainer, Notification notif) { + View actionsContainer, Notification notif, MediaDevice device) { Log.d(TAG, "got media session: " + token); mToken = token; + mForegroundColor = iconColor; + mBackgroundColor = bgColor; mController = new MediaController(mContext, token); MediaMetadata mMediaMetadata = mController.getMetadata(); - if (mMediaMetadata == null) { Log.e(TAG, "Media metadata was null"); return; @@ -123,9 +130,6 @@ public class QSMediaPlayer { headerView.removeAllViews(); headerView.addView(result); - View seamless = headerView.findViewById(com.android.internal.R.id.media_seamless); - seamless.setVisibility(View.VISIBLE); - // App icon ImageView appIcon = headerView.findViewById(com.android.internal.R.id.icon); Drawable iconDrawable = icon.loadDrawable(mContext); @@ -168,23 +172,11 @@ public class QSMediaPlayer { } // Transfer chip - View transferBackgroundView = headerView.findViewById( - com.android.internal.R.id.media_seamless); - LinearLayout viewLayout = (LinearLayout) transferBackgroundView; - RippleDrawable bkgDrawable = (RippleDrawable) viewLayout.getBackground(); - GradientDrawable rect = (GradientDrawable) bkgDrawable.getDrawable(0); - rect.setStroke(2, iconColor); - rect.setColor(bgColor); - ImageView transferIcon = headerView.findViewById( - com.android.internal.R.id.media_seamless_image); - transferIcon.setBackgroundColor(bgColor); - transferIcon.setImageTintList(ColorStateList.valueOf(iconColor)); - TextView transferText = headerView.findViewById( - com.android.internal.R.id.media_seamless_text); - transferText.setTextColor(iconColor); - + mSeamless = headerView.findViewById(com.android.internal.R.id.media_seamless); + mSeamless.setVisibility(View.VISIBLE); + updateChip(device); ActivityStarter mActivityStarter = Dependency.get(ActivityStarter.class); - transferBackgroundView.setOnClickListener(v -> { + mSeamless.setOnClickListener(v -> { final Intent intent = new Intent() .setAction(MediaOutputSliceConstants.ACTION_MEDIA_OUTPUT); mActivityStarter.startActivity(intent, false, true /* dismissShade */, @@ -219,10 +211,13 @@ public class QSMediaPlayer { com.android.internal.R.id.action3, com.android.internal.R.id.action4 }; - for (int i = 0; i < parentActionsLayout.getChildCount() && i < actionIds.length; i++) { + + int i = 0; + for (; i < parentActionsLayout.getChildCount() && i < actionIds.length; i++) { ImageButton thisBtn = mMediaNotifView.findViewById(actionIds[i]); ImageButton thatBtn = parentActionsLayout.findViewById(notifActionIds[i]); - if (thatBtn == null || thatBtn.getDrawable() == null) { + if (thatBtn == null || thatBtn.getDrawable() == null + || thatBtn.getVisibility() != View.VISIBLE) { thisBtn.setVisibility(View.GONE); continue; } @@ -235,6 +230,13 @@ public class QSMediaPlayer { thatBtn.performClick(); }); } + + // Hide any unused buttons + for (; i < actionIds.length; i++) { + ImageButton thisBtn = mMediaNotifView.findViewById(actionIds[i]); + thisBtn.setVisibility(View.GONE); + Log.d(TAG, "hid a button"); + } } public MediaSession.Token getMediaSessionToken() { @@ -284,6 +286,7 @@ public class QSMediaPlayer { mMediaNotifView.setBackground(roundedDrawable); } else { Log.e(TAG, "No album art available"); + mMediaNotifView.setBackground(null); } } @@ -303,4 +306,41 @@ public class QSMediaPlayer { return cropped; } + + protected void updateChip(MediaDevice device) { + if (mSeamless == null) { + return; + } + ColorStateList fgTintList = ColorStateList.valueOf(mForegroundColor); + + // Update the outline color + LinearLayout viewLayout = (LinearLayout) mSeamless; + RippleDrawable bkgDrawable = (RippleDrawable) viewLayout.getBackground(); + GradientDrawable rect = (GradientDrawable) bkgDrawable.getDrawable(0); + rect.setStroke(2, mForegroundColor); + rect.setColor(mBackgroundColor); + + ImageView iconView = mSeamless.findViewById(com.android.internal.R.id.media_seamless_image); + TextView deviceName = mSeamless.findViewById(com.android.internal.R.id.media_seamless_text); + deviceName.setTextColor(fgTintList); + + if (device != null) { + Drawable icon = device.getIcon(); + iconView.setVisibility(View.VISIBLE); + iconView.setImageTintList(fgTintList); + + if (icon instanceof AdaptiveIcon) { + AdaptiveIcon aIcon = (AdaptiveIcon) icon; + aIcon.setBackgroundColor(mBackgroundColor); + iconView.setImageDrawable(aIcon); + } else { + iconView.setImageDrawable(icon); + } + deviceName.setText(device.getName()); + } else { + // Reset to default + iconView.setVisibility(View.GONE); + deviceName.setText(com.android.internal.R.string.ext_media_seamless_action); + } + } } diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java index cac90257cd43..5e98f9356403 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java @@ -46,6 +46,8 @@ import android.widget.LinearLayout; import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.settingslib.Utils; +import com.android.settingslib.media.LocalMediaManager; +import com.android.settingslib.media.MediaDevice; import com.android.systemui.Dependency; import com.android.systemui.DumpController; import com.android.systemui.Dumpable; @@ -70,6 +72,7 @@ import java.io.FileDescriptor; import java.io.PrintWriter; import java.util.ArrayList; import java.util.Collection; +import java.util.List; import javax.inject.Inject; import javax.inject.Named; @@ -92,6 +95,8 @@ public class QSPanel extends LinearLayout implements Tunable, Callback, Brightne private final LinearLayout mMediaCarousel; private final ArrayList<QSMediaPlayer> mMediaPlayers = new ArrayList<>(); + private LocalMediaManager mLocalMediaManager; + private MediaDevice mDevice; protected boolean mExpanded; protected boolean mListening; @@ -117,6 +122,31 @@ public class QSPanel extends LinearLayout implements Tunable, Callback, Brightne private final PluginManager mPluginManager; private NPVPluginManager mNPVPluginManager; + private final LocalMediaManager.DeviceCallback mDeviceCallback = + new LocalMediaManager.DeviceCallback() { + @Override + public void onDeviceListUpdate(List<MediaDevice> devices) { + MediaDevice currentDevice = mLocalMediaManager.getCurrentConnectedDevice(); + // Check because this can be called several times while changing devices + if (mDevice == null || !mDevice.equals(currentDevice)) { + mDevice = currentDevice; + for (QSMediaPlayer p : mMediaPlayers) { + p.updateChip(mDevice); + } + } + } + + @Override + public void onSelectedDeviceStateChanged(MediaDevice device, int state) { + if (mDevice == null || !mDevice.equals(device)) { + mDevice = device; + for (QSMediaPlayer p : mMediaPlayers) { + p.updateChip(mDevice); + } + } + } + }; + public QSPanel(Context context) { this(context, null); } @@ -208,6 +238,11 @@ public class QSPanel extends LinearLayout implements Tunable, Callback, Brightne Log.e(TAG, "Tried to add media session without player!"); return; } + if (token == null) { + Log.e(TAG, "Media session token was null!"); + return; + } + QSMediaPlayer player = null; String packageName = notif.getPackageName(); for (QSMediaPlayer p : mMediaPlayers) { @@ -250,10 +285,17 @@ public class QSPanel extends LinearLayout implements Tunable, Callback, Brightne Log.d(TAG, "setting player session"); player.setMediaSession(token, icon, iconColor, bgColor, actionsContainer, - notif.getNotification()); + notif.getNotification(), mDevice); if (mMediaPlayers.size() > 0) { ((View) mMediaCarousel.getParent()).setVisibility(View.VISIBLE); + + // Set up listener for device changes + // TODO: integrate with MediaTransferManager? + mLocalMediaManager = new LocalMediaManager(mContext, null, null); + mLocalMediaManager.startScan(); + mDevice = mLocalMediaManager.getCurrentConnectedDevice(); + mLocalMediaManager.registerCallback(mDeviceCallback); } } @@ -326,6 +368,10 @@ public class QSPanel extends LinearLayout implements Tunable, Callback, Brightne mBrightnessMirrorController.removeCallback(this); } if (mDumpController != null) mDumpController.unregisterDumpable(this); + if (mLocalMediaManager != null) { + mLocalMediaManager.stopScan(); + mLocalMediaManager.unregisterCallback(mDeviceCallback); + } super.onDetachedFromWindow(); } diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickQSMediaPlayer.java b/packages/SystemUI/src/com/android/systemui/qs/QuickQSMediaPlayer.java index 3ec71ac30da1..d7b8b83f01fb 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QuickQSMediaPlayer.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QuickQSMediaPlayer.java @@ -76,9 +76,11 @@ public class QuickQSMediaPlayer { * @param iconColor foreground color (for text, icons) * @param bgColor background color * @param actionsContainer a LinearLayout containing the media action buttons + * @param actionsToShow indices of which actions to display in the mini player + * (max 3: Notification.MediaStyle.MAX_MEDIA_BUTTONS_IN_COMPACT) */ public void setMediaSession(MediaSession.Token token, Icon icon, int iconColor, int bgColor, - View actionsContainer) { + View actionsContainer, int[] actionsToShow) { Log.d(TAG, "Setting media session: " + token); mToken = token; mController = new MediaController(mContext, token); @@ -110,32 +112,46 @@ public class QuickQSMediaPlayer { titleText.setText(songName); titleText.setTextColor(iconColor); - // Action buttons - LinearLayout parentActionsLayout = (LinearLayout) actionsContainer; + // Buttons we can display final int[] actionIds = {R.id.action0, R.id.action1, R.id.action2}; - // TODO some apps choose different buttons to show in compact mode + // Existing buttons in the notification + LinearLayout parentActionsLayout = (LinearLayout) actionsContainer; final int[] notifActionIds = { + com.android.internal.R.id.action0, com.android.internal.R.id.action1, com.android.internal.R.id.action2, - com.android.internal.R.id.action3 + com.android.internal.R.id.action3, + com.android.internal.R.id.action4 }; - for (int i = 0; i < parentActionsLayout.getChildCount() && i < actionIds.length; i++) { - ImageButton thisBtn = mMediaNotifView.findViewById(actionIds[i]); - ImageButton thatBtn = parentActionsLayout.findViewById(notifActionIds[i]); - if (thatBtn == null || thatBtn.getDrawable() == null) { - thisBtn.setVisibility(View.GONE); - continue; - } - Drawable thatIcon = thatBtn.getDrawable(); - thisBtn.setImageDrawable(thatIcon.mutate()); - thisBtn.setVisibility(View.VISIBLE); + int i = 0; + if (actionsToShow != null) { + int maxButtons = Math.min(actionsToShow.length, parentActionsLayout.getChildCount()); + maxButtons = Math.min(maxButtons, actionIds.length); + for (; i < maxButtons; i++) { + ImageButton thisBtn = mMediaNotifView.findViewById(actionIds[i]); + int thatId = notifActionIds[actionsToShow[i]]; + ImageButton thatBtn = parentActionsLayout.findViewById(thatId); + if (thatBtn == null || thatBtn.getDrawable() == null + || thatBtn.getVisibility() != View.VISIBLE) { + thisBtn.setVisibility(View.GONE); + continue; + } + + Drawable thatIcon = thatBtn.getDrawable(); + thisBtn.setImageDrawable(thatIcon.mutate()); + thisBtn.setVisibility(View.VISIBLE); + thisBtn.setOnClickListener(v -> { + thatBtn.performClick(); + }); + } + } - thisBtn.setOnClickListener(v -> { - Log.d(TAG, "clicking on other button"); - thatBtn.performClick(); - }); + // Hide any unused buttons + for (; i < actionIds.length; i++) { + ImageButton thisBtn = mMediaNotifView.findViewById(actionIds[i]); + thisBtn.setVisibility(View.GONE); } } @@ -186,6 +202,7 @@ public class QuickQSMediaPlayer { mMediaNotifView.setBackground(roundedDrawable); } else { Log.e(TAG, "No album art available"); + mMediaNotifView.setBackground(null); } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/MediaTransferManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/MediaTransferManager.java index 926ae71194d9..b21c65ea85ea 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/MediaTransferManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/MediaTransferManager.java @@ -19,10 +19,12 @@ package com.android.systemui.statusbar; import android.content.Context; import android.content.Intent; import android.content.res.ColorStateList; +import android.graphics.drawable.Drawable; import android.graphics.drawable.GradientDrawable; import android.graphics.drawable.RippleDrawable; import android.service.notification.StatusBarNotification; import android.util.FeatureFlagUtils; +import android.util.Log; import android.view.View; import android.view.ViewGroup; import android.view.ViewParent; @@ -30,19 +32,29 @@ import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.TextView; -import com.android.internal.R; +import com.android.settingslib.media.LocalMediaManager; +import com.android.settingslib.media.MediaDevice; import com.android.settingslib.media.MediaOutputSliceConstants; +import com.android.settingslib.widget.AdaptiveIcon; import com.android.systemui.Dependency; import com.android.systemui.plugins.ActivityStarter; import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; +import java.util.ArrayList; +import java.util.List; + /** * Class for handling MediaTransfer state over a set of notifications. */ public class MediaTransferManager { private final Context mContext; private final ActivityStarter mActivityStarter; + private MediaDevice mDevice; + private List<View> mViews = new ArrayList<>(); + private LocalMediaManager mLocalMediaManager; + + private static final String TAG = "MediaTransferManager"; private final View.OnClickListener mOnClickHandler = new View.OnClickListener() { @Override @@ -70,9 +82,50 @@ public class MediaTransferManager { } }; + private final LocalMediaManager.DeviceCallback mMediaDeviceCallback = + new LocalMediaManager.DeviceCallback() { + @Override + public void onDeviceListUpdate(List<MediaDevice> devices) { + MediaDevice currentDevice = mLocalMediaManager.getCurrentConnectedDevice(); + // Check because this can be called several times while changing devices + if (mDevice == null || !mDevice.equals(currentDevice)) { + mDevice = currentDevice; + updateAllChips(); + } + } + + @Override + public void onSelectedDeviceStateChanged(MediaDevice device, int state) { + if (mDevice == null || !mDevice.equals(device)) { + mDevice = device; + updateAllChips(); + } + } + }; + public MediaTransferManager(Context context) { mContext = context; mActivityStarter = Dependency.get(ActivityStarter.class); + mLocalMediaManager = new LocalMediaManager(mContext, null, null); + } + + /** + * Mark a view as removed. If no views remain the media device listener will be unregistered. + * @param root + */ + public void setRemoved(View root) { + if (!FeatureFlagUtils.isEnabled(mContext, FeatureFlagUtils.SEAMLESS_TRANSFER) + || mLocalMediaManager == null || root == null) { + return; + } + View view = root.findViewById(com.android.internal.R.id.media_seamless); + if (mViews.remove(view)) { + if (mViews.size() == 0) { + mLocalMediaManager.unregisterCallback(mMediaDeviceCallback); + } + } else { + Log.e(TAG, "Tried to remove unknown view " + view); + } } private ExpandableNotificationRow getRowForParent(ViewParent parent) { @@ -92,7 +145,8 @@ public class MediaTransferManager { * @param entry The entry of MediaTransfer action button. */ public void applyMediaTransferView(ViewGroup root, NotificationEntry entry) { - if (!FeatureFlagUtils.isEnabled(mContext, FeatureFlagUtils.SEAMLESS_TRANSFER)) { + if (!FeatureFlagUtils.isEnabled(mContext, FeatureFlagUtils.SEAMLESS_TRANSFER) + || mLocalMediaManager == null || root == null) { return; } @@ -103,23 +157,59 @@ public class MediaTransferManager { view.setVisibility(View.VISIBLE); view.setOnClickListener(mOnClickHandler); + if (!mViews.contains(view)) { + mViews.add(view); + if (mViews.size() == 1) { + mLocalMediaManager.registerCallback(mMediaDeviceCallback); + } + } + + // Initial update + mLocalMediaManager.startScan(); + mDevice = mLocalMediaManager.getCurrentConnectedDevice(); + updateChip(view); + } + private void updateAllChips() { + for (View view : mViews) { + updateChip(view); + } + } + + private void updateChip(View view) { ExpandableNotificationRow enr = getRowForParent(view.getParent()); - int color = enr.getNotificationHeader().getOriginalIconColor(); - ColorStateList tintList = ColorStateList.valueOf(color); + int fgColor = enr.getNotificationHeader().getOriginalIconColor(); + ColorStateList fgTintList = ColorStateList.valueOf(fgColor); + int bgColor = enr.getCurrentBackgroundTint(); - // Update the outline color + // Update outline color LinearLayout viewLayout = (LinearLayout) view; RippleDrawable bkgDrawable = (RippleDrawable) viewLayout.getBackground(); GradientDrawable rect = (GradientDrawable) bkgDrawable.getDrawable(0); - rect.setStroke(2, color); - - // Update the image color - ImageView image = view.findViewById(R.id.media_seamless_image); - image.setImageTintList(tintList); - - // Update the text color - TextView text = view.findViewById(R.id.media_seamless_text); - text.setTextColor(tintList); + rect.setStroke(2, fgColor); + rect.setColor(bgColor); + + ImageView iconView = view.findViewById(com.android.internal.R.id.media_seamless_image); + TextView deviceName = view.findViewById(com.android.internal.R.id.media_seamless_text); + deviceName.setTextColor(fgTintList); + + if (mDevice != null) { + Drawable icon = mDevice.getIcon(); + iconView.setVisibility(View.VISIBLE); + iconView.setImageTintList(fgTintList); + + if (icon instanceof AdaptiveIcon) { + AdaptiveIcon aIcon = (AdaptiveIcon) icon; + aIcon.setBackgroundColor(bgColor); + iconView.setImageDrawable(aIcon); + } else { + iconView.setImageDrawable(icon); + } + deviceName.setText(mDevice.getName()); + } else { + // Reset to default + iconView.setVisibility(View.GONE); + deviceName.setText(com.android.internal.R.string.ext_media_seamless_action); + } } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ActivityLaunchAnimator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ActivityLaunchAnimator.java index 9b312341c583..e48e81957225 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ActivityLaunchAnimator.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ActivityLaunchAnimator.java @@ -125,22 +125,21 @@ public class ActivityLaunchAnimator { return mAnimationRunning; } - class AnimationRunner extends IRemoteAnimationRunner.Stub { + private class AnimationRunner extends IRemoteAnimationRunner.Stub { - private final ExpandableNotificationRow mSourceNotification; - private final ExpandAnimationParameters mParams; + private ExpandableNotificationRow mSourceNotification; + private final ExpandAnimationParameters mParams = new ExpandAnimationParameters(); private final Rect mWindowCrop = new Rect(); private final float mNotificationCornerRadius; private float mCornerRadius; private boolean mIsFullScreenLaunch = true; private final SyncRtSurfaceTransactionApplier mSyncRtTransactionApplier; - public AnimationRunner(ExpandableNotificationRow sourceNofitication) { - mSourceNotification = sourceNofitication; - mParams = new ExpandAnimationParameters(); - mSyncRtTransactionApplier = new SyncRtSurfaceTransactionApplier(mSourceNotification); - mNotificationCornerRadius = Math.max(mSourceNotification.getCurrentTopRoundness(), - mSourceNotification.getCurrentBottomRoundness()); + AnimationRunner(ExpandableNotificationRow sourceNotification) { + mSourceNotification = sourceNotification; + mSyncRtTransactionApplier = new SyncRtSurfaceTransactionApplier(sourceNotification); + mNotificationCornerRadius = Math.max(sourceNotification.getCurrentTopRoundness(), + sourceNotification.getCurrentBottomRoundness()); } @Override @@ -155,6 +154,7 @@ public class ActivityLaunchAnimator { setAnimationPending(false); invokeCallback(iRemoteAnimationFinishedCallback); mNotificationPanel.collapse(false /* delayed */, 1.0f /* speedUpFactor */); + mSourceNotification = null; return; } @@ -254,6 +254,7 @@ public class ActivityLaunchAnimator { mCallback.onExpandAnimationFinished(mIsFullScreenLaunch); applyParamsToNotification(null); applyParamsToNotificationList(null); + mSourceNotification = null; } } @@ -281,6 +282,7 @@ public class ActivityLaunchAnimator { mSourceNotification.post(() -> { setAnimationPending(false); mCallback.onLaunchAnimationCancelled(); + mSourceNotification = null; }); } }; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java index b12c76c750a8..d1b9a87c1ddc 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java @@ -1546,9 +1546,11 @@ public class NotificationContentView extends FrameLayout { } if (mExpandedWrapper != null) { mExpandedWrapper.setRemoved(); + mMediaTransferManager.setRemoved(mExpandedChild); } if (mContractedWrapper != null) { mContractedWrapper.setRemoved(); + mMediaTransferManager.setRemoved(mContractedChild); } if (mHeadsUpWrapper != null) { mHeadsUpWrapper.setRemoved(); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java index f90e561dece1..f67cd1bef281 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java @@ -319,7 +319,7 @@ public class NotificationGutsManager implements Dumpable, NotificationLifetimeEx packageName, row.getEntry().getChannel(), row.getUniqueChannels(), - sbn, + row.getEntry(), mCheckSaveListener, onSettingsClick, onAppSettingsClick, diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInfo.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInfo.java index 148d83b5ab5c..a9a4804a2be4 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInfo.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInfo.java @@ -65,7 +65,10 @@ import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.systemui.Dependency; import com.android.systemui.Interpolators; import com.android.systemui.R; +import com.android.systemui.bubbles.BubbleController; +import com.android.systemui.bubbles.BubbleExperimentConfig; import com.android.systemui.statusbar.notification.VisualStabilityManager; +import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.logging.NotificationCounters; import java.lang.annotation.Retention; @@ -99,6 +102,7 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G // standard controls private static final int ACTION_ALERT = 5; + private TextView mBubbleDescriptionView; private TextView mPriorityDescriptionView; private TextView mSilentDescriptionView; @@ -116,6 +120,7 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G private Set<NotificationChannel> mUniqueChannelsInRow; private NotificationChannel mSingleNotificationChannel; private int mStartingChannelImportance; + private boolean mStartedAsBubble; private boolean mWasShownHighPriority; private boolean mPressedApply; private boolean mPresentingChannelEditorDialog = false; @@ -125,8 +130,15 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G * level; non-null once the user takes an action which indicates an explicit preference. */ @Nullable private Integer mChosenImportance; + /** + * The last bubble setting chosen by the user. Null if the user has not chosen a bubble level; + * non-null once the user takes an action which indicates an explicit preference. + */ + @Nullable private Boolean mChosenBubbleEnabled; private boolean mIsSingleDefaultChannel; private boolean mIsNonblockable; + private boolean mIsBubbleable; + private NotificationEntry mEntry; private StatusBarNotification mSbn; private AnimatorSet mExpandAnimation; private boolean mIsDeviceProvisioned; @@ -137,18 +149,27 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G private NotificationGuts mGutsContainer; private Drawable mPkgIcon; + private BubbleController mBubbleController; + /** Whether this view is being shown as part of the blocking helper. */ private boolean mIsForBlockingHelper; + @VisibleForTesting + boolean mSkipPost = false; + /** * String that describes how the user exit or quit out of this view, also used as a counter tag. */ private String mExitReason = NotificationCounters.BLOCKING_HELPER_DISMISSED; + // used by standard ui private OnClickListener mOnAlert = v -> { mExitReason = NotificationCounters.BLOCKING_HELPER_KEEP_SHOWING; mChosenImportance = IMPORTANCE_DEFAULT; + if (mStartedAsBubble) { + mChosenBubbleEnabled = false; + } applyAlertingBehavior(BEHAVIOR_ALERTING, true /* userTriggered */); }; @@ -156,9 +177,19 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G private OnClickListener mOnSilent = v -> { mExitReason = NotificationCounters.BLOCKING_HELPER_DELIVER_SILENTLY; mChosenImportance = IMPORTANCE_LOW; + if (mStartedAsBubble) { + mChosenBubbleEnabled = false; + } applyAlertingBehavior(BEHAVIOR_SILENT, true /* userTriggered */); }; + /** Used by standard ui (in an experiment) {@see BubbleExperimentConfig#allowNotifBubbleMenu} */ + private OnClickListener mOnBubble = v -> { + mExitReason = NotificationCounters.BLOCKING_HELPER_KEEP_SHOWING; + mChosenBubbleEnabled = true; + applyAlertingBehavior(BEHAVIOR_BUBBLE, true /* userTriggered */); + }; + // used by standard ui private OnClickListener mOnDismissSettings = v -> { mPressedApply = true; @@ -224,6 +255,7 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G protected void onFinishInflate() { super.onFinishInflate(); + mBubbleDescriptionView = findViewById(R.id.bubble_summary); mPriorityDescriptionView = findViewById(R.id.alert_summary); mSilentDescriptionView = findViewById(R.id.silence_summary); } @@ -251,7 +283,7 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G final String pkg, final NotificationChannel notificationChannel, final Set<NotificationChannel> uniqueChannelsInRow, - final StatusBarNotification sbn, + final NotificationEntry entry, final CheckSaveListener checkSaveListener, final OnSettingsClickListener onSettingsClick, final OnAppSettingsClickListener onAppSettingsClick, @@ -261,7 +293,7 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G boolean wasShownHighPriority) throws RemoteException { bindNotification(pm, iNotificationManager, visualStabilityManager, pkg, notificationChannel, - uniqueChannelsInRow, sbn, checkSaveListener, onSettingsClick, + uniqueChannelsInRow, entry, checkSaveListener, onSettingsClick, onAppSettingsClick, isDeviceProvisioned, isNonblockable, false /* isBlockingHelper */, importance, wasShownHighPriority); @@ -274,7 +306,7 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G String pkg, NotificationChannel notificationChannel, Set<NotificationChannel> uniqueChannelsInRow, - StatusBarNotification sbn, + NotificationEntry entry, CheckSaveListener checkSaveListener, OnSettingsClickListener onSettingsClick, OnAppSettingsClickListener onAppSettingsClick, @@ -288,10 +320,12 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G mMetricsLogger = Dependency.get(MetricsLogger.class); mVisualStabilityManager = visualStabilityManager; mChannelEditorDialogController = Dependency.get(ChannelEditorDialogController.class); + mBubbleController = Dependency.get(BubbleController.class); mPackageName = pkg; mUniqueChannelsInRow = uniqueChannelsInRow; mNumUniqueChannelsInRow = uniqueChannelsInRow.size(); - mSbn = sbn; + mEntry = entry; + mSbn = entry.getSbn(); mPm = pm; mAppSettingsClickListener = onAppSettingsClick; mAppName = mPackageName; @@ -318,6 +352,9 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G && numTotalChannels == 1; } + mIsBubbleable = mEntry.getBubbleMetadata() != null; + mStartedAsBubble = mEntry.isBubble(); + bindHeader(); bindChannelDetails(); @@ -365,6 +402,7 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G findViewById(R.id.non_configurable_text).setVisibility(GONE); findViewById(R.id.non_configurable_multichannel_text).setVisibility(GONE); findViewById(R.id.interruptiveness_settings).setVisibility(VISIBLE); + findViewById(R.id.bubble).setVisibility(mIsBubbleable ? VISIBLE : GONE); } View turnOffButton = findViewById(R.id.turn_off_notifications); @@ -378,12 +416,17 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G View silent = findViewById(R.id.silence); View alert = findViewById(R.id.alert); + View bubble = findViewById(R.id.bubble); silent.setOnClickListener(mOnSilent); alert.setOnClickListener(mOnAlert); + bubble.setOnClickListener(mOnBubble); - applyAlertingBehavior( - mWasShownHighPriority ? BEHAVIOR_ALERTING : BEHAVIOR_SILENT, - false /* userTriggered */); + int behavior = mStartedAsBubble + ? BEHAVIOR_BUBBLE + : mWasShownHighPriority + ? BEHAVIOR_ALERTING + : BEHAVIOR_SILENT; + applyAlertingBehavior(behavior, false /* userTriggered */); } private void bindHeader() { @@ -544,6 +587,14 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G } } + if (mChosenBubbleEnabled != null && mStartedAsBubble != mChosenBubbleEnabled) { + if (mChosenBubbleEnabled) { + mBubbleController.onUserCreatedBubbleFromNotification(mEntry); + } else { + mBubbleController.onUserDemotedBubbleFromNotification(mEntry); + } + } + Handler bgHandler = new Handler(Dependency.get(Dependency.BG_LOOPER)); bgHandler.post( new UpdateImportanceRunnable(mINotificationManager, mPackageName, mAppUid, @@ -553,6 +604,16 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G } } + @Override + public boolean post(Runnable action) { + if (mSkipPost) { + action.run(); + return true; + } else { + return super.post(action); + } + } + private void applyAlertingBehavior(@AlertingBehavior int behavior, boolean userTriggered) { if (userTriggered) { TransitionSet transition = new TransitionSet(); @@ -569,6 +630,7 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G TransitionManager.beginDelayedTransition(this, transition); } + View bubble = findViewById(R.id.bubble); View alert = findViewById(R.id.alert); View silence = findViewById(R.id.silence); @@ -576,33 +638,53 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G case BEHAVIOR_ALERTING: mPriorityDescriptionView.setVisibility(VISIBLE); mSilentDescriptionView.setVisibility(GONE); + mBubbleDescriptionView.setVisibility(GONE); post(() -> { alert.setSelected(true); silence.setSelected(false); + bubble.setSelected(false); }); break; - case BEHAVIOR_SILENT: + case BEHAVIOR_SILENT: mSilentDescriptionView.setVisibility(VISIBLE); mPriorityDescriptionView.setVisibility(GONE); + mBubbleDescriptionView.setVisibility(GONE); post(() -> { alert.setSelected(false); silence.setSelected(true); + bubble.setSelected(false); + }); + break; + + case BEHAVIOR_BUBBLE: + mBubbleDescriptionView.setVisibility(VISIBLE); + mSilentDescriptionView.setVisibility(GONE); + mPriorityDescriptionView.setVisibility(GONE); + post(() -> { + alert.setSelected(false); + silence.setSelected(false); + bubble.setSelected(true); }); break; + default: throw new IllegalArgumentException("Unrecognized alerting behavior: " + behavior); } boolean isAChange = mWasShownHighPriority != (behavior == BEHAVIOR_ALERTING); + boolean isABubbleChange = mStartedAsBubble != (behavior == BEHAVIOR_BUBBLE); TextView done = findViewById(R.id.done); - done.setText(isAChange ? R.string.inline_ok_button : R.string.inline_done_button); + done.setText((isAChange || isABubbleChange) + ? R.string.inline_ok_button + : R.string.inline_done_button); } private void saveImportanceAndExitReason(@NotificationInfoAction int action) { switch (action) { case ACTION_UNDO: mChosenImportance = mStartingChannelImportance; + mChosenBubbleEnabled = mStartedAsBubble; break; case ACTION_DELIVER_SILENTLY: mExitReason = NotificationCounters.BLOCKING_HELPER_DELIVER_SILENTLY; @@ -685,6 +767,9 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G if (mChosenImportance != null) { mStartingChannelImportance = mChosenImportance; } + if (mChosenBubbleEnabled != null) { + mStartedAsBubble = mChosenBubbleEnabled; + } mExitReason = NotificationCounters.BLOCKING_HELPER_DISMISSED; if (mIsForBlockingHelper) { @@ -884,8 +969,9 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G } @Retention(SOURCE) - @IntDef({BEHAVIOR_ALERTING, BEHAVIOR_SILENT}) + @IntDef({BEHAVIOR_ALERTING, BEHAVIOR_SILENT, BEHAVIOR_BUBBLE}) private @interface AlertingBehavior {} private static final int BEHAVIOR_ALERTING = 0; private static final int BEHAVIOR_SILENT = 1; + private static final int BEHAVIOR_BUBBLE = 2; } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationMediaTemplateViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationMediaTemplateViewWrapper.java index d0122c2b59b2..54c71418bd08 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationMediaTemplateViewWrapper.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationMediaTemplateViewWrapper.java @@ -183,6 +183,8 @@ public class NotificationMediaTemplateViewWrapper extends NotificationTemplateVi .getParcelable(Notification.EXTRA_MEDIA_SESSION); if (Utils.useQsMediaPlayer(mContext)) { + final int[] compactActions = mRow.getEntry().getSbn().getNotification().extras + .getIntArray(Notification.EXTRA_COMPACT_ACTIONS); StatusBarWindowController ctrl = Dependency.get(StatusBarWindowController.class); QuickQSPanel panel = ctrl.getStatusBarView().findViewById( com.android.systemui.R.id.quick_qs_panel); @@ -190,7 +192,8 @@ public class NotificationMediaTemplateViewWrapper extends NotificationTemplateVi mRow.getStatusBarNotification().getNotification().getSmallIcon(), getNotificationHeader().getOriginalIconColor(), mRow.getCurrentBackgroundTint(), - mActions); + mActions, + compactActions); QSPanel bigPanel = ctrl.getStatusBarView().findViewById( com.android.systemui.R.id.quick_settings_panel); bigPanel.addMediaSession(token, diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java index dba3b923db4f..ddacc3aedce0 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java @@ -185,6 +185,9 @@ public class Clock extends TextView implements DemoMode, Tunable, CommandQueue.C filter.addAction(Intent.ACTION_CONFIGURATION_CHANGED); filter.addAction(Intent.ACTION_USER_SWITCHED); + // NOTE: This receiver could run before this method returns, as it's not dispatching + // on the main thread and BroadcastDispatcher may not need to register with Context. + // The receiver will return immediately if the view does not have a Handler yet. mBroadcastDispatcher.registerReceiver(mIntentReceiver, filter, Dependency.get(Dependency.TIME_TICK_HANDLER), UserHandle.ALL); Dependency.get(TunerService.class).addTunable(this, CLOCK_SECONDS, @@ -197,11 +200,9 @@ public class Clock extends TextView implements DemoMode, Tunable, CommandQueue.C mCurrentUserId = mCurrentUserTracker.getCurrentUserId(); } - // NOTE: It's safe to do these after registering the receiver since the receiver always runs - // in the main thread, therefore the receiver can't run before this method returns. - // The time zone may have changed while the receiver wasn't registered, so update the Time mCalendar = Calendar.getInstance(TimeZone.getDefault()); + mClockFormatString = ""; // Make sure we update to the current time updateClock(); @@ -227,10 +228,16 @@ public class Clock extends TextView implements DemoMode, Tunable, CommandQueue.C private final BroadcastReceiver mIntentReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { + // If the handler is null, it means we received a broadcast while the view has not + // finished being attached or in the process of being detached. + // In that case, do not post anything. + Handler handler = getHandler(); + if (handler == null) return; + String action = intent.getAction(); if (action.equals(Intent.ACTION_TIMEZONE_CHANGED)) { String tz = intent.getStringExtra("time-zone"); - getHandler().post(() -> { + handler.post(() -> { mCalendar = Calendar.getInstance(TimeZone.getTimeZone(tz)); if (mClockFormat != null) { mClockFormat.setTimeZone(mCalendar.getTimeZone()); @@ -238,14 +245,14 @@ public class Clock extends TextView implements DemoMode, Tunable, CommandQueue.C }); } else if (action.equals(Intent.ACTION_CONFIGURATION_CHANGED)) { final Locale newLocale = getResources().getConfiguration().locale; - getHandler().post(() -> { + handler.post(() -> { if (!newLocale.equals(mLocale)) { mLocale = newLocale; mClockFormatString = ""; // force refresh } }); } - getHandler().post(() -> updateClock()); + handler.post(() -> updateClock()); } }; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java index bae51b6ebd9e..3f25bb63a614 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java @@ -23,6 +23,8 @@ import android.os.Handler; import android.os.Looper; import android.os.Message; import android.provider.Settings.Global; +import android.telephony.CellSignalStrength; +import android.telephony.CellSignalStrengthCdma; import android.telephony.NetworkRegistrationInfo; import android.telephony.PhoneStateListener; import android.telephony.ServiceState; @@ -50,6 +52,7 @@ import java.io.PrintWriter; import java.util.BitSet; import java.util.concurrent.Executor; import java.util.Objects; +import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -477,6 +480,18 @@ public class MobileSignalController extends SignalController< } /** + * Extracts the CellSignalStrengthCdma from SignalStrength then returns the level + */ + private final int getCdmaLevel() { + List<CellSignalStrengthCdma> signalStrengthCdma = + mSignalStrength.getCellSignalStrengths(CellSignalStrengthCdma.class); + if (!signalStrengthCdma.isEmpty()) { + return signalStrengthCdma.get(0).getLevel(); + } + return CellSignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN; + } + + /** * Updates the current state based on mServiceState, mSignalStrength, mDataNetType, * mDataState, and mSimState. It should be called any time one of these is updated. * This will call listeners if necessary. @@ -491,7 +506,7 @@ public class MobileSignalController extends SignalController< && mSignalStrength != null; if (mCurrentState.connected) { if (!mSignalStrength.isGsm() && mConfig.alwaysShowCdmaRssi) { - mCurrentState.level = mSignalStrength.getCdmaLevel(); + mCurrentState.level = getCdmaLevel(); } else { mCurrentState.level = mSignalStrength.getLevel(); } diff --git a/packages/SystemUI/src/com/android/systemui/wm/DisplayWindowController.java b/packages/SystemUI/src/com/android/systemui/wm/DisplayWindowController.java new file mode 100644 index 000000000000..f3487fb5e2d2 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/wm/DisplayWindowController.java @@ -0,0 +1,199 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.wm; + +import android.os.Handler; +import android.os.RemoteException; +import android.util.SparseArray; +import android.view.IDisplayWindowListener; +import android.view.IDisplayWindowRotationCallback; +import android.view.IDisplayWindowRotationController; +import android.view.WindowContainerTransaction; +import android.view.WindowManagerGlobal; + +import com.android.systemui.dagger.qualifiers.MainHandler; + +import java.util.ArrayList; + +import javax.inject.Inject; +import javax.inject.Singleton; + +/** + * This module deals with display rotations coming from WM. When WM starts a rotation: after it has + * frozen the screen, it will call into this class. This will then call all registered local + * controllers and give them a chance to queue up task changes to be applied synchronously with that + * rotation. + */ +@Singleton +public class DisplayWindowController { + private final Handler mHandler; + + private final ArrayList<OnDisplayWindowRotationController> mRotationControllers = + new ArrayList<>(); + private final ArrayList<OnDisplayWindowRotationController> mTmpControllers = new ArrayList<>(); + + private final SparseArray<DisplayRecord> mDisplays = new SparseArray<>(); + private final ArrayList<DisplayWindowListener> mDisplayChangedListeners = new ArrayList<>(); + + private final IDisplayWindowRotationController mDisplayRotationController = + new IDisplayWindowRotationController.Stub() { + @Override + public void onRotateDisplay(int displayId, final int fromRotation, + final int toRotation, IDisplayWindowRotationCallback callback) { + mHandler.post(() -> { + WindowContainerTransaction t = new WindowContainerTransaction(); + synchronized (mRotationControllers) { + mTmpControllers.clear(); + // Make a local copy in case the handlers add/remove themselves. + mTmpControllers.addAll(mRotationControllers); + } + for (OnDisplayWindowRotationController c : mTmpControllers) { + c.onRotateDisplay(displayId, fromRotation, toRotation, t); + } + try { + callback.continueRotateDisplay(toRotation, t); + } catch (RemoteException e) { + } + }); + } + }; + + private final IDisplayWindowListener mDisplayContainerListener = + new IDisplayWindowListener.Stub() { + @Override + public void onDisplayAdded(int displayId) { + mHandler.post(() -> { + synchronized (mDisplays) { + if (mDisplays.get(displayId) != null) { + return; + } + DisplayRecord record = new DisplayRecord(); + record.mDisplayId = displayId; + mDisplays.put(displayId, record); + for (DisplayWindowListener l : mDisplayChangedListeners) { + l.onDisplayAdded(displayId); + } + } + }); + } + + @Override + public void onDisplayRemoved(int displayId) { + mHandler.post(() -> { + synchronized (mDisplays) { + for (int i = mDisplayChangedListeners.size() - 1; i >= 0; --i) { + mDisplayChangedListeners.get(i).onDisplayRemoved(displayId); + } + mDisplays.remove(displayId); + } + }); + } + }; + + @Inject + public DisplayWindowController(@MainHandler Handler mainHandler) { + mHandler = mainHandler; + try { + WindowManagerGlobal.getWindowManagerService().registerDisplayWindowListener( + mDisplayContainerListener); + WindowManagerGlobal.getWindowManagerService().setDisplayWindowRotationController( + mDisplayRotationController); + } catch (RemoteException e) { + throw new RuntimeException("Unable to register hierarchy listener"); + } + } + + /** + * Add a display window-container listener. It will get notified when displays are + * added/removed from the WM hierarchy. + */ + public void addDisplayWindowListener(DisplayWindowListener listener) { + synchronized (mDisplays) { + if (mDisplayChangedListeners.contains(listener)) { + return; + } + mDisplayChangedListeners.add(listener); + for (int i = 0; i < mDisplays.size(); ++i) { + listener.onDisplayAdded(mDisplays.keyAt(i)); + } + } + } + + /** + * Remove a display window-container listener. + */ + public void removeDisplayWindowListener(DisplayWindowListener listener) { + synchronized (mDisplays) { + mDisplayChangedListeners.remove(listener); + } + } + + /** + * Adds a display rotation controller. + */ + public void addRotationController(OnDisplayWindowRotationController controller) { + synchronized (mRotationControllers) { + mRotationControllers.add(controller); + } + } + + /** + * Removes a display rotation controller. + */ + public void removeRotationController(OnDisplayWindowRotationController controller) { + synchronized (mRotationControllers) { + mRotationControllers.remove(controller); + } + } + + private static class DisplayRecord { + int mDisplayId; + } + + /** + * Gets notified when a display is added/removed to the WM hierarchy. + * + * @see IDisplayWindowListener + */ + public interface DisplayWindowListener { + /** + * Called when a display has been added to the WM hierarchy. + */ + void onDisplayAdded(int displayId); + + /** + * Called when a display is removed. + */ + void onDisplayRemoved(int displayId); + } + + /** + * Give a controller a chance to queue up configuration changes to execute as part of a + * display rotation. The contents of {@link #onRotateDisplay} must run synchronously. + */ + public interface OnDisplayWindowRotationController { + /** + * Called before the display is rotated. Contents of this method must run synchronously. + * @param displayId Id of display that is rotating. + * @param fromRotation starting rotation of the display. + * @param toRotation target rotation of the display (after rotating). + * @param t A task transaction to populate. + */ + void onRotateDisplay(int displayId, int fromRotation, int toRotation, + WindowContainerTransaction t); + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/SbnBuilder.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/SbnBuilder.java index 9bc962c77019..fe117fe443a6 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/SbnBuilder.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/SbnBuilder.java @@ -33,6 +33,7 @@ public class SbnBuilder { private int mUid; private int mInitialPid; private Notification mNotification = new Notification(); + private Notification.BubbleMetadata mBubbleMetadata; private UserHandle mUser = UserHandle.of(0); private String mOverrideGroupKey; private long mPostTime; @@ -54,6 +55,9 @@ public class SbnBuilder { } public StatusBarNotification build() { + if (mBubbleMetadata != null) { + mNotification.setBubbleMetadata(mBubbleMetadata); + } return new StatusBarNotification( mPkg, mOpPkg, @@ -116,4 +120,9 @@ public class SbnBuilder { mPostTime = postTime; return this; } + + public SbnBuilder setBubbleMetadata(Notification.BubbleMetadata data) { + mBubbleMetadata = data; + return this; + } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java index bc616c5d7163..0b123fc8ff7e 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java @@ -321,6 +321,7 @@ public class NotificationGutsManagerTest extends SysuiTestCase { .build(); when(row.getIsNonblockable()).thenReturn(false); StatusBarNotification statusBarNotification = row.getStatusBarNotification(); + NotificationEntry entry = row.getEntry(); mGutsManager.initializeNotificationInfo(row, notificationInfoView); @@ -331,7 +332,7 @@ public class NotificationGutsManagerTest extends SysuiTestCase { eq(statusBarNotification.getPackageName()), any(NotificationChannel.class), anySet(), - eq(statusBarNotification), + eq(entry), any(NotificationInfo.CheckSaveListener.class), any(NotificationInfo.OnSettingsClickListener.class), any(NotificationInfo.OnAppSettingsClickListener.class), @@ -352,6 +353,7 @@ public class NotificationGutsManagerTest extends SysuiTestCase { .build(); when(row.getIsNonblockable()).thenReturn(false); StatusBarNotification statusBarNotification = row.getStatusBarNotification(); + NotificationEntry entry = row.getEntry(); mGutsManager.initializeNotificationInfo(row, notificationInfoView); @@ -362,7 +364,7 @@ public class NotificationGutsManagerTest extends SysuiTestCase { eq(statusBarNotification.getPackageName()), any(NotificationChannel.class), anySet(), - eq(statusBarNotification), + eq(entry), any(NotificationInfo.CheckSaveListener.class), any(NotificationInfo.OnSettingsClickListener.class), any(NotificationInfo.OnAppSettingsClickListener.class), @@ -385,6 +387,7 @@ public class NotificationGutsManagerTest extends SysuiTestCase { row.getEntry().setIsHighPriority(true); when(row.getIsNonblockable()).thenReturn(false); StatusBarNotification statusBarNotification = row.getStatusBarNotification(); + NotificationEntry entry = row.getEntry(); mGutsManager.initializeNotificationInfo(row, notificationInfoView); @@ -395,7 +398,7 @@ public class NotificationGutsManagerTest extends SysuiTestCase { eq(statusBarNotification.getPackageName()), any(NotificationChannel.class), anySet(), - eq(statusBarNotification), + eq(entry), any(NotificationInfo.CheckSaveListener.class), any(NotificationInfo.OnSettingsClickListener.class), any(NotificationInfo.OnAppSettingsClickListener.class), @@ -416,6 +419,8 @@ public class NotificationGutsManagerTest extends SysuiTestCase { .build(); when(row.getIsNonblockable()).thenReturn(false); StatusBarNotification statusBarNotification = row.getStatusBarNotification(); + NotificationEntry entry = row.getEntry(); + when(mDeviceProvisionedController.isDeviceProvisioned()).thenReturn(true); mGutsManager.initializeNotificationInfo(row, notificationInfoView); @@ -427,7 +432,7 @@ public class NotificationGutsManagerTest extends SysuiTestCase { eq(statusBarNotification.getPackageName()), any(NotificationChannel.class), anySet(), - eq(statusBarNotification), + eq(entry), any(NotificationInfo.CheckSaveListener.class), any(NotificationInfo.OnSettingsClickListener.class), any(NotificationInfo.OnAppSettingsClickListener.class), @@ -448,6 +453,7 @@ public class NotificationGutsManagerTest extends SysuiTestCase { .build(); when(row.getIsNonblockable()).thenReturn(false); StatusBarNotification statusBarNotification = row.getStatusBarNotification(); + NotificationEntry entry = row.getEntry(); mGutsManager.initializeNotificationInfo(row, notificationInfoView); @@ -458,7 +464,7 @@ public class NotificationGutsManagerTest extends SysuiTestCase { eq(statusBarNotification.getPackageName()), any(NotificationChannel.class), anySet(), - eq(statusBarNotification), + eq(entry), any(NotificationInfo.CheckSaveListener.class), any(NotificationInfo.OnSettingsClickListener.class), any(NotificationInfo.OnAppSettingsClickListener.class), diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInfoTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInfoTest.java index 703adf7a047f..bdca7efeb608 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInfoTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInfoTest.java @@ -16,6 +16,7 @@ package com.android.systemui.statusbar.notification.row; +import static android.app.Notification.FLAG_BUBBLE; import static android.app.NotificationChannel.USER_LOCKED_IMPORTANCE; import static android.app.NotificationManager.IMPORTANCE_DEFAULT; import static android.app.NotificationManager.IMPORTANCE_LOW; @@ -49,10 +50,13 @@ import android.app.INotificationManager; import android.app.Notification; import android.app.NotificationChannel; import android.app.NotificationChannelGroup; +import android.app.PendingIntent; +import android.content.Intent; import android.content.pm.ApplicationInfo; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.graphics.drawable.Drawable; +import android.graphics.drawable.Icon; import android.os.IBinder; import android.os.UserHandle; import android.provider.Settings; @@ -72,7 +76,12 @@ import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.systemui.Dependency; import com.android.systemui.R; import com.android.systemui.SysuiTestCase; +import com.android.systemui.bubbles.BubbleController; +import com.android.systemui.bubbles.BubblesTestActivity; +import com.android.systemui.statusbar.NotificationEntryBuilder; +import com.android.systemui.statusbar.SbnBuilder; import com.android.systemui.statusbar.notification.VisualStabilityManager; +import com.android.systemui.statusbar.notification.collection.NotificationEntry; import org.junit.After; import org.junit.Before; @@ -106,6 +115,9 @@ public class NotificationInfoTest extends SysuiTestCase { private Set<NotificationChannel> mNotificationChannelSet = new HashSet<>(); private Set<NotificationChannel> mDefaultNotificationChannelSet = new HashSet<>(); private StatusBarNotification mSbn; + private NotificationEntry mEntry; + private StatusBarNotification mBubbleSbn; + private NotificationEntry mBubbleEntry; @Rule public MockitoRule mockito = MockitoJUnit.rule(); @@ -119,6 +131,8 @@ public class NotificationInfoTest extends SysuiTestCase { private NotificationBlockingHelperManager mBlockingHelperManager; @Mock private VisualStabilityManager mVisualStabilityManager; + @Mock + private BubbleController mBubbleController; @Before public void setUp() throws Exception { @@ -126,13 +140,18 @@ public class NotificationInfoTest extends SysuiTestCase { NotificationBlockingHelperManager.class, mBlockingHelperManager); mTestableLooper = TestableLooper.get(this); + mDependency.injectTestDependency(Dependency.BG_LOOPER, mTestableLooper.getLooper()); mDependency.injectTestDependency(MetricsLogger.class, mMetricsLogger); + mDependency.injectTestDependency(BubbleController.class, mBubbleController); // Inflate the layout final LayoutInflater layoutInflater = LayoutInflater.from(mContext); mNotificationInfo = (NotificationInfo) layoutInflater.inflate(R.layout.notification_info, null); mNotificationInfo.setGutsParent(mock(NotificationGuts.class)); + // Our view is never attached to a window so the View#post methods in NotificationInfo never + // get called. Setting this will skip the post and do the action immediately. + mNotificationInfo.mSkipPost = true; // PackageManager must return a packageInfo and applicationInfo. final PackageInfo packageInfo = new PackageInfo(); @@ -164,6 +183,16 @@ public class NotificationInfoTest extends SysuiTestCase { mDefaultNotificationChannelSet.add(mDefaultNotificationChannel); mSbn = new StatusBarNotification(TEST_PACKAGE_NAME, TEST_PACKAGE_NAME, 0, null, TEST_UID, 0, new Notification(), UserHandle.CURRENT, null, 0); + mEntry = new NotificationEntryBuilder().setSbn(mSbn).build(); + + PendingIntent bubbleIntent = PendingIntent.getActivity(mContext, 0, + new Intent(mContext, BubblesTestActivity.class), 0); + mBubbleSbn = new SbnBuilder(mSbn).setBubbleMetadata( + new Notification.BubbleMetadata.Builder() + .setIntent(bubbleIntent) + .setIcon(Icon.createWithResource(mContext, R.drawable.android)).build()) + .build(); + mBubbleEntry = new NotificationEntryBuilder().setSbn(mBubbleSbn).build(); Settings.Secure.putInt(mContext.getContentResolver(), NOTIFICATION_NEW_INTERRUPTION_MODEL, 1); @@ -182,17 +211,6 @@ public class NotificationInfoTest extends SysuiTestCase { () -> VISIBLE == mNotificationInfo.findViewById(R.id.confirmation).getVisibility()); } - private void ensureNoUndoButton() { - PollingCheck.waitFor(1000, - () -> GONE == mNotificationInfo.findViewById(R.id.confirmation).getVisibility() - && !mNotificationInfo.isAnimating()); - } - - private void waitForStopButton() { - PollingCheck.waitFor(1000, - () -> VISIBLE == mNotificationInfo.findViewById(R.id.prompt).getVisibility()); - } - @Test public void testBindNotification_SetsTextApplicationName() throws Exception { when(mMockPackageManager.getApplicationLabel(any())).thenReturn("App Name"); @@ -203,7 +221,7 @@ public class NotificationInfoTest extends SysuiTestCase { TEST_PACKAGE_NAME, mNotificationChannel, mNotificationChannelSet, - mSbn, + mEntry, null, null, null, @@ -228,7 +246,7 @@ public class NotificationInfoTest extends SysuiTestCase { TEST_PACKAGE_NAME, mNotificationChannel, mNotificationChannelSet, - mSbn, + mEntry, null, null, null, @@ -249,7 +267,7 @@ public class NotificationInfoTest extends SysuiTestCase { TEST_PACKAGE_NAME, mNotificationChannel, mNotificationChannelSet, - mSbn, + mEntry, null, null, null, @@ -273,6 +291,7 @@ public class NotificationInfoTest extends SysuiTestCase { applicationInfo); when(mMockPackageManager.getApplicationLabel(any())).thenReturn("Other"); + NotificationEntry entry = new NotificationEntryBuilder().setSbn(mSbn).build(); mNotificationInfo.bindNotification( mMockPackageManager, mMockINotificationManager, @@ -280,7 +299,7 @@ public class NotificationInfoTest extends SysuiTestCase { TEST_PACKAGE_NAME, mNotificationChannel, mNotificationChannelSet, - mSbn, + entry, null, null, null, @@ -304,7 +323,7 @@ public class NotificationInfoTest extends SysuiTestCase { TEST_PACKAGE_NAME, mNotificationChannel, mNotificationChannelSet, - mSbn, + mEntry, null, null, null, @@ -331,7 +350,7 @@ public class NotificationInfoTest extends SysuiTestCase { TEST_PACKAGE_NAME, mNotificationChannel, mNotificationChannelSet, - mSbn, + mEntry, null, null, null, @@ -353,7 +372,7 @@ public class NotificationInfoTest extends SysuiTestCase { TEST_PACKAGE_NAME, mNotificationChannel, mNotificationChannelSet, - mSbn, + mEntry, null, null, null, @@ -374,7 +393,7 @@ public class NotificationInfoTest extends SysuiTestCase { TEST_PACKAGE_NAME, mDefaultNotificationChannel, mDefaultNotificationChannelSet, - mSbn, + mEntry, null, null, null, @@ -399,7 +418,7 @@ public class NotificationInfoTest extends SysuiTestCase { TEST_PACKAGE_NAME, mDefaultNotificationChannel, mDefaultNotificationChannelSet, - mSbn, + mEntry, null, null, null, @@ -420,7 +439,7 @@ public class NotificationInfoTest extends SysuiTestCase { TEST_PACKAGE_NAME, mNotificationChannel, mNotificationChannelSet, - mSbn, + mEntry, null, null, null, @@ -441,7 +460,7 @@ public class NotificationInfoTest extends SysuiTestCase { TEST_PACKAGE_NAME, mNotificationChannel, mNotificationChannelSet, - mSbn, + mEntry, null, mock(NotificationInfo.OnSettingsClickListener.class), null, @@ -468,7 +487,7 @@ public class NotificationInfoTest extends SysuiTestCase { TEST_PACKAGE_NAME, mNotificationChannel, mNotificationChannelSet, - mSbn, + mEntry, null, (View v, NotificationChannel c, int appUid) -> { assertEquals(mNotificationChannel, c); @@ -495,7 +514,7 @@ public class NotificationInfoTest extends SysuiTestCase { TEST_PACKAGE_NAME, mNotificationChannel, mNotificationChannelSet, - mSbn, + mEntry, null, null, null, @@ -517,7 +536,7 @@ public class NotificationInfoTest extends SysuiTestCase { TEST_PACKAGE_NAME, mNotificationChannel, mNotificationChannelSet, - mSbn, + mEntry, null, (View v, NotificationChannel c, int appUid) -> { assertEquals(mNotificationChannel, c); @@ -540,7 +559,7 @@ public class NotificationInfoTest extends SysuiTestCase { TEST_PACKAGE_NAME, mNotificationChannel, mNotificationChannelSet, - mSbn, + mEntry, null, null, null, @@ -555,7 +574,7 @@ public class NotificationInfoTest extends SysuiTestCase { TEST_PACKAGE_NAME, mNotificationChannel, mNotificationChannelSet, - mSbn, + mEntry, null, (View v, NotificationChannel c, int appUid) -> { }, null, @@ -576,7 +595,7 @@ public class NotificationInfoTest extends SysuiTestCase { TEST_PACKAGE_NAME, mNotificationChannel, mNotificationChannelSet, - mSbn, + mEntry, null, null, null, @@ -600,7 +619,7 @@ public class NotificationInfoTest extends SysuiTestCase { TEST_PACKAGE_NAME, mNotificationChannel, mNotificationChannelSet, - mSbn, + mEntry, null, null, null, @@ -625,7 +644,7 @@ public class NotificationInfoTest extends SysuiTestCase { TEST_PACKAGE_NAME, mNotificationChannel, mNotificationChannelSet, - mSbn, + mEntry, null, null, null, @@ -647,7 +666,7 @@ public class NotificationInfoTest extends SysuiTestCase { mVisualStabilityManager, TEST_PACKAGE_NAME, mNotificationChannel, createMultipleChannelSet(MULTIPLE_CHANNEL_COUNT), - mSbn, + mEntry, null, (View v, NotificationChannel c, int appUid) -> { assertEquals(null, c); @@ -675,7 +694,7 @@ public class NotificationInfoTest extends SysuiTestCase { TEST_PACKAGE_NAME, mNotificationChannel, createMultipleChannelSet(MULTIPLE_CHANNEL_COUNT), - mSbn, + mEntry, null, null, null, @@ -698,7 +717,7 @@ public class NotificationInfoTest extends SysuiTestCase { TEST_PACKAGE_NAME, mNotificationChannel, createMultipleChannelSet(MULTIPLE_CHANNEL_COUNT), - mSbn, + mEntry, null, null, null, @@ -721,7 +740,7 @@ public class NotificationInfoTest extends SysuiTestCase { TEST_PACKAGE_NAME, mNotificationChannel, mNotificationChannelSet, - mSbn, + mEntry, null, null, null, @@ -738,6 +757,202 @@ public class NotificationInfoTest extends SysuiTestCase { } @Test + public void testBindNotification_alertIsSelected() throws Exception { + mNotificationInfo.bindNotification( + mMockPackageManager, + mMockINotificationManager, + mVisualStabilityManager, + TEST_PACKAGE_NAME, + mNotificationChannel, + mNotificationChannelSet, + mBubbleEntry, + null, + null, + null, + true, + false, + IMPORTANCE_DEFAULT, + true); + assertTrue(mNotificationInfo.findViewById(R.id.alert).isSelected()); + } + + @Test + public void testBindNotification_silenceIsSelected() throws Exception { + mNotificationInfo.bindNotification( + mMockPackageManager, + mMockINotificationManager, + mVisualStabilityManager, + TEST_PACKAGE_NAME, + mNotificationChannel, + mNotificationChannelSet, + mBubbleEntry, + null, + null, + null, + true, + false, + IMPORTANCE_DEFAULT, + false); + assertTrue(mNotificationInfo.findViewById(R.id.silence).isSelected()); + } + + @Test + public void testBindNotification_bubbleIsSelected() throws Exception { + mBubbleEntry.getSbn().getNotification().flags |= FLAG_BUBBLE; + mNotificationInfo.bindNotification( + mMockPackageManager, + mMockINotificationManager, + mVisualStabilityManager, + TEST_PACKAGE_NAME, + mNotificationChannel, + mNotificationChannelSet, + mBubbleEntry, + null, + null, + null, + true, + false, + IMPORTANCE_DEFAULT, + true); + + View bubbleView = mNotificationInfo.findViewById(R.id.bubble); + assertEquals(View.VISIBLE, bubbleView.getVisibility()); + assertTrue(bubbleView.isSelected()); + } + + @Test + public void testBindNotification_whenCanBubble() throws Exception { + mNotificationInfo.bindNotification( + mMockPackageManager, + mMockINotificationManager, + mVisualStabilityManager, + TEST_PACKAGE_NAME, + mNotificationChannel, + mNotificationChannelSet, + mBubbleEntry, + null, + null, + null, + true, + false, + IMPORTANCE_DEFAULT, + true); + + View bubbleView = mNotificationInfo.findViewById(R.id.bubble); + assertEquals(View.VISIBLE, bubbleView.getVisibility()); + assertFalse(bubbleView.isSelected()); + } + + @Test + public void testBindNotification_whenCantBubble() throws Exception { + mNotificationInfo.bindNotification( + mMockPackageManager, + mMockINotificationManager, + mVisualStabilityManager, + TEST_PACKAGE_NAME, + mNotificationChannel, + mNotificationChannelSet, + mEntry, + null, + null, + null, + true, + false, + IMPORTANCE_DEFAULT, + true); + View bubbleView = mNotificationInfo.findViewById(R.id.bubble); + assertEquals(View.GONE, bubbleView.getVisibility()); + } + + @Test + public void testBubble_promotesBubble() throws Exception { + mNotificationInfo.bindNotification( + mMockPackageManager, + mMockINotificationManager, + mVisualStabilityManager, + TEST_PACKAGE_NAME, + mNotificationChannel, + mNotificationChannelSet, + mBubbleEntry, + null, + null, + null, + true, + false, + IMPORTANCE_DEFAULT, + true); + + assertFalse(mBubbleEntry.isBubble()); + + // Promote it + mNotificationInfo.findViewById(R.id.bubble).performClick(); + mNotificationInfo.findViewById(R.id.done).performClick(); + mNotificationInfo.handleCloseControls(true, false); + + verify(mBubbleController, times(1)).onUserCreatedBubbleFromNotification(mBubbleEntry); + } + + @Test + public void testAlert_demotesBubble() throws Exception { + mBubbleEntry.getSbn().getNotification().flags |= FLAG_BUBBLE; + + mNotificationInfo.bindNotification( + mMockPackageManager, + mMockINotificationManager, + mVisualStabilityManager, + TEST_PACKAGE_NAME, + mNotificationChannel, + mNotificationChannelSet, + mBubbleEntry, + null, + null, + null, + true, + false, + IMPORTANCE_DEFAULT, + true); + + assertTrue(mBubbleEntry.isBubble()); + + // Demote it + mNotificationInfo.findViewById(R.id.alert).performClick(); + mNotificationInfo.findViewById(R.id.done).performClick(); + mNotificationInfo.handleCloseControls(true, false); + + verify(mBubbleController, times(1)).onUserDemotedBubbleFromNotification(mBubbleEntry); + } + + @Test + public void testSilence_demotesBubble() throws Exception { + mBubbleEntry.getSbn().getNotification().flags |= FLAG_BUBBLE; + + mNotificationInfo.bindNotification( + mMockPackageManager, + mMockINotificationManager, + mVisualStabilityManager, + TEST_PACKAGE_NAME, + mNotificationChannel, + mNotificationChannelSet, + mBubbleEntry, + null, + null, + null, + true, + false, + IMPORTANCE_DEFAULT, + true); + + assertTrue(mBubbleEntry.isBubble()); + + // Demote it + mNotificationInfo.findViewById(R.id.silence).performClick(); + mNotificationInfo.findViewById(R.id.done).performClick(); + mNotificationInfo.handleCloseControls(true, false); + + verify(mBubbleController, times(1)).onUserDemotedBubbleFromNotification(mBubbleEntry); + } + + @Test public void testBindNotification_DoesNotUpdateNotificationChannel() throws Exception { mNotificationInfo.bindNotification( mMockPackageManager, @@ -746,7 +961,7 @@ public class NotificationInfoTest extends SysuiTestCase { TEST_PACKAGE_NAME, mNotificationChannel, mNotificationChannelSet, - mSbn, + mEntry, null, null, null, @@ -769,7 +984,7 @@ public class NotificationInfoTest extends SysuiTestCase { TEST_PACKAGE_NAME, mNotificationChannel, mNotificationChannelSet, - mSbn, + mEntry, null, null, null, @@ -795,7 +1010,7 @@ public class NotificationInfoTest extends SysuiTestCase { TEST_PACKAGE_NAME, mNotificationChannel, mNotificationChannelSet, - mSbn, + mEntry, null, null, null, @@ -821,7 +1036,7 @@ public class NotificationInfoTest extends SysuiTestCase { TEST_PACKAGE_NAME, mNotificationChannel, mNotificationChannelSet, - mSbn, + mEntry, null, null, null, @@ -848,7 +1063,7 @@ public class NotificationInfoTest extends SysuiTestCase { TEST_PACKAGE_NAME, mNotificationChannel, mNotificationChannelSet, - mSbn, + mEntry, null, null, null, @@ -878,7 +1093,7 @@ public class NotificationInfoTest extends SysuiTestCase { TEST_PACKAGE_NAME, mNotificationChannel /* notificationChannel */, createMultipleChannelSet(10) /* numUniqueChannelsInRow */, - mSbn, + mEntry, listener /* checkSaveListener */, null /* onSettingsClick */, null /* onAppSettingsClick */, @@ -917,7 +1132,7 @@ public class NotificationInfoTest extends SysuiTestCase { TEST_PACKAGE_NAME, mNotificationChannel /* notificationChannel */, createMultipleChannelSet(10) /* numUniqueChannelsInRow */, - mSbn, + mEntry, listener /* checkSaveListener */, null /* onSettingsClick */, null /* onAppSettingsClick */, @@ -945,7 +1160,7 @@ public class NotificationInfoTest extends SysuiTestCase { TEST_PACKAGE_NAME, mNotificationChannel /* notificationChannel */, createMultipleChannelSet(10) /* numUniqueChannelsInRow */, - mSbn, + mEntry, listener /* checkSaveListener */, null /* onSettingsClick */, null /* onAppSettingsClick */, @@ -970,7 +1185,7 @@ public class NotificationInfoTest extends SysuiTestCase { TEST_PACKAGE_NAME, mNotificationChannel, mNotificationChannelSet /* numChannels */, - mSbn, + mEntry, null /* checkSaveListener */, null /* onSettingsClick */, null /* onAppSettingsClick */, @@ -999,7 +1214,7 @@ public class NotificationInfoTest extends SysuiTestCase { TEST_PACKAGE_NAME, mNotificationChannel, mNotificationChannelSet /* numChannels */, - mSbn, + mEntry, null /* checkSaveListener */, null /* onSettingsClick */, null /* onAppSettingsClick */, @@ -1033,7 +1248,7 @@ public class NotificationInfoTest extends SysuiTestCase { TEST_PACKAGE_NAME, mNotificationChannel, mNotificationChannelSet, - mSbn, + mEntry, null, null, null, @@ -1064,7 +1279,7 @@ public class NotificationInfoTest extends SysuiTestCase { TEST_PACKAGE_NAME, mNotificationChannel, mNotificationChannelSet, - mSbn, + mEntry, null, null, null, @@ -1094,7 +1309,7 @@ public class NotificationInfoTest extends SysuiTestCase { TEST_PACKAGE_NAME, mNotificationChannel, mNotificationChannelSet, - mSbn, + mEntry, null, null, null, @@ -1127,7 +1342,7 @@ public class NotificationInfoTest extends SysuiTestCase { TEST_PACKAGE_NAME, mNotificationChannel, mNotificationChannelSet, - mSbn, + mEntry, null, null, null, @@ -1161,7 +1376,7 @@ public class NotificationInfoTest extends SysuiTestCase { TEST_PACKAGE_NAME, mNotificationChannel, mNotificationChannelSet, - mSbn, + mEntry, null, null, null, @@ -1195,7 +1410,7 @@ public class NotificationInfoTest extends SysuiTestCase { TEST_PACKAGE_NAME, mNotificationChannel, mNotificationChannelSet, - mSbn, + mEntry, null, null, null, @@ -1232,7 +1447,7 @@ public class NotificationInfoTest extends SysuiTestCase { TEST_PACKAGE_NAME, mNotificationChannel, mNotificationChannelSet, - mSbn, + mEntry, null, null, null, @@ -1268,7 +1483,7 @@ public class NotificationInfoTest extends SysuiTestCase { TEST_PACKAGE_NAME, mNotificationChannel, mNotificationChannelSet, - mSbn, + mEntry, null, null, null, @@ -1295,7 +1510,7 @@ public class NotificationInfoTest extends SysuiTestCase { TEST_PACKAGE_NAME, mNotificationChannel, mNotificationChannelSet, - mSbn, + mEntry, null, null, null, @@ -1325,7 +1540,7 @@ public class NotificationInfoTest extends SysuiTestCase { TEST_PACKAGE_NAME, mNotificationChannel, mNotificationChannelSet, - mSbn, + mEntry, null, null, null, @@ -1358,7 +1573,7 @@ public class NotificationInfoTest extends SysuiTestCase { TEST_PACKAGE_NAME, mNotificationChannel, mNotificationChannelSet, - mSbn, + mEntry, null, null, null, @@ -1386,7 +1601,7 @@ public class NotificationInfoTest extends SysuiTestCase { TEST_PACKAGE_NAME, mNotificationChannel, mNotificationChannelSet, - mSbn, + mEntry, (Runnable saveImportance, StatusBarNotification sbn) -> { saveImportance.run(); }, @@ -1421,7 +1636,7 @@ public class NotificationInfoTest extends SysuiTestCase { TEST_PACKAGE_NAME, mNotificationChannel, mNotificationChannelSet, - mSbn, + mEntry, (Runnable saveImportance, StatusBarNotification sbn) -> { saveImportance.run(); }, @@ -1449,7 +1664,7 @@ public class NotificationInfoTest extends SysuiTestCase { TEST_PACKAGE_NAME, mNotificationChannel, mNotificationChannelSet, - mSbn, + mEntry, (Runnable saveImportance, StatusBarNotification sbn) -> { saveImportance.run(); }, diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index aeff9ea50b11..4bb29f014d0e 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -24,6 +24,7 @@ import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL; import static android.Manifest.permission.REMOVE_TASKS; import static android.Manifest.permission.START_ACTIVITIES_FROM_BACKGROUND; import static android.app.ActivityManager.INSTR_FLAG_DISABLE_HIDDEN_API_CHECKS; +import static android.app.ActivityManager.INSTR_FLAG_DISABLE_TEST_API_CHECKS; import static android.app.ActivityManager.INSTR_FLAG_MOUNT_EXTERNAL_STORAGE_FULL; import static android.app.ActivityManager.PROCESS_STATE_LAST_ACTIVITY; import static android.app.ActivityManager.PROCESS_STATE_NONEXISTENT; @@ -16060,13 +16061,12 @@ public class ActivityManagerService extends IActivityManager.Stub boolean disableHiddenApiChecks = ai.usesNonSdkApi() || (flags & INSTR_FLAG_DISABLE_HIDDEN_API_CHECKS) != 0; - if (disableHiddenApiChecks) { + boolean disableTestApiChecks = disableHiddenApiChecks + || (flags & INSTR_FLAG_DISABLE_TEST_API_CHECKS) != 0; + if (disableHiddenApiChecks || disableTestApiChecks) { enforceCallingPermission(android.Manifest.permission.DISABLE_HIDDEN_API_CHECKS, "disable hidden API checks"); } - // Allow instrumented processes access to test APIs. - // TODO(satayev): make this configurable via testing framework. - boolean disableTestApiChecks = true; final boolean mountExtStorageFull = isCallerShell() && (flags & INSTR_FLAG_MOUNT_EXTERNAL_STORAGE_FULL) != 0; diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java index 59acdcf4a875..1f56176bf00d 100644 --- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java +++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java @@ -3028,7 +3028,8 @@ final class ActivityManagerShellCommand extends ShellCommand { pw.println(" --allow-background-activity-starts: The receiver may start activities"); pw.println(" even if in the background."); pw.println(" instrument [-r] [-e <NAME> <VALUE>] [-p <FILE>] [-w]"); - pw.println(" [--user <USER_ID> | current] [--no-hidden-api-checks]"); + pw.println(" [--user <USER_ID> | current]"); + pw.println(" [--no-hidden-api-checks [--no-test-api-checks]]"); pw.println(" [--no-isolated-storage]"); pw.println(" [--no-window-animation] [--abi <ABI>] <COMPONENT>"); pw.println(" Start an Instrumentation. Typically this target <COMPONENT> is in the"); @@ -3048,6 +3049,8 @@ final class ActivityManagerShellCommand extends ShellCommand { pw.println(" --user <USER_ID> | current: Specify user instrumentation runs in;"); pw.println(" current user if not specified."); pw.println(" --no-hidden-api-checks: disable restrictions on use of hidden API."); + pw.println(" --no-test-api-checks: disable restrictions to test APIs, if hidden"); + pw.println(" API checks are enabled."); pw.println(" --no-isolated-storage: don't use isolated storage sandbox and "); pw.println(" mount full external storage"); pw.println(" --no-window-animation: turn off window animations while running."); diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java index d09139c0589c..9fa572f9fe9a 100644 --- a/services/core/java/com/android/server/audio/AudioService.java +++ b/services/core/java/com/android/server/audio/AudioService.java @@ -772,6 +772,8 @@ public class AudioService extends IAudioService.Stub readAndSetLowRamDevice(); + mIsCallScreeningModeSupported = AudioSystem.isCallScreeningModeSupported(); + // Call setRingerModeInt() to apply correct mute // state on streams affected by ringer mode. mRingerAndZenModeMutedStreams = 0; @@ -965,6 +967,8 @@ public class AudioService extends IAudioService.Stub readAndSetLowRamDevice(); + mIsCallScreeningModeSupported = AudioSystem.isCallScreeningModeSupported(); + // Restore device connection states, BT state mDeviceBroker.onAudioServerDied(); @@ -1469,10 +1473,13 @@ public class AudioService extends IAudioService.Stub } if (!TextUtils.isEmpty(packageName)) { PackageManager pm = mContext.getPackageManager(); + ActivityManager am = + (ActivityManager) mContext.getSystemService(mContext.ACTIVITY_SERVICE); + if (pm.checkPermission(Manifest.permission.CAPTURE_AUDIO_HOTWORD, packageName) == PackageManager.PERMISSION_GRANTED) { try { - assistantUid = pm.getPackageUid(packageName, 0); + assistantUid = pm.getPackageUidAsUser(packageName, am.getCurrentUser()); } catch (PackageManager.NameNotFoundException e) { Log.e(TAG, "updateAssistantUId() could not find UID for package: " + packageName); @@ -3287,6 +3294,12 @@ public class AudioService extends IAudioService.Stub return; } + if (mode == AudioSystem.MODE_CALL_SCREENING && !mIsCallScreeningModeSupported) { + Log.w(TAG, "setMode(MODE_CALL_SCREENING) not permitted " + + "when call screening is not supported"); + return; + } + if (mode < AudioSystem.MODE_CURRENT || mode >= AudioSystem.NUM_MODES) { return; } @@ -3417,6 +3430,14 @@ public class AudioService extends IAudioService.Stub return mMode; } + /** cached value read from audiopolicy manager after initialization. */ + private boolean mIsCallScreeningModeSupported = false; + + /** @see AudioManager#isCallScreeningModeSupported() */ + public boolean isCallScreeningModeSupported() { + return mIsCallScreeningModeSupported; + } + //========================================================================================== // Sound Effects //========================================================================================== @@ -6149,6 +6170,7 @@ public class AudioService extends IAudioService.Stub pw.print(" mHdmiPlaybackClient="); pw.println(mHdmiPlaybackClient); pw.print(" mHdmiTvClient="); pw.println(mHdmiTvClient); pw.print(" mHdmiSystemAudioSupported="); pw.println(mHdmiSystemAudioSupported); + pw.print(" mIsCallScreeningModeSupported="); pw.println(mIsCallScreeningModeSupported); dumpAudioPolicies(pw); mDynPolicyLogger.dump(pw); diff --git a/services/core/java/com/android/server/content/SyncStorageEngine.java b/services/core/java/com/android/server/content/SyncStorageEngine.java index ebaa5a1bd475..dea47db62b9c 100644 --- a/services/core/java/com/android/server/content/SyncStorageEngine.java +++ b/services/core/java/com/android/server/content/SyncStorageEngine.java @@ -51,6 +51,8 @@ import android.util.Pair; import android.util.Slog; import android.util.SparseArray; import android.util.Xml; +import android.util.proto.ProtoInputStream; +import android.util.proto.ProtoOutputStream; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.ArrayUtils; @@ -64,6 +66,9 @@ import org.xmlpull.v1.XmlSerializer; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.Calendar; @@ -428,7 +433,8 @@ public class SyncStorageEngine { } // Primary list of all syncable authorities. Also our global lock. - private final SparseArray<AuthorityInfo> mAuthorities = + @VisibleForTesting + final SparseArray<AuthorityInfo> mAuthorities = new SparseArray<AuthorityInfo>(); private final HashMap<AccountAndUser, AccountInfo> mAccounts @@ -437,7 +443,8 @@ public class SyncStorageEngine { private final SparseArray<ArrayList<SyncInfo>> mCurrentSyncs = new SparseArray<ArrayList<SyncInfo>>(); - private final SparseArray<SyncStatusInfo> mSyncStatus = + @VisibleForTesting + final SparseArray<SyncStatusInfo> mSyncStatus = new SparseArray<SyncStatusInfo>(); private final ArrayList<SyncHistoryItem> mSyncHistory = @@ -453,7 +460,8 @@ public class SyncStorageEngine { private int mNextAuthorityId = 0; // We keep 4 weeks of stats. - private final DayStats[] mDayStats = new DayStats[7*4]; + @VisibleForTesting + final DayStats[] mDayStats = new DayStats[7*4]; private final Calendar mCal; private int mYear; private int mYearInDays; @@ -464,6 +472,18 @@ public class SyncStorageEngine { private int mSyncRandomOffset; + // STOPSHIP: b/143656271 this should be true on launch + private static final boolean DELETE_LEGACY_PARCEL_FILES = false; + private static final String LEGACY_STATUS_FILE_NAME = "status.bin"; + private static final String LEGACY_STATISTICS_FILE_NAME = "stats.bin"; + + private static final String SYNC_DIR_NAME = "sync"; + private static final String ACCOUNT_INFO_FILE_NAME = "accounts.xml"; + private static final String STATUS_FILE_NAME = "status"; + private static final String STATISTICS_FILE_NAME = "stats"; + + private File mSyncDir; + /** * This file contains the core engine state: all accounts and the * settings for them. It must never be lost, and should be changed @@ -508,14 +528,15 @@ public class SyncStorageEngine { com.android.internal.R.bool.config_syncstorageengine_masterSyncAutomatically); File systemDir = new File(dataDir, "system"); - File syncDir = new File(systemDir, "sync"); - syncDir.mkdirs(); + mSyncDir = new File(systemDir, SYNC_DIR_NAME); + mSyncDir.mkdirs(); - maybeDeleteLegacyPendingInfoLocked(syncDir); + maybeDeleteLegacyPendingInfoLocked(mSyncDir); - mAccountInfoFile = new AtomicFile(new File(syncDir, "accounts.xml"), "sync-accounts"); - mStatusFile = new AtomicFile(new File(syncDir, "status.bin"), "sync-status"); - mStatisticsFile = new AtomicFile(new File(syncDir, "stats.bin"), "sync-stats"); + mAccountInfoFile = new AtomicFile(new File(mSyncDir, ACCOUNT_INFO_FILE_NAME), + "sync-accounts"); + mStatusFile = new AtomicFile(new File(mSyncDir, STATUS_FILE_NAME), "sync-status"); + mStatisticsFile = new AtomicFile(new File(mSyncDir, STATISTICS_FILE_NAME), "sync-stats"); readAccountInfoLocked(); readStatusLocked(); @@ -2017,15 +2038,10 @@ public class SyncStorageEngine { public static final int STATUS_FILE_END = 0; public static final int STATUS_FILE_ITEM = 100; - /** - * Read all sync status back in to the initial engine state. - */ - private void readStatusLocked() { - if (Log.isLoggable(TAG_FILE, Log.VERBOSE)) { - Slog.v(TAG_FILE, "Reading " + mStatusFile.getBaseFile()); - } + private void readStatusParcelLocked(File parcel) { try { - byte[] data = mStatusFile.readFully(); + final AtomicFile parcelFile = new AtomicFile(parcel); + byte[] data = parcelFile.readFully(); Parcel in = Parcel.obtain(); in.unmarshall(data, 0, data.length); in.setDataPosition(0); @@ -2036,9 +2052,6 @@ public class SyncStorageEngine { SyncStatusInfo status = new SyncStatusInfo(in); if (mAuthorities.indexOfKey(status.authorityId) >= 0) { status.pending = false; - if (Log.isLoggable(TAG_FILE, Log.VERBOSE)) { - Slog.v(TAG_FILE, "Adding status for id " + status.authorityId); - } mSyncStatus.put(status.authorityId, status); } } catch (Exception e) { @@ -2050,15 +2063,247 @@ public class SyncStorageEngine { break; } } - } catch (java.io.IOException e) { + } catch (IOException e) { Slog.i(TAG, "No initial status"); } } + private void upgradeStatusIfNeededLocked() { + final File parcelStatus = new File(mSyncDir, LEGACY_STATUS_FILE_NAME); + if (parcelStatus.exists() && !mStatusFile.exists()) { + readStatusParcelLocked(parcelStatus); + writeStatusLocked(); + } + + // if upgrade to proto was successful, delete parcel file + if (DELETE_LEGACY_PARCEL_FILES && mStatusFile.exists()) { + parcelStatus.delete(); + } + } + + /** + * Read all sync status back in to the initial engine state. + */ + @VisibleForTesting + void readStatusLocked() { + upgradeStatusIfNeededLocked(); + + if (!mStatusFile.exists()) { + return; + } + try { + try (FileInputStream in = mStatusFile.openRead()) { + readStatusInfoLocked(in); + } + } catch (IOException e) { + Slog.e(TAG, "Unable to read status info file.", e); + } + } + + private void readStatusInfoLocked(InputStream in) throws IOException { + final ProtoInputStream proto = new ProtoInputStream(in); + while (true) { + switch (proto.nextField()) { + case (int) SyncStatusProto.STATUS: + final long token = proto.start(SyncStatusProto.STATUS); + final SyncStatusInfo status = readSyncStatusInfoLocked(proto); + proto.end(token); + if (mAuthorities.indexOfKey(status.authorityId) >= 0) { + status.pending = false; + mSyncStatus.put(status.authorityId, status); + } + break; + case ProtoInputStream.NO_MORE_FIELDS: + return; + } + } + } + + private SyncStatusInfo readSyncStatusInfoLocked(ProtoInputStream proto) throws IOException { + SyncStatusInfo status; + if (proto.nextField(SyncStatusProto.StatusInfo.AUTHORITY_ID)) { + //fast-path; this should work for most cases since the authority id is written first + status = new SyncStatusInfo(proto.readInt(SyncStatusProto.StatusInfo.AUTHORITY_ID)); + } else { + // placeholder to read other data; assume the default authority id as 0 + status = new SyncStatusInfo(0); + } + + int successTimesCount = 0; + int failureTimesCount = 0; + ArrayList<Pair<Long, String>> lastEventInformation = new ArrayList<>(); + while (true) { + switch (proto.nextField()) { + case (int) SyncStatusProto.StatusInfo.AUTHORITY_ID: + // fast-path failed for some reason, rebuild the status from placeholder object + Slog.w(TAG, "Failed to read the authority id via fast-path; " + + "some data might not have been read."); + status = new SyncStatusInfo( + proto.readInt(SyncStatusProto.StatusInfo.AUTHORITY_ID), status); + break; + case (int) SyncStatusProto.StatusInfo.LAST_SUCCESS_TIME: + status.lastSuccessTime = proto.readLong( + SyncStatusProto.StatusInfo.LAST_SUCCESS_TIME); + break; + case (int) SyncStatusProto.StatusInfo.LAST_SUCCESS_SOURCE: + status.lastSuccessSource = proto.readInt( + SyncStatusProto.StatusInfo.LAST_SUCCESS_SOURCE); + break; + case (int) SyncStatusProto.StatusInfo.LAST_FAILURE_TIME: + status.lastFailureTime = proto.readLong( + SyncStatusProto.StatusInfo.LAST_FAILURE_TIME); + break; + case (int) SyncStatusProto.StatusInfo.LAST_FAILURE_SOURCE: + status.lastFailureSource = proto.readInt( + SyncStatusProto.StatusInfo.LAST_FAILURE_SOURCE); + break; + case (int) SyncStatusProto.StatusInfo.LAST_FAILURE_MESSAGE: + status.lastFailureMesg = proto.readString( + SyncStatusProto.StatusInfo.LAST_FAILURE_MESSAGE); + break; + case (int) SyncStatusProto.StatusInfo.INITIAL_FAILURE_TIME: + status.initialFailureTime = proto.readLong( + SyncStatusProto.StatusInfo.INITIAL_FAILURE_TIME); + break; + case (int) SyncStatusProto.StatusInfo.PENDING: + status.pending = proto.readBoolean(SyncStatusProto.StatusInfo.PENDING); + break; + case (int) SyncStatusProto.StatusInfo.INITIALIZE: + status.initialize = proto.readBoolean(SyncStatusProto.StatusInfo.INITIALIZE); + break; + case (int) SyncStatusProto.StatusInfo.PERIODIC_SYNC_TIMES: + status.addPeriodicSyncTime( + proto.readLong(SyncStatusProto.StatusInfo.PERIODIC_SYNC_TIMES)); + break; + case (int) SyncStatusProto.StatusInfo.LAST_EVENT_INFO: + final long eventToken = proto.start(SyncStatusProto.StatusInfo.LAST_EVENT_INFO); + final Pair<Long, String> lastEventInfo = parseLastEventInfoLocked(proto); + if (lastEventInfo != null) { + lastEventInformation.add(lastEventInfo); + } + proto.end(eventToken); + break; + case (int) SyncStatusProto.StatusInfo.LAST_TODAY_RESET_TIME: + status.lastTodayResetTime = proto.readLong( + SyncStatusProto.StatusInfo.LAST_TODAY_RESET_TIME); + break; + case (int) SyncStatusProto.StatusInfo.TOTAL_STATS: + final long totalStatsToken = proto.start( + SyncStatusProto.StatusInfo.TOTAL_STATS); + readSyncStatusStatsLocked(proto, status.totalStats); + proto.end(totalStatsToken); + break; + case (int) SyncStatusProto.StatusInfo.TODAY_STATS: + final long todayStatsToken = proto.start( + SyncStatusProto.StatusInfo.TODAY_STATS); + readSyncStatusStatsLocked(proto, status.todayStats); + proto.end(todayStatsToken); + break; + case (int) SyncStatusProto.StatusInfo.YESTERDAY_STATS: + final long yesterdayStatsToken = proto.start( + SyncStatusProto.StatusInfo.YESTERDAY_STATS); + readSyncStatusStatsLocked(proto, status.yesterdayStats); + proto.end(yesterdayStatsToken); + break; + case (int) SyncStatusProto.StatusInfo.PER_SOURCE_LAST_SUCCESS_TIMES: + final long successTime = proto.readLong( + SyncStatusProto.StatusInfo.PER_SOURCE_LAST_SUCCESS_TIMES); + if (successTimesCount == status.perSourceLastSuccessTimes.length) { + Slog.w(TAG, "Attempted to read more per source last success times " + + "than expected; data might be corrupted."); + break; + } + status.perSourceLastSuccessTimes[successTimesCount] = successTime; + successTimesCount++; + break; + case (int) SyncStatusProto.StatusInfo.PER_SOURCE_LAST_FAILURE_TIMES: + final long failureTime = proto.readLong( + SyncStatusProto.StatusInfo.PER_SOURCE_LAST_FAILURE_TIMES); + if (failureTimesCount == status.perSourceLastFailureTimes.length) { + Slog.w(TAG, "Attempted to read more per source last failure times " + + "than expected; data might be corrupted."); + break; + } + status.perSourceLastFailureTimes[failureTimesCount] = failureTime; + failureTimesCount++; + break; + case ProtoInputStream.NO_MORE_FIELDS: + status.populateLastEventsInformation(lastEventInformation); + return status; + } + } + } + + private Pair<Long, String> parseLastEventInfoLocked(ProtoInputStream proto) throws IOException { + long time = 0; + String message = null; + while (true) { + switch (proto.nextField()) { + case (int) SyncStatusProto.StatusInfo.LastEventInfo.LAST_EVENT_TIME: + time = proto.readLong(SyncStatusProto.StatusInfo.LastEventInfo.LAST_EVENT_TIME); + break; + case (int) SyncStatusProto.StatusInfo.LastEventInfo.LAST_EVENT: + message = proto.readString(SyncStatusProto.StatusInfo.LastEventInfo.LAST_EVENT); + break; + case ProtoInputStream.NO_MORE_FIELDS: + return message == null ? null : new Pair<>(time, message); + } + } + } + + private void readSyncStatusStatsLocked(ProtoInputStream proto, SyncStatusInfo.Stats stats) + throws IOException { + while (true) { + switch (proto.nextField()) { + case (int) SyncStatusProto.StatusInfo.Stats.TOTAL_ELAPSED_TIME: + stats.totalElapsedTime = proto.readLong( + SyncStatusProto.StatusInfo.Stats.TOTAL_ELAPSED_TIME); + break; + case (int) SyncStatusProto.StatusInfo.Stats.NUM_SYNCS: + stats.numSyncs = proto.readInt(SyncStatusProto.StatusInfo.Stats.NUM_SYNCS); + break; + case (int) SyncStatusProto.StatusInfo.Stats.NUM_FAILURES: + stats.numFailures = proto.readInt( + SyncStatusProto.StatusInfo.Stats.NUM_FAILURES); + break; + case (int) SyncStatusProto.StatusInfo.Stats.NUM_CANCELS: + stats.numCancels = proto.readInt(SyncStatusProto.StatusInfo.Stats.NUM_CANCELS); + break; + case (int) SyncStatusProto.StatusInfo.Stats.NUM_SOURCE_OTHER: + stats.numSourceOther = proto.readInt( + SyncStatusProto.StatusInfo.Stats.NUM_SOURCE_OTHER); + break; + case (int) SyncStatusProto.StatusInfo.Stats.NUM_SOURCE_LOCAL: + stats.numSourceLocal = proto.readInt( + SyncStatusProto.StatusInfo.Stats.NUM_SOURCE_LOCAL); + break; + case (int) SyncStatusProto.StatusInfo.Stats.NUM_SOURCE_POLL: + stats.numSourcePoll = proto.readInt( + SyncStatusProto.StatusInfo.Stats.NUM_SOURCE_POLL); + break; + case (int) SyncStatusProto.StatusInfo.Stats.NUM_SOURCE_USER: + stats.numSourceUser = proto.readInt( + SyncStatusProto.StatusInfo.Stats.NUM_SOURCE_USER); + break; + case (int) SyncStatusProto.StatusInfo.Stats.NUM_SOURCE_PERIODIC: + stats.numSourcePeriodic = proto.readInt( + SyncStatusProto.StatusInfo.Stats.NUM_SOURCE_PERIODIC); + break; + case (int) SyncStatusProto.StatusInfo.Stats.NUM_SOURCE_FEED: + stats.numSourceFeed = proto.readInt( + SyncStatusProto.StatusInfo.Stats.NUM_SOURCE_FEED); + break; + case ProtoInputStream.NO_MORE_FIELDS: + return; + } + } + } + /** * Write all sync status to the sync status file. */ - private void writeStatusLocked() { + @VisibleForTesting + void writeStatusLocked() { if (Log.isLoggable(TAG_FILE, Log.VERBOSE)) { Slog.v(TAG_FILE, "Writing new " + mStatusFile.getBaseFile()); } @@ -2070,24 +2315,85 @@ public class SyncStorageEngine { FileOutputStream fos = null; try { fos = mStatusFile.startWrite(); - Parcel out = Parcel.obtain(); - final int N = mSyncStatus.size(); - for (int i=0; i<N; i++) { - SyncStatusInfo status = mSyncStatus.valueAt(i); - out.writeInt(STATUS_FILE_ITEM); - status.writeToParcel(out, 0); - } - out.writeInt(STATUS_FILE_END); - fos.write(out.marshall()); - out.recycle(); - + writeStatusInfoLocked(fos); mStatusFile.finishWrite(fos); - } catch (java.io.IOException e1) { - Slog.w(TAG, "Error writing status", e1); - if (fos != null) { - mStatusFile.failWrite(fos); - } - } + fos = null; + } catch (IOException | IllegalArgumentException e) { + Slog.e(TAG, "Unable to write sync status to proto.", e); + } finally { + // when fos is null (successful write), this is a no-op. + mStatusFile.failWrite(fos); + } + } + + private void writeStatusInfoLocked(OutputStream out) { + final ProtoOutputStream proto = new ProtoOutputStream(out); + final int size = mSyncStatus.size(); + for (int i = 0; i < size; i++) { + final SyncStatusInfo info = mSyncStatus.valueAt(i); + final long token = proto.start(SyncStatusProto.STATUS); + // authority id should be written first to take advantage of the fast path in read + proto.write(SyncStatusProto.StatusInfo.AUTHORITY_ID, info.authorityId); + proto.write(SyncStatusProto.StatusInfo.LAST_SUCCESS_TIME, info.lastSuccessTime); + proto.write(SyncStatusProto.StatusInfo.LAST_SUCCESS_SOURCE, info.lastSuccessSource); + proto.write(SyncStatusProto.StatusInfo.LAST_FAILURE_TIME, info.lastFailureTime); + proto.write(SyncStatusProto.StatusInfo.LAST_FAILURE_SOURCE, info.lastFailureSource); + proto.write(SyncStatusProto.StatusInfo.LAST_FAILURE_MESSAGE, info.lastFailureMesg); + proto.write(SyncStatusProto.StatusInfo.INITIAL_FAILURE_TIME, info.initialFailureTime); + proto.write(SyncStatusProto.StatusInfo.PENDING, info.pending); + proto.write(SyncStatusProto.StatusInfo.INITIALIZE, info.initialize); + final int periodicSyncTimesSize = info.getPeriodicSyncTimesSize(); + for (int j = 0; j < periodicSyncTimesSize; j++) { + proto.write(SyncStatusProto.StatusInfo.PERIODIC_SYNC_TIMES, + info.getPeriodicSyncTime(j)); + } + final int lastEventsSize = info.getEventCount(); + for (int j = 0; j < lastEventsSize; j++) { + final long eventToken = proto.start(SyncStatusProto.StatusInfo.LAST_EVENT_INFO); + proto.write(SyncStatusProto.StatusInfo.LastEventInfo.LAST_EVENT_TIME, + info.getEventTime(j)); + proto.write(SyncStatusProto.StatusInfo.LastEventInfo.LAST_EVENT, info.getEvent(j)); + proto.end(eventToken); + } + proto.write(SyncStatusProto.StatusInfo.LAST_TODAY_RESET_TIME, info.lastTodayResetTime); + + final long totalStatsToken = proto.start(SyncStatusProto.StatusInfo.TOTAL_STATS); + writeStatusStatsLocked(proto, info.totalStats); + proto.end(totalStatsToken); + final long todayStatsToken = proto.start(SyncStatusProto.StatusInfo.TODAY_STATS); + writeStatusStatsLocked(proto, info.todayStats); + proto.end(todayStatsToken); + final long yesterdayStatsToken = proto.start( + SyncStatusProto.StatusInfo.YESTERDAY_STATS); + writeStatusStatsLocked(proto, info.yesterdayStats); + proto.end(yesterdayStatsToken); + + final int lastSuccessTimesSize = info.perSourceLastSuccessTimes.length; + for (int j = 0; j < lastSuccessTimesSize; j++) { + proto.write(SyncStatusProto.StatusInfo.PER_SOURCE_LAST_SUCCESS_TIMES, + info.perSourceLastSuccessTimes[j]); + } + final int lastFailureTimesSize = info.perSourceLastFailureTimes.length; + for (int j = 0; j < lastFailureTimesSize; j++) { + proto.write(SyncStatusProto.StatusInfo.PER_SOURCE_LAST_FAILURE_TIMES, + info.perSourceLastFailureTimes[j]); + } + proto.end(token); + } + proto.flush(); + } + + private void writeStatusStatsLocked(ProtoOutputStream proto, SyncStatusInfo.Stats stats) { + proto.write(SyncStatusProto.StatusInfo.Stats.TOTAL_ELAPSED_TIME, stats.totalElapsedTime); + proto.write(SyncStatusProto.StatusInfo.Stats.NUM_SYNCS, stats.numSyncs); + proto.write(SyncStatusProto.StatusInfo.Stats.NUM_FAILURES, stats.numFailures); + proto.write(SyncStatusProto.StatusInfo.Stats.NUM_CANCELS, stats.numCancels); + proto.write(SyncStatusProto.StatusInfo.Stats.NUM_SOURCE_OTHER, stats.numSourceOther); + proto.write(SyncStatusProto.StatusInfo.Stats.NUM_SOURCE_LOCAL, stats.numSourceLocal); + proto.write(SyncStatusProto.StatusInfo.Stats.NUM_SOURCE_POLL, stats.numSourcePoll); + proto.write(SyncStatusProto.StatusInfo.Stats.NUM_SOURCE_USER, stats.numSourceUser); + proto.write(SyncStatusProto.StatusInfo.Stats.NUM_SOURCE_PERIODIC, stats.numSourcePeriodic); + proto.write(SyncStatusProto.StatusInfo.Stats.NUM_SOURCE_FEED, stats.numSourceFeed); } private void requestSync(AuthorityInfo authorityInfo, int reason, Bundle extras, @@ -2126,20 +2432,17 @@ public class SyncStorageEngine { public static final int STATISTICS_FILE_ITEM_OLD = 100; public static final int STATISTICS_FILE_ITEM = 101; - /** - * Read all sync statistics back in to the initial engine state. - */ - private void readStatisticsLocked() { + private void readStatsParcelLocked(File parcel) { try { - byte[] data = mStatisticsFile.readFully(); + final AtomicFile parcelFile = new AtomicFile(parcel); + byte[] data = parcelFile.readFully(); Parcel in = Parcel.obtain(); in.unmarshall(data, 0, data.length); in.setDataPosition(0); int token; int index = 0; while ((token=in.readInt()) != STATISTICS_FILE_END) { - if (token == STATISTICS_FILE_ITEM - || token == STATISTICS_FILE_ITEM_OLD) { + if (token == STATISTICS_FILE_ITEM || token == STATISTICS_FILE_ITEM_OLD) { int day = in.readInt(); if (token == STATISTICS_FILE_ITEM_OLD) { day = day - 2009 + 14245; // Magic! @@ -2159,15 +2462,110 @@ public class SyncStorageEngine { break; } } - } catch (java.io.IOException e) { + } catch (IOException e) { Slog.i(TAG, "No initial statistics"); } } + private void upgradeStatisticsIfNeededLocked() { + final File parcelStats = new File(mSyncDir, LEGACY_STATISTICS_FILE_NAME); + if (parcelStats.exists() && !mStatisticsFile.exists()) { + readStatsParcelLocked(parcelStats); + writeStatisticsLocked(); + } + + // if upgrade to proto was successful, delete parcel file + if (DELETE_LEGACY_PARCEL_FILES && mStatisticsFile.exists()) { + parcelStats.delete(); + } + } + + /** + * Read all sync statistics back in to the initial engine state. + */ + private void readStatisticsLocked() { + upgradeStatisticsIfNeededLocked(); + + if (!mStatisticsFile.exists()) { + return; + } + try { + try (FileInputStream in = mStatisticsFile.openRead()) { + readDayStatsLocked(in); + } + } catch (IOException e) { + Slog.e(TAG, "Unable to read day stats file.", e); + } + } + + private void readDayStatsLocked(InputStream in) throws IOException { + final ProtoInputStream proto = new ProtoInputStream(in); + int statsCount = 0; + while (true) { + switch (proto.nextField()) { + case (int) SyncStatisticsProto.STATS: + final long token = proto.start(SyncStatisticsProto.STATS); + final DayStats stats = readIndividualDayStatsLocked(proto); + proto.end(token); + mDayStats[statsCount] = stats; + statsCount++; + if (statsCount == mDayStats.length) { + return; + } + break; + case ProtoInputStream.NO_MORE_FIELDS: + return; + } + } + } + + private DayStats readIndividualDayStatsLocked(ProtoInputStream proto) throws IOException { + DayStats stats; + if (proto.nextField(SyncStatisticsProto.DayStats.DAY)) { + // fast-path; this should work for most cases since the day is written first + stats = new DayStats(proto.readInt(SyncStatisticsProto.DayStats.DAY)); + } else { + // placeholder to read other data; assume the default day as 0 + stats = new DayStats(0); + } + + while (true) { + switch (proto.nextField()) { + case (int) SyncStatisticsProto.DayStats.DAY: + // fast-path failed for some reason, rebuild stats from placeholder object + Slog.w(TAG, "Failed to read the day via fast-path; some data " + + "might not have been read."); + final DayStats temp = new DayStats( + proto.readInt(SyncStatisticsProto.DayStats.DAY)); + temp.successCount = stats.successCount; + temp.successTime = stats.successTime; + temp.failureCount = stats.failureCount; + temp.failureTime = stats.failureTime; + stats = temp; + break; + case (int) SyncStatisticsProto.DayStats.SUCCESS_COUNT: + stats.successCount = proto.readInt(SyncStatisticsProto.DayStats.SUCCESS_COUNT); + break; + case (int) SyncStatisticsProto.DayStats.SUCCESS_TIME: + stats.successTime = proto.readLong(SyncStatisticsProto.DayStats.SUCCESS_TIME); + break; + case (int) SyncStatisticsProto.DayStats.FAILURE_COUNT: + stats.failureCount = proto.readInt(SyncStatisticsProto.DayStats.FAILURE_COUNT); + break; + case (int) SyncStatisticsProto.DayStats.FAILURE_TIME: + stats.failureTime = proto.readLong(SyncStatisticsProto.DayStats.FAILURE_TIME); + break; + case ProtoInputStream.NO_MORE_FIELDS: + return stats; + } + } + } + /** * Write all sync statistics to the sync status file. */ - private void writeStatisticsLocked() { + @VisibleForTesting + void writeStatisticsLocked() { if (Log.isLoggable(TAG_FILE, Log.VERBOSE)) { Slog.v(TAG, "Writing new " + mStatisticsFile.getBaseFile()); } @@ -2179,31 +2577,36 @@ public class SyncStorageEngine { FileOutputStream fos = null; try { fos = mStatisticsFile.startWrite(); - Parcel out = Parcel.obtain(); - final int N = mDayStats.length; - for (int i=0; i<N; i++) { - DayStats ds = mDayStats[i]; - if (ds == null) { - break; - } - out.writeInt(STATISTICS_FILE_ITEM); - out.writeInt(ds.day); - out.writeInt(ds.successCount); - out.writeLong(ds.successTime); - out.writeInt(ds.failureCount); - out.writeLong(ds.failureTime); - } - out.writeInt(STATISTICS_FILE_END); - fos.write(out.marshall()); - out.recycle(); - + writeDayStatsLocked(fos); mStatisticsFile.finishWrite(fos); - } catch (java.io.IOException e1) { - Slog.w(TAG, "Error writing stats", e1); - if (fos != null) { - mStatisticsFile.failWrite(fos); - } - } + fos = null; + } catch (IOException | IllegalArgumentException e) { + Slog.e(TAG, "Unable to write day stats to proto.", e); + } finally { + // when fos is null (successful write), this is a no-op. + mStatisticsFile.failWrite(fos); + } + } + + private void writeDayStatsLocked(OutputStream out) + throws IOException, IllegalArgumentException { + final ProtoOutputStream proto = new ProtoOutputStream(out); + final int size = mDayStats.length; + for (int i = 0; i < size; i++) { + final DayStats stats = mDayStats[i]; + if (stats == null) { + break; + } + final long token = proto.start(SyncStatisticsProto.STATS); + // day should be written first to take advantage of the fast path in read + proto.write(SyncStatisticsProto.DayStats.DAY, stats.day); + proto.write(SyncStatisticsProto.DayStats.SUCCESS_COUNT, stats.successCount); + proto.write(SyncStatisticsProto.DayStats.SUCCESS_TIME, stats.successTime); + proto.write(SyncStatisticsProto.DayStats.FAILURE_COUNT, stats.failureCount); + proto.write(SyncStatisticsProto.DayStats.FAILURE_TIME, stats.failureTime); + proto.end(token); + } + proto.flush(); } /** diff --git a/services/core/java/com/android/server/location/TEST_MAPPING b/services/core/java/com/android/server/location/TEST_MAPPING deleted file mode 100644 index 2e21fa67a967..000000000000 --- a/services/core/java/com/android/server/location/TEST_MAPPING +++ /dev/null @@ -1,10 +0,0 @@ -{ - "presubmit": [ - { - "name": "CtsLocationCoarseTestCases" - }, - { - "name": "CtsLocationNoneTestCases" - } - ] -}
\ No newline at end of file diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java index f1c84b8701ba..525d3578ccff 100644 --- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java +++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java @@ -115,6 +115,7 @@ import java.io.OutputStream; import java.io.PrintWriter; import java.net.URISyntaxException; import java.util.ArrayList; +import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.LinkedList; @@ -438,8 +439,14 @@ class PackageManagerShellCommand extends ShellCommand { } } - private void setParamsSize(InstallParams params, String inPath) { - if (params.sessionParams.sizeBytes == -1 && !STDIN_PATH.equals(inPath)) { + private void setParamsSize(InstallParams params, List<String> inPaths) { + if (params.sessionParams.sizeBytes != -1 || STDIN_PATH.equals(inPaths.get(0))) { + return; + } + + long sessionSize = 0; + + for (String inPath : inPaths) { final ParcelFileDescriptor fd = openFileForSystem(inPath, "r"); if (fd == null) { getErrPrintWriter().println("Error: Can't open file: " + inPath); @@ -449,8 +456,8 @@ class PackageManagerShellCommand extends ShellCommand { ApkLite baseApk = PackageParser.parseApkLite(fd.getFileDescriptor(), inPath, 0); PackageLite pkgLite = new PackageLite(null, baseApk, null, null, null, null, null, null); - params.sessionParams.setSize(PackageHelper.calculateInstalledSize( - pkgLite, params.sessionParams.abiOverride, fd.getFileDescriptor())); + sessionSize += PackageHelper.calculateInstalledSize(pkgLite, + params.sessionParams.abiOverride, fd.getFileDescriptor()); } catch (PackageParserException | IOException e) { getErrPrintWriter().println("Error: Failed to parse APK file: " + inPath); throw new IllegalArgumentException( @@ -462,6 +469,7 @@ class PackageManagerShellCommand extends ShellCommand { } } } + params.sessionParams.setSize(sessionSize); } /** * Displays the package file for a package. @@ -1148,23 +1156,44 @@ class PackageManagerShellCommand extends ShellCommand { private int runInstall() throws RemoteException { final PrintWriter pw = getOutPrintWriter(); final InstallParams params = makeInstallParams(); - final String inPath = getNextArg(); - setParamsSize(params, inPath); + ArrayList<String> inPaths = getRemainingArgs(); + if (inPaths.isEmpty()) { + inPaths.add(STDIN_PATH); + } + + final boolean hasSplits = inPaths.size() > 1; + + if (STDIN_PATH.equals(inPaths.get(0))) { + if (hasSplits) { + pw.println("Error: can't specify SPLIT(s) along with STDIN"); + return 1; + } + if (params.sessionParams.sizeBytes == -1) { + pw.println("Error: must either specify a package size or an APK file"); + return 1; + } + } + + final boolean isApex = + (params.sessionParams.installFlags & PackageManager.INSTALL_APEX) != 0; + if (isApex && hasSplits) { + pw.println("Error: can't specify SPLIT(s) for APEX"); + return 1; + } + + setParamsSize(params, inPaths); final int sessionId = doCreateSession(params.sessionParams, params.installerPackageName, params.userId); boolean abandonSession = true; try { - if (inPath == null && params.sessionParams.sizeBytes == -1) { - pw.println("Error: must either specify a package size or an APK file"); - return 1; - } - final boolean isApex = - (params.sessionParams.installFlags & PackageManager.INSTALL_APEX) != 0; - String splitName = "base." + (isApex ? "apex" : "apk"); - if (doWriteSplit(sessionId, inPath, params.sessionParams.sizeBytes, splitName, - false /*logSuccess*/) != PackageInstaller.STATUS_SUCCESS) { - return 1; + for (String inPath : inPaths) { + String splitName = hasSplits ? (new File(inPath)).getName() + : "base." + (isApex ? "apex" : "apk"); + if (doWriteSplit(sessionId, inPath, params.sessionParams.sizeBytes, splitName, + false /*logSuccess*/) != PackageInstaller.STATUS_SUCCESS) { + return 1; + } } if (doCommitSession(sessionId, false /*logSuccess*/) != PackageInstaller.STATUS_SUCCESS) { @@ -1283,12 +1312,12 @@ class PackageManagerShellCommand extends ShellCommand { final int sessionId = Integer.parseInt(getNextArg()); - final String splitName = getNextArg(); - if (splitName == null) { + ArrayList<String> splitNames = getRemainingArgs(); + if (splitNames.isEmpty()) { pw.println("Error: split name not specified"); return 1; } - return doRemoveSplit(sessionId, splitName, true /*logSuccess*/); + return doRemoveSplits(sessionId, splitNames, true /*logSuccess*/); } private int runInstallExisting() throws RemoteException { @@ -1731,6 +1760,15 @@ class PackageManagerShellCommand extends ShellCommand { return 0; } + private ArrayList<String> getRemainingArgs() { + ArrayList<String> args = new ArrayList<>(); + String arg; + while ((arg = getNextArg()) != null) { + args.add(arg); + } + return args; + } + private static class SnapshotRuntimeProfileCallback extends ISnapshotRuntimeProfileCallback.Stub { private boolean mSuccess = false; @@ -1802,9 +1840,9 @@ class PackageManagerShellCommand extends ShellCommand { } // if a split is specified, just remove it and not the whole package - final String splitName = getNextArg(); - if (splitName != null) { - return runRemoveSplit(packageName, splitName); + ArrayList<String> splitNames = getRemainingArgs(); + if (!splitNames.isEmpty()) { + return runRemoveSplits(packageName, splitNames); } userId = translateUserId(userId, true /*allowAll*/, "runUninstall"); @@ -1852,7 +1890,8 @@ class PackageManagerShellCommand extends ShellCommand { } } - private int runRemoveSplit(String packageName, String splitName) throws RemoteException { + private int runRemoveSplits(String packageName, Collection<String> splitNames) + throws RemoteException { final PrintWriter pw = getOutPrintWriter(); final SessionParams sessionParams = new SessionParams(SessionParams.MODE_INHERIT_EXISTING); sessionParams.installFlags |= PackageManager.INSTALL_REPLACE_EXISTING; @@ -1861,7 +1900,7 @@ class PackageManagerShellCommand extends ShellCommand { doCreateSession(sessionParams, null /*installerPackageName*/, UserHandle.USER_ALL); boolean abandonSession = true; try { - if (doRemoveSplit(sessionId, splitName, false /*logSuccess*/) + if (doRemoveSplits(sessionId, splitNames, false /*logSuccess*/) != PackageInstaller.STATUS_SUCCESS) { return 1; } @@ -2945,14 +2984,17 @@ class PackageManagerShellCommand extends ShellCommand { } } - private int doRemoveSplit(int sessionId, String splitName, boolean logSuccess) + private int doRemoveSplits(int sessionId, Collection<String> splitNames, boolean logSuccess) throws RemoteException { final PrintWriter pw = getOutPrintWriter(); PackageInstaller.Session session = null; try { session = new PackageInstaller.Session( mInterface.getPackageInstaller().openSession(sessionId)); - session.removeSplit(splitName); + + for (String splitName : splitNames) { + session.removeSplit(splitName); + } if (logSuccess) { pw.println("Success"); @@ -3237,9 +3279,9 @@ class PackageManagerShellCommand extends ShellCommand { pw.println(" [--enable-rollback]"); pw.println(" [--force-uuid internal|UUID] [--pkg PACKAGE] [-S BYTES]"); pw.println(" [--apex] [--wait TIMEOUT]"); - pw.println(" [PATH|-]"); - pw.println(" Install an application. Must provide the apk data to install, either as a"); - pw.println(" file path or '-' to read from stdin. Options are:"); + pw.println(" [PATH [SPLIT...]|-]"); + pw.println(" Install an application. Must provide the apk data to install, either as"); + pw.println(" file path(s) or '-' to read from stdin. Options are:"); pw.println(" -R: disallow replacement of existing application"); pw.println(" -t: allow test packages"); pw.println(" -i: specify package name of installer owning the app"); @@ -3293,6 +3335,9 @@ class PackageManagerShellCommand extends ShellCommand { pw.println(" will be read from stdin. Options are:"); pw.println(" -S: size in bytes of package, required for stdin"); pw.println(""); + pw.println(" install-remove SESSION_ID SPLIT..."); + pw.println(" Mark SPLIT(s) as removed in the given install session."); + pw.println(""); pw.println(" install-add-session MULTI_PACKAGE_SESSION_ID CHILD_SESSION_IDs"); pw.println(" Add one or more session IDs to a multi-package session."); pw.println(""); @@ -3317,9 +3362,10 @@ class PackageManagerShellCommand extends ShellCommand { pw.println(""); pw.println(" move-primary-storage [internal|UUID]"); pw.println(""); - pw.println(" pm uninstall [-k] [--user USER_ID] [--versionCode VERSION_CODE] PACKAGE [SPLIT]"); + pw.println(" uninstall [-k] [--user USER_ID] [--versionCode VERSION_CODE]"); + pw.println(" PACKAGE [SPLIT...]"); pw.println(" Remove the given package name from the system. May remove an entire app"); - pw.println(" if no SPLIT name is specified, otherwise will remove only the split of the"); + pw.println(" if no SPLIT names specified, otherwise will remove only the splits of the"); pw.println(" given app. Options are:"); pw.println(" -k: keep the data and cache directories around after package removal."); pw.println(" --user: remove the app from the given user."); diff --git a/services/core/java/com/android/server/pm/TEST_MAPPING b/services/core/java/com/android/server/pm/TEST_MAPPING index f7b60c25ce4a..e8798ffa3720 100644 --- a/services/core/java/com/android/server/pm/TEST_MAPPING +++ b/services/core/java/com/android/server/pm/TEST_MAPPING @@ -22,6 +22,9 @@ "exclude-annotation": "androidx.test.filters.FlakyTest" } ] + }, + { + "name": "PackageManagerShellCommandTest" } ], "postsubmit": [ diff --git a/services/core/java/com/android/server/pm/dex/ArtManagerService.java b/services/core/java/com/android/server/pm/dex/ArtManagerService.java index b3f1867fdb06..cc5aec2e113e 100644 --- a/services/core/java/com/android/server/pm/dex/ArtManagerService.java +++ b/services/core/java/com/android/server/pm/dex/ArtManagerService.java @@ -314,9 +314,13 @@ public class ArtManagerService extends android.content.pm.dex.IArtManager.Stub { case ArtManager.PROFILE_APPS : return SystemProperties.getBoolean("dalvik.vm.usejitprofiles", false); case ArtManager.PROFILE_BOOT_IMAGE: + // The device config property overrides the system property version. + boolean profileBootClassPath = SystemProperties.getBoolean( + "persist.device_config.runtime_native_boot.profilebootclasspath", + SystemProperties.getBoolean("dalvik.vm.profilebootclasspath", false)); return (Build.IS_USERDEBUG || Build.IS_ENG) && SystemProperties.getBoolean("dalvik.vm.usejitprofiles", false) && - SystemProperties.getBoolean("dalvik.vm.profilebootimage", false); + profileBootClassPath; default: throw new IllegalArgumentException("Invalid profile type:" + profileType); } diff --git a/services/core/java/com/android/server/stats/ProcfsMemoryUtil.java b/services/core/java/com/android/server/stats/ProcfsMemoryUtil.java index 8431ae4aeb98..c1eacce1f304 100644 --- a/services/core/java/com/android/server/stats/ProcfsMemoryUtil.java +++ b/services/core/java/com/android/server/stats/ProcfsMemoryUtil.java @@ -15,28 +15,22 @@ */ package com.android.server.stats; -import android.annotation.Nullable; -import android.os.FileUtils; -import android.util.Slog; +import static android.os.Process.PROC_OUT_STRING; -import com.android.internal.annotations.VisibleForTesting; +import android.annotation.Nullable; +import android.os.Process; -import java.io.File; -import java.io.IOException; -import java.util.regex.Matcher; -import java.util.regex.Pattern; +import java.util.function.BiConsumer; final class ProcfsMemoryUtil { - private static final String TAG = "ProcfsMemoryUtil"; - - private static final Pattern STATUS_MEMORY_STATS = - Pattern.compile(String.join( - ".*", - "Uid:\\s*(\\d+)\\s*", - "VmHWM:\\s*(\\d+)\\s*kB", - "VmRSS:\\s*(\\d+)\\s*kB", - "RssAnon:\\s*(\\d+)\\s*kB", - "VmSwap:\\s*(\\d+)\\s*kB"), Pattern.DOTALL); + private static final int[] CMDLINE_OUT = new int[] { PROC_OUT_STRING }; + private static final String[] STATUS_KEYS = new String[] { + "Uid:", + "VmHWM:", + "VmRSS:", + "RssAnon:", + "VmSwap:" + }; private ProcfsMemoryUtil() {} @@ -46,30 +40,21 @@ final class ProcfsMemoryUtil { */ @Nullable static MemorySnapshot readMemorySnapshotFromProcfs(int pid) { - return parseMemorySnapshotFromStatus(readFile("/proc/" + pid + "/status")); - } - - @VisibleForTesting - @Nullable - static MemorySnapshot parseMemorySnapshotFromStatus(String contents) { - if (contents.isEmpty()) { + long[] output = new long[STATUS_KEYS.length]; + output[0] = -1; + Process.readProcLines("/proc/" + pid + "/status", STATUS_KEYS, output); + if (output[0] == -1 || (output[3] == 0 && output[4] == 0)) { + // Could not open file or anon rss / swap are 0 indicating the process is in a zombie + // state. return null; } - try { - final Matcher matcher = STATUS_MEMORY_STATS.matcher(contents); - if (matcher.find()) { - final MemorySnapshot snapshot = new MemorySnapshot(); - snapshot.uid = Integer.parseInt(matcher.group(1)); - snapshot.rssHighWaterMarkInKilobytes = Integer.parseInt(matcher.group(2)); - snapshot.rssInKilobytes = Integer.parseInt(matcher.group(3)); - snapshot.anonRssInKilobytes = Integer.parseInt(matcher.group(4)); - snapshot.swapInKilobytes = Integer.parseInt(matcher.group(5)); - return snapshot; - } - } catch (NumberFormatException e) { - Slog.e(TAG, "Failed to parse value", e); - } - return null; + final MemorySnapshot snapshot = new MemorySnapshot(); + snapshot.uid = (int) output[0]; + snapshot.rssHighWaterMarkInKilobytes = (int) output[1]; + snapshot.rssInKilobytes = (int) output[2]; + snapshot.anonRssInKilobytes = (int) output[3]; + snapshot.swapInKilobytes = (int) output[4]; + return snapshot; } /** @@ -78,30 +63,26 @@ final class ProcfsMemoryUtil { * Returns content of /proc/pid/cmdline (e.g. /system/bin/statsd) or an empty string * if the file is not available. */ - public static String readCmdlineFromProcfs(int pid) { - return parseCmdline(readFile("/proc/" + pid + "/cmdline")); - } - - /** - * Parses cmdline out of the contents of the /proc/pid/cmdline file in procfs. - * - * Parsing is required to strip anything after the first null byte. - */ - @VisibleForTesting - static String parseCmdline(String contents) { - int firstNullByte = contents.indexOf("\0"); - if (firstNullByte == -1) { - return contents; + static String readCmdlineFromProcfs(int pid) { + String[] cmdline = new String[1]; + if (!Process.readProcFile("/proc/" + pid + "/cmdline", CMDLINE_OUT, cmdline, null, null)) { + return ""; } - return contents.substring(0, firstNullByte); + return cmdline[0]; } - private static String readFile(String path) { - try { - final File file = new File(path); - return FileUtils.readTextFile(file, 0 /* max */, null /* ellipsis */); - } catch (IOException e) { - return ""; + static void forEachPid(BiConsumer<Integer, String> func) { + int[] pids = new int[1024]; + pids = Process.getPids("/proc", pids); + for (int pid : pids) { + if (pid < 0) { + return; + } + String cmdline = readCmdlineFromProcfs(pid); + if (cmdline.isEmpty()) { + continue; + } + func.accept(pid, cmdline); } } diff --git a/services/core/java/com/android/server/wm/ActivityDisplay.java b/services/core/java/com/android/server/wm/ActivityDisplay.java index c5924f73e14c..ebfc65e5d1e5 100644 --- a/services/core/java/com/android/server/wm/ActivityDisplay.java +++ b/services/core/java/com/android/server/wm/ActivityDisplay.java @@ -180,6 +180,7 @@ class ActivityDisplay extends ConfigurationContainer<ActivityStack> { mDisplayContent.reconfigureDisplayLocked(); onRequestedOverrideConfigurationChanged( mDisplayContent.getRequestedOverrideConfiguration()); + mService.mWindowManager.mDisplayNotificationController.dispatchDisplayAdded(this); } void onDisplayChanged() { diff --git a/services/core/java/com/android/server/wm/ActivityMetricsLogger.java b/services/core/java/com/android/server/wm/ActivityMetricsLogger.java index 73034b020a76..0a861ade2900 100644 --- a/services/core/java/com/android/server/wm/ActivityMetricsLogger.java +++ b/services/core/java/com/android/server/wm/ActivityMetricsLogger.java @@ -548,7 +548,7 @@ class ActivityMetricsLogger { private static boolean hasActivityToBeDrawn(Task t) { for (int i = t.getChildCount() - 1; i >= 0; --i) { final ActivityRecord r = t.getChildAt(i); - if (r.visible && !r.mDrawn && !r.finishing) { + if (r.mVisibleRequested && !r.mDrawn && !r.finishing) { return true; } } diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java index 081bd2b7cce3..51e7a0181f18 100644 --- a/services/core/java/com/android/server/wm/ActivityRecord.java +++ b/services/core/java/com/android/server/wm/ActivityRecord.java @@ -121,6 +121,7 @@ import static com.android.server.am.ActivityRecordProto.PROC_ID; import static com.android.server.am.ActivityRecordProto.STATE; import static com.android.server.am.ActivityRecordProto.TRANSLUCENT; import static com.android.server.am.ActivityRecordProto.VISIBLE; +import static com.android.server.am.ActivityRecordProto.VISIBLE_REQUESTED; import static com.android.server.am.EventLogTags.AM_RELAUNCH_ACTIVITY; import static com.android.server.am.EventLogTags.AM_RELAUNCH_RESUME_ACTIVITY; import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM; @@ -176,8 +177,6 @@ import static com.android.server.wm.AppWindowTokenProto.CLIENT_HIDDEN; import static com.android.server.wm.AppWindowTokenProto.DEFER_HIDING_CLIENT; import static com.android.server.wm.AppWindowTokenProto.FILLS_PARENT; import static com.android.server.wm.AppWindowTokenProto.FROZEN_BOUNDS; -import static com.android.server.wm.AppWindowTokenProto.HIDDEN_REQUESTED; -import static com.android.server.wm.AppWindowTokenProto.HIDDEN_SET_FROM_TRANSFERRED_STARTING_WINDOW; import static com.android.server.wm.AppWindowTokenProto.IS_ANIMATING; import static com.android.server.wm.AppWindowTokenProto.IS_WAITING_FOR_TRANSITION_START; import static com.android.server.wm.AppWindowTokenProto.LAST_ALL_DRAWN; @@ -192,6 +191,7 @@ import static com.android.server.wm.AppWindowTokenProto.STARTING_DISPLAYED; import static com.android.server.wm.AppWindowTokenProto.STARTING_MOVED; import static com.android.server.wm.AppWindowTokenProto.STARTING_WINDOW; import static com.android.server.wm.AppWindowTokenProto.THUMBNAIL; +import static com.android.server.wm.AppWindowTokenProto.VISIBLE_SET_FROM_TRANSFERRED_STARTING_WINDOW; import static com.android.server.wm.AppWindowTokenProto.WINDOW_TOKEN; import static com.android.server.wm.IdentifierProto.HASH_CODE; import static com.android.server.wm.IdentifierProto.TITLE; @@ -462,13 +462,13 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A private boolean keysPaused; // has key dispatching been paused for it? int launchMode; // the launch mode activity attribute. int lockTaskLaunchMode; // the lockTaskMode manifest attribute, subject to override - boolean visible; // does this activity's window need to be shown? + private boolean mVisible; // Should this token's windows be visible? boolean visibleIgnoringKeyguard; // is this activity visible, ignoring the fact that Keyguard // might hide this activity? // True if the hidden state of this token was forced to false due to a transferred starting // window. - private boolean mHiddenSetFromTransferredStartingWindow; - // TODO: figureout how to consolidate with the same variable in ActivityRecord. + private boolean mVisibleSetFromTransferredStartingWindow; + // TODO: figure out how to consolidate with the same variable in ActivityRecord. private boolean mDeferHidingClient; // If true we told WM to defer reporting to the client // process that it is hidden. private boolean mLastDeferHidingClient; // If true we will defer setting mClientHidden to true @@ -622,11 +622,11 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A // case do not clear allDrawn until the animation completes. boolean deferClearAllDrawn; - // Is this window's surface needed? This is almost like hidden, except - // it will sometimes be true a little earlier: when the token has + // Is this window's surface needed? This is almost like visible, except + // it will sometimes be true a little earlier: when the activity record has // been shown, but is still waiting for its app transition to execute // before making its windows shown. - boolean hiddenRequested; + boolean mVisibleRequested; // Last visibility state we reported to the app token. boolean reportedVisible; @@ -836,7 +836,6 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A pw.print(" finishing="); pw.println(finishing); pw.print(prefix); pw.print("keysPaused="); pw.print(keysPaused); pw.print(" inHistory="); pw.print(inHistory); - pw.print(" visible="); pw.print(visible); pw.print(" sleeping="); pw.print(sleeping); pw.print(" idle="); pw.print(idle); pw.print(" mStartingWindowState="); @@ -855,12 +854,14 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A pw.println(requestedVrComponent); } super.dump(pw, prefix, dumpAll); + pw.print(" visible="); pw.print(mVisible); if (appToken != null) { pw.println(prefix + "app=true mVoiceInteraction=" + mVoiceInteraction); } pw.print(prefix); pw.print(" mOccludesParent="); pw.print(mOccludesParent); pw.print(" mOrientation="); pw.println(mOrientation); - pw.println(prefix + "hiddenRequested=" + hiddenRequested + " mClientHidden=" + mClientHidden + pw.println(prefix + "mVisibleRequested=" + mVisibleRequested + + " mClientHidden=" + mClientHidden + ((mDeferHidingClient) ? " mDeferHidingClient=" + mDeferHidingClient : "") + " reportedDrawn=" + reportedDrawn + " reportedVisible=" + reportedVisible); if (paused) { @@ -885,13 +886,13 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A pw.print(" mIsExiting="); pw.println(mIsExiting); } if (startingWindow != null || startingSurface != null - || startingDisplayed || startingMoved || mHiddenSetFromTransferredStartingWindow) { + || startingDisplayed || startingMoved || mVisibleSetFromTransferredStartingWindow) { pw.print(prefix); pw.print("startingWindow="); pw.print(startingWindow); pw.print(" startingSurface="); pw.print(startingSurface); pw.print(" startingDisplayed="); pw.print(startingDisplayed); pw.print(" startingMoved="); pw.print(startingMoved); pw.println(" mHiddenSetFromTransferredStartingWindow=" - + mHiddenSetFromTransferredStartingWindow); + + mVisibleSetFromTransferredStartingWindow); } if (!mFrozenBounds.isEmpty()) { pw.print(prefix); pw.print("mFrozenBounds="); pw.println(mFrozenBounds); @@ -1487,8 +1488,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A } // Application tokens start out hidden. - setHidden(true); - hiddenRequested = true; + setVisible(false); + mVisibleRequested = false; ColorDisplayService.ColorDisplayServiceInternal cds = LocalServices.getService( ColorDisplayService.ColorDisplayServiceInternal.class); @@ -1517,7 +1518,6 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A deferRelaunchUntilPaused = false; keysPaused = false; inHistory = false; - visible = false; nowVisible = false; mDrawn = false; idle = false; @@ -2200,7 +2200,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A * 2. App is delayed closing since it might enter PIP. */ boolean isClosingOrEnteringPip() { - return (isAnimating(TRANSITION | PARENTS) && hiddenRequested) || mWillCloseOrEnterPip; + return (isAnimating(TRANSITION | PARENTS) && !mVisibleRequested) || mWillCloseOrEnterPip; } /** * @return Whether AppOps allows this package to enter picture-in-picture. @@ -2459,7 +2459,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A mAtmService.getLockTaskController().clearLockedTask(task); } } else if (!isState(PAUSING)) { - if (visible) { + if (mVisibleRequested) { // Prepare and execute close transition. prepareActivityHideTransitionAnimation(transit); } @@ -2538,12 +2538,13 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A // TODO(b/137329632): find the next activity directly underneath this one, not just anywhere final ActivityRecord next = getDisplay().topRunningActivity( true /* considerKeyguardState */); - final boolean isVisible = visible || nowVisible; + final boolean isVisible = mVisibleRequested || nowVisible; // isNextNotYetVisible is to check if the next activity is invisible, or it has been // requested to be invisible but its windows haven't reported as invisible. If so, it // implied that the current finishing activity should be added into stopping list rather // than destroy immediately. - final boolean isNextNotYetVisible = next != null && (!next.nowVisible || !next.visible); + final boolean isNextNotYetVisible = next != null + && (!next.nowVisible || !next.mVisibleRequested); if (isVisible && isNextNotYetVisible) { // Add this activity to the list of stopping activities. It will be processed and // destroyed when the next activity reports idle. @@ -3213,7 +3214,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A "Removing starting %s from %s", tStartingWindow, fromActivity); fromActivity.removeChild(tStartingWindow); fromActivity.postWindowRemoveStartingWindowCleanup(tStartingWindow); - fromActivity.mHiddenSetFromTransferredStartingWindow = false; + fromActivity.mVisibleSetFromTransferredStartingWindow = false; addWindow(tStartingWindow); // Propagate other interesting state between the tokens. If the old token is displayed, @@ -3226,10 +3227,10 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A if (fromActivity.firstWindowDrawn) { firstWindowDrawn = true; } - if (!fromActivity.isHidden()) { - setHidden(false); - hiddenRequested = false; - mHiddenSetFromTransferredStartingWindow = true; + if (fromActivity.isVisible()) { + setVisible(true); + mVisibleRequested = true; + mVisibleSetFromTransferredStartingWindow = true; } setClientHidden(fromActivity.mClientHidden); @@ -3277,7 +3278,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A if (fromActivity == this) { return; } - if (fromActivity.hiddenRequested && transferStartingWindow(fromActivity.token)) { + if (!fromActivity.mVisibleRequested && transferStartingWindow(fromActivity.token)) { return; } } @@ -3792,6 +3793,10 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A return opts; } + boolean allowMoveToFront() { + return pendingOptions == null || !pendingOptions.getAvoidMoveToFront(); + } + void removeUriPermissionsLocked() { if (uriPermissions != null) { uriPermissions.removeUriPermissions(); @@ -3828,7 +3833,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A return; } mDeferHidingClient = deferHidingClient; - if (!mDeferHidingClient && !visible) { + if (!mDeferHidingClient && !mVisibleRequested) { // Hiding the client is no longer deferred and the app isn't visible still, go ahead and // update the visibility. setVisibility(false); @@ -3839,7 +3844,14 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A boolean isVisible() { // If the activity isn't hidden then it is considered visible and there is no need to check // its children windows to see if they are visible. - return !isHidden(); + return mVisible; + } + + void setVisible(boolean visible) { + if (visible != mVisible) { + mVisible = visible; + scheduleAnimation(); + } } void setVisibility(boolean visible) { @@ -3848,20 +3860,17 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A + appToken); return; } + if (visible) { + mDeferHidingClient = false; + } setVisibility(visible, mDeferHidingClient); mAtmService.addWindowLayoutReasons( ActivityTaskManagerService.LAYOUT_REASON_VISIBILITY_CHANGED); mStackSupervisor.getActivityMetricsLogger().notifyVisibilityChanged(this); - } - - // TODO: Look into merging with #commitVisibility() - void setVisible(boolean newVisible) { - visible = newVisible; - mDeferHidingClient = !visible && mDeferHidingClient; - setVisibility(visible); mStackSupervisor.mAppVisibilitiesChangedSinceLastPause = true; } + @VisibleForTesting void setVisibility(boolean visible, boolean deferHidingClient) { final AppTransition appTransition = getDisplayContent().mAppTransition; @@ -3872,7 +3881,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A // transition can be selected. // TODO: Probably a good idea to separate the concept of opening/closing apps from the // concept of setting visibility... - if (!visible && hiddenRequested) { + if (!visible && !mVisibleRequested) { if (!deferHidingClient && mLastDeferHidingClient) { // We previously deferred telling the client to hide itself when visibility was @@ -3884,8 +3893,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A } ProtoLog.v(WM_DEBUG_APP_TRANSITIONS, - "setAppVisibility(%s, visible=%b): %s hidden=%b hiddenRequested=%b Callers=%s", - appToken, visible, appTransition, isHidden(), hiddenRequested, + "setAppVisibility(%s, visible=%b): %s visible=%b mVisibleRequested=%b Callers=%s", + appToken, visible, appTransition, isVisible(), mVisibleRequested, Debug.getCallers(6)); final DisplayContent displayContent = getDisplayContent(); @@ -3896,7 +3905,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A } displayContent.mChangingApps.remove(this); waitingToShow = false; - hiddenRequested = !visible; + mVisibleRequested = visible; mLastDeferHidingClient = deferHidingClient; if (!visible) { @@ -3915,11 +3924,11 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A startingMoved = false; // If the token is currently hidden (should be the common case), or has been // stopped, then we need to set up to wait for its windows to be ready. - if (isHidden() || mAppStopped) { + if (!isVisible() || mAppStopped) { clearAllDrawn(); // If the app was already visible, don't reset the waitingToShow state. - if (isHidden()) { + if (!isVisible()) { waitingToShow = true; // If the client isn't hidden, we don't need to reset the drawing state. @@ -3989,9 +3998,9 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A boolean visible, int transit, boolean performLayout, boolean isVoiceInteraction) { boolean delayed = false; - // Reset the state of mHiddenSetFromTransferredStartingWindow since visibility is actually + // Reset the state of mVisibleSetFromTransferredStartingWindow since visibility is actually // been set by the app now. - mHiddenSetFromTransferredStartingWindow = false; + mVisibleSetFromTransferredStartingWindow = false; // Allow for state changes and animation to be applied if: // * token is transitioning visibility state @@ -4001,7 +4010,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A // * or the token is the opening app and visible while opening task behind existing one. final DisplayContent displayContent = getDisplayContent(); boolean visibilityChanged = false; - if (isHidden() == visible || (isHidden() && mIsExiting) + if (isVisible() != visible || (!isVisible() && mIsExiting) || (visible && waitingForReplacement()) || (visible && displayContent.mOpeningApps.contains(this) && displayContent.mAppTransition.getAppTransition() == TRANSIT_TASK_OPEN_BEHIND)) { @@ -4009,7 +4018,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A mWmService.mAccessibilityController; boolean changed = false; ProtoLog.v(WM_DEBUG_APP_TRANSITIONS, - "Changing app %s hidden=%b performLayout=%b", this, isHidden(), + "Changing app %s visible=%b performLayout=%b", this, isVisible(), performLayout); boolean runningAppAnimation = false; @@ -4034,8 +4043,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A changed |= win.onAppVisibilityChanged(visible, runningAppAnimation); } - setHidden(!visible); - hiddenRequested = !visible; + setVisible(visible); + mVisibleRequested = visible; visibilityChanged = true; if (!visible) { stopFreezingScreen(true, true); @@ -4053,8 +4062,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A } ProtoLog.v(WM_DEBUG_APP_TRANSITIONS, - "commitVisibility: %s: hidden=%b hiddenRequested=%b", this, - isHidden(), hiddenRequested); + "commitVisibility: %s: visible=%b visibleRequested=%b", this, + isVisible(), mVisibleRequested); if (changed) { displayContent.getInputMonitor().setUpdateInputWindowsNeededLw(); @@ -4118,7 +4127,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A // no animation but there will still be a transition set. // We still need to delay hiding the surface such that it // can be synchronized with showing the next surface in the transition. - if (isHidden() && !delayed && !displayContent.mAppTransition.isTransitionSet()) { + if (!isVisible() && !delayed && !displayContent.mAppTransition.isTransitionSet()) { SurfaceControl.openTransaction(); for (int i = mChildren.size() - 1; i >= 0; i--) { mChildren.get(i).mWinAnimator.hide("immediately hidden"); @@ -4131,12 +4140,6 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A } @Override - void setHidden(boolean hidden) { - super.setHidden(hidden); - scheduleAnimation(); - } - - @Override void onAppTransitionDone() { sendingToBottom = false; } @@ -4399,7 +4402,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A updateOptionsLocked(returningOptions); stack.mUndrawnActivitiesBelowTopTranslucent.add(this); } - setVisible(true); + setVisibility(true); sleeping = false; app.postPendingUiCleanMsg(true); if (reportToClient) { @@ -4435,7 +4438,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A } void makeInvisible() { - if (!visible) { + if (!mVisibleRequested) { if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY, "Already invisible: " + this); return; } @@ -4457,7 +4460,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A final boolean deferHidingClient = canEnterPictureInPicture && !isState(STOPPING, STOPPED, PAUSED); setDeferHidingClient(deferHidingClient); - setVisible(false); + setVisibility(false); switch (getState()) { case STOPPING: @@ -4644,8 +4647,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A * state to match that fact. */ void completeResumeLocked() { - final boolean wasVisible = visible; - setVisible(true); + final boolean wasVisible = mVisibleRequested; + setVisibility(true); if (!wasVisible) { // Visibility has changed, so take a note of it so we call the TaskStackChangedListener mStackSupervisor.mAppVisibilitiesChangedSinceLastPause = true; @@ -4729,15 +4732,16 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A } setState(STOPPING, "stopIfPossible"); if (DEBUG_VISIBILITY) { - Slog.v(TAG_VISIBILITY, "Stopping visible=" + visible + " for " + this); + Slog.v(TAG_VISIBILITY, "Stopping visibleRequested=" + + mVisibleRequested + " for " + this); } - if (!visible) { - setVisible(false); + if (!mVisibleRequested) { + setVisibility(false); } EventLogTags.writeAmStopActivity( mUserId, System.identityHashCode(this), shortComponentName); mAtmService.getLifecycleManager().scheduleTransaction(app.getThread(), appToken, - StopActivityItem.obtain(visible, configChangeFlags)); + StopActivityItem.obtain(mVisibleRequested, configChangeFlags)); if (stack.shouldSleepOrShutDownActivities()) { setSleeping(true); } @@ -4900,10 +4904,10 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A void startFreezingScreen() { ProtoLog.i(WM_DEBUG_ORIENTATION, - "Set freezing of %s: hidden=%b freezing=%b hiddenRequested=%b. %s", - appToken, isHidden(), mFreezingScreen, hiddenRequested, + "Set freezing of %s: visible=%b freezing=%b visibleRequested=%b. %s", + appToken, isVisible(), mFreezingScreen, mVisibleRequested, new RuntimeException().fillInStackTrace()); - if (!hiddenRequested) { + if (mVisibleRequested) { if (!mFreezingScreen) { mFreezingScreen = true; mWmService.registerAppFreezeListener(this); @@ -4939,8 +4943,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A return; } ProtoLog.v(WM_DEBUG_ORIENTATION, - "Clear freezing of %s: hidden=%b freezing=%b", appToken, - isHidden(), isFreezingScreen()); + "Clear freezing of %s: visible=%b freezing=%b", appToken, + isVisible(), isFreezingScreen()); stopFreezingScreen(true, force); } } @@ -5100,7 +5104,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A boolean nowGone = mReportedVisibilityResults.nowGone; boolean nowDrawn = numInteresting > 0 && numDrawn >= numInteresting; - boolean nowVisible = numInteresting > 0 && numVisible >= numInteresting && !isHidden(); + boolean nowVisible = numInteresting > 0 && numVisible >= numInteresting && isVisible(); if (!nowGone) { // If the app is not yet gone, then it can only become visible/drawn. if (!nowDrawn) { @@ -5182,7 +5186,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A Slog.v(TAG, "Not displayed: s=" + winAnimator.mSurfaceController + " pv=" + w.isVisibleByPolicy() + " mDrawState=" + winAnimator.drawStateToString() - + " ph=" + w.isParentWindowHidden() + " th=" + hiddenRequested + + " ph=" + w.isParentWindowHidden() + " th=" + mVisibleRequested + " a=" + isAnimating(TRANSITION)); } } @@ -5290,7 +5294,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A * currently pausing, or is resumed. */ public boolean isInterestingToUserLocked() { - return visible || nowVisible || mState == PAUSING || mState == RESUMED; + return mVisibleRequested || nowVisible || mState == PAUSING || mState == RESUMED; } void setSleeping(boolean _sleeping) { @@ -5364,7 +5368,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A // We're not ready for this kind of thing. return false; } - if (visible) { + if (mVisibleRequested) { // The user would notice this! return false; } @@ -5461,11 +5465,11 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A // well there is no point now. ProtoLog.v(WM_DEBUG_STARTING_WINDOW, "Nulling last startingData"); mStartingData = null; - if (mHiddenSetFromTransferredStartingWindow) { - // We set the hidden state to false for the token from a transferred starting window. - // We now reset it back to true since the starting window was the last window in the - // token. - setHidden(true); + if (mVisibleSetFromTransferredStartingWindow) { + // We set the visible state to true for the token from a transferred starting + // window. We now reset it back to false since the starting window was the last + // window in the token. + setVisible(false); } } else if (mChildren.size() == 1 && startingSurface != null && !isRelaunching()) { // If this is the last window except for a starting transition window, @@ -5803,7 +5807,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A @Override void prepareSurfaces() { - final boolean show = !isHidden() || isAnimating(); + final boolean show = isVisible() || isAnimating(); if (mSurfaceControl != null) { if (show && !mLastSurfaceShowing) { @@ -5922,7 +5926,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A "AppWindowToken"); clearThumbnail(); - setClientHidden(isHidden() && hiddenRequested); + setClientHidden(!isVisible() && !mVisibleRequested); getDisplayContent().computeImeTargetIfNeeded(this); @@ -6519,7 +6523,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A if (display == null) { return; } - if (visible) { + if (mVisibleRequested) { // It may toggle the UI for user to restart the size compatibility mode activity. display.handleActivitySizeCompatModeIfNeeded(this); } else if (mCompatDisplayInsets != null) { @@ -6816,7 +6820,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A } else { if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION, "Config is relaunching " + this); - if (DEBUG_STATES && !visible) { + if (DEBUG_STATES && !mVisibleRequested) { Slog.v(TAG_STATES, "Config is relaunching invisible activity " + this + " called by " + Debug.getCallers(4)); } @@ -7002,7 +7006,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A // Reset the existing override configuration so it can be updated according to the latest // configuration. clearSizeCompatMode(); - if (visible) { + if (mVisibleRequested) { // Configuration will be ensured when becoming visible, so if it is already visible, // then the manual update is needed. updateSizeCompatMode(); @@ -7015,7 +7019,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A // The restarting state avoids removing this record when process is died. setState(RESTARTING_PROCESS, "restartActivityProcess"); - if (!visible || mHaveState) { + if (!mVisibleRequested || mHaveState) { // Kill its process immediately because the activity should be in background. // The activity state will be update to {@link #DESTROYED} in // {@link ActivityStack#cleanUp} when handling process died. @@ -7306,12 +7310,13 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A writeToProto(proto, APP_WINDOW_TOKEN, WindowTraceLogLevel.ALL); writeIdentifierToProto(proto, IDENTIFIER); proto.write(STATE, mState.toString()); - proto.write(VISIBLE, visible); + proto.write(VISIBLE_REQUESTED, mVisibleRequested); proto.write(FRONT_OF_TASK, isRootOfTask()); if (hasProcess()) { proto.write(PROC_ID, app.getPid()); } proto.write(TRANSLUCENT, !occludesParent()); + proto.write(VISIBLE, mVisible); } public void writeToProto(ProtoOutputStream proto, long fieldId) { @@ -7342,7 +7347,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A } proto.write(FILLS_PARENT, mOccludesParent); proto.write(APP_STOPPED, mAppStopped); - proto.write(HIDDEN_REQUESTED, hiddenRequested); + proto.write(com.android.server.wm.AppWindowTokenProto.VISIBLE_REQUESTED, mVisibleRequested); proto.write(CLIENT_HIDDEN, mClientHidden); proto.write(DEFER_HIDING_CLIENT, mDeferHidingClient); proto.write(REPORTED_DRAWN, reportedDrawn); @@ -7357,11 +7362,12 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A } proto.write(STARTING_DISPLAYED, startingDisplayed); proto.write(STARTING_MOVED, startingMoved); - proto.write(HIDDEN_SET_FROM_TRANSFERRED_STARTING_WINDOW, - mHiddenSetFromTransferredStartingWindow); + proto.write(VISIBLE_SET_FROM_TRANSFERRED_STARTING_WINDOW, + mVisibleSetFromTransferredStartingWindow); for (Rect bounds : mFrozenBounds) { bounds.writeToProto(proto, FROZEN_BOUNDS); } + proto.write(com.android.server.wm.AppWindowTokenProto.VISIBLE, mVisible); proto.end(token); } diff --git a/services/core/java/com/android/server/wm/ActivityServiceConnectionsHolder.java b/services/core/java/com/android/server/wm/ActivityServiceConnectionsHolder.java index c56a9e2ac560..6e75f9c9167f 100644 --- a/services/core/java/com/android/server/wm/ActivityServiceConnectionsHolder.java +++ b/services/core/java/com/android/server/wm/ActivityServiceConnectionsHolder.java @@ -73,7 +73,7 @@ public class ActivityServiceConnectionsHolder<T> { public boolean isActivityVisible() { synchronized (mService.mGlobalLock) { - return mActivity.visible || mActivity.isState(RESUMED, PAUSING); + return mActivity.mVisibleRequested || mActivity.isState(RESUMED, PAUSING); } } diff --git a/services/core/java/com/android/server/wm/ActivityStack.java b/services/core/java/com/android/server/wm/ActivityStack.java index 8d90d6d283c5..e22a6e234ea0 100644 --- a/services/core/java/com/android/server/wm/ActivityStack.java +++ b/services/core/java/com/android/server/wm/ActivityStack.java @@ -1628,7 +1628,8 @@ class ActivityStack extends TaskStack { prev = prev.completeFinishing("completePausedLocked"); } else if (prev.hasProcess()) { if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Enqueue pending stop if needed: " + prev - + " wasStopping=" + wasStopping + " visible=" + prev.visible); + + " wasStopping=" + wasStopping + + " visibleRequested=" + prev.mVisibleRequested); if (prev.deferRelaunchUntilPaused) { // Complete the deferred relaunch that was waiting for pause to complete. if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Re-launching after pause: " + prev); @@ -1638,7 +1639,7 @@ class ActivityStack extends TaskStack { // We can't clobber it, because the stop confirmation will not be handled. // We don't need to schedule another stop, we only need to let it happen. prev.setState(STOPPING, "completePausedLocked"); - } else if (!prev.visible || shouldSleepOrShutDownActivities()) { + } else if (!prev.mVisibleRequested || shouldSleepOrShutDownActivities()) { // Clear out any deferred client hide we might currently have. prev.setDeferHidingClient(false); // If we were visible then resumeTopActivities will release resources before @@ -1759,7 +1760,7 @@ class ActivityStack extends TaskStack { boolean isTopActivityVisible() { final ActivityRecord topActivity = getTopActivity(); - return topActivity != null && topActivity.visible; + return topActivity != null && topActivity.mVisibleRequested; } /** @@ -1900,7 +1901,7 @@ class ActivityStack extends TaskStack { for (int taskNdx = getChildCount() - 1; taskNdx >= 0; --taskNdx) { final Task task = getChildAt(taskNdx); ActivityRecord r = task.topRunningActivityLocked(); - if (r == null || r.finishing || !r.visible) { + if (r == null || r.finishing || !r.mVisibleRequested) { task.mLayerRank = -1; } else { task.mLayerRank = baseLayer + layer++; @@ -1989,7 +1990,7 @@ class ActivityStack extends TaskStack { if (!r.attachedToProcess()) { makeVisibleAndRestartIfNeeded(starting, configChanges, isTop, resumeTopActivity && isTop, r); - } else if (r.visible) { + } else if (r.mVisibleRequested) { // If this activity is already visible, then there is nothing to do here. if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY, "Skipping: already visible at " + r); @@ -2166,16 +2167,16 @@ class ActivityStack extends TaskStack { // invisible. If the app is already visible, it must have died while it was visible. In this // case, we'll show the dead window but will not restart the app. Otherwise we could end up // thrashing. - if (isTop || !r.visible) { + if (isTop || !r.mVisibleRequested) { // This activity needs to be visible, but isn't even running... // get it started and resume if no other stack in this stack is resumed. if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY, "Start and freeze screen for " + r); if (r != starting) { r.startFreezingScreenLocked(configChanges); } - if (!r.visible || r.mLaunchTaskBehind) { + if (!r.mVisibleRequested || r.mLaunchTaskBehind) { if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY, "Starting and making visible: " + r); - r.setVisible(true); + r.setVisibility(true); } if (r != starting) { mStackSupervisor.startSpecificActivityLocked(r, andResume, true /* checkConfig */); @@ -2618,7 +2619,8 @@ class ActivityStack extends TaskStack { if (next.attachedToProcess()) { if (DEBUG_SWITCH) Slog.v(TAG_SWITCH, "Resume running: " + next - + " stopped=" + next.stopped + " visible=" + next.visible); + + " stopped=" + next.stopped + + " visibleRequested=" + next.mVisibleRequested); // If the previous activity is translucent, force a visibility update of // the next activity, so that it's added to WM's opening app list, and @@ -2633,7 +2635,7 @@ class ActivityStack extends TaskStack { && !lastFocusedStack.mLastPausedActivity.occludesParent())); // This activity is now becoming visible. - if (!next.visible || next.stopped || lastActivityTranslucent) { + if (!next.mVisibleRequested || next.stopped || lastActivityTranslucent) { next.setVisibility(true); } @@ -2688,7 +2690,7 @@ class ActivityStack extends TaskStack { // Do over! mStackSupervisor.scheduleResumeTopActivities(); } - if (!next.visible || next.stopped) { + if (!next.mVisibleRequested || next.stopped) { next.setVisibility(true); } next.completeResumeLocked(); @@ -3357,7 +3359,7 @@ class ActivityStack extends TaskStack { final ActivityRecord top = stack.topRunningActivityLocked(); - if (stack.isActivityTypeHome() && (top == null || !top.visible)) { + if (stack.isActivityTypeHome() && (top == null || !top.mVisibleRequested)) { // If we will be focusing on the home stack next and its current top activity isn't // visible, then use the move the home stack task to top to make the activity visible. stack.getDisplay().moveHomeActivityToTop(reason); @@ -3851,7 +3853,7 @@ class ActivityStack extends TaskStack { "Record #" + targetIndex + " " + r + ": app=" + r.app); if (r.app == app) { - if (r.visible) { + if (r.mVisibleRequested) { hasVisibleActivities = true; } final boolean remove; @@ -3867,8 +3869,8 @@ class ActivityStack extends TaskStack { // Don't currently have state for the activity, or // it is finishing -- always remove it. remove = true; - } else if (!r.visible && r.launchCount > 2 && - r.lastLaunchTime > (SystemClock.uptimeMillis() - 60000)) { + } else if (!r.mVisibleRequested && r.launchCount > 2 + && r.lastLaunchTime > (SystemClock.uptimeMillis() - 60000)) { // We have launched this activity too many times since it was // able to run, so give up and remove it. // (Note if the activity is visible, we don't remove the record. @@ -3904,7 +3906,7 @@ class ActivityStack extends TaskStack { // it died, we leave the dead window on screen so it's basically visible. // This is needed when user later tap on the dead window, we need to stop // other apps when user transfers focus to the restarted activity. - r.nowVisible = r.visible; + r.nowVisible = r.mVisibleRequested; } r.cleanUp(true /* cleanServices */, true /* setState */); if (remove) { @@ -4086,7 +4088,7 @@ class ActivityStack extends TaskStack { * Ensures all visible activities at or below the input activity have the right configuration. */ void ensureVisibleActivitiesConfigurationLocked(ActivityRecord start, boolean preserveWindow) { - if (start == null || !start.visible) { + if (start == null || !start.mVisibleRequested) { return; } @@ -4481,7 +4483,7 @@ class ActivityStack extends TaskStack { final ActivityRecord a = task.getChildAt(activityNdx); if (a.info.packageName.equals(packageName)) { a.forceNewConfig = true; - if (starting != null && a == starting && a.visible) { + if (starting != null && a == starting && a.mVisibleRequested) { a.startFreezingScreenLocked(CONFIG_SCREEN_LAYOUT); } } diff --git a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java index 79fae068e720..e94ac4cc51e8 100644 --- a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java +++ b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java @@ -773,12 +773,11 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks { } if (r.getActivityStack().checkKeyguardVisibility(r, true /* shouldBeVisible */, - true /* isTop */)) { - // We only set the visibility to true if the activity is allowed to be visible - // based on - // keyguard state. This avoids setting this into motion in window manager that is - // later cancelled due to later calls to ensure visible activities that set - // visibility back to false. + true /* isTop */) && r.allowMoveToFront()) { + // We only set the visibility to true if the activity is not being launched in + // background, and is allowed to be visible based on keyguard state. This avoids + // setting this into motion in window manager that is later cancelled due to later + // calls to ensure visible activities that set visibility back to false. r.setVisibility(true); } diff --git a/services/core/java/com/android/server/wm/ActivityStartController.java b/services/core/java/com/android/server/wm/ActivityStartController.java index 3c79c32fb008..d3fd450f311a 100644 --- a/services/core/java/com/android/server/wm/ActivityStartController.java +++ b/services/core/java/com/android/server/wm/ActivityStartController.java @@ -182,9 +182,17 @@ public class ActivityStartController { final ActivityDisplay display = mService.mRootActivityContainer.getActivityDisplay(displayId); - // Make sure home stack exist on display. - final ActivityStack homeStack = - display.getOrCreateStack(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, ON_TOP); + // The home activity will be started later, defer resuming to avoid unneccerary operations + // (e.g. start home recursively) when creating home stack. + mSupervisor.beginDeferResume(); + final ActivityStack homeStack; + try { + // Make sure home stack exist on display. + homeStack = display.getOrCreateStack(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, + ON_TOP); + } finally { + mSupervisor.endDeferResume(); + } mLastHomeActivityStartResult = obtainStarter(intent, "startHomeActivity: " + reason) .setOutActivity(tmpOutRecord) diff --git a/services/core/java/com/android/server/wm/AppTransitionController.java b/services/core/java/com/android/server/wm/AppTransitionController.java index bef6af350269..ff1b42377f5f 100644 --- a/services/core/java/com/android/server/wm/AppTransitionController.java +++ b/services/core/java/com/android/server/wm/AppTransitionController.java @@ -688,15 +688,16 @@ public class AppTransitionController { * compare z-order. * * @param apps The list of apps to search. - * @param ignoreHidden If set to true, ignores apps that are {@link ActivityRecord#isHidden}. + * @param ignoreInvisible If set to true, ignores apps that are not + * {@link ActivityRecord#isVisible}. * @return The top {@link ActivityRecord}. */ - private ActivityRecord getTopApp(ArraySet<ActivityRecord> apps, boolean ignoreHidden) { + private ActivityRecord getTopApp(ArraySet<ActivityRecord> apps, boolean ignoreInvisible) { int topPrefixOrderIndex = Integer.MIN_VALUE; ActivityRecord topApp = null; for (int i = apps.size() - 1; i >= 0; i--) { final ActivityRecord app = apps.valueAt(i); - if (ignoreHidden && app.isHidden()) { + if (ignoreInvisible && !app.isVisible()) { continue; } final int prefixOrderIndex = app.getPrefixOrderIndex(); diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java index 7cca08f6cab0..e78e30248131 100644 --- a/services/core/java/com/android/server/wm/DisplayContent.java +++ b/services/core/java/com/android/server/wm/DisplayContent.java @@ -652,12 +652,12 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo + " config reported=" + w.isLastConfigReportedToClient()); final ActivityRecord activity = w.mActivityRecord; if (gone) Slog.v(TAG, " GONE: mViewVisibility=" + w.mViewVisibility - + " mRelayoutCalled=" + w.mRelayoutCalled + " hidden=" + w.mToken.isHidden() - + " hiddenRequested=" + (activity != null && activity.hiddenRequested) + + " mRelayoutCalled=" + w.mRelayoutCalled + " visible=" + w.mToken.isVisible() + + " visibleRequested=" + (activity != null && activity.mVisibleRequested) + " parentHidden=" + w.isParentWindowHidden()); else Slog.v(TAG, " VIS: mViewVisibility=" + w.mViewVisibility - + " mRelayoutCalled=" + w.mRelayoutCalled + " hidden=" + w.mToken.isHidden() - + " hiddenRequested=" + (activity != null && activity.hiddenRequested) + + " mRelayoutCalled=" + w.mRelayoutCalled + " visible=" + w.mToken.isVisible() + + " visibleRequested=" + (activity != null && activity.mVisibleRequested) + " parentHidden=" + w.isParentWindowHidden()); } @@ -1173,6 +1173,9 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo if (!isReady() || mActivityDisplay == null) { return; } + if (mDisplayRotation.isWaitingForRemoteRotation()) { + return; + } final boolean configUpdated = mActivityDisplay.updateDisplayOverrideConfigurationLocked(); if (configUpdated) { return; @@ -2257,7 +2260,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo */ boolean pointWithinAppWindow(int x, int y) { final int[] targetWindowType = {-1}; - final Consumer fn = PooledLambda.obtainConsumer((w, nonArg) -> { + final PooledConsumer fn = PooledLambda.obtainConsumer((w, nonArg) -> { if (targetWindowType[0] != -1) { return; } @@ -2268,7 +2271,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo } }, PooledLambda.__(WindowState.class), mTmpRect); forAllWindows(fn, true /* traverseTopToBottom */); - ((PooledConsumer) fn).recycle(); + fn.recycle(); return FIRST_APPLICATION_WINDOW <= targetWindowType[0] && targetWindowType[0] <= LAST_APPLICATION_WINDOW; } @@ -2391,6 +2394,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo mWindowingLayer.release(); mOverlayLayer.release(); mInputMonitor.onDisplayRemoved(); + mWmService.mDisplayNotificationController.dispatchDisplayRemoved(mActivityDisplay); } finally { mDisplayReady = false; mRemovingDisplay = false; diff --git a/services/core/java/com/android/server/wm/DisplayRotation.java b/services/core/java/com/android/server/wm/DisplayRotation.java index 67f1d1b217af..0c68084151c7 100644 --- a/services/core/java/com/android/server/wm/DisplayRotation.java +++ b/services/core/java/com/android/server/wm/DisplayRotation.java @@ -45,15 +45,19 @@ import android.database.ContentObserver; import android.hardware.power.V1_0.PowerHint; import android.net.Uri; import android.os.Handler; +import android.os.RemoteException; import android.os.SystemProperties; import android.os.UserHandle; import android.provider.Settings; import android.util.Slog; import android.util.SparseArray; +import android.view.IDisplayWindowRotationCallback; import android.view.Surface; +import android.view.WindowContainerTransaction; import com.android.internal.R; import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.util.function.pooled.PooledLambda; import com.android.server.LocalServices; import com.android.server.UiThread; import com.android.server.policy.WindowManagerPolicy; @@ -212,6 +216,31 @@ public class DisplayRotation { private boolean mDemoHdmiRotationLock; private boolean mDemoRotationLock; + private static final int REMOTE_ROTATION_TIMEOUT_MS = 800; + + private boolean mIsWaitingForRemoteRotation = false; + + private final Runnable mDisplayRotationHandlerTimeout = + new Runnable() { + @Override + public void run() { + continueRotation(mRotation, null /* transaction */); + } + }; + + private final IDisplayWindowRotationCallback mRemoteRotationCallback = + new IDisplayWindowRotationCallback.Stub() { + @Override + public void continueRotateDisplay(int targetRotation, + WindowContainerTransaction t) { + synchronized (mService.getWindowManagerLock()) { + mService.mH.sendMessage(PooledLambda.obtainMessage( + DisplayRotation::continueRotation, DisplayRotation.this, + targetRotation, t)); + } + } + }; + DisplayRotation(WindowManagerService service, DisplayContent displayContent) { this(service, displayContent, displayContent.getDisplayPolicy(), service.mDisplayWindowSettings, service.mContext, service.getWindowManagerLock()); @@ -471,9 +500,52 @@ public class DisplayRotation { prepareNormalRotationAnimation(); } + // The display is frozen now, give a remote handler (system ui) some time to reposition + // things. + startRemoteRotation(oldRotation, mRotation); + return true; } + /** + * A Remote rotation is when we are waiting for some registered (remote) + * {@link IDisplayWindowRotationController} to calculate and return some hierarchy operations + * to perform in sync with the rotation. + */ + boolean isWaitingForRemoteRotation() { + return mIsWaitingForRemoteRotation; + } + + private void startRemoteRotation(int fromRotation, int toRotation) { + if (mService.mDisplayRotationController == null) { + return; + } + mIsWaitingForRemoteRotation = true; + try { + mService.mDisplayRotationController.onRotateDisplay(mDisplayContent.getDisplayId(), + fromRotation, toRotation, mRemoteRotationCallback); + mService.mH.removeCallbacks(mDisplayRotationHandlerTimeout); + mService.mH.postDelayed(mDisplayRotationHandlerTimeout, REMOTE_ROTATION_TIMEOUT_MS); + } catch (RemoteException e) { + mIsWaitingForRemoteRotation = false; + return; + } + } + + private void continueRotation(int targetRotation, WindowContainerTransaction t) { + synchronized (mService.mGlobalLock) { + if (targetRotation != mRotation || !mIsWaitingForRemoteRotation) { + // Drop it, this is either coming from an outdated remote rotation; or, we've + // already moved on. + return; + } + mService.mH.removeCallbacks(mDisplayRotationHandlerTimeout); + mIsWaitingForRemoteRotation = false; + mService.mAtmService.applyContainerTransaction(t); + mDisplayContent.sendNewConfiguration(); + } + } + void prepareNormalRotationAnimation() { final RotationAnimationPair anim = selectRotationAnimation(); mService.startFreezingDisplayLocked(anim.mExit, anim.mEnter, mDisplayContent); diff --git a/services/core/java/com/android/server/wm/DisplayWindowListenerController.java b/services/core/java/com/android/server/wm/DisplayWindowListenerController.java new file mode 100644 index 000000000000..dbc452f6e026 --- /dev/null +++ b/services/core/java/com/android/server/wm/DisplayWindowListenerController.java @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.wm; + +import android.os.RemoteCallbackList; +import android.os.RemoteException; +import android.view.IDisplayWindowListener; + +/** + * Manages dispatch of relevant hierarchy changes to interested listeners. Listeners are assumed + * to be remote. + */ +class DisplayWindowListenerController { + RemoteCallbackList<IDisplayWindowListener> mDisplayListeners = new RemoteCallbackList<>(); + +// private final ArrayList<DisplayContainerListener> mDisplayListeners = new ArrayList<>(); + private final WindowManagerService mService; + + DisplayWindowListenerController(WindowManagerService service) { + mService = service; + } + + void registerListener(IDisplayWindowListener listener) { + synchronized (mService.mGlobalLock) { + mDisplayListeners.register(listener); + try { + for (int i = 0; i < mService.mAtmService.mRootActivityContainer.getChildCount(); + ++i) { + ActivityDisplay d = mService.mAtmService.mRootActivityContainer.getChildAt(i); + listener.onDisplayAdded(d.mDisplayId); + } + } catch (RemoteException e) { } + } + } + + void unregisterListener(IDisplayWindowListener listener) { + mDisplayListeners.unregister(listener); + } + + void dispatchDisplayAdded(ActivityDisplay display) { + int count = mDisplayListeners.beginBroadcast(); + for (int i = 0; i < count; ++i) { + try { + mDisplayListeners.getBroadcastItem(i).onDisplayAdded(display.mDisplayId); + } catch (RemoteException e) { + } + } + mDisplayListeners.finishBroadcast(); + } + + void dispatchDisplayRemoved(ActivityDisplay display) { + int count = mDisplayListeners.beginBroadcast(); + for (int i = 0; i < count; ++i) { + try { + mDisplayListeners.getBroadcastItem(i).onDisplayRemoved(display.mDisplayId); + } catch (RemoteException e) { + } + } + mDisplayListeners.finishBroadcast(); + } +} diff --git a/services/core/java/com/android/server/wm/RecentsAnimation.java b/services/core/java/com/android/server/wm/RecentsAnimation.java index caf95de75357..fc74d00e82db 100644 --- a/services/core/java/com/android/server/wm/RecentsAnimation.java +++ b/services/core/java/com/android/server/wm/RecentsAnimation.java @@ -107,7 +107,7 @@ class RecentsAnimation implements RecentsAnimationCallbacks, mTargetActivityType); ActivityRecord targetActivity = getTargetActivity(targetStack); if (targetActivity != null) { - if (targetActivity.visible || targetActivity.isTopRunningActivity()) { + if (targetActivity.mVisibleRequested || targetActivity.isTopRunningActivity()) { // The activity is ready. return; } @@ -189,7 +189,7 @@ class RecentsAnimation implements RecentsAnimationCallbacks, // Send launch hint if we are actually launching the target. If it's already visible // (shouldn't happen in general) we don't need to send it. - if (targetActivity == null || !targetActivity.visible) { + if (targetActivity == null || !targetActivity.mVisibleRequested) { mService.mRootActivityContainer.sendPowerHintForLaunchStartIfNeeded( true /* forceSend */, targetActivity); } diff --git a/services/core/java/com/android/server/wm/RootActivityContainer.java b/services/core/java/com/android/server/wm/RootActivityContainer.java index cb41372f6960..5a21016e54dc 100644 --- a/services/core/java/com/android/server/wm/RootActivityContainer.java +++ b/services/core/java/com/android/server/wm/RootActivityContainer.java @@ -1156,6 +1156,9 @@ class RootActivityContainer extends ConfigurationContainer final ActivityStack focusedStack = display.getFocusedStack(); if (focusedStack != null) { result |= focusedStack.resumeTopActivityUncheckedLocked(target, targetOptions); + } else if (targetStack == null && !display.hasChild()) { + result |= resumeHomeActivity(null /* prev */, "empty-display", + display.mDisplayId); } } } diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java index 4038548e8b74..60b7ac09b3fb 100644 --- a/services/core/java/com/android/server/wm/Task.java +++ b/services/core/java/com/android/server/wm/Task.java @@ -60,9 +60,7 @@ import static com.android.server.EventLogTags.WM_TASK_CREATED; import static com.android.server.EventLogTags.WM_TASK_REMOVED; import static com.android.server.am.TaskRecordProto.ACTIVITIES; import static com.android.server.am.TaskRecordProto.ACTIVITY_TYPE; -import static com.android.server.am.TaskRecordProto.BOUNDS; import static com.android.server.am.TaskRecordProto.FULLSCREEN; -import static com.android.server.am.TaskRecordProto.ID; import static com.android.server.am.TaskRecordProto.LAST_NON_FULLSCREEN_BOUNDS; import static com.android.server.am.TaskRecordProto.MIN_HEIGHT; import static com.android.server.am.TaskRecordProto.MIN_WIDTH; @@ -89,10 +87,8 @@ import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLAS import static com.android.server.wm.DragResizeMode.DRAG_RESIZE_MODE_DOCKED_DIVIDER; import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_ADD_REMOVE; import static com.android.server.wm.TaskProto.APP_WINDOW_TOKENS; -import static com.android.server.wm.TaskProto.BOUNDS; import static com.android.server.wm.TaskProto.DISPLAYED_BOUNDS; import static com.android.server.wm.TaskProto.FILLS_PARENT; -import static com.android.server.wm.TaskProto.ID; import static com.android.server.wm.TaskProto.SURFACE_HEIGHT; import static com.android.server.wm.TaskProto.SURFACE_WIDTH; import static com.android.server.wm.TaskProto.WINDOW_CONTAINER; @@ -682,7 +678,7 @@ class Task extends WindowContainer<ActivityRecord> implements ConfigurationConta // actual reparent. if (inPinnedWindowingMode() && !(toStackWindowingMode == WINDOWING_MODE_UNDEFINED) - && !r.isHidden()) { + && r.isVisible()) { r.savePinnedStackBounds(); } final boolean wasFocused = r != null && root.isTopDisplayFocusedStack(sourceStack) @@ -2209,7 +2205,7 @@ class Task extends WindowContainer<ActivityRecord> implements ConfigurationConta void addStartingWindowsForVisibleActivities(boolean taskSwitch) { for (int activityNdx = getChildCount() - 1; activityNdx >= 0; --activityNdx) { final ActivityRecord r = getChildAt(activityNdx); - if (r.visible) { + if (r.mVisibleRequested) { r.showStartingWindow(null /* prev */, false /* newTask */, taskSwitch); } } @@ -2531,7 +2527,7 @@ class Task extends WindowContainer<ActivityRecord> implements ConfigurationConta for (int i = mChildren.size() - 1; i >= 0; i--) { final ActivityRecord token = mChildren.get(i); // skip hidden (or about to hide) apps - if (token.mIsExiting || token.isClientHidden() || token.hiddenRequested) { + if (token.mIsExiting || token.isClientHidden() || !token.mVisibleRequested) { continue; } final WindowState win = token.findMainWindow(); @@ -2751,7 +2747,7 @@ class Task extends WindowContainer<ActivityRecord> implements ConfigurationConta for (int i = mChildren.size() - 1; i >= 0; i--) { final ActivityRecord token = mChildren.get(i); // skip hidden (or about to hide) apps - if (!token.mIsExiting && !token.isClientHidden() && !token.hiddenRequested) { + if (!token.mIsExiting && !token.isClientHidden() && token.mVisibleRequested) { return token; } } diff --git a/services/core/java/com/android/server/wm/WallpaperController.java b/services/core/java/com/android/server/wm/WallpaperController.java index 3632284fdeb6..6ff4b2e504f1 100644 --- a/services/core/java/com/android/server/wm/WallpaperController.java +++ b/services/core/java/com/android/server/wm/WallpaperController.java @@ -120,7 +120,7 @@ class WallpaperController { } mFindResults.resetTopWallpaper = true; - if (w.mActivityRecord != null && w.mActivityRecord.isHidden() + if (w.mActivityRecord != null && !w.mActivityRecord.isVisible() && !w.mActivityRecord.isAnimating(TRANSITION)) { // If this window's app token is hidden and not animating, it is of no interest to us. @@ -278,9 +278,11 @@ class WallpaperController { for (int i = mWallpaperTokens.size() - 1; i >= 0; i--) { final WallpaperWindowToken token = mWallpaperTokens.get(i); token.hideWallpaperToken(wasDeferred, "hideWallpapers"); - if (DEBUG_WALLPAPER_LIGHT && !token.isHidden()) Slog.d(TAG, "Hiding wallpaper " + token - + " from " + winGoingAway + " target=" + mWallpaperTarget + " prev=" - + mPrevWallpaperTarget + "\n" + Debug.getCallers(5, " ")); + if (DEBUG_WALLPAPER_LIGHT && token.isVisible()) { + Slog.d(TAG, "Hiding wallpaper " + token + + " from " + winGoingAway + " target=" + mWallpaperTarget + " prev=" + + mPrevWallpaperTarget + "\n" + Debug.getCallers(5, " ")); + } } } @@ -532,9 +534,9 @@ class WallpaperController { } final boolean newTargetHidden = wallpaperTarget.mActivityRecord != null - && wallpaperTarget.mActivityRecord.hiddenRequested; + && !wallpaperTarget.mActivityRecord.mVisibleRequested; final boolean oldTargetHidden = prevWallpaperTarget.mActivityRecord != null - && prevWallpaperTarget.mActivityRecord.hiddenRequested; + && !prevWallpaperTarget.mActivityRecord.mVisibleRequested; if (DEBUG_WALLPAPER_LIGHT) Slog.v(TAG, "Animating wallpapers:" + " old: " + prevWallpaperTarget + " hidden=" + oldTargetHidden + " new: " + wallpaperTarget diff --git a/services/core/java/com/android/server/wm/WallpaperWindowToken.java b/services/core/java/com/android/server/wm/WallpaperWindowToken.java index 528cece9a78b..d23bf978cbab 100644 --- a/services/core/java/com/android/server/wm/WallpaperWindowToken.java +++ b/services/core/java/com/android/server/wm/WallpaperWindowToken.java @@ -56,7 +56,6 @@ class WallpaperWindowToken extends WindowToken { final WindowState wallpaper = mChildren.get(j); wallpaper.hideWallpaperWindow(wasDeferred, reason); } - setHidden(true); } void sendWindowWallpaperCommand( @@ -88,9 +87,7 @@ class WallpaperWindowToken extends WindowToken { final int dw = displayInfo.logicalWidth; final int dh = displayInfo.logicalHeight; - if (isHidden() == visible) { - setHidden(!visible); - + if (isVisible() != visible) { // Need to do a layout to ensure the wallpaper now has the correct size. mDisplayContent.setLayoutNeeded(); } @@ -118,10 +115,9 @@ class WallpaperWindowToken extends WindowToken { void updateWallpaperWindows(boolean visible) { - if (isHidden() == visible) { + if (isVisible() != visible) { if (DEBUG_WALLPAPER_LIGHT) Slog.d(TAG, - "Wallpaper token " + token + " hidden=" + !visible); - setHidden(!visible); + "Wallpaper token " + token + " visible=" + visible); // Need to do a layout to ensure the wallpaper now has the correct size. mDisplayContent.setLayoutNeeded(); } diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index fc8705bbaae6..9bdf010703d8 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -19,6 +19,7 @@ package com.android.server.wm; import static android.Manifest.permission.ACCESS_SURFACE_FLINGER; import static android.Manifest.permission.CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS; import static android.Manifest.permission.INTERNAL_SYSTEM_WINDOW; +import static android.Manifest.permission.MANAGE_ACTIVITY_STACKS; import static android.Manifest.permission.MANAGE_APP_TOKENS; import static android.Manifest.permission.READ_FRAME_BUFFER; import static android.Manifest.permission.REGISTER_WINDOW_MANAGER_LISTENERS; @@ -211,6 +212,8 @@ import android.view.DisplayInfo; import android.view.Gravity; import android.view.IAppTransitionAnimationSpecsFuture; import android.view.IDisplayFoldListener; +import android.view.IDisplayWindowListener; +import android.view.IDisplayWindowRotationController; import android.view.IDockedStackListener; import android.view.IInputFilter; import android.view.IOnKeyguardExitResult; @@ -260,6 +263,7 @@ import com.android.internal.util.DumpUtils; import com.android.internal.util.FastPrintWriter; import com.android.internal.util.LatencyTracker; import com.android.internal.util.Preconditions; +import com.android.internal.util.function.pooled.PooledConsumer; import com.android.internal.util.function.pooled.PooledLambda; import com.android.internal.view.WindowManagerPolicyThread; import com.android.server.AnimationThread; @@ -433,8 +437,10 @@ public class WindowManagerService extends IWindowManager.Stub public void onVrStateChanged(boolean enabled) { synchronized (mGlobalLock) { mVrModeEnabled = enabled; - mRoot.forAllDisplayPolicies(PooledLambda.obtainConsumer( - DisplayPolicy::onVrStateChangedLw, PooledLambda.__(), enabled)); + final PooledConsumer c = PooledLambda.obtainConsumer( + DisplayPolicy::onVrStateChangedLw, PooledLambda.__(), enabled); + mRoot.forAllDisplayPolicies(c); + c.recycle(); } } }; @@ -658,6 +664,12 @@ public class WindowManagerService extends IWindowManager.Stub final WallpaperVisibilityListeners mWallpaperVisibilityListeners = new WallpaperVisibilityListeners(); + IDisplayWindowRotationController mDisplayRotationController = null; + private final DeathRecipient mDisplayRotationControllerDeath = + () -> mDisplayRotationController = null; + + final DisplayWindowListenerController mDisplayNotificationController; + boolean mDisplayFrozen = false; long mDisplayFreezeTime = 0; int mLastDisplayFreezeDuration = 0; @@ -827,9 +839,11 @@ public class WindowManagerService extends IWindowManager.Stub } mPointerLocationEnabled = enablePointerLocation; synchronized (mGlobalLock) { - mRoot.forAllDisplayPolicies(PooledLambda.obtainConsumer( + final PooledConsumer c = PooledLambda.obtainConsumer( DisplayPolicy::setPointerLocationEnabled, PooledLambda.__(), - mPointerLocationEnabled)); + mPointerLocationEnabled); + mRoot.forAllDisplayPolicies(c); + c.recycle(); } } @@ -1181,6 +1195,8 @@ public class WindowManagerService extends IWindowManager.Stub PowerManager.PARTIAL_WAKE_LOCK, "SCREEN_FROZEN"); mScreenFrozenLock.setReferenceCounted(false); + mDisplayNotificationController = new DisplayWindowListenerController(this); + mActivityManager = ActivityManager.getService(); mActivityTaskManager = ActivityTaskManager.getService(); mAmInternal = LocalServices.getService(ActivityManagerInternal.class); @@ -2797,8 +2813,10 @@ public class WindowManagerService extends IWindowManager.Stub @Override public void onPowerKeyDown(boolean isScreenOn) { - mRoot.forAllDisplayPolicies(PooledLambda.obtainConsumer( - DisplayPolicy::onPowerKeyDown, PooledLambda.__(), isScreenOn)); + final PooledConsumer c = PooledLambda.obtainConsumer( + DisplayPolicy::onPowerKeyDown, PooledLambda.__(), isScreenOn); + mRoot.forAllDisplayPolicies(c); + c.recycle(); } @Override @@ -3781,6 +3799,27 @@ public class WindowManagerService extends IWindowManager.Stub } @Override + public void setDisplayWindowRotationController(IDisplayWindowRotationController controller) { + if (mContext.checkCallingOrSelfPermission(MANAGE_ACTIVITY_STACKS) + != PackageManager.PERMISSION_GRANTED) { + throw new SecurityException("Must hold permission " + MANAGE_ACTIVITY_STACKS); + } + try { + synchronized (mGlobalLock) { + if (mDisplayRotationController != null) { + mDisplayRotationController.asBinder().unlinkToDeath( + mDisplayRotationControllerDeath, 0); + mDisplayRotationController = null; + } + controller.asBinder().linkToDeath(mDisplayRotationControllerDeath, 0); + mDisplayRotationController = controller; + } + } catch (RemoteException e) { + throw new RuntimeException("Unable to set rotation controller"); + } + } + + @Override public int watchRotation(IRotationWatcher watcher, int displayId) { final DisplayContent displayContent; synchronized (mGlobalLock) { @@ -3944,6 +3983,31 @@ public class WindowManagerService extends IWindowManager.Stub } } + /** Registers a hierarchy listener that gets callbacks when the hierarchy changes. */ + @Override + public void registerDisplayWindowListener(IDisplayWindowListener listener) { + if (mContext.checkCallingOrSelfPermission(MANAGE_ACTIVITY_STACKS) + != PackageManager.PERMISSION_GRANTED) { + throw new SecurityException("Must hold permission " + MANAGE_ACTIVITY_STACKS); + } + long ident = Binder.clearCallingIdentity(); + try { + mDisplayNotificationController.registerListener(listener); + } finally { + Binder.restoreCallingIdentity(ident); + } + } + + /** Unregister a hierarchy listener so that it stops receiving callbacks. */ + @Override + public void unregisterDisplayWindowListener(IDisplayWindowListener listener) { + if (mContext.checkCallingOrSelfPermission(MANAGE_ACTIVITY_STACKS) + != PackageManager.PERMISSION_GRANTED) { + throw new SecurityException("Must hold permission " + MANAGE_ACTIVITY_STACKS); + } + mDisplayNotificationController.unregisterListener(listener); + } + @Override public int getPreferredOptionsPanelGravity(int displayId) { synchronized (mGlobalLock) { @@ -5623,8 +5687,10 @@ public class WindowManagerService extends IWindowManager.Stub + android.Manifest.permission.STATUS_BAR); } synchronized (mGlobalLock) { - mRoot.forAllDisplayPolicies(PooledLambda.obtainConsumer( - DisplayPolicy::setForceShowSystemBars, PooledLambda.__(), show)); + final PooledConsumer c = PooledLambda.obtainConsumer( + DisplayPolicy::setForceShowSystemBars, PooledLambda.__(), show); + mRoot.forAllDisplayPolicies(c); + c.recycle(); } } @@ -7564,8 +7630,10 @@ public class WindowManagerService extends IWindowManager.Stub void onLockTaskStateChanged(int lockTaskState) { // TODO: pass in displayId to determine which display the lock task state changed synchronized (mGlobalLock) { - mRoot.forAllDisplayPolicies(PooledLambda.obtainConsumer( - DisplayPolicy::onLockTaskStateChangedLw, PooledLambda.__(), lockTaskState)); + final PooledConsumer c = PooledLambda.obtainConsumer( + DisplayPolicy::onLockTaskStateChangedLw, PooledLambda.__(), lockTaskState); + mRoot.forAllDisplayPolicies(c); + c.recycle(); } } diff --git a/services/core/java/com/android/server/wm/WindowProcessController.java b/services/core/java/com/android/server/wm/WindowProcessController.java index d63fbc217e54..2e188b7cc86d 100644 --- a/services/core/java/com/android/server/wm/WindowProcessController.java +++ b/services/core/java/com/android/server/wm/WindowProcessController.java @@ -533,7 +533,7 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio synchronized (mAtm.mGlobalLockWithoutBoost) { for (int i = mActivities.size() - 1; i >= 0; --i) { final ActivityRecord r = mActivities.get(i); - if (r.visible) { + if (r.mVisibleRequested) { return true; } } @@ -555,7 +555,7 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio continue; } ActivityRecord topActivity = task.getTopActivity(); - if (topActivity != null && topActivity.visible) { + if (topActivity != null && topActivity.mVisibleRequested) { return true; } } @@ -589,7 +589,7 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio // - no longer visible OR // - not focusable (in PiP mode for instance) if (topDisplay == null - || !mPreQTopResumedActivity.visible + || !mPreQTopResumedActivity.mVisibleRequested || !mPreQTopResumedActivity.isFocusable()) { canUpdate = true; } @@ -739,7 +739,7 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio } // Don't consider any activities that are currently not in a state where they // can be destroyed. - if (r.visible || !r.stopped || !r.hasSavedState() + if (r.mVisibleRequested || !r.stopped || !r.hasSavedState() || r.isState(STARTED, RESUMED, PAUSING, PAUSED, STOPPING)) { if (DEBUG_RELEASE) Slog.d(TAG_RELEASE, "Not releasing in-use activity: " + r); continue; @@ -793,7 +793,7 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio continue; } } - if (r.visible) { + if (r.mVisibleRequested) { final Task task = r.getTask(); if (task != null && minTaskLayer > 0) { final int layer = task.mLayerRank; diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java index d5905720a611..4047bdd1b858 100644 --- a/services/core/java/com/android/server/wm/WindowState.java +++ b/services/core/java/com/android/server/wm/WindowState.java @@ -1554,7 +1554,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP */ // TODO: Can we consolidate this with #isVisible() or have a more appropriate name for this? boolean isWinVisibleLw() { - return (mActivityRecord == null || !mActivityRecord.hiddenRequested + return (mActivityRecord == null || mActivityRecord.mVisibleRequested || mActivityRecord.isAnimating(TRANSITION)) && isVisible(); } @@ -1563,7 +1563,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP * not the pending requested hidden state. */ boolean isVisibleNow() { - return (!mToken.isHidden() || mAttrs.type == TYPE_APPLICATION_STARTING) + return (mToken.isVisible() || mAttrs.type == TYPE_APPLICATION_STARTING) && isVisible(); } @@ -1585,7 +1585,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP final ActivityRecord atoken = mActivityRecord; return (mHasSurface || (!mRelayoutCalled && mViewVisibility == View.VISIBLE)) && isVisibleByPolicy() && !isParentWindowHidden() - && (atoken == null || !atoken.hiddenRequested) + && (atoken == null || atoken.mVisibleRequested) && !mAnimatingExit && !mDestroying; } @@ -1600,7 +1600,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP } final ActivityRecord atoken = mActivityRecord; if (atoken != null) { - return ((!isParentWindowHidden() && !atoken.hiddenRequested) + return ((!isParentWindowHidden() && atoken.mVisibleRequested) || isAnimating(TRANSITION | PARENTS)); } return !isParentWindowHidden() || isAnimating(TRANSITION | PARENTS); @@ -1636,7 +1636,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP return false; } final boolean parentAndClientVisible = !isParentWindowHidden() - && mViewVisibility == View.VISIBLE && !mToken.isHidden(); + && mViewVisibility == View.VISIBLE && mToken.isVisible(); return mHasSurface && isVisibleByPolicy() && !mDestroying && (parentAndClientVisible || isAnimating(TRANSITION | PARENTS)); } @@ -1655,7 +1655,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP } else { final Task task = getTask(); final boolean canFromTask = task != null && task.canAffectSystemUiFlags(); - return canFromTask && !mActivityRecord.isHidden(); + return canFromTask && mActivityRecord.isVisible(); } } @@ -1667,7 +1667,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP public boolean isDisplayedLw() { final ActivityRecord atoken = mActivityRecord; return isDrawnLw() && isVisibleByPolicy() - && ((!isParentWindowHidden() && (atoken == null || !atoken.hiddenRequested)) + && ((!isParentWindowHidden() && (atoken == null || atoken.mVisibleRequested)) || isAnimating(TRANSITION | PARENTS)); } @@ -1684,8 +1684,8 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP final ActivityRecord atoken = mActivityRecord; return mViewVisibility == View.GONE || !mRelayoutCalled - || (atoken == null && mToken.isHidden()) - || (atoken != null && atoken.hiddenRequested) + || (atoken == null && !mToken.isVisible()) + || (atoken != null && !atoken.mVisibleRequested) || isParentWindowGoneForLayout() || (mAnimatingExit && !isAnimatingLw()) || mDestroying; @@ -2177,7 +2177,8 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP + " parentHidden=" + isParentWindowHidden() + " exiting=" + mAnimatingExit + " destroying=" + mDestroying); if (mActivityRecord != null) { - Slog.i(TAG_WM, " mActivityRecord.hiddenRequested=" + mActivityRecord.hiddenRequested); + Slog.i(TAG_WM, " mActivityRecord.visibleRequested=" + + mActivityRecord.mVisibleRequested); } } } @@ -2625,14 +2626,14 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP return showBecauseOfActivity || showBecauseOfWindow; } - /** @return false if this window desires touch events. */ + /** @return {@code false} if this window desires touch events. */ boolean cantReceiveTouchInput() { if (mActivityRecord == null || mActivityRecord.getTask() == null) { return false; } return mActivityRecord.getTask().getTaskStack().shouldIgnoreInput() - || mActivityRecord.hiddenRequested + || !mActivityRecord.mVisibleRequested || isAnimatingToRecents(); } @@ -4163,9 +4164,9 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP + " starting=" + (mAttrs.type == TYPE_APPLICATION_STARTING) + " during animation: policyVis=" + isVisibleByPolicy() + " parentHidden=" + isParentWindowHidden() - + " tok.hiddenRequested=" - + (mActivityRecord != null && mActivityRecord.hiddenRequested) - + " tok.hidden=" + (mActivityRecord != null && mActivityRecord.isHidden()) + + " tok.visibleRequested=" + + (mActivityRecord != null && mActivityRecord.mVisibleRequested) + + " tok.visible=" + (mActivityRecord != null && mActivityRecord.isVisible()) + " animating=" + isAnimating(TRANSITION | PARENTS) + " tok animating=" + (mActivityRecord != null && mActivityRecord.isAnimating(TRANSITION)) @@ -4572,7 +4573,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP + " pv=" + isVisibleByPolicy() + " mDrawState=" + mWinAnimator.mDrawState + " ph=" + isParentWindowHidden() - + " th=" + (mActivityRecord != null ? mActivityRecord.hiddenRequested : false) + + " th=" + (mActivityRecord != null && mActivityRecord.mVisibleRequested) + " a=" + isAnimating(TRANSITION | PARENTS)); } } diff --git a/services/core/java/com/android/server/wm/WindowToken.java b/services/core/java/com/android/server/wm/WindowToken.java index 88a1458a783f..6480a15a4220 100644 --- a/services/core/java/com/android/server/wm/WindowToken.java +++ b/services/core/java/com/android/server/wm/WindowToken.java @@ -29,7 +29,6 @@ import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_NORMAL; import static com.android.server.wm.WindowTokenProto.HASH_CODE; -import static com.android.server.wm.WindowTokenProto.HIDDEN; import static com.android.server.wm.WindowTokenProto.PAUSED; import static com.android.server.wm.WindowTokenProto.WAITING_TO_SHOW; import static com.android.server.wm.WindowTokenProto.WINDOWS; @@ -72,9 +71,6 @@ class WindowToken extends WindowContainer<WindowState> { // Is key dispatching paused for this token? boolean paused = false; - // Should this token's windows be hidden? - private boolean mHidden; - // Temporary for finding which tokens no longer have visible windows. boolean hasVisible; @@ -128,16 +124,6 @@ class WindowToken extends WindowContainer<WindowState> { } } - void setHidden(boolean hidden) { - if (hidden != mHidden) { - mHidden = hidden; - } - } - - boolean isHidden() { - return mHidden; - } - void removeAllWindowsIfPossible() { for (int i = mChildren.size() - 1; i >= 0; --i) { final WindowState win = mChildren.get(i); @@ -156,7 +142,7 @@ class WindowToken extends WindowContainer<WindowState> { // This token is exiting, so allow it to be removed when it no longer contains any windows. mPersistOnEmpty = false; - if (mHidden) { + if (!isVisible()) { return; } @@ -169,7 +155,10 @@ class WindowToken extends WindowContainer<WindowState> { changed |= win.onSetAppExiting(); } - setHidden(true); + final ActivityRecord app = asActivityRecord(); + if (app != null) { + app.setVisible(false); + } if (changed) { mWmService.mWindowPlacerLocked.performSurfacePlacement(); @@ -286,7 +275,6 @@ class WindowToken extends WindowContainer<WindowState> { final WindowState w = mChildren.get(i); w.writeToProto(proto, WINDOWS, logLevel); } - proto.write(HIDDEN, mHidden); proto.write(WAITING_TO_SHOW, waitingToShow); proto.write(PAUSED, paused); proto.end(token); @@ -296,8 +284,7 @@ class WindowToken extends WindowContainer<WindowState> { super.dump(pw, prefix, dumpAll); pw.print(prefix); pw.print("windows="); pw.println(mChildren); pw.print(prefix); pw.print("windowType="); pw.print(windowType); - pw.print(" hidden="); pw.print(mHidden); - pw.print(" hasVisible="); pw.println(hasVisible); + pw.print(" hasVisible="); pw.println(hasVisible); if (waitingToShow || sendingToBottom) { pw.print(prefix); pw.print("waitingToShow="); pw.print(waitingToShow); pw.print(" sendingToBottom="); pw.print(sendingToBottom); diff --git a/services/tests/servicestests/src/com/android/server/content/SyncStorageEngineTest.java b/services/tests/servicestests/src/com/android/server/content/SyncStorageEngineTest.java new file mode 100644 index 000000000000..2e2270bc6ef5 --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/content/SyncStorageEngineTest.java @@ -0,0 +1,200 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.server.content; + +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertFalse; + +import android.content.Context; +import android.content.SyncStatusInfo; +import android.util.Pair; +import android.util.SparseArray; + +import androidx.test.InstrumentationRegistry; +import androidx.test.runner.AndroidJUnit4; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.util.ArrayList; +import java.util.Random; + +/** + * Tests for {@link SyncStorageEngine}. + */ +@RunWith(AndroidJUnit4.class) +public class SyncStorageEngineTest { + + private Context mContext; + private SyncStorageEngine mSyncStorageEngine; + + private static final int NUM_SYNC_STATUS = 100; + private static final int NUM_PERIODIC_SYNC_TIMES = 20; + private static final int NUM_EVENTS = 10; + private static final int NUM_SOURCES = 6; + + @Before + public void setUp() { + mContext = InstrumentationRegistry.getTargetContext(); + mSyncStorageEngine = SyncStorageEngine.newTestInstance(mContext); + } + + @Test + public void testStatisticsReadWrite() { + populateDayStats(mSyncStorageEngine.mDayStats); + mSyncStorageEngine.writeStatisticsLocked(); + + final SyncStorageEngine other = SyncStorageEngine.newTestInstance(mContext); + verifyDayStats(mSyncStorageEngine.mDayStats, other.getDayStatistics()); + } + + @Test + public void testStatusReadWrite() { + populateStatus(mSyncStorageEngine.mSyncStatus); + mSyncStorageEngine.writeStatusLocked(); + + final SyncStorageEngine other = SyncStorageEngine.newTestInstance(mContext); + for (int i = 0; i < NUM_SYNC_STATUS; i++) { + other.mAuthorities.put(i, null); + } + other.readStatusLocked(); + verifyStatus(mSyncStorageEngine.mSyncStatus, other.mSyncStatus); + } + + private void populateDayStats(SyncStorageEngine.DayStats[] dayStats) { + final Random r = new Random(1); + for (int i = 0; i < dayStats.length; i++) { + final SyncStorageEngine.DayStats ds = new SyncStorageEngine.DayStats(i); + ds.successCount = r.nextInt(); + ds.successTime = r.nextLong(); + ds.failureCount = r.nextInt(); + ds.failureTime = r.nextLong(); + dayStats[i] = ds; + } + } + + private void verifyDayStats(SyncStorageEngine.DayStats[] dayStats, + SyncStorageEngine.DayStats[] dayStatsOther) { + assertEquals(dayStatsOther.length, dayStats.length); + for (int i = 0; i < dayStatsOther.length; i++) { + final SyncStorageEngine.DayStats ds = dayStats[i]; + final SyncStorageEngine.DayStats dsOther = dayStatsOther[i]; + assertEquals(dsOther.day, ds.day); + assertEquals(dsOther.successCount, ds.successCount); + assertEquals(dsOther.successTime, ds.successTime); + assertEquals(dsOther.failureCount, ds.failureCount); + assertEquals(dsOther.failureTime, ds.failureTime); + } + } + + private void populateStatus(SparseArray<SyncStatusInfo> syncStatus) { + final Random r = new Random(1); + for (int i = 0; i < NUM_SYNC_STATUS; i++) { + final SyncStatusInfo ss = new SyncStatusInfo(i); + ss.lastSuccessTime = r.nextLong(); + ss.lastSuccessSource = r.nextInt(); + ss.lastFailureTime = r.nextLong(); + ss.lastFailureSource = r.nextInt(); + ss.lastFailureMesg = "fail_msg_" + r.nextInt(); + ss.initialFailureTime = r.nextLong(); + ss.initialize = r.nextBoolean(); + for (int j = 0; j < NUM_PERIODIC_SYNC_TIMES; j++) { + ss.addPeriodicSyncTime(r.nextLong()); + } + final ArrayList<Pair<Long, String>> lastEventInfos = new ArrayList<>(); + for (int j = 0; j < NUM_EVENTS; j++) { + lastEventInfos.add(new Pair<>(r.nextLong(), "event_" + r.nextInt())); + } + ss.populateLastEventsInformation(lastEventInfos); + ss.lastTodayResetTime = r.nextLong(); + populateStats(ss.totalStats, r); + populateStats(ss.todayStats, r); + populateStats(ss.yesterdayStats, r); + for (int j = 0; j < NUM_SOURCES; j++) { + ss.perSourceLastSuccessTimes[j] = r.nextLong(); + } + for (int j = 0; j < NUM_SOURCES; j++) { + ss.perSourceLastFailureTimes[j] = r.nextLong(); + } + syncStatus.put(i, ss); + } + } + + private void populateStats(SyncStatusInfo.Stats stats, Random r) { + stats.totalElapsedTime = r.nextLong(); + stats.numSyncs = r.nextInt(); + stats.numFailures = r.nextInt(); + stats.numCancels = r.nextInt(); + stats.numSourceOther = r.nextInt(); + stats.numSourceLocal = r.nextInt(); + stats.numSourcePoll = r.nextInt(); + stats.numSourceUser = r.nextInt(); + stats.numSourcePeriodic = r.nextInt(); + stats.numSourceFeed = r.nextInt(); + } + + private void verifyStatus(SparseArray<SyncStatusInfo> syncStatus, + SparseArray<SyncStatusInfo> syncStatusOther) { + assertEquals(syncStatusOther.size(), syncStatus.size()); + for (int i = 0; i < NUM_SYNC_STATUS; i++) { + final SyncStatusInfo ss = syncStatus.valueAt(i); + final SyncStatusInfo ssOther = syncStatusOther.valueAt(i); + assertEquals(ssOther.authorityId, ss.authorityId); + assertEquals(ssOther.lastSuccessTime, ss.lastSuccessTime); + assertEquals(ssOther.lastSuccessSource, ss.lastSuccessSource); + assertEquals(ssOther.lastFailureTime, ss.lastFailureTime); + assertEquals(ssOther.lastFailureSource, ss.lastFailureSource); + assertEquals(ssOther.lastFailureMesg, ss.lastFailureMesg); + assertFalse(ssOther.pending); // pending is always set to false when read + assertEquals(ssOther.initialize, ss.initialize); + assertEquals(ssOther.getPeriodicSyncTimesSize(), NUM_PERIODIC_SYNC_TIMES); + for (int j = 0; j < NUM_PERIODIC_SYNC_TIMES; j++) { + assertEquals(ssOther.getPeriodicSyncTime(j), ss.getPeriodicSyncTime(j)); + } + assertEquals(ssOther.getEventCount(), NUM_EVENTS); + for (int j = 0; j < NUM_EVENTS; j++) { + assertEquals(ssOther.getEventTime(j), ss.getEventTime(j)); + assertEquals(ssOther.getEvent(j), ss.getEvent(j)); + } + assertEquals(ssOther.lastTodayResetTime, ss.lastTodayResetTime); + verifyStats(ss.totalStats, ssOther.totalStats); + verifyStats(ss.todayStats, ssOther.todayStats); + verifyStats(ss.yesterdayStats, ssOther.yesterdayStats); + assertEquals(ssOther.perSourceLastSuccessTimes.length, NUM_SOURCES); + for (int j = 0; j < NUM_SOURCES; j++) { + assertEquals(ssOther.perSourceLastSuccessTimes[j], ss.perSourceLastSuccessTimes[j]); + } + assertEquals(ssOther.perSourceLastFailureTimes.length, NUM_SOURCES); + for (int j = 0; j < NUM_SOURCES; j++) { + assertEquals(ssOther.perSourceLastFailureTimes[j], ss.perSourceLastFailureTimes[j]); + } + } + } + + private void verifyStats(SyncStatusInfo.Stats stats, SyncStatusInfo.Stats statsOther) { + assertEquals(statsOther.totalElapsedTime, stats.totalElapsedTime); + assertEquals(statsOther.numSyncs, stats.numSyncs); + assertEquals(statsOther.numFailures, stats.numFailures); + assertEquals(statsOther.numCancels, stats.numCancels); + assertEquals(statsOther.numSourceOther, stats.numSourceOther); + assertEquals(statsOther.numSourceLocal, stats.numSourceLocal); + assertEquals(statsOther.numSourcePoll, stats.numSourcePoll); + assertEquals(statsOther.numSourceUser, stats.numSourceUser); + assertEquals(statsOther.numSourcePeriodic, stats.numSourcePeriodic); + assertEquals(statsOther.numSourceFeed, stats.numSourceFeed); + } +} diff --git a/services/tests/servicestests/src/com/android/server/stats/ProcfsMemoryUtilTest.java b/services/tests/servicestests/src/com/android/server/stats/ProcfsMemoryUtilTest.java deleted file mode 100644 index d1ac19c540a4..000000000000 --- a/services/tests/servicestests/src/com/android/server/stats/ProcfsMemoryUtilTest.java +++ /dev/null @@ -1,141 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.android.server.stats; - -import static com.android.server.stats.ProcfsMemoryUtil.parseCmdline; -import static com.android.server.stats.ProcfsMemoryUtil.parseMemorySnapshotFromStatus; - -import static com.google.common.truth.Truth.assertThat; - -import androidx.test.filters.SmallTest; - -import com.android.server.stats.ProcfsMemoryUtil.MemorySnapshot; - -import org.junit.Test; - -import java.io.ByteArrayOutputStream; - -/** - * Build/Install/Run: - * atest FrameworksServicesTests:ProcfsMemoryUtilTest - */ -@SmallTest -public class ProcfsMemoryUtilTest { - private static final String STATUS_CONTENTS = "Name:\tandroid.youtube\n" - + "State:\tS (sleeping)\n" - + "Tgid:\t12088\n" - + "Pid:\t12088\n" - + "PPid:\t723\n" - + "TracerPid:\t0\n" - + "Uid:\t10083\t10083\t10083\t10083\n" - + "Gid:\t10083\t10083\t10083\t10083\n" - + "Ngid:\t0\n" - + "FDSize:\t128\n" - + "Groups:\t3003 9997 20083 50083 \n" - + "VmPeak:\t 4546844 kB\n" - + "VmSize:\t 4542636 kB\n" - + "VmLck:\t 0 kB\n" - + "VmPin:\t 0 kB\n" - + "VmHWM:\t 137668 kB\n" // RSS high-water mark - + "VmRSS:\t 126776 kB\n" // RSS - + "RssAnon:\t 37860 kB\n" - + "RssFile:\t 88764 kB\n" - + "RssShmem:\t 152 kB\n" - + "VmData:\t 4125112 kB\n" - + "VmStk:\t 8192 kB\n" - + "VmExe:\t 24 kB\n" - + "VmLib:\t 102432 kB\n" - + "VmPTE:\t 1300 kB\n" - + "VmPMD:\t 36 kB\n" - + "VmSwap:\t 22 kB\n" // Swap - + "Threads:\t95\n" - + "SigQ:\t0/13641\n" - + "SigPnd:\t0000000000000000\n" - + "ShdPnd:\t0000000000000000\n" - + "SigBlk:\t0000000000001204\n" - + "SigIgn:\t0000000000000001\n" - + "SigCgt:\t00000006400084f8\n" - + "CapInh:\t0000000000000000\n" - + "CapPrm:\t0000000000000000\n" - + "CapEff:\t0000000000000000\n" - + "CapBnd:\t0000000000000000\n" - + "CapAmb:\t0000000000000000\n" - + "Seccomp:\t2\n" - + "Cpus_allowed:\tff\n" - + "Cpus_allowed_list:\t0-7\n" - + "Mems_allowed:\t1\n" - + "Mems_allowed_list:\t0\n" - + "voluntary_ctxt_switches:\t903\n" - + "nonvoluntary_ctxt_switches:\t104\n"; - - @Test - public void testParseMemorySnapshotFromStatus_parsesCorrectValue() { - MemorySnapshot snapshot = parseMemorySnapshotFromStatus(STATUS_CONTENTS); - assertThat(snapshot.uid).isEqualTo(10083); - assertThat(snapshot.rssHighWaterMarkInKilobytes).isEqualTo(137668); - assertThat(snapshot.rssInKilobytes).isEqualTo(126776); - assertThat(snapshot.anonRssInKilobytes).isEqualTo(37860); - assertThat(snapshot.swapInKilobytes).isEqualTo(22); - } - - @Test - public void testParseMemorySnapshotFromStatus_invalidValue() { - MemorySnapshot snapshot = - parseMemorySnapshotFromStatus("test\nVmRSS:\tx0x0x\nVmSwap:\t1 kB\ntest"); - assertThat(snapshot).isNull(); - } - - @Test - public void testParseMemorySnapshotFromStatus_emptyContents() { - MemorySnapshot snapshot = parseMemorySnapshotFromStatus(""); - assertThat(snapshot).isNull(); - } - - @Test - public void testParseCmdline_invalidValue() { - byte[] nothing = new byte[] {0x00, 0x74, 0x65, 0x73, 0x74}; // \0test - - assertThat(parseCmdline(bytesToString(nothing))).isEmpty(); - } - - @Test - public void testParseCmdline_correctValue_noNullBytes() { - assertThat(parseCmdline("com.google.app")).isEqualTo("com.google.app"); - } - - @Test - public void testParseCmdline_correctValue_withNullBytes() { - byte[] trailing = new byte[] {0x74, 0x65, 0x73, 0x74, 0x00, 0x00, 0x00}; // test\0\0\0 - - assertThat(parseCmdline(bytesToString(trailing))).isEqualTo("test"); - - // test\0\0test - byte[] inside = new byte[] {0x74, 0x65, 0x73, 0x74, 0x00, 0x00, 0x74, 0x65, 0x73, 0x74}; - - assertThat(parseCmdline(bytesToString(trailing))).isEqualTo("test"); - } - - @Test - public void testParseCmdline_emptyContents() { - assertThat(parseCmdline("")).isEmpty(); - } - - private static String bytesToString(byte[] bytes) { - ByteArrayOutputStream output = new ByteArrayOutputStream(); - output.write(bytes, 0, bytes.length); - return output.toString(); - } -} diff --git a/services/tests/servicestests/src/com/android/server/usage/AppIdleHistoryTests.java b/services/tests/servicestests/src/com/android/server/usage/AppIdleHistoryTests.java index 36504ac7ec65..4a13dce5642b 100644 --- a/services/tests/servicestests/src/com/android/server/usage/AppIdleHistoryTests.java +++ b/services/tests/servicestests/src/com/android/server/usage/AppIdleHistoryTests.java @@ -28,7 +28,6 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; -import android.app.usage.UsageStatsManager; import android.os.FileUtils; import android.test.AndroidTestCase; @@ -150,4 +149,21 @@ public class AppIdleHistoryTests extends AndroidTestCase { aih = new AppIdleHistory(mStorageDir, 5000); assertEquals(REASON_MAIN_TIMEOUT, aih.getAppStandbyReason(PACKAGE_1, USER_ID, 5000)); } + + public void testNullPackage() throws Exception { + AppIdleHistory aih = new AppIdleHistory(mStorageDir, 1000); + // Report usage of a package + aih.reportUsage(PACKAGE_1, USER_ID, STANDBY_BUCKET_ACTIVE, + REASON_SUB_USAGE_MOVE_TO_FOREGROUND, 2000, 0); + // "Accidentally" report usage against a null named package + aih.reportUsage(null, USER_ID, STANDBY_BUCKET_ACTIVE, + REASON_SUB_USAGE_MOVE_TO_FOREGROUND, 2000, 0); + // Persist data + aih.writeAppIdleTimes(USER_ID); + // Recover data from disk + aih = new AppIdleHistory(mStorageDir, 5000); + // Verify data is intact + assertEquals(REASON_MAIN_USAGE | REASON_SUB_USAGE_MOVE_TO_FOREGROUND, + aih.getAppStandbyReason(PACKAGE_1, USER_ID, 3000)); + } }
\ No newline at end of file diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityDisplayTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityDisplayTests.java index 9df7b4576427..e560cb9a6cf7 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityDisplayTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityDisplayTests.java @@ -346,7 +346,7 @@ public class ActivityDisplayTests extends ActivityTestsBase { ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); activity.info.resizeMode = ActivityInfo.RESIZE_MODE_UNRESIZEABLE; activity.info.screenOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT; - activity.visible = true; + activity.mVisibleRequested = true; activity.ensureActivityConfiguration(0 /* globalChanges */, false /* preserveWindow */); final ArrayList<CompletableFuture<IBinder>> resultWrapper = new ArrayList<>(); diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java index 3c619f73aa6f..734761fd8048 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java @@ -160,7 +160,7 @@ public class ActivityMetricsLaunchObserverTests extends ActivityTestsBase { public void testOnActivityLaunchCancelled_hasDrawn() { onActivityLaunched(); - mTopActivity.visible = mTopActivity.mDrawn = true; + mTopActivity.mVisibleRequested = mTopActivity.mDrawn = true; // Cannot time already-visible activities. mActivityMetricsLogger.notifyActivityLaunched(START_TASK_TO_FRONT, mTopActivity); @@ -171,7 +171,7 @@ public class ActivityMetricsLaunchObserverTests extends ActivityTestsBase { @Test public void testOnActivityLaunchCancelled_finishedBeforeDrawn() { - mTopActivity.visible = mTopActivity.mDrawn = true; + mTopActivity.mVisibleRequested = mTopActivity.mDrawn = true; // Suppress resume when creating the record because we want to notify logger manually. mSupervisor.beginDeferResume(); diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java index c51a46a76f4c..e22c419f5919 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java @@ -221,7 +221,7 @@ public class ActivityRecordTests extends ActivityTestsBase { @Test public void testRestartProcessIfVisible() { doNothing().when(mSupervisor).scheduleRestartTimeout(mActivity); - mActivity.visible = true; + mActivity.mVisibleRequested = true; mActivity.setSavedState(null /* savedState */); mActivity.setState(ActivityStack.ActivityState.RESUMED, "testRestart"); prepareFixedAspectRatioUnresizableActivity(); @@ -502,7 +502,7 @@ public class ActivityRecordTests extends ActivityTestsBase { mTask.setBounds(100, 100, 400, 600); mActivity.info.screenOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT; mActivity.info.resizeMode = ActivityInfo.RESIZE_MODE_UNRESIZEABLE; - mActivity.visible = true; + mActivity.mVisibleRequested = true; ensureActivityConfiguration(); final Rect bounds = new Rect(mActivity.getBounds()); @@ -547,7 +547,7 @@ public class ActivityRecordTests extends ActivityTestsBase { .when(mActivity).getRequestedOrientation(); mActivity.info.resizeMode = RESIZE_MODE_UNRESIZEABLE; mActivity.info.minAspectRatio = mActivity.info.maxAspectRatio = 1; - mActivity.visible = true; + mActivity.mVisibleRequested = true; ensureActivityConfiguration(); // The parent configuration doesn't change since the first resolved configuration, so the // activity shouldn't be in the size compatibility mode. @@ -589,7 +589,7 @@ public class ActivityRecordTests extends ActivityTestsBase { .setResizeMode(RESIZE_MODE_UNRESIZEABLE) .setMaxAspectRatio(1.5f) .build(); - mActivity.visible = true; + mActivity.mVisibleRequested = true; final Rect originalBounds = new Rect(mActivity.getBounds()); final int originalDpi = mActivity.getConfiguration().densityDpi; @@ -614,7 +614,7 @@ public class ActivityRecordTests extends ActivityTestsBase { mTask.getRequestedOverrideConfiguration().orientation = Configuration.ORIENTATION_PORTRAIT; mActivity.info.screenOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT; mActivity.info.resizeMode = ActivityInfo.RESIZE_MODE_UNRESIZEABLE; - mActivity.visible = true; + mActivity.mVisibleRequested = true; ensureActivityConfiguration(); final Rect originalBounds = new Rect(mActivity.getBounds()); @@ -661,7 +661,7 @@ public class ActivityRecordTests extends ActivityTestsBase { prepareFixedAspectRatioUnresizableActivity(); mActivity.setState(STOPPED, "testSizeCompatMode"); - mActivity.visible = false; + mActivity.mVisibleRequested = false; mActivity.app.setReportedProcState(ActivityManager.PROCESS_STATE_CACHED_ACTIVITY); // Make the parent bounds to be different so the activity is in size compatibility mode. setupDisplayAndParentSize(600, 1200); @@ -829,7 +829,7 @@ public class ActivityRecordTests extends ActivityTestsBase { // Prepare the activity record to be ready for immediate removal. It should be invisible and // have no process. Otherwise, request to finish it will send a message to client first. mActivity.setState(STOPPED, "test"); - mActivity.visible = false; + mActivity.mVisibleRequested = false; mActivity.nowVisible = false; // Set process to 'null' to allow immediate removal, but don't call mActivity.setProcess() - // this will cause NPE when updating task's process. @@ -838,7 +838,7 @@ public class ActivityRecordTests extends ActivityTestsBase { // Put a visible activity on top, so the finishing activity doesn't have to wait until the // next activity reports idle to destroy it. final ActivityRecord topActivity = new ActivityBuilder(mService).setTask(mTask).build(); - topActivity.visible = true; + topActivity.mVisibleRequested = true; topActivity.nowVisible = true; topActivity.setState(RESUMED, "test"); @@ -924,7 +924,7 @@ public class ActivityRecordTests extends ActivityTestsBase { @Test public void testFinishActivityIfPossible_visibleResumedPreparesAppTransition() { mActivity.finishing = false; - mActivity.visible = true; + mActivity.mVisibleRequested = true; mActivity.setState(RESUMED, "test"); mActivity.finishIfPossible("test", false /* oomAdj */); @@ -940,7 +940,7 @@ public class ActivityRecordTests extends ActivityTestsBase { @Test public void testFinishActivityIfPossible_visibleNotResumedExecutesAppTransition() { mActivity.finishing = false; - mActivity.visible = true; + mActivity.mVisibleRequested = true; mActivity.setState(PAUSED, "test"); mActivity.finishIfPossible("test", false /* oomAdj */); @@ -958,7 +958,7 @@ public class ActivityRecordTests extends ActivityTestsBase { // Put an activity on top of test activity to make it invisible and prevent us from // accidentally resuming the topmost one again. new ActivityBuilder(mService).build(); - mActivity.visible = false; + mActivity.mVisibleRequested = false; mActivity.setState(STOPPED, "test"); mActivity.finishIfPossible("test", false /* oomAdj */); @@ -1010,7 +1010,7 @@ public class ActivityRecordTests extends ActivityTestsBase { @Test public void testCompleteFinishing_keepStateOfNextInvisible() { final ActivityRecord currentTop = mActivity; - currentTop.visible = currentTop.nowVisible = true; + currentTop.mVisibleRequested = currentTop.nowVisible = true; // Simulates that {@code currentTop} starts an existing activity from background (so its // state is stopped) and the starting flow just goes to place it at top. @@ -1036,13 +1036,13 @@ public class ActivityRecordTests extends ActivityTestsBase { @Test public void testCompleteFinishing_waitForNextVisible() { final ActivityRecord topActivity = new ActivityBuilder(mService).setTask(mTask).build(); - topActivity.visible = true; + topActivity.mVisibleRequested = true; topActivity.nowVisible = true; topActivity.finishing = true; topActivity.setState(PAUSED, "true"); // Mark the bottom activity as not visible, so that we will wait for it before removing // the top one. - mActivity.visible = false; + mActivity.mVisibleRequested = false; mActivity.nowVisible = false; mActivity.setState(STOPPED, "test"); @@ -1061,13 +1061,13 @@ public class ActivityRecordTests extends ActivityTestsBase { @Test public void testCompleteFinishing_noWaitForNextVisible_alreadyInvisible() { final ActivityRecord topActivity = new ActivityBuilder(mService).setTask(mTask).build(); - topActivity.visible = false; + topActivity.mVisibleRequested = false; topActivity.nowVisible = false; topActivity.finishing = true; topActivity.setState(PAUSED, "true"); // Mark the bottom activity as not visible, so that we would wait for it before removing // the top one. - mActivity.visible = false; + mActivity.mVisibleRequested = false; mActivity.nowVisible = false; mActivity.setState(STOPPED, "test"); @@ -1083,12 +1083,12 @@ public class ActivityRecordTests extends ActivityTestsBase { @Test public void testCompleteFinishing_waitForIdle() { final ActivityRecord topActivity = new ActivityBuilder(mService).setTask(mTask).build(); - topActivity.visible = true; + topActivity.mVisibleRequested = true; topActivity.nowVisible = true; topActivity.finishing = true; topActivity.setState(PAUSED, "true"); // Mark the bottom activity as already visible, so that there is no need to wait for it. - mActivity.visible = true; + mActivity.mVisibleRequested = true; mActivity.nowVisible = true; mActivity.setState(RESUMED, "test"); @@ -1104,12 +1104,12 @@ public class ActivityRecordTests extends ActivityTestsBase { @Test public void testCompleteFinishing_noWaitForNextVisible_stopped() { final ActivityRecord topActivity = new ActivityBuilder(mService).setTask(mTask).build(); - topActivity.visible = false; + topActivity.mVisibleRequested = false; topActivity.nowVisible = false; topActivity.finishing = true; topActivity.setState(STOPPED, "true"); // Mark the bottom activity as already visible, so that there is no need to wait for it. - mActivity.visible = true; + mActivity.mVisibleRequested = true; mActivity.nowVisible = true; mActivity.setState(RESUMED, "test"); @@ -1125,12 +1125,12 @@ public class ActivityRecordTests extends ActivityTestsBase { @Test public void testCompleteFinishing_noWaitForNextVisible_nonFocusedStack() { final ActivityRecord topActivity = new ActivityBuilder(mService).setTask(mTask).build(); - topActivity.visible = true; + topActivity.mVisibleRequested = true; topActivity.nowVisible = true; topActivity.finishing = true; topActivity.setState(PAUSED, "true"); // Mark the bottom activity as already visible, so that there is no need to wait for it. - mActivity.visible = true; + mActivity.mVisibleRequested = true; mActivity.nowVisible = true; mActivity.setState(RESUMED, "test"); @@ -1139,7 +1139,7 @@ public class ActivityRecordTests extends ActivityTestsBase { final ActivityStack stack = new StackBuilder(mRootActivityContainer).build(); final ActivityRecord focusedActivity = stack.getChildAt(0).getChildAt(0); focusedActivity.nowVisible = true; - focusedActivity.visible = true; + focusedActivity.mVisibleRequested = true; focusedActivity.setState(RESUMED, "test"); stack.mResumedActivity = focusedActivity; @@ -1346,7 +1346,7 @@ public class ActivityRecordTests extends ActivityTestsBase { setupDisplayContentForCompatDisplayInsets(); mActivity.info.resizeMode = RESIZE_MODE_UNRESIZEABLE; mActivity.info.maxAspectRatio = 1.5f; - mActivity.visible = true; + mActivity.mVisibleRequested = true; ensureActivityConfiguration(); } diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java index d0e07b619ad6..fc44652cc668 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java @@ -1006,7 +1006,7 @@ public class ActivityStackTests extends ActivityTestsBase { // There is still an activity1 in stack1 so the activity2 should be added to finishing list // that will be destroyed until idle. - stack2.getTopActivity().visible = true; + stack2.getTopActivity().mVisibleRequested = true; final ActivityRecord activity2 = finishTopActivity(stack2); assertEquals(STOPPING, activity2.getState()); assertThat(mSupervisor.mStoppingActivities).contains(activity2); diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java index 47b39b042fb5..163268191df1 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java @@ -271,7 +271,7 @@ class ActivityTestsBase extends SystemServiceTestsBase { doReturn(true).when(activity).occludesParent(); mTask.addChild(activity); // Make visible by default... - activity.setHidden(false); + activity.setVisible(true); } final WindowProcessController wpc = new WindowProcessController(mService, diff --git a/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java index 60204539d178..d415f25baab9 100644 --- a/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java @@ -62,7 +62,7 @@ public class AppTransitionControllerTest extends WindowTestsBase { final ActivityRecord translucentOpening = createActivityRecord(mDisplayContent, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD); translucentOpening.setOccludesParent(false); - translucentOpening.setHidden(true); + translucentOpening.setVisible(false); mDisplayContent.mOpeningApps.add(behind); mDisplayContent.mOpeningApps.add(translucentOpening); assertEquals(WindowManager.TRANSIT_TRANSLUCENT_ACTIVITY_OPEN, @@ -90,7 +90,7 @@ public class AppTransitionControllerTest extends WindowTestsBase { final ActivityRecord translucentOpening = createActivityRecord(mDisplayContent, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD); translucentOpening.setOccludesParent(false); - translucentOpening.setHidden(true); + translucentOpening.setVisible(false); mDisplayContent.mOpeningApps.add(behind); mDisplayContent.mOpeningApps.add(translucentOpening); assertEquals(TRANSIT_TASK_CHANGE_WINDOWING_MODE, diff --git a/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java b/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java index bd336ad2494f..d491569149a5 100644 --- a/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java @@ -252,7 +252,7 @@ public class AppWindowTokenTests extends WindowTestsBase { @Test @Presubmit public void testGetOrientation() { - mActivity.setHidden(false); + mActivity.setVisible(true); mActivity.setOrientation(SCREEN_ORIENTATION_LANDSCAPE); @@ -261,7 +261,7 @@ public class AppWindowTokenTests extends WindowTestsBase { assertEquals(SCREEN_ORIENTATION_LANDSCAPE, mActivity.getOrientation()); mActivity.setOccludesParent(true); - mActivity.setHidden(true); + mActivity.setVisible(false); mActivity.sendingToBottom = true; // Can not specify orientation if app isn't visible even though it occludes parent. assertEquals(SCREEN_ORIENTATION_UNSET, mActivity.getOrientation()); @@ -314,7 +314,7 @@ public class AppWindowTokenTests extends WindowTestsBase { @Test public void testSetOrientation() { - mActivity.setHidden(false); + mActivity.setVisible(true); // Assert orientation is unspecified to start. assertEquals(SCREEN_ORIENTATION_UNSPECIFIED, mActivity.getOrientation()); diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java index ab9a7caf8b93..8db48584295a 100644 --- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java @@ -26,6 +26,7 @@ import static android.view.Display.DEFAULT_DISPLAY; import static android.view.DisplayCutout.BOUNDS_POSITION_LEFT; import static android.view.DisplayCutout.BOUNDS_POSITION_TOP; import static android.view.DisplayCutout.fromBoundingRect; +import static android.view.Surface.ROTATION_90; import static android.view.View.SYSTEM_UI_FLAG_FULLSCREEN; import static android.view.View.SYSTEM_UI_FLAG_HIDE_NAVIGATION; import static android.view.View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY; @@ -62,6 +63,7 @@ import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertThat; import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.eq; import android.annotation.SuppressLint; @@ -70,11 +72,14 @@ import android.content.res.Configuration; import android.graphics.Rect; import android.graphics.Region; import android.metrics.LogMaker; +import android.os.RemoteException; import android.os.SystemClock; import android.platform.test.annotations.Presubmit; import android.util.DisplayMetrics; import android.view.DisplayCutout; import android.view.Gravity; +import android.view.IDisplayWindowRotationCallback; +import android.view.IDisplayWindowRotationController; import android.view.ISystemGestureExclusionListener; import android.view.MotionEvent; import android.view.Surface; @@ -389,7 +394,7 @@ public class DisplayContentTests extends WindowTestsBase { assertEquals(window1, mWm.mRoot.getTopFocusedDisplayContent().mCurrentFocus); // Make sure top focused display not changed if there is a focused app. - window1.mActivityRecord.hiddenRequested = true; + window1.mActivityRecord.mVisibleRequested = false; window1.getDisplayContent().setFocusedApp(window1.mActivityRecord); updateFocusedWindow(); assertTrue(!window1.isFocused()); @@ -656,7 +661,7 @@ public class DisplayContentTests extends WindowTestsBase { portraitDisplay.getDisplayRotation().setRotation(Surface.ROTATION_0); assertFalse(isOptionsPanelAtRight(portraitDisplay.getDisplayId())); - portraitDisplay.getDisplayRotation().setRotation(Surface.ROTATION_90); + portraitDisplay.getDisplayRotation().setRotation(ROTATION_90); assertTrue(isOptionsPanelAtRight(portraitDisplay.getDisplayId())); final DisplayContent landscapeDisplay = createNewDisplay(); @@ -665,7 +670,7 @@ public class DisplayContentTests extends WindowTestsBase { landscapeDisplay.getDisplayRotation().setRotation(Surface.ROTATION_0); assertTrue(isOptionsPanelAtRight(landscapeDisplay.getDisplayId())); - landscapeDisplay.getDisplayRotation().setRotation(Surface.ROTATION_90); + landscapeDisplay.getDisplayRotation().setRotation(ROTATION_90); assertFalse(isOptionsPanelAtRight(landscapeDisplay.getDisplayId())); } @@ -917,6 +922,45 @@ public class DisplayContentTests extends WindowTestsBase { is(Configuration.ORIENTATION_PORTRAIT)); } + @Test + public void testRemoteRotation() { + DisplayContent dc = createNewDisplay(); + + final DisplayRotation dr = dc.getDisplayRotation(); + Mockito.doCallRealMethod().when(dr).updateRotationUnchecked(anyBoolean()); + Mockito.doReturn(ROTATION_90).when(dr).rotationForOrientation(anyInt(), anyInt()); + final boolean[] continued = new boolean[1]; + spyOn(dc.mActivityDisplay); + Mockito.doAnswer( + invocation -> { + continued[0] = true; + return true; + }).when(dc.mActivityDisplay).updateDisplayOverrideConfigurationLocked(); + final boolean[] called = new boolean[1]; + mWm.mDisplayRotationController = + new IDisplayWindowRotationController.Stub() { + @Override + public void onRotateDisplay(int displayId, int fromRotation, int toRotation, + IDisplayWindowRotationCallback callback) { + called[0] = true; + + try { + callback.continueRotateDisplay(toRotation, null); + } catch (RemoteException e) { + assertTrue(false); + } + } + }; + + // kill any existing rotation animation (vestigial from test setup). + dc.setRotationAnimation(null); + + mWm.updateRotation(true /* alwaysSendConfiguration */, false /* forceRelayout */); + assertTrue(called[0]); + waitUntilHandlersIdle(); + assertTrue(continued[0]); + } + private boolean isOptionsPanelAtRight(int displayId) { return (mWm.getPreferredOptionsPanelGravity(displayId) & Gravity.RIGHT) == Gravity.RIGHT; } diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java index 702600402d8e..1abd3662165e 100644 --- a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java @@ -149,7 +149,7 @@ public class RecentsAnimationControllerTest extends WindowTestsBase { WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD); final ActivityRecord hiddenActivity = createActivityRecord(mDisplayContent, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD); - hiddenActivity.setHidden(true); + hiddenActivity.setVisible(false); mDisplayContent.getConfiguration().windowConfiguration.setRotation( mDisplayContent.getRotation()); mController.initialize(ACTIVITY_TYPE_HOME, new SparseBooleanArray(), homeActivity); diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationTest.java index 41cbd8137f5e..06d96fee3757 100644 --- a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationTest.java @@ -106,12 +106,12 @@ public class RecentsAnimationTest extends ActivityTestsBase { RecentsAnimationCallbacks recentsAnimation = startRecentsActivity( mRecentsComponent, true /* getRecentsAnimation */); // The launch-behind state should make the recents activity visible. - assertTrue(recentActivity.visible); + assertTrue(recentActivity.mVisibleRequested); // Simulate the animation is cancelled without changing the stack order. recentsAnimation.onAnimationFinished(REORDER_KEEP_IN_PLACE, false /* sendUserLeaveHint */); // The non-top recents activity should be invisible by the restored launch-behind state. - assertFalse(recentActivity.visible); + assertFalse(recentActivity.mVisibleRequested); } @Test @@ -158,7 +158,7 @@ public class RecentsAnimationTest extends ActivityTestsBase { // The activity is started in background so it should be invisible and will be stopped. assertThat(recentsActivity).isNotNull(); assertThat(mSupervisor.mStoppingActivities).contains(recentsActivity); - assertFalse(recentsActivity.visible); + assertFalse(recentsActivity.mVisibleRequested); // Assume it is stopped to test next use case. recentsActivity.activityStoppedLocked(null /* newIcicle */, null /* newPersistentState */, @@ -361,7 +361,7 @@ public class RecentsAnimationTest extends ActivityTestsBase { true); // Ensure we find the task for the right user and it is made visible - assertTrue(otherUserHomeActivity.visible); + assertTrue(otherUserHomeActivity.mVisibleRequested); } private void startRecentsActivity() { diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java index e1f92dddf053..0b7cbceb8f95 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java @@ -383,11 +383,11 @@ public class WindowStateTests extends WindowTestsBase { @Test public void testCanAffectSystemUiFlags() { final WindowState app = createWindow(null, TYPE_APPLICATION, "app"); - app.mToken.setHidden(false); + app.mActivityRecord.setVisible(true); assertTrue(app.canAffectSystemUiFlags()); - app.mToken.setHidden(true); + app.mActivityRecord.setVisible(false); assertFalse(app.canAffectSystemUiFlags()); - app.mToken.setHidden(false); + app.mActivityRecord.setVisible(true); app.mAttrs.alpha = 0.0f; assertFalse(app.canAffectSystemUiFlags()); } @@ -395,7 +395,7 @@ public class WindowStateTests extends WindowTestsBase { @Test public void testCanAffectSystemUiFlags_disallow() { final WindowState app = createWindow(null, TYPE_APPLICATION, "app"); - app.mToken.setHidden(false); + app.mActivityRecord.setVisible(true); assertTrue(app.canAffectSystemUiFlags()); app.getTask().setCanAffectSystemUiFlags(false); assertFalse(app.canAffectSystemUiFlags()); @@ -569,7 +569,7 @@ public class WindowStateTests extends WindowTestsBase { @Test public void testCantReceiveTouchWhenAppTokenHiddenRequested() { final WindowState win0 = createWindow(null, TYPE_APPLICATION, "win0"); - win0.mActivityRecord.hiddenRequested = true; + win0.mActivityRecord.mVisibleRequested = false; assertTrue(win0.cantReceiveTouchInput()); } diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTestUtils.java b/services/tests/wmtests/src/com/android/server/wm/WindowTestUtils.java index 797a6bc7e087..26743c842122 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowTestUtils.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestUtils.java @@ -74,8 +74,8 @@ class WindowTestUtils { private static void postCreateActivitySetup(ActivityRecord activity, DisplayContent dc) { activity.onDisplayChanged(dc); activity.setOccludesParent(true); - activity.setHidden(false); - activity.hiddenRequested = false; + activity.setVisible(true); + activity.mVisibleRequested = true; } static TestWindowToken createTestWindowToken(int type, DisplayContent dc) { diff --git a/telecomm/java/android/telecom/Call.java b/telecomm/java/android/telecom/Call.java index 24b40460066b..3ecf8d73d0a6 100644 --- a/telecomm/java/android/telecom/Call.java +++ b/telecomm/java/android/telecom/Call.java @@ -25,8 +25,11 @@ import android.net.Uri; import android.os.Build; import android.os.Bundle; import android.os.Handler; +import android.os.IBinder; import android.os.ParcelFileDescriptor; +import com.android.internal.telecom.IVideoProvider; + import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStreamWriter; @@ -2132,13 +2135,22 @@ public final class Call { cannedTextResponsesChanged = true; } - VideoCallImpl newVideoCallImpl = parcelableCall.getVideoCallImpl(mCallingPackage, - mTargetSdkVersion); - boolean videoCallChanged = parcelableCall.isVideoCallProviderChanged() && - !Objects.equals(mVideoCallImpl, newVideoCallImpl); + IVideoProvider previousVideoProvider = mVideoCallImpl == null ? null : + mVideoCallImpl.getVideoProvider(); + IVideoProvider newVideoProvider = parcelableCall.getVideoProvider(); + + // parcelableCall.isVideoCallProviderChanged is only true when we have a video provider + // specified; so we should check if the actual IVideoProvider changes as well. + boolean videoCallChanged = parcelableCall.isVideoCallProviderChanged() + && !Objects.equals(previousVideoProvider, newVideoProvider); if (videoCallChanged) { - mVideoCallImpl = newVideoCallImpl; + if (mVideoCallImpl != null) { + mVideoCallImpl.destroy(); + } + mVideoCallImpl = parcelableCall.isVideoCallProviderChanged() ? + parcelableCall.getVideoCallImpl(mCallingPackage, mTargetSdkVersion) : null; } + if (mVideoCallImpl != null) { mVideoCallImpl.setVideoState(getDetails().getVideoState()); } diff --git a/telecomm/java/android/telecom/CallScreeningService.java b/telecomm/java/android/telecom/CallScreeningService.java index ef1c790dcc83..b91787ccff83 100644 --- a/telecomm/java/android/telecom/CallScreeningService.java +++ b/telecomm/java/android/telecom/CallScreeningService.java @@ -106,8 +106,14 @@ public abstract class CallScreeningService extends Service { SomeArgs args = (SomeArgs) msg.obj; try { mCallScreeningAdapter = (ICallScreeningAdapter) args.arg1; - onScreenCall( - Call.Details.createFromParcelableCall((ParcelableCall) args.arg2)); + Call.Details callDetails = Call.Details + .createFromParcelableCall((ParcelableCall) args.arg2); + onScreenCall(callDetails); + if (callDetails.getCallDirection() == Call.Details.DIRECTION_OUTGOING) { + mCallScreeningAdapter.allowCall(callDetails.getTelecomCallId()); + } + } catch (RemoteException e) { + Log.w(this, "Exception when screening call: " + e); } finally { args.recycle(); } diff --git a/telecomm/java/android/telecom/ParcelableCall.java b/telecomm/java/android/telecom/ParcelableCall.java index aa50991b118c..fdc324308d7a 100644 --- a/telecomm/java/android/telecom/ParcelableCall.java +++ b/telecomm/java/android/telecom/ParcelableCall.java @@ -21,6 +21,7 @@ import android.annotation.UnsupportedAppUsage; import android.net.Uri; import android.os.Build; import android.os.Bundle; +import android.os.IBinder; import android.os.Parcel; import android.os.Parcelable; import android.os.RemoteException; @@ -225,6 +226,10 @@ public final class ParcelableCall implements Parcelable { return mVideoCall; } + public IVideoProvider getVideoProvider() { + return mVideoCallProvider; + } + public boolean getIsRttCallChanged() { return mIsRttCallChanged; } diff --git a/telecomm/java/android/telecom/VideoCallImpl.java b/telecomm/java/android/telecom/VideoCallImpl.java index cb74012e2b81..4a1aa0a8ffa4 100644 --- a/telecomm/java/android/telecom/VideoCallImpl.java +++ b/telecomm/java/android/telecom/VideoCallImpl.java @@ -32,6 +32,8 @@ import com.android.internal.os.SomeArgs; import com.android.internal.telecom.IVideoCallback; import com.android.internal.telecom.IVideoProvider; +import java.util.NoSuchElementException; + /** * Implementation of a Video Call, which allows InCallUi to communicate commands to the underlying * {@link Connection.VideoProvider}, and direct callbacks from the @@ -53,7 +55,11 @@ public class VideoCallImpl extends VideoCall { private IBinder.DeathRecipient mDeathRecipient = new IBinder.DeathRecipient() { @Override public void binderDied() { - mVideoProvider.asBinder().unlinkToDeath(this, 0); + try { + mVideoProvider.asBinder().unlinkToDeath(this, 0); + } catch (NoSuchElementException nse) { + // Already unlinked in destroy below. + } } }; @@ -222,6 +228,11 @@ public class VideoCallImpl extends VideoCall { @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 127403196) public void destroy() { unregisterCallback(mCallback); + try { + mVideoProvider.asBinder().unlinkToDeath(mDeathRecipient, 0); + } catch (NoSuchElementException nse) { + // Already unlinked in binderDied above. + } } /** {@inheritDoc} */ @@ -353,4 +364,12 @@ public class VideoCallImpl extends VideoCall { public void setVideoState(int videoState) { mVideoState = videoState; } + + /** + * Get the video provider binder. + * @return the video provider binder. + */ + public IVideoProvider getVideoProvider() { + return mVideoProvider; + } } diff --git a/tests/net/integration/AndroidManifest.xml b/tests/net/integration/AndroidManifest.xml index 91b3cd9e791f..4dd3b5a23d7a 100644 --- a/tests/net/integration/AndroidManifest.xml +++ b/tests/net/integration/AndroidManifest.xml @@ -17,7 +17,6 @@ */ --> <manifest xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:tools="http://schemas.android.com/tools" package="com.android.server.net.integrationtests"> <!-- For ConnectivityService registerReceiverAsUser (receiving broadcasts) --> @@ -26,13 +25,19 @@ <uses-permission android:name="android.permission.MANAGE_USERS" /> <!-- ConnectivityService sends notifications to BatteryStats --> <uses-permission android:name="android.permission.UPDATE_DEVICE_STATS" /> + <!-- Reading network status --> + <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" /> + <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> + <uses-permission android:name="android.permission.CONNECTIVITY_INTERNAL" /> + <uses-permission android:name="android.permission.READ_PRIVILEGED_PHONE_STATE" /> + <!-- Reading DeviceConfig flags --> + <uses-permission android:name="android.permission.READ_DEVICE_CONFIG" /> <application android:debuggable="true"> <uses-library android:name="android.test.runner" /> <!-- This manifest is merged with the base manifest of the real NetworkStack app. Remove the NetworkStackService from the base (real) manifest, and replace with a test service that responds to the same intent --> - <service android:name="com.android.server.NetworkStackService" tools:node="remove"/> <service android:name=".TestNetworkStackService" android:process="com.android.server.net.integrationtests.testnetworkstack"> <intent-filter> @@ -45,9 +50,9 @@ <action android:name=".INetworkStackInstrumentation"/> </intent-filter> </service> - <service tools:replace="android:process" - android:name="com.android.server.connectivity.ipmemorystore.RegularMaintenanceJobService" - android:process="com.android.server.net.integrationtests.testnetworkstack"/> + <service android:name="com.android.server.connectivity.ipmemorystore.RegularMaintenanceJobService" + android:process="com.android.server.net.integrationtests.testnetworkstack" + android:permission="android.permission.BIND_JOB_SERVICE"/> </application> diff --git a/tools/aapt2/java/ProguardRules.cpp b/tools/aapt2/java/ProguardRules.cpp index 05ba8f05ec67..806f4e37e22a 100644 --- a/tools/aapt2/java/ProguardRules.cpp +++ b/tools/aapt2/java/ProguardRules.cpp @@ -404,12 +404,15 @@ void WriteKeepSet(const KeepSet& keep_set, OutputStream* out, bool minimal_keep) for (const auto& entry : keep_set.conditional_class_set_) { std::set<UsageLocation> locations; - bool can_be_conditional = true; - for (const UsageLocation& location : entry.second) { - can_be_conditional &= CollectLocations(location, keep_set, &locations); + bool can_be_conditional = false; + if (keep_set.conditional_keep_rules_) { + can_be_conditional = true; + for (const UsageLocation& location : entry.second) { + can_be_conditional &= CollectLocations(location, keep_set, &locations); + } } - if (keep_set.conditional_keep_rules_ && can_be_conditional) { + if (can_be_conditional) { for (const UsageLocation& location : locations) { printer.Print("# Referenced at ").Println(location.source.to_string()); printer.Print("-if class **.R$layout { int ") diff --git a/wifi/java/android/net/wifi/aware/WifiAwareNetworkInfo.java b/wifi/java/android/net/wifi/aware/WifiAwareNetworkInfo.java index fd26817bfd79..60fe60438ce7 100644 --- a/wifi/java/android/net/wifi/aware/WifiAwareNetworkInfo.java +++ b/wifi/java/android/net/wifi/aware/WifiAwareNetworkInfo.java @@ -120,10 +120,12 @@ public final class WifiAwareNetworkInfo implements TransportInfo, Parcelable { new Creator<WifiAwareNetworkInfo>() { @Override public WifiAwareNetworkInfo createFromParcel(Parcel in) { + byte[] addr = in.createByteArray(); + String interfaceName = in.readString(); + int port = in.readInt(); + int transportProtocol = in.readInt(); Inet6Address ipv6Addr; try { - byte[] addr = in.createByteArray(); - String interfaceName = in.readString(); NetworkInterface ni = null; if (interfaceName != null) { try { @@ -135,11 +137,8 @@ public final class WifiAwareNetworkInfo implements TransportInfo, Parcelable { ipv6Addr = Inet6Address.getByAddress(null, addr, ni); } catch (UnknownHostException e) { e.printStackTrace(); - return null; + return new WifiAwareNetworkInfo(null); } - int port = in.readInt(); - int transportProtocol = in.readInt(); - return new WifiAwareNetworkInfo(ipv6Addr, port, transportProtocol); } |