Merge "AID: Change loop to repeat and set from xml"
diff --git a/api/current.txt b/api/current.txt
index ab6f13b..7bdff3f 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -7445,6 +7445,7 @@
method public java.util.Map<java.lang.String, android.app.usage.UsageStats> queryAndAggregateUsageStats(long, long);
method public java.util.List<android.app.usage.ConfigurationStats> queryConfigurations(int, long, long);
method public android.app.usage.UsageEvents queryEvents(long, long);
+ method public android.app.usage.UsageEvents queryEventsForSelf(long, long);
method public java.util.List<android.app.usage.UsageStats> queryUsageStats(int, long, long);
field public static final int INTERVAL_BEST = 4; // 0x4
field public static final int INTERVAL_DAILY = 0; // 0x0
@@ -22865,12 +22866,12 @@
public static class MediaBrowser2.BrowserCallback extends android.media.MediaController2.ControllerCallback {
ctor public MediaBrowser2.BrowserCallback();
- method public void onChildrenChanged(java.lang.String, int, android.os.Bundle);
- method public void onGetChildrenDone(java.lang.String, int, int, java.util.List<android.media.MediaItem2>, android.os.Bundle);
- method public void onGetItemDone(java.lang.String, android.media.MediaItem2);
- method public void onGetLibraryRootDone(android.os.Bundle, java.lang.String, android.os.Bundle);
- method public void onGetSearchResultDone(java.lang.String, int, int, java.util.List<android.media.MediaItem2>, android.os.Bundle);
- method public void onSearchResultChanged(java.lang.String, int, android.os.Bundle);
+ method public void onChildrenChanged(android.media.MediaBrowser2, java.lang.String, int, android.os.Bundle);
+ method public void onGetChildrenDone(android.media.MediaBrowser2, java.lang.String, int, int, java.util.List<android.media.MediaItem2>, android.os.Bundle);
+ method public void onGetItemDone(android.media.MediaBrowser2, java.lang.String, android.media.MediaItem2);
+ method public void onGetLibraryRootDone(android.media.MediaBrowser2, android.os.Bundle, java.lang.String, android.os.Bundle);
+ method public void onGetSearchResultDone(android.media.MediaBrowser2, java.lang.String, int, int, java.util.List<android.media.MediaItem2>, android.os.Bundle);
+ method public void onSearchResultChanged(android.media.MediaBrowser2, java.lang.String, int, android.os.Bundle);
}
public final class MediaCas implements java.lang.AutoCloseable {
@@ -23392,20 +23393,20 @@
public static abstract class MediaController2.ControllerCallback {
ctor public MediaController2.ControllerCallback();
- method public void onAllowedCommandsChanged(android.media.MediaSession2.CommandGroup);
- method public void onBufferedPositionChanged(long);
- method public void onConnected(android.media.MediaSession2.CommandGroup);
- method public void onCurrentPlaylistItemChanged(android.media.MediaItem2);
- method public void onCustomCommand(android.media.MediaSession2.Command, android.os.Bundle, android.os.ResultReceiver);
- method public void onCustomLayoutChanged(java.util.List<android.media.MediaSession2.CommandButton>);
- method public void onDisconnected();
- method public void onError(int, android.os.Bundle);
- method public void onPlaybackInfoChanged(android.media.MediaController2.PlaybackInfo);
- method public void onPlaybackSpeedChanged(float);
- method public void onPlayerStateChanged(int);
- method public void onPlaylistChanged(java.util.List<android.media.MediaItem2>);
- method public void onPlaylistParamsChanged(android.media.MediaSession2.PlaylistParams);
- method public void onPositionChanged(long, long);
+ method public void onAllowedCommandsChanged(android.media.MediaController2, android.media.MediaSession2.CommandGroup);
+ method public void onBufferedPositionChanged(android.media.MediaController2, long);
+ method public void onConnected(android.media.MediaController2, android.media.MediaSession2.CommandGroup);
+ method public void onCurrentPlaylistItemChanged(android.media.MediaController2, android.media.MediaItem2);
+ method public void onCustomCommand(android.media.MediaController2, android.media.MediaSession2.Command, android.os.Bundle, android.os.ResultReceiver);
+ method public void onCustomLayoutChanged(android.media.MediaController2, java.util.List<android.media.MediaSession2.CommandButton>);
+ method public void onDisconnected(android.media.MediaController2);
+ method public void onError(android.media.MediaController2, int, android.os.Bundle);
+ method public void onPlaybackInfoChanged(android.media.MediaController2, android.media.MediaController2.PlaybackInfo);
+ method public void onPlaybackSpeedChanged(android.media.MediaController2, float);
+ method public void onPlayerStateChanged(android.media.MediaController2, int);
+ method public void onPlaylistChanged(android.media.MediaController2, java.util.List<android.media.MediaItem2>);
+ method public void onPlaylistParamsChanged(android.media.MediaController2, android.media.MediaSession2.PlaylistParams);
+ method public void onPositionChanged(android.media.MediaController2, long, long);
}
public static final class MediaController2.PlaybackInfo {
@@ -23874,13 +23875,13 @@
public static class MediaLibraryService2.MediaLibrarySession.MediaLibrarySessionCallback extends android.media.MediaSession2.SessionCallback {
ctor public MediaLibraryService2.MediaLibrarySession.MediaLibrarySessionCallback(android.content.Context);
- method public java.util.List<android.media.MediaItem2> onGetChildren(android.media.MediaSession2.ControllerInfo, java.lang.String, int, int, android.os.Bundle);
- method public android.media.MediaItem2 onGetItem(android.media.MediaSession2.ControllerInfo, java.lang.String);
- method public android.media.MediaLibraryService2.LibraryRoot onGetLibraryRoot(android.media.MediaSession2.ControllerInfo, android.os.Bundle);
- method public java.util.List<android.media.MediaItem2> onGetSearchResult(android.media.MediaSession2.ControllerInfo, java.lang.String, int, int, android.os.Bundle);
- method public void onSearch(android.media.MediaSession2.ControllerInfo, java.lang.String, android.os.Bundle);
- method public void onSubscribe(android.media.MediaSession2.ControllerInfo, java.lang.String, android.os.Bundle);
- method public void onUnsubscribe(android.media.MediaSession2.ControllerInfo, java.lang.String);
+ method public java.util.List<android.media.MediaItem2> onGetChildren(android.media.MediaLibraryService2.MediaLibrarySession, android.media.MediaSession2.ControllerInfo, java.lang.String, int, int, android.os.Bundle);
+ method public android.media.MediaItem2 onGetItem(android.media.MediaLibraryService2.MediaLibrarySession, android.media.MediaSession2.ControllerInfo, java.lang.String);
+ method public android.media.MediaLibraryService2.LibraryRoot onGetLibraryRoot(android.media.MediaLibraryService2.MediaLibrarySession, android.media.MediaSession2.ControllerInfo, android.os.Bundle);
+ method public java.util.List<android.media.MediaItem2> onGetSearchResult(android.media.MediaLibraryService2.MediaLibrarySession, android.media.MediaSession2.ControllerInfo, java.lang.String, int, int, android.os.Bundle);
+ method public void onSearch(android.media.MediaLibraryService2.MediaLibrarySession, android.media.MediaSession2.ControllerInfo, java.lang.String, android.os.Bundle);
+ method public void onSubscribe(android.media.MediaLibraryService2.MediaLibrarySession, android.media.MediaSession2.ControllerInfo, java.lang.String, android.os.Bundle);
+ method public void onUnsubscribe(android.media.MediaLibraryService2.MediaLibrarySession, android.media.MediaSession2.ControllerInfo, java.lang.String);
}
public final class MediaMetadata implements android.os.Parcelable {
@@ -24346,7 +24347,6 @@
method public abstract void prepareDrm(java.util.UUID) throws android.media.MediaPlayer2.ProvisioningNetworkErrorException, android.media.MediaPlayer2.ProvisioningServerErrorException, android.media.ResourceBusyException, android.media.UnsupportedSchemeException;
method public abstract byte[] provideDrmKeyResponse(byte[], byte[]) throws android.media.DeniedByServerException, android.media.MediaPlayer2.NoDrmSchemeException;
method public abstract void releaseDrm() throws android.media.MediaPlayer2.NoDrmSchemeException;
- method public abstract void reset();
method public abstract void restoreDrmKeys(byte[]) throws android.media.MediaPlayer2.NoDrmSchemeException;
method public void seekTo(long);
method public abstract void seekTo(long, int);
@@ -24511,6 +24511,7 @@
method public abstract void play();
method public abstract void prepare();
method public abstract void registerPlayerEventCallback(java.util.concurrent.Executor, android.media.MediaPlayerBase.PlayerEventCallback);
+ method public abstract void reset();
method public abstract void seekTo(long);
method public abstract void setAudioAttributes(android.media.AudioAttributes);
method public abstract void setDataSource(android.media.DataSourceDesc);
@@ -24968,17 +24969,17 @@
public static abstract class MediaSession2.SessionCallback {
ctor public MediaSession2.SessionCallback(android.content.Context);
- method public boolean onCommandRequest(android.media.MediaSession2.ControllerInfo, android.media.MediaSession2.Command);
- method public android.media.MediaSession2.CommandGroup onConnect(android.media.MediaSession2.ControllerInfo);
- method public void onCustomCommand(android.media.MediaSession2.ControllerInfo, android.media.MediaSession2.Command, android.os.Bundle, android.os.ResultReceiver);
- method public void onDisconnected(android.media.MediaSession2.ControllerInfo);
- method public void onPlayFromMediaId(android.media.MediaSession2.ControllerInfo, java.lang.String, android.os.Bundle);
- method public void onPlayFromSearch(android.media.MediaSession2.ControllerInfo, java.lang.String, android.os.Bundle);
- method public void onPlayFromUri(android.media.MediaSession2.ControllerInfo, android.net.Uri, android.os.Bundle);
- method public void onPrepareFromMediaId(android.media.MediaSession2.ControllerInfo, java.lang.String, android.os.Bundle);
- method public void onPrepareFromSearch(android.media.MediaSession2.ControllerInfo, java.lang.String, android.os.Bundle);
- method public void onPrepareFromUri(android.media.MediaSession2.ControllerInfo, android.net.Uri, android.os.Bundle);
- method public void onSetRating(android.media.MediaSession2.ControllerInfo, java.lang.String, android.media.Rating2);
+ method public boolean onCommandRequest(android.media.MediaSession2, android.media.MediaSession2.ControllerInfo, android.media.MediaSession2.Command);
+ method public android.media.MediaSession2.CommandGroup onConnect(android.media.MediaSession2, android.media.MediaSession2.ControllerInfo);
+ method public void onCustomCommand(android.media.MediaSession2, android.media.MediaSession2.ControllerInfo, android.media.MediaSession2.Command, android.os.Bundle, android.os.ResultReceiver);
+ method public void onDisconnected(android.media.MediaSession2, android.media.MediaSession2.ControllerInfo);
+ method public void onPlayFromMediaId(android.media.MediaSession2, android.media.MediaSession2.ControllerInfo, java.lang.String, android.os.Bundle);
+ method public void onPlayFromSearch(android.media.MediaSession2, android.media.MediaSession2.ControllerInfo, java.lang.String, android.os.Bundle);
+ method public void onPlayFromUri(android.media.MediaSession2, android.media.MediaSession2.ControllerInfo, android.net.Uri, android.os.Bundle);
+ method public void onPrepareFromMediaId(android.media.MediaSession2, android.media.MediaSession2.ControllerInfo, java.lang.String, android.os.Bundle);
+ method public void onPrepareFromSearch(android.media.MediaSession2, android.media.MediaSession2.ControllerInfo, java.lang.String, android.os.Bundle);
+ method public void onPrepareFromUri(android.media.MediaSession2, android.media.MediaSession2.ControllerInfo, android.net.Uri, android.os.Bundle);
+ method public void onSetRating(android.media.MediaSession2, android.media.MediaSession2.ControllerInfo, java.lang.String, android.media.Rating2);
}
public abstract class MediaSessionService2 extends android.app.Service {
@@ -42233,6 +42234,8 @@
field public static final java.lang.String KEY_CARRIER_INSTANT_LETTERING_ESCAPED_CHARS_STRING = "carrier_instant_lettering_escaped_chars_string";
field public static final java.lang.String KEY_CARRIER_INSTANT_LETTERING_INVALID_CHARS_STRING = "carrier_instant_lettering_invalid_chars_string";
field public static final java.lang.String KEY_CARRIER_INSTANT_LETTERING_LENGTH_LIMIT_INT = "carrier_instant_lettering_length_limit_int";
+ field public static final java.lang.String KEY_CARRIER_NAME_OVERRIDE_BOOL = "carrier_name_override_bool";
+ field public static final java.lang.String KEY_CARRIER_NAME_STRING = "carrier_name_string";
field public static final java.lang.String KEY_CARRIER_SETTINGS_ENABLE_BOOL = "carrier_settings_enable_bool";
field public static final java.lang.String KEY_CARRIER_USE_IMS_FIRST_FOR_EMERGENCY_BOOL = "carrier_use_ims_first_for_emergency_bool";
field public static final java.lang.String KEY_CARRIER_VOLTE_AVAILABLE_BOOL = "carrier_volte_available_bool";
@@ -42381,9 +42384,9 @@
method public int getCid();
method public int getLac();
method public deprecated int getMcc();
- method public java.lang.String getMccStr();
+ method public java.lang.String getMccString();
method public deprecated int getMnc();
- method public java.lang.String getMncStr();
+ method public java.lang.String getMncString();
method public java.lang.String getMobileNetworkOperator();
method public java.lang.CharSequence getOperatorAlphaLong();
method public java.lang.CharSequence getOperatorAlphaShort();
@@ -42397,9 +42400,9 @@
method public int getCi();
method public int getEarfcn();
method public deprecated int getMcc();
- method public java.lang.String getMccStr();
+ method public java.lang.String getMccString();
method public deprecated int getMnc();
- method public java.lang.String getMncStr();
+ method public java.lang.String getMncString();
method public java.lang.String getMobileNetworkOperator();
method public java.lang.CharSequence getOperatorAlphaLong();
method public java.lang.CharSequence getOperatorAlphaShort();
@@ -42413,8 +42416,8 @@
method public int getCid();
method public int getCpid();
method public int getLac();
- method public java.lang.String getMccStr();
- method public java.lang.String getMncStr();
+ method public java.lang.String getMccString();
+ method public java.lang.String getMncString();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.telephony.CellIdentityTdscdma> CREATOR;
}
@@ -42423,9 +42426,9 @@
method public int getCid();
method public int getLac();
method public deprecated int getMcc();
- method public java.lang.String getMccStr();
+ method public java.lang.String getMccString();
method public deprecated int getMnc();
- method public java.lang.String getMncStr();
+ method public java.lang.String getMncString();
method public java.lang.String getMobileNetworkOperator();
method public java.lang.CharSequence getOperatorAlphaLong();
method public java.lang.CharSequence getOperatorAlphaShort();
@@ -50778,7 +50781,6 @@
method public abstract boolean performEditorAction(int);
method public abstract boolean performPrivateCommand(java.lang.String, android.os.Bundle);
method public abstract boolean reportFullscreenMode(boolean);
- method public default void reportLanguageHint(android.os.LocaleList);
method public abstract boolean requestCursorUpdates(int);
method public abstract boolean sendKeyEvent(android.view.KeyEvent);
method public abstract boolean setComposingRegion(int, int);
diff --git a/cmds/statsd/src/StatsLogProcessor.cpp b/cmds/statsd/src/StatsLogProcessor.cpp
index 9b58a14..e98b54d 100644
--- a/cmds/statsd/src/StatsLogProcessor.cpp
+++ b/cmds/statsd/src/StatsLogProcessor.cpp
@@ -330,9 +330,7 @@
mLastByteSizeTimes[key] = timestampNs;
if (totalBytes >
StatsdStats::kMaxMetricsBytesPerConfig) { // Too late. We need to start clearing data.
- // TODO(b/70571383): By 12/15/2017 add API to drop data directly
- ProtoOutputStream proto;
- metricsManager.onDumpReport(timestampNs, &proto);
+ metricsManager.dropData(timestampNs);
StatsdStats::getInstance().noteDataDropped(key);
VLOG("StatsD had to toss out metrics for %s", key.ToString().c_str());
} else if (totalBytes > .9 * StatsdStats::kMaxMetricsBytesPerConfig) {
diff --git a/cmds/statsd/src/StatsLogProcessor.h b/cmds/statsd/src/StatsLogProcessor.h
index 7a6aa1e..a672ab4 100644
--- a/cmds/statsd/src/StatsLogProcessor.h
+++ b/cmds/statsd/src/StatsLogProcessor.h
@@ -113,7 +113,6 @@
FRIEND_TEST(StatsLogProcessorTest, TestRateLimitByteSize);
FRIEND_TEST(StatsLogProcessorTest, TestRateLimitBroadcast);
FRIEND_TEST(StatsLogProcessorTest, TestDropWhenByteSizeTooLarge);
- FRIEND_TEST(StatsLogProcessorTest, TestDropWhenByteSizeTooLarge);
FRIEND_TEST(WakelockDurationE2eTest, TestAggregatedPredicateDimensionsForSumDuration1);
FRIEND_TEST(WakelockDurationE2eTest, TestAggregatedPredicateDimensionsForSumDuration2);
FRIEND_TEST(WakelockDurationE2eTest, TestAggregatedPredicateDimensionsForSumDuration3);
diff --git a/cmds/statsd/src/metrics/CountMetricProducer.cpp b/cmds/statsd/src/metrics/CountMetricProducer.cpp
index af2e362..671c57f 100644
--- a/cmds/statsd/src/metrics/CountMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/CountMetricProducer.cpp
@@ -151,8 +151,11 @@
protoOutput->end(protoToken);
mPastBuckets.clear();
+}
- // TODO: Clear mDimensionKeyMap once the report is dumped.
+void CountMetricProducer::dropDataLocked(const uint64_t dropTimeNs) {
+ flushIfNeededLocked(dropTimeNs);
+ mPastBuckets.clear();
}
void CountMetricProducer::onConditionChangedLocked(const bool conditionMet,
diff --git a/cmds/statsd/src/metrics/CountMetricProducer.h b/cmds/statsd/src/metrics/CountMetricProducer.h
index 0c4291d..1d8e42b 100644
--- a/cmds/statsd/src/metrics/CountMetricProducer.h
+++ b/cmds/statsd/src/metrics/CountMetricProducer.h
@@ -69,6 +69,8 @@
void dumpStatesLocked(FILE* out, bool verbose) const override{};
+ void dropDataLocked(const uint64_t dropTimeNs) override;
+
// Util function to flush the old packet.
void flushIfNeededLocked(const uint64_t& newEventTime) override;
diff --git a/cmds/statsd/src/metrics/DurationMetricProducer.cpp b/cmds/statsd/src/metrics/DurationMetricProducer.cpp
index 80329c3..ac39662 100644
--- a/cmds/statsd/src/metrics/DurationMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/DurationMetricProducer.cpp
@@ -221,6 +221,11 @@
}
}
+void DurationMetricProducer::dropDataLocked(const uint64_t dropTimeNs) {
+ flushIfNeededLocked(dropTimeNs);
+ mPastBuckets.clear();
+}
+
void DurationMetricProducer::onDumpReportLocked(const uint64_t dumpTimeNs,
ProtoOutputStream* protoOutput) {
flushIfNeededLocked(dumpTimeNs);
diff --git a/cmds/statsd/src/metrics/DurationMetricProducer.h b/cmds/statsd/src/metrics/DurationMetricProducer.h
index 73d074f..23408a7 100644
--- a/cmds/statsd/src/metrics/DurationMetricProducer.h
+++ b/cmds/statsd/src/metrics/DurationMetricProducer.h
@@ -74,6 +74,8 @@
void dumpStatesLocked(FILE* out, bool verbose) const override;
+ void dropDataLocked(const uint64_t dropTimeNs) override;
+
// Util function to flush the old packet.
void flushIfNeededLocked(const uint64_t& eventTime);
diff --git a/cmds/statsd/src/metrics/EventMetricProducer.cpp b/cmds/statsd/src/metrics/EventMetricProducer.cpp
index 96d0cfc..fff91f6 100644
--- a/cmds/statsd/src/metrics/EventMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/EventMetricProducer.cpp
@@ -75,6 +75,10 @@
VLOG("~EventMetricProducer() called");
}
+void EventMetricProducer::dropDataLocked(const uint64_t dropTimeNs) {
+ mProto->clear();
+}
+
void EventMetricProducer::onSlicedConditionMayChangeLocked(const uint64_t eventTime) {
}
diff --git a/cmds/statsd/src/metrics/EventMetricProducer.h b/cmds/statsd/src/metrics/EventMetricProducer.h
index 3f2c5a5..d6f81fd 100644
--- a/cmds/statsd/src/metrics/EventMetricProducer.h
+++ b/cmds/statsd/src/metrics/EventMetricProducer.h
@@ -55,6 +55,8 @@
// Internal interface to handle sliced condition change.
void onSlicedConditionMayChangeLocked(const uint64_t eventTime) override;
+ void dropDataLocked(const uint64_t dropTimeNs) override;
+
// Internal function to calculate the current used bytes.
size_t byteSizeLocked() const override;
diff --git a/cmds/statsd/src/metrics/GaugeMetricProducer.cpp b/cmds/statsd/src/metrics/GaugeMetricProducer.cpp
index 7d09ff9..000c7a7 100644
--- a/cmds/statsd/src/metrics/GaugeMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/GaugeMetricProducer.cpp
@@ -353,6 +353,11 @@
}
}
+void GaugeMetricProducer::dropDataLocked(const uint64_t dropTimeNs) {
+ flushIfNeededLocked(dropTimeNs);
+ mPastBuckets.clear();
+}
+
// When a new matched event comes in, we check if event falls into the current
// bucket. If not, flush the old counter to past buckets and initialize the new
// bucket.
diff --git a/cmds/statsd/src/metrics/GaugeMetricProducer.h b/cmds/statsd/src/metrics/GaugeMetricProducer.h
index c3ae6ce..ca8dc75 100644
--- a/cmds/statsd/src/metrics/GaugeMetricProducer.h
+++ b/cmds/statsd/src/metrics/GaugeMetricProducer.h
@@ -108,6 +108,8 @@
void dumpStatesLocked(FILE* out, bool verbose) const override{};
+ void dropDataLocked(const uint64_t dropTimeNs) override;
+
// Util function to flush the old packet.
void flushIfNeededLocked(const uint64_t& eventTime) override;
diff --git a/cmds/statsd/src/metrics/MetricProducer.h b/cmds/statsd/src/metrics/MetricProducer.h
index 2bf6241..05b7f87 100644
--- a/cmds/statsd/src/metrics/MetricProducer.h
+++ b/cmds/statsd/src/metrics/MetricProducer.h
@@ -148,6 +148,15 @@
return mMetricId;
}
+ // Let MetricProducer drop in-memory data to save memory.
+ // We still need to keep future data valid and anomaly tracking work, which means we will
+ // have to flush old data, informing anomaly trackers then safely drop old data.
+ // We still keep current bucket data for future metrics' validity.
+ void dropData(const uint64_t dropTimeNs) {
+ std::lock_guard<std::mutex> lock(mMutex);
+ dropDataLocked(dropTimeNs);
+ }
+
protected:
virtual void onConditionChangedLocked(const bool condition, const uint64_t eventTime) = 0;
virtual void onSlicedConditionMayChangeLocked(const uint64_t eventTime) = 0;
@@ -179,6 +188,8 @@
return mStartTimeNs + (mCurrentBucketNum + 1) * mBucketSizeNs;
}
+ virtual void dropDataLocked(const uint64_t dropTimeNs) = 0;
+
const int64_t mMetricId;
const ConfigKey mConfigKey;
diff --git a/cmds/statsd/src/metrics/MetricsManager.cpp b/cmds/statsd/src/metrics/MetricsManager.cpp
index 4c8a7d8..0693031 100644
--- a/cmds/statsd/src/metrics/MetricsManager.cpp
+++ b/cmds/statsd/src/metrics/MetricsManager.cpp
@@ -173,6 +173,12 @@
}
}
+void MetricsManager::dropData(const uint64_t dropTimeNs) {
+ for (const auto& producer : mAllMetricProducers) {
+ producer->dropData(dropTimeNs);
+ }
+}
+
void MetricsManager::onDumpReport(const uint64_t dumpTimeStampNs, ProtoOutputStream* protoOutput) {
VLOG("=========================Metric Reports Start==========================");
// one StatsLogReport per MetricProduer
diff --git a/cmds/statsd/src/metrics/MetricsManager.h b/cmds/statsd/src/metrics/MetricsManager.h
index b50ef4a..a32e037 100644
--- a/cmds/statsd/src/metrics/MetricsManager.h
+++ b/cmds/statsd/src/metrics/MetricsManager.h
@@ -73,6 +73,8 @@
return mLastReportTimeNs;
};
+ virtual void dropData(const uint64_t dropTimeNs);
+
// Config source owner can call onDumpReport() to get all the metrics collected.
virtual void onDumpReport(const uint64_t dumpTimeNs,
android::util::ProtoOutputStream* protoOutput);
diff --git a/cmds/statsd/src/metrics/ValueMetricProducer.cpp b/cmds/statsd/src/metrics/ValueMetricProducer.cpp
index 35fcdc4..f6bba3d 100644
--- a/cmds/statsd/src/metrics/ValueMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/ValueMetricProducer.cpp
@@ -129,6 +129,11 @@
VLOG("Metric %lld onSlicedConditionMayChange", (long long)mMetricId);
}
+void ValueMetricProducer::dropDataLocked(const uint64_t dropTimeNs) {
+ flushIfNeededLocked(dropTimeNs);
+ mPastBuckets.clear();
+}
+
void ValueMetricProducer::onDumpReportLocked(const uint64_t dumpTimeNs,
ProtoOutputStream* protoOutput) {
VLOG("metric %lld dump report now...", (long long)mMetricId);
diff --git a/cmds/statsd/src/metrics/ValueMetricProducer.h b/cmds/statsd/src/metrics/ValueMetricProducer.h
index b518f2f..5e42bd2 100644
--- a/cmds/statsd/src/metrics/ValueMetricProducer.h
+++ b/cmds/statsd/src/metrics/ValueMetricProducer.h
@@ -106,6 +106,8 @@
void flushCurrentBucketLocked(const uint64_t& eventTimeNs) override;
+ void dropDataLocked(const uint64_t dropTimeNs) override;
+
const FieldMatcher mValueField;
std::shared_ptr<StatsPullerManager> mStatsPullerManager;
diff --git a/cmds/statsd/tests/StatsLogProcessor_test.cpp b/cmds/statsd/tests/StatsLogProcessor_test.cpp
index 3238b74..efed42e 100644
--- a/cmds/statsd/tests/StatsLogProcessor_test.cpp
+++ b/cmds/statsd/tests/StatsLogProcessor_test.cpp
@@ -51,7 +51,8 @@
}
MOCK_METHOD0(byteSize, size_t());
- MOCK_METHOD2(onDumpReport, void(const uint64_t timeNs, ProtoOutputStream* output));
+
+ MOCK_METHOD1(dropData, void(const uint64_t dropTimeNs));
};
TEST(StatsLogProcessorTest, TestRateLimitByteSize) {
@@ -114,7 +115,7 @@
.Times(1)
.WillRepeatedly(Return(int(StatsdStats::kMaxMetricsBytesPerConfig * 1.2)));
- EXPECT_CALL(mockMetricsManager, onDumpReport(_, _)).Times(1);
+ EXPECT_CALL(mockMetricsManager, dropData(_)).Times(1);
// Expect to call the onDumpReport and skip the broadcast.
p.flushIfNecessaryLocked(1, key, mockMetricsManager);
diff --git a/config/hiddenapi-light-greylist.txt b/config/hiddenapi-light-greylist.txt
index 2c400e0..fb4d3b8 100644
--- a/config/hiddenapi-light-greylist.txt
+++ b/config/hiddenapi-light-greylist.txt
@@ -526,41 +526,22 @@
Landroid/content/res/AssetFileDescriptor;->mStartOffset:J
Landroid/content/res/AssetManager;->addAssetPathAsSharedLibrary(Ljava/lang/String;)I
Landroid/content/res/AssetManager;->addAssetPath(Ljava/lang/String;)I
-Landroid/content/res/AssetManager;->addAssetPathNative(Ljava/lang/String;Z)I
-Landroid/content/res/AssetManager;->addAssetPaths([Ljava/lang/String;)[I
-Landroid/content/res/AssetManager;->applyStyle(JIIJ[IIJJ)V
-Landroid/content/res/AssetManager;->ensureStringBlocks()[Landroid/content/res/StringBlock;
-Landroid/content/res/AssetManager;->getArraySize(I)I
Landroid/content/res/AssetManager;->getAssignedPackageIdentifiers()Landroid/util/SparseArray;
-Landroid/content/res/AssetManager;->getCookieName(I)Ljava/lang/String;
-Landroid/content/res/AssetManager;->getNativeStringBlock(I)J
Landroid/content/res/AssetManager;->getResourceBagText(II)Ljava/lang/CharSequence;
Landroid/content/res/AssetManager;->getResourceEntryName(I)Ljava/lang/String;
Landroid/content/res/AssetManager;->getResourceIdentifier(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)I
Landroid/content/res/AssetManager;->getResourceName(I)Ljava/lang/String;
Landroid/content/res/AssetManager;->getResourcePackageName(I)Ljava/lang/String;
Landroid/content/res/AssetManager;->getResourceTypeName(I)Ljava/lang/String;
-Landroid/content/res/AssetManager;->getStringBlockCount()I
Landroid/content/res/AssetManager;-><init>()V
Landroid/content/res/AssetManager;->isUpToDate()Z
-Landroid/content/res/AssetManager;->loadResourceBagValue(IILandroid/util/TypedValue;Z)I
-Landroid/content/res/AssetManager;->loadResourceValue(ISLandroid/util/TypedValue;Z)I
-Landroid/content/res/AssetManager;->loadThemeAttributeValue(JILandroid/util/TypedValue;Z)I
Landroid/content/res/AssetManager;->mObject:J
-Landroid/content/res/AssetManager;->mStringBlocks:[Landroid/content/res/StringBlock;
-Landroid/content/res/AssetManager;->openNonAssetFdNative(ILjava/lang/String;[J)Landroid/os/ParcelFileDescriptor;
Landroid/content/res/AssetManager;->openNonAsset(ILjava/lang/String;I)Ljava/io/InputStream;
Landroid/content/res/AssetManager;->openNonAsset(ILjava/lang/String;)Ljava/io/InputStream;
Landroid/content/res/AssetManager;->openNonAsset(Ljava/lang/String;I)Ljava/io/InputStream;
Landroid/content/res/AssetManager;->openNonAsset(Ljava/lang/String;)Ljava/io/InputStream;
-Landroid/content/res/AssetManager;->openNonAssetNative(ILjava/lang/String;I)J
-Landroid/content/res/AssetManager;->openXmlAssetNative(ILjava/lang/String;)J
Landroid/content/res/AssetManager;->resolveAttrs(JII[I[I[I[I)Z
-Landroid/content/res/AssetManager;->retrieveArray(I[I)I
-Landroid/content/res/AssetManager;->retrieveAttributes(J[I[I[I)Z
Landroid/content/res/AssetManager;->setConfiguration(IILjava/lang/String;IIIIIIIIIIIIIII)V
-Landroid/content/res/AssetManager;->STYLE_NUM_ENTRIES:I
-Landroid/content/res/AssetManager;->STYLE_RESOURCE_ID:I
Landroid/content/res/ColorStateList$ColorStateListFactory;-><init>(Landroid/content/res/ColorStateList;)V
Landroid/content/res/ColorStateList;->mColors:[I
Landroid/content/res/ColorStateList;->mDefaultColor:I
@@ -602,7 +583,6 @@
Landroid/content/res/TypedArray;->mTheme:Landroid/content/res/Resources$Theme;
Landroid/content/res/TypedArray;->mValue:Landroid/util/TypedValue;
Landroid/content/res/TypedArray;->mXml:Landroid/content/res/XmlBlock$Parser;
-Landroid/content/res/XmlBlock;->close()V
Landroid/content/res/XmlBlock;-><init>([B)V
Landroid/content/res/XmlBlock;->newParser()Landroid/content/res/XmlResourceParser;
Landroid/content/res/XmlBlock$Parser;->mParseState:J
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 3d04e2c..99c5d2b 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -6366,6 +6366,8 @@
} else {
writer.print(prefix); writer.println("No AutofillManager");
}
+
+ ResourcesManager.getInstance().dump(prefix, writer);
}
/**
diff --git a/core/java/android/app/LoadedApk.java b/core/java/android/app/LoadedApk.java
index ea5932c..fc7d9a5 100644
--- a/core/java/android/app/LoadedApk.java
+++ b/core/java/android/app/LoadedApk.java
@@ -219,7 +219,7 @@
}
private AppComponentFactory createAppFactory(ApplicationInfo appInfo, ClassLoader cl) {
- if (appInfo.appComponentFactory != null) {
+ if (appInfo.appComponentFactory != null && cl != null) {
try {
return (AppComponentFactory) cl.loadClass(appInfo.appComponentFactory)
.newInstance();
@@ -613,6 +613,7 @@
} else {
mClassLoader = ClassLoader.getSystemClassLoader();
}
+ mAppComponentFactory = createAppFactory(mApplicationInfo, mClassLoader);
return;
}
@@ -687,6 +688,7 @@
librarySearchPath, libraryPermittedPath, mBaseClassLoader,
null /* classLoaderName */);
StrictMode.setThreadPolicy(oldPolicy);
+ mAppComponentFactory = createAppFactory(mApplicationInfo, mClassLoader);
}
return;
@@ -714,6 +716,7 @@
mApplicationInfo.targetSdkVersion, isBundledApp, librarySearchPath,
libraryPermittedPath, mBaseClassLoader,
mApplicationInfo.classLoaderName);
+ mAppComponentFactory = createAppFactory(mApplicationInfo, mClassLoader);
StrictMode.setThreadPolicy(oldPolicy);
// Setup the class loader paths for profiling.
diff --git a/core/java/android/app/ResourcesManager.java b/core/java/android/app/ResourcesManager.java
index fb11272..fc5ea66 100644
--- a/core/java/android/app/ResourcesManager.java
+++ b/core/java/android/app/ResourcesManager.java
@@ -21,6 +21,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.pm.ActivityInfo;
+import android.content.res.ApkAssets;
import android.content.res.AssetManager;
import android.content.res.CompatResources;
import android.content.res.CompatibilityInfo;
@@ -34,6 +35,7 @@
import android.util.ArrayMap;
import android.util.DisplayMetrics;
import android.util.Log;
+import android.util.LruCache;
import android.util.Pair;
import android.util.Slog;
import android.view.Display;
@@ -41,9 +43,13 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.ArrayUtils;
+import com.android.internal.util.IndentingPrintWriter;
+import java.io.IOException;
+import java.io.PrintWriter;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.Objects;
import java.util.WeakHashMap;
import java.util.function.Predicate;
@@ -59,12 +65,7 @@
* Predicate that returns true if a WeakReference is gc'ed.
*/
private static final Predicate<WeakReference<Resources>> sEmptyReferencePredicate =
- new Predicate<WeakReference<Resources>>() {
- @Override
- public boolean test(WeakReference<Resources> weakRef) {
- return weakRef == null || weakRef.get() == null;
- }
- };
+ weakRef -> weakRef == null || weakRef.get() == null;
/**
* The global compatibility settings.
@@ -89,6 +90,48 @@
*/
private final ArrayList<WeakReference<Resources>> mResourceReferences = new ArrayList<>();
+ private static class ApkKey {
+ public final String path;
+ public final boolean sharedLib;
+ public final boolean overlay;
+
+ ApkKey(String path, boolean sharedLib, boolean overlay) {
+ this.path = path;
+ this.sharedLib = sharedLib;
+ this.overlay = overlay;
+ }
+
+ @Override
+ public int hashCode() {
+ int result = 1;
+ result = 31 * result + this.path.hashCode();
+ result = 31 * result + Boolean.hashCode(this.sharedLib);
+ result = 31 * result + Boolean.hashCode(this.overlay);
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (!(obj instanceof ApkKey)) {
+ return false;
+ }
+ ApkKey other = (ApkKey) obj;
+ return this.path.equals(other.path) && this.sharedLib == other.sharedLib
+ && this.overlay == other.overlay;
+ }
+ }
+
+ /**
+ * The ApkAssets we are caching and intend to hold strong references to.
+ */
+ private final LruCache<ApkKey, ApkAssets> mLoadedApkAssets = new LruCache<>(15);
+
+ /**
+ * The ApkAssets that are being referenced in the wild that we can reuse, even if they aren't
+ * in our LRU cache. Bonus resources :)
+ */
+ private final ArrayMap<ApkKey, WeakReference<ApkAssets>> mCachedApkAssets = new ArrayMap<>();
+
/**
* Resources and base configuration override associated with an Activity.
*/
@@ -260,6 +303,43 @@
}
}
+ private static String overlayPathToIdmapPath(String path) {
+ return "/data/resource-cache/" + path.substring(1).replace('/', '@') + "@idmap";
+ }
+
+ private @NonNull ApkAssets loadApkAssets(String path, boolean sharedLib, boolean overlay)
+ throws IOException {
+ final ApkKey newKey = new ApkKey(path, sharedLib, overlay);
+ ApkAssets apkAssets = mLoadedApkAssets.get(newKey);
+ if (apkAssets != null) {
+ return apkAssets;
+ }
+
+ // Optimistically check if this ApkAssets exists somewhere else.
+ final WeakReference<ApkAssets> apkAssetsRef = mCachedApkAssets.get(newKey);
+ if (apkAssetsRef != null) {
+ apkAssets = apkAssetsRef.get();
+ if (apkAssets != null) {
+ mLoadedApkAssets.put(newKey, apkAssets);
+ return apkAssets;
+ } else {
+ // Clean up the reference.
+ mCachedApkAssets.remove(newKey);
+ }
+ }
+
+ // We must load this from disk.
+ if (overlay) {
+ apkAssets = ApkAssets.loadOverlayFromPath(overlayPathToIdmapPath(path),
+ false /*system*/);
+ } else {
+ apkAssets = ApkAssets.loadFromPath(path, false /*system*/, sharedLib);
+ }
+ mLoadedApkAssets.put(newKey, apkAssets);
+ mCachedApkAssets.put(newKey, new WeakReference<>(apkAssets));
+ return apkAssets;
+ }
+
/**
* Creates an AssetManager from the paths within the ResourcesKey.
*
@@ -270,13 +350,16 @@
*/
@VisibleForTesting
protected @Nullable AssetManager createAssetManager(@NonNull final ResourcesKey key) {
- AssetManager assets = new AssetManager();
+ final AssetManager.Builder builder = new AssetManager.Builder();
// resDir can be null if the 'android' package is creating a new Resources object.
// This is fine, since each AssetManager automatically loads the 'android' package
// already.
if (key.mResDir != null) {
- if (assets.addAssetPath(key.mResDir) == 0) {
+ try {
+ builder.addApkAssets(loadApkAssets(key.mResDir, false /*sharedLib*/,
+ false /*overlay*/));
+ } catch (IOException e) {
Log.e(TAG, "failed to add asset path " + key.mResDir);
return null;
}
@@ -284,7 +367,10 @@
if (key.mSplitResDirs != null) {
for (final String splitResDir : key.mSplitResDirs) {
- if (assets.addAssetPath(splitResDir) == 0) {
+ try {
+ builder.addApkAssets(loadApkAssets(splitResDir, false /*sharedLib*/,
+ false /*overlay*/));
+ } catch (IOException e) {
Log.e(TAG, "failed to add split asset path " + splitResDir);
return null;
}
@@ -293,7 +379,14 @@
if (key.mOverlayDirs != null) {
for (final String idmapPath : key.mOverlayDirs) {
- assets.addOverlayPath(idmapPath);
+ try {
+ builder.addApkAssets(loadApkAssets(idmapPath, false /*sharedLib*/,
+ true /*overlay*/));
+ } catch (IOException e) {
+ Log.w(TAG, "failed to add overlay path " + idmapPath);
+
+ // continue.
+ }
}
}
@@ -302,14 +395,73 @@
if (libDir.endsWith(".apk")) {
// Avoid opening files we know do not have resources,
// like code-only .jar files.
- if (assets.addAssetPathAsSharedLibrary(libDir) == 0) {
+ try {
+ builder.addApkAssets(loadApkAssets(libDir, true /*sharedLib*/,
+ false /*overlay*/));
+ } catch (IOException e) {
Log.w(TAG, "Asset path '" + libDir +
"' does not exist or contains no resources.");
+
+ // continue.
}
}
}
}
- return assets;
+
+ return builder.build();
+ }
+
+ private static <T> int countLiveReferences(Collection<WeakReference<T>> collection) {
+ int count = 0;
+ for (WeakReference<T> ref : collection) {
+ final T value = ref != null ? ref.get() : null;
+ if (value != null) {
+ count++;
+ }
+ }
+ return count;
+ }
+
+ /**
+ * @hide
+ */
+ public void dump(String prefix, PrintWriter printWriter) {
+ synchronized (this) {
+ IndentingPrintWriter pw = new IndentingPrintWriter(printWriter, " ");
+ for (int i = 0; i < prefix.length() / 2; i++) {
+ pw.increaseIndent();
+ }
+
+ pw.println("ResourcesManager:");
+ pw.increaseIndent();
+ pw.print("cached apks: total=");
+ pw.print(mLoadedApkAssets.size());
+ pw.print(" created=");
+ pw.print(mLoadedApkAssets.createCount());
+ pw.print(" evicted=");
+ pw.print(mLoadedApkAssets.evictionCount());
+ pw.print(" hit=");
+ pw.print(mLoadedApkAssets.hitCount());
+ pw.print(" miss=");
+ pw.print(mLoadedApkAssets.missCount());
+ pw.print(" max=");
+ pw.print(mLoadedApkAssets.maxSize());
+ pw.println();
+
+ pw.print("total apks: ");
+ pw.println(countLiveReferences(mCachedApkAssets.values()));
+
+ pw.print("resources: ");
+
+ int references = countLiveReferences(mResourceReferences);
+ for (ActivityResources activityResources : mActivityResourceReferences.values()) {
+ references += countLiveReferences(activityResources.activityResources);
+ }
+ pw.println(references);
+
+ pw.print("resource impls: ");
+ pw.println(countLiveReferences(mResourceImpls.values()));
+ }
}
private Configuration generateConfig(@NonNull ResourcesKey key, @NonNull DisplayMetrics dm) {
@@ -630,28 +782,16 @@
// We will create the ResourcesImpl object outside of holding this lock.
}
- }
- // If we're here, we didn't find a suitable ResourcesImpl to use, so create one now.
- ResourcesImpl resourcesImpl = createResourcesImpl(key);
- if (resourcesImpl == null) {
- return null;
- }
-
- synchronized (this) {
- ResourcesImpl existingResourcesImpl = findResourcesImplForKeyLocked(key);
- if (existingResourcesImpl != null) {
- if (DEBUG) {
- Slog.d(TAG, "- got beat! existing impl=" + existingResourcesImpl
- + " new impl=" + resourcesImpl);
- }
- resourcesImpl.getAssets().close();
- resourcesImpl = existingResourcesImpl;
- } else {
- // Add this ResourcesImpl to the cache.
- mResourceImpls.put(key, new WeakReference<>(resourcesImpl));
+ // If we're here, we didn't find a suitable ResourcesImpl to use, so create one now.
+ ResourcesImpl resourcesImpl = createResourcesImpl(key);
+ if (resourcesImpl == null) {
+ return null;
}
+ // Add this ResourcesImpl to the cache.
+ mResourceImpls.put(key, new WeakReference<>(resourcesImpl));
+
final Resources resources;
if (activityToken != null) {
resources = getOrCreateResourcesForActivityLocked(activityToken, classLoader,
diff --git a/core/java/android/app/usage/IUsageStatsManager.aidl b/core/java/android/app/usage/IUsageStatsManager.aidl
index e72b84d..fff1a00 100644
--- a/core/java/android/app/usage/IUsageStatsManager.aidl
+++ b/core/java/android/app/usage/IUsageStatsManager.aidl
@@ -32,6 +32,7 @@
ParceledListSlice queryConfigurationStats(int bucketType, long beginTime, long endTime,
String callingPackage);
UsageEvents queryEvents(long beginTime, long endTime, String callingPackage);
+ UsageEvents queryEventsForPackage(long beginTime, long endTime, String callingPackage);
void setAppInactive(String packageName, boolean inactive, int userId);
boolean isAppInactive(String packageName, int userId);
void whitelistAppTemporarily(String packageName, long duration, int userId);
diff --git a/core/java/android/app/usage/UsageStatsManager.java b/core/java/android/app/usage/UsageStatsManager.java
index 5a57b06..5f9fa43 100644
--- a/core/java/android/app/usage/UsageStatsManager.java
+++ b/core/java/android/app/usage/UsageStatsManager.java
@@ -52,10 +52,13 @@
* </pre>
* A request for data in the middle of a time interval will include that interval.
* <p/>
- * <b>NOTE:</b> This API requires the permission android.permission.PACKAGE_USAGE_STATS.
- * However, declaring the permission implies intention to use the API and the user of the device
- * still needs to grant permission through the Settings application.
- * See {@link android.provider.Settings#ACTION_USAGE_ACCESS_SETTINGS}
+ * <b>NOTE:</b> Most methods on this API require the permission
+ * android.permission.PACKAGE_USAGE_STATS. However, declaring the permission implies intention to
+ * use the API and the user of the device still needs to grant permission through the Settings
+ * application.
+ * See {@link android.provider.Settings#ACTION_USAGE_ACCESS_SETTINGS}.
+ * Methods which only return the information for the calling package do not require this permission.
+ * E.g. {@link #getAppStandbyBucket()} and {@link #queryEventsForSelf(long, long)}.
*/
@SystemService(Context.USAGE_STATS_SERVICE)
public final class UsageStatsManager {
@@ -206,6 +209,8 @@
* 2014 - com.example.charlie
* </pre>
*
+ * <p> The caller must have {@link android.Manifest.permission#PACKAGE_USAGE_STATS} </p>
+ *
* @param intervalType The time interval by which the stats are aggregated.
* @param beginTime The inclusive beginning of the range of stats to include in the results.
* @param endTime The exclusive end of the range of stats to include in the results.
@@ -235,6 +240,7 @@
* Gets the hardware configurations the device was in for the given time range, aggregated by
* the specified interval. The results are ordered as in
* {@link #queryUsageStats(int, long, long)}.
+ * <p> The caller must have {@link android.Manifest.permission#PACKAGE_USAGE_STATS} </p>
*
* @param intervalType The time interval by which the stats are aggregated.
* @param beginTime The inclusive beginning of the range of stats to include in the results.
@@ -259,6 +265,7 @@
/**
* Query for events in the given time range. Events are only kept by the system for a few
* days.
+ * <p> The caller must have {@link android.Manifest.permission#PACKAGE_USAGE_STATS} </p>
*
* @param beginTime The inclusive beginning of the range of events to include in the results.
* @param endTime The exclusive end of the range of events to include in the results.
@@ -278,9 +285,32 @@
}
/**
+ * Like {@link #queryEvents(long, long)}, but only returns events for the calling package.
+ *
+ * @param beginTime The inclusive beginning of the range of events to include in the results.
+ * @param endTime The exclusive end of the range of events to include in the results.
+ * @return A {@link UsageEvents} object.
+ *
+ * @see #queryEvents(long, long)
+ */
+ public UsageEvents queryEventsForSelf(long beginTime, long endTime) {
+ try {
+ final UsageEvents events = mService.queryEventsForPackage(beginTime, endTime,
+ mContext.getOpPackageName());
+ if (events != null) {
+ return events;
+ }
+ } catch (RemoteException e) {
+ // fallthrough
+ }
+ return sEmptyResults;
+ }
+
+ /**
* A convenience method that queries for all stats in the given range (using the best interval
* for that range), merges the resulting data, and keys it by package name.
* See {@link #queryUsageStats(int, long, long)}.
+ * <p> The caller must have {@link android.Manifest.permission#PACKAGE_USAGE_STATS} </p>
*
* @param beginTime The inclusive beginning of the range of stats to include in the results.
* @param endTime The exclusive end of the range of stats to include in the results.
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index b2c9edd4..f7649c9 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -763,15 +763,13 @@
public String[] resourceDirs;
/**
- * String retrieved from the seinfo tag found in selinux policy. This value
- * can be overridden with a value set through the mac_permissions.xml policy
- * construct. This value is useful in setting an SELinux security context on
- * the process as well as its data directory. The String default is being used
- * here to represent a catchall label when no policy matches.
+ * String retrieved from the seinfo tag found in selinux policy. This value can be set through
+ * the mac_permissions.xml policy construct. This value is used for setting an SELinux security
+ * context on the process as well as its data directory.
*
* {@hide}
*/
- public String seInfo = "default";
+ public String seInfo;
/**
* The seinfo tag generated per-user. This value may change based upon the
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 04a028b..5d5a978 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -54,6 +54,7 @@
import android.content.pm.split.DefaultSplitAssetLoader;
import android.content.pm.split.SplitAssetDependencyLoader;
import android.content.pm.split.SplitAssetLoader;
+import android.content.res.ApkAssets;
import android.content.res.AssetManager;
import android.content.res.Configuration;
import android.content.res.Resources;
@@ -1287,7 +1288,6 @@
*/
@Deprecated
public Package parseMonolithicPackage(File apkFile, int flags) throws PackageParserException {
- final AssetManager assets = newConfiguredAssetManager();
final PackageLite lite = parseMonolithicPackageLite(apkFile, flags);
if (mOnlyCoreApps) {
if (!lite.coreApp) {
@@ -1296,8 +1296,9 @@
}
}
+ final SplitAssetLoader assetLoader = new DefaultSplitAssetLoader(lite, flags);
try {
- final Package pkg = parseBaseApk(apkFile, assets, flags);
+ final Package pkg = parseBaseApk(apkFile, assetLoader.getBaseAssetManager(), flags);
pkg.setCodePath(apkFile.getCanonicalPath());
pkg.setUse32bitAbi(lite.use32bitAbi);
return pkg;
@@ -1305,28 +1306,10 @@
throw new PackageParserException(INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION,
"Failed to get path: " + apkFile, e);
} finally {
- IoUtils.closeQuietly(assets);
+ IoUtils.closeQuietly(assetLoader);
}
}
- private static int loadApkIntoAssetManager(AssetManager assets, String apkPath, int flags)
- throws PackageParserException {
- if ((flags & PARSE_MUST_BE_APK) != 0 && !isApkPath(apkPath)) {
- throw new PackageParserException(INSTALL_PARSE_FAILED_NOT_APK,
- "Invalid package file: " + apkPath);
- }
-
- // The AssetManager guarantees uniqueness for asset paths, so if this asset path
- // already exists in the AssetManager, addAssetPath will only return the cookie
- // assigned to it.
- int cookie = assets.addAssetPath(apkPath);
- if (cookie == 0) {
- throw new PackageParserException(INSTALL_PARSE_FAILED_BAD_MANIFEST,
- "Failed adding asset path: " + apkPath);
- }
- return cookie;
- }
-
private Package parseBaseApk(File apkFile, AssetManager assets, int flags)
throws PackageParserException {
final String apkPath = apkFile.getAbsolutePath();
@@ -1342,13 +1325,15 @@
if (DEBUG_JAR) Slog.d(TAG, "Scanning base APK: " + apkPath);
- final int cookie = loadApkIntoAssetManager(assets, apkPath, flags);
-
- Resources res = null;
XmlResourceParser parser = null;
try {
- res = new Resources(assets, mMetrics, null);
+ final int cookie = assets.findCookieForPath(apkPath);
+ if (cookie == 0) {
+ throw new PackageParserException(INSTALL_PARSE_FAILED_BAD_MANIFEST,
+ "Failed adding asset path: " + apkPath);
+ }
parser = assets.openXmlResourceParser(cookie, ANDROID_MANIFEST_FILENAME);
+ final Resources res = new Resources(assets, mMetrics, null);
final String[] outError = new String[1];
final Package pkg = parseBaseApk(apkPath, res, parser, flags, outError);
@@ -1383,15 +1368,18 @@
if (DEBUG_JAR) Slog.d(TAG, "Scanning split APK: " + apkPath);
- final int cookie = loadApkIntoAssetManager(assets, apkPath, flags);
-
final Resources res;
XmlResourceParser parser = null;
try {
- res = new Resources(assets, mMetrics, null);
- assets.setConfiguration(0, 0, null, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- Build.VERSION.RESOURCES_SDK_INT);
+ // This must always succeed, as the path has been added to the AssetManager before.
+ final int cookie = assets.findCookieForPath(apkPath);
+ if (cookie == 0) {
+ throw new PackageParserException(INSTALL_PARSE_FAILED_BAD_MANIFEST,
+ "Failed adding asset path: " + apkPath);
+ }
+
parser = assets.openXmlResourceParser(cookie, ANDROID_MANIFEST_FILENAME);
+ res = new Resources(assets, mMetrics, null);
final String[] outError = new String[1];
pkg = parseSplitApk(pkg, res, parser, flags, splitIndex, outError);
@@ -1593,21 +1581,19 @@
int flags) throws PackageParserException {
final String apkPath = fd != null ? debugPathName : apkFile.getAbsolutePath();
- AssetManager assets = null;
XmlResourceParser parser = null;
try {
- assets = newConfiguredAssetManager();
- int cookie = fd != null
- ? assets.addAssetFd(fd, debugPathName) : assets.addAssetPath(apkPath);
- if (cookie == 0) {
+ final ApkAssets apkAssets;
+ try {
+ apkAssets = fd != null
+ ? ApkAssets.loadFromFd(fd, debugPathName, false, false)
+ : ApkAssets.loadFromPath(apkPath);
+ } catch (IOException e) {
throw new PackageParserException(INSTALL_PARSE_FAILED_NOT_APK,
"Failed to parse " + apkPath);
}
- final DisplayMetrics metrics = new DisplayMetrics();
- metrics.setToDefaults();
-
- parser = assets.openXmlResourceParser(cookie, ANDROID_MANIFEST_FILENAME);
+ parser = apkAssets.openXml(ANDROID_MANIFEST_FILENAME);
final SigningDetails signingDetails;
if ((flags & PARSE_COLLECT_CERTIFICATES) != 0) {
@@ -1634,7 +1620,7 @@
"Failed to parse " + apkPath, e);
} finally {
IoUtils.closeQuietly(parser);
- IoUtils.closeQuietly(assets);
+ // TODO(b/72056911): Implement and call close() on ApkAssets.
}
}
diff --git a/core/java/android/content/pm/split/DefaultSplitAssetLoader.java b/core/java/android/content/pm/split/DefaultSplitAssetLoader.java
index 99eb470..9e3a8f4 100644
--- a/core/java/android/content/pm/split/DefaultSplitAssetLoader.java
+++ b/core/java/android/content/pm/split/DefaultSplitAssetLoader.java
@@ -15,10 +15,13 @@
*/
package android.content.pm.split;
-import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_BAD_MANIFEST;
+import static android.content.pm.PackageManager.INSTALL_FAILED_INVALID_APK;
import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_NOT_APK;
import android.content.pm.PackageParser;
+import android.content.pm.PackageParser.PackageParserException;
+import android.content.pm.PackageParser.ParseFlags;
+import android.content.res.ApkAssets;
import android.content.res.AssetManager;
import android.os.Build;
@@ -26,6 +29,8 @@
import libcore.io.IoUtils;
+import java.io.IOException;
+
/**
* Loads the base and split APKs into a single AssetManager.
* @hide
@@ -33,68 +38,66 @@
public class DefaultSplitAssetLoader implements SplitAssetLoader {
private final String mBaseCodePath;
private final String[] mSplitCodePaths;
- private final int mFlags;
-
+ private final @ParseFlags int mFlags;
private AssetManager mCachedAssetManager;
- public DefaultSplitAssetLoader(PackageParser.PackageLite pkg, int flags) {
+ public DefaultSplitAssetLoader(PackageParser.PackageLite pkg, @ParseFlags int flags) {
mBaseCodePath = pkg.baseCodePath;
mSplitCodePaths = pkg.splitCodePaths;
mFlags = flags;
}
- private static void loadApkIntoAssetManager(AssetManager assets, String apkPath, int flags)
- throws PackageParser.PackageParserException {
- if ((flags & PackageParser.PARSE_MUST_BE_APK) != 0 && !PackageParser.isApkPath(apkPath)) {
- throw new PackageParser.PackageParserException(INSTALL_PARSE_FAILED_NOT_APK,
- "Invalid package file: " + apkPath);
+ private static ApkAssets loadApkAssets(String path, @ParseFlags int flags)
+ throws PackageParserException {
+ if ((flags & PackageParser.PARSE_MUST_BE_APK) != 0 && !PackageParser.isApkPath(path)) {
+ throw new PackageParserException(INSTALL_PARSE_FAILED_NOT_APK,
+ "Invalid package file: " + path);
}
- if (assets.addAssetPath(apkPath) == 0) {
- throw new PackageParser.PackageParserException(
- INSTALL_PARSE_FAILED_BAD_MANIFEST,
- "Failed adding asset path: " + apkPath);
+ try {
+ return ApkAssets.loadFromPath(path);
+ } catch (IOException e) {
+ throw new PackageParserException(INSTALL_FAILED_INVALID_APK,
+ "Failed to load APK at path " + path, e);
}
}
@Override
- public AssetManager getBaseAssetManager() throws PackageParser.PackageParserException {
+ public AssetManager getBaseAssetManager() throws PackageParserException {
if (mCachedAssetManager != null) {
return mCachedAssetManager;
}
- AssetManager assets = new AssetManager();
- try {
- assets.setConfiguration(0, 0, null, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- Build.VERSION.RESOURCES_SDK_INT);
- loadApkIntoAssetManager(assets, mBaseCodePath, mFlags);
+ ApkAssets[] apkAssets = new ApkAssets[(mSplitCodePaths != null
+ ? mSplitCodePaths.length : 0) + 1];
- if (!ArrayUtils.isEmpty(mSplitCodePaths)) {
- for (String apkPath : mSplitCodePaths) {
- loadApkIntoAssetManager(assets, apkPath, mFlags);
- }
- }
+ // Load the base.
+ int splitIdx = 0;
+ apkAssets[splitIdx++] = loadApkAssets(mBaseCodePath, mFlags);
- mCachedAssetManager = assets;
- assets = null;
- return mCachedAssetManager;
- } finally {
- if (assets != null) {
- IoUtils.closeQuietly(assets);
+ // Load any splits.
+ if (!ArrayUtils.isEmpty(mSplitCodePaths)) {
+ for (String apkPath : mSplitCodePaths) {
+ apkAssets[splitIdx++] = loadApkAssets(apkPath, mFlags);
}
}
+
+ AssetManager assets = new AssetManager();
+ assets.setConfiguration(0, 0, null, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ Build.VERSION.RESOURCES_SDK_INT);
+ assets.setApkAssets(apkAssets, false /*invalidateCaches*/);
+
+ mCachedAssetManager = assets;
+ return mCachedAssetManager;
}
@Override
- public AssetManager getSplitAssetManager(int splitIdx)
- throws PackageParser.PackageParserException {
+ public AssetManager getSplitAssetManager(int splitIdx) throws PackageParserException {
return getBaseAssetManager();
}
@Override
public void close() throws Exception {
- if (mCachedAssetManager != null) {
- IoUtils.closeQuietly(mCachedAssetManager);
- }
+ IoUtils.closeQuietly(mCachedAssetManager);
}
}
diff --git a/core/java/android/content/pm/split/SplitAssetDependencyLoader.java b/core/java/android/content/pm/split/SplitAssetDependencyLoader.java
index 16023f0..58eaabf 100644
--- a/core/java/android/content/pm/split/SplitAssetDependencyLoader.java
+++ b/core/java/android/content/pm/split/SplitAssetDependencyLoader.java
@@ -15,17 +15,21 @@
*/
package android.content.pm.split;
-import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_BAD_MANIFEST;
import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_NOT_APK;
import android.annotation.NonNull;
+import android.content.pm.PackageManager;
import android.content.pm.PackageParser;
+import android.content.pm.PackageParser.PackageParserException;
+import android.content.pm.PackageParser.ParseFlags;
+import android.content.res.ApkAssets;
import android.content.res.AssetManager;
import android.os.Build;
import android.util.SparseArray;
import libcore.io.IoUtils;
+import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
@@ -34,17 +38,15 @@
* is to be used when an application opts-in to isolated split loading.
* @hide
*/
-public class SplitAssetDependencyLoader
- extends SplitDependencyLoader<PackageParser.PackageParserException>
+public class SplitAssetDependencyLoader extends SplitDependencyLoader<PackageParserException>
implements SplitAssetLoader {
private final String[] mSplitPaths;
- private final int mFlags;
-
- private String[][] mCachedPaths;
- private AssetManager[] mCachedAssetManagers;
+ private final @ParseFlags int mFlags;
+ private final ApkAssets[][] mCachedSplitApks;
+ private final AssetManager[] mCachedAssetManagers;
public SplitAssetDependencyLoader(PackageParser.PackageLite pkg,
- SparseArray<int[]> dependencies, int flags) {
+ SparseArray<int[]> dependencies, @ParseFlags int flags) {
super(dependencies);
// The base is inserted into index 0, so we need to shift all the splits by 1.
@@ -53,7 +55,7 @@
System.arraycopy(pkg.splitCodePaths, 0, mSplitPaths, 1, pkg.splitCodePaths.length);
mFlags = flags;
- mCachedPaths = new String[mSplitPaths.length][];
+ mCachedSplitApks = new ApkAssets[mSplitPaths.length][];
mCachedAssetManagers = new AssetManager[mSplitPaths.length];
}
@@ -62,58 +64,60 @@
return mCachedAssetManagers[splitIdx] != null;
}
- private static AssetManager createAssetManagerWithPaths(String[] assetPaths, int flags)
- throws PackageParser.PackageParserException {
- final AssetManager assets = new AssetManager();
- try {
- assets.setConfiguration(0, 0, null, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- Build.VERSION.RESOURCES_SDK_INT);
-
- for (String assetPath : assetPaths) {
- if ((flags & PackageParser.PARSE_MUST_BE_APK) != 0 &&
- !PackageParser.isApkPath(assetPath)) {
- throw new PackageParser.PackageParserException(INSTALL_PARSE_FAILED_NOT_APK,
- "Invalid package file: " + assetPath);
- }
-
- if (assets.addAssetPath(assetPath) == 0) {
- throw new PackageParser.PackageParserException(
- INSTALL_PARSE_FAILED_BAD_MANIFEST,
- "Failed adding asset path: " + assetPath);
- }
- }
- return assets;
- } catch (Throwable e) {
- IoUtils.closeQuietly(assets);
- throw e;
+ private static ApkAssets loadApkAssets(String path, @ParseFlags int flags)
+ throws PackageParserException {
+ if ((flags & PackageParser.PARSE_MUST_BE_APK) != 0 && !PackageParser.isApkPath(path)) {
+ throw new PackageParserException(INSTALL_PARSE_FAILED_NOT_APK,
+ "Invalid package file: " + path);
}
+
+ try {
+ return ApkAssets.loadFromPath(path);
+ } catch (IOException e) {
+ throw new PackageParserException(PackageManager.INSTALL_FAILED_INVALID_APK,
+ "Failed to load APK at path " + path, e);
+ }
+ }
+
+ private static AssetManager createAssetManagerWithAssets(ApkAssets[] apkAssets) {
+ final AssetManager assets = new AssetManager();
+ assets.setConfiguration(0, 0, null, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ Build.VERSION.RESOURCES_SDK_INT);
+ assets.setApkAssets(apkAssets, false /*invalidateCaches*/);
+ return assets;
}
@Override
protected void constructSplit(int splitIdx, @NonNull int[] configSplitIndices,
- int parentSplitIdx) throws PackageParser.PackageParserException {
- final ArrayList<String> assetPaths = new ArrayList<>();
+ int parentSplitIdx) throws PackageParserException {
+ final ArrayList<ApkAssets> assets = new ArrayList<>();
+
+ // Include parent ApkAssets.
if (parentSplitIdx >= 0) {
- Collections.addAll(assetPaths, mCachedPaths[parentSplitIdx]);
+ Collections.addAll(assets, mCachedSplitApks[parentSplitIdx]);
}
- assetPaths.add(mSplitPaths[splitIdx]);
+ // Include this ApkAssets.
+ assets.add(loadApkAssets(mSplitPaths[splitIdx], mFlags));
+
+ // Load and include all config splits for this feature.
for (int configSplitIdx : configSplitIndices) {
- assetPaths.add(mSplitPaths[configSplitIdx]);
+ assets.add(loadApkAssets(mSplitPaths[configSplitIdx], mFlags));
}
- mCachedPaths[splitIdx] = assetPaths.toArray(new String[assetPaths.size()]);
- mCachedAssetManagers[splitIdx] = createAssetManagerWithPaths(mCachedPaths[splitIdx],
- mFlags);
+
+ // Cache the results.
+ mCachedSplitApks[splitIdx] = assets.toArray(new ApkAssets[assets.size()]);
+ mCachedAssetManagers[splitIdx] = createAssetManagerWithAssets(mCachedSplitApks[splitIdx]);
}
@Override
- public AssetManager getBaseAssetManager() throws PackageParser.PackageParserException {
+ public AssetManager getBaseAssetManager() throws PackageParserException {
loadDependenciesForSplit(0);
return mCachedAssetManagers[0];
}
@Override
- public AssetManager getSplitAssetManager(int idx) throws PackageParser.PackageParserException {
+ public AssetManager getSplitAssetManager(int idx) throws PackageParserException {
// Since we insert the base at position 0, and PackageParser keeps splits separate from
// the base, we need to adjust the index.
loadDependenciesForSplit(idx + 1);
diff --git a/core/java/android/content/res/ApkAssets.java b/core/java/android/content/res/ApkAssets.java
new file mode 100644
index 0000000..9de8be3
--- /dev/null
+++ b/core/java/android/content/res/ApkAssets.java
@@ -0,0 +1,195 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.content.res;
+
+import android.annotation.NonNull;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.util.Preconditions;
+
+import java.io.FileDescriptor;
+import java.io.IOException;
+
+/**
+ * The loaded, immutable, in-memory representation of an APK.
+ *
+ * The main implementation is native C++ and there is very little API surface exposed here. The APK
+ * is mainly accessed via {@link AssetManager}.
+ *
+ * Since the ApkAssets instance is immutable, it can be reused and shared across AssetManagers,
+ * making the creation of AssetManagers very cheap.
+ * @hide
+ */
+public final class ApkAssets {
+ @GuardedBy("this") private final long mNativePtr;
+ @GuardedBy("this") private StringBlock mStringBlock;
+
+ /**
+ * Creates a new ApkAssets instance from the given path on disk.
+ *
+ * @param path The path to an APK on disk.
+ * @return a new instance of ApkAssets.
+ * @throws IOException if a disk I/O error or parsing error occurred.
+ */
+ public static @NonNull ApkAssets loadFromPath(@NonNull String path) throws IOException {
+ return new ApkAssets(path, false /*system*/, false /*forceSharedLib*/, false /*overlay*/);
+ }
+
+ /**
+ * Creates a new ApkAssets instance from the given path on disk.
+ *
+ * @param path The path to an APK on disk.
+ * @param system When true, the APK is loaded as a system APK (framework).
+ * @return a new instance of ApkAssets.
+ * @throws IOException if a disk I/O error or parsing error occurred.
+ */
+ public static @NonNull ApkAssets loadFromPath(@NonNull String path, boolean system)
+ throws IOException {
+ return new ApkAssets(path, system, false /*forceSharedLib*/, false /*overlay*/);
+ }
+
+ /**
+ * Creates a new ApkAssets instance from the given path on disk.
+ *
+ * @param path The path to an APK on disk.
+ * @param system When true, the APK is loaded as a system APK (framework).
+ * @param forceSharedLibrary When true, any packages within the APK with package ID 0x7f are
+ * loaded as a shared library.
+ * @return a new instance of ApkAssets.
+ * @throws IOException if a disk I/O error or parsing error occurred.
+ */
+ public static @NonNull ApkAssets loadFromPath(@NonNull String path, boolean system,
+ boolean forceSharedLibrary) throws IOException {
+ return new ApkAssets(path, system, forceSharedLibrary, false /*overlay*/);
+ }
+
+ /**
+ * Creates a new ApkAssets instance from the given file descriptor. Not for use by applications.
+ *
+ * Performs a dup of the underlying fd, so you must take care of still closing
+ * the FileDescriptor yourself (and can do that whenever you want).
+ *
+ * @param fd The FileDescriptor of an open, readable APK.
+ * @param friendlyName The friendly name used to identify this ApkAssets when logging.
+ * @param system When true, the APK is loaded as a system APK (framework).
+ * @param forceSharedLibrary When true, any packages within the APK with package ID 0x7f are
+ * loaded as a shared library.
+ * @return a new instance of ApkAssets.
+ * @throws IOException if a disk I/O error or parsing error occurred.
+ */
+ public static @NonNull ApkAssets loadFromFd(@NonNull FileDescriptor fd,
+ @NonNull String friendlyName, boolean system, boolean forceSharedLibrary)
+ throws IOException {
+ return new ApkAssets(fd, friendlyName, system, forceSharedLibrary);
+ }
+
+ /**
+ * Creates a new ApkAssets instance from the IDMAP at idmapPath. The overlay APK path
+ * is encoded within the IDMAP.
+ *
+ * @param idmapPath Path to the IDMAP of an overlay APK.
+ * @param system When true, the APK is loaded as a system APK (framework).
+ * @return a new instance of ApkAssets.
+ * @throws IOException if a disk I/O error or parsing error occurred.
+ */
+ public static @NonNull ApkAssets loadOverlayFromPath(@NonNull String idmapPath, boolean system)
+ throws IOException {
+ return new ApkAssets(idmapPath, system, false /*forceSharedLibrary*/, true /*overlay*/);
+ }
+
+ private ApkAssets(@NonNull String path, boolean system, boolean forceSharedLib, boolean overlay)
+ throws IOException {
+ Preconditions.checkNotNull(path, "path");
+ mNativePtr = nativeLoad(path, system, forceSharedLib, overlay);
+ mStringBlock = new StringBlock(nativeGetStringBlock(mNativePtr), true /*useSparse*/);
+ }
+
+ private ApkAssets(@NonNull FileDescriptor fd, @NonNull String friendlyName, boolean system,
+ boolean forceSharedLib) throws IOException {
+ Preconditions.checkNotNull(fd, "fd");
+ Preconditions.checkNotNull(friendlyName, "friendlyName");
+ mNativePtr = nativeLoadFromFd(fd, friendlyName, system, forceSharedLib);
+ mStringBlock = new StringBlock(nativeGetStringBlock(mNativePtr), true /*useSparse*/);
+ }
+
+ public @NonNull String getAssetPath() {
+ synchronized (this) {
+ return nativeGetAssetPath(mNativePtr);
+ }
+ }
+
+ CharSequence getStringFromPool(int idx) {
+ synchronized (this) {
+ return mStringBlock.get(idx);
+ }
+ }
+
+ /**
+ * Retrieve a parser for a compiled XML file. This is associated with a single APK and
+ * <em>NOT</em> a full AssetManager. This means that shared-library references will not be
+ * dynamically assigned runtime package IDs.
+ *
+ * @param fileName The path to the file within the APK.
+ * @return An XmlResourceParser.
+ * @throws IOException if the file was not found or an error occurred retrieving it.
+ */
+ public @NonNull XmlResourceParser openXml(@NonNull String fileName) throws IOException {
+ Preconditions.checkNotNull(fileName, "fileName");
+ synchronized (this) {
+ long nativeXmlPtr = nativeOpenXml(mNativePtr, fileName);
+ try (XmlBlock block = new XmlBlock(null, nativeXmlPtr)) {
+ XmlResourceParser parser = block.newParser();
+ // If nativeOpenXml doesn't throw, it will always return a valid native pointer,
+ // which makes newParser always return non-null. But let's be paranoid.
+ if (parser == null) {
+ throw new AssertionError("block.newParser() returned a null parser");
+ }
+ return parser;
+ }
+ }
+ }
+
+ /**
+ * Returns false if the underlying APK was changed since this ApkAssets was loaded.
+ */
+ public boolean isUpToDate() {
+ synchronized (this) {
+ return nativeIsUpToDate(mNativePtr);
+ }
+ }
+
+ @Override
+ public String toString() {
+ return "ApkAssets{path=" + getAssetPath() + "}";
+ }
+
+ @Override
+ protected void finalize() throws Throwable {
+ nativeDestroy(mNativePtr);
+ }
+
+ private static native long nativeLoad(
+ @NonNull String path, boolean system, boolean forceSharedLib, boolean overlay)
+ throws IOException;
+ private static native long nativeLoadFromFd(@NonNull FileDescriptor fd,
+ @NonNull String friendlyName, boolean system, boolean forceSharedLib)
+ throws IOException;
+ private static native void nativeDestroy(long ptr);
+ private static native @NonNull String nativeGetAssetPath(long ptr);
+ private static native long nativeGetStringBlock(long ptr);
+ private static native boolean nativeIsUpToDate(long ptr);
+ private static native long nativeOpenXml(long ptr, @NonNull String fileName) throws IOException;
+}
diff --git a/core/java/android/content/res/AssetManager.java b/core/java/android/content/res/AssetManager.java
index 5f8a34d..2895342 100644
--- a/core/java/android/content/res/AssetManager.java
+++ b/core/java/android/content/res/AssetManager.java
@@ -18,22 +18,33 @@
import android.annotation.AnyRes;
import android.annotation.ArrayRes;
+import android.annotation.AttrRes;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.StringRes;
+import android.annotation.StyleRes;
import android.content.pm.ActivityInfo;
import android.content.res.Configuration.NativeConfig;
import android.os.ParcelFileDescriptor;
+import android.util.ArraySet;
import android.util.Log;
import android.util.SparseArray;
import android.util.TypedValue;
import com.android.internal.annotations.GuardedBy;
+import com.android.internal.util.Preconditions;
-import java.io.FileDescriptor;
+import libcore.io.IoUtils;
+
+import java.io.BufferedReader;
+import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.nio.channels.FileLock;
+import java.util.ArrayList;
+import java.util.Arrays;
import java.util.HashMap;
/**
@@ -44,7 +55,20 @@
* bytes.
*/
public final class AssetManager implements AutoCloseable {
- /* modes used when opening an asset */
+ private static final String TAG = "AssetManager";
+ private static final boolean DEBUG_REFS = false;
+
+ private static final String FRAMEWORK_APK_PATH = "/system/framework/framework-res.apk";
+
+ private static final Object sSync = new Object();
+
+ private static final ApkAssets[] sEmptyApkAssets = new ApkAssets[0];
+
+ // Not private for LayoutLib's BridgeAssetManager.
+ @GuardedBy("sSync") static AssetManager sSystem = null;
+
+ @GuardedBy("sSync") private static ApkAssets[] sSystemApkAssets = new ApkAssets[0];
+ @GuardedBy("sSync") private static ArraySet<ApkAssets> sSystemApkAssetsSet;
/**
* Mode for {@link #open(String, int)}: no specific information about how
@@ -67,146 +91,358 @@
*/
public static final int ACCESS_BUFFER = 3;
- private static final String TAG = "AssetManager";
- private static final boolean localLOGV = false || false;
-
- private static final boolean DEBUG_REFS = false;
-
- private static final Object sSync = new Object();
- /*package*/ static AssetManager sSystem = null;
+ @GuardedBy("this") private final TypedValue mValue = new TypedValue();
+ @GuardedBy("this") private final long[] mOffsets = new long[2];
- private final TypedValue mValue = new TypedValue();
- private final long[] mOffsets = new long[2];
-
- // For communication with native code.
- private long mObject;
+ // Pointer to native implementation, stuffed inside a long.
+ @GuardedBy("this") private long mObject;
- private StringBlock mStringBlocks[] = null;
-
- private int mNumRefs = 1;
- private boolean mOpen = true;
- private HashMap<Long, RuntimeException> mRefStacks;
-
+ // The loaded asset paths.
+ @GuardedBy("this") private ApkAssets[] mApkAssets;
+
+ // Debug/reference counting implementation.
+ @GuardedBy("this") private boolean mOpen = true;
+ @GuardedBy("this") private int mNumRefs = 1;
+ @GuardedBy("this") private HashMap<Long, RuntimeException> mRefStacks;
+
+ /**
+ * A Builder class that helps create an AssetManager with only a single invocation of
+ * {@link AssetManager#setApkAssets(ApkAssets[], boolean)}. Without using this builder,
+ * AssetManager must ensure there are system ApkAssets loaded at all times, which when combined
+ * with the user's call to add additional ApkAssets, results in multiple calls to
+ * {@link AssetManager#setApkAssets(ApkAssets[], boolean)}.
+ * @hide
+ */
+ public static class Builder {
+ private ArrayList<ApkAssets> mUserApkAssets = new ArrayList<>();
+
+ public Builder addApkAssets(ApkAssets apkAssets) {
+ mUserApkAssets.add(apkAssets);
+ return this;
+ }
+
+ public AssetManager build() {
+ // Retrieving the system ApkAssets forces their creation as well.
+ final ApkAssets[] systemApkAssets = getSystem().getApkAssets();
+
+ final int totalApkAssetCount = systemApkAssets.length + mUserApkAssets.size();
+ final ApkAssets[] apkAssets = new ApkAssets[totalApkAssetCount];
+
+ System.arraycopy(systemApkAssets, 0, apkAssets, 0, systemApkAssets.length);
+
+ final int userApkAssetCount = mUserApkAssets.size();
+ for (int i = 0; i < userApkAssetCount; i++) {
+ apkAssets[i + systemApkAssets.length] = mUserApkAssets.get(i);
+ }
+
+ // Calling this constructor prevents creation of system ApkAssets, which we took care
+ // of in this Builder.
+ final AssetManager assetManager = new AssetManager(false /*sentinel*/);
+ assetManager.mApkAssets = apkAssets;
+ AssetManager.nativeSetApkAssets(assetManager.mObject, apkAssets,
+ false /*invalidateCaches*/);
+ return assetManager;
+ }
+ }
+
/**
* Create a new AssetManager containing only the basic system assets.
* Applications will not generally use this method, instead retrieving the
* appropriate asset manager with {@link Resources#getAssets}. Not for
* use by applications.
- * {@hide}
+ * @hide
*/
public AssetManager() {
- synchronized (this) {
- if (DEBUG_REFS) {
- mNumRefs = 0;
- incRefsLocked(this.hashCode());
- }
- init(false);
- if (localLOGV) Log.v(TAG, "New asset manager: " + this);
- ensureSystemAssets();
+ final ApkAssets[] assets;
+ synchronized (sSync) {
+ createSystemAssetsInZygoteLocked();
+ assets = sSystemApkAssets;
+ }
+
+ mObject = nativeCreate();
+ if (DEBUG_REFS) {
+ mNumRefs = 0;
+ incRefsLocked(hashCode());
+ }
+
+ // Always set the framework resources.
+ setApkAssets(assets, false /*invalidateCaches*/);
+ }
+
+ /**
+ * Private constructor that doesn't call ensureSystemAssets.
+ * Used for the creation of system assets.
+ */
+ @SuppressWarnings("unused")
+ private AssetManager(boolean sentinel) {
+ mObject = nativeCreate();
+ if (DEBUG_REFS) {
+ mNumRefs = 0;
+ incRefsLocked(hashCode());
}
}
- private static void ensureSystemAssets() {
- synchronized (sSync) {
- if (sSystem == null) {
- AssetManager system = new AssetManager(true);
- system.makeStringBlocks(null);
- sSystem = system;
- }
+ /**
+ * This must be called from Zygote so that system assets are shared by all applications.
+ */
+ @GuardedBy("sSync")
+ private static void createSystemAssetsInZygoteLocked() {
+ if (sSystem != null) {
+ return;
+ }
+
+ // Make sure that all IDMAPs are up to date.
+ nativeVerifySystemIdmaps();
+
+ try {
+ final ArrayList<ApkAssets> apkAssets = new ArrayList<>();
+ apkAssets.add(ApkAssets.loadFromPath(FRAMEWORK_APK_PATH, true /*system*/));
+ loadStaticRuntimeOverlays(apkAssets);
+
+ sSystemApkAssetsSet = new ArraySet<>(apkAssets);
+ sSystemApkAssets = apkAssets.toArray(new ApkAssets[apkAssets.size()]);
+ sSystem = new AssetManager(true /*sentinel*/);
+ sSystem.setApkAssets(sSystemApkAssets, false /*invalidateCaches*/);
+ } catch (IOException e) {
+ throw new IllegalStateException("Failed to create system AssetManager", e);
}
}
-
- private AssetManager(boolean isSystem) {
- if (DEBUG_REFS) {
- synchronized (this) {
- mNumRefs = 0;
- incRefsLocked(this.hashCode());
- }
+
+ /**
+ * Loads the static runtime overlays declared in /data/resource-cache/overlays.list.
+ * Throws an exception if the file is corrupt or if loading the APKs referenced by the file
+ * fails. Returns quietly if the overlays.list file doesn't exist.
+ * @param outApkAssets The list to fill with the loaded ApkAssets.
+ */
+ private static void loadStaticRuntimeOverlays(ArrayList<ApkAssets> outApkAssets)
+ throws IOException {
+ final FileInputStream fis;
+ try {
+ fis = new FileInputStream("/data/resource-cache/overlays.list");
+ } catch (FileNotFoundException e) {
+ // We might not have any overlays, this is fine. We catch here since ApkAssets
+ // loading can also fail with the same exception, which we would want to propagate.
+ Log.i(TAG, "no overlays.list file found");
+ return;
}
- init(true);
- if (localLOGV) Log.v(TAG, "New asset manager: " + this);
+
+ try {
+ // Acquire a lock so that any idmap scanning doesn't impact the current set.
+ // The order of this try-with-resources block matters. We must release the lock, and
+ // then close the file streams when exiting the block.
+ try (final BufferedReader br = new BufferedReader(new InputStreamReader(fis));
+ final FileLock flock = fis.getChannel().lock(0, Long.MAX_VALUE, true /*shared*/)) {
+ for (String line; (line = br.readLine()) != null; ) {
+ final String idmapPath = line.split(" ")[1];
+ outApkAssets.add(ApkAssets.loadOverlayFromPath(idmapPath, true /*system*/));
+ }
+ }
+ } finally {
+ // When BufferedReader is closed above, FileInputStream is closed as well. But let's be
+ // paranoid.
+ IoUtils.closeQuietly(fis);
+ }
}
/**
* Return a global shared asset manager that provides access to only
* system assets (no application assets).
- * {@hide}
+ * @hide
*/
public static AssetManager getSystem() {
- ensureSystemAssets();
- return sSystem;
+ synchronized (sSync) {
+ createSystemAssetsInZygoteLocked();
+ return sSystem;
+ }
}
/**
* Close this asset manager.
*/
+ @Override
public void close() {
- synchronized(this) {
- //System.out.println("Release: num=" + mNumRefs
- // + ", released=" + mReleased);
+ synchronized (this) {
+ if (!mOpen) {
+ return;
+ }
+
+ mOpen = false;
+ decRefsLocked(hashCode());
+ }
+ }
+
+ /**
+ * Changes the asset paths in this AssetManager. This replaces the {@link #addAssetPath(String)}
+ * family of methods.
+ *
+ * @param apkAssets The new set of paths.
+ * @param invalidateCaches Whether to invalidate any caches. This should almost always be true.
+ * Set this to false if you are appending new resources
+ * (not new configurations).
+ * @hide
+ */
+ public void setApkAssets(@NonNull ApkAssets[] apkAssets, boolean invalidateCaches) {
+ Preconditions.checkNotNull(apkAssets, "apkAssets");
+
+ ApkAssets[] newApkAssets = new ApkAssets[sSystemApkAssets.length + apkAssets.length];
+
+ // Copy the system assets first.
+ System.arraycopy(sSystemApkAssets, 0, newApkAssets, 0, sSystemApkAssets.length);
+
+ // Copy the given ApkAssets if they are not already in the system list.
+ int newLength = sSystemApkAssets.length;
+ for (ApkAssets apkAsset : apkAssets) {
+ if (!sSystemApkAssetsSet.contains(apkAsset)) {
+ newApkAssets[newLength++] = apkAsset;
+ }
+ }
+
+ // Truncate if necessary.
+ if (newLength != newApkAssets.length) {
+ newApkAssets = Arrays.copyOf(newApkAssets, newLength);
+ }
+
+ synchronized (this) {
+ ensureOpenLocked();
+ mApkAssets = newApkAssets;
+ nativeSetApkAssets(mObject, mApkAssets, invalidateCaches);
+ if (invalidateCaches) {
+ // Invalidate all caches.
+ invalidateCachesLocked(-1);
+ }
+ }
+ }
+
+ /**
+ * Invalidates the caches in this AssetManager according to the bitmask `diff`.
+ *
+ * @param diff The bitmask of changes generated by {@link Configuration#diff(Configuration)}.
+ * @see ActivityInfo.Config
+ */
+ private void invalidateCachesLocked(int diff) {
+ // TODO(adamlesinski): Currently there are no caches to invalidate in Java code.
+ }
+
+ /**
+ * Returns the set of ApkAssets loaded by this AssetManager. If the AssetManager is closed, this
+ * returns a 0-length array.
+ * @hide
+ */
+ public @NonNull ApkAssets[] getApkAssets() {
+ synchronized (this) {
if (mOpen) {
- mOpen = false;
- decRefsLocked(this.hashCode());
+ return mApkAssets;
}
}
+ return sEmptyApkAssets;
}
/**
- * Retrieves the string value associated with a particular resource
- * identifier for the current configuration.
- *
- * @param resId the resource identifier to load
- * @return the string value, or {@code null}
+ * Returns a cookie for use with the other APIs of AssetManager.
+ * @return 0 if the path was not found, otherwise a positive integer cookie representing
+ * this path in the AssetManager.
+ * @hide
*/
- @Nullable
- final CharSequence getResourceText(@StringRes int resId) {
+ public int findCookieForPath(@NonNull String path) {
+ Preconditions.checkNotNull(path, "path");
synchronized (this) {
- final TypedValue outValue = mValue;
- if (getResourceValue(resId, 0, outValue, true)) {
- return outValue.coerceToString();
+ ensureValidLocked();
+ final int count = mApkAssets.length;
+ for (int i = 0; i < count; i++) {
+ if (path.equals(mApkAssets[i].getAssetPath())) {
+ return i + 1;
+ }
}
- return null;
}
+ return 0;
}
/**
- * Retrieves the string value associated with a particular resource
- * identifier for the current configuration.
- *
- * @param resId the resource identifier to load
- * @param bagEntryId
- * @return the string value, or {@code null}
+ * @deprecated Use {@link #setApkAssets(ApkAssets[], boolean)}
+ * @hide
*/
- @Nullable
- final CharSequence getResourceBagText(@StringRes int resId, int bagEntryId) {
+ @Deprecated
+ public int addAssetPath(String path) {
+ return addAssetPathInternal(path, false /*overlay*/, false /*appAsLib*/);
+ }
+
+ /**
+ * @deprecated Use {@link #setApkAssets(ApkAssets[], boolean)}
+ * @hide
+ */
+ @Deprecated
+ public int addAssetPathAsSharedLibrary(String path) {
+ return addAssetPathInternal(path, false /*overlay*/, true /*appAsLib*/);
+ }
+
+ /**
+ * @deprecated Use {@link #setApkAssets(ApkAssets[], boolean)}
+ * @hide
+ */
+ @Deprecated
+ public int addOverlayPath(String path) {
+ return addAssetPathInternal(path, true /*overlay*/, false /*appAsLib*/);
+ }
+
+ private int addAssetPathInternal(String path, boolean overlay, boolean appAsLib) {
+ Preconditions.checkNotNull(path, "path");
synchronized (this) {
- final TypedValue outValue = mValue;
- final int block = loadResourceBagValue(resId, bagEntryId, outValue, true);
- if (block < 0) {
- return null;
+ ensureOpenLocked();
+ final int count = mApkAssets.length;
+
+ // See if we already have it loaded.
+ for (int i = 0; i < count; i++) {
+ if (mApkAssets[i].getAssetPath().equals(path)) {
+ return i + 1;
+ }
}
- // Convert the changing configurations flags populated by native code.
- outValue.changingConfigurations = ActivityInfo.activityInfoConfigNativeToJava(
- outValue.changingConfigurations);
-
- if (outValue.type == TypedValue.TYPE_STRING) {
- return mStringBlocks[block].get(outValue.data);
+ final ApkAssets assets;
+ try {
+ if (overlay) {
+ // TODO(b/70343104): This hardcoded path will be removed once
+ // addAssetPathInternal is deleted.
+ final String idmapPath = "/data/resource-cache/"
+ + path.substring(1).replace('/', '@')
+ + "@idmap";
+ assets = ApkAssets.loadOverlayFromPath(idmapPath, false /*system*/);
+ } else {
+ assets = ApkAssets.loadFromPath(path, false /*system*/, appAsLib);
+ }
+ } catch (IOException e) {
+ return 0;
}
- return outValue.coerceToString();
+
+ mApkAssets = Arrays.copyOf(mApkAssets, count + 1);
+ mApkAssets[count] = assets;
+ nativeSetApkAssets(mObject, mApkAssets, true);
+ invalidateCachesLocked(-1);
+ return count + 1;
}
}
/**
- * Retrieves the string array associated with a particular resource
- * identifier for the current configuration.
- *
- * @param resId the resource identifier of the string array
- * @return the string array, or {@code null}
+ * Ensures that the native implementation has not been destroyed.
+ * The AssetManager may have been closed, but references to it still exist
+ * and therefore the native implementation is not destroyed.
*/
- @Nullable
- final String[] getResourceStringArray(@ArrayRes int resId) {
- return getArrayStringResource(resId);
+ @GuardedBy("this")
+ private void ensureValidLocked() {
+ if (mObject == 0) {
+ throw new RuntimeException("AssetManager has been destroyed");
+ }
+ }
+
+ /**
+ * Ensures that the AssetManager has not been explicitly closed. If this method passes,
+ * then this implies that ensureValidLocked() also passes.
+ */
+ @GuardedBy("this")
+ private void ensureOpenLocked() {
+ // If mOpen is true, this implies that mObject != 0.
+ if (!mOpen) {
+ throw new RuntimeException("AssetManager has been closed");
+ }
}
/**
@@ -221,11 +457,14 @@
* @return {@code true} if the data was loaded into {@code outValue},
* {@code false} otherwise
*/
- final boolean getResourceValue(@AnyRes int resId, int densityDpi, @NonNull TypedValue outValue,
+ boolean getResourceValue(@AnyRes int resId, int densityDpi, @NonNull TypedValue outValue,
boolean resolveRefs) {
+ Preconditions.checkNotNull(outValue, "outValue");
synchronized (this) {
- final int block = loadResourceValue(resId, (short) densityDpi, outValue, resolveRefs);
- if (block < 0) {
+ ensureValidLocked();
+ final int cookie = nativeGetResourceValue(
+ mObject, resId, (short) densityDpi, outValue, resolveRefs);
+ if (cookie <= 0) {
return false;
}
@@ -234,38 +473,156 @@
outValue.changingConfigurations);
if (outValue.type == TypedValue.TYPE_STRING) {
- outValue.string = mStringBlocks[block].get(outValue.data);
+ outValue.string = mApkAssets[cookie - 1].getStringFromPool(outValue.data);
}
return true;
}
}
/**
+ * Retrieves the string value associated with a particular resource
+ * identifier for the current configuration.
+ *
+ * @param resId the resource identifier to load
+ * @return the string value, or {@code null}
+ */
+ @Nullable CharSequence getResourceText(@StringRes int resId) {
+ synchronized (this) {
+ final TypedValue outValue = mValue;
+ if (getResourceValue(resId, 0, outValue, true)) {
+ return outValue.coerceToString();
+ }
+ return null;
+ }
+ }
+
+ /**
+ * Retrieves the string value associated with a particular resource
+ * identifier for the current configuration.
+ *
+ * @param resId the resource identifier to load
+ * @param bagEntryId the index into the bag to load
+ * @return the string value, or {@code null}
+ */
+ @Nullable CharSequence getResourceBagText(@StringRes int resId, int bagEntryId) {
+ synchronized (this) {
+ ensureValidLocked();
+ final TypedValue outValue = mValue;
+ final int cookie = nativeGetResourceBagValue(mObject, resId, bagEntryId, outValue);
+ if (cookie <= 0) {
+ return null;
+ }
+
+ // Convert the changing configurations flags populated by native code.
+ outValue.changingConfigurations = ActivityInfo.activityInfoConfigNativeToJava(
+ outValue.changingConfigurations);
+
+ if (outValue.type == TypedValue.TYPE_STRING) {
+ return mApkAssets[cookie - 1].getStringFromPool(outValue.data);
+ }
+ return outValue.coerceToString();
+ }
+ }
+
+ int getResourceArraySize(@ArrayRes int resId) {
+ synchronized (this) {
+ ensureValidLocked();
+ return nativeGetResourceArraySize(mObject, resId);
+ }
+ }
+
+ /**
+ * Populates `outData` with array elements of `resId`. `outData` is normally
+ * used with
+ * {@link TypedArray}.
+ *
+ * Each logical element in `outData` is {@link TypedArray#STYLE_NUM_ENTRIES}
+ * long,
+ * with the indices of the data representing the type, value, asset cookie,
+ * resource ID,
+ * configuration change mask, and density of the element.
+ *
+ * @param resId The resource ID of an array resource.
+ * @param outData The array to populate with data.
+ * @return The length of the array.
+ *
+ * @see TypedArray#STYLE_TYPE
+ * @see TypedArray#STYLE_DATA
+ * @see TypedArray#STYLE_ASSET_COOKIE
+ * @see TypedArray#STYLE_RESOURCE_ID
+ * @see TypedArray#STYLE_CHANGING_CONFIGURATIONS
+ * @see TypedArray#STYLE_DENSITY
+ */
+ int getResourceArray(@ArrayRes int resId, @NonNull int[] outData) {
+ Preconditions.checkNotNull(outData, "outData");
+ synchronized (this) {
+ ensureValidLocked();
+ return nativeGetResourceArray(mObject, resId, outData);
+ }
+ }
+
+ /**
+ * Retrieves the string array associated with a particular resource
+ * identifier for the current configuration.
+ *
+ * @param resId the resource identifier of the string array
+ * @return the string array, or {@code null}
+ */
+ @Nullable String[] getResourceStringArray(@ArrayRes int resId) {
+ synchronized (this) {
+ ensureValidLocked();
+ return nativeGetResourceStringArray(mObject, resId);
+ }
+ }
+
+ /**
* Retrieve the text array associated with a particular resource
* identifier.
*
* @param resId the resource id of the string array
*/
- final @Nullable CharSequence[] getResourceTextArray(@ArrayRes int resId) {
+ @Nullable CharSequence[] getResourceTextArray(@ArrayRes int resId) {
synchronized (this) {
- final int[] rawInfoArray = getArrayStringInfo(resId);
+ ensureValidLocked();
+ final int[] rawInfoArray = nativeGetResourceStringArrayInfo(mObject, resId);
if (rawInfoArray == null) {
return null;
}
+
final int rawInfoArrayLen = rawInfoArray.length;
final int infoArrayLen = rawInfoArrayLen / 2;
- int block;
- int index;
final CharSequence[] retArray = new CharSequence[infoArrayLen];
for (int i = 0, j = 0; i < rawInfoArrayLen; i = i + 2, j++) {
- block = rawInfoArray[i];
- index = rawInfoArray[i + 1];
- retArray[j] = index >= 0 ? mStringBlocks[block].get(index) : null;
+ int cookie = rawInfoArray[i];
+ int index = rawInfoArray[i + 1];
+ retArray[j] = (index >= 0 && cookie > 0)
+ ? mApkAssets[cookie - 1].getStringFromPool(index) : null;
}
return retArray;
}
}
+ @Nullable int[] getResourceIntArray(@ArrayRes int resId) {
+ synchronized (this) {
+ ensureValidLocked();
+ return nativeGetResourceIntArray(mObject, resId);
+ }
+ }
+
+ /**
+ * Get the attributes for a style resource. These are the <item>
+ * elements in
+ * a <style> resource.
+ * @param resId The resource ID of the style
+ * @return An array of attribute IDs.
+ */
+ @AttrRes int[] getStyleAttributes(@StyleRes int resId) {
+ synchronized (this) {
+ ensureValidLocked();
+ return nativeGetStyleAttributes(mObject, resId);
+ }
+ }
+
/**
* Populates {@code outValue} with the data associated with a particular
* resource identifier for the current configuration. Resolves theme
@@ -279,73 +636,88 @@
* @return {@code true} if the data was loaded into {@code outValue},
* {@code false} otherwise
*/
- final boolean getThemeValue(long theme, @AnyRes int resId, @NonNull TypedValue outValue,
+ boolean getThemeValue(long theme, @AnyRes int resId, @NonNull TypedValue outValue,
boolean resolveRefs) {
- final int block = loadThemeAttributeValue(theme, resId, outValue, resolveRefs);
- if (block < 0) {
- return false;
- }
-
- // Convert the changing configurations flags populated by native code.
- outValue.changingConfigurations = ActivityInfo.activityInfoConfigNativeToJava(
- outValue.changingConfigurations);
-
- if (outValue.type == TypedValue.TYPE_STRING) {
- final StringBlock[] blocks = ensureStringBlocks();
- outValue.string = blocks[block].get(outValue.data);
- }
- return true;
- }
-
- /**
- * Ensures the string blocks are loaded.
- *
- * @return the string blocks
- */
- @NonNull
- final StringBlock[] ensureStringBlocks() {
+ Preconditions.checkNotNull(outValue, "outValue");
synchronized (this) {
- if (mStringBlocks == null) {
- makeStringBlocks(sSystem.mStringBlocks);
+ ensureValidLocked();
+ final int cookie = nativeThemeGetAttributeValue(mObject, theme, resId, outValue,
+ resolveRefs);
+ if (cookie <= 0) {
+ return false;
}
- return mStringBlocks;
+
+ // Convert the changing configurations flags populated by native code.
+ outValue.changingConfigurations = ActivityInfo.activityInfoConfigNativeToJava(
+ outValue.changingConfigurations);
+
+ if (outValue.type == TypedValue.TYPE_STRING) {
+ outValue.string = mApkAssets[cookie - 1].getStringFromPool(outValue.data);
+ }
+ return true;
}
}
- /*package*/ final void makeStringBlocks(StringBlock[] seed) {
- final int seedNum = (seed != null) ? seed.length : 0;
- final int num = getStringBlockCount();
- mStringBlocks = new StringBlock[num];
- if (localLOGV) Log.v(TAG, "Making string blocks for " + this
- + ": " + num);
- for (int i=0; i<num; i++) {
- if (i < seedNum) {
- mStringBlocks[i] = seed[i];
- } else {
- mStringBlocks[i] = new StringBlock(getNativeStringBlock(i), true);
- }
- }
- }
-
- /*package*/ final CharSequence getPooledStringForCookie(int cookie, int id) {
+ void dumpTheme(long theme, int priority, String tag, String prefix) {
synchronized (this) {
- // Cookies map to string blocks starting at 1.
- return mStringBlocks[cookie - 1].get(id);
+ ensureValidLocked();
+ nativeThemeDump(mObject, theme, priority, tag, prefix);
}
}
+ @Nullable String getResourceName(@AnyRes int resId) {
+ synchronized (this) {
+ ensureValidLocked();
+ return nativeGetResourceName(mObject, resId);
+ }
+ }
+
+ @Nullable String getResourcePackageName(@AnyRes int resId) {
+ synchronized (this) {
+ ensureValidLocked();
+ return nativeGetResourcePackageName(mObject, resId);
+ }
+ }
+
+ @Nullable String getResourceTypeName(@AnyRes int resId) {
+ synchronized (this) {
+ ensureValidLocked();
+ return nativeGetResourceTypeName(mObject, resId);
+ }
+ }
+
+ @Nullable String getResourceEntryName(@AnyRes int resId) {
+ synchronized (this) {
+ ensureValidLocked();
+ return nativeGetResourceEntryName(mObject, resId);
+ }
+ }
+
+ @AnyRes int getResourceIdentifier(@NonNull String name, @Nullable String defType,
+ @Nullable String defPackage) {
+ synchronized (this) {
+ ensureValidLocked();
+ // name is checked in JNI.
+ return nativeGetResourceIdentifier(mObject, name, defType, defPackage);
+ }
+ }
+
+ CharSequence getPooledStringForCookie(int cookie, int id) {
+ // Cookies map to ApkAssets starting at 1.
+ return getApkAssets()[cookie - 1].getStringFromPool(id);
+ }
+
/**
* Open an asset using ACCESS_STREAMING mode. This provides access to
* files that have been bundled with an application as assets -- that is,
* files placed in to the "assets" directory.
*
- * @param fileName The name of the asset to open. This name can be
- * hierarchical.
+ * @param fileName The name of the asset to open. This name can be hierarchical.
*
* @see #open(String, int)
* @see #list
*/
- public final InputStream open(String fileName) throws IOException {
+ public @NonNull InputStream open(@NonNull String fileName) throws IOException {
return open(fileName, ACCESS_STREAMING);
}
@@ -355,8 +727,7 @@
* with an application as assets -- that is, files placed in to the
* "assets" directory.
*
- * @param fileName The name of the asset to open. This name can be
- * hierarchical.
+ * @param fileName The name of the asset to open. This name can be hierarchical.
* @param accessMode Desired access mode for retrieving the data.
*
* @see #ACCESS_UNKNOWN
@@ -366,34 +737,40 @@
* @see #open(String)
* @see #list
*/
- public final InputStream open(String fileName, int accessMode)
- throws IOException {
+ public @NonNull InputStream open(@NonNull String fileName, int accessMode) throws IOException {
+ Preconditions.checkNotNull(fileName, "fileName");
synchronized (this) {
- if (!mOpen) {
- throw new RuntimeException("Assetmanager has been closed");
+ ensureOpenLocked();
+ final long asset = nativeOpenAsset(mObject, fileName, accessMode);
+ if (asset == 0) {
+ throw new FileNotFoundException("Asset file: " + fileName);
}
- long asset = openAsset(fileName, accessMode);
- if (asset != 0) {
- AssetInputStream res = new AssetInputStream(asset);
- incRefsLocked(res.hashCode());
- return res;
- }
+ final AssetInputStream assetInputStream = new AssetInputStream(asset);
+ incRefsLocked(assetInputStream.hashCode());
+ return assetInputStream;
}
- throw new FileNotFoundException("Asset file: " + fileName);
}
- public final AssetFileDescriptor openFd(String fileName)
- throws IOException {
+ /**
+ * Open an uncompressed asset by mmapping it and returning an {@link AssetFileDescriptor}.
+ * This provides access to files that have been bundled with an application as assets -- that
+ * is, files placed in to the "assets" directory.
+ *
+ * The asset must be uncompressed, or an exception will be thrown.
+ *
+ * @param fileName The name of the asset to open. This name can be hierarchical.
+ * @return An open AssetFileDescriptor.
+ */
+ public @NonNull AssetFileDescriptor openFd(@NonNull String fileName) throws IOException {
+ Preconditions.checkNotNull(fileName, "fileName");
synchronized (this) {
- if (!mOpen) {
- throw new RuntimeException("Assetmanager has been closed");
+ ensureOpenLocked();
+ final ParcelFileDescriptor pfd = nativeOpenAssetFd(mObject, fileName, mOffsets);
+ if (pfd == null) {
+ throw new FileNotFoundException("Asset file: " + fileName);
}
- ParcelFileDescriptor pfd = openAssetFd(fileName, mOffsets);
- if (pfd != null) {
- return new AssetFileDescriptor(pfd, mOffsets[0], mOffsets[1]);
- }
+ return new AssetFileDescriptor(pfd, mOffsets[0], mOffsets[1]);
}
- throw new FileNotFoundException("Asset file: " + fileName);
}
/**
@@ -408,90 +785,121 @@
*
* @see #open
*/
- public native final String[] list(String path)
- throws IOException;
+ public @Nullable String[] list(@NonNull String path) throws IOException {
+ Preconditions.checkNotNull(path, "path");
+ synchronized (this) {
+ ensureValidLocked();
+ return nativeList(mObject, path);
+ }
+ }
/**
- * {@hide}
* Open a non-asset file as an asset using ACCESS_STREAMING mode. This
* provides direct access to all of the files included in an application
* package (not only its assets). Applications should not normally use
* this.
- *
+ *
+ * @param fileName Name of the asset to retrieve.
+ *
* @see #open(String)
+ * @hide
*/
- public final InputStream openNonAsset(String fileName) throws IOException {
+ public @NonNull InputStream openNonAsset(@NonNull String fileName) throws IOException {
return openNonAsset(0, fileName, ACCESS_STREAMING);
}
/**
- * {@hide}
* Open a non-asset file as an asset using a specific access mode. This
* provides direct access to all of the files included in an application
* package (not only its assets). Applications should not normally use
* this.
- *
+ *
+ * @param fileName Name of the asset to retrieve.
+ * @param accessMode Desired access mode for retrieving the data.
+ *
+ * @see #ACCESS_UNKNOWN
+ * @see #ACCESS_STREAMING
+ * @see #ACCESS_RANDOM
+ * @see #ACCESS_BUFFER
* @see #open(String, int)
+ * @hide
*/
- public final InputStream openNonAsset(String fileName, int accessMode)
- throws IOException {
+ public @NonNull InputStream openNonAsset(@NonNull String fileName, int accessMode)
+ throws IOException {
return openNonAsset(0, fileName, accessMode);
}
/**
- * {@hide}
* Open a non-asset in a specified package. Not for use by applications.
- *
+ *
* @param cookie Identifier of the package to be opened.
* @param fileName Name of the asset to retrieve.
+ * @hide
*/
- public final InputStream openNonAsset(int cookie, String fileName)
- throws IOException {
+ public @NonNull InputStream openNonAsset(int cookie, @NonNull String fileName)
+ throws IOException {
return openNonAsset(cookie, fileName, ACCESS_STREAMING);
}
/**
- * {@hide}
* Open a non-asset in a specified package. Not for use by applications.
- *
+ *
* @param cookie Identifier of the package to be opened.
* @param fileName Name of the asset to retrieve.
* @param accessMode Desired access mode for retrieving the data.
+ * @hide
*/
- public final InputStream openNonAsset(int cookie, String fileName, int accessMode)
- throws IOException {
+ public @NonNull InputStream openNonAsset(int cookie, @NonNull String fileName, int accessMode)
+ throws IOException {
+ Preconditions.checkNotNull(fileName, "fileName");
synchronized (this) {
- if (!mOpen) {
- throw new RuntimeException("Assetmanager has been closed");
+ ensureOpenLocked();
+ final long asset = nativeOpenNonAsset(mObject, cookie, fileName, accessMode);
+ if (asset == 0) {
+ throw new FileNotFoundException("Asset absolute file: " + fileName);
}
- long asset = openNonAssetNative(cookie, fileName, accessMode);
- if (asset != 0) {
- AssetInputStream res = new AssetInputStream(asset);
- incRefsLocked(res.hashCode());
- return res;
- }
+ final AssetInputStream assetInputStream = new AssetInputStream(asset);
+ incRefsLocked(assetInputStream.hashCode());
+ return assetInputStream;
}
- throw new FileNotFoundException("Asset absolute file: " + fileName);
}
- public final AssetFileDescriptor openNonAssetFd(String fileName)
+ /**
+ * Open a non-asset as an asset by mmapping it and returning an {@link AssetFileDescriptor}.
+ * This provides direct access to all of the files included in an application
+ * package (not only its assets). Applications should not normally use this.
+ *
+ * The asset must not be compressed, or an exception will be thrown.
+ *
+ * @param fileName Name of the asset to retrieve.
+ */
+ public @NonNull AssetFileDescriptor openNonAssetFd(@NonNull String fileName)
throws IOException {
return openNonAssetFd(0, fileName);
}
-
- public final AssetFileDescriptor openNonAssetFd(int cookie,
- String fileName) throws IOException {
+
+ /**
+ * Open a non-asset as an asset by mmapping it and returning an {@link AssetFileDescriptor}.
+ * This provides direct access to all of the files included in an application
+ * package (not only its assets). Applications should not normally use this.
+ *
+ * The asset must not be compressed, or an exception will be thrown.
+ *
+ * @param cookie Identifier of the package to be opened.
+ * @param fileName Name of the asset to retrieve.
+ */
+ public @NonNull AssetFileDescriptor openNonAssetFd(int cookie, @NonNull String fileName)
+ throws IOException {
+ Preconditions.checkNotNull(fileName, "fileName");
synchronized (this) {
- if (!mOpen) {
- throw new RuntimeException("Assetmanager has been closed");
+ ensureOpenLocked();
+ final ParcelFileDescriptor pfd =
+ nativeOpenNonAssetFd(mObject, cookie, fileName, mOffsets);
+ if (pfd == null) {
+ throw new FileNotFoundException("Asset absolute file: " + fileName);
}
- ParcelFileDescriptor pfd = openNonAssetFdNative(cookie,
- fileName, mOffsets);
- if (pfd != null) {
- return new AssetFileDescriptor(pfd, mOffsets[0], mOffsets[1]);
- }
+ return new AssetFileDescriptor(pfd, mOffsets[0], mOffsets[1]);
}
- throw new FileNotFoundException("Asset absolute file: " + fileName);
}
/**
@@ -499,7 +907,7 @@
*
* @param fileName The name of the file to retrieve.
*/
- public final XmlResourceParser openXmlResourceParser(String fileName)
+ public @NonNull XmlResourceParser openXmlResourceParser(@NonNull String fileName)
throws IOException {
return openXmlResourceParser(0, fileName);
}
@@ -510,270 +918,265 @@
* @param cookie Identifier of the package to be opened.
* @param fileName The name of the file to retrieve.
*/
- public final XmlResourceParser openXmlResourceParser(int cookie,
- String fileName) throws IOException {
- XmlBlock block = openXmlBlockAsset(cookie, fileName);
- XmlResourceParser rp = block.newParser();
- block.close();
- return rp;
+ public @NonNull XmlResourceParser openXmlResourceParser(int cookie, @NonNull String fileName)
+ throws IOException {
+ try (XmlBlock block = openXmlBlockAsset(cookie, fileName)) {
+ XmlResourceParser parser = block.newParser();
+ // If openXmlBlockAsset doesn't throw, it will always return an XmlBlock object with
+ // a valid native pointer, which makes newParser always return non-null. But let's
+ // be paranoid.
+ if (parser == null) {
+ throw new AssertionError("block.newParser() returned a null parser");
+ }
+ return parser;
+ }
}
/**
- * {@hide}
- * Retrieve a non-asset as a compiled XML file. Not for use by
- * applications.
+ * Retrieve a non-asset as a compiled XML file. Not for use by applications.
*
* @param fileName The name of the file to retrieve.
+ * @hide
*/
- /*package*/ final XmlBlock openXmlBlockAsset(String fileName)
- throws IOException {
+ @NonNull XmlBlock openXmlBlockAsset(@NonNull String fileName) throws IOException {
return openXmlBlockAsset(0, fileName);
}
/**
- * {@hide}
* Retrieve a non-asset as a compiled XML file. Not for use by
* applications.
*
* @param cookie Identifier of the package to be opened.
* @param fileName Name of the asset to retrieve.
+ * @hide
*/
- /*package*/ final XmlBlock openXmlBlockAsset(int cookie, String fileName)
- throws IOException {
+ @NonNull XmlBlock openXmlBlockAsset(int cookie, @NonNull String fileName) throws IOException {
+ Preconditions.checkNotNull(fileName, "fileName");
synchronized (this) {
- if (!mOpen) {
- throw new RuntimeException("Assetmanager has been closed");
+ ensureOpenLocked();
+ final long xmlBlock = nativeOpenXmlAsset(mObject, cookie, fileName);
+ if (xmlBlock == 0) {
+ throw new FileNotFoundException("Asset XML file: " + fileName);
}
- long xmlBlock = openXmlAssetNative(cookie, fileName);
- if (xmlBlock != 0) {
- XmlBlock res = new XmlBlock(this, xmlBlock);
- incRefsLocked(res.hashCode());
- return res;
- }
+ final XmlBlock block = new XmlBlock(this, xmlBlock);
+ incRefsLocked(block.hashCode());
+ return block;
}
- throw new FileNotFoundException("Asset XML file: " + fileName);
}
- /*package*/ void xmlBlockGone(int id) {
+ void xmlBlockGone(int id) {
synchronized (this) {
decRefsLocked(id);
}
}
- /*package*/ final long createTheme() {
+ void applyStyle(long themePtr, @AttrRes int defStyleAttr, @StyleRes int defStyleRes,
+ @Nullable XmlBlock.Parser parser, @NonNull int[] inAttrs, long outValuesAddress,
+ long outIndicesAddress) {
+ Preconditions.checkNotNull(inAttrs, "inAttrs");
synchronized (this) {
- if (!mOpen) {
- throw new RuntimeException("Assetmanager has been closed");
- }
- long res = newTheme();
- incRefsLocked(res);
- return res;
+ // Need to synchronize on AssetManager because we will be accessing
+ // the native implementation of AssetManager.
+ ensureValidLocked();
+ nativeApplyStyle(mObject, themePtr, defStyleAttr, defStyleRes,
+ parser != null ? parser.mParseState : 0, inAttrs, outValuesAddress,
+ outIndicesAddress);
}
}
- /*package*/ final void releaseTheme(long theme) {
+ boolean resolveAttrs(long themePtr, @AttrRes int defStyleAttr, @StyleRes int defStyleRes,
+ @Nullable int[] inValues, @NonNull int[] inAttrs, @NonNull int[] outValues,
+ @NonNull int[] outIndices) {
+ Preconditions.checkNotNull(inAttrs, "inAttrs");
+ Preconditions.checkNotNull(outValues, "outValues");
+ Preconditions.checkNotNull(outIndices, "outIndices");
synchronized (this) {
- deleteTheme(theme);
- decRefsLocked(theme);
+ // Need to synchronize on AssetManager because we will be accessing
+ // the native implementation of AssetManager.
+ ensureValidLocked();
+ return nativeResolveAttrs(mObject,
+ themePtr, defStyleAttr, defStyleRes, inValues, inAttrs, outValues, outIndices);
}
}
+ boolean retrieveAttributes(@NonNull XmlBlock.Parser parser, @NonNull int[] inAttrs,
+ @NonNull int[] outValues, @NonNull int[] outIndices) {
+ Preconditions.checkNotNull(parser, "parser");
+ Preconditions.checkNotNull(inAttrs, "inAttrs");
+ Preconditions.checkNotNull(outValues, "outValues");
+ Preconditions.checkNotNull(outIndices, "outIndices");
+ synchronized (this) {
+ // Need to synchronize on AssetManager because we will be accessing
+ // the native implementation of AssetManager.
+ ensureValidLocked();
+ return nativeRetrieveAttributes(
+ mObject, parser.mParseState, inAttrs, outValues, outIndices);
+ }
+ }
+
+ long createTheme() {
+ synchronized (this) {
+ ensureValidLocked();
+ long themePtr = nativeThemeCreate(mObject);
+ incRefsLocked(themePtr);
+ return themePtr;
+ }
+ }
+
+ void releaseTheme(long themePtr) {
+ synchronized (this) {
+ nativeThemeDestroy(themePtr);
+ decRefsLocked(themePtr);
+ }
+ }
+
+ void applyStyleToTheme(long themePtr, @StyleRes int resId, boolean force) {
+ synchronized (this) {
+ // Need to synchronize on AssetManager because we will be accessing
+ // the native implementation of AssetManager.
+ ensureValidLocked();
+ nativeThemeApplyStyle(mObject, themePtr, resId, force);
+ }
+ }
+
+ @Override
protected void finalize() throws Throwable {
- try {
- if (DEBUG_REFS && mNumRefs != 0) {
- Log.w(TAG, "AssetManager " + this
- + " finalized with non-zero refs: " + mNumRefs);
- if (mRefStacks != null) {
- for (RuntimeException e : mRefStacks.values()) {
- Log.w(TAG, "Reference from here", e);
- }
+ if (DEBUG_REFS && mNumRefs != 0) {
+ Log.w(TAG, "AssetManager " + this + " finalized with non-zero refs: " + mNumRefs);
+ if (mRefStacks != null) {
+ for (RuntimeException e : mRefStacks.values()) {
+ Log.w(TAG, "Reference from here", e);
}
}
- destroy();
- } finally {
- super.finalize();
+ }
+
+ if (mObject != 0) {
+ nativeDestroy(mObject);
}
}
-
+
+ /* No Locking is needed for AssetInputStream because an AssetInputStream is not-thread
+ safe and it does not rely on AssetManager once it has been created. It completely owns the
+ underlying Asset. */
public final class AssetInputStream extends InputStream {
+ private long mAssetNativePtr;
+ private long mLength;
+ private long mMarkPos;
+
/**
* @hide
*/
public final int getAssetInt() {
throw new UnsupportedOperationException();
}
+
/**
* @hide
*/
public final long getNativeAsset() {
- return mAsset;
+ return mAssetNativePtr;
}
- private AssetInputStream(long asset)
- {
- mAsset = asset;
- mLength = getAssetLength(asset);
+
+ private AssetInputStream(long assetNativePtr) {
+ mAssetNativePtr = assetNativePtr;
+ mLength = nativeAssetGetLength(assetNativePtr);
}
+
+ @Override
public final int read() throws IOException {
- return readAssetChar(mAsset);
+ ensureOpen();
+ return nativeAssetReadChar(mAssetNativePtr);
}
- public final boolean markSupported() {
- return true;
+
+ @Override
+ public final int read(@NonNull byte[] b) throws IOException {
+ ensureOpen();
+ Preconditions.checkNotNull(b, "b");
+ return nativeAssetRead(mAssetNativePtr, b, 0, b.length);
}
- public final int available() throws IOException {
- long len = getAssetRemainingLength(mAsset);
- return len > Integer.MAX_VALUE ? Integer.MAX_VALUE : (int)len;
+
+ @Override
+ public final int read(@NonNull byte[] b, int off, int len) throws IOException {
+ ensureOpen();
+ Preconditions.checkNotNull(b, "b");
+ return nativeAssetRead(mAssetNativePtr, b, off, len);
}
- public final void close() throws IOException {
- synchronized (AssetManager.this) {
- if (mAsset != 0) {
- destroyAsset(mAsset);
- mAsset = 0;
- decRefsLocked(hashCode());
- }
- }
- }
- public final void mark(int readlimit) {
- mMarkPos = seekAsset(mAsset, 0, 0);
- }
- public final void reset() throws IOException {
- seekAsset(mAsset, mMarkPos, -1);
- }
- public final int read(byte[] b) throws IOException {
- return readAsset(mAsset, b, 0, b.length);
- }
- public final int read(byte[] b, int off, int len) throws IOException {
- return readAsset(mAsset, b, off, len);
- }
+
+ @Override
public final long skip(long n) throws IOException {
- long pos = seekAsset(mAsset, 0, 0);
- if ((pos+n) > mLength) {
- n = mLength-pos;
+ ensureOpen();
+ long pos = nativeAssetSeek(mAssetNativePtr, 0, 0);
+ if ((pos + n) > mLength) {
+ n = mLength - pos;
}
if (n > 0) {
- seekAsset(mAsset, n, 0);
+ nativeAssetSeek(mAssetNativePtr, n, 0);
}
return n;
}
- protected void finalize() throws Throwable
- {
+ @Override
+ public final int available() throws IOException {
+ ensureOpen();
+ final long len = nativeAssetGetRemainingLength(mAssetNativePtr);
+ return len > Integer.MAX_VALUE ? Integer.MAX_VALUE : (int) len;
+ }
+
+ @Override
+ public final boolean markSupported() {
+ return true;
+ }
+
+ @Override
+ public final void mark(int readlimit) {
+ ensureOpen();
+ mMarkPos = nativeAssetSeek(mAssetNativePtr, 0, 0);
+ }
+
+ @Override
+ public final void reset() throws IOException {
+ ensureOpen();
+ nativeAssetSeek(mAssetNativePtr, mMarkPos, -1);
+ }
+
+ @Override
+ public final void close() throws IOException {
+ if (mAssetNativePtr != 0) {
+ nativeAssetDestroy(mAssetNativePtr);
+ mAssetNativePtr = 0;
+
+ synchronized (AssetManager.this) {
+ decRefsLocked(hashCode());
+ }
+ }
+ }
+
+ @Override
+ protected void finalize() throws Throwable {
close();
}
- private long mAsset;
- private long mLength;
- private long mMarkPos;
- }
-
- /**
- * Add an additional set of assets to the asset manager. This can be
- * either a directory or ZIP file. Not for use by applications. Returns
- * the cookie of the added asset, or 0 on failure.
- * {@hide}
- */
- public final int addAssetPath(String path) {
- return addAssetPathInternal(path, false);
- }
-
- /**
- * Add an application assets to the asset manager and loading it as shared library.
- * This can be either a directory or ZIP file. Not for use by applications. Returns
- * the cookie of the added asset, or 0 on failure.
- * {@hide}
- */
- public final int addAssetPathAsSharedLibrary(String path) {
- return addAssetPathInternal(path, true);
- }
-
- private final int addAssetPathInternal(String path, boolean appAsLib) {
- synchronized (this) {
- int res = addAssetPathNative(path, appAsLib);
- makeStringBlocks(mStringBlocks);
- return res;
+ private void ensureOpen() {
+ if (mAssetNativePtr == 0) {
+ throw new IllegalStateException("AssetInputStream is closed");
+ }
}
}
- private native final int addAssetPathNative(String path, boolean appAsLib);
-
- /**
- * Add an additional set of assets to the asset manager from an already open
- * FileDescriptor. Not for use by applications.
- * This does not give full AssetManager functionality for these assets,
- * since the origin of the file is not known for purposes of sharing,
- * overlay resolution, and other features. However it does allow you
- * to do simple access to the contents of the given fd as an apk file.
- * Performs a dup of the underlying fd, so you must take care of still closing
- * the FileDescriptor yourself (and can do that whenever you want).
- * Returns the cookie of the added asset, or 0 on failure.
- * {@hide}
- */
- public int addAssetFd(FileDescriptor fd, String debugPathName) {
- return addAssetFdInternal(fd, debugPathName, false);
- }
-
- private int addAssetFdInternal(FileDescriptor fd, String debugPathName,
- boolean appAsLib) {
- synchronized (this) {
- int res = addAssetFdNative(fd, debugPathName, appAsLib);
- makeStringBlocks(mStringBlocks);
- return res;
- }
- }
-
- private native int addAssetFdNative(FileDescriptor fd, String debugPathName,
- boolean appAsLib);
-
- /**
- * Add a set of assets to overlay an already added set of assets.
- *
- * This is only intended for application resources. System wide resources
- * are handled before any Java code is executed.
- *
- * {@hide}
- */
-
- public final int addOverlayPath(String idmapPath) {
- synchronized (this) {
- int res = addOverlayPathNative(idmapPath);
- makeStringBlocks(mStringBlocks);
- return res;
- }
- }
-
- /**
- * See addOverlayPath.
- *
- * {@hide}
- */
- public native final int addOverlayPathNative(String idmapPath);
-
- /**
- * Add multiple sets of assets to the asset manager at once. See
- * {@link #addAssetPath(String)} for more information. Returns array of
- * cookies for each added asset with 0 indicating failure, or null if
- * the input array of paths is null.
- * {@hide}
- */
- public final int[] addAssetPaths(String[] paths) {
- if (paths == null) {
- return null;
- }
-
- int[] cookies = new int[paths.length];
- for (int i = 0; i < paths.length; i++) {
- cookies[i] = addAssetPath(paths[i]);
- }
-
- return cookies;
- }
-
/**
* Determine whether the state in this asset manager is up-to-date with
* the files on the filesystem. If false is returned, you need to
* instantiate a new AssetManager class to see the new data.
- * {@hide}
+ * @hide
*/
- public native final boolean isUpToDate();
+ public boolean isUpToDate() {
+ for (ApkAssets apkAssets : getApkAssets()) {
+ if (!apkAssets.isUpToDate()) {
+ return false;
+ }
+ }
+ return true;
+ }
/**
* Get the locales that this asset manager contains data for.
@@ -786,7 +1189,12 @@
* are of the form {@code ll_CC} where {@code ll} is a two letter language code,
* and {@code CC} is a two letter country code.
*/
- public native final String[] getLocales();
+ public String[] getLocales() {
+ synchronized (this) {
+ ensureValidLocked();
+ return nativeGetLocales(mObject, false /*excludeSystem*/);
+ }
+ }
/**
* Same as getLocales(), except that locales that are only provided by the system (i.e. those
@@ -796,132 +1204,58 @@
* assets support Cherokee and French, getLocales() would return
* [Cherokee, English, French, German], while getNonSystemLocales() would return
* [Cherokee, French].
- * {@hide}
+ * @hide
*/
- public native final String[] getNonSystemLocales();
-
- /** {@hide} */
- public native final Configuration[] getSizeConfigurations();
+ public String[] getNonSystemLocales() {
+ synchronized (this) {
+ ensureValidLocked();
+ return nativeGetLocales(mObject, true /*excludeSystem*/);
+ }
+ }
/**
- * Change the configuation used when retrieving resources. Not for use by
+ * @hide
+ */
+ Configuration[] getSizeConfigurations() {
+ synchronized (this) {
+ ensureValidLocked();
+ return nativeGetSizeConfigurations(mObject);
+ }
+ }
+
+ /**
+ * Change the configuration used when retrieving resources. Not for use by
* applications.
- * {@hide}
+ * @hide
*/
- public native final void setConfiguration(int mcc, int mnc, String locale,
- int orientation, int touchscreen, int density, int keyboard,
- int keyboardHidden, int navigation, int screenWidth, int screenHeight,
- int smallestScreenWidthDp, int screenWidthDp, int screenHeightDp,
- int screenLayout, int uiMode, int colorMode, int majorVersion);
+ public void setConfiguration(int mcc, int mnc, @Nullable String locale, int orientation,
+ int touchscreen, int density, int keyboard, int keyboardHidden, int navigation,
+ int screenWidth, int screenHeight, int smallestScreenWidthDp, int screenWidthDp,
+ int screenHeightDp, int screenLayout, int uiMode, int colorMode, int majorVersion) {
+ synchronized (this) {
+ ensureValidLocked();
+ nativeSetConfiguration(mObject, mcc, mnc, locale, orientation, touchscreen, density,
+ keyboard, keyboardHidden, navigation, screenWidth, screenHeight,
+ smallestScreenWidthDp, screenWidthDp, screenHeightDp, screenLayout, uiMode,
+ colorMode, majorVersion);
+ }
+ }
/**
- * Retrieve the resource identifier for the given resource name.
+ * @hide
*/
- /*package*/ native final int getResourceIdentifier(String name,
- String defType,
- String defPackage);
-
- /*package*/ native final String getResourceName(int resid);
- /*package*/ native final String getResourcePackageName(int resid);
- /*package*/ native final String getResourceTypeName(int resid);
- /*package*/ native final String getResourceEntryName(int resid);
-
- private native final long openAsset(String fileName, int accessMode);
- private final native ParcelFileDescriptor openAssetFd(String fileName,
- long[] outOffsets) throws IOException;
- private native final long openNonAssetNative(int cookie, String fileName,
- int accessMode);
- private native ParcelFileDescriptor openNonAssetFdNative(int cookie,
- String fileName, long[] outOffsets) throws IOException;
- private native final void destroyAsset(long asset);
- private native final int readAssetChar(long asset);
- private native final int readAsset(long asset, byte[] b, int off, int len);
- private native final long seekAsset(long asset, long offset, int whence);
- private native final long getAssetLength(long asset);
- private native final long getAssetRemainingLength(long asset);
-
- /** Returns true if the resource was found, filling in mRetStringBlock and
- * mRetData. */
- private native final int loadResourceValue(int ident, short density, TypedValue outValue,
- boolean resolve);
- /** Returns true if the resource was found, filling in mRetStringBlock and
- * mRetData. */
- private native final int loadResourceBagValue(int ident, int bagEntryId, TypedValue outValue,
- boolean resolve);
- /*package*/ static final int STYLE_NUM_ENTRIES = 6;
- /*package*/ static final int STYLE_TYPE = 0;
- /*package*/ static final int STYLE_DATA = 1;
- /*package*/ static final int STYLE_ASSET_COOKIE = 2;
- /*package*/ static final int STYLE_RESOURCE_ID = 3;
-
- /* Offset within typed data array for native changingConfigurations. */
- static final int STYLE_CHANGING_CONFIGURATIONS = 4;
-
- /*package*/ static final int STYLE_DENSITY = 5;
- /*package*/ native static final void applyStyle(long theme,
- int defStyleAttr, int defStyleRes, long xmlParser,
- int[] inAttrs, int length, long outValuesAddress, long outIndicesAddress);
- /*package*/ native static final boolean resolveAttrs(long theme,
- int defStyleAttr, int defStyleRes, int[] inValues,
- int[] inAttrs, int[] outValues, int[] outIndices);
- /*package*/ native final boolean retrieveAttributes(
- long xmlParser, int[] inAttrs, int[] outValues, int[] outIndices);
- /*package*/ native final int getArraySize(int resource);
- /*package*/ native final int retrieveArray(int resource, int[] outValues);
- private native final int getStringBlockCount();
- private native final long getNativeStringBlock(int block);
-
- /**
- * {@hide}
- */
- public native final String getCookieName(int cookie);
-
- /**
- * {@hide}
- */
- public native final SparseArray<String> getAssignedPackageIdentifiers();
-
- /**
- * {@hide}
- */
- public native static final int getGlobalAssetCount();
-
- /**
- * {@hide}
- */
- public native static final String getAssetAllocations();
-
- /**
- * {@hide}
- */
- public native static final int getGlobalAssetManagerCount();
-
- private native final long newTheme();
- private native final void deleteTheme(long theme);
- /*package*/ native static final void applyThemeStyle(long theme, int styleRes, boolean force);
- /*package*/ native static final void copyTheme(long dest, long source);
- /*package*/ native static final void clearTheme(long theme);
- /*package*/ native static final int loadThemeAttributeValue(long theme, int ident,
- TypedValue outValue,
- boolean resolve);
- /*package*/ native static final void dumpTheme(long theme, int priority, String tag, String prefix);
- /*package*/ native static final @NativeConfig int getThemeChangingConfigurations(long theme);
-
- private native final long openXmlAssetNative(int cookie, String fileName);
-
- private native final String[] getArrayStringResource(int arrayRes);
- private native final int[] getArrayStringInfo(int arrayRes);
- /*package*/ native final int[] getArrayIntResource(int arrayRes);
- /*package*/ native final int[] getStyleAttributes(int themeRes);
-
- private native final void init(boolean isSystem);
- private native final void destroy();
+ public SparseArray<String> getAssignedPackageIdentifiers() {
+ synchronized (this) {
+ ensureValidLocked();
+ return nativeGetAssignedPackageIdentifiers(mObject);
+ }
+ }
@GuardedBy("this")
- private final void incRefsLocked(long id) {
+ private void incRefsLocked(long id) {
if (DEBUG_REFS) {
if (mRefStacks == null) {
- mRefStacks = new HashMap<Long, RuntimeException>();
+ mRefStacks = new HashMap<>();
}
RuntimeException ex = new RuntimeException();
ex.fillInStackTrace();
@@ -931,15 +1265,117 @@
}
@GuardedBy("this")
- private final void decRefsLocked(long id) {
+ private void decRefsLocked(long id) {
if (DEBUG_REFS && mRefStacks != null) {
mRefStacks.remove(id);
}
mNumRefs--;
- //System.out.println("Dec streams: mNumRefs=" + mNumRefs
- // + " mReleased=" + mReleased);
- if (mNumRefs == 0) {
- destroy();
+ if (mNumRefs == 0 && mObject != 0) {
+ nativeDestroy(mObject);
+ mObject = 0;
+ mApkAssets = sEmptyApkAssets;
}
}
+
+ // AssetManager setup native methods.
+ private static native long nativeCreate();
+ private static native void nativeDestroy(long ptr);
+ private static native void nativeSetApkAssets(long ptr, @NonNull ApkAssets[] apkAssets,
+ boolean invalidateCaches);
+ private static native void nativeSetConfiguration(long ptr, int mcc, int mnc,
+ @Nullable String locale, int orientation, int touchscreen, int density, int keyboard,
+ int keyboardHidden, int navigation, int screenWidth, int screenHeight,
+ int smallestScreenWidthDp, int screenWidthDp, int screenHeightDp, int screenLayout,
+ int uiMode, int colorMode, int majorVersion);
+ private static native @NonNull SparseArray<String> nativeGetAssignedPackageIdentifiers(
+ long ptr);
+
+ // File native methods.
+ private static native @Nullable String[] nativeList(long ptr, @NonNull String path)
+ throws IOException;
+ private static native long nativeOpenAsset(long ptr, @NonNull String fileName, int accessMode);
+ private static native @Nullable ParcelFileDescriptor nativeOpenAssetFd(long ptr,
+ @NonNull String fileName, long[] outOffsets) throws IOException;
+ private static native long nativeOpenNonAsset(long ptr, int cookie, @NonNull String fileName,
+ int accessMode);
+ private static native @Nullable ParcelFileDescriptor nativeOpenNonAssetFd(long ptr, int cookie,
+ @NonNull String fileName, @NonNull long[] outOffsets) throws IOException;
+ private static native long nativeOpenXmlAsset(long ptr, int cookie, @NonNull String fileName);
+
+ // Primitive resource native methods.
+ private static native int nativeGetResourceValue(long ptr, @AnyRes int resId, short density,
+ @NonNull TypedValue outValue, boolean resolveReferences);
+ private static native int nativeGetResourceBagValue(long ptr, @AnyRes int resId, int bagEntryId,
+ @NonNull TypedValue outValue);
+
+ private static native @Nullable @AttrRes int[] nativeGetStyleAttributes(long ptr,
+ @StyleRes int resId);
+ private static native @Nullable String[] nativeGetResourceStringArray(long ptr,
+ @ArrayRes int resId);
+ private static native @Nullable int[] nativeGetResourceStringArrayInfo(long ptr,
+ @ArrayRes int resId);
+ private static native @Nullable int[] nativeGetResourceIntArray(long ptr, @ArrayRes int resId);
+ private static native int nativeGetResourceArraySize(long ptr, @ArrayRes int resId);
+ private static native int nativeGetResourceArray(long ptr, @ArrayRes int resId,
+ @NonNull int[] outValues);
+
+ // Resource name/ID native methods.
+ private static native @AnyRes int nativeGetResourceIdentifier(long ptr, @NonNull String name,
+ @Nullable String defType, @Nullable String defPackage);
+ private static native @Nullable String nativeGetResourceName(long ptr, @AnyRes int resid);
+ private static native @Nullable String nativeGetResourcePackageName(long ptr,
+ @AnyRes int resid);
+ private static native @Nullable String nativeGetResourceTypeName(long ptr, @AnyRes int resid);
+ private static native @Nullable String nativeGetResourceEntryName(long ptr, @AnyRes int resid);
+ private static native @Nullable String[] nativeGetLocales(long ptr, boolean excludeSystem);
+ private static native @Nullable Configuration[] nativeGetSizeConfigurations(long ptr);
+
+ // Style attribute retrieval native methods.
+ private static native void nativeApplyStyle(long ptr, long themePtr, @AttrRes int defStyleAttr,
+ @StyleRes int defStyleRes, long xmlParserPtr, @NonNull int[] inAttrs,
+ long outValuesAddress, long outIndicesAddress);
+ private static native boolean nativeResolveAttrs(long ptr, long themePtr,
+ @AttrRes int defStyleAttr, @StyleRes int defStyleRes, @Nullable int[] inValues,
+ @NonNull int[] inAttrs, @NonNull int[] outValues, @NonNull int[] outIndices);
+ private static native boolean nativeRetrieveAttributes(long ptr, long xmlParserPtr,
+ @NonNull int[] inAttrs, @NonNull int[] outValues, @NonNull int[] outIndices);
+
+ // Theme related native methods
+ private static native long nativeThemeCreate(long ptr);
+ private static native void nativeThemeDestroy(long themePtr);
+ private static native void nativeThemeApplyStyle(long ptr, long themePtr, @StyleRes int resId,
+ boolean force);
+ static native void nativeThemeCopy(long destThemePtr, long sourceThemePtr);
+ static native void nativeThemeClear(long themePtr);
+ private static native int nativeThemeGetAttributeValue(long ptr, long themePtr,
+ @AttrRes int resId, @NonNull TypedValue outValue, boolean resolve);
+ private static native void nativeThemeDump(long ptr, long themePtr, int priority, String tag,
+ String prefix);
+ static native @NativeConfig int nativeThemeGetChangingConfigurations(long themePtr);
+
+ // AssetInputStream related native methods.
+ private static native void nativeAssetDestroy(long assetPtr);
+ private static native int nativeAssetReadChar(long assetPtr);
+ private static native int nativeAssetRead(long assetPtr, byte[] b, int off, int len);
+ private static native long nativeAssetSeek(long assetPtr, long offset, int whence);
+ private static native long nativeAssetGetLength(long assetPtr);
+ private static native long nativeAssetGetRemainingLength(long assetPtr);
+
+ private static native void nativeVerifySystemIdmaps();
+
+ // Global debug native methods.
+ /**
+ * @hide
+ */
+ public static native int getGlobalAssetCount();
+
+ /**
+ * @hide
+ */
+ public static native String getAssetAllocations();
+
+ /**
+ * @hide
+ */
+ public static native int getGlobalAssetManagerCount();
}
diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java
index ad85e71..d813382 100644
--- a/core/java/android/content/res/Resources.java
+++ b/core/java/android/content/res/Resources.java
@@ -590,7 +590,7 @@
*/
@NonNull
public int[] getIntArray(@ArrayRes int id) throws NotFoundException {
- int[] res = mResourcesImpl.getAssets().getArrayIntResource(id);
+ int[] res = mResourcesImpl.getAssets().getResourceIntArray(id);
if (res != null) {
return res;
}
@@ -613,13 +613,13 @@
@NonNull
public TypedArray obtainTypedArray(@ArrayRes int id) throws NotFoundException {
final ResourcesImpl impl = mResourcesImpl;
- int len = impl.getAssets().getArraySize(id);
+ int len = impl.getAssets().getResourceArraySize(id);
if (len < 0) {
throw new NotFoundException("Array resource ID #0x" + Integer.toHexString(id));
}
TypedArray array = TypedArray.obtain(this, len);
- array.mLength = impl.getAssets().retrieveArray(id, array.mData);
+ array.mLength = impl.getAssets().getResourceArray(id, array.mData);
array.mIndices[0] = 0;
return array;
@@ -1794,8 +1794,7 @@
// out the attributes from the XML file (applying type information
// contained in the resources and such).
XmlBlock.Parser parser = (XmlBlock.Parser)set;
- mResourcesImpl.getAssets().retrieveAttributes(parser.mParseState, attrs,
- array.mData, array.mIndices);
+ mResourcesImpl.getAssets().retrieveAttributes(parser, attrs, array.mData, array.mIndices);
array.mXml = parser;
diff --git a/core/java/android/content/res/ResourcesImpl.java b/core/java/android/content/res/ResourcesImpl.java
index 424fa83..157910a 100644
--- a/core/java/android/content/res/ResourcesImpl.java
+++ b/core/java/android/content/res/ResourcesImpl.java
@@ -170,7 +170,6 @@
mDisplayAdjustments = displayAdjustments;
mConfiguration.setToDefaults();
updateConfiguration(config, metrics, displayAdjustments.getCompatibilityInfo());
- mAssets.ensureStringBlocks();
}
public DisplayAdjustments getDisplayAdjustments() {
@@ -1300,8 +1299,7 @@
void applyStyle(int resId, boolean force) {
synchronized (mKey) {
- AssetManager.applyThemeStyle(mTheme, resId, force);
-
+ mAssets.applyStyleToTheme(mTheme, resId, force);
mThemeResId = resId;
mKey.append(resId, force);
}
@@ -1310,7 +1308,7 @@
void setTo(ThemeImpl other) {
synchronized (mKey) {
synchronized (other.mKey) {
- AssetManager.copyTheme(mTheme, other.mTheme);
+ AssetManager.nativeThemeCopy(mTheme, other.mTheme);
mThemeResId = other.mThemeResId;
mKey.setTo(other.getKey());
@@ -1333,12 +1331,10 @@
// out the attributes from the XML file (applying type information
// contained in the resources and such).
final XmlBlock.Parser parser = (XmlBlock.Parser) set;
- AssetManager.applyStyle(mTheme, defStyleAttr, defStyleRes,
- parser != null ? parser.mParseState : 0,
- attrs, attrs.length, array.mDataAddress, array.mIndicesAddress);
+ mAssets.applyStyle(mTheme, defStyleAttr, defStyleRes, parser, attrs,
+ array.mDataAddress, array.mIndicesAddress);
array.mTheme = wrapper;
array.mXml = parser;
-
return array;
}
}
@@ -1355,7 +1351,7 @@
}
final TypedArray array = TypedArray.obtain(wrapper.getResources(), len);
- AssetManager.resolveAttrs(mTheme, 0, 0, values, attrs, array.mData, array.mIndices);
+ mAssets.resolveAttrs(mTheme, 0, 0, values, attrs, array.mData, array.mIndices);
array.mTheme = wrapper;
array.mXml = null;
return array;
@@ -1375,14 +1371,14 @@
@Config int getChangingConfigurations() {
synchronized (mKey) {
final @NativeConfig int nativeChangingConfig =
- AssetManager.getThemeChangingConfigurations(mTheme);
+ AssetManager.nativeThemeGetChangingConfigurations(mTheme);
return ActivityInfo.activityInfoConfigNativeToJava(nativeChangingConfig);
}
}
public void dump(int priority, String tag, String prefix) {
synchronized (mKey) {
- AssetManager.dumpTheme(mTheme, priority, tag, prefix);
+ mAssets.dumpTheme(mTheme, priority, tag, prefix);
}
}
@@ -1411,13 +1407,13 @@
*/
void rebase() {
synchronized (mKey) {
- AssetManager.clearTheme(mTheme);
+ AssetManager.nativeThemeClear(mTheme);
// Reapply the same styles in the same order.
for (int i = 0; i < mKey.mCount; i++) {
final int resId = mKey.mResId[i];
final boolean force = mKey.mForce[i];
- AssetManager.applyThemeStyle(mTheme, resId, force);
+ mAssets.applyStyleToTheme(mTheme, resId, force);
}
}
}
diff --git a/core/java/android/content/res/TypedArray.java b/core/java/android/content/res/TypedArray.java
index f33c751..cbb3c6d 100644
--- a/core/java/android/content/res/TypedArray.java
+++ b/core/java/android/content/res/TypedArray.java
@@ -61,6 +61,15 @@
return attrs;
}
+ // STYLE_ prefixed constants are offsets within the typed data array.
+ static final int STYLE_NUM_ENTRIES = 6;
+ static final int STYLE_TYPE = 0;
+ static final int STYLE_DATA = 1;
+ static final int STYLE_ASSET_COOKIE = 2;
+ static final int STYLE_RESOURCE_ID = 3;
+ static final int STYLE_CHANGING_CONFIGURATIONS = 4;
+ static final int STYLE_DENSITY = 5;
+
private final Resources mResources;
private DisplayMetrics mMetrics;
private AssetManager mAssets;
@@ -78,7 +87,7 @@
private void resize(int len) {
mLength = len;
- final int dataLen = len * AssetManager.STYLE_NUM_ENTRIES;
+ final int dataLen = len * STYLE_NUM_ENTRIES;
final int indicesLen = len + 1;
final VMRuntime runtime = VMRuntime.getRuntime();
if (mDataAddress == 0 || mData.length < dataLen) {
@@ -166,9 +175,9 @@
throw new RuntimeException("Cannot make calls to a recycled instance!");
}
- index *= AssetManager.STYLE_NUM_ENTRIES;
+ index *= STYLE_NUM_ENTRIES;
final int[] data = mData;
- final int type = data[index+AssetManager.STYLE_TYPE];
+ final int type = data[index + STYLE_TYPE];
if (type == TypedValue.TYPE_NULL) {
return null;
} else if (type == TypedValue.TYPE_STRING) {
@@ -203,9 +212,9 @@
throw new RuntimeException("Cannot make calls to a recycled instance!");
}
- index *= AssetManager.STYLE_NUM_ENTRIES;
+ index *= STYLE_NUM_ENTRIES;
final int[] data = mData;
- final int type = data[index+AssetManager.STYLE_TYPE];
+ final int type = data[index + STYLE_TYPE];
if (type == TypedValue.TYPE_NULL) {
return null;
} else if (type == TypedValue.TYPE_STRING) {
@@ -242,14 +251,13 @@
throw new RuntimeException("Cannot make calls to a recycled instance!");
}
- index *= AssetManager.STYLE_NUM_ENTRIES;
+ index *= STYLE_NUM_ENTRIES;
final int[] data = mData;
- final int type = data[index+AssetManager.STYLE_TYPE];
+ final int type = data[index + STYLE_TYPE];
if (type == TypedValue.TYPE_STRING) {
- final int cookie = data[index+AssetManager.STYLE_ASSET_COOKIE];
+ final int cookie = data[index + STYLE_ASSET_COOKIE];
if (cookie < 0) {
- return mXml.getPooledString(
- data[index+AssetManager.STYLE_DATA]).toString();
+ return mXml.getPooledString(data[index + STYLE_DATA]).toString();
}
}
return null;
@@ -274,11 +282,11 @@
throw new RuntimeException("Cannot make calls to a recycled instance!");
}
- index *= AssetManager.STYLE_NUM_ENTRIES;
+ index *= STYLE_NUM_ENTRIES;
final int[] data = mData;
- final int type = data[index+AssetManager.STYLE_TYPE];
+ final int type = data[index + STYLE_TYPE];
final @Config int changingConfigs = ActivityInfo.activityInfoConfigNativeToJava(
- data[index + AssetManager.STYLE_CHANGING_CONFIGURATIONS]);
+ data[index + STYLE_CHANGING_CONFIGURATIONS]);
if ((changingConfigs & ~allowedChangingConfigs) != 0) {
return null;
}
@@ -320,14 +328,14 @@
throw new RuntimeException("Cannot make calls to a recycled instance!");
}
- index *= AssetManager.STYLE_NUM_ENTRIES;
+ index *= STYLE_NUM_ENTRIES;
final int[] data = mData;
- final int type = data[index+AssetManager.STYLE_TYPE];
+ final int type = data[index + STYLE_TYPE];
if (type == TypedValue.TYPE_NULL) {
return defValue;
} else if (type >= TypedValue.TYPE_FIRST_INT
&& type <= TypedValue.TYPE_LAST_INT) {
- return data[index+AssetManager.STYLE_DATA] != 0;
+ return data[index + STYLE_DATA] != 0;
}
final TypedValue v = mValue;
@@ -359,14 +367,14 @@
throw new RuntimeException("Cannot make calls to a recycled instance!");
}
- index *= AssetManager.STYLE_NUM_ENTRIES;
+ index *= STYLE_NUM_ENTRIES;
final int[] data = mData;
- final int type = data[index+AssetManager.STYLE_TYPE];
+ final int type = data[index + STYLE_TYPE];
if (type == TypedValue.TYPE_NULL) {
return defValue;
} else if (type >= TypedValue.TYPE_FIRST_INT
&& type <= TypedValue.TYPE_LAST_INT) {
- return data[index+AssetManager.STYLE_DATA];
+ return data[index + STYLE_DATA];
}
final TypedValue v = mValue;
@@ -396,16 +404,16 @@
throw new RuntimeException("Cannot make calls to a recycled instance!");
}
- index *= AssetManager.STYLE_NUM_ENTRIES;
+ index *= STYLE_NUM_ENTRIES;
final int[] data = mData;
- final int type = data[index+AssetManager.STYLE_TYPE];
+ final int type = data[index + STYLE_TYPE];
if (type == TypedValue.TYPE_NULL) {
return defValue;
} else if (type == TypedValue.TYPE_FLOAT) {
- return Float.intBitsToFloat(data[index+AssetManager.STYLE_DATA]);
+ return Float.intBitsToFloat(data[index + STYLE_DATA]);
} else if (type >= TypedValue.TYPE_FIRST_INT
&& type <= TypedValue.TYPE_LAST_INT) {
- return data[index+AssetManager.STYLE_DATA];
+ return data[index + STYLE_DATA];
}
final TypedValue v = mValue;
@@ -446,15 +454,15 @@
}
final int attrIndex = index;
- index *= AssetManager.STYLE_NUM_ENTRIES;
+ index *= STYLE_NUM_ENTRIES;
final int[] data = mData;
- final int type = data[index+AssetManager.STYLE_TYPE];
+ final int type = data[index + STYLE_TYPE];
if (type == TypedValue.TYPE_NULL) {
return defValue;
} else if (type >= TypedValue.TYPE_FIRST_INT
&& type <= TypedValue.TYPE_LAST_INT) {
- return data[index+AssetManager.STYLE_DATA];
+ return data[index + STYLE_DATA];
} else if (type == TypedValue.TYPE_STRING) {
final TypedValue value = mValue;
if (getValueAt(index, value)) {
@@ -498,7 +506,7 @@
}
final TypedValue value = mValue;
- if (getValueAt(index*AssetManager.STYLE_NUM_ENTRIES, value)) {
+ if (getValueAt(index * STYLE_NUM_ENTRIES, value)) {
if (value.type == TypedValue.TYPE_ATTRIBUTE) {
throw new UnsupportedOperationException(
"Failed to resolve attribute at index " + index + ": " + value);
@@ -533,7 +541,7 @@
}
final TypedValue value = mValue;
- if (getValueAt(index*AssetManager.STYLE_NUM_ENTRIES, value)) {
+ if (getValueAt(index * STYLE_NUM_ENTRIES, value)) {
if (value.type == TypedValue.TYPE_ATTRIBUTE) {
throw new UnsupportedOperationException(
"Failed to resolve attribute at index " + index + ": " + value);
@@ -564,15 +572,15 @@
}
final int attrIndex = index;
- index *= AssetManager.STYLE_NUM_ENTRIES;
+ index *= STYLE_NUM_ENTRIES;
final int[] data = mData;
- final int type = data[index+AssetManager.STYLE_TYPE];
+ final int type = data[index + STYLE_TYPE];
if (type == TypedValue.TYPE_NULL) {
return defValue;
} else if (type >= TypedValue.TYPE_FIRST_INT
&& type <= TypedValue.TYPE_LAST_INT) {
- return data[index+AssetManager.STYLE_DATA];
+ return data[index + STYLE_DATA];
} else if (type == TypedValue.TYPE_ATTRIBUTE) {
final TypedValue value = mValue;
getValueAt(index, value);
@@ -612,15 +620,14 @@
}
final int attrIndex = index;
- index *= AssetManager.STYLE_NUM_ENTRIES;
+ index *= STYLE_NUM_ENTRIES;
final int[] data = mData;
- final int type = data[index+AssetManager.STYLE_TYPE];
+ final int type = data[index + STYLE_TYPE];
if (type == TypedValue.TYPE_NULL) {
return defValue;
} else if (type == TypedValue.TYPE_DIMENSION) {
- return TypedValue.complexToDimension(
- data[index + AssetManager.STYLE_DATA], mMetrics);
+ return TypedValue.complexToDimension(data[index + STYLE_DATA], mMetrics);
} else if (type == TypedValue.TYPE_ATTRIBUTE) {
final TypedValue value = mValue;
getValueAt(index, value);
@@ -661,15 +668,14 @@
}
final int attrIndex = index;
- index *= AssetManager.STYLE_NUM_ENTRIES;
+ index *= STYLE_NUM_ENTRIES;
final int[] data = mData;
- final int type = data[index+AssetManager.STYLE_TYPE];
+ final int type = data[index + STYLE_TYPE];
if (type == TypedValue.TYPE_NULL) {
return defValue;
} else if (type == TypedValue.TYPE_DIMENSION) {
- return TypedValue.complexToDimensionPixelOffset(
- data[index + AssetManager.STYLE_DATA], mMetrics);
+ return TypedValue.complexToDimensionPixelOffset(data[index + STYLE_DATA], mMetrics);
} else if (type == TypedValue.TYPE_ATTRIBUTE) {
final TypedValue value = mValue;
getValueAt(index, value);
@@ -711,15 +717,14 @@
}
final int attrIndex = index;
- index *= AssetManager.STYLE_NUM_ENTRIES;
+ index *= STYLE_NUM_ENTRIES;
final int[] data = mData;
- final int type = data[index+AssetManager.STYLE_TYPE];
+ final int type = data[index + STYLE_TYPE];
if (type == TypedValue.TYPE_NULL) {
return defValue;
} else if (type == TypedValue.TYPE_DIMENSION) {
- return TypedValue.complexToDimensionPixelSize(
- data[index+AssetManager.STYLE_DATA], mMetrics);
+ return TypedValue.complexToDimensionPixelSize(data[index + STYLE_DATA], mMetrics);
} else if (type == TypedValue.TYPE_ATTRIBUTE) {
final TypedValue value = mValue;
getValueAt(index, value);
@@ -755,16 +760,15 @@
}
final int attrIndex = index;
- index *= AssetManager.STYLE_NUM_ENTRIES;
+ index *= STYLE_NUM_ENTRIES;
final int[] data = mData;
- final int type = data[index+AssetManager.STYLE_TYPE];
+ final int type = data[index + STYLE_TYPE];
if (type >= TypedValue.TYPE_FIRST_INT
&& type <= TypedValue.TYPE_LAST_INT) {
- return data[index+AssetManager.STYLE_DATA];
+ return data[index + STYLE_DATA];
} else if (type == TypedValue.TYPE_DIMENSION) {
- return TypedValue.complexToDimensionPixelSize(
- data[index+AssetManager.STYLE_DATA], mMetrics);
+ return TypedValue.complexToDimensionPixelSize(data[index + STYLE_DATA], mMetrics);
} else if (type == TypedValue.TYPE_ATTRIBUTE) {
final TypedValue value = mValue;
getValueAt(index, value);
@@ -795,15 +799,14 @@
throw new RuntimeException("Cannot make calls to a recycled instance!");
}
- index *= AssetManager.STYLE_NUM_ENTRIES;
+ index *= STYLE_NUM_ENTRIES;
final int[] data = mData;
- final int type = data[index+AssetManager.STYLE_TYPE];
+ final int type = data[index + STYLE_TYPE];
if (type >= TypedValue.TYPE_FIRST_INT
&& type <= TypedValue.TYPE_LAST_INT) {
- return data[index+AssetManager.STYLE_DATA];
+ return data[index + STYLE_DATA];
} else if (type == TypedValue.TYPE_DIMENSION) {
- return TypedValue.complexToDimensionPixelSize(
- data[index + AssetManager.STYLE_DATA], mMetrics);
+ return TypedValue.complexToDimensionPixelSize(data[index + STYLE_DATA], mMetrics);
}
return defValue;
@@ -833,15 +836,14 @@
}
final int attrIndex = index;
- index *= AssetManager.STYLE_NUM_ENTRIES;
+ index *= STYLE_NUM_ENTRIES;
final int[] data = mData;
- final int type = data[index+AssetManager.STYLE_TYPE];
+ final int type = data[index + STYLE_TYPE];
if (type == TypedValue.TYPE_NULL) {
return defValue;
} else if (type == TypedValue.TYPE_FRACTION) {
- return TypedValue.complexToFraction(
- data[index+AssetManager.STYLE_DATA], base, pbase);
+ return TypedValue.complexToFraction(data[index + STYLE_DATA], base, pbase);
} else if (type == TypedValue.TYPE_ATTRIBUTE) {
final TypedValue value = mValue;
getValueAt(index, value);
@@ -874,10 +876,10 @@
throw new RuntimeException("Cannot make calls to a recycled instance!");
}
- index *= AssetManager.STYLE_NUM_ENTRIES;
+ index *= STYLE_NUM_ENTRIES;
final int[] data = mData;
- if (data[index+AssetManager.STYLE_TYPE] != TypedValue.TYPE_NULL) {
- final int resid = data[index+AssetManager.STYLE_RESOURCE_ID];
+ if (data[index + STYLE_TYPE] != TypedValue.TYPE_NULL) {
+ final int resid = data[index + STYLE_RESOURCE_ID];
if (resid != 0) {
return resid;
}
@@ -902,10 +904,10 @@
throw new RuntimeException("Cannot make calls to a recycled instance!");
}
- index *= AssetManager.STYLE_NUM_ENTRIES;
+ index *= STYLE_NUM_ENTRIES;
final int[] data = mData;
- if (data[index + AssetManager.STYLE_TYPE] == TypedValue.TYPE_ATTRIBUTE) {
- return data[index + AssetManager.STYLE_DATA];
+ if (data[index + STYLE_TYPE] == TypedValue.TYPE_ATTRIBUTE) {
+ return data[index + STYLE_DATA];
}
return defValue;
}
@@ -939,7 +941,7 @@
}
final TypedValue value = mValue;
- if (getValueAt(index*AssetManager.STYLE_NUM_ENTRIES, value)) {
+ if (getValueAt(index * STYLE_NUM_ENTRIES, value)) {
if (value.type == TypedValue.TYPE_ATTRIBUTE) {
throw new UnsupportedOperationException(
"Failed to resolve attribute at index " + index + ": " + value);
@@ -975,7 +977,7 @@
}
final TypedValue value = mValue;
- if (getValueAt(index*AssetManager.STYLE_NUM_ENTRIES, value)) {
+ if (getValueAt(index * STYLE_NUM_ENTRIES, value)) {
if (value.type == TypedValue.TYPE_ATTRIBUTE) {
throw new UnsupportedOperationException(
"Failed to resolve attribute at index " + index + ": " + value);
@@ -1006,7 +1008,7 @@
}
final TypedValue value = mValue;
- if (getValueAt(index*AssetManager.STYLE_NUM_ENTRIES, value)) {
+ if (getValueAt(index * STYLE_NUM_ENTRIES, value)) {
return mResources.getTextArray(value.resourceId);
}
return null;
@@ -1027,7 +1029,7 @@
throw new RuntimeException("Cannot make calls to a recycled instance!");
}
- return getValueAt(index*AssetManager.STYLE_NUM_ENTRIES, outValue);
+ return getValueAt(index * STYLE_NUM_ENTRIES, outValue);
}
/**
@@ -1043,8 +1045,8 @@
throw new RuntimeException("Cannot make calls to a recycled instance!");
}
- index *= AssetManager.STYLE_NUM_ENTRIES;
- return mData[index + AssetManager.STYLE_TYPE];
+ index *= STYLE_NUM_ENTRIES;
+ return mData[index + STYLE_TYPE];
}
/**
@@ -1063,9 +1065,9 @@
throw new RuntimeException("Cannot make calls to a recycled instance!");
}
- index *= AssetManager.STYLE_NUM_ENTRIES;
+ index *= STYLE_NUM_ENTRIES;
final int[] data = mData;
- final int type = data[index+AssetManager.STYLE_TYPE];
+ final int type = data[index + STYLE_TYPE];
return type != TypedValue.TYPE_NULL;
}
@@ -1084,11 +1086,11 @@
throw new RuntimeException("Cannot make calls to a recycled instance!");
}
- index *= AssetManager.STYLE_NUM_ENTRIES;
+ index *= STYLE_NUM_ENTRIES;
final int[] data = mData;
- final int type = data[index+AssetManager.STYLE_TYPE];
+ final int type = data[index + STYLE_TYPE];
return type != TypedValue.TYPE_NULL
- || data[index+AssetManager.STYLE_DATA] == TypedValue.DATA_NULL_EMPTY;
+ || data[index + STYLE_DATA] == TypedValue.DATA_NULL_EMPTY;
}
/**
@@ -1109,7 +1111,7 @@
}
final TypedValue value = mValue;
- if (getValueAt(index*AssetManager.STYLE_NUM_ENTRIES, value)) {
+ if (getValueAt(index * STYLE_NUM_ENTRIES, value)) {
return value;
}
return null;
@@ -1181,16 +1183,16 @@
final int[] data = mData;
final int N = length();
for (int i = 0; i < N; i++) {
- final int index = i * AssetManager.STYLE_NUM_ENTRIES;
- if (data[index + AssetManager.STYLE_TYPE] != TypedValue.TYPE_ATTRIBUTE) {
+ final int index = i * STYLE_NUM_ENTRIES;
+ if (data[index + STYLE_TYPE] != TypedValue.TYPE_ATTRIBUTE) {
// Not an attribute, ignore.
continue;
}
// Null the entry so that we can safely call getZzz().
- data[index + AssetManager.STYLE_TYPE] = TypedValue.TYPE_NULL;
+ data[index + STYLE_TYPE] = TypedValue.TYPE_NULL;
- final int attr = data[index + AssetManager.STYLE_DATA];
+ final int attr = data[index + STYLE_DATA];
if (attr == 0) {
// Useless data, ignore.
continue;
@@ -1231,45 +1233,44 @@
final int[] data = mData;
final int N = length();
for (int i = 0; i < N; i++) {
- final int index = i * AssetManager.STYLE_NUM_ENTRIES;
- final int type = data[index + AssetManager.STYLE_TYPE];
+ final int index = i * STYLE_NUM_ENTRIES;
+ final int type = data[index + STYLE_TYPE];
if (type == TypedValue.TYPE_NULL) {
continue;
}
changingConfig |= ActivityInfo.activityInfoConfigNativeToJava(
- data[index + AssetManager.STYLE_CHANGING_CONFIGURATIONS]);
+ data[index + STYLE_CHANGING_CONFIGURATIONS]);
}
return changingConfig;
}
private boolean getValueAt(int index, TypedValue outValue) {
final int[] data = mData;
- final int type = data[index+AssetManager.STYLE_TYPE];
+ final int type = data[index + STYLE_TYPE];
if (type == TypedValue.TYPE_NULL) {
return false;
}
outValue.type = type;
- outValue.data = data[index+AssetManager.STYLE_DATA];
- outValue.assetCookie = data[index+AssetManager.STYLE_ASSET_COOKIE];
- outValue.resourceId = data[index+AssetManager.STYLE_RESOURCE_ID];
+ outValue.data = data[index + STYLE_DATA];
+ outValue.assetCookie = data[index + STYLE_ASSET_COOKIE];
+ outValue.resourceId = data[index + STYLE_RESOURCE_ID];
outValue.changingConfigurations = ActivityInfo.activityInfoConfigNativeToJava(
- data[index + AssetManager.STYLE_CHANGING_CONFIGURATIONS]);
- outValue.density = data[index+AssetManager.STYLE_DENSITY];
+ data[index + STYLE_CHANGING_CONFIGURATIONS]);
+ outValue.density = data[index + STYLE_DENSITY];
outValue.string = (type == TypedValue.TYPE_STRING) ? loadStringValueAt(index) : null;
return true;
}
private CharSequence loadStringValueAt(int index) {
final int[] data = mData;
- final int cookie = data[index+AssetManager.STYLE_ASSET_COOKIE];
+ final int cookie = data[index + STYLE_ASSET_COOKIE];
if (cookie < 0) {
if (mXml != null) {
- return mXml.getPooledString(
- data[index+AssetManager.STYLE_DATA]);
+ return mXml.getPooledString(data[index + STYLE_DATA]);
}
return null;
}
- return mAssets.getPooledStringForCookie(cookie, data[index+AssetManager.STYLE_DATA]);
+ return mAssets.getPooledStringForCookie(cookie, data[index + STYLE_DATA]);
}
/** @hide */
diff --git a/core/java/android/content/res/XmlBlock.java b/core/java/android/content/res/XmlBlock.java
index e6b95741..d4ccffb 100644
--- a/core/java/android/content/res/XmlBlock.java
+++ b/core/java/android/content/res/XmlBlock.java
@@ -16,6 +16,7 @@
package android.content.res;
+import android.annotation.Nullable;
import android.util.TypedValue;
import com.android.internal.util.XmlUtils;
@@ -33,7 +34,7 @@
*
* {@hide}
*/
-final class XmlBlock {
+final class XmlBlock implements AutoCloseable {
private static final boolean DEBUG=false;
public XmlBlock(byte[] data) {
@@ -48,6 +49,7 @@
mStrings = new StringBlock(nativeGetStringBlock(mNative), false);
}
+ @Override
public void close() {
synchronized (this) {
if (mOpen) {
@@ -478,13 +480,13 @@
* are doing! The given native object must exist for the entire lifetime
* of this newly creating XmlBlock.
*/
- XmlBlock(AssetManager assets, long xmlBlock) {
+ XmlBlock(@Nullable AssetManager assets, long xmlBlock) {
mAssets = assets;
mNative = xmlBlock;
mStrings = new StringBlock(nativeGetStringBlock(xmlBlock), false);
}
- private final AssetManager mAssets;
+ private @Nullable final AssetManager mAssets;
private final long mNative;
/*package*/ final StringBlock mStrings;
private boolean mOpen = true;
diff --git a/core/java/android/hardware/camera2/CaptureRequest.java b/core/java/android/hardware/camera2/CaptureRequest.java
index ada7ebf..98901a1 100644
--- a/core/java/android/hardware/camera2/CaptureRequest.java
+++ b/core/java/android/hardware/camera2/CaptureRequest.java
@@ -1457,7 +1457,8 @@
* is used, all non-zero weights will have the same effect. A region with 0 weight is
* ignored.</p>
* <p>If all regions have 0 weight, then no specific metering area needs to be used by the
- * camera device.</p>
+ * camera device. The capture result will either be a zero weight region as well, or
+ * the region selected by the camera device as the focus area of interest.</p>
* <p>If the metering region is outside the used {@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion} returned in
* capture result metadata, the camera device will ignore the sections outside the crop
* region and output only the intersection rectangle as the metering region in the result
diff --git a/core/java/android/hardware/camera2/CaptureResult.java b/core/java/android/hardware/camera2/CaptureResult.java
index 8c2f8c1..e14dfa8 100644
--- a/core/java/android/hardware/camera2/CaptureResult.java
+++ b/core/java/android/hardware/camera2/CaptureResult.java
@@ -1156,7 +1156,8 @@
* is used, all non-zero weights will have the same effect. A region with 0 weight is
* ignored.</p>
* <p>If all regions have 0 weight, then no specific metering area needs to be used by the
- * camera device.</p>
+ * camera device. The capture result will either be a zero weight region as well, or
+ * the region selected by the camera device as the focus area of interest.</p>
* <p>If the metering region is outside the used {@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion} returned in
* capture result metadata, the camera device will ignore the sections outside the crop
* region and output only the intersection rectangle as the metering region in the result
diff --git a/core/java/android/net/NetworkCapabilities.java b/core/java/android/net/NetworkCapabilities.java
index 17b46c6..ef58f94 100644
--- a/core/java/android/net/NetworkCapabilities.java
+++ b/core/java/android/net/NetworkCapabilities.java
@@ -17,6 +17,7 @@
package android.net;
import android.annotation.IntDef;
+import android.annotation.SystemApi;
import android.net.ConnectivityManager.NetworkCallback;
import android.os.Parcel;
import android.os.Parcelable;
@@ -69,6 +70,7 @@
mSignalStrength = nc.mSignalStrength;
mUids = nc.mUids;
mEstablishingVpnAppUid = nc.mEstablishingVpnAppUid;
+ mUnwantedNetworkCapabilities = nc.mUnwantedNetworkCapabilities;
}
}
@@ -78,7 +80,7 @@
* @hide
*/
public void clearAll() {
- mNetworkCapabilities = mTransportTypes = 0;
+ mNetworkCapabilities = mTransportTypes = mUnwantedNetworkCapabilities = 0;
mLinkUpBandwidthKbps = mLinkDownBandwidthKbps = LINK_BANDWIDTH_UNSPECIFIED;
mNetworkSpecifier = null;
mSignalStrength = SIGNAL_STRENGTH_UNSPECIFIED;
@@ -92,6 +94,11 @@
*/
private long mNetworkCapabilities;
+ /**
+ * If any capabilities specified here they must not exist in the matching Network.
+ */
+ private long mUnwantedNetworkCapabilities;
+
/** @hide */
@Retention(RetentionPolicy.SOURCE)
@IntDef(prefix = { "NET_CAPABILITY_" }, value = {
@@ -339,31 +346,55 @@
* Adds the given capability to this {@code NetworkCapability} instance.
* Multiple capabilities may be applied sequentially. Note that when searching
* for a network to satisfy a request, all capabilities requested must be satisfied.
+ * <p>
+ * If the given capability was previously added to the list of unwanted capabilities
+ * then the capability will also be removed from the list of unwanted capabilities.
*
* @param capability the capability to be added.
* @return This NetworkCapabilities instance, to facilitate chaining.
* @hide
*/
public NetworkCapabilities addCapability(@NetCapability int capability) {
- if (capability < MIN_NET_CAPABILITY || capability > MAX_NET_CAPABILITY) {
- throw new IllegalArgumentException("NetworkCapability out of range");
- }
+ checkValidCapability(capability);
mNetworkCapabilities |= 1 << capability;
+ mUnwantedNetworkCapabilities &= ~(1 << capability); // remove from unwanted capability list
return this;
}
/**
+ * Adds the given capability to the list of unwanted capabilities of this
+ * {@code NetworkCapability} instance. Multiple unwanted capabilities may be applied
+ * sequentially. Note that when searching for a network to satisfy a request, the network
+ * must not contain any capability from unwanted capability list.
+ * <p>
+ * If the capability was previously added to the list of required capabilities (for
+ * example, it was there by default or added using {@link #addCapability(int)} method), then
+ * it will be removed from the list of required capabilities as well.
+ *
+ * @see #addCapability(int)
+ * @hide
+ */
+ public void addUnwantedCapability(@NetCapability int capability) {
+ checkValidCapability(capability);
+ mUnwantedNetworkCapabilities |= 1 << capability;
+ mNetworkCapabilities &= ~(1 << capability); // remove from requested capabilities
+ }
+
+ /**
* Removes (if found) the given capability from this {@code NetworkCapability} instance.
+ * <p>
+ * Note that this method removes capabilities that was added via {@link #addCapability(int)},
+ * {@link #addUnwantedCapability(int)} or {@link #setCapabilities(int[], int[])} .
*
* @param capability the capability to be removed.
* @return This NetworkCapabilities instance, to facilitate chaining.
* @hide
*/
public NetworkCapabilities removeCapability(@NetCapability int capability) {
- if (capability < MIN_NET_CAPABILITY || capability > MAX_NET_CAPABILITY) {
- throw new IllegalArgumentException("NetworkCapability out of range");
- }
- mNetworkCapabilities &= ~(1 << capability);
+ checkValidCapability(capability);
+ final long mask = ~(1 << capability);
+ mNetworkCapabilities &= mask;
+ mUnwantedNetworkCapabilities &= mask;
return this;
}
@@ -393,30 +424,57 @@
}
/**
+ * Gets all the unwanted capabilities set on this {@code NetworkCapability} instance.
+ *
+ * @return an array of unwanted capability values for this instance.
+ * @hide
+ */
+ public @NetCapability int[] getUnwantedCapabilities() {
+ return BitUtils.unpackBits(mUnwantedNetworkCapabilities);
+ }
+
+
+ /**
* Sets all the capabilities set on this {@code NetworkCapability} instance.
* This overwrites any existing capabilities.
*
* @hide
*/
- public void setCapabilities(@NetCapability int[] capabilities) {
+ public void setCapabilities(@NetCapability int[] capabilities,
+ @NetCapability int[] unwantedCapabilities) {
mNetworkCapabilities = BitUtils.packBits(capabilities);
+ mUnwantedNetworkCapabilities = BitUtils.packBits(unwantedCapabilities);
}
/**
- * Tests for the presence of a capabilitity on this instance.
+ * @deprecated use {@link #setCapabilities(int[], int[])}
+ * @hide
+ */
+ @Deprecated
+ public void setCapabilities(@NetCapability int[] capabilities) {
+ setCapabilities(capabilities, new int[] {});
+ }
+
+ /**
+ * Tests for the presence of a capability on this instance.
*
* @param capability the capabilities to be tested for.
* @return {@code true} if set on this instance.
*/
public boolean hasCapability(@NetCapability int capability) {
- if (capability < MIN_NET_CAPABILITY || capability > MAX_NET_CAPABILITY) {
- return false;
- }
- return ((mNetworkCapabilities & (1 << capability)) != 0);
+ return isValidCapability(capability)
+ && ((mNetworkCapabilities & (1 << capability)) != 0);
+ }
+
+ /** @hide */
+ public boolean hasUnwantedCapability(@NetCapability int capability) {
+ return isValidCapability(capability)
+ && ((mUnwantedNetworkCapabilities & (1 << capability)) != 0);
}
private void combineNetCapabilities(NetworkCapabilities nc) {
this.mNetworkCapabilities |= nc.mNetworkCapabilities;
+ this.mUnwantedNetworkCapabilities |= nc.mUnwantedNetworkCapabilities;
}
/**
@@ -427,7 +485,9 @@
* @hide
*/
public String describeFirstNonRequestableCapability() {
- final long nonRequestable = (mNetworkCapabilities & NON_REQUESTABLE_CAPABILITIES);
+ final long nonRequestable = (mNetworkCapabilities | mUnwantedNetworkCapabilities)
+ & NON_REQUESTABLE_CAPABILITIES;
+
if (nonRequestable != 0) {
return capabilityNameOf(BitUtils.unpackBits(nonRequestable)[0]);
}
@@ -437,21 +497,29 @@
}
private boolean satisfiedByNetCapabilities(NetworkCapabilities nc, boolean onlyImmutable) {
- long networkCapabilities = this.mNetworkCapabilities;
+ long requestedCapabilities = mNetworkCapabilities;
+ long requestedUnwantedCapabilities = mUnwantedNetworkCapabilities;
+ long providedCapabilities = nc.mNetworkCapabilities;
+
if (onlyImmutable) {
- networkCapabilities = networkCapabilities & ~MUTABLE_CAPABILITIES;
+ requestedCapabilities &= ~MUTABLE_CAPABILITIES;
+ requestedUnwantedCapabilities &= ~MUTABLE_CAPABILITIES;
}
- return ((nc.mNetworkCapabilities & networkCapabilities) == networkCapabilities);
+ return ((providedCapabilities & requestedCapabilities) == requestedCapabilities)
+ && ((requestedUnwantedCapabilities & providedCapabilities) == 0);
}
/** @hide */
public boolean equalsNetCapabilities(NetworkCapabilities nc) {
- return (nc.mNetworkCapabilities == this.mNetworkCapabilities);
+ return (nc.mNetworkCapabilities == this.mNetworkCapabilities)
+ && (nc.mUnwantedNetworkCapabilities == this.mUnwantedNetworkCapabilities);
}
private boolean equalsNetCapabilitiesRequestable(NetworkCapabilities that) {
return ((this.mNetworkCapabilities & ~NON_REQUESTABLE_CAPABILITIES) ==
- (that.mNetworkCapabilities & ~NON_REQUESTABLE_CAPABILITIES));
+ (that.mNetworkCapabilities & ~NON_REQUESTABLE_CAPABILITIES))
+ && ((this.mUnwantedNetworkCapabilities & ~NON_REQUESTABLE_CAPABILITIES) ==
+ (that.mUnwantedNetworkCapabilities & ~NON_REQUESTABLE_CAPABILITIES));
}
/**
@@ -1185,15 +1253,17 @@
@Override
public int hashCode() {
- return ((int) (mNetworkCapabilities & 0xFFFFFFFF)
+ return (int) (mNetworkCapabilities & 0xFFFFFFFF)
+ ((int) (mNetworkCapabilities >> 32) * 3)
- + ((int) (mTransportTypes & 0xFFFFFFFF) * 5)
- + ((int) (mTransportTypes >> 32) * 7)
- + (mLinkUpBandwidthKbps * 11)
- + (mLinkDownBandwidthKbps * 13)
- + Objects.hashCode(mNetworkSpecifier) * 17
- + (mSignalStrength * 19)
- + Objects.hashCode(mUids) * 23);
+ + ((int) (mUnwantedNetworkCapabilities & 0xFFFFFFFF) * 5)
+ + ((int) (mUnwantedNetworkCapabilities >> 32) * 7)
+ + ((int) (mTransportTypes & 0xFFFFFFFF) * 11)
+ + ((int) (mTransportTypes >> 32) * 13)
+ + (mLinkUpBandwidthKbps * 17)
+ + (mLinkDownBandwidthKbps * 19)
+ + Objects.hashCode(mNetworkSpecifier) * 23
+ + (mSignalStrength * 29)
+ + Objects.hashCode(mUids) * 31;
}
@Override
@@ -1203,6 +1273,7 @@
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeLong(mNetworkCapabilities);
+ dest.writeLong(mUnwantedNetworkCapabilities);
dest.writeLong(mTransportTypes);
dest.writeInt(mLinkUpBandwidthKbps);
dest.writeInt(mLinkDownBandwidthKbps);
@@ -1218,6 +1289,7 @@
NetworkCapabilities netCap = new NetworkCapabilities();
netCap.mNetworkCapabilities = in.readLong();
+ netCap.mUnwantedNetworkCapabilities = in.readLong();
netCap.mTransportTypes = in.readLong();
netCap.mLinkUpBandwidthKbps = in.readInt();
netCap.mLinkDownBandwidthKbps = in.readInt();
@@ -1246,6 +1318,11 @@
appendStringRepresentationOfBitMaskToStringBuilder(sb, mNetworkCapabilities,
NetworkCapabilities::capabilityNameOf, "&");
}
+ if (0 != mNetworkCapabilities) {
+ sb.append(" Unwanted: ");
+ appendStringRepresentationOfBitMaskToStringBuilder(sb, mUnwantedNetworkCapabilities,
+ NetworkCapabilities::capabilityNameOf, "&");
+ }
if (mLinkUpBandwidthKbps > 0) {
sb.append(" LinkUpBandwidth>=").append(mLinkUpBandwidthKbps).append("Kbps");
}
@@ -1396,4 +1473,13 @@
Preconditions.checkArgument(
isValidTransport(transport), "Invalid TransportType " + transport);
}
+
+ private static boolean isValidCapability(@NetworkCapabilities.NetCapability int capability) {
+ return capability >= MIN_NET_CAPABILITY && capability <= MAX_NET_CAPABILITY;
+ }
+
+ private static void checkValidCapability(@NetworkCapabilities.NetCapability int capability) {
+ Preconditions.checkArgument(isValidCapability(capability),
+ "NetworkCapability " + capability + "out of range");
+ }
}
diff --git a/core/java/android/net/NetworkRequest.java b/core/java/android/net/NetworkRequest.java
index 61199f9..fdcc304 100644
--- a/core/java/android/net/NetworkRequest.java
+++ b/core/java/android/net/NetworkRequest.java
@@ -165,6 +165,9 @@
* the requested network's required capabilities. Note that when searching
* for a network to satisfy a request, all capabilities requested must be
* satisfied.
+ * <p>
+ * If the given capability was previously added to the list of unwanted capabilities
+ * then the capability will also be removed from the list of unwanted capabilities.
*
* @param capability The capability to add.
* @return The builder to facilitate chaining
@@ -176,7 +179,8 @@
}
/**
- * Removes (if found) the given capability from this builder instance.
+ * Removes (if found) the given capability from this builder instance from both required
+ * and unwanted capabilities lists.
*
* @param capability The capability to remove.
* @return The builder to facilitate chaining.
@@ -201,6 +205,24 @@
}
/**
+ * Add a capability that must not exist in the requested network.
+ * <p>
+ * If the capability was previously added to the list of required capabilities (for
+ * example, it was there by default or added using {@link #addCapability(int)} method), then
+ * it will be removed from the list of required capabilities as well.
+ *
+ * @see #addCapability(int)
+ *
+ * @param capability The capability to add to unwanted capability list.
+ * @return The builder to facilitate chaining.
+ * @hide
+ */
+ public Builder addUnwantedCapability(@NetworkCapabilities.NetCapability int capability) {
+ mNetworkCapabilities.addUnwantedCapability(capability);
+ return this;
+ }
+
+ /**
* Completely clears all the {@code NetworkCapabilities} from this builder instance,
* removing even the capabilities that are set by default when the object is constructed.
*
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index 9a30487..7bc5d5b 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -294,8 +294,8 @@
/**
* jbd line is:
* BATTERY_STATS_CHECKIN_VERSION, uid, which, "jbd",
- * jobsDeferredEventCount, jobsDeferredCount, averageLatencyMillis,
- * count at latency < 1 hr, count at latency < 2 hrs, count at latency < 6 hrs, beyond 6 hrs
+ * jobsDeferredEventCount, jobsDeferredCount, totalLatencyMillis,
+ * count at latency < 1 hr, count at latency 1 to 2 hrs, 2 to 4 hrs, 4 to 8 hrs, and past 8 hrs
* <p>
* @see #JOB_FRESHNESS_BUCKETS
*/
@@ -364,13 +364,14 @@
/**
* These are the thresholds for bucketing last time since a job was run for an app
* that just moved to ACTIVE due to a launch. So if the last time a job ran was less
- * than 30 minutes ago, then it's reasonably fresh, 2 hours ago, not so fresh and so
+ * than 1 hour ago, then it's reasonably fresh, 2 hours ago, not so fresh and so
* on.
*/
public static final long[] JOB_FRESHNESS_BUCKETS = {
1 * 60 * 60 * 1000L,
2 * 60 * 60 * 1000L,
- 6 * 60 * 60 * 1000L,
+ 4 * 60 * 60 * 1000L,
+ 8 * 60 * 60 * 1000L,
Long.MAX_VALUE
};
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 8fc6901..3c3c762 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -84,6 +84,7 @@
import android.util.Log;
import android.util.MemoryIntArray;
import android.util.StatsLog;
+import android.view.textservice.TextServicesManager;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.widget.ILockSettings;
@@ -7970,6 +7971,10 @@
CLONE_TO_MANAGED_PROFILE.add(LOCATION_MODE);
CLONE_TO_MANAGED_PROFILE.add(LOCATION_PROVIDERS_ALLOWED);
CLONE_TO_MANAGED_PROFILE.add(SELECTED_INPUT_METHOD_SUBTYPE);
+ if (TextServicesManager.DISABLE_PER_PROFILE_SPELL_CHECKER) {
+ CLONE_TO_MANAGED_PROFILE.add(SELECTED_SPELL_CHECKER);
+ CLONE_TO_MANAGED_PROFILE.add(SELECTED_SPELL_CHECKER_SUBTYPE);
+ }
}
/** @hide */
@@ -10612,6 +10617,15 @@
public static final String OFF_BODY_RADIOS_OFF_DELAY_MS = "off_body_radios_off_delay_ms";
/**
+ * Whether or not to turn on Wifi when proxy is disconnected.
+ * Type: int (0 for false, 1 for true)
+ * Default: 1
+ * @hide
+ */
+ public static final String WIFI_ON_WHEN_PROXY_DISCONNECTED
+ = "wifi_on_when_proxy_disconnected";
+
+ /**
* Whether or not to enable Time Only Mode for watch type devices.
* Type: int (0 for false, 1 for true)
* Default: 0
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index 914ba0c..75940e8 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -283,6 +283,11 @@
*/
oneway void setPipVisibility(boolean visible);
+ /**
+ * Called by System UI to enable or disable haptic feedback on the navigation bar buttons.
+ */
+ void setNavBarVirtualKeyHapticFeedbackEnabled(boolean enabled);
+
/**
* Device has a software navigation bar (separate from the status bar).
*/
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index e285222..03c3ded 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -14003,7 +14003,7 @@
// setFlags invocation.
shouldNotifyFocusableAvailable = true;
} else {
- if (hasFocus()) clearFocus();
+ if (isFocused()) clearFocus();
}
}
diff --git a/core/java/android/view/inputmethod/InputConnection.java b/core/java/android/view/inputmethod/InputConnection.java
index eba9176..e554540 100644
--- a/core/java/android/view/inputmethod/InputConnection.java
+++ b/core/java/android/view/inputmethod/InputConnection.java
@@ -21,7 +21,6 @@
import android.inputmethodservice.InputMethodService;
import android.os.Bundle;
import android.os.Handler;
-import android.os.LocaleList;
import android.view.KeyCharacterMap;
import android.view.KeyEvent;
@@ -899,37 +898,4 @@
*/
boolean commitContent(@NonNull InputContentInfo inputContentInfo, int flags,
@Nullable Bundle opts);
-
- /**
- * Called by the input method to tell a hint about the locales of text to be committed.
- *
- * <p>This is just a hint for editor authors (and the system) to choose better options when
- * they have to disambiguate languages, like editor authors can do for input methods with
- * {@link EditorInfo#hintLocales}.</p>
- *
- * <p>The language hint provided by this callback should have higher priority than
- * {@link InputMethodSubtype#getLanguageTag()}, which cannot be updated dynamically.</p>
- *
- * <p>Note that in general it is discouraged for input method to specify
- * {@link android.text.style.LocaleSpan} when inputting text, mainly because of application
- * compatibility concerns.</p>
- * <ul>
- * <li>When an existing text that already has {@link android.text.style.LocaleSpan} is being
- * modified by both the input method and application, there is no reliable and easy way to
- * keep track of who modified {@link android.text.style.LocaleSpan}. For instance, if the
- * text was updated by JavaScript, it it highly likely that span information is completely
- * removed, while some input method attempts to preserve spans if possible.</li>
- * <li>There is no clear semantics regarding whether {@link android.text.style.LocaleSpan}
- * means a weak (ignorable) hint or a strong hint. This becomes more problematic when
- * multiple {@link android.text.style.LocaleSpan} instances are specified to the same
- * text region, especially when those spans are conflicting.</li>
- * </ul>
- * @param languageHint list of languages sorted by the priority and/or probability
- */
- default void reportLanguageHint(@NonNull LocaleList languageHint) {
- // Intentionally empty.
- //
- // We need to have *some* default implementation for the source compatibility.
- // See Bug 72127682 for details.
- }
}
diff --git a/core/java/android/view/inputmethod/InputConnectionWrapper.java b/core/java/android/view/inputmethod/InputConnectionWrapper.java
index cbe6856..f671e22 100644
--- a/core/java/android/view/inputmethod/InputConnectionWrapper.java
+++ b/core/java/android/view/inputmethod/InputConnectionWrapper.java
@@ -16,10 +16,8 @@
package android.view.inputmethod;
-import android.annotation.NonNull;
import android.os.Bundle;
import android.os.Handler;
-import android.os.LocaleList;
import android.view.KeyEvent;
/**
@@ -305,13 +303,4 @@
public boolean commitContent(InputContentInfo inputContentInfo, int flags, Bundle opts) {
return mTarget.commitContent(inputContentInfo, flags, opts);
}
-
- /**
- * {@inheritDoc}
- * @throws NullPointerException if the target is {@code null}.
- */
- @Override
- public void reportLanguageHint(@NonNull LocaleList languageHint) {
- mTarget.reportLanguageHint(languageHint);
- }
}
diff --git a/core/java/android/view/textservice/TextServicesManager.java b/core/java/android/view/textservice/TextServicesManager.java
index f368c74..21ec42b 100644
--- a/core/java/android/view/textservice/TextServicesManager.java
+++ b/core/java/android/view/textservice/TextServicesManager.java
@@ -66,6 +66,12 @@
private static final String TAG = TextServicesManager.class.getSimpleName();
private static final boolean DBG = false;
+ /**
+ * A compile time switch to control per-profile spell checker, which is not yet ready.
+ * @hide
+ */
+ public static final boolean DISABLE_PER_PROFILE_SPELL_CHECKER = true;
+
private static TextServicesManager sInstance;
private final ITextServicesManager mService;
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index a13de75..9a99963 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -31,7 +31,6 @@
import android.os.Bundle;
import android.os.Debug;
import android.os.Handler;
-import android.os.LocaleList;
import android.os.Parcel;
import android.os.Parcelable;
import android.os.StrictMode;
@@ -6036,11 +6035,6 @@
public boolean commitContent(InputContentInfo inputContentInfo, int flags, Bundle opts) {
return getTarget().commitContent(inputContentInfo, flags, opts);
}
-
- @Override
- public void reportLanguageHint(@NonNull LocaleList languageHint) {
- getTarget().reportLanguageHint(languageHint);
- }
}
/**
diff --git a/core/java/com/android/internal/accessibility/AccessibilityShortcutController.java b/core/java/com/android/internal/accessibility/AccessibilityShortcutController.java
index ffc21d5..90712fd 100644
--- a/core/java/com/android/internal/accessibility/AccessibilityShortcutController.java
+++ b/core/java/com/android/internal/accessibility/AccessibilityShortcutController.java
@@ -143,6 +143,9 @@
mContext.getContentResolver().registerContentObserver(
Settings.Secure.getUriFor(Settings.Secure.ACCESSIBILITY_SHORTCUT_ON_LOCK_SCREEN),
false, co, UserHandle.USER_ALL);
+ mContext.getContentResolver().registerContentObserver(
+ Settings.Secure.getUriFor(Settings.Secure.ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN),
+ false, co, UserHandle.USER_ALL);
setCurrentUser(mUserId);
}
@@ -168,8 +171,12 @@
final ContentResolver cr = mContext.getContentResolver();
final boolean enabled = Settings.Secure.getIntForUser(
cr, Settings.Secure.ACCESSIBILITY_SHORTCUT_ENABLED, 1, mUserId) == 1;
+ // Enable the shortcut from the lockscreen by default if the dialog has been shown
+ final int dialogAlreadyShown = Settings.Secure.getIntForUser(
+ cr, Settings.Secure.ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN, 0, mUserId);
mEnabledOnLockScreen = Settings.Secure.getIntForUser(
- cr, Settings.Secure.ACCESSIBILITY_SHORTCUT_ON_LOCK_SCREEN, 0, mUserId) == 1;
+ cr, Settings.Secure.ACCESSIBILITY_SHORTCUT_ON_LOCK_SCREEN,
+ dialogAlreadyShown, mUserId) == 1;
mIsShortcutEnabled = enabled && haveValidService;
}
diff --git a/core/java/com/android/internal/globalactions/Action.java b/core/java/com/android/internal/globalactions/Action.java
new file mode 100644
index 0000000..ddb75c1c
--- /dev/null
+++ b/core/java/com/android/internal/globalactions/Action.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.internal.globalactions;
+
+import android.content.Context;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+/** What each item in the global actions dialog must be able to support. */
+public interface Action {
+ /** @return Text that will be announced when dialog is created. {@code null} for none. */
+ CharSequence getLabelForAccessibility(Context context);
+
+ /** Create the view that represents this action. */
+ View create(Context context, View convertView, ViewGroup parent, LayoutInflater inflater);
+
+ /** Called when the action is selected by the user. */
+ void onPress();
+
+ /** @return whether this action should appear in the dialog when the keygaurd is showing. */
+ boolean showDuringKeyguard();
+
+ /** @return whether this action should appear in the dialog before the device is provisioned. */
+ boolean showBeforeProvisioning();
+
+ /** @return {@code true} if the action is enabled for user interaction. */
+ boolean isEnabled();
+}
diff --git a/core/java/com/android/internal/globalactions/ActionsAdapter.java b/core/java/com/android/internal/globalactions/ActionsAdapter.java
new file mode 100644
index 0000000..c9f01ce
--- /dev/null
+++ b/core/java/com/android/internal/globalactions/ActionsAdapter.java
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.internal.globalactions;
+
+import android.content.Context;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.BaseAdapter;
+import java.util.function.BooleanSupplier;
+import java.util.List;
+
+/**
+ * The adapter used for the list within the global actions dialog, taking into account whether the
+ * keyguard is showing via {@link LegacyGlobalActions#mKeyguardShowing} and whether the device is
+ * provisioned via {@link LegacyGlobalActions#mDeviceProvisioned}.
+ */
+public class ActionsAdapter extends BaseAdapter {
+ private final Context mContext;
+ private final List<Action> mItems;
+ private final BooleanSupplier mDeviceProvisioned;
+ private final BooleanSupplier mKeyguardShowing;
+
+ public ActionsAdapter(Context context, List<Action> items,
+ BooleanSupplier deviceProvisioned, BooleanSupplier keyguardShowing) {
+ mContext = context;
+ mItems = items;
+ mDeviceProvisioned = deviceProvisioned;
+ mKeyguardShowing = keyguardShowing;
+ }
+
+ @Override
+ public int getCount() {
+ final boolean keyguardShowing = mKeyguardShowing.getAsBoolean();
+ final boolean deviceProvisioned = mDeviceProvisioned.getAsBoolean();
+ int count = 0;
+
+ for (int i = 0; i < mItems.size(); i++) {
+ final Action action = mItems.get(i);
+
+ if (keyguardShowing && !action.showDuringKeyguard()) {
+ continue;
+ }
+ if (!deviceProvisioned && !action.showBeforeProvisioning()) {
+ continue;
+ }
+ count++;
+ }
+ return count;
+ }
+
+ @Override
+ public boolean isEnabled(int position) {
+ return getItem(position).isEnabled();
+ }
+
+ @Override
+ public boolean areAllItemsEnabled() {
+ return false;
+ }
+
+ @Override
+ public Action getItem(int position) {
+ final boolean keyguardShowing = mKeyguardShowing.getAsBoolean();
+ final boolean deviceProvisioned = mDeviceProvisioned.getAsBoolean();
+
+ int filteredPos = 0;
+ for (int i = 0; i < mItems.size(); i++) {
+ final Action action = mItems.get(i);
+ if (keyguardShowing && !action.showDuringKeyguard()) {
+ continue;
+ }
+ if (!deviceProvisioned && !action.showBeforeProvisioning()) {
+ continue;
+ }
+ if (filteredPos == position) {
+ return action;
+ }
+ filteredPos++;
+ }
+
+ throw new IllegalArgumentException("position " + position
+ + " out of range of showable actions"
+ + ", filtered count=" + getCount()
+ + ", keyguardshowing=" + keyguardShowing
+ + ", provisioned=" + deviceProvisioned);
+ }
+
+ @Override
+ public long getItemId(int position) {
+ return position;
+ }
+
+ @Override
+ public View getView(int position, View convertView, ViewGroup parent) {
+ Action action = getItem(position);
+ return action.create(mContext, convertView, parent, LayoutInflater.from(mContext));
+ }
+}
diff --git a/core/java/com/android/internal/globalactions/ActionsDialog.java b/core/java/com/android/internal/globalactions/ActionsDialog.java
new file mode 100644
index 0000000..1cca1cc
--- /dev/null
+++ b/core/java/com/android/internal/globalactions/ActionsDialog.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.internal.globalactions;
+
+import android.app.Dialog;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.os.Bundle;
+import android.util.TypedValue;
+import android.view.accessibility.AccessibilityEvent;
+import android.view.KeyEvent;
+import android.widget.ListView;
+import com.android.internal.app.AlertController;
+
+/** A dialog that lists the given Action items to be user selectable. */
+public final class ActionsDialog extends Dialog implements DialogInterface {
+ private final Context mContext;
+ private final AlertController mAlert;
+ private final ActionsAdapter mAdapter;
+
+ public ActionsDialog(Context context, AlertController.AlertParams params) {
+ super(context, getDialogTheme(context));
+ mContext = getContext();
+ mAlert = AlertController.create(mContext, this, getWindow());
+ mAdapter = (ActionsAdapter) params.mAdapter;
+ params.apply(mAlert);
+ }
+
+ private static int getDialogTheme(Context context) {
+ TypedValue outValue = new TypedValue();
+ context.getTheme().resolveAttribute(com.android.internal.R.attr.alertDialogTheme,
+ outValue, true);
+ return outValue.resourceId;
+ }
+
+ @Override
+ protected void onStart() {
+ super.setCanceledOnTouchOutside(true);
+ super.onStart();
+ }
+
+ public ListView getListView() {
+ return mAlert.getListView();
+ }
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ mAlert.installContent();
+ }
+
+ @Override
+ public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {
+ if (event.getEventType() == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED) {
+ for (int i = 0; i < mAdapter.getCount(); ++i) {
+ CharSequence label =
+ mAdapter.getItem(i).getLabelForAccessibility(getContext());
+ if (label != null) {
+ event.getText().add(label);
+ }
+ }
+ }
+ return super.dispatchPopulateAccessibilityEvent(event);
+ }
+
+ @Override
+ public boolean onKeyDown(int keyCode, KeyEvent event) {
+ if (mAlert.onKeyDown(keyCode, event)) {
+ return true;
+ }
+ return super.onKeyDown(keyCode, event);
+ }
+
+ @Override
+ public boolean onKeyUp(int keyCode, KeyEvent event) {
+ if (mAlert.onKeyUp(keyCode, event)) {
+ return true;
+ }
+ return super.onKeyUp(keyCode, event);
+ }
+}
diff --git a/core/java/com/android/internal/globalactions/LongPressAction.java b/core/java/com/android/internal/globalactions/LongPressAction.java
new file mode 100644
index 0000000..eed4cd9
--- /dev/null
+++ b/core/java/com/android/internal/globalactions/LongPressAction.java
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.internal.globalactions;
+
+/** An action that also supports long press. */
+public interface LongPressAction extends Action {
+ boolean onLongPress();
+}
diff --git a/core/java/com/android/internal/globalactions/SinglePressAction.java b/core/java/com/android/internal/globalactions/SinglePressAction.java
new file mode 100644
index 0000000..0b8cd0b
--- /dev/null
+++ b/core/java/com/android/internal/globalactions/SinglePressAction.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.internal.globalactions;
+
+import android.content.Context;
+import android.graphics.drawable.Drawable;
+import android.text.TextUtils;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ImageView;
+import android.widget.TextView;
+import com.android.internal.R;
+
+/** A single press action maintains no state, just responds to a press and takes an action. */
+public abstract class SinglePressAction implements Action {
+ private final int mIconResId;
+ private final Drawable mIcon;
+ private final int mMessageResId;
+ private final CharSequence mMessage;
+
+ protected SinglePressAction(int iconResId, int messageResId) {
+ mIconResId = iconResId;
+ mMessageResId = messageResId;
+ mMessage = null;
+ mIcon = null;
+ }
+
+ protected SinglePressAction(int iconResId, Drawable icon, CharSequence message) {
+ mIconResId = iconResId;
+ mMessageResId = 0;
+ mMessage = message;
+ mIcon = icon;
+ }
+
+ @Override
+ public boolean isEnabled() {
+ return true;
+ }
+
+ public String getStatus() {
+ return null;
+ }
+
+ @Override
+ abstract public void onPress();
+
+ @Override
+ public CharSequence getLabelForAccessibility(Context context) {
+ if (mMessage != null) {
+ return mMessage;
+ } else {
+ return context.getString(mMessageResId);
+ }
+ }
+
+ @Override
+ public View create(
+ Context context, View convertView, ViewGroup parent, LayoutInflater inflater) {
+ View v = inflater.inflate(R.layout.global_actions_item, parent, false);
+
+ ImageView icon = v.findViewById(R.id.icon);
+ TextView messageView = v.findViewById(R.id.message);
+
+ TextView statusView = v.findViewById(R.id.status);
+ final String status = getStatus();
+ if (!TextUtils.isEmpty(status)) {
+ statusView.setText(status);
+ } else {
+ statusView.setVisibility(View.GONE);
+ }
+ if (mIcon != null) {
+ icon.setImageDrawable(mIcon);
+ icon.setScaleType(ImageView.ScaleType.CENTER_CROP);
+ } else if (mIconResId != 0) {
+ icon.setImageDrawable(context.getDrawable(mIconResId));
+ }
+ if (mMessage != null) {
+ messageView.setText(mMessage);
+ } else {
+ messageView.setText(mMessageResId);
+ }
+
+ return v;
+ }
+}
diff --git a/core/java/com/android/internal/globalactions/ToggleAction.java b/core/java/com/android/internal/globalactions/ToggleAction.java
new file mode 100644
index 0000000..9167958
--- /dev/null
+++ b/core/java/com/android/internal/globalactions/ToggleAction.java
@@ -0,0 +1,155 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.internal.globalactions;
+
+import android.content.Context;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ImageView;
+import android.widget.TextView;
+import com.android.internal.R;
+
+/**
+ * A toggle action knows whether it is on or off, and displays an icon and status message
+ * accordingly.
+ */
+public abstract class ToggleAction implements Action {
+ private static final String TAG = "ToggleAction";
+
+ public enum State {
+ Off(false),
+ TurningOn(true),
+ TurningOff(true),
+ On(false);
+
+ private final boolean inTransition;
+
+ State(boolean intermediate) {
+ inTransition = intermediate;
+ }
+
+ public boolean inTransition() {
+ return inTransition;
+ }
+ }
+
+ protected State mState = State.Off;
+
+ // prefs
+ protected int mEnabledIconResId;
+ protected int mDisabledIconResid;
+ protected int mMessageResId;
+ protected int mEnabledStatusMessageResId;
+ protected int mDisabledStatusMessageResId;
+
+ /**
+ * @param enabledIconResId The icon for when this action is on.
+ * @param disabledIconResid The icon for when this action is off.
+ * @param message The general information message, e.g 'Silent Mode'
+ * @param enabledStatusMessageResId The on status message, e.g 'sound disabled'
+ * @param disabledStatusMessageResId The off status message, e.g. 'sound enabled'
+ */
+ public ToggleAction(int enabledIconResId,
+ int disabledIconResid,
+ int message,
+ int enabledStatusMessageResId,
+ int disabledStatusMessageResId) {
+ mEnabledIconResId = enabledIconResId;
+ mDisabledIconResid = disabledIconResid;
+ mMessageResId = message;
+ mEnabledStatusMessageResId = enabledStatusMessageResId;
+ mDisabledStatusMessageResId = disabledStatusMessageResId;
+ }
+
+ /** Override to make changes to resource IDs just before creating the View. */
+ void willCreate() {
+
+ }
+
+ @Override
+ public CharSequence getLabelForAccessibility(Context context) {
+ return context.getString(mMessageResId);
+ }
+
+ @Override
+ public View create(Context context, View convertView, ViewGroup parent,
+ LayoutInflater inflater) {
+ willCreate();
+
+ View v = inflater.inflate(R.layout.global_actions_item, parent, false);
+
+ ImageView icon = v.findViewById(R.id.icon);
+ TextView messageView = v.findViewById(R.id.message);
+ TextView statusView = v.findViewById(R.id.status);
+ final boolean enabled = isEnabled();
+
+ if (messageView != null) {
+ messageView.setText(mMessageResId);
+ messageView.setEnabled(enabled);
+ }
+
+ boolean on = ((mState == State.On) || (mState == State.TurningOn));
+ if (icon != null) {
+ icon.setImageDrawable(context.getDrawable(
+ (on ? mEnabledIconResId : mDisabledIconResid)));
+ icon.setEnabled(enabled);
+ }
+
+ if (statusView != null) {
+ statusView.setText(on ? mEnabledStatusMessageResId : mDisabledStatusMessageResId);
+ statusView.setVisibility(View.VISIBLE);
+ statusView.setEnabled(enabled);
+ }
+ v.setEnabled(enabled);
+
+ return v;
+ }
+
+ @Override
+ public final void onPress() {
+ if (mState.inTransition()) {
+ Log.w(TAG, "shouldn't be able to toggle when in transition");
+ return;
+ }
+
+ final boolean nowOn = !(mState == State.On);
+ onToggle(nowOn);
+ changeStateFromPress(nowOn);
+ }
+
+ @Override
+ public boolean isEnabled() {
+ return !mState.inTransition();
+ }
+
+ /**
+ * Implementations may override this if their state can be in on of the intermediate
+ * states until some notification is received (e.g airplane mode is 'turning off' until
+ * we know the wireless connections are back online
+ * @param buttonOn Whether the button was turned on or off
+ */
+ protected void changeStateFromPress(boolean buttonOn) {
+ mState = buttonOn ? State.On : State.Off;
+ }
+
+ public abstract void onToggle(boolean on);
+
+ public void updateState(State state) {
+ mState = state;
+ }
+}
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 242f422..4ab2fec 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -7872,12 +7872,10 @@
return;
}
final int deferredCount = mJobsDeferredCount.getCountLocked(which);
- final long averageLatency = deferredEventCount != 0
- ? mJobsFreshnessTimeMs.getCountLocked(which) / deferredEventCount
- : 0L;
+ final long totalLatency = mJobsFreshnessTimeMs.getCountLocked(which);
sb.append(deferredEventCount); sb.append(',');
sb.append(deferredCount); sb.append(',');
- sb.append(averageLatency);
+ sb.append(totalLatency);
for (int i = 0; i < JOB_FRESHNESS_BUCKETS.length; i++) {
if (mJobsFreshnessBuckets[i] == null) {
sb.append(",0");
@@ -7896,12 +7894,10 @@
return;
}
final int deferredCount = mJobsDeferredCount.getCountLocked(which);
- final long averageLatency = deferredEventCount != 0
- ? mJobsFreshnessTimeMs.getCountLocked(which) / deferredEventCount
- : 0L;
+ final long totalLatency = mJobsFreshnessTimeMs.getCountLocked(which);
sb.append("times="); sb.append(deferredEventCount); sb.append(", ");
sb.append("count="); sb.append(deferredCount); sb.append(", ");
- sb.append("avgLatency="); sb.append(averageLatency); sb.append(", ");
+ sb.append("totalLatencyMs="); sb.append(totalLatency); sb.append(", ");
for (int i = 0; i < JOB_FRESHNESS_BUCKETS.length; i++) {
sb.append("<"); sb.append(JOB_FRESHNESS_BUCKETS[i]); sb.append("ms=");
if (mJobsFreshnessBuckets[i] == null) {
diff --git a/core/java/com/android/internal/os/logging/MetricsLoggerWrapper.java b/core/java/com/android/internal/os/logging/MetricsLoggerWrapper.java
index adad036..bfe3780 100644
--- a/core/java/com/android/internal/os/logging/MetricsLoggerWrapper.java
+++ b/core/java/com/android/internal/os/logging/MetricsLoggerWrapper.java
@@ -21,6 +21,7 @@
import android.content.pm.PackageManager.NameNotFoundException;
import android.util.Pair;
import android.util.StatsLog;
+import android.view.WindowManager.LayoutParams;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
@@ -103,13 +104,27 @@
StatsLog.PICTURE_IN_PICTURE_STATE_CHANGED__STATE__EXPANDED_TO_FULL_SCREEN);
}
- public static void logAppOverlayEnter(int uid, String packageName, boolean usingAlertWindow) {
- StatsLog.write(StatsLog.OVERLAY_STATE_CHANGED, uid, packageName, usingAlertWindow,
- StatsLog.OVERLAY_STATE_CHANGED__STATE__ENTERED);
+ public static void logAppOverlayEnter(int uid, String packageName, boolean changed, int type, boolean usingAlertWindow) {
+ if (changed) {
+ if (type != LayoutParams.TYPE_APPLICATION_OVERLAY) {
+ StatsLog.write(StatsLog.OVERLAY_STATE_CHANGED, uid, packageName, true,
+ StatsLog.OVERLAY_STATE_CHANGED__STATE__ENTERED);
+ } else if (!usingAlertWindow){
+ StatsLog.write(StatsLog.OVERLAY_STATE_CHANGED, uid, packageName, false,
+ StatsLog.OVERLAY_STATE_CHANGED__STATE__ENTERED);
+ }
+ }
}
- public static void logAppOverlayExit(int uid, String packageName, boolean usingAlertWindow) {
- StatsLog.write(StatsLog.OVERLAY_STATE_CHANGED, uid, packageName, usingAlertWindow,
- StatsLog.OVERLAY_STATE_CHANGED__STATE__EXITED);
+ public static void logAppOverlayExit(int uid, String packageName, boolean changed, int type, boolean usingAlertWindow) {
+ if (changed) {
+ if (type != LayoutParams.TYPE_APPLICATION_OVERLAY) {
+ StatsLog.write(StatsLog.OVERLAY_STATE_CHANGED, uid, packageName, true,
+ StatsLog.OVERLAY_STATE_CHANGED__STATE__EXITED);
+ } else if (!usingAlertWindow){
+ StatsLog.write(StatsLog.OVERLAY_STATE_CHANGED, uid, packageName, false,
+ StatsLog.OVERLAY_STATE_CHANGED__STATE__EXITED);
+ }
+ }
}
}
diff --git a/core/java/com/android/internal/textservice/LazyIntToIntMap.java b/core/java/com/android/internal/textservice/LazyIntToIntMap.java
new file mode 100644
index 0000000..ca9936c
--- /dev/null
+++ b/core/java/com/android/internal/textservice/LazyIntToIntMap.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.textservice;
+
+import android.annotation.NonNull;
+import android.util.SparseIntArray;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.util.function.IntUnaryOperator;
+
+/**
+ * Simple int-to-int key-value-store that is to be lazily initialized with the given
+ * {@link IntUnaryOperator}.
+ */
+@VisibleForTesting
+public final class LazyIntToIntMap {
+
+ private final SparseIntArray mMap = new SparseIntArray();
+
+ @NonNull
+ private final IntUnaryOperator mMappingFunction;
+
+ /**
+ * @param mappingFunction int to int mapping rules to be (lazily) evaluated
+ */
+ public LazyIntToIntMap(@NonNull IntUnaryOperator mappingFunction) {
+ mMappingFunction = mappingFunction;
+ }
+
+ /**
+ * Deletes {@code key} and associated value.
+ * @param key key to be deleted
+ */
+ public void delete(int key) {
+ mMap.delete(key);
+ }
+
+ /**
+ * @param key key associated with the value
+ * @return value associated with the {@code key}. If this is the first time to access
+ * {@code key}, then {@code mappingFunction} passed to the constructor will be evaluated
+ */
+ public int get(int key) {
+ final int index = mMap.indexOfKey(key);
+ if (index >= 0) {
+ return mMap.valueAt(index);
+ }
+ final int value = mMappingFunction.applyAsInt(key);
+ mMap.append(key, value);
+ return value;
+ }
+}
diff --git a/core/java/com/android/internal/view/IInputConnectionWrapper.java b/core/java/com/android/internal/view/IInputConnectionWrapper.java
index e08caa8..28291ae 100644
--- a/core/java/com/android/internal/view/IInputConnectionWrapper.java
+++ b/core/java/com/android/internal/view/IInputConnectionWrapper.java
@@ -23,7 +23,6 @@
import android.annotation.Nullable;
import android.os.Bundle;
import android.os.Handler;
-import android.os.LocaleList;
import android.os.Looper;
import android.os.Message;
import android.os.RemoteException;
@@ -65,7 +64,6 @@
private static final int DO_REQUEST_UPDATE_CURSOR_ANCHOR_INFO = 140;
private static final int DO_CLOSE_CONNECTION = 150;
private static final int DO_COMMIT_CONTENT = 160;
- private static final int DO_REPORT_LANGUAGE_HINT = 170;
@GuardedBy("mLock")
@Nullable
@@ -219,10 +217,6 @@
callback));
}
- public void reportLanguageHint(@NonNull LocaleList languageHint) {
- dispatchMessage(obtainMessageO(DO_REPORT_LANGUAGE_HINT, languageHint));
- }
-
void dispatchMessage(Message msg) {
// If we are calling this from the main thread, then we can call
// right through. Otherwise, we need to send the message to the
@@ -583,16 +577,6 @@
}
return;
}
- case DO_REPORT_LANGUAGE_HINT: {
- final LocaleList languageHint = (LocaleList) msg.obj;
- final InputConnection ic = getInputConnection();
- if (ic == null || !isActive()) {
- Log.w(TAG, "reportLanguageHint on inactive InputConnection");
- return;
- }
- ic.reportLanguageHint(languageHint);
- return;
- }
}
Log.w(TAG, "Unhandled message code: " + msg.what);
}
diff --git a/core/java/com/android/internal/view/IInputContext.aidl b/core/java/com/android/internal/view/IInputContext.aidl
index e69a87ff..c227991 100644
--- a/core/java/com/android/internal/view/IInputContext.aidl
+++ b/core/java/com/android/internal/view/IInputContext.aidl
@@ -17,7 +17,6 @@
package com.android.internal.view;
import android.os.Bundle;
-import android.os.LocaleList;
import android.view.KeyEvent;
import android.view.inputmethod.CompletionInfo;
import android.view.inputmethod.CorrectionInfo;
@@ -79,6 +78,4 @@
void commitContent(in InputContentInfo inputContentInfo, int flags, in Bundle opts, int sec,
IInputContextCallback callback);
-
- void reportLanguageHint(in LocaleList languageHint);
}
diff --git a/core/java/com/android/internal/view/InputConnectionWrapper.java b/core/java/com/android/internal/view/InputConnectionWrapper.java
index 34be598..5b65bbe 100644
--- a/core/java/com/android/internal/view/InputConnectionWrapper.java
+++ b/core/java/com/android/internal/view/InputConnectionWrapper.java
@@ -22,7 +22,6 @@
import android.inputmethodservice.AbstractInputMethodService;
import android.os.Bundle;
import android.os.Handler;
-import android.os.LocaleList;
import android.os.RemoteException;
import android.os.SystemClock;
import android.util.Log;
@@ -621,14 +620,6 @@
}
@AnyThread
- public void reportLanguageHint(@NonNull LocaleList languageHint) {
- try {
- mIInputContext.reportLanguageHint(languageHint);
- } catch (RemoteException e) {
- }
- }
-
- @AnyThread
private boolean isMethodMissing(@MissingMethodFlags final int methodFlag) {
return (mMissingMethods & methodFlag) == methodFlag;
}
diff --git a/core/jni/Android.bp b/core/jni/Android.bp
index b048977..1d22093 100644
--- a/core/jni/Android.bp
+++ b/core/jni/Android.bp
@@ -110,8 +110,8 @@
"android_util_AssetManager.cpp",
"android_util_Binder.cpp",
"android_util_EventLog.cpp",
- "android_util_MemoryIntArray.cpp",
"android_util_Log.cpp",
+ "android_util_MemoryIntArray.cpp",
"android_util_PathParser.cpp",
"android_util_Process.cpp",
"android_util_StringBlock.cpp",
@@ -191,6 +191,7 @@
"android_backup_FileBackupHelperBase.cpp",
"android_backup_BackupHelperDispatcher.cpp",
"android_app_backup_FullBackup.cpp",
+ "android_content_res_ApkAssets.cpp",
"android_content_res_ObbScanner.cpp",
"android_content_res_Configuration.cpp",
"android_animation_PropertyValuesHolder.cpp",
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index f280c7a..5ae4a52 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -123,6 +123,7 @@
extern int register_android_util_PathParser(JNIEnv* env);
extern int register_android_content_StringBlock(JNIEnv* env);
extern int register_android_content_XmlBlock(JNIEnv* env);
+extern int register_android_content_res_ApkAssets(JNIEnv* env);
extern int register_android_graphics_Canvas(JNIEnv* env);
extern int register_android_graphics_CanvasProperty(JNIEnv* env);
extern int register_android_graphics_ColorFilter(JNIEnv* env);
@@ -1346,6 +1347,7 @@
REG_JNI(register_android_content_AssetManager),
REG_JNI(register_android_content_StringBlock),
REG_JNI(register_android_content_XmlBlock),
+ REG_JNI(register_android_content_res_ApkAssets),
REG_JNI(register_android_text_AndroidCharacter),
REG_JNI(register_android_text_Hyphenator),
REG_JNI(register_android_text_MeasuredParagraph),
diff --git a/core/jni/android/graphics/FontFamily.cpp b/core/jni/android/graphics/FontFamily.cpp
index 48aef4a..ed032c7 100644
--- a/core/jni/android/graphics/FontFamily.cpp
+++ b/core/jni/android/graphics/FontFamily.cpp
@@ -28,7 +28,7 @@
#include <nativehelper/ScopedUtfChars.h>
#include <android_runtime/AndroidRuntime.h>
#include <android_runtime/android_util_AssetManager.h>
-#include <androidfw/AssetManager.h>
+#include <androidfw/AssetManager2.h>
#include "Utils.h"
#include "FontUtils.h"
@@ -205,7 +205,8 @@
NPE_CHECK_RETURN_ZERO(env, jpath);
NativeFamilyBuilder* builder = reinterpret_cast<NativeFamilyBuilder*>(builderPtr);
- AssetManager* mgr = assetManagerForJavaObject(env, jassetMgr);
+
+ Guarded<AssetManager2>* mgr = AssetManagerForJavaObject(env, jassetMgr);
if (NULL == mgr) {
builder->axes.clear();
return false;
@@ -217,27 +218,33 @@
return false;
}
- Asset* asset;
- if (isAsset) {
- asset = mgr->open(str.c_str(), Asset::ACCESS_BUFFER);
- } else {
- asset = cookie ? mgr->openNonAsset(static_cast<int32_t>(cookie), str.c_str(),
- Asset::ACCESS_BUFFER) : mgr->openNonAsset(str.c_str(), Asset::ACCESS_BUFFER);
+ std::unique_ptr<Asset> asset;
+ {
+ ScopedLock<AssetManager2> locked_mgr(*mgr);
+ if (isAsset) {
+ asset = locked_mgr->Open(str.c_str(), Asset::ACCESS_BUFFER);
+ } else if (cookie > 0) {
+ // Valid java cookies are 1-based, but AssetManager cookies are 0-based.
+ asset = locked_mgr->OpenNonAsset(str.c_str(), static_cast<ApkAssetsCookie>(cookie - 1),
+ Asset::ACCESS_BUFFER);
+ } else {
+ asset = locked_mgr->OpenNonAsset(str.c_str(), Asset::ACCESS_BUFFER);
+ }
}
- if (NULL == asset) {
+ if (nullptr == asset) {
builder->axes.clear();
return false;
}
const void* buf = asset->getBuffer(false);
if (NULL == buf) {
- delete asset;
builder->axes.clear();
return false;
}
- sk_sp<SkData> data(SkData::MakeWithProc(buf, asset->getLength(), releaseAsset, asset));
+ sk_sp<SkData> data(SkData::MakeWithProc(buf, asset->getLength(), releaseAsset,
+ asset.release()));
return addSkTypeface(builder, std::move(data), ttcIndex, weight, isItalic);
}
diff --git a/core/jni/android_app_NativeActivity.cpp b/core/jni/android_app_NativeActivity.cpp
index 09e37e1..49a24a3 100644
--- a/core/jni/android_app_NativeActivity.cpp
+++ b/core/jni/android_app_NativeActivity.cpp
@@ -361,7 +361,7 @@
code->sdkVersion = sdkVersion;
code->javaAssetManager = env->NewGlobalRef(jAssetMgr);
- code->assetManager = assetManagerForJavaObject(env, jAssetMgr);
+ code->assetManager = NdkAssetManagerForJavaObject(env, jAssetMgr);
if (obbDir != NULL) {
dirStr = env->GetStringUTFChars(obbDir, NULL);
diff --git a/core/jni/android_content_res_ApkAssets.cpp b/core/jni/android_content_res_ApkAssets.cpp
new file mode 100644
index 0000000..7738d84
--- /dev/null
+++ b/core/jni/android_content_res_ApkAssets.cpp
@@ -0,0 +1,157 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define ATRACE_TAG ATRACE_TAG_RESOURCES
+
+#include "android-base/macros.h"
+#include "android-base/stringprintf.h"
+#include "android-base/unique_fd.h"
+#include "androidfw/ApkAssets.h"
+#include "utils/misc.h"
+#include "utils/Trace.h"
+
+#include "core_jni_helpers.h"
+#include "jni.h"
+#include "nativehelper/ScopedUtfChars.h"
+
+using ::android::base::unique_fd;
+
+namespace android {
+
+static jlong NativeLoad(JNIEnv* env, jclass /*clazz*/, jstring java_path, jboolean system,
+ jboolean force_shared_lib, jboolean overlay) {
+ ScopedUtfChars path(env, java_path);
+ if (path.c_str() == nullptr) {
+ return 0;
+ }
+
+ ATRACE_NAME(base::StringPrintf("LoadApkAssets(%s)", path.c_str()).c_str());
+
+ std::unique_ptr<const ApkAssets> apk_assets;
+ if (overlay) {
+ apk_assets = ApkAssets::LoadOverlay(path.c_str(), system);
+ } else if (force_shared_lib) {
+ apk_assets = ApkAssets::LoadAsSharedLibrary(path.c_str(), system);
+ } else {
+ apk_assets = ApkAssets::Load(path.c_str(), system);
+ }
+
+ if (apk_assets == nullptr) {
+ std::string error_msg = base::StringPrintf("Failed to load asset path %s", path.c_str());
+ jniThrowException(env, "java/io/IOException", error_msg.c_str());
+ return 0;
+ }
+ return reinterpret_cast<jlong>(apk_assets.release());
+}
+
+static jlong NativeLoadFromFd(JNIEnv* env, jclass /*clazz*/, jobject file_descriptor,
+ jstring friendly_name, jboolean system, jboolean force_shared_lib) {
+ ScopedUtfChars friendly_name_utf8(env, friendly_name);
+ if (friendly_name_utf8.c_str() == nullptr) {
+ return 0;
+ }
+
+ ATRACE_NAME(base::StringPrintf("LoadApkAssetsFd(%s)", friendly_name_utf8.c_str()).c_str());
+
+ int fd = jniGetFDFromFileDescriptor(env, file_descriptor);
+ if (fd < 0) {
+ jniThrowException(env, "java/lang/IllegalArgumentException", "Bad FileDescriptor");
+ return 0;
+ }
+
+ unique_fd dup_fd(::dup(fd));
+ if (dup_fd < 0) {
+ jniThrowIOException(env, errno);
+ return 0;
+ }
+
+ std::unique_ptr<const ApkAssets> apk_assets = ApkAssets::LoadFromFd(std::move(dup_fd),
+ friendly_name_utf8.c_str(),
+ system, force_shared_lib);
+ if (apk_assets == nullptr) {
+ std::string error_msg = base::StringPrintf("Failed to load asset path %s from fd %d",
+ friendly_name_utf8.c_str(), dup_fd.get());
+ jniThrowException(env, "java/io/IOException", error_msg.c_str());
+ return 0;
+ }
+ return reinterpret_cast<jlong>(apk_assets.release());
+}
+
+static void NativeDestroy(JNIEnv* /*env*/, jclass /*clazz*/, jlong ptr) {
+ delete reinterpret_cast<ApkAssets*>(ptr);
+}
+
+static jstring NativeGetAssetPath(JNIEnv* env, jclass /*clazz*/, jlong ptr) {
+ const ApkAssets* apk_assets = reinterpret_cast<const ApkAssets*>(ptr);
+ return env->NewStringUTF(apk_assets->GetPath().c_str());
+}
+
+static jlong NativeGetStringBlock(JNIEnv* /*env*/, jclass /*clazz*/, jlong ptr) {
+ const ApkAssets* apk_assets = reinterpret_cast<const ApkAssets*>(ptr);
+ return reinterpret_cast<jlong>(apk_assets->GetLoadedArsc()->GetStringPool());
+}
+
+static jboolean NativeIsUpToDate(JNIEnv* /*env*/, jclass /*clazz*/, jlong ptr) {
+ const ApkAssets* apk_assets = reinterpret_cast<const ApkAssets*>(ptr);
+ (void)apk_assets;
+ return JNI_TRUE;
+}
+
+static jlong NativeOpenXml(JNIEnv* env, jclass /*clazz*/, jlong ptr, jstring file_name) {
+ ScopedUtfChars path_utf8(env, file_name);
+ if (path_utf8.c_str() == nullptr) {
+ return 0;
+ }
+
+ const ApkAssets* apk_assets = reinterpret_cast<const ApkAssets*>(ptr);
+ std::unique_ptr<Asset> asset = apk_assets->Open(path_utf8.c_str(),
+ Asset::AccessMode::ACCESS_RANDOM);
+ if (asset == nullptr) {
+ jniThrowException(env, "java/io/FileNotFoundException", path_utf8.c_str());
+ return 0;
+ }
+
+ // DynamicRefTable is only needed when looking up resource references. Opening an XML file
+ // directly from an ApkAssets has no notion of proper resource references.
+ std::unique_ptr<ResXMLTree> xml_tree = util::make_unique<ResXMLTree>(nullptr /*dynamicRefTable*/);
+ status_t err = xml_tree->setTo(asset->getBuffer(true), asset->getLength(), true);
+ asset.reset();
+
+ if (err != NO_ERROR) {
+ jniThrowException(env, "java/io/FileNotFoundException", "Corrupt XML binary file");
+ return 0;
+ }
+ return reinterpret_cast<jlong>(xml_tree.release());
+}
+
+// JNI registration.
+static const JNINativeMethod gApkAssetsMethods[] = {
+ {"nativeLoad", "(Ljava/lang/String;ZZZ)J", (void*)NativeLoad},
+ {"nativeLoadFromFd", "(Ljava/io/FileDescriptor;Ljava/lang/String;ZZ)J",
+ (void*)NativeLoadFromFd},
+ {"nativeDestroy", "(J)V", (void*)NativeDestroy},
+ {"nativeGetAssetPath", "(J)Ljava/lang/String;", (void*)NativeGetAssetPath},
+ {"nativeGetStringBlock", "(J)J", (void*)NativeGetStringBlock},
+ {"nativeIsUpToDate", "(J)Z", (void*)NativeIsUpToDate},
+ {"nativeOpenXml", "(JLjava/lang/String;)J", (void*)NativeOpenXml},
+};
+
+int register_android_content_res_ApkAssets(JNIEnv* env) {
+ return RegisterMethodsOrDie(env, "android/content/res/ApkAssets", gApkAssetsMethods,
+ arraysize(gApkAssetsMethods));
+}
+
+} // namespace android
diff --git a/core/jni/android_util_AssetManager.cpp b/core/jni/android_util_AssetManager.cpp
index 683b4c4..8be6ed8 100644
--- a/core/jni/android_util_AssetManager.cpp
+++ b/core/jni/android_util_AssetManager.cpp
@@ -1,1851 +1,1449 @@
-/* //device/libs/android_runtime/android_util_AssetManager.cpp
-**
-** Copyright 2006, 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.
-*/
+/*
+ * Copyright 2006, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#define ATRACE_TAG ATRACE_TAG_RESOURCES
#define LOG_TAG "asset"
-#include <android_runtime/android_util_AssetManager.h>
-
#include <inttypes.h>
#include <linux/capability.h>
#include <stdio.h>
-#include <sys/types.h>
-#include <sys/wait.h>
#include <sys/stat.h>
#include <sys/system_properties.h>
+#include <sys/types.h>
+#include <sys/wait.h>
#include <private/android_filesystem_config.h> // for AID_SYSTEM
-#include "androidfw/Asset.h"
-#include "androidfw/AssetManager.h"
-#include "androidfw/AttributeResolution.h"
-#include "androidfw/ResourceTypes.h"
+#include "android-base/logging.h"
+#include "android-base/properties.h"
+#include "android-base/stringprintf.h"
+#include "android_runtime/android_util_AssetManager.h"
#include "android_runtime/AndroidRuntime.h"
#include "android_util_Binder.h"
+#include "androidfw/Asset.h"
+#include "androidfw/AssetManager.h"
+#include "androidfw/AssetManager2.h"
+#include "androidfw/AttributeResolution.h"
+#include "androidfw/MutexGuard.h"
+#include "androidfw/ResourceTypes.h"
#include "core_jni_helpers.h"
#include "jni.h"
-#include <nativehelper/JNIHelp.h>
-#include <nativehelper/ScopedStringChars.h>
-#include <nativehelper/ScopedUtfChars.h>
+#include "nativehelper/JNIHelp.h"
+#include "nativehelper/ScopedPrimitiveArray.h"
+#include "nativehelper/ScopedStringChars.h"
+#include "nativehelper/ScopedUtfChars.h"
#include "utils/Log.h"
#include "utils/misc.h"
#include "utils/String8.h"
+#include "utils/Trace.h"
extern "C" int capget(cap_user_header_t hdrp, cap_user_data_t datap);
extern "C" int capset(cap_user_header_t hdrp, const cap_user_data_t datap);
+using ::android::base::StringPrintf;
namespace android {
-static const bool kThrowOnBadId = false;
-
// ----------------------------------------------------------------------------
-static struct typedvalue_offsets_t
-{
- jfieldID mType;
- jfieldID mData;
- jfieldID mString;
- jfieldID mAssetCookie;
- jfieldID mResourceId;
- jfieldID mChangingConfigurations;
- jfieldID mDensity;
+static struct typedvalue_offsets_t {
+ jfieldID mType;
+ jfieldID mData;
+ jfieldID mString;
+ jfieldID mAssetCookie;
+ jfieldID mResourceId;
+ jfieldID mChangingConfigurations;
+ jfieldID mDensity;
} gTypedValueOffsets;
-static struct assetfiledescriptor_offsets_t
-{
- jfieldID mFd;
- jfieldID mStartOffset;
- jfieldID mLength;
+static struct assetfiledescriptor_offsets_t {
+ jfieldID mFd;
+ jfieldID mStartOffset;
+ jfieldID mLength;
} gAssetFileDescriptorOffsets;
-static struct assetmanager_offsets_t
-{
- jfieldID mObject;
+static struct assetmanager_offsets_t {
+ jfieldID mObject;
} gAssetManagerOffsets;
-static struct sparsearray_offsets_t
-{
- jclass classObject;
- jmethodID constructor;
- jmethodID put;
+static struct {
+ jfieldID native_ptr;
+} gApkAssetsFields;
+
+static struct sparsearray_offsets_t {
+ jclass classObject;
+ jmethodID constructor;
+ jmethodID put;
} gSparseArrayOffsets;
-static struct configuration_offsets_t
-{
- jclass classObject;
- jmethodID constructor;
- jfieldID mSmallestScreenWidthDpOffset;
- jfieldID mScreenWidthDpOffset;
- jfieldID mScreenHeightDpOffset;
+static struct configuration_offsets_t {
+ jclass classObject;
+ jmethodID constructor;
+ jfieldID mSmallestScreenWidthDpOffset;
+ jfieldID mScreenWidthDpOffset;
+ jfieldID mScreenHeightDpOffset;
} gConfigurationOffsets;
-jclass g_stringClass = NULL;
+jclass g_stringClass = nullptr;
// ----------------------------------------------------------------------------
-static jint copyValue(JNIEnv* env, jobject outValue, const ResTable* table,
- const Res_value& value, uint32_t ref, ssize_t block,
- uint32_t typeSpecFlags, ResTable_config* config = NULL);
+// Java asset cookies have 0 as an invalid cookie, but TypedArray expects < 0.
+constexpr inline static jint ApkAssetsCookieToJavaCookie(ApkAssetsCookie cookie) {
+ return cookie != kInvalidCookie ? static_cast<jint>(cookie + 1) : -1;
+}
-jint copyValue(JNIEnv* env, jobject outValue, const ResTable* table,
- const Res_value& value, uint32_t ref, ssize_t block,
- uint32_t typeSpecFlags, ResTable_config* config)
-{
- env->SetIntField(outValue, gTypedValueOffsets.mType, value.dataType);
- env->SetIntField(outValue, gTypedValueOffsets.mAssetCookie,
- static_cast<jint>(table->getTableCookie(block)));
- env->SetIntField(outValue, gTypedValueOffsets.mData, value.data);
- env->SetObjectField(outValue, gTypedValueOffsets.mString, NULL);
- env->SetIntField(outValue, gTypedValueOffsets.mResourceId, ref);
- env->SetIntField(outValue, gTypedValueOffsets.mChangingConfigurations,
- typeSpecFlags);
- if (config != NULL) {
- env->SetIntField(outValue, gTypedValueOffsets.mDensity, config->density);
- }
- return block;
+constexpr inline static ApkAssetsCookie JavaCookieToApkAssetsCookie(jint cookie) {
+ return cookie > 0 ? static_cast<ApkAssetsCookie>(cookie - 1) : kInvalidCookie;
}
// This is called by zygote (running as user root) as part of preloadResources.
-static void verifySystemIdmaps()
-{
- pid_t pid;
- char system_id[10];
+static void NativeVerifySystemIdmaps(JNIEnv* /*env*/, jclass /*clazz*/) {
+ switch (pid_t pid = fork()) {
+ case -1:
+ PLOG(ERROR) << "failed to fork for idmap";
+ break;
- snprintf(system_id, sizeof(system_id), "%d", AID_SYSTEM);
+ // child
+ case 0: {
+ struct __user_cap_header_struct capheader;
+ struct __user_cap_data_struct capdata;
- switch (pid = fork()) {
- case -1:
- ALOGE("failed to fork for idmap: %s", strerror(errno));
- break;
- case 0: // child
- {
- struct __user_cap_header_struct capheader;
- struct __user_cap_data_struct capdata;
+ memset(&capheader, 0, sizeof(capheader));
+ memset(&capdata, 0, sizeof(capdata));
- memset(&capheader, 0, sizeof(capheader));
- memset(&capdata, 0, sizeof(capdata));
+ capheader.version = _LINUX_CAPABILITY_VERSION;
+ capheader.pid = 0;
- capheader.version = _LINUX_CAPABILITY_VERSION;
- capheader.pid = 0;
+ if (capget(&capheader, &capdata) != 0) {
+ PLOG(ERROR) << "capget";
+ exit(1);
+ }
- if (capget(&capheader, &capdata) != 0) {
- ALOGE("capget: %s\n", strerror(errno));
- exit(1);
- }
+ capdata.effective = capdata.permitted;
+ if (capset(&capheader, &capdata) != 0) {
+ PLOG(ERROR) << "capset";
+ exit(1);
+ }
- capdata.effective = capdata.permitted;
- if (capset(&capheader, &capdata) != 0) {
- ALOGE("capset: %s\n", strerror(errno));
- exit(1);
- }
+ if (setgid(AID_SYSTEM) != 0) {
+ PLOG(ERROR) << "setgid";
+ exit(1);
+ }
- if (setgid(AID_SYSTEM) != 0) {
- ALOGE("setgid: %s\n", strerror(errno));
- exit(1);
- }
+ if (setuid(AID_SYSTEM) != 0) {
+ PLOG(ERROR) << "setuid";
+ exit(1);
+ }
- if (setuid(AID_SYSTEM) != 0) {
- ALOGE("setuid: %s\n", strerror(errno));
- exit(1);
- }
+ // Generic idmap parameters
+ const char* argv[8];
+ int argc = 0;
+ struct stat st;
- // Generic idmap parameters
- const char* argv[8];
- int argc = 0;
- struct stat st;
+ memset(argv, 0, sizeof(argv));
+ argv[argc++] = AssetManager::IDMAP_BIN;
+ argv[argc++] = "--scan";
+ argv[argc++] = AssetManager::TARGET_PACKAGE_NAME;
+ argv[argc++] = AssetManager::TARGET_APK_PATH;
+ argv[argc++] = AssetManager::IDMAP_DIR;
- memset(argv, NULL, sizeof(argv));
- argv[argc++] = AssetManager::IDMAP_BIN;
- argv[argc++] = "--scan";
- argv[argc++] = AssetManager::TARGET_PACKAGE_NAME;
- argv[argc++] = AssetManager::TARGET_APK_PATH;
- argv[argc++] = AssetManager::IDMAP_DIR;
-
- // Directories to scan for overlays: if OVERLAY_THEME_DIR_PROPERTY is defined,
- // use OVERLAY_DIR/<value of OVERLAY_THEME_DIR_PROPERTY> in addition to OVERLAY_DIR.
- char subdir[PROP_VALUE_MAX];
- int len = __system_property_get(AssetManager::OVERLAY_THEME_DIR_PROPERTY, subdir);
- if (len > 0) {
- String8 overlayPath = String8(AssetManager::OVERLAY_DIR) + "/" + subdir;
- if (stat(overlayPath.string(), &st) == 0) {
- argv[argc++] = overlayPath.string();
- }
- }
- if (stat(AssetManager::OVERLAY_DIR, &st) == 0) {
- argv[argc++] = AssetManager::OVERLAY_DIR;
- }
-
- if (stat(AssetManager::PRODUCT_OVERLAY_DIR, &st) == 0) {
- argv[argc++] = AssetManager::PRODUCT_OVERLAY_DIR;
- }
-
- // Finally, invoke idmap (if any overlay directory exists)
- if (argc > 5) {
- execv(AssetManager::IDMAP_BIN, (char* const*)argv);
- ALOGE("failed to execv for idmap: %s", strerror(errno));
- exit(1); // should never get here
- } else {
- exit(0);
- }
- }
- break;
- default: // parent
- waitpid(pid, NULL, 0);
- break;
- }
-}
-
-
-// ----------------------------------------------------------------------------
-
-// this guy is exported to other jni routines
-AssetManager* assetManagerForJavaObject(JNIEnv* env, jobject obj)
-{
- jlong amHandle = env->GetLongField(obj, gAssetManagerOffsets.mObject);
- AssetManager* am = reinterpret_cast<AssetManager*>(amHandle);
- if (am != NULL) {
- return am;
- }
- jniThrowException(env, "java/lang/IllegalStateException", "AssetManager has been finalized!");
- return NULL;
-}
-
-static jlong android_content_AssetManager_openAsset(JNIEnv* env, jobject clazz,
- jstring fileName, jint mode)
-{
- AssetManager* am = assetManagerForJavaObject(env, clazz);
- if (am == NULL) {
- return 0;
- }
-
- ALOGV("openAsset in %p (Java object %p)\n", am, clazz);
-
- ScopedUtfChars fileName8(env, fileName);
- if (fileName8.c_str() == NULL) {
- jniThrowException(env, "java/lang/IllegalArgumentException", "Empty file name");
- return -1;
- }
-
- if (mode != Asset::ACCESS_UNKNOWN && mode != Asset::ACCESS_RANDOM
- && mode != Asset::ACCESS_STREAMING && mode != Asset::ACCESS_BUFFER) {
- jniThrowException(env, "java/lang/IllegalArgumentException", "Bad access mode");
- return -1;
- }
-
- Asset* a = am->open(fileName8.c_str(), (Asset::AccessMode)mode);
-
- if (a == NULL) {
- jniThrowException(env, "java/io/FileNotFoundException", fileName8.c_str());
- return -1;
- }
-
- //printf("Created Asset Stream: %p\n", a);
-
- return reinterpret_cast<jlong>(a);
-}
-
-static jobject returnParcelFileDescriptor(JNIEnv* env, Asset* a, jlongArray outOffsets)
-{
- off64_t startOffset, length;
- int fd = a->openFileDescriptor(&startOffset, &length);
- delete a;
-
- if (fd < 0) {
- jniThrowException(env, "java/io/FileNotFoundException",
- "This file can not be opened as a file descriptor; it is probably compressed");
- return NULL;
- }
-
- jlong* offsets = (jlong*)env->GetPrimitiveArrayCritical(outOffsets, 0);
- if (offsets == NULL) {
- close(fd);
- return NULL;
- }
-
- offsets[0] = startOffset;
- offsets[1] = length;
-
- env->ReleasePrimitiveArrayCritical(outOffsets, offsets, 0);
-
- jobject fileDesc = jniCreateFileDescriptor(env, fd);
- if (fileDesc == NULL) {
- close(fd);
- return NULL;
- }
-
- return newParcelFileDescriptor(env, fileDesc);
-}
-
-static jobject android_content_AssetManager_openAssetFd(JNIEnv* env, jobject clazz,
- jstring fileName, jlongArray outOffsets)
-{
- AssetManager* am = assetManagerForJavaObject(env, clazz);
- if (am == NULL) {
- return NULL;
- }
-
- ALOGV("openAssetFd in %p (Java object %p)\n", am, clazz);
-
- ScopedUtfChars fileName8(env, fileName);
- if (fileName8.c_str() == NULL) {
- return NULL;
- }
-
- Asset* a = am->open(fileName8.c_str(), Asset::ACCESS_RANDOM);
-
- if (a == NULL) {
- jniThrowException(env, "java/io/FileNotFoundException", fileName8.c_str());
- return NULL;
- }
-
- //printf("Created Asset Stream: %p\n", a);
-
- return returnParcelFileDescriptor(env, a, outOffsets);
-}
-
-static jlong android_content_AssetManager_openNonAssetNative(JNIEnv* env, jobject clazz,
- jint cookie,
- jstring fileName,
- jint mode)
-{
- AssetManager* am = assetManagerForJavaObject(env, clazz);
- if (am == NULL) {
- return 0;
- }
-
- ALOGV("openNonAssetNative in %p (Java object %p)\n", am, clazz);
-
- ScopedUtfChars fileName8(env, fileName);
- if (fileName8.c_str() == NULL) {
- return -1;
- }
-
- if (mode != Asset::ACCESS_UNKNOWN && mode != Asset::ACCESS_RANDOM
- && mode != Asset::ACCESS_STREAMING && mode != Asset::ACCESS_BUFFER) {
- jniThrowException(env, "java/lang/IllegalArgumentException", "Bad access mode");
- return -1;
- }
-
- Asset* a = cookie
- ? am->openNonAsset(static_cast<int32_t>(cookie), fileName8.c_str(),
- (Asset::AccessMode)mode)
- : am->openNonAsset(fileName8.c_str(), (Asset::AccessMode)mode);
-
- if (a == NULL) {
- jniThrowException(env, "java/io/FileNotFoundException", fileName8.c_str());
- return -1;
- }
-
- //printf("Created Asset Stream: %p\n", a);
-
- return reinterpret_cast<jlong>(a);
-}
-
-static jobject android_content_AssetManager_openNonAssetFdNative(JNIEnv* env, jobject clazz,
- jint cookie,
- jstring fileName,
- jlongArray outOffsets)
-{
- AssetManager* am = assetManagerForJavaObject(env, clazz);
- if (am == NULL) {
- return NULL;
- }
-
- ALOGV("openNonAssetFd in %p (Java object %p)\n", am, clazz);
-
- ScopedUtfChars fileName8(env, fileName);
- if (fileName8.c_str() == NULL) {
- return NULL;
- }
-
- Asset* a = cookie
- ? am->openNonAsset(static_cast<int32_t>(cookie), fileName8.c_str(), Asset::ACCESS_RANDOM)
- : am->openNonAsset(fileName8.c_str(), Asset::ACCESS_RANDOM);
-
- if (a == NULL) {
- jniThrowException(env, "java/io/FileNotFoundException", fileName8.c_str());
- return NULL;
- }
-
- //printf("Created Asset Stream: %p\n", a);
-
- return returnParcelFileDescriptor(env, a, outOffsets);
-}
-
-static jobjectArray android_content_AssetManager_list(JNIEnv* env, jobject clazz,
- jstring fileName)
-{
- AssetManager* am = assetManagerForJavaObject(env, clazz);
- if (am == NULL) {
- return NULL;
- }
-
- ScopedUtfChars fileName8(env, fileName);
- if (fileName8.c_str() == NULL) {
- return NULL;
- }
-
- AssetDir* dir = am->openDir(fileName8.c_str());
-
- if (dir == NULL) {
- jniThrowException(env, "java/io/FileNotFoundException", fileName8.c_str());
- return NULL;
- }
-
- size_t N = dir->getFileCount();
-
- jobjectArray array = env->NewObjectArray(dir->getFileCount(),
- g_stringClass, NULL);
- if (array == NULL) {
- delete dir;
- return NULL;
- }
-
- for (size_t i=0; i<N; i++) {
- const String8& name = dir->getFileName(i);
- jstring str = env->NewStringUTF(name.string());
- if (str == NULL) {
- delete dir;
- return NULL;
+ // Directories to scan for overlays: if OVERLAY_THEME_DIR_PROPERTY is defined,
+ // use OVERLAY_DIR/<value of OVERLAY_THEME_DIR_PROPERTY> in addition to OVERLAY_DIR.
+ std::string overlay_theme_path = base::GetProperty(AssetManager::OVERLAY_THEME_DIR_PROPERTY,
+ "");
+ if (!overlay_theme_path.empty()) {
+ overlay_theme_path = std::string(AssetManager::OVERLAY_DIR) + "/" + overlay_theme_path;
+ if (stat(overlay_theme_path.c_str(), &st) == 0) {
+ argv[argc++] = overlay_theme_path.c_str();
}
- env->SetObjectArrayElement(array, i, str);
- env->DeleteLocalRef(str);
- }
+ }
- delete dir;
+ if (stat(AssetManager::OVERLAY_DIR, &st) == 0) {
+ argv[argc++] = AssetManager::OVERLAY_DIR;
+ }
- return array;
+ if (stat(AssetManager::PRODUCT_OVERLAY_DIR, &st) == 0) {
+ argv[argc++] = AssetManager::PRODUCT_OVERLAY_DIR;
+ }
+
+ // Finally, invoke idmap (if any overlay directory exists)
+ if (argc > 5) {
+ execv(AssetManager::IDMAP_BIN, (char* const*)argv);
+ PLOG(ERROR) << "failed to execv for idmap";
+ exit(1); // should never get here
+ } else {
+ exit(0);
+ }
+ } break;
+
+ // parent
+ default:
+ waitpid(pid, nullptr, 0);
+ break;
+ }
}
-static void android_content_AssetManager_destroyAsset(JNIEnv* env, jobject clazz,
- jlong assetHandle)
-{
- Asset* a = reinterpret_cast<Asset*>(assetHandle);
-
- //printf("Destroying Asset Stream: %p\n", a);
-
- if (a == NULL) {
- jniThrowNullPointerException(env, "asset");
- return;
- }
-
- delete a;
-}
-
-static jint android_content_AssetManager_readAssetChar(JNIEnv* env, jobject clazz,
- jlong assetHandle)
-{
- Asset* a = reinterpret_cast<Asset*>(assetHandle);
-
- if (a == NULL) {
- jniThrowNullPointerException(env, "asset");
- return -1;
- }
-
- uint8_t b;
- ssize_t res = a->read(&b, 1);
- return res == 1 ? b : -1;
-}
-
-static jint android_content_AssetManager_readAsset(JNIEnv* env, jobject clazz,
- jlong assetHandle, jbyteArray bArray,
- jint off, jint len)
-{
- Asset* a = reinterpret_cast<Asset*>(assetHandle);
-
- if (a == NULL || bArray == NULL) {
- jniThrowNullPointerException(env, "asset");
- return -1;
- }
-
- if (len == 0) {
- return 0;
- }
-
- jsize bLen = env->GetArrayLength(bArray);
- if (off < 0 || off >= bLen || len < 0 || len > bLen || (off+len) > bLen) {
- jniThrowException(env, "java/lang/IndexOutOfBoundsException", "");
- return -1;
- }
-
- jbyte* b = env->GetByteArrayElements(bArray, NULL);
- ssize_t res = a->read(b+off, len);
- env->ReleaseByteArrayElements(bArray, b, 0);
-
- if (res > 0) return static_cast<jint>(res);
-
- if (res < 0) {
- jniThrowException(env, "java/io/IOException", "");
- }
- return -1;
-}
-
-static jlong android_content_AssetManager_seekAsset(JNIEnv* env, jobject clazz,
- jlong assetHandle,
- jlong offset, jint whence)
-{
- Asset* a = reinterpret_cast<Asset*>(assetHandle);
-
- if (a == NULL) {
- jniThrowNullPointerException(env, "asset");
- return -1;
- }
-
- return a->seek(
- offset, (whence > 0) ? SEEK_END : (whence < 0 ? SEEK_SET : SEEK_CUR));
-}
-
-static jlong android_content_AssetManager_getAssetLength(JNIEnv* env, jobject clazz,
- jlong assetHandle)
-{
- Asset* a = reinterpret_cast<Asset*>(assetHandle);
-
- if (a == NULL) {
- jniThrowNullPointerException(env, "asset");
- return -1;
- }
-
- return a->getLength();
-}
-
-static jlong android_content_AssetManager_getAssetRemainingLength(JNIEnv* env, jobject clazz,
- jlong assetHandle)
-{
- Asset* a = reinterpret_cast<Asset*>(assetHandle);
-
- if (a == NULL) {
- jniThrowNullPointerException(env, "asset");
- return -1;
- }
-
- return a->getRemainingLength();
-}
-
-static jint android_content_AssetManager_addAssetPath(JNIEnv* env, jobject clazz,
- jstring path, jboolean appAsLib)
-{
- ScopedUtfChars path8(env, path);
- if (path8.c_str() == NULL) {
- return 0;
- }
-
- AssetManager* am = assetManagerForJavaObject(env, clazz);
- if (am == NULL) {
- return 0;
- }
-
- int32_t cookie;
- bool res = am->addAssetPath(String8(path8.c_str()), &cookie, appAsLib);
-
- return (res) ? static_cast<jint>(cookie) : 0;
-}
-
-static jint android_content_AssetManager_addOverlayPath(JNIEnv* env, jobject clazz,
- jstring idmapPath)
-{
- ScopedUtfChars idmapPath8(env, idmapPath);
- if (idmapPath8.c_str() == NULL) {
- return 0;
- }
-
- AssetManager* am = assetManagerForJavaObject(env, clazz);
- if (am == NULL) {
- return 0;
- }
-
- int32_t cookie;
- bool res = am->addOverlayPath(String8(idmapPath8.c_str()), &cookie);
-
- return (res) ? (jint)cookie : 0;
-}
-
-static jint android_content_AssetManager_addAssetFd(JNIEnv* env, jobject clazz,
- jobject fileDescriptor, jstring debugPathName,
- jboolean appAsLib)
-{
- ScopedUtfChars debugPathName8(env, debugPathName);
-
- int fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
- if (fd < 0) {
- jniThrowException(env, "java/lang/IllegalArgumentException", "Bad FileDescriptor");
- return 0;
- }
-
- AssetManager* am = assetManagerForJavaObject(env, clazz);
- if (am == NULL) {
- return 0;
- }
-
- int dupfd = ::dup(fd);
- if (dupfd < 0) {
- jniThrowIOException(env, errno);
- return 0;
- }
-
- int32_t cookie;
- bool res = am->addAssetFd(dupfd, String8(debugPathName8.c_str()), &cookie, appAsLib);
-
- return (res) ? static_cast<jint>(cookie) : 0;
-}
-
-static jboolean android_content_AssetManager_isUpToDate(JNIEnv* env, jobject clazz)
-{
- AssetManager* am = assetManagerForJavaObject(env, clazz);
- if (am == NULL) {
- return JNI_TRUE;
- }
- return am->isUpToDate() ? JNI_TRUE : JNI_FALSE;
-}
-
-static jobjectArray getLocales(JNIEnv* env, jobject clazz, bool includeSystemLocales)
-{
- Vector<String8> locales;
-
- AssetManager* am = assetManagerForJavaObject(env, clazz);
- if (am == NULL) {
- return NULL;
- }
-
- am->getLocales(&locales, includeSystemLocales);
-
- const int N = locales.size();
-
- jobjectArray result = env->NewObjectArray(N, g_stringClass, NULL);
- if (result == NULL) {
- return NULL;
- }
-
- for (int i=0; i<N; i++) {
- jstring str = env->NewStringUTF(locales[i].string());
- if (str == NULL) {
- return NULL;
- }
- env->SetObjectArrayElement(result, i, str);
- env->DeleteLocalRef(str);
- }
-
- return result;
-}
-
-static jobjectArray android_content_AssetManager_getLocales(JNIEnv* env, jobject clazz)
-{
- return getLocales(env, clazz, true /* include system locales */);
-}
-
-static jobjectArray android_content_AssetManager_getNonSystemLocales(JNIEnv* env, jobject clazz)
-{
- return getLocales(env, clazz, false /* don't include system locales */);
-}
-
-static jobject constructConfigurationObject(JNIEnv* env, const ResTable_config& config) {
- jobject result = env->NewObject(gConfigurationOffsets.classObject,
- gConfigurationOffsets.constructor);
- if (result == NULL) {
- return NULL;
- }
-
- env->SetIntField(result, gConfigurationOffsets.mSmallestScreenWidthDpOffset,
- config.smallestScreenWidthDp);
- env->SetIntField(result, gConfigurationOffsets.mScreenWidthDpOffset, config.screenWidthDp);
- env->SetIntField(result, gConfigurationOffsets.mScreenHeightDpOffset, config.screenHeightDp);
-
- return result;
-}
-
-static jobjectArray getSizeConfigurationsInternal(JNIEnv* env,
- const Vector<ResTable_config>& configs) {
- const int N = configs.size();
- jobjectArray result = env->NewObjectArray(N, gConfigurationOffsets.classObject, NULL);
- if (result == NULL) {
- return NULL;
- }
-
- for (int i=0; i<N; i++) {
- jobject config = constructConfigurationObject(env, configs[i]);
- if (config == NULL) {
- env->DeleteLocalRef(result);
- return NULL;
- }
-
- env->SetObjectArrayElement(result, i, config);
- env->DeleteLocalRef(config);
- }
-
- return result;
-}
-
-static jobjectArray android_content_AssetManager_getSizeConfigurations(JNIEnv* env, jobject clazz) {
- AssetManager* am = assetManagerForJavaObject(env, clazz);
- if (am == NULL) {
- return NULL;
- }
-
- const ResTable& res(am->getResources());
- Vector<ResTable_config> configs;
- res.getConfigurations(&configs, false /* ignoreMipmap */, true /* ignoreAndroidPackage */);
-
- return getSizeConfigurationsInternal(env, configs);
-}
-
-static void android_content_AssetManager_setConfiguration(JNIEnv* env, jobject clazz,
- jint mcc, jint mnc,
- jstring locale, jint orientation,
- jint touchscreen, jint density,
- jint keyboard, jint keyboardHidden,
- jint navigation,
- jint screenWidth, jint screenHeight,
- jint smallestScreenWidthDp,
- jint screenWidthDp, jint screenHeightDp,
- jint screenLayout, jint uiMode,
- jint colorMode, jint sdkVersion)
-{
- AssetManager* am = assetManagerForJavaObject(env, clazz);
- if (am == NULL) {
- return;
- }
-
- ResTable_config config;
- memset(&config, 0, sizeof(config));
-
- const char* locale8 = locale != NULL ? env->GetStringUTFChars(locale, NULL) : NULL;
-
- // Constants duplicated from Java class android.content.res.Configuration.
- static const jint kScreenLayoutRoundMask = 0x300;
- static const jint kScreenLayoutRoundShift = 8;
-
- config.mcc = (uint16_t)mcc;
- config.mnc = (uint16_t)mnc;
- config.orientation = (uint8_t)orientation;
- config.touchscreen = (uint8_t)touchscreen;
- config.density = (uint16_t)density;
- config.keyboard = (uint8_t)keyboard;
- config.inputFlags = (uint8_t)keyboardHidden;
- config.navigation = (uint8_t)navigation;
- config.screenWidth = (uint16_t)screenWidth;
- config.screenHeight = (uint16_t)screenHeight;
- config.smallestScreenWidthDp = (uint16_t)smallestScreenWidthDp;
- config.screenWidthDp = (uint16_t)screenWidthDp;
- config.screenHeightDp = (uint16_t)screenHeightDp;
- config.screenLayout = (uint8_t)screenLayout;
- config.uiMode = (uint8_t)uiMode;
- config.colorMode = (uint8_t)colorMode;
- config.sdkVersion = (uint16_t)sdkVersion;
- config.minorVersion = 0;
-
- // In Java, we use a 32bit integer for screenLayout, while we only use an 8bit integer
- // in C++. We must extract the round qualifier out of the Java screenLayout and put it
- // into screenLayout2.
- config.screenLayout2 =
- (uint8_t)((screenLayout & kScreenLayoutRoundMask) >> kScreenLayoutRoundShift);
-
- am->setConfiguration(config, locale8);
-
- if (locale != NULL) env->ReleaseStringUTFChars(locale, locale8);
-}
-
-static jint android_content_AssetManager_getResourceIdentifier(JNIEnv* env, jobject clazz,
- jstring name,
- jstring defType,
- jstring defPackage)
-{
- ScopedStringChars name16(env, name);
- if (name16.get() == NULL) {
- return 0;
- }
-
- AssetManager* am = assetManagerForJavaObject(env, clazz);
- if (am == NULL) {
- return 0;
- }
-
- const char16_t* defType16 = reinterpret_cast<const char16_t*>(defType)
- ? reinterpret_cast<const char16_t*>(env->GetStringChars(defType, NULL))
- : NULL;
- jsize defTypeLen = defType
- ? env->GetStringLength(defType) : 0;
- const char16_t* defPackage16 = reinterpret_cast<const char16_t*>(defPackage)
- ? reinterpret_cast<const char16_t*>(env->GetStringChars(defPackage,
- NULL))
- : NULL;
- jsize defPackageLen = defPackage
- ? env->GetStringLength(defPackage) : 0;
-
- jint ident = am->getResources().identifierForName(
- reinterpret_cast<const char16_t*>(name16.get()), name16.size(),
- defType16, defTypeLen, defPackage16, defPackageLen);
-
- if (defPackage16) {
- env->ReleaseStringChars(defPackage,
- reinterpret_cast<const jchar*>(defPackage16));
- }
- if (defType16) {
- env->ReleaseStringChars(defType,
- reinterpret_cast<const jchar*>(defType16));
- }
-
- return ident;
-}
-
-static jstring android_content_AssetManager_getResourceName(JNIEnv* env, jobject clazz,
- jint resid)
-{
- AssetManager* am = assetManagerForJavaObject(env, clazz);
- if (am == NULL) {
- return NULL;
- }
-
- ResTable::resource_name name;
- if (!am->getResources().getResourceName(resid, true, &name)) {
- return NULL;
- }
-
- String16 str;
- if (name.package != NULL) {
- str.setTo(name.package, name.packageLen);
- }
- if (name.type8 != NULL || name.type != NULL) {
- if (str.size() > 0) {
- char16_t div = ':';
- str.append(&div, 1);
- }
- if (name.type8 != NULL) {
- str.append(String16(name.type8, name.typeLen));
- } else {
- str.append(name.type, name.typeLen);
- }
- }
- if (name.name8 != NULL || name.name != NULL) {
- if (str.size() > 0) {
- char16_t div = '/';
- str.append(&div, 1);
- }
- if (name.name8 != NULL) {
- str.append(String16(name.name8, name.nameLen));
- } else {
- str.append(name.name, name.nameLen);
- }
- }
-
- return env->NewString((const jchar*)str.string(), str.size());
-}
-
-static jstring android_content_AssetManager_getResourcePackageName(JNIEnv* env, jobject clazz,
- jint resid)
-{
- AssetManager* am = assetManagerForJavaObject(env, clazz);
- if (am == NULL) {
- return NULL;
- }
-
- ResTable::resource_name name;
- if (!am->getResources().getResourceName(resid, true, &name)) {
- return NULL;
- }
-
- if (name.package != NULL) {
- return env->NewString((const jchar*)name.package, name.packageLen);
- }
-
- return NULL;
-}
-
-static jstring android_content_AssetManager_getResourceTypeName(JNIEnv* env, jobject clazz,
- jint resid)
-{
- AssetManager* am = assetManagerForJavaObject(env, clazz);
- if (am == NULL) {
- return NULL;
- }
-
- ResTable::resource_name name;
- if (!am->getResources().getResourceName(resid, true, &name)) {
- return NULL;
- }
-
- if (name.type8 != NULL) {
- return env->NewStringUTF(name.type8);
- }
-
- if (name.type != NULL) {
- return env->NewString((const jchar*)name.type, name.typeLen);
- }
-
- return NULL;
-}
-
-static jstring android_content_AssetManager_getResourceEntryName(JNIEnv* env, jobject clazz,
- jint resid)
-{
- AssetManager* am = assetManagerForJavaObject(env, clazz);
- if (am == NULL) {
- return NULL;
- }
-
- ResTable::resource_name name;
- if (!am->getResources().getResourceName(resid, true, &name)) {
- return NULL;
- }
-
- if (name.name8 != NULL) {
- return env->NewStringUTF(name.name8);
- }
-
- if (name.name != NULL) {
- return env->NewString((const jchar*)name.name, name.nameLen);
- }
-
- return NULL;
-}
-
-static jint android_content_AssetManager_loadResourceValue(JNIEnv* env, jobject clazz,
- jint ident,
- jshort density,
- jobject outValue,
- jboolean resolve)
-{
- if (outValue == NULL) {
- jniThrowNullPointerException(env, "outValue");
- return 0;
- }
- AssetManager* am = assetManagerForJavaObject(env, clazz);
- if (am == NULL) {
- return 0;
- }
- const ResTable& res(am->getResources());
-
- Res_value value;
- ResTable_config config;
- uint32_t typeSpecFlags;
- ssize_t block = res.getResource(ident, &value, false, density, &typeSpecFlags, &config);
- if (kThrowOnBadId) {
- if (block == BAD_INDEX) {
- jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
- return 0;
- }
- }
- uint32_t ref = ident;
- if (resolve) {
- block = res.resolveReference(&value, block, &ref, &typeSpecFlags, &config);
- if (kThrowOnBadId) {
- if (block == BAD_INDEX) {
- jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
- return 0;
- }
- }
- }
- if (block >= 0) {
- return copyValue(env, outValue, &res, value, ref, block, typeSpecFlags, &config);
- }
-
- return static_cast<jint>(block);
-}
-
-static jint android_content_AssetManager_loadResourceBagValue(JNIEnv* env, jobject clazz,
- jint ident, jint bagEntryId,
- jobject outValue, jboolean resolve)
-{
- AssetManager* am = assetManagerForJavaObject(env, clazz);
- if (am == NULL) {
- return 0;
- }
- const ResTable& res(am->getResources());
-
- // Now lock down the resource object and start pulling stuff from it.
- res.lock();
-
- ssize_t block = -1;
- Res_value value;
-
- const ResTable::bag_entry* entry = NULL;
- uint32_t typeSpecFlags;
- ssize_t entryCount = res.getBagLocked(ident, &entry, &typeSpecFlags);
-
- for (ssize_t i=0; i<entryCount; i++) {
- if (((uint32_t)bagEntryId) == entry->map.name.ident) {
- block = entry->stringBlock;
- value = entry->map.value;
- }
- entry++;
- }
-
- res.unlock();
-
- if (block < 0) {
- return static_cast<jint>(block);
- }
-
- uint32_t ref = ident;
- if (resolve) {
- block = res.resolveReference(&value, block, &ref, &typeSpecFlags);
- if (kThrowOnBadId) {
- if (block == BAD_INDEX) {
- jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
- return 0;
- }
- }
- }
- if (block >= 0) {
- return copyValue(env, outValue, &res, value, ref, block, typeSpecFlags);
- }
-
- return static_cast<jint>(block);
-}
-
-static jint android_content_AssetManager_getStringBlockCount(JNIEnv* env, jobject clazz)
-{
- AssetManager* am = assetManagerForJavaObject(env, clazz);
- if (am == NULL) {
- return 0;
- }
- return am->getResources().getTableCount();
-}
-
-static jlong android_content_AssetManager_getNativeStringBlock(JNIEnv* env, jobject clazz,
- jint block)
-{
- AssetManager* am = assetManagerForJavaObject(env, clazz);
- if (am == NULL) {
- return 0;
- }
- return reinterpret_cast<jlong>(am->getResources().getTableStringBlock(block));
-}
-
-static jstring android_content_AssetManager_getCookieName(JNIEnv* env, jobject clazz,
- jint cookie)
-{
- AssetManager* am = assetManagerForJavaObject(env, clazz);
- if (am == NULL) {
- return NULL;
- }
- String8 name(am->getAssetPath(static_cast<int32_t>(cookie)));
- if (name.length() == 0) {
- jniThrowException(env, "java/lang/IndexOutOfBoundsException", "Empty cookie name");
- return NULL;
- }
- jstring str = env->NewStringUTF(name.string());
- return str;
-}
-
-static jobject android_content_AssetManager_getAssignedPackageIdentifiers(JNIEnv* env, jobject clazz)
-{
- AssetManager* am = assetManagerForJavaObject(env, clazz);
- if (am == NULL) {
- return 0;
- }
-
- const ResTable& res = am->getResources();
-
- jobject sparseArray = env->NewObject(gSparseArrayOffsets.classObject,
- gSparseArrayOffsets.constructor);
- const size_t N = res.getBasePackageCount();
- for (size_t i = 0; i < N; i++) {
- const String16 name = res.getBasePackageName(i);
- env->CallVoidMethod(
- sparseArray, gSparseArrayOffsets.put,
- static_cast<jint>(res.getBasePackageId(i)),
- env->NewString(reinterpret_cast<const jchar*>(name.string()),
- name.size()));
- }
- return sparseArray;
-}
-
-static jlong android_content_AssetManager_newTheme(JNIEnv* env, jobject clazz)
-{
- AssetManager* am = assetManagerForJavaObject(env, clazz);
- if (am == NULL) {
- return 0;
- }
- return reinterpret_cast<jlong>(new ResTable::Theme(am->getResources()));
-}
-
-static void android_content_AssetManager_deleteTheme(JNIEnv* env, jobject clazz,
- jlong themeHandle)
-{
- ResTable::Theme* theme = reinterpret_cast<ResTable::Theme*>(themeHandle);
- delete theme;
-}
-
-static void android_content_AssetManager_applyThemeStyle(JNIEnv* env, jobject clazz,
- jlong themeHandle,
- jint styleRes,
- jboolean force)
-{
- ResTable::Theme* theme = reinterpret_cast<ResTable::Theme*>(themeHandle);
- theme->applyStyle(styleRes, force ? true : false);
-}
-
-static void android_content_AssetManager_copyTheme(JNIEnv* env, jobject clazz,
- jlong destHandle, jlong srcHandle)
-{
- ResTable::Theme* dest = reinterpret_cast<ResTable::Theme*>(destHandle);
- ResTable::Theme* src = reinterpret_cast<ResTable::Theme*>(srcHandle);
- dest->setTo(*src);
-}
-
-static void android_content_AssetManager_clearTheme(JNIEnv* env, jobject clazz, jlong themeHandle)
-{
- ResTable::Theme* theme = reinterpret_cast<ResTable::Theme*>(themeHandle);
- theme->clear();
-}
-
-static jint android_content_AssetManager_loadThemeAttributeValue(
- JNIEnv* env, jobject clazz, jlong themeHandle, jint ident, jobject outValue, jboolean resolve)
-{
- ResTable::Theme* theme = reinterpret_cast<ResTable::Theme*>(themeHandle);
- const ResTable& res(theme->getResTable());
-
- Res_value value;
- // XXX value could be different in different configs!
- uint32_t typeSpecFlags = 0;
- ssize_t block = theme->getAttribute(ident, &value, &typeSpecFlags);
- uint32_t ref = 0;
- if (resolve) {
- block = res.resolveReference(&value, block, &ref, &typeSpecFlags);
- if (kThrowOnBadId) {
- if (block == BAD_INDEX) {
- jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
- return 0;
- }
- }
- }
- return block >= 0 ? copyValue(env, outValue, &res, value, ref, block, typeSpecFlags) : block;
-}
-
-static jint android_content_AssetManager_getThemeChangingConfigurations(JNIEnv* env, jobject clazz,
- jlong themeHandle)
-{
- ResTable::Theme* theme = reinterpret_cast<ResTable::Theme*>(themeHandle);
- return theme->getChangingConfigurations();
-}
-
-static void android_content_AssetManager_dumpTheme(JNIEnv* env, jobject clazz,
- jlong themeHandle, jint pri,
- jstring tag, jstring prefix)
-{
- ResTable::Theme* theme = reinterpret_cast<ResTable::Theme*>(themeHandle);
- const ResTable& res(theme->getResTable());
- (void)res;
-
- // XXX Need to use params.
- theme->dumpToLog();
-}
-
-static jboolean android_content_AssetManager_resolveAttrs(JNIEnv* env, jobject clazz,
- jlong themeToken,
- jint defStyleAttr,
- jint defStyleRes,
- jintArray inValues,
- jintArray attrs,
- jintArray outValues,
- jintArray outIndices)
-{
- if (themeToken == 0) {
- jniThrowNullPointerException(env, "theme token");
- return JNI_FALSE;
- }
- if (attrs == NULL) {
- jniThrowNullPointerException(env, "attrs");
- return JNI_FALSE;
- }
- if (outValues == NULL) {
- jniThrowNullPointerException(env, "out values");
- return JNI_FALSE;
- }
-
- const jsize NI = env->GetArrayLength(attrs);
- const jsize NV = env->GetArrayLength(outValues);
- if (NV < (NI*STYLE_NUM_ENTRIES)) {
- jniThrowException(env, "java/lang/IndexOutOfBoundsException", "out values too small");
- return JNI_FALSE;
- }
-
- jint* src = (jint*)env->GetPrimitiveArrayCritical(attrs, 0);
- if (src == NULL) {
- return JNI_FALSE;
- }
-
- jint* srcValues = (jint*)env->GetPrimitiveArrayCritical(inValues, 0);
- const jsize NSV = srcValues == NULL ? 0 : env->GetArrayLength(inValues);
-
- jint* baseDest = (jint*)env->GetPrimitiveArrayCritical(outValues, 0);
- if (baseDest == NULL) {
- env->ReleasePrimitiveArrayCritical(attrs, src, 0);
- return JNI_FALSE;
- }
-
- jint* indices = NULL;
- if (outIndices != NULL) {
- if (env->GetArrayLength(outIndices) > NI) {
- indices = (jint*)env->GetPrimitiveArrayCritical(outIndices, 0);
- }
- }
-
- ResTable::Theme* theme = reinterpret_cast<ResTable::Theme*>(themeToken);
- bool result = ResolveAttrs(theme, defStyleAttr, defStyleRes,
- (uint32_t*) srcValues, NSV,
- (uint32_t*) src, NI,
- (uint32_t*) baseDest,
- (uint32_t*) indices);
-
- if (indices != NULL) {
- env->ReleasePrimitiveArrayCritical(outIndices, indices, 0);
- }
- env->ReleasePrimitiveArrayCritical(outValues, baseDest, 0);
- env->ReleasePrimitiveArrayCritical(inValues, srcValues, 0);
- env->ReleasePrimitiveArrayCritical(attrs, src, 0);
- return result ? JNI_TRUE : JNI_FALSE;
-}
-
-static void android_content_AssetManager_applyStyle(JNIEnv* env, jobject, jlong themeToken,
- jint defStyleAttr, jint defStyleRes, jlong xmlParserToken, jintArray attrsObj, jint length,
- jlong outValuesAddress, jlong outIndicesAddress) {
- jint* attrs = env->GetIntArrayElements(attrsObj, 0);
- ResTable::Theme* theme = reinterpret_cast<ResTable::Theme*>(themeToken);
- ResXMLParser* xmlParser = reinterpret_cast<ResXMLParser*>(xmlParserToken);
- uint32_t* outValues = reinterpret_cast<uint32_t*>(static_cast<uintptr_t>(outValuesAddress));
- uint32_t* outIndices = reinterpret_cast<uint32_t*>(static_cast<uintptr_t>(outIndicesAddress));
- ApplyStyle(theme, xmlParser, defStyleAttr, defStyleRes,
- reinterpret_cast<const uint32_t*>(attrs), length, outValues, outIndices);
- env->ReleaseIntArrayElements(attrsObj, attrs, JNI_ABORT);
-}
-
-static jboolean android_content_AssetManager_retrieveAttributes(JNIEnv* env, jobject clazz,
- jlong xmlParserToken,
- jintArray attrs,
- jintArray outValues,
- jintArray outIndices)
-{
- if (xmlParserToken == 0) {
- jniThrowNullPointerException(env, "xmlParserToken");
- return JNI_FALSE;
- }
- if (attrs == NULL) {
- jniThrowNullPointerException(env, "attrs");
- return JNI_FALSE;
- }
- if (outValues == NULL) {
- jniThrowNullPointerException(env, "out values");
- return JNI_FALSE;
- }
-
- AssetManager* am = assetManagerForJavaObject(env, clazz);
- if (am == NULL) {
- return JNI_FALSE;
- }
- const ResTable& res(am->getResources());
- ResXMLParser* xmlParser = (ResXMLParser*)xmlParserToken;
-
- const jsize NI = env->GetArrayLength(attrs);
- const jsize NV = env->GetArrayLength(outValues);
- if (NV < (NI*STYLE_NUM_ENTRIES)) {
- jniThrowException(env, "java/lang/IndexOutOfBoundsException", "out values too small");
- return JNI_FALSE;
- }
-
- jint* src = (jint*)env->GetPrimitiveArrayCritical(attrs, 0);
- if (src == NULL) {
- return JNI_FALSE;
- }
-
- jint* baseDest = (jint*)env->GetPrimitiveArrayCritical(outValues, 0);
- if (baseDest == NULL) {
- env->ReleasePrimitiveArrayCritical(attrs, src, 0);
- return JNI_FALSE;
- }
-
- jint* indices = NULL;
- if (outIndices != NULL) {
- if (env->GetArrayLength(outIndices) > NI) {
- indices = (jint*)env->GetPrimitiveArrayCritical(outIndices, 0);
- }
- }
-
- bool result = RetrieveAttributes(&res, xmlParser,
- (uint32_t*) src, NI,
- (uint32_t*) baseDest,
- (uint32_t*) indices);
-
- if (indices != NULL) {
- env->ReleasePrimitiveArrayCritical(outIndices, indices, 0);
- }
- env->ReleasePrimitiveArrayCritical(outValues, baseDest, 0);
- env->ReleasePrimitiveArrayCritical(attrs, src, 0);
- return result ? JNI_TRUE : JNI_FALSE;
-}
-
-static jint android_content_AssetManager_getArraySize(JNIEnv* env, jobject clazz,
- jint id)
-{
- AssetManager* am = assetManagerForJavaObject(env, clazz);
- if (am == NULL) {
- return 0;
- }
- const ResTable& res(am->getResources());
-
- res.lock();
- const ResTable::bag_entry* defStyleEnt = NULL;
- ssize_t bagOff = res.getBagLocked(id, &defStyleEnt);
- res.unlock();
-
- return static_cast<jint>(bagOff);
-}
-
-static jint android_content_AssetManager_retrieveArray(JNIEnv* env, jobject clazz,
- jint id,
- jintArray outValues)
-{
- if (outValues == NULL) {
- jniThrowNullPointerException(env, "out values");
- return JNI_FALSE;
- }
-
- AssetManager* am = assetManagerForJavaObject(env, clazz);
- if (am == NULL) {
- return JNI_FALSE;
- }
- const ResTable& res(am->getResources());
- ResTable_config config;
- Res_value value;
- ssize_t block;
-
- const jsize NV = env->GetArrayLength(outValues);
-
- jint* baseDest = (jint*)env->GetPrimitiveArrayCritical(outValues, 0);
- jint* dest = baseDest;
- if (dest == NULL) {
- jniThrowException(env, "java/lang/OutOfMemoryError", "");
- return JNI_FALSE;
- }
-
- // Now lock down the resource object and start pulling stuff from it.
- res.lock();
-
- const ResTable::bag_entry* arrayEnt = NULL;
- uint32_t arrayTypeSetFlags = 0;
- ssize_t bagOff = res.getBagLocked(id, &arrayEnt, &arrayTypeSetFlags);
- const ResTable::bag_entry* endArrayEnt = arrayEnt +
- (bagOff >= 0 ? bagOff : 0);
-
- int i = 0;
- uint32_t typeSetFlags;
- while (i < NV && arrayEnt < endArrayEnt) {
- block = arrayEnt->stringBlock;
- typeSetFlags = arrayTypeSetFlags;
- config.density = 0;
- value = arrayEnt->map.value;
-
- uint32_t resid = 0;
- if (value.dataType != Res_value::TYPE_NULL) {
- // Take care of resolving the found resource to its final value.
- //printf("Resolving attribute reference\n");
- ssize_t newBlock = res.resolveReference(&value, block, &resid,
- &typeSetFlags, &config);
- if (kThrowOnBadId) {
- if (newBlock == BAD_INDEX) {
- jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
- return JNI_FALSE;
- }
- }
- if (newBlock >= 0) block = newBlock;
- }
-
- // Deal with the special @null value -- it turns back to TYPE_NULL.
- if (value.dataType == Res_value::TYPE_REFERENCE && value.data == 0) {
- value.dataType = Res_value::TYPE_NULL;
- value.data = Res_value::DATA_NULL_UNDEFINED;
- }
-
- //printf("Attribute 0x%08x: final type=0x%x, data=0x%08x\n", curIdent, value.dataType, value.data);
-
- // Write the final value back to Java.
- dest[STYLE_TYPE] = value.dataType;
- dest[STYLE_DATA] = value.data;
- dest[STYLE_ASSET_COOKIE] = reinterpret_cast<jint>(res.getTableCookie(block));
- dest[STYLE_RESOURCE_ID] = resid;
- dest[STYLE_CHANGING_CONFIGURATIONS] = typeSetFlags;
- dest[STYLE_DENSITY] = config.density;
- dest += STYLE_NUM_ENTRIES;
- i+= STYLE_NUM_ENTRIES;
- arrayEnt++;
- }
-
- i /= STYLE_NUM_ENTRIES;
-
- res.unlock();
-
- env->ReleasePrimitiveArrayCritical(outValues, baseDest, 0);
-
- return i;
-}
-
-static jlong android_content_AssetManager_openXmlAssetNative(JNIEnv* env, jobject clazz,
- jint cookie,
- jstring fileName)
-{
- AssetManager* am = assetManagerForJavaObject(env, clazz);
- if (am == NULL) {
- return 0;
- }
-
- ALOGV("openXmlAsset in %p (Java object %p)\n", am, clazz);
-
- ScopedUtfChars fileName8(env, fileName);
- if (fileName8.c_str() == NULL) {
- return 0;
- }
-
- int32_t assetCookie = static_cast<int32_t>(cookie);
- Asset* a = assetCookie
- ? am->openNonAsset(assetCookie, fileName8.c_str(), Asset::ACCESS_BUFFER)
- : am->openNonAsset(fileName8.c_str(), Asset::ACCESS_BUFFER, &assetCookie);
-
- if (a == NULL) {
- jniThrowException(env, "java/io/FileNotFoundException", fileName8.c_str());
- return 0;
- }
-
- const DynamicRefTable* dynamicRefTable =
- am->getResources().getDynamicRefTableForCookie(assetCookie);
- ResXMLTree* block = new ResXMLTree(dynamicRefTable);
- status_t err = block->setTo(a->getBuffer(true), a->getLength(), true);
- a->close();
- delete a;
-
- if (err != NO_ERROR) {
- jniThrowException(env, "java/io/FileNotFoundException", "Corrupt XML binary file");
- return 0;
- }
-
- return reinterpret_cast<jlong>(block);
-}
-
-static jintArray android_content_AssetManager_getArrayStringInfo(JNIEnv* env, jobject clazz,
- jint arrayResId)
-{
- AssetManager* am = assetManagerForJavaObject(env, clazz);
- if (am == NULL) {
- return NULL;
- }
- const ResTable& res(am->getResources());
-
- const ResTable::bag_entry* startOfBag;
- const ssize_t N = res.lockBag(arrayResId, &startOfBag);
- if (N < 0) {
- return NULL;
- }
-
- jintArray array = env->NewIntArray(N * 2);
- if (array == NULL) {
- res.unlockBag(startOfBag);
- return NULL;
- }
-
- Res_value value;
- const ResTable::bag_entry* bag = startOfBag;
- for (size_t i = 0, j = 0; ((ssize_t)i)<N; i++, bag++) {
- jint stringIndex = -1;
- jint stringBlock = 0;
- value = bag->map.value;
-
- // Take care of resolving the found resource to its final value.
- stringBlock = res.resolveReference(&value, bag->stringBlock, NULL);
- if (value.dataType == Res_value::TYPE_STRING) {
- stringIndex = value.data;
- }
-
- if (kThrowOnBadId) {
- if (stringBlock == BAD_INDEX) {
- jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
- return array;
- }
- }
-
- //todo: It might be faster to allocate a C array to contain
- // the blocknums and indices, put them in there and then
- // do just one SetIntArrayRegion()
- env->SetIntArrayRegion(array, j, 1, &stringBlock);
- env->SetIntArrayRegion(array, j + 1, 1, &stringIndex);
- j = j + 2;
- }
- res.unlockBag(startOfBag);
- return array;
-}
-
-static jobjectArray android_content_AssetManager_getArrayStringResource(JNIEnv* env, jobject clazz,
- jint arrayResId)
-{
- AssetManager* am = assetManagerForJavaObject(env, clazz);
- if (am == NULL) {
- return NULL;
- }
- const ResTable& res(am->getResources());
-
- const ResTable::bag_entry* startOfBag;
- const ssize_t N = res.lockBag(arrayResId, &startOfBag);
- if (N < 0) {
- return NULL;
- }
-
- jobjectArray array = env->NewObjectArray(N, g_stringClass, NULL);
- if (env->ExceptionCheck()) {
- res.unlockBag(startOfBag);
- return NULL;
- }
-
- Res_value value;
- const ResTable::bag_entry* bag = startOfBag;
- size_t strLen = 0;
- for (size_t i=0; ((ssize_t)i)<N; i++, bag++) {
- value = bag->map.value;
- jstring str = NULL;
-
- // Take care of resolving the found resource to its final value.
- ssize_t block = res.resolveReference(&value, bag->stringBlock, NULL);
- if (kThrowOnBadId) {
- if (block == BAD_INDEX) {
- jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
- return array;
- }
- }
- if (value.dataType == Res_value::TYPE_STRING) {
- const ResStringPool* pool = res.getTableStringBlock(block);
- const char* str8 = pool->string8At(value.data, &strLen);
- if (str8 != NULL) {
- str = env->NewStringUTF(str8);
- } else {
- const char16_t* str16 = pool->stringAt(value.data, &strLen);
- str = env->NewString(reinterpret_cast<const jchar*>(str16),
- strLen);
- }
-
- // If one of our NewString{UTF} calls failed due to memory, an
- // exception will be pending.
- if (env->ExceptionCheck()) {
- res.unlockBag(startOfBag);
- return NULL;
- }
-
- env->SetObjectArrayElement(array, i, str);
-
- // str is not NULL at that point, otherwise ExceptionCheck would have been true.
- // If we have a large amount of strings in our array, we might
- // overflow the local reference table of the VM.
- env->DeleteLocalRef(str);
- }
- }
- res.unlockBag(startOfBag);
- return array;
-}
-
-static jintArray android_content_AssetManager_getArrayIntResource(JNIEnv* env, jobject clazz,
- jint arrayResId)
-{
- AssetManager* am = assetManagerForJavaObject(env, clazz);
- if (am == NULL) {
- return NULL;
- }
- const ResTable& res(am->getResources());
-
- const ResTable::bag_entry* startOfBag;
- const ssize_t N = res.lockBag(arrayResId, &startOfBag);
- if (N < 0) {
- return NULL;
- }
-
- jintArray array = env->NewIntArray(N);
- if (array == NULL) {
- res.unlockBag(startOfBag);
- return NULL;
- }
-
- Res_value value;
- const ResTable::bag_entry* bag = startOfBag;
- for (size_t i=0; ((ssize_t)i)<N; i++, bag++) {
- value = bag->map.value;
-
- // Take care of resolving the found resource to its final value.
- ssize_t block = res.resolveReference(&value, bag->stringBlock, NULL);
- if (kThrowOnBadId) {
- if (block == BAD_INDEX) {
- jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
- return array;
- }
- }
- if (value.dataType >= Res_value::TYPE_FIRST_INT
- && value.dataType <= Res_value::TYPE_LAST_INT) {
- int intVal = value.data;
- env->SetIntArrayRegion(array, i, 1, &intVal);
- }
- }
- res.unlockBag(startOfBag);
- return array;
-}
-
-static jintArray android_content_AssetManager_getStyleAttributes(JNIEnv* env, jobject clazz,
- jint styleId)
-{
- AssetManager* am = assetManagerForJavaObject(env, clazz);
- if (am == NULL) {
- return NULL;
- }
- const ResTable& res(am->getResources());
-
- const ResTable::bag_entry* startOfBag;
- const ssize_t N = res.lockBag(styleId, &startOfBag);
- if (N < 0) {
- return NULL;
- }
-
- jintArray array = env->NewIntArray(N);
- if (array == NULL) {
- res.unlockBag(startOfBag);
- return NULL;
- }
-
- const ResTable::bag_entry* bag = startOfBag;
- for (size_t i=0; ((ssize_t)i)<N; i++, bag++) {
- int resourceId = bag->map.name.ident;
- env->SetIntArrayRegion(array, i, 1, &resourceId);
- }
- res.unlockBag(startOfBag);
- return array;
-}
-
-static void android_content_AssetManager_init(JNIEnv* env, jobject clazz, jboolean isSystem)
-{
- if (isSystem) {
- verifySystemIdmaps();
- }
- AssetManager* am = new AssetManager();
- if (am == NULL) {
- jniThrowException(env, "java/lang/OutOfMemoryError", "");
- return;
- }
-
- am->addDefaultAssets();
-
- ALOGV("Created AssetManager %p for Java object %p\n", am, clazz);
- env->SetLongField(clazz, gAssetManagerOffsets.mObject, reinterpret_cast<jlong>(am));
-}
-
-static void android_content_AssetManager_destroy(JNIEnv* env, jobject clazz)
-{
- AssetManager* am = (AssetManager*)
- (env->GetLongField(clazz, gAssetManagerOffsets.mObject));
- ALOGV("Destroying AssetManager %p for Java object %p\n", am, clazz);
- if (am != NULL) {
- delete am;
- env->SetLongField(clazz, gAssetManagerOffsets.mObject, 0);
- }
-}
-
-static jint android_content_AssetManager_getGlobalAssetCount(JNIEnv* env, jobject clazz)
-{
- return Asset::getGlobalCount();
-}
-
-static jobject android_content_AssetManager_getAssetAllocations(JNIEnv* env, jobject clazz)
-{
- String8 alloc = Asset::getAssetAllocations();
- if (alloc.length() <= 0) {
- return NULL;
- }
-
- jstring str = env->NewStringUTF(alloc.string());
- return str;
-}
-
-static jint android_content_AssetManager_getGlobalAssetManagerCount(JNIEnv* env, jobject clazz)
-{
- return AssetManager::getGlobalCount();
+static jint CopyValue(JNIEnv* env, ApkAssetsCookie cookie, const Res_value& value, uint32_t ref,
+ uint32_t type_spec_flags, ResTable_config* config, jobject out_typed_value) {
+ env->SetIntField(out_typed_value, gTypedValueOffsets.mType, value.dataType);
+ env->SetIntField(out_typed_value, gTypedValueOffsets.mAssetCookie,
+ ApkAssetsCookieToJavaCookie(cookie));
+ env->SetIntField(out_typed_value, gTypedValueOffsets.mData, value.data);
+ env->SetObjectField(out_typed_value, gTypedValueOffsets.mString, nullptr);
+ env->SetIntField(out_typed_value, gTypedValueOffsets.mResourceId, ref);
+ env->SetIntField(out_typed_value, gTypedValueOffsets.mChangingConfigurations, type_spec_flags);
+ if (config != nullptr) {
+ env->SetIntField(out_typed_value, gTypedValueOffsets.mDensity, config->density);
+ }
+ return static_cast<jint>(ApkAssetsCookieToJavaCookie(cookie));
}
// ----------------------------------------------------------------------------
-/*
- * JNI registration.
- */
-static const JNINativeMethod gAssetManagerMethods[] = {
- /* name, signature, funcPtr */
-
- // Basic asset stuff.
- { "openAsset", "(Ljava/lang/String;I)J",
- (void*) android_content_AssetManager_openAsset },
- { "openAssetFd", "(Ljava/lang/String;[J)Landroid/os/ParcelFileDescriptor;",
- (void*) android_content_AssetManager_openAssetFd },
- { "openNonAssetNative", "(ILjava/lang/String;I)J",
- (void*) android_content_AssetManager_openNonAssetNative },
- { "openNonAssetFdNative", "(ILjava/lang/String;[J)Landroid/os/ParcelFileDescriptor;",
- (void*) android_content_AssetManager_openNonAssetFdNative },
- { "list", "(Ljava/lang/String;)[Ljava/lang/String;",
- (void*) android_content_AssetManager_list },
- { "destroyAsset", "(J)V",
- (void*) android_content_AssetManager_destroyAsset },
- { "readAssetChar", "(J)I",
- (void*) android_content_AssetManager_readAssetChar },
- { "readAsset", "(J[BII)I",
- (void*) android_content_AssetManager_readAsset },
- { "seekAsset", "(JJI)J",
- (void*) android_content_AssetManager_seekAsset },
- { "getAssetLength", "(J)J",
- (void*) android_content_AssetManager_getAssetLength },
- { "getAssetRemainingLength", "(J)J",
- (void*) android_content_AssetManager_getAssetRemainingLength },
- { "addAssetPathNative", "(Ljava/lang/String;Z)I",
- (void*) android_content_AssetManager_addAssetPath },
- { "addAssetFdNative", "(Ljava/io/FileDescriptor;Ljava/lang/String;Z)I",
- (void*) android_content_AssetManager_addAssetFd },
- { "addOverlayPathNative", "(Ljava/lang/String;)I",
- (void*) android_content_AssetManager_addOverlayPath },
- { "isUpToDate", "()Z",
- (void*) android_content_AssetManager_isUpToDate },
-
- // Resources.
- { "getLocales", "()[Ljava/lang/String;",
- (void*) android_content_AssetManager_getLocales },
- { "getNonSystemLocales", "()[Ljava/lang/String;",
- (void*) android_content_AssetManager_getNonSystemLocales },
- { "getSizeConfigurations", "()[Landroid/content/res/Configuration;",
- (void*) android_content_AssetManager_getSizeConfigurations },
- { "setConfiguration", "(IILjava/lang/String;IIIIIIIIIIIIIII)V",
- (void*) android_content_AssetManager_setConfiguration },
- { "getResourceIdentifier","(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)I",
- (void*) android_content_AssetManager_getResourceIdentifier },
- { "getResourceName","(I)Ljava/lang/String;",
- (void*) android_content_AssetManager_getResourceName },
- { "getResourcePackageName","(I)Ljava/lang/String;",
- (void*) android_content_AssetManager_getResourcePackageName },
- { "getResourceTypeName","(I)Ljava/lang/String;",
- (void*) android_content_AssetManager_getResourceTypeName },
- { "getResourceEntryName","(I)Ljava/lang/String;",
- (void*) android_content_AssetManager_getResourceEntryName },
- { "loadResourceValue","(ISLandroid/util/TypedValue;Z)I",
- (void*) android_content_AssetManager_loadResourceValue },
- { "loadResourceBagValue","(IILandroid/util/TypedValue;Z)I",
- (void*) android_content_AssetManager_loadResourceBagValue },
- { "getStringBlockCount","()I",
- (void*) android_content_AssetManager_getStringBlockCount },
- { "getNativeStringBlock","(I)J",
- (void*) android_content_AssetManager_getNativeStringBlock },
- { "getCookieName","(I)Ljava/lang/String;",
- (void*) android_content_AssetManager_getCookieName },
- { "getAssignedPackageIdentifiers","()Landroid/util/SparseArray;",
- (void*) android_content_AssetManager_getAssignedPackageIdentifiers },
-
- // Themes.
- { "newTheme", "()J",
- (void*) android_content_AssetManager_newTheme },
- { "deleteTheme", "(J)V",
- (void*) android_content_AssetManager_deleteTheme },
- { "applyThemeStyle", "(JIZ)V",
- (void*) android_content_AssetManager_applyThemeStyle },
- { "copyTheme", "(JJ)V",
- (void*) android_content_AssetManager_copyTheme },
- { "clearTheme", "(J)V",
- (void*) android_content_AssetManager_clearTheme },
- { "loadThemeAttributeValue", "(JILandroid/util/TypedValue;Z)I",
- (void*) android_content_AssetManager_loadThemeAttributeValue },
- { "getThemeChangingConfigurations", "(J)I",
- (void*) android_content_AssetManager_getThemeChangingConfigurations },
- { "dumpTheme", "(JILjava/lang/String;Ljava/lang/String;)V",
- (void*) android_content_AssetManager_dumpTheme },
- { "applyStyle","(JIIJ[IIJJ)V",
- (void*) android_content_AssetManager_applyStyle },
- { "resolveAttrs","(JII[I[I[I[I)Z",
- (void*) android_content_AssetManager_resolveAttrs },
- { "retrieveAttributes","(J[I[I[I)Z",
- (void*) android_content_AssetManager_retrieveAttributes },
- { "getArraySize","(I)I",
- (void*) android_content_AssetManager_getArraySize },
- { "retrieveArray","(I[I)I",
- (void*) android_content_AssetManager_retrieveArray },
-
- // XML files.
- { "openXmlAssetNative", "(ILjava/lang/String;)J",
- (void*) android_content_AssetManager_openXmlAssetNative },
-
- // Arrays.
- { "getArrayStringResource","(I)[Ljava/lang/String;",
- (void*) android_content_AssetManager_getArrayStringResource },
- { "getArrayStringInfo","(I)[I",
- (void*) android_content_AssetManager_getArrayStringInfo },
- { "getArrayIntResource","(I)[I",
- (void*) android_content_AssetManager_getArrayIntResource },
- { "getStyleAttributes","(I)[I",
- (void*) android_content_AssetManager_getStyleAttributes },
-
- // Bookkeeping.
- { "init", "(Z)V",
- (void*) android_content_AssetManager_init },
- { "destroy", "()V",
- (void*) android_content_AssetManager_destroy },
- { "getGlobalAssetCount", "()I",
- (void*) android_content_AssetManager_getGlobalAssetCount },
- { "getAssetAllocations", "()Ljava/lang/String;",
- (void*) android_content_AssetManager_getAssetAllocations },
- { "getGlobalAssetManagerCount", "()I",
- (void*) android_content_AssetManager_getGlobalAssetManagerCount },
+// Let the opaque type AAssetManager refer to a guarded AssetManager2 instance.
+struct GuardedAssetManager : public ::AAssetManager {
+ Guarded<AssetManager2> guarded_assetmanager;
};
-int register_android_content_AssetManager(JNIEnv* env)
-{
- jclass typedValue = FindClassOrDie(env, "android/util/TypedValue");
- gTypedValueOffsets.mType = GetFieldIDOrDie(env, typedValue, "type", "I");
- gTypedValueOffsets.mData = GetFieldIDOrDie(env, typedValue, "data", "I");
- gTypedValueOffsets.mString = GetFieldIDOrDie(env, typedValue, "string",
- "Ljava/lang/CharSequence;");
- gTypedValueOffsets.mAssetCookie = GetFieldIDOrDie(env, typedValue, "assetCookie", "I");
- gTypedValueOffsets.mResourceId = GetFieldIDOrDie(env, typedValue, "resourceId", "I");
- gTypedValueOffsets.mChangingConfigurations = GetFieldIDOrDie(env, typedValue,
- "changingConfigurations", "I");
- gTypedValueOffsets.mDensity = GetFieldIDOrDie(env, typedValue, "density", "I");
+::AAssetManager* NdkAssetManagerForJavaObject(JNIEnv* env, jobject jassetmanager) {
+ jlong assetmanager_handle = env->GetLongField(jassetmanager, gAssetManagerOffsets.mObject);
+ ::AAssetManager* am = reinterpret_cast<::AAssetManager*>(assetmanager_handle);
+ if (am == nullptr) {
+ jniThrowException(env, "java/lang/IllegalStateException", "AssetManager has been finalized!");
+ return nullptr;
+ }
+ return am;
+}
- jclass assetFd = FindClassOrDie(env, "android/content/res/AssetFileDescriptor");
- gAssetFileDescriptorOffsets.mFd = GetFieldIDOrDie(env, assetFd, "mFd",
- "Landroid/os/ParcelFileDescriptor;");
- gAssetFileDescriptorOffsets.mStartOffset = GetFieldIDOrDie(env, assetFd, "mStartOffset", "J");
- gAssetFileDescriptorOffsets.mLength = GetFieldIDOrDie(env, assetFd, "mLength", "J");
+Guarded<AssetManager2>* AssetManagerForNdkAssetManager(::AAssetManager* assetmanager) {
+ if (assetmanager == nullptr) {
+ return nullptr;
+ }
+ return &reinterpret_cast<GuardedAssetManager*>(assetmanager)->guarded_assetmanager;
+}
- jclass assetManager = FindClassOrDie(env, "android/content/res/AssetManager");
- gAssetManagerOffsets.mObject = GetFieldIDOrDie(env, assetManager, "mObject", "J");
+Guarded<AssetManager2>* AssetManagerForJavaObject(JNIEnv* env, jobject jassetmanager) {
+ return AssetManagerForNdkAssetManager(NdkAssetManagerForJavaObject(env, jassetmanager));
+}
- jclass stringClass = FindClassOrDie(env, "java/lang/String");
- g_stringClass = MakeGlobalRefOrDie(env, stringClass);
+static Guarded<AssetManager2>& AssetManagerFromLong(jlong ptr) {
+ return *AssetManagerForNdkAssetManager(reinterpret_cast<AAssetManager*>(ptr));
+}
- jclass sparseArrayClass = FindClassOrDie(env, "android/util/SparseArray");
- gSparseArrayOffsets.classObject = MakeGlobalRefOrDie(env, sparseArrayClass);
- gSparseArrayOffsets.constructor = GetMethodIDOrDie(env, gSparseArrayOffsets.classObject,
- "<init>", "()V");
- gSparseArrayOffsets.put = GetMethodIDOrDie(env, gSparseArrayOffsets.classObject, "put",
- "(ILjava/lang/Object;)V");
+static jobject ReturnParcelFileDescriptor(JNIEnv* env, std::unique_ptr<Asset> asset,
+ jlongArray out_offsets) {
+ off64_t start_offset, length;
+ int fd = asset->openFileDescriptor(&start_offset, &length);
+ asset.reset();
- jclass configurationClass = FindClassOrDie(env, "android/content/res/Configuration");
- gConfigurationOffsets.classObject = MakeGlobalRefOrDie(env, configurationClass);
- gConfigurationOffsets.constructor = GetMethodIDOrDie(env, configurationClass,
- "<init>", "()V");
- gConfigurationOffsets.mSmallestScreenWidthDpOffset = GetFieldIDOrDie(env, configurationClass,
- "smallestScreenWidthDp", "I");
- gConfigurationOffsets.mScreenWidthDpOffset = GetFieldIDOrDie(env, configurationClass,
- "screenWidthDp", "I");
- gConfigurationOffsets.mScreenHeightDpOffset = GetFieldIDOrDie(env, configurationClass,
- "screenHeightDp", "I");
+ if (fd < 0) {
+ jniThrowException(env, "java/io/FileNotFoundException",
+ "This file can not be opened as a file descriptor; it is probably "
+ "compressed");
+ return nullptr;
+ }
- return RegisterMethodsOrDie(env, "android/content/res/AssetManager", gAssetManagerMethods,
- NELEM(gAssetManagerMethods));
+ jlong* offsets = reinterpret_cast<jlong*>(env->GetPrimitiveArrayCritical(out_offsets, 0));
+ if (offsets == nullptr) {
+ close(fd);
+ return nullptr;
+ }
+
+ offsets[0] = start_offset;
+ offsets[1] = length;
+
+ env->ReleasePrimitiveArrayCritical(out_offsets, offsets, 0);
+
+ jobject file_desc = jniCreateFileDescriptor(env, fd);
+ if (file_desc == nullptr) {
+ close(fd);
+ return nullptr;
+ }
+ return newParcelFileDescriptor(env, file_desc);
+}
+
+static jint NativeGetGlobalAssetCount(JNIEnv* /*env*/, jobject /*clazz*/) {
+ return Asset::getGlobalCount();
+}
+
+static jobject NativeGetAssetAllocations(JNIEnv* env, jobject /*clazz*/) {
+ String8 alloc = Asset::getAssetAllocations();
+ if (alloc.length() <= 0) {
+ return nullptr;
+ }
+ return env->NewStringUTF(alloc.string());
+}
+
+static jint NativeGetGlobalAssetManagerCount(JNIEnv* /*env*/, jobject /*clazz*/) {
+ // TODO(adamlesinski): Switch to AssetManager2.
+ return AssetManager::getGlobalCount();
+}
+
+static jlong NativeCreate(JNIEnv* /*env*/, jclass /*clazz*/) {
+ // AssetManager2 needs to be protected by a lock. To avoid cache misses, we allocate the lock and
+ // AssetManager2 in a contiguous block (GuardedAssetManager).
+ return reinterpret_cast<jlong>(new GuardedAssetManager());
+}
+
+static void NativeDestroy(JNIEnv* /*env*/, jclass /*clazz*/, jlong ptr) {
+ delete reinterpret_cast<GuardedAssetManager*>(ptr);
+}
+
+static void NativeSetApkAssets(JNIEnv* env, jclass /*clazz*/, jlong ptr,
+ jobjectArray apk_assets_array, jboolean invalidate_caches) {
+ ATRACE_NAME("AssetManager::SetApkAssets");
+
+ const jsize apk_assets_len = env->GetArrayLength(apk_assets_array);
+ std::vector<const ApkAssets*> apk_assets;
+ apk_assets.reserve(apk_assets_len);
+ for (jsize i = 0; i < apk_assets_len; i++) {
+ jobject obj = env->GetObjectArrayElement(apk_assets_array, i);
+ if (obj == nullptr) {
+ std::string msg = StringPrintf("ApkAssets at index %d is null", i);
+ jniThrowNullPointerException(env, msg.c_str());
+ return;
+ }
+
+ jlong apk_assets_native_ptr = env->GetLongField(obj, gApkAssetsFields.native_ptr);
+ if (env->ExceptionCheck()) {
+ return;
+ }
+ apk_assets.push_back(reinterpret_cast<const ApkAssets*>(apk_assets_native_ptr));
+ }
+
+ ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
+ assetmanager->SetApkAssets(apk_assets, invalidate_caches);
+}
+
+static void NativeSetConfiguration(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint mcc, jint mnc,
+ jstring locale, jint orientation, jint touchscreen, jint density,
+ jint keyboard, jint keyboard_hidden, jint navigation,
+ jint screen_width, jint screen_height,
+ jint smallest_screen_width_dp, jint screen_width_dp,
+ jint screen_height_dp, jint screen_layout, jint ui_mode,
+ jint color_mode, jint major_version) {
+ ATRACE_NAME("AssetManager::SetConfiguration");
+
+ ResTable_config configuration;
+ memset(&configuration, 0, sizeof(configuration));
+ configuration.mcc = static_cast<uint16_t>(mcc);
+ configuration.mnc = static_cast<uint16_t>(mnc);
+ configuration.orientation = static_cast<uint8_t>(orientation);
+ configuration.touchscreen = static_cast<uint8_t>(touchscreen);
+ configuration.density = static_cast<uint16_t>(density);
+ configuration.keyboard = static_cast<uint8_t>(keyboard);
+ configuration.inputFlags = static_cast<uint8_t>(keyboard_hidden);
+ configuration.navigation = static_cast<uint8_t>(navigation);
+ configuration.screenWidth = static_cast<uint16_t>(screen_width);
+ configuration.screenHeight = static_cast<uint16_t>(screen_height);
+ configuration.smallestScreenWidthDp = static_cast<uint16_t>(smallest_screen_width_dp);
+ configuration.screenWidthDp = static_cast<uint16_t>(screen_width_dp);
+ configuration.screenHeightDp = static_cast<uint16_t>(screen_height_dp);
+ configuration.screenLayout = static_cast<uint8_t>(screen_layout);
+ configuration.uiMode = static_cast<uint8_t>(ui_mode);
+ configuration.colorMode = static_cast<uint8_t>(color_mode);
+ configuration.sdkVersion = static_cast<uint16_t>(major_version);
+
+ if (locale != nullptr) {
+ ScopedUtfChars locale_utf8(env, locale);
+ CHECK(locale_utf8.c_str() != nullptr);
+ configuration.setBcp47Locale(locale_utf8.c_str());
+ }
+
+ // Constants duplicated from Java class android.content.res.Configuration.
+ static const jint kScreenLayoutRoundMask = 0x300;
+ static const jint kScreenLayoutRoundShift = 8;
+
+ // In Java, we use a 32bit integer for screenLayout, while we only use an 8bit integer
+ // in C++. We must extract the round qualifier out of the Java screenLayout and put it
+ // into screenLayout2.
+ configuration.screenLayout2 =
+ static_cast<uint8_t>((screen_layout & kScreenLayoutRoundMask) >> kScreenLayoutRoundShift);
+
+ ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
+ assetmanager->SetConfiguration(configuration);
+}
+
+static jobject NativeGetAssignedPackageIdentifiers(JNIEnv* env, jclass /*clazz*/, jlong ptr) {
+ ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
+
+ jobject sparse_array =
+ env->NewObject(gSparseArrayOffsets.classObject, gSparseArrayOffsets.constructor);
+
+ if (sparse_array == nullptr) {
+ // An exception is pending.
+ return nullptr;
+ }
+
+ assetmanager->ForEachPackage([&](const std::string& package_name, uint8_t package_id) {
+ jstring jpackage_name = env->NewStringUTF(package_name.c_str());
+ if (jpackage_name == nullptr) {
+ // An exception is pending.
+ return;
+ }
+
+ env->CallVoidMethod(sparse_array, gSparseArrayOffsets.put, static_cast<jint>(package_id),
+ jpackage_name);
+ });
+ return sparse_array;
+}
+
+static jobjectArray NativeList(JNIEnv* env, jclass /*clazz*/, jlong ptr, jstring path) {
+ ScopedUtfChars path_utf8(env, path);
+ if (path_utf8.c_str() == nullptr) {
+ // This will throw NPE.
+ return nullptr;
+ }
+
+ ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
+ std::unique_ptr<AssetDir> asset_dir =
+ assetmanager->OpenDir(path_utf8.c_str());
+ if (asset_dir == nullptr) {
+ jniThrowException(env, "java/io/FileNotFoundException", path_utf8.c_str());
+ return nullptr;
+ }
+
+ const size_t file_count = asset_dir->getFileCount();
+
+ jobjectArray array = env->NewObjectArray(file_count, g_stringClass, nullptr);
+ if (array == nullptr) {
+ return nullptr;
+ }
+
+ for (size_t i = 0; i < file_count; i++) {
+ jstring java_string = env->NewStringUTF(asset_dir->getFileName(i).string());
+
+ // Check for errors creating the strings (if malformed or no memory).
+ if (env->ExceptionCheck()) {
+ return nullptr;
+ }
+
+ env->SetObjectArrayElement(array, i, java_string);
+
+ // If we have a large amount of string in our array, we might overflow the
+ // local reference table of the VM.
+ env->DeleteLocalRef(java_string);
+ }
+ return array;
+}
+
+static jlong NativeOpenAsset(JNIEnv* env, jclass /*clazz*/, jlong ptr, jstring asset_path,
+ jint access_mode) {
+ ScopedUtfChars asset_path_utf8(env, asset_path);
+ if (asset_path_utf8.c_str() == nullptr) {
+ // This will throw NPE.
+ return 0;
+ }
+
+ ATRACE_NAME(base::StringPrintf("AssetManager::OpenAsset(%s)", asset_path_utf8.c_str()).c_str());
+
+ if (access_mode != Asset::ACCESS_UNKNOWN && access_mode != Asset::ACCESS_RANDOM &&
+ access_mode != Asset::ACCESS_STREAMING && access_mode != Asset::ACCESS_BUFFER) {
+ jniThrowException(env, "java/lang/IllegalArgumentException", "Bad access mode");
+ return 0;
+ }
+
+ ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
+ std::unique_ptr<Asset> asset =
+ assetmanager->Open(asset_path_utf8.c_str(), static_cast<Asset::AccessMode>(access_mode));
+ if (!asset) {
+ jniThrowException(env, "java/io/FileNotFoundException", asset_path_utf8.c_str());
+ return 0;
+ }
+ return reinterpret_cast<jlong>(asset.release());
+}
+
+static jobject NativeOpenAssetFd(JNIEnv* env, jclass /*clazz*/, jlong ptr, jstring asset_path,
+ jlongArray out_offsets) {
+ ScopedUtfChars asset_path_utf8(env, asset_path);
+ if (asset_path_utf8.c_str() == nullptr) {
+ // This will throw NPE.
+ return nullptr;
+ }
+
+ ATRACE_NAME(base::StringPrintf("AssetManager::OpenAssetFd(%s)", asset_path_utf8.c_str()).c_str());
+
+ ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
+ std::unique_ptr<Asset> asset = assetmanager->Open(asset_path_utf8.c_str(), Asset::ACCESS_RANDOM);
+ if (!asset) {
+ jniThrowException(env, "java/io/FileNotFoundException", asset_path_utf8.c_str());
+ return nullptr;
+ }
+ return ReturnParcelFileDescriptor(env, std::move(asset), out_offsets);
+}
+
+static jlong NativeOpenNonAsset(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint jcookie,
+ jstring asset_path, jint access_mode) {
+ ApkAssetsCookie cookie = JavaCookieToApkAssetsCookie(jcookie);
+ ScopedUtfChars asset_path_utf8(env, asset_path);
+ if (asset_path_utf8.c_str() == nullptr) {
+ // This will throw NPE.
+ return 0;
+ }
+
+ ATRACE_NAME(base::StringPrintf("AssetManager::OpenNonAsset(%s)", asset_path_utf8.c_str()).c_str());
+
+ if (access_mode != Asset::ACCESS_UNKNOWN && access_mode != Asset::ACCESS_RANDOM &&
+ access_mode != Asset::ACCESS_STREAMING && access_mode != Asset::ACCESS_BUFFER) {
+ jniThrowException(env, "java/lang/IllegalArgumentException", "Bad access mode");
+ return 0;
+ }
+
+ ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
+ std::unique_ptr<Asset> asset;
+ if (cookie != kInvalidCookie) {
+ asset = assetmanager->OpenNonAsset(asset_path_utf8.c_str(), cookie,
+ static_cast<Asset::AccessMode>(access_mode));
+ } else {
+ asset = assetmanager->OpenNonAsset(asset_path_utf8.c_str(),
+ static_cast<Asset::AccessMode>(access_mode));
+ }
+
+ if (!asset) {
+ jniThrowException(env, "java/io/FileNotFoundException", asset_path_utf8.c_str());
+ return 0;
+ }
+ return reinterpret_cast<jlong>(asset.release());
+}
+
+static jobject NativeOpenNonAssetFd(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint jcookie,
+ jstring asset_path, jlongArray out_offsets) {
+ ApkAssetsCookie cookie = JavaCookieToApkAssetsCookie(jcookie);
+ ScopedUtfChars asset_path_utf8(env, asset_path);
+ if (asset_path_utf8.c_str() == nullptr) {
+ // This will throw NPE.
+ return nullptr;
+ }
+
+ ATRACE_NAME(base::StringPrintf("AssetManager::OpenNonAssetFd(%s)", asset_path_utf8.c_str()).c_str());
+
+ ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
+ std::unique_ptr<Asset> asset;
+ if (cookie != kInvalidCookie) {
+ asset = assetmanager->OpenNonAsset(asset_path_utf8.c_str(), cookie, Asset::ACCESS_RANDOM);
+ } else {
+ asset = assetmanager->OpenNonAsset(asset_path_utf8.c_str(), Asset::ACCESS_RANDOM);
+ }
+
+ if (!asset) {
+ jniThrowException(env, "java/io/FileNotFoundException", asset_path_utf8.c_str());
+ return nullptr;
+ }
+ return ReturnParcelFileDescriptor(env, std::move(asset), out_offsets);
+}
+
+static jlong NativeOpenXmlAsset(JNIEnv* env, jobject /*clazz*/, jlong ptr, jint jcookie,
+ jstring asset_path) {
+ ApkAssetsCookie cookie = JavaCookieToApkAssetsCookie(jcookie);
+ ScopedUtfChars asset_path_utf8(env, asset_path);
+ if (asset_path_utf8.c_str() == nullptr) {
+ // This will throw NPE.
+ return 0;
+ }
+
+ ATRACE_NAME(base::StringPrintf("AssetManager::OpenXmlAsset(%s)", asset_path_utf8.c_str()).c_str());
+
+ ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
+ std::unique_ptr<Asset> asset;
+ if (cookie != kInvalidCookie) {
+ asset = assetmanager->OpenNonAsset(asset_path_utf8.c_str(), cookie, Asset::ACCESS_RANDOM);
+ } else {
+ asset = assetmanager->OpenNonAsset(asset_path_utf8.c_str(), Asset::ACCESS_RANDOM, &cookie);
+ }
+
+ if (!asset) {
+ jniThrowException(env, "java/io/FileNotFoundException", asset_path_utf8.c_str());
+ return 0;
+ }
+
+ // May be nullptr.
+ const DynamicRefTable* dynamic_ref_table = assetmanager->GetDynamicRefTableForCookie(cookie);
+
+ std::unique_ptr<ResXMLTree> xml_tree = util::make_unique<ResXMLTree>(dynamic_ref_table);
+ status_t err = xml_tree->setTo(asset->getBuffer(true), asset->getLength(), true);
+ asset.reset();
+
+ if (err != NO_ERROR) {
+ jniThrowException(env, "java/io/FileNotFoundException", "Corrupt XML binary file");
+ return 0;
+ }
+ return reinterpret_cast<jlong>(xml_tree.release());
+}
+
+static jint NativeGetResourceValue(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint resid,
+ jshort density, jobject typed_value,
+ jboolean resolve_references) {
+ ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
+ Res_value value;
+ ResTable_config selected_config;
+ uint32_t flags;
+ ApkAssetsCookie cookie =
+ assetmanager->GetResource(static_cast<uint32_t>(resid), false /*may_be_bag*/,
+ static_cast<uint16_t>(density), &value, &selected_config, &flags);
+ if (cookie == kInvalidCookie) {
+ return ApkAssetsCookieToJavaCookie(kInvalidCookie);
+ }
+
+ uint32_t ref = static_cast<uint32_t>(resid);
+ if (resolve_references) {
+ cookie = assetmanager->ResolveReference(cookie, &value, &selected_config, &flags, &ref);
+ if (cookie == kInvalidCookie) {
+ return ApkAssetsCookieToJavaCookie(kInvalidCookie);
+ }
+ }
+ return CopyValue(env, cookie, value, ref, flags, &selected_config, typed_value);
+}
+
+static jint NativeGetResourceBagValue(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint resid,
+ jint bag_entry_id, jobject typed_value) {
+ ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
+ const ResolvedBag* bag = assetmanager->GetBag(static_cast<uint32_t>(resid));
+ if (bag == nullptr) {
+ return ApkAssetsCookieToJavaCookie(kInvalidCookie);
+ }
+
+ uint32_t type_spec_flags = bag->type_spec_flags;
+ ApkAssetsCookie cookie = kInvalidCookie;
+ const Res_value* bag_value = nullptr;
+ for (const ResolvedBag::Entry& entry : bag) {
+ if (entry.key == static_cast<uint32_t>(bag_entry_id)) {
+ cookie = entry.cookie;
+ bag_value = &entry.value;
+
+ // Keep searching (the old implementation did that).
+ }
+ }
+
+ if (cookie == kInvalidCookie) {
+ return ApkAssetsCookieToJavaCookie(kInvalidCookie);
+ }
+
+ Res_value value = *bag_value;
+ uint32_t ref = static_cast<uint32_t>(resid);
+ ResTable_config selected_config;
+ cookie = assetmanager->ResolveReference(cookie, &value, &selected_config, &type_spec_flags, &ref);
+ if (cookie == kInvalidCookie) {
+ return ApkAssetsCookieToJavaCookie(kInvalidCookie);
+ }
+ return CopyValue(env, cookie, value, ref, type_spec_flags, nullptr, typed_value);
+}
+
+static jintArray NativeGetStyleAttributes(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint resid) {
+ ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
+ const ResolvedBag* bag = assetmanager->GetBag(static_cast<uint32_t>(resid));
+ if (bag == nullptr) {
+ return nullptr;
+ }
+
+ jintArray array = env->NewIntArray(bag->entry_count);
+ if (env->ExceptionCheck()) {
+ return nullptr;
+ }
+
+ for (uint32_t i = 0; i < bag->entry_count; i++) {
+ jint attr_resid = bag->entries[i].key;
+ env->SetIntArrayRegion(array, i, 1, &attr_resid);
+ }
+ return array;
+}
+
+static jobjectArray NativeGetResourceStringArray(JNIEnv* env, jclass /*clazz*/, jlong ptr,
+ jint resid) {
+ ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
+ const ResolvedBag* bag = assetmanager->GetBag(static_cast<uint32_t>(resid));
+ if (bag == nullptr) {
+ return nullptr;
+ }
+
+ jobjectArray array = env->NewObjectArray(bag->entry_count, g_stringClass, nullptr);
+ if (array == nullptr) {
+ return nullptr;
+ }
+
+ for (uint32_t i = 0; i < bag->entry_count; i++) {
+ const ResolvedBag::Entry& entry = bag->entries[i];
+
+ // Resolve any references to their final value.
+ Res_value value = entry.value;
+ ResTable_config selected_config;
+ uint32_t flags;
+ uint32_t ref;
+ ApkAssetsCookie cookie =
+ assetmanager->ResolveReference(entry.cookie, &value, &selected_config, &flags, &ref);
+ if (cookie == kInvalidCookie) {
+ return nullptr;
+ }
+
+ if (value.dataType == Res_value::TYPE_STRING) {
+ const ApkAssets* apk_assets = assetmanager->GetApkAssets()[cookie];
+ const ResStringPool* pool = apk_assets->GetLoadedArsc()->GetStringPool();
+
+ jstring java_string = nullptr;
+ size_t str_len;
+ const char* str_utf8 = pool->string8At(value.data, &str_len);
+ if (str_utf8 != nullptr) {
+ java_string = env->NewStringUTF(str_utf8);
+ } else {
+ const char16_t* str_utf16 = pool->stringAt(value.data, &str_len);
+ java_string = env->NewString(reinterpret_cast<const jchar*>(str_utf16), str_len);
+ }
+
+ // Check for errors creating the strings (if malformed or no memory).
+ if (env->ExceptionCheck()) {
+ return nullptr;
+ }
+
+ env->SetObjectArrayElement(array, i, java_string);
+
+ // If we have a large amount of string in our array, we might overflow the
+ // local reference table of the VM.
+ env->DeleteLocalRef(java_string);
+ }
+ }
+ return array;
+}
+
+static jintArray NativeGetResourceStringArrayInfo(JNIEnv* env, jclass /*clazz*/, jlong ptr,
+ jint resid) {
+ ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
+ const ResolvedBag* bag = assetmanager->GetBag(static_cast<uint32_t>(resid));
+ if (bag == nullptr) {
+ return nullptr;
+ }
+
+ jintArray array = env->NewIntArray(bag->entry_count * 2);
+ if (array == nullptr) {
+ return nullptr;
+ }
+
+ jint* buffer = reinterpret_cast<jint*>(env->GetPrimitiveArrayCritical(array, nullptr));
+ if (buffer == nullptr) {
+ return nullptr;
+ }
+
+ for (size_t i = 0; i < bag->entry_count; i++) {
+ const ResolvedBag::Entry& entry = bag->entries[i];
+ Res_value value = entry.value;
+ ResTable_config selected_config;
+ uint32_t flags;
+ uint32_t ref;
+ ApkAssetsCookie cookie =
+ assetmanager->ResolveReference(entry.cookie, &value, &selected_config, &flags, &ref);
+ if (cookie == kInvalidCookie) {
+ env->ReleasePrimitiveArrayCritical(array, buffer, JNI_ABORT);
+ return nullptr;
+ }
+
+ jint string_index = -1;
+ if (value.dataType == Res_value::TYPE_STRING) {
+ string_index = static_cast<jint>(value.data);
+ }
+
+ buffer[i * 2] = ApkAssetsCookieToJavaCookie(cookie);
+ buffer[(i * 2) + 1] = string_index;
+ }
+ env->ReleasePrimitiveArrayCritical(array, buffer, 0);
+ return array;
+}
+
+static jintArray NativeGetResourceIntArray(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint resid) {
+ ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
+ const ResolvedBag* bag = assetmanager->GetBag(static_cast<uint32_t>(resid));
+ if (bag == nullptr) {
+ return nullptr;
+ }
+
+ jintArray array = env->NewIntArray(bag->entry_count);
+ if (array == nullptr) {
+ return nullptr;
+ }
+
+ jint* buffer = reinterpret_cast<jint*>(env->GetPrimitiveArrayCritical(array, nullptr));
+ if (buffer == nullptr) {
+ return nullptr;
+ }
+
+ for (size_t i = 0; i < bag->entry_count; i++) {
+ const ResolvedBag::Entry& entry = bag->entries[i];
+ Res_value value = entry.value;
+ ResTable_config selected_config;
+ uint32_t flags;
+ uint32_t ref;
+ ApkAssetsCookie cookie =
+ assetmanager->ResolveReference(entry.cookie, &value, &selected_config, &flags, &ref);
+ if (cookie == kInvalidCookie) {
+ env->ReleasePrimitiveArrayCritical(array, buffer, JNI_ABORT);
+ return nullptr;
+ }
+
+ if (value.dataType >= Res_value::TYPE_FIRST_INT && value.dataType <= Res_value::TYPE_LAST_INT) {
+ buffer[i] = static_cast<jint>(value.data);
+ }
+ }
+ env->ReleasePrimitiveArrayCritical(array, buffer, 0);
+ return array;
+}
+
+static jint NativeGetResourceArraySize(JNIEnv* /*env*/, jclass /*clazz*/, jlong ptr, jint resid) {
+ ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
+ const ResolvedBag* bag = assetmanager->GetBag(static_cast<uint32_t>(resid));
+ if (bag == nullptr) {
+ return -1;
+ }
+ return static_cast<jint>(bag->entry_count);
+}
+
+static jint NativeGetResourceArray(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint resid,
+ jintArray out_data) {
+ ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
+ const ResolvedBag* bag = assetmanager->GetBag(static_cast<uint32_t>(resid));
+ if (bag == nullptr) {
+ return -1;
+ }
+
+ const jsize out_data_length = env->GetArrayLength(out_data);
+ if (env->ExceptionCheck()) {
+ return -1;
+ }
+
+ if (static_cast<jsize>(bag->entry_count) > out_data_length * STYLE_NUM_ENTRIES) {
+ jniThrowException(env, "java/lang/IllegalArgumentException", "Input array is not large enough");
+ return -1;
+ }
+
+ jint* buffer = reinterpret_cast<jint*>(env->GetPrimitiveArrayCritical(out_data, nullptr));
+ if (buffer == nullptr) {
+ return -1;
+ }
+
+ jint* cursor = buffer;
+ for (size_t i = 0; i < bag->entry_count; i++) {
+ const ResolvedBag::Entry& entry = bag->entries[i];
+ Res_value value = entry.value;
+ ResTable_config selected_config;
+ selected_config.density = 0;
+ uint32_t flags = bag->type_spec_flags;
+ uint32_t ref;
+ ApkAssetsCookie cookie =
+ assetmanager->ResolveReference(entry.cookie, &value, &selected_config, &flags, &ref);
+ if (cookie == kInvalidCookie) {
+ env->ReleasePrimitiveArrayCritical(out_data, buffer, JNI_ABORT);
+ return -1;
+ }
+
+ // Deal with the special @null value -- it turns back to TYPE_NULL.
+ if (value.dataType == Res_value::TYPE_REFERENCE && value.data == 0) {
+ value.dataType = Res_value::TYPE_NULL;
+ value.data = Res_value::DATA_NULL_UNDEFINED;
+ }
+
+ cursor[STYLE_TYPE] = static_cast<jint>(value.dataType);
+ cursor[STYLE_DATA] = static_cast<jint>(value.data);
+ cursor[STYLE_ASSET_COOKIE] = ApkAssetsCookieToJavaCookie(cookie);
+ cursor[STYLE_RESOURCE_ID] = static_cast<jint>(ref);
+ cursor[STYLE_CHANGING_CONFIGURATIONS] = static_cast<jint>(flags);
+ cursor[STYLE_DENSITY] = static_cast<jint>(selected_config.density);
+ cursor += STYLE_NUM_ENTRIES;
+ }
+ env->ReleasePrimitiveArrayCritical(out_data, buffer, 0);
+ return static_cast<jint>(bag->entry_count);
+}
+
+static jint NativeGetResourceIdentifier(JNIEnv* env, jclass /*clazz*/, jlong ptr, jstring name,
+ jstring def_type, jstring def_package) {
+ ScopedUtfChars name_utf8(env, name);
+ if (name_utf8.c_str() == nullptr) {
+ // This will throw NPE.
+ return 0;
+ }
+
+ std::string type;
+ if (def_type != nullptr) {
+ ScopedUtfChars type_utf8(env, def_type);
+ CHECK(type_utf8.c_str() != nullptr);
+ type = type_utf8.c_str();
+ }
+
+ std::string package;
+ if (def_package != nullptr) {
+ ScopedUtfChars package_utf8(env, def_package);
+ CHECK(package_utf8.c_str() != nullptr);
+ package = package_utf8.c_str();
+ }
+ ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
+ return static_cast<jint>(assetmanager->GetResourceId(name_utf8.c_str(), type, package));
+}
+
+static jstring NativeGetResourceName(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint resid) {
+ ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
+ AssetManager2::ResourceName name;
+ if (!assetmanager->GetResourceName(static_cast<uint32_t>(resid), &name)) {
+ return nullptr;
+ }
+
+ std::string result;
+ if (name.package != nullptr) {
+ result.append(name.package, name.package_len);
+ }
+
+ if (name.type != nullptr || name.type16 != nullptr) {
+ if (!result.empty()) {
+ result += ":";
+ }
+
+ if (name.type != nullptr) {
+ result.append(name.type, name.type_len);
+ } else {
+ result += util::Utf16ToUtf8(StringPiece16(name.type16, name.type_len));
+ }
+ }
+
+ if (name.entry != nullptr || name.entry16 != nullptr) {
+ if (!result.empty()) {
+ result += "/";
+ }
+
+ if (name.entry != nullptr) {
+ result.append(name.entry, name.entry_len);
+ } else {
+ result += util::Utf16ToUtf8(StringPiece16(name.entry16, name.entry_len));
+ }
+ }
+ return env->NewStringUTF(result.c_str());
+}
+
+static jstring NativeGetResourcePackageName(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint resid) {
+ ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
+ AssetManager2::ResourceName name;
+ if (!assetmanager->GetResourceName(static_cast<uint32_t>(resid), &name)) {
+ return nullptr;
+ }
+
+ if (name.package != nullptr) {
+ return env->NewStringUTF(name.package);
+ }
+ return nullptr;
+}
+
+static jstring NativeGetResourceTypeName(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint resid) {
+ ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
+ AssetManager2::ResourceName name;
+ if (!assetmanager->GetResourceName(static_cast<uint32_t>(resid), &name)) {
+ return nullptr;
+ }
+
+ if (name.type != nullptr) {
+ return env->NewStringUTF(name.type);
+ } else if (name.type16 != nullptr) {
+ return env->NewString(reinterpret_cast<const jchar*>(name.type16), name.type_len);
+ }
+ return nullptr;
+}
+
+static jstring NativeGetResourceEntryName(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint resid) {
+ ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
+ AssetManager2::ResourceName name;
+ if (!assetmanager->GetResourceName(static_cast<uint32_t>(resid), &name)) {
+ return nullptr;
+ }
+
+ if (name.entry != nullptr) {
+ return env->NewStringUTF(name.entry);
+ } else if (name.entry16 != nullptr) {
+ return env->NewString(reinterpret_cast<const jchar*>(name.entry16), name.entry_len);
+ }
+ return nullptr;
+}
+
+static jobjectArray NativeGetLocales(JNIEnv* env, jclass /*class*/, jlong ptr,
+ jboolean exclude_system) {
+ ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
+ std::set<std::string> locales =
+ assetmanager->GetResourceLocales(exclude_system, true /*merge_equivalent_languages*/);
+
+ jobjectArray array = env->NewObjectArray(locales.size(), g_stringClass, nullptr);
+ if (array == nullptr) {
+ return nullptr;
+ }
+
+ size_t idx = 0;
+ for (const std::string& locale : locales) {
+ jstring java_string = env->NewStringUTF(locale.c_str());
+ if (java_string == nullptr) {
+ return nullptr;
+ }
+ env->SetObjectArrayElement(array, idx++, java_string);
+ env->DeleteLocalRef(java_string);
+ }
+ return array;
+}
+
+static jobject ConstructConfigurationObject(JNIEnv* env, const ResTable_config& config) {
+ jobject result =
+ env->NewObject(gConfigurationOffsets.classObject, gConfigurationOffsets.constructor);
+ if (result == nullptr) {
+ return nullptr;
+ }
+
+ env->SetIntField(result, gConfigurationOffsets.mSmallestScreenWidthDpOffset,
+ config.smallestScreenWidthDp);
+ env->SetIntField(result, gConfigurationOffsets.mScreenWidthDpOffset, config.screenWidthDp);
+ env->SetIntField(result, gConfigurationOffsets.mScreenHeightDpOffset, config.screenHeightDp);
+ return result;
+}
+
+static jobjectArray NativeGetSizeConfigurations(JNIEnv* env, jclass /*clazz*/, jlong ptr) {
+ ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
+ std::set<ResTable_config> configurations =
+ assetmanager->GetResourceConfigurations(true /*exclude_system*/, false /*exclude_mipmap*/);
+
+ jobjectArray array =
+ env->NewObjectArray(configurations.size(), gConfigurationOffsets.classObject, nullptr);
+ if (array == nullptr) {
+ return nullptr;
+ }
+
+ size_t idx = 0;
+ for (const ResTable_config& configuration : configurations) {
+ jobject java_configuration = ConstructConfigurationObject(env, configuration);
+ if (java_configuration == nullptr) {
+ return nullptr;
+ }
+
+ env->SetObjectArrayElement(array, idx++, java_configuration);
+ env->DeleteLocalRef(java_configuration);
+ }
+ return array;
+}
+
+static void NativeApplyStyle(JNIEnv* env, jclass /*clazz*/, jlong ptr, jlong theme_ptr,
+ jint def_style_attr, jint def_style_resid, jlong xml_parser_ptr,
+ jintArray java_attrs, jlong out_values_ptr, jlong out_indices_ptr) {
+ ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
+ Theme* theme = reinterpret_cast<Theme*>(theme_ptr);
+ CHECK(theme->GetAssetManager() == &(*assetmanager));
+ (void) assetmanager;
+
+ ResXMLParser* xml_parser = reinterpret_cast<ResXMLParser*>(xml_parser_ptr);
+ uint32_t* out_values = reinterpret_cast<uint32_t*>(out_values_ptr);
+ uint32_t* out_indices = reinterpret_cast<uint32_t*>(out_indices_ptr);
+
+ jsize attrs_len = env->GetArrayLength(java_attrs);
+ jint* attrs = reinterpret_cast<jint*>(env->GetPrimitiveArrayCritical(java_attrs, nullptr));
+ if (attrs == nullptr) {
+ return;
+ }
+
+ ApplyStyle(theme, xml_parser, static_cast<uint32_t>(def_style_attr),
+ static_cast<uint32_t>(def_style_resid), reinterpret_cast<uint32_t*>(attrs), attrs_len,
+ out_values, out_indices);
+ env->ReleasePrimitiveArrayCritical(java_attrs, attrs, JNI_ABORT);
+}
+
+static jboolean NativeResolveAttrs(JNIEnv* env, jclass /*clazz*/, jlong ptr, jlong theme_ptr,
+ jint def_style_attr, jint def_style_resid, jintArray java_values,
+ jintArray java_attrs, jintArray out_java_values,
+ jintArray out_java_indices) {
+ const jsize attrs_len = env->GetArrayLength(java_attrs);
+ const jsize out_values_len = env->GetArrayLength(out_java_values);
+ if (out_values_len < (attrs_len * STYLE_NUM_ENTRIES)) {
+ jniThrowException(env, "java/lang/IndexOutOfBoundsException", "outValues too small");
+ return JNI_FALSE;
+ }
+
+ jint* attrs = reinterpret_cast<jint*>(env->GetPrimitiveArrayCritical(java_attrs, nullptr));
+ if (attrs == nullptr) {
+ return JNI_FALSE;
+ }
+
+ jint* values = nullptr;
+ jsize values_len = 0;
+ if (java_values != nullptr) {
+ values_len = env->GetArrayLength(java_values);
+ values = reinterpret_cast<jint*>(env->GetPrimitiveArrayCritical(java_values, nullptr));
+ if (values == nullptr) {
+ env->ReleasePrimitiveArrayCritical(java_attrs, attrs, JNI_ABORT);
+ return JNI_FALSE;
+ }
+ }
+
+ jint* out_values =
+ reinterpret_cast<jint*>(env->GetPrimitiveArrayCritical(out_java_values, nullptr));
+ if (out_values == nullptr) {
+ env->ReleasePrimitiveArrayCritical(java_attrs, attrs, JNI_ABORT);
+ if (values != nullptr) {
+ env->ReleasePrimitiveArrayCritical(java_values, values, JNI_ABORT);
+ }
+ return JNI_FALSE;
+ }
+
+ jint* out_indices = nullptr;
+ if (out_java_indices != nullptr) {
+ jsize out_indices_len = env->GetArrayLength(out_java_indices);
+ if (out_indices_len > attrs_len) {
+ out_indices =
+ reinterpret_cast<jint*>(env->GetPrimitiveArrayCritical(out_java_indices, nullptr));
+ if (out_indices == nullptr) {
+ env->ReleasePrimitiveArrayCritical(java_attrs, attrs, JNI_ABORT);
+ if (values != nullptr) {
+ env->ReleasePrimitiveArrayCritical(java_values, values, JNI_ABORT);
+ }
+ env->ReleasePrimitiveArrayCritical(out_java_values, out_values, JNI_ABORT);
+ return JNI_FALSE;
+ }
+ }
+ }
+
+ ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
+ Theme* theme = reinterpret_cast<Theme*>(theme_ptr);
+ CHECK(theme->GetAssetManager() == &(*assetmanager));
+ (void) assetmanager;
+
+ bool result = ResolveAttrs(
+ theme, static_cast<uint32_t>(def_style_attr), static_cast<uint32_t>(def_style_resid),
+ reinterpret_cast<uint32_t*>(values), values_len, reinterpret_cast<uint32_t*>(attrs),
+ attrs_len, reinterpret_cast<uint32_t*>(out_values), reinterpret_cast<uint32_t*>(out_indices));
+ if (out_indices != nullptr) {
+ env->ReleasePrimitiveArrayCritical(out_java_indices, out_indices, 0);
+ }
+
+ env->ReleasePrimitiveArrayCritical(out_java_values, out_values, 0);
+ if (values != nullptr) {
+ env->ReleasePrimitiveArrayCritical(java_values, values, JNI_ABORT);
+ }
+ env->ReleasePrimitiveArrayCritical(java_attrs, attrs, JNI_ABORT);
+ return result ? JNI_TRUE : JNI_FALSE;
+}
+
+static jboolean NativeRetrieveAttributes(JNIEnv* env, jclass /*clazz*/, jlong ptr,
+ jlong xml_parser_ptr, jintArray java_attrs,
+ jintArray out_java_values, jintArray out_java_indices) {
+ const jsize attrs_len = env->GetArrayLength(java_attrs);
+ const jsize out_values_len = env->GetArrayLength(out_java_values);
+ if (out_values_len < (attrs_len * STYLE_NUM_ENTRIES)) {
+ jniThrowException(env, "java/lang/IndexOutOfBoundsException", "outValues too small");
+ return JNI_FALSE;
+ }
+
+ jint* attrs = reinterpret_cast<jint*>(env->GetPrimitiveArrayCritical(java_attrs, nullptr));
+ if (attrs == nullptr) {
+ return JNI_FALSE;
+ }
+
+ jint* out_values =
+ reinterpret_cast<jint*>(env->GetPrimitiveArrayCritical(out_java_values, nullptr));
+ if (out_values == nullptr) {
+ env->ReleasePrimitiveArrayCritical(java_attrs, attrs, JNI_ABORT);
+ return JNI_FALSE;
+ }
+
+ jint* out_indices = nullptr;
+ if (out_java_indices != nullptr) {
+ jsize out_indices_len = env->GetArrayLength(out_java_indices);
+ if (out_indices_len > attrs_len) {
+ out_indices =
+ reinterpret_cast<jint*>(env->GetPrimitiveArrayCritical(out_java_indices, nullptr));
+ if (out_indices == nullptr) {
+ env->ReleasePrimitiveArrayCritical(java_attrs, attrs, JNI_ABORT);
+ env->ReleasePrimitiveArrayCritical(out_java_values, out_values, JNI_ABORT);
+ return JNI_FALSE;
+ }
+ }
+ }
+
+ ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
+ ResXMLParser* xml_parser = reinterpret_cast<ResXMLParser*>(xml_parser_ptr);
+
+ bool result = RetrieveAttributes(assetmanager.get(), xml_parser,
+ reinterpret_cast<uint32_t*>(attrs), attrs_len,
+ reinterpret_cast<uint32_t*>(out_values),
+ reinterpret_cast<uint32_t*>(out_indices));
+
+ if (out_indices != nullptr) {
+ env->ReleasePrimitiveArrayCritical(out_java_indices, out_indices, 0);
+ }
+ env->ReleasePrimitiveArrayCritical(out_java_values, out_values, 0);
+ env->ReleasePrimitiveArrayCritical(java_attrs, attrs, JNI_ABORT);
+ return result ? JNI_TRUE : JNI_FALSE;
+}
+
+static jlong NativeThemeCreate(JNIEnv* /*env*/, jclass /*clazz*/, jlong ptr) {
+ ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
+ return reinterpret_cast<jlong>(assetmanager->NewTheme().release());
+}
+
+static void NativeThemeDestroy(JNIEnv* /*env*/, jclass /*clazz*/, jlong theme_ptr) {
+ delete reinterpret_cast<Theme*>(theme_ptr);
+}
+
+static void NativeThemeApplyStyle(JNIEnv* env, jclass /*clazz*/, jlong ptr, jlong theme_ptr,
+ jint resid, jboolean force) {
+ // AssetManager is accessed via the theme, so grab an explicit lock here.
+ ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
+ Theme* theme = reinterpret_cast<Theme*>(theme_ptr);
+ CHECK(theme->GetAssetManager() == &(*assetmanager));
+ (void) assetmanager;
+ theme->ApplyStyle(static_cast<uint32_t>(resid), force);
+
+ // TODO(adamlesinski): Consider surfacing exception when result is failure.
+ // CTS currently expects no exceptions from this method.
+ // std::string error_msg = StringPrintf("Failed to apply style 0x%08x to theme", resid);
+ // jniThrowException(env, "java/lang/IllegalArgumentException", error_msg.c_str());
+}
+
+static void NativeThemeCopy(JNIEnv* env, jclass /*clazz*/, jlong dst_theme_ptr,
+ jlong src_theme_ptr) {
+ Theme* dst_theme = reinterpret_cast<Theme*>(dst_theme_ptr);
+ Theme* src_theme = reinterpret_cast<Theme*>(src_theme_ptr);
+ if (!dst_theme->SetTo(*src_theme)) {
+ jniThrowException(env, "java/lang/IllegalArgumentException",
+ "Themes are from different AssetManagers");
+ }
+}
+
+static void NativeThemeClear(JNIEnv* /*env*/, jclass /*clazz*/, jlong theme_ptr) {
+ reinterpret_cast<Theme*>(theme_ptr)->Clear();
+}
+
+static jint NativeThemeGetAttributeValue(JNIEnv* env, jclass /*clazz*/, jlong ptr, jlong theme_ptr,
+ jint resid, jobject typed_value,
+ jboolean resolve_references) {
+ ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
+ Theme* theme = reinterpret_cast<Theme*>(theme_ptr);
+ CHECK(theme->GetAssetManager() == &(*assetmanager));
+ (void) assetmanager;
+
+ Res_value value;
+ uint32_t flags;
+ ApkAssetsCookie cookie = theme->GetAttribute(static_cast<uint32_t>(resid), &value, &flags);
+ if (cookie == kInvalidCookie) {
+ return ApkAssetsCookieToJavaCookie(kInvalidCookie);
+ }
+
+ uint32_t ref = 0u;
+ if (resolve_references) {
+ ResTable_config selected_config;
+ cookie =
+ theme->GetAssetManager()->ResolveReference(cookie, &value, &selected_config, &flags, &ref);
+ if (cookie == kInvalidCookie) {
+ return ApkAssetsCookieToJavaCookie(kInvalidCookie);
+ }
+ }
+ return CopyValue(env, cookie, value, ref, flags, nullptr, typed_value);
+}
+
+static void NativeThemeDump(JNIEnv* /*env*/, jclass /*clazz*/, jlong ptr, jlong theme_ptr,
+ jint priority, jstring tag, jstring prefix) {
+ ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
+ Theme* theme = reinterpret_cast<Theme*>(theme_ptr);
+ CHECK(theme->GetAssetManager() == &(*assetmanager));
+ (void) assetmanager;
+ (void) theme;
+ (void) priority;
+ (void) tag;
+ (void) prefix;
+}
+
+static jint NativeThemeGetChangingConfigurations(JNIEnv* /*env*/, jclass /*clazz*/,
+ jlong theme_ptr) {
+ Theme* theme = reinterpret_cast<Theme*>(theme_ptr);
+ return static_cast<jint>(theme->GetChangingConfigurations());
+}
+
+static void NativeAssetDestroy(JNIEnv* /*env*/, jclass /*clazz*/, jlong asset_ptr) {
+ delete reinterpret_cast<Asset*>(asset_ptr);
+}
+
+static jint NativeAssetReadChar(JNIEnv* /*env*/, jclass /*clazz*/, jlong asset_ptr) {
+ Asset* asset = reinterpret_cast<Asset*>(asset_ptr);
+ uint8_t b;
+ ssize_t res = asset->read(&b, sizeof(b));
+ return res == sizeof(b) ? static_cast<jint>(b) : -1;
+}
+
+static jint NativeAssetRead(JNIEnv* env, jclass /*clazz*/, jlong asset_ptr, jbyteArray java_buffer,
+ jint offset, jint len) {
+ if (len == 0) {
+ return 0;
+ }
+
+ jsize buffer_len = env->GetArrayLength(java_buffer);
+ if (offset < 0 || offset >= buffer_len || len < 0 || len > buffer_len ||
+ offset > buffer_len - len) {
+ jniThrowException(env, "java/lang/IndexOutOfBoundsException", "");
+ return -1;
+ }
+
+ ScopedByteArrayRW byte_array(env, java_buffer);
+ if (byte_array.get() == nullptr) {
+ return -1;
+ }
+
+ Asset* asset = reinterpret_cast<Asset*>(asset_ptr);
+ ssize_t res = asset->read(byte_array.get() + offset, len);
+ if (res < 0) {
+ jniThrowException(env, "java/io/IOException", "");
+ return -1;
+ }
+ return res > 0 ? static_cast<jint>(res) : -1;
+}
+
+static jlong NativeAssetSeek(JNIEnv* env, jclass /*clazz*/, jlong asset_ptr, jlong offset,
+ jint whence) {
+ Asset* asset = reinterpret_cast<Asset*>(asset_ptr);
+ return static_cast<jlong>(asset->seek(
+ static_cast<off64_t>(offset), (whence > 0 ? SEEK_END : (whence < 0 ? SEEK_SET : SEEK_CUR))));
+}
+
+static jlong NativeAssetGetLength(JNIEnv* /*env*/, jclass /*clazz*/, jlong asset_ptr) {
+ Asset* asset = reinterpret_cast<Asset*>(asset_ptr);
+ return static_cast<jlong>(asset->getLength());
+}
+
+static jlong NativeAssetGetRemainingLength(JNIEnv* /*env*/, jclass /*clazz*/, jlong asset_ptr) {
+ Asset* asset = reinterpret_cast<Asset*>(asset_ptr);
+ return static_cast<jlong>(asset->getRemainingLength());
+}
+
+// ----------------------------------------------------------------------------
+
+// JNI registration.
+static const JNINativeMethod gAssetManagerMethods[] = {
+ // AssetManager setup methods.
+ {"nativeCreate", "()J", (void*)NativeCreate},
+ {"nativeDestroy", "(J)V", (void*)NativeDestroy},
+ {"nativeSetApkAssets", "(J[Landroid/content/res/ApkAssets;Z)V", (void*)NativeSetApkAssets},
+ {"nativeSetConfiguration", "(JIILjava/lang/String;IIIIIIIIIIIIIII)V",
+ (void*)NativeSetConfiguration},
+ {"nativeGetAssignedPackageIdentifiers", "(J)Landroid/util/SparseArray;",
+ (void*)NativeGetAssignedPackageIdentifiers},
+
+ // AssetManager file methods.
+ {"nativeList", "(JLjava/lang/String;)[Ljava/lang/String;", (void*)NativeList},
+ {"nativeOpenAsset", "(JLjava/lang/String;I)J", (void*)NativeOpenAsset},
+ {"nativeOpenAssetFd", "(JLjava/lang/String;[J)Landroid/os/ParcelFileDescriptor;",
+ (void*)NativeOpenAssetFd},
+ {"nativeOpenNonAsset", "(JILjava/lang/String;I)J", (void*)NativeOpenNonAsset},
+ {"nativeOpenNonAssetFd", "(JILjava/lang/String;[J)Landroid/os/ParcelFileDescriptor;",
+ (void*)NativeOpenNonAssetFd},
+ {"nativeOpenXmlAsset", "(JILjava/lang/String;)J", (void*)NativeOpenXmlAsset},
+
+ // AssetManager resource methods.
+ {"nativeGetResourceValue", "(JISLandroid/util/TypedValue;Z)I", (void*)NativeGetResourceValue},
+ {"nativeGetResourceBagValue", "(JIILandroid/util/TypedValue;)I",
+ (void*)NativeGetResourceBagValue},
+ {"nativeGetStyleAttributes", "(JI)[I", (void*)NativeGetStyleAttributes},
+ {"nativeGetResourceStringArray", "(JI)[Ljava/lang/String;",
+ (void*)NativeGetResourceStringArray},
+ {"nativeGetResourceStringArrayInfo", "(JI)[I", (void*)NativeGetResourceStringArrayInfo},
+ {"nativeGetResourceIntArray", "(JI)[I", (void*)NativeGetResourceIntArray},
+ {"nativeGetResourceArraySize", "(JI)I", (void*)NativeGetResourceArraySize},
+ {"nativeGetResourceArray", "(JI[I)I", (void*)NativeGetResourceArray},
+
+ // AssetManager resource name/ID methods.
+ {"nativeGetResourceIdentifier", "(JLjava/lang/String;Ljava/lang/String;Ljava/lang/String;)I",
+ (void*)NativeGetResourceIdentifier},
+ {"nativeGetResourceName", "(JI)Ljava/lang/String;", (void*)NativeGetResourceName},
+ {"nativeGetResourcePackageName", "(JI)Ljava/lang/String;", (void*)NativeGetResourcePackageName},
+ {"nativeGetResourceTypeName", "(JI)Ljava/lang/String;", (void*)NativeGetResourceTypeName},
+ {"nativeGetResourceEntryName", "(JI)Ljava/lang/String;", (void*)NativeGetResourceEntryName},
+ {"nativeGetLocales", "(JZ)[Ljava/lang/String;", (void*)NativeGetLocales},
+ {"nativeGetSizeConfigurations", "(J)[Landroid/content/res/Configuration;",
+ (void*)NativeGetSizeConfigurations},
+
+ // Style attribute related methods.
+ {"nativeApplyStyle", "(JJIIJ[IJJ)V", (void*)NativeApplyStyle},
+ {"nativeResolveAttrs", "(JJII[I[I[I[I)Z", (void*)NativeResolveAttrs},
+ {"nativeRetrieveAttributes", "(JJ[I[I[I)Z", (void*)NativeRetrieveAttributes},
+
+ // Theme related methods.
+ {"nativeThemeCreate", "(J)J", (void*)NativeThemeCreate},
+ {"nativeThemeDestroy", "(J)V", (void*)NativeThemeDestroy},
+ {"nativeThemeApplyStyle", "(JJIZ)V", (void*)NativeThemeApplyStyle},
+ {"nativeThemeCopy", "(JJ)V", (void*)NativeThemeCopy},
+ {"nativeThemeClear", "(J)V", (void*)NativeThemeClear},
+ {"nativeThemeGetAttributeValue", "(JJILandroid/util/TypedValue;Z)I",
+ (void*)NativeThemeGetAttributeValue},
+ {"nativeThemeDump", "(JJILjava/lang/String;Ljava/lang/String;)V", (void*)NativeThemeDump},
+ {"nativeThemeGetChangingConfigurations", "(J)I", (void*)NativeThemeGetChangingConfigurations},
+
+ // AssetInputStream methods.
+ {"nativeAssetDestroy", "(J)V", (void*)NativeAssetDestroy},
+ {"nativeAssetReadChar", "(J)I", (void*)NativeAssetReadChar},
+ {"nativeAssetRead", "(J[BII)I", (void*)NativeAssetRead},
+ {"nativeAssetSeek", "(JJI)J", (void*)NativeAssetSeek},
+ {"nativeAssetGetLength", "(J)J", (void*)NativeAssetGetLength},
+ {"nativeAssetGetRemainingLength", "(J)J", (void*)NativeAssetGetRemainingLength},
+
+ // System/idmap related methods.
+ {"nativeVerifySystemIdmaps", "()V", (void*)NativeVerifySystemIdmaps},
+
+ // Global management/debug methods.
+ {"getGlobalAssetCount", "()I", (void*)NativeGetGlobalAssetCount},
+ {"getAssetAllocations", "()Ljava/lang/String;", (void*)NativeGetAssetAllocations},
+ {"getGlobalAssetManagerCount", "()I", (void*)NativeGetGlobalAssetManagerCount},
+};
+
+int register_android_content_AssetManager(JNIEnv* env) {
+ jclass apk_assets_class = FindClassOrDie(env, "android/content/res/ApkAssets");
+ gApkAssetsFields.native_ptr = GetFieldIDOrDie(env, apk_assets_class, "mNativePtr", "J");
+
+ jclass typedValue = FindClassOrDie(env, "android/util/TypedValue");
+ gTypedValueOffsets.mType = GetFieldIDOrDie(env, typedValue, "type", "I");
+ gTypedValueOffsets.mData = GetFieldIDOrDie(env, typedValue, "data", "I");
+ gTypedValueOffsets.mString =
+ GetFieldIDOrDie(env, typedValue, "string", "Ljava/lang/CharSequence;");
+ gTypedValueOffsets.mAssetCookie = GetFieldIDOrDie(env, typedValue, "assetCookie", "I");
+ gTypedValueOffsets.mResourceId = GetFieldIDOrDie(env, typedValue, "resourceId", "I");
+ gTypedValueOffsets.mChangingConfigurations =
+ GetFieldIDOrDie(env, typedValue, "changingConfigurations", "I");
+ gTypedValueOffsets.mDensity = GetFieldIDOrDie(env, typedValue, "density", "I");
+
+ jclass assetFd = FindClassOrDie(env, "android/content/res/AssetFileDescriptor");
+ gAssetFileDescriptorOffsets.mFd =
+ GetFieldIDOrDie(env, assetFd, "mFd", "Landroid/os/ParcelFileDescriptor;");
+ gAssetFileDescriptorOffsets.mStartOffset = GetFieldIDOrDie(env, assetFd, "mStartOffset", "J");
+ gAssetFileDescriptorOffsets.mLength = GetFieldIDOrDie(env, assetFd, "mLength", "J");
+
+ jclass assetManager = FindClassOrDie(env, "android/content/res/AssetManager");
+ gAssetManagerOffsets.mObject = GetFieldIDOrDie(env, assetManager, "mObject", "J");
+
+ jclass stringClass = FindClassOrDie(env, "java/lang/String");
+ g_stringClass = MakeGlobalRefOrDie(env, stringClass);
+
+ jclass sparseArrayClass = FindClassOrDie(env, "android/util/SparseArray");
+ gSparseArrayOffsets.classObject = MakeGlobalRefOrDie(env, sparseArrayClass);
+ gSparseArrayOffsets.constructor =
+ GetMethodIDOrDie(env, gSparseArrayOffsets.classObject, "<init>", "()V");
+ gSparseArrayOffsets.put =
+ GetMethodIDOrDie(env, gSparseArrayOffsets.classObject, "put", "(ILjava/lang/Object;)V");
+
+ jclass configurationClass = FindClassOrDie(env, "android/content/res/Configuration");
+ gConfigurationOffsets.classObject = MakeGlobalRefOrDie(env, configurationClass);
+ gConfigurationOffsets.constructor = GetMethodIDOrDie(env, configurationClass, "<init>", "()V");
+ gConfigurationOffsets.mSmallestScreenWidthDpOffset =
+ GetFieldIDOrDie(env, configurationClass, "smallestScreenWidthDp", "I");
+ gConfigurationOffsets.mScreenWidthDpOffset =
+ GetFieldIDOrDie(env, configurationClass, "screenWidthDp", "I");
+ gConfigurationOffsets.mScreenHeightDpOffset =
+ GetFieldIDOrDie(env, configurationClass, "screenHeightDp", "I");
+
+ return RegisterMethodsOrDie(env, "android/content/res/AssetManager", gAssetManagerMethods,
+ NELEM(gAssetManagerMethods));
}
}; // namespace android
diff --git a/core/jni/include/android_runtime/android_util_AssetManager.h b/core/jni/include/android_runtime/android_util_AssetManager.h
index 8dd9337..2c1e357 100644
--- a/core/jni/include/android_runtime/android_util_AssetManager.h
+++ b/core/jni/include/android_runtime/android_util_AssetManager.h
@@ -14,17 +14,20 @@
* limitations under the License.
*/
-#ifndef android_util_AssetManager_H
-#define android_util_AssetManager_H
+#ifndef ANDROID_RUNTIME_ASSETMANAGER_H
+#define ANDROID_RUNTIME_ASSETMANAGER_H
-#include <androidfw/AssetManager.h>
+#include "androidfw/AssetManager2.h"
+#include "androidfw/MutexGuard.h"
#include "jni.h"
namespace android {
-extern AssetManager* assetManagerForJavaObject(JNIEnv* env, jobject assetMgr);
+extern AAssetManager* NdkAssetManagerForJavaObject(JNIEnv* env, jobject jassetmanager);
+extern Guarded<AssetManager2>* AssetManagerForJavaObject(JNIEnv* env, jobject jassetmanager);
+extern Guarded<AssetManager2>* AssetManagerForNdkAssetManager(AAssetManager* assetmanager);
-}
+} // namespace android
-#endif
+#endif // ANDROID_RUNTIME_ASSETMANAGER_H
diff --git a/core/proto/android/server/statlogger.proto b/core/proto/android/server/statlogger.proto
index 2ae526a..2b7daea 100644
--- a/core/proto/android/server/statlogger.proto
+++ b/core/proto/android/server/statlogger.proto
@@ -24,10 +24,13 @@
// Dump from StatLogger.
message StatLoggerProto {
- option (.android.msg_privacy).dest = DEST_EXPLICIT;
+ option (.android.msg_privacy).dest = DEST_AUTOMATIC;
message Event {
+ option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
optional int32 eventId = 1;
+ // Labels are hard-coded in Android framework code.
optional string label = 2;
optional int32 count = 3;
optional int64 total_duration_micros = 4;
diff --git a/core/res/res/drawable-watch/global_action_icon_background.xml b/core/res/res/drawable-watch/global_action_icon_background.xml
new file mode 100644
index 0000000..b7bc7e6
--- /dev/null
+++ b/core/res/res/drawable-watch/global_action_icon_background.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2018 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shape="oval"
+ android:tint="?android:attr/colorButtonNormal">
+ <solid android:color="@android:color/white"/>
+ <size android:height="40dp" android:width="40dp"/>
+</shape>
diff --git a/core/res/res/drawable/ic_qs_battery_saver.xml b/core/res/res/drawable/ic_qs_battery_saver.xml
new file mode 100644
index 0000000..89b2569
--- /dev/null
+++ b/core/res/res/drawable/ic_qs_battery_saver.xml
@@ -0,0 +1,28 @@
+<!--
+ Copyright (C) 2018 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:autoMirrored="true"
+ android:width="32.0dp"
+ android:height="32.0dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0"
+ android:tint="?android:attr/colorControlNormal">
+ <path
+ android:pathData="M5,3
+ l3.5,0 l0,-1.5 l7,0 l0,1.5 l3.5,0 l0,19.5 l-14,0z
+ M10.5,8.5 l0,3 l-3,0 l0,3 l3,0 l0,3 l3,0 l0,-3 l3,0 l0,-3 l-3,0 l0,-3 z"
+ android:fillColor="#FFFFFF"/>
+</vector>
diff --git a/core/res/res/layout-watch/global_actions_item.xml b/core/res/res/layout-watch/global_actions_item.xml
new file mode 100644
index 0000000..025d45e
--- /dev/null
+++ b/core/res/res/layout-watch/global_actions_item.xml
@@ -0,0 +1,58 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2018 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:minHeight="?attr/listPreferredItemHeightSmall"
+ android:gravity="center_vertical"
+ android:paddingStart="?attr/listPreferredItemPaddingStart"
+ android:paddingEnd="?attr/listPreferredItemPaddingEnd"
+ android:background="?attr/activatedBackgroundIndicator"
+ android:clipToPadding="false">
+ <ImageView android:id="@+id/icon"
+ android:background="@drawable/global_action_icon_background"
+ android:scaleType="centerInside"
+ android:layout_width="40dp"
+ android:layout_height="40dp"
+ android:padding="8dp"
+ android:gravity="center"
+ android:orientation="horizontal"
+ android:layout_marginEnd="8dp"
+ android:layout_marginTop="8dp"
+ android:layout_marginBottom="8dp"/>
+
+ <RelativeLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:layout_marginTop="8dp"
+ android:layout_marginBottom="8dp">
+
+ <TextView android:id="@+id/message"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textAppearance="?attr/textAppearanceListItem"
+ android:ellipsize="end" />
+
+ <TextView android:id="@+id/status"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_below="@id/message"
+ android:layout_alignStart="@id/message"
+ android:textAppearance="?attr/textAppearanceListItemSecondary"
+ android:textColor="?attr/textColorSecondary"/>
+ </RelativeLayout>
+</LinearLayout>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index f38dcea..d59ba18 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -539,6 +539,15 @@
<!-- status message in phone options dialog for when airplane mode is off -->
<string name="global_actions_airplane_mode_off_status">Airplane mode is OFF</string>
+ <!-- label for item that enables battery saver in phone options dialog -->
+ <string name="global_action_toggle_battery_saver">Battery saver</string>
+
+ <!-- status message in phone options dialog for when battery saver is enabled -->
+ <string name="global_action_battery_saver_on_status">Battery saver is OFF</string>
+
+ <!-- status message in phone options dialog for when battery saver is disabled -->
+ <string name="global_action_battery_saver_off_status">Battery saver is ON</string>
+
<!-- label for item that launches settings in phone options dialog [CHAR LIMIT=15]-->
<string name="global_action_settings">Settings</string>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 8d67957..0cd1007 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -1378,6 +1378,7 @@
<java-symbol type="drawable" name="ic_corp_statusbar_icon" />
<java-symbol type="drawable" name="ic_instant_icon_badge_bolt" />
<java-symbol type="drawable" name="emulator_circular_window_overlay" />
+ <java-symbol type="drawable" name="ic_qs_battery_saver" />
<java-symbol type="drawable" name="sim_light_blue" />
<java-symbol type="drawable" name="sim_light_green" />
@@ -1738,6 +1739,9 @@
<java-symbol type="string" name="global_action_silent_mode_off_status" />
<java-symbol type="string" name="global_action_silent_mode_on_status" />
<java-symbol type="string" name="global_action_toggle_silent_mode" />
+ <java-symbol type="string" name="global_action_battery_saver_off_status" />
+ <java-symbol type="string" name="global_action_battery_saver_on_status" />
+ <java-symbol type="string" name="global_action_toggle_battery_saver" />
<java-symbol type="string" name="global_action_lockdown" />
<java-symbol type="string" name="global_action_voice_assist" />
<java-symbol type="string" name="global_action_assist" />
diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
index d6580d6..6c72ac1 100644
--- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java
+++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
@@ -231,6 +231,7 @@
Settings.Global.FORCE_ALLOW_ON_EXTERNAL,
Settings.Global.FORCED_APP_STANDBY_ENABLED,
Settings.Global.FORCED_APP_STANDBY_FOR_SMALL_BATTERY_ENABLED,
+ Settings.Global.WIFI_ON_WHEN_PROXY_DISCONNECTED,
Settings.Global.FSTRIM_MANDATORY_INTERVAL,
Settings.Global.GLOBAL_HTTP_PROXY_EXCLUSION_LIST,
Settings.Global.GLOBAL_HTTP_PROXY_HOST,
diff --git a/core/tests/coretests/src/com/android/internal/accessibility/AccessibilityShortcutControllerTest.java b/core/tests/coretests/src/com/android/internal/accessibility/AccessibilityShortcutControllerTest.java
index a15d337..f3e10e0 100644
--- a/core/tests/coretests/src/com/android/internal/accessibility/AccessibilityShortcutControllerTest.java
+++ b/core/tests/coretests/src/com/android/internal/accessibility/AccessibilityShortcutControllerTest.java
@@ -214,6 +214,20 @@
}
@Test
+ public void testShortcutAvailable_onLockScreenAndLockScreenPreferenceUnset() {
+ // When the user hasn't specified a lock screen preference, we allow from the lock screen
+ // as long as the user has agreed to enable the shortcut
+ configureValidShortcutService();
+ configureShortcutEnabled(ENABLED_INCLUDING_LOCK_SCREEN);
+ Settings.Secure.putString(
+ mContentResolver, ACCESSIBILITY_SHORTCUT_ON_LOCK_SCREEN, null);
+ Settings.Secure.putInt(mContentResolver, ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN, 0);
+ assertFalse(getController().isAccessibilityShortcutAvailable(true));
+ Settings.Secure.putInt(mContentResolver, ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN, 1);
+ assertTrue(getController().isAccessibilityShortcutAvailable(true));
+ }
+
+ @Test
public void testShortcutAvailable_whenServiceIdBecomesNull_shouldReturnFalse() {
configureShortcutEnabled(ENABLED_EXCEPT_LOCK_SCREEN);
configureValidShortcutService();
diff --git a/core/tests/coretests/src/com/android/internal/textservice/LazyIntToIntMapTest.java b/core/tests/coretests/src/com/android/internal/textservice/LazyIntToIntMapTest.java
new file mode 100644
index 0000000..3518527
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/textservice/LazyIntToIntMapTest.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.textservice;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.concurrent.atomic.AtomicReference;
+import java.util.function.IntUnaryOperator;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class LazyIntToIntMapTest {
+ @Test
+ public void testLaziness() {
+ final IntUnaryOperator func = mock(IntUnaryOperator.class);
+ when(func.applyAsInt(eq(1))).thenReturn(11);
+ when(func.applyAsInt(eq(2))).thenReturn(22);
+
+ final LazyIntToIntMap map = new LazyIntToIntMap(func);
+
+ verify(func, never()).applyAsInt(anyInt());
+
+ assertEquals(22, map.get(2));
+ verify(func, times(0)).applyAsInt(eq(1));
+ verify(func, times(1)).applyAsInt(eq(2));
+
+ // Accessing to the same key does not evaluate the function again.
+ assertEquals(22, map.get(2));
+ verify(func, times(0)).applyAsInt(eq(1));
+ verify(func, times(1)).applyAsInt(eq(2));
+ }
+
+ @Test
+ public void testDelete() {
+ final IntUnaryOperator func1 = mock(IntUnaryOperator.class);
+ when(func1.applyAsInt(eq(1))).thenReturn(11);
+ when(func1.applyAsInt(eq(2))).thenReturn(22);
+
+ final IntUnaryOperator func2 = mock(IntUnaryOperator.class);
+ when(func2.applyAsInt(eq(1))).thenReturn(111);
+ when(func2.applyAsInt(eq(2))).thenReturn(222);
+
+ final AtomicReference<IntUnaryOperator> funcRef = new AtomicReference<>(func1);
+ final LazyIntToIntMap map = new LazyIntToIntMap(i -> funcRef.get().applyAsInt(i));
+
+ verify(func1, never()).applyAsInt(anyInt());
+ verify(func2, never()).applyAsInt(anyInt());
+
+ assertEquals(22, map.get(2));
+ verify(func1, times(1)).applyAsInt(eq(2));
+ verify(func2, times(0)).applyAsInt(eq(2));
+
+ // Swap func1 with func2 then invalidate the key=2
+ funcRef.set(func2);
+ map.delete(2);
+
+ // Calling get(2) again should re-evaluate the value.
+ assertEquals(222, map.get(2));
+ verify(func1, times(1)).applyAsInt(eq(2));
+ verify(func2, times(1)).applyAsInt(eq(2));
+
+ // Trying to delete non-existing keys does nothing.
+ map.delete(1);
+ }
+}
diff --git a/libs/androidfw/Android.bp b/libs/androidfw/Android.bp
index 251b2e7..70d5216 100644
--- a/libs/androidfw/Android.bp
+++ b/libs/androidfw/Android.bp
@@ -145,6 +145,7 @@
"tests/TypeWrappers_test.cpp",
"tests/ZipUtils_test.cpp",
],
+ static_libs: ["libgmock"],
target: {
android: {
srcs: [
@@ -171,6 +172,7 @@
// Actual benchmarks.
"tests/AssetManager2_bench.cpp",
+ "tests/AttributeResolution_bench.cpp",
"tests/SparseEntry_bench.cpp",
"tests/Theme_bench.cpp",
],
diff --git a/libs/androidfw/ApkAssets.cpp b/libs/androidfw/ApkAssets.cpp
index da0205d..8f58f74 100644
--- a/libs/androidfw/ApkAssets.cpp
+++ b/libs/androidfw/ApkAssets.cpp
@@ -14,8 +14,6 @@
* limitations under the License.
*/
-#define ATRACE_TAG ATRACE_TAG_RESOURCES
-
#include "androidfw/ApkAssets.h"
#include <algorithm>
@@ -27,7 +25,6 @@
#include "android-base/utf8.h"
#include "utils/Compat.h"
#include "utils/FileMap.h"
-#include "utils/Trace.h"
#include "ziparchive/zip_archive.h"
#include "androidfw/Asset.h"
@@ -105,8 +102,6 @@
std::unique_ptr<const ApkAssets> ApkAssets::LoadImpl(
unique_fd fd, const std::string& path, std::unique_ptr<Asset> idmap_asset,
std::unique_ptr<const LoadedIdmap> loaded_idmap, bool system, bool load_as_shared_library) {
- ATRACE_CALL();
-
::ZipArchiveHandle unmanaged_handle;
int32_t result;
if (fd >= 0) {
@@ -163,7 +158,6 @@
}
std::unique_ptr<Asset> ApkAssets::Open(const std::string& path, Asset::AccessMode mode) const {
- ATRACE_CALL();
CHECK(zip_handle_ != nullptr);
::ZipString name(path.c_str());
@@ -231,12 +225,16 @@
while ((result = ::Next(cookie, &entry, &name)) == 0) {
StringPiece full_file_path(reinterpret_cast<const char*>(name.name), name.name_length);
StringPiece leaf_file_path = full_file_path.substr(root_path_full.size());
- auto iter = std::find(leaf_file_path.begin(), leaf_file_path.end(), '/');
- if (iter != leaf_file_path.end()) {
- dirs.insert(
- leaf_file_path.substr(0, std::distance(leaf_file_path.begin(), iter)).to_string());
- } else if (!leaf_file_path.empty()) {
- f(leaf_file_path, kFileTypeRegular);
+
+ if (!leaf_file_path.empty()) {
+ auto iter = std::find(leaf_file_path.begin(), leaf_file_path.end(), '/');
+ if (iter != leaf_file_path.end()) {
+ std::string dir =
+ leaf_file_path.substr(0, std::distance(leaf_file_path.begin(), iter)).to_string();
+ dirs.insert(std::move(dir));
+ } else {
+ f(leaf_file_path, kFileTypeRegular);
+ }
}
}
::EndIteration(cookie);
diff --git a/libs/androidfw/AssetManager2.cpp b/libs/androidfw/AssetManager2.cpp
index 415d3e3..d9f1293 100644
--- a/libs/androidfw/AssetManager2.cpp
+++ b/libs/androidfw/AssetManager2.cpp
@@ -36,6 +36,31 @@
namespace android {
+struct FindEntryResult {
+ // A pointer to the resource table entry for this resource.
+ // If the size of the entry is > sizeof(ResTable_entry), it can be cast to
+ // a ResTable_map_entry and processed as a bag/map.
+ const ResTable_entry* entry;
+
+ // The configuration for which the resulting entry was defined. This is already swapped to host
+ // endianness.
+ ResTable_config config;
+
+ // The bitmask of configuration axis with which the resource value varies.
+ uint32_t type_flags;
+
+ // The dynamic package ID map for the package from which this resource came from.
+ const DynamicRefTable* dynamic_ref_table;
+
+ // The string pool reference to the type's name. This uses a different string pool than
+ // the global string pool, but this is hidden from the caller.
+ StringPoolRef type_string_ref;
+
+ // The string pool reference to the entry's name. This uses a different string pool than
+ // the global string pool, but this is hidden from the caller.
+ StringPoolRef entry_string_ref;
+};
+
AssetManager2::AssetManager2() {
memset(&configuration_, 0, sizeof(configuration_));
}
@@ -44,6 +69,7 @@
bool invalidate_caches) {
apk_assets_ = apk_assets;
BuildDynamicRefTable();
+ RebuildFilterList();
if (invalidate_caches) {
InvalidateCaches(static_cast<uint32_t>(-1));
}
@@ -74,12 +100,14 @@
if (idx == 0xff) {
package_ids_[package_id] = idx = static_cast<uint8_t>(package_groups_.size());
package_groups_.push_back({});
- package_groups_.back().dynamic_ref_table.mAssignedPackageId = package_id;
+ DynamicRefTable& ref_table = package_groups_.back().dynamic_ref_table;
+ ref_table.mAssignedPackageId = package_id;
+ ref_table.mAppAsLib = package->IsDynamic() && package->GetPackageId() == 0x7f;
}
PackageGroup* package_group = &package_groups_[idx];
// Add the package and to the set of packages with the same ID.
- package_group->packages_.push_back(package.get());
+ package_group->packages_.push_back(ConfiguredPackage{package.get(), {}});
package_group->cookies_.push_back(static_cast<ApkAssetsCookie>(i));
// Add the package name -> build time ID mappings.
@@ -94,7 +122,7 @@
// Now assign the runtime IDs so that we have a build-time to runtime ID map.
const auto package_groups_end = package_groups_.end();
for (auto iter = package_groups_.begin(); iter != package_groups_end; ++iter) {
- const std::string& package_name = iter->packages_[0]->GetPackageName();
+ const std::string& package_name = iter->packages_[0].loaded_package_->GetPackageName();
for (auto iter2 = package_groups_.begin(); iter2 != package_groups_end; ++iter2) {
iter2->dynamic_ref_table.addMapping(String16(package_name.c_str(), package_name.size()),
iter->dynamic_ref_table.mAssignedPackageId);
@@ -105,20 +133,33 @@
void AssetManager2::DumpToLog() const {
base::ScopedLogSeverity _log(base::INFO);
+ LOG(INFO) << base::StringPrintf("AssetManager2(this=%p)", this);
+
std::string list;
+ for (const auto& apk_assets : apk_assets_) {
+ base::StringAppendF(&list, "%s,", apk_assets->GetPath().c_str());
+ }
+ LOG(INFO) << "ApkAssets: " << list;
+
+ list = "";
for (size_t i = 0; i < package_ids_.size(); i++) {
if (package_ids_[i] != 0xff) {
- base::StringAppendF(&list, "%02x -> %d, ", (int) i, package_ids_[i]);
+ base::StringAppendF(&list, "%02x -> %d, ", (int)i, package_ids_[i]);
}
}
LOG(INFO) << "Package ID map: " << list;
for (const auto& package_group: package_groups_) {
- list = "";
- for (const auto& package : package_group.packages_) {
- base::StringAppendF(&list, "%s(%02x), ", package->GetPackageName().c_str(), package->GetPackageId());
- }
- LOG(INFO) << base::StringPrintf("PG (%02x): ", package_group.dynamic_ref_table.mAssignedPackageId) << list;
+ list = "";
+ for (const auto& package : package_group.packages_) {
+ const LoadedPackage* loaded_package = package.loaded_package_;
+ base::StringAppendF(&list, "%s(%02x%s), ", loaded_package->GetPackageName().c_str(),
+ loaded_package->GetPackageId(),
+ (loaded_package->IsDynamic() ? " dynamic" : ""));
+ }
+ LOG(INFO) << base::StringPrintf("PG (%02x): ",
+ package_group.dynamic_ref_table.mAssignedPackageId)
+ << list;
}
}
@@ -157,53 +198,55 @@
configuration_ = configuration;
if (diff) {
+ RebuildFilterList();
InvalidateCaches(static_cast<uint32_t>(diff));
}
}
std::set<ResTable_config> AssetManager2::GetResourceConfigurations(bool exclude_system,
- bool exclude_mipmap) {
- ATRACE_CALL();
+ bool exclude_mipmap) const {
+ ATRACE_NAME("AssetManager::GetResourceConfigurations");
std::set<ResTable_config> configurations;
for (const PackageGroup& package_group : package_groups_) {
- for (const LoadedPackage* package : package_group.packages_) {
- if (exclude_system && package->IsSystem()) {
+ for (const ConfiguredPackage& package : package_group.packages_) {
+ if (exclude_system && package.loaded_package_->IsSystem()) {
continue;
}
- package->CollectConfigurations(exclude_mipmap, &configurations);
+ package.loaded_package_->CollectConfigurations(exclude_mipmap, &configurations);
}
}
return configurations;
}
std::set<std::string> AssetManager2::GetResourceLocales(bool exclude_system,
- bool merge_equivalent_languages) {
- ATRACE_CALL();
+ bool merge_equivalent_languages) const {
+ ATRACE_NAME("AssetManager::GetResourceLocales");
std::set<std::string> locales;
for (const PackageGroup& package_group : package_groups_) {
- for (const LoadedPackage* package : package_group.packages_) {
- if (exclude_system && package->IsSystem()) {
+ for (const ConfiguredPackage& package : package_group.packages_) {
+ if (exclude_system && package.loaded_package_->IsSystem()) {
continue;
}
- package->CollectLocales(merge_equivalent_languages, &locales);
+ package.loaded_package_->CollectLocales(merge_equivalent_languages, &locales);
}
}
return locales;
}
-std::unique_ptr<Asset> AssetManager2::Open(const std::string& filename, Asset::AccessMode mode) {
+std::unique_ptr<Asset> AssetManager2::Open(const std::string& filename,
+ Asset::AccessMode mode) const {
const std::string new_path = "assets/" + filename;
return OpenNonAsset(new_path, mode);
}
std::unique_ptr<Asset> AssetManager2::Open(const std::string& filename, ApkAssetsCookie cookie,
- Asset::AccessMode mode) {
+ Asset::AccessMode mode) const {
const std::string new_path = "assets/" + filename;
return OpenNonAsset(new_path, cookie, mode);
}
-std::unique_ptr<AssetDir> AssetManager2::OpenDir(const std::string& dirname) {
- ATRACE_CALL();
+std::unique_ptr<AssetDir> AssetManager2::OpenDir(const std::string& dirname) const {
+ ATRACE_NAME("AssetManager::OpenDir");
std::string full_path = "assets/" + dirname;
std::unique_ptr<SortedVector<AssetDir::FileInfo>> files =
@@ -236,8 +279,7 @@
// is inconsistent for split APKs.
std::unique_ptr<Asset> AssetManager2::OpenNonAsset(const std::string& filename,
Asset::AccessMode mode,
- ApkAssetsCookie* out_cookie) {
- ATRACE_CALL();
+ ApkAssetsCookie* out_cookie) const {
for (int32_t i = apk_assets_.size() - 1; i >= 0; i--) {
std::unique_ptr<Asset> asset = apk_assets_[i]->Open(filename, mode);
if (asset) {
@@ -255,8 +297,8 @@
}
std::unique_ptr<Asset> AssetManager2::OpenNonAsset(const std::string& filename,
- ApkAssetsCookie cookie, Asset::AccessMode mode) {
- ATRACE_CALL();
+ ApkAssetsCookie cookie,
+ Asset::AccessMode mode) const {
if (cookie < 0 || static_cast<size_t>(cookie) >= apk_assets_.size()) {
return {};
}
@@ -264,14 +306,13 @@
}
ApkAssetsCookie AssetManager2::FindEntry(uint32_t resid, uint16_t density_override,
- bool stop_at_first_match, FindEntryResult* out_entry) {
- ATRACE_CALL();
-
+ bool /*stop_at_first_match*/,
+ FindEntryResult* out_entry) const {
// Might use this if density_override != 0.
ResTable_config density_override_config;
// Select our configuration or generate a density override configuration.
- ResTable_config* desired_config = &configuration_;
+ const ResTable_config* desired_config = &configuration_;
if (density_override != 0 && density_override != configuration_.density) {
density_override_config = configuration_;
density_override_config.density = density_override;
@@ -285,55 +326,135 @@
const uint32_t package_id = get_package_id(resid);
const uint8_t type_idx = get_type_id(resid) - 1;
- const uint16_t entry_id = get_entry_id(resid);
+ const uint16_t entry_idx = get_entry_id(resid);
- const uint8_t idx = package_ids_[package_id];
- if (idx == 0xff) {
+ const uint8_t package_idx = package_ids_[package_id];
+ if (package_idx == 0xff) {
LOG(ERROR) << base::StringPrintf("No package ID %02x found for ID 0x%08x.", package_id, resid);
return kInvalidCookie;
}
- FindEntryResult best_entry;
- ApkAssetsCookie best_cookie = kInvalidCookie;
- uint32_t cumulated_flags = 0u;
-
- const PackageGroup& package_group = package_groups_[idx];
+ const PackageGroup& package_group = package_groups_[package_idx];
const size_t package_count = package_group.packages_.size();
- FindEntryResult current_entry;
- for (size_t i = 0; i < package_count; i++) {
- const LoadedPackage* loaded_package = package_group.packages_[i];
- if (!loaded_package->FindEntry(type_idx, entry_id, *desired_config, ¤t_entry)) {
+
+ ApkAssetsCookie best_cookie = kInvalidCookie;
+ const LoadedPackage* best_package = nullptr;
+ const ResTable_type* best_type = nullptr;
+ const ResTable_config* best_config = nullptr;
+ ResTable_config best_config_copy;
+ uint32_t best_offset = 0u;
+ uint32_t type_flags = 0u;
+
+ // If desired_config is the same as the set configuration, then we can use our filtered list
+ // and we don't need to match the configurations, since they already matched.
+ const bool use_fast_path = desired_config == &configuration_;
+
+ for (size_t pi = 0; pi < package_count; pi++) {
+ const ConfiguredPackage& loaded_package_impl = package_group.packages_[pi];
+ const LoadedPackage* loaded_package = loaded_package_impl.loaded_package_;
+ ApkAssetsCookie cookie = package_group.cookies_[pi];
+
+ // If the type IDs are offset in this package, we need to take that into account when searching
+ // for a type.
+ const TypeSpec* type_spec = loaded_package->GetTypeSpecByTypeIndex(type_idx);
+ if (UNLIKELY(type_spec == nullptr)) {
continue;
}
- cumulated_flags |= current_entry.type_flags;
+ uint16_t local_entry_idx = entry_idx;
- const ResTable_config* current_config = current_entry.config;
- const ResTable_config* best_config = best_entry.config;
- if (best_cookie == kInvalidCookie ||
- current_config->isBetterThan(*best_config, desired_config) ||
- (loaded_package->IsOverlay() && current_config->compare(*best_config) == 0)) {
- best_entry = current_entry;
- best_cookie = package_group.cookies_[i];
- if (stop_at_first_match) {
- break;
+ // If there is an IDMAP supplied with this package, translate the entry ID.
+ if (type_spec->idmap_entries != nullptr) {
+ if (!LoadedIdmap::Lookup(type_spec->idmap_entries, local_entry_idx, &local_entry_idx)) {
+ // There is no mapping, so the resource is not meant to be in this overlay package.
+ continue;
+ }
+ }
+
+ type_flags |= type_spec->GetFlagsForEntryIndex(local_entry_idx);
+
+ // If the package is an overlay, then even configurations that are the same MUST be chosen.
+ const bool package_is_overlay = loaded_package->IsOverlay();
+
+ const FilteredConfigGroup& filtered_group = loaded_package_impl.filtered_configs_[type_idx];
+ if (use_fast_path) {
+ const std::vector<ResTable_config>& candidate_configs = filtered_group.configurations;
+ const size_t type_count = candidate_configs.size();
+ for (uint32_t i = 0; i < type_count; i++) {
+ const ResTable_config& this_config = candidate_configs[i];
+
+ // We can skip calling ResTable_config::match() because we know that all candidate
+ // configurations that do NOT match have been filtered-out.
+ if ((best_config == nullptr || this_config.isBetterThan(*best_config, desired_config)) ||
+ (package_is_overlay && this_config.compare(*best_config) == 0)) {
+ // The configuration matches and is better than the previous selection.
+ // Find the entry value if it exists for this configuration.
+ const ResTable_type* type_chunk = filtered_group.types[i];
+ const uint32_t offset = LoadedPackage::GetEntryOffset(type_chunk, local_entry_idx);
+ if (offset == ResTable_type::NO_ENTRY) {
+ continue;
+ }
+
+ best_cookie = cookie;
+ best_package = loaded_package;
+ best_type = type_chunk;
+ best_config = &this_config;
+ best_offset = offset;
+ }
+ }
+ } else {
+ // This is the slower path, which doesn't use the filtered list of configurations.
+ // Here we must read the ResTable_config from the mmapped APK, convert it to host endianness
+ // and fill in any new fields that did not exist when the APK was compiled.
+ // Furthermore when selecting configurations we can't just record the pointer to the
+ // ResTable_config, we must copy it.
+ const auto iter_end = type_spec->types + type_spec->type_count;
+ for (auto iter = type_spec->types; iter != iter_end; ++iter) {
+ ResTable_config this_config;
+ this_config.copyFromDtoH((*iter)->config);
+
+ if (this_config.match(*desired_config)) {
+ if ((best_config == nullptr || this_config.isBetterThan(*best_config, desired_config)) ||
+ (package_is_overlay && this_config.compare(*best_config) == 0)) {
+ // The configuration matches and is better than the previous selection.
+ // Find the entry value if it exists for this configuration.
+ const uint32_t offset = LoadedPackage::GetEntryOffset(*iter, local_entry_idx);
+ if (offset == ResTable_type::NO_ENTRY) {
+ continue;
+ }
+
+ best_cookie = cookie;
+ best_package = loaded_package;
+ best_type = *iter;
+ best_config_copy = this_config;
+ best_config = &best_config_copy;
+ best_offset = offset;
+ }
+ }
}
}
}
- if (best_cookie == kInvalidCookie) {
+ if (UNLIKELY(best_cookie == kInvalidCookie)) {
return kInvalidCookie;
}
- *out_entry = best_entry;
+ const ResTable_entry* best_entry = LoadedPackage::GetEntryFromOffset(best_type, best_offset);
+ if (UNLIKELY(best_entry == nullptr)) {
+ return kInvalidCookie;
+ }
+
+ out_entry->entry = best_entry;
+ out_entry->config = *best_config;
+ out_entry->type_flags = type_flags;
+ out_entry->type_string_ref = StringPoolRef(best_package->GetTypeStringPool(), best_type->id - 1);
+ out_entry->entry_string_ref =
+ StringPoolRef(best_package->GetKeyStringPool(), best_entry->key.index);
out_entry->dynamic_ref_table = &package_group.dynamic_ref_table;
- out_entry->type_flags = cumulated_flags;
return best_cookie;
}
-bool AssetManager2::GetResourceName(uint32_t resid, ResourceName* out_name) {
- ATRACE_CALL();
-
+bool AssetManager2::GetResourceName(uint32_t resid, ResourceName* out_name) const {
FindEntryResult entry;
ApkAssetsCookie cookie =
FindEntry(resid, 0u /* density_override */, true /* stop_at_first_match */, &entry);
@@ -341,7 +462,8 @@
return false;
}
- const LoadedPackage* package = apk_assets_[cookie]->GetLoadedArsc()->GetPackageForId(resid);
+ const LoadedPackage* package =
+ apk_assets_[cookie]->GetLoadedArsc()->GetPackageById(get_package_id(resid));
if (package == nullptr) {
return false;
}
@@ -369,7 +491,7 @@
return true;
}
-bool AssetManager2::GetResourceFlags(uint32_t resid, uint32_t* out_flags) {
+bool AssetManager2::GetResourceFlags(uint32_t resid, uint32_t* out_flags) const {
FindEntryResult entry;
ApkAssetsCookie cookie =
FindEntry(resid, 0u /* density_override */, false /* stop_at_first_match */, &entry);
@@ -383,9 +505,7 @@
ApkAssetsCookie AssetManager2::GetResource(uint32_t resid, bool may_be_bag,
uint16_t density_override, Res_value* out_value,
ResTable_config* out_selected_config,
- uint32_t* out_flags) {
- ATRACE_CALL();
-
+ uint32_t* out_flags) const {
FindEntryResult entry;
ApkAssetsCookie cookie =
FindEntry(resid, density_override, false /* stop_at_first_match */, &entry);
@@ -402,7 +522,7 @@
// Create a reference since we can't represent this complex type as a Res_value.
out_value->dataType = Res_value::TYPE_REFERENCE;
out_value->data = resid;
- *out_selected_config = *entry.config;
+ *out_selected_config = entry.config;
*out_flags = entry.type_flags;
return cookie;
}
@@ -414,7 +534,7 @@
// Convert the package ID to the runtime assigned package ID.
entry.dynamic_ref_table->lookupResourceValue(out_value);
- *out_selected_config = *entry.config;
+ *out_selected_config = entry.config;
*out_flags = entry.type_flags;
return cookie;
}
@@ -422,16 +542,13 @@
ApkAssetsCookie AssetManager2::ResolveReference(ApkAssetsCookie cookie, Res_value* in_out_value,
ResTable_config* in_out_selected_config,
uint32_t* in_out_flags,
- uint32_t* out_last_reference) {
- ATRACE_CALL();
+ uint32_t* out_last_reference) const {
constexpr const int kMaxIterations = 20;
for (size_t iteration = 0u; in_out_value->dataType == Res_value::TYPE_REFERENCE &&
in_out_value->data != 0u && iteration < kMaxIterations;
iteration++) {
- if (out_last_reference != nullptr) {
- *out_last_reference = in_out_value->data;
- }
+ *out_last_reference = in_out_value->data;
uint32_t new_flags = 0u;
cookie = GetResource(in_out_value->data, true /*may_be_bag*/, 0u /*density_override*/,
in_out_value, in_out_selected_config, &new_flags);
@@ -450,7 +567,7 @@
}
const ResolvedBag* AssetManager2::GetBag(uint32_t resid) {
- ATRACE_CALL();
+ ATRACE_NAME("AssetManager::GetBag");
auto cached_iter = cached_bags_.find(resid);
if (cached_iter != cached_bags_.end()) {
@@ -492,7 +609,8 @@
// Attributes, arrays, etc don't have a resource id as the name. They specify
// other data, which would be wrong to change via a lookup.
if (entry.dynamic_ref_table->lookupResourceId(&new_key) != NO_ERROR) {
- LOG(ERROR) << base::StringPrintf("Failed to resolve key 0x%08x in bag 0x%08x.", new_key, resid);
+ LOG(ERROR) << base::StringPrintf("Failed to resolve key 0x%08x in bag 0x%08x.", new_key,
+ resid);
return nullptr;
}
}
@@ -524,7 +642,8 @@
const ResolvedBag* parent_bag = GetBag(parent_resid);
if (parent_bag == nullptr) {
// Failed to get the parent that should exist.
- LOG(ERROR) << base::StringPrintf("Failed to find parent 0x%08x of bag 0x%08x.", parent_resid, resid);
+ LOG(ERROR) << base::StringPrintf("Failed to find parent 0x%08x of bag 0x%08x.", parent_resid,
+ resid);
return nullptr;
}
@@ -543,7 +662,8 @@
uint32_t child_key = dtohl(map_entry->name.ident);
if (!is_internal_resid(child_key)) {
if (entry.dynamic_ref_table->lookupResourceId(&child_key) != NO_ERROR) {
- LOG(ERROR) << base::StringPrintf("Failed to resolve key 0x%08x in bag 0x%08x.", child_key, resid);
+ LOG(ERROR) << base::StringPrintf("Failed to resolve key 0x%08x in bag 0x%08x.", child_key,
+ resid);
return nullptr;
}
}
@@ -582,7 +702,8 @@
uint32_t new_key = dtohl(map_entry->name.ident);
if (!is_internal_resid(new_key)) {
if (entry.dynamic_ref_table->lookupResourceId(&new_key) != NO_ERROR) {
- LOG(ERROR) << base::StringPrintf("Failed to resolve key 0x%08x in bag 0x%08x.", new_key, resid);
+ LOG(ERROR) << base::StringPrintf("Failed to resolve key 0x%08x in bag 0x%08x.", new_key,
+ resid);
return nullptr;
}
}
@@ -638,7 +759,7 @@
uint32_t AssetManager2::GetResourceId(const std::string& resource_name,
const std::string& fallback_type,
- const std::string& fallback_package) {
+ const std::string& fallback_package) const {
StringPiece package_name, type, entry;
if (!ExtractResourceName(resource_name, &package_name, &type, &entry)) {
return 0u;
@@ -670,7 +791,8 @@
const static std::u16string kAttrPrivate16 = u"^attr-private";
for (const PackageGroup& package_group : package_groups_) {
- for (const LoadedPackage* package : package_group.packages_) {
+ for (const ConfiguredPackage& package_impl : package_group.packages_) {
+ const LoadedPackage* package = package_impl.loaded_package_;
if (package_name != package->GetPackageName()) {
// All packages in the same group are expected to have the same package name.
break;
@@ -692,6 +814,32 @@
return 0u;
}
+void AssetManager2::RebuildFilterList() {
+ for (PackageGroup& group : package_groups_) {
+ for (ConfiguredPackage& impl : group.packages_) {
+ // Destroy it.
+ impl.filtered_configs_.~ByteBucketArray();
+
+ // Re-create it.
+ new (&impl.filtered_configs_) ByteBucketArray<FilteredConfigGroup>();
+
+ // Create the filters here.
+ impl.loaded_package_->ForEachTypeSpec([&](const TypeSpec* spec, uint8_t type_index) {
+ FilteredConfigGroup& group = impl.filtered_configs_.editItemAt(type_index);
+ const auto iter_end = spec->types + spec->type_count;
+ for (auto iter = spec->types; iter != iter_end; ++iter) {
+ ResTable_config this_config;
+ this_config.copyFromDtoH((*iter)->config);
+ if (this_config.match(configuration_)) {
+ group.configurations.push_back(this_config);
+ group.types.push_back(*iter);
+ }
+ }
+ });
+ }
+ }
+}
+
void AssetManager2::InvalidateCaches(uint32_t diff) {
if (diff == 0xffffffffu) {
// Everything must go.
@@ -743,7 +891,7 @@
};
bool Theme::ApplyStyle(uint32_t resid, bool force) {
- ATRACE_CALL();
+ ATRACE_NAME("Theme::ApplyStyle");
const ResolvedBag* bag = asset_manager_->GetBag(resid);
if (bag == nullptr) {
@@ -872,7 +1020,7 @@
ApkAssetsCookie Theme::ResolveAttributeReference(ApkAssetsCookie cookie, Res_value* in_out_value,
ResTable_config* in_out_selected_config,
uint32_t* in_out_type_spec_flags,
- uint32_t* out_last_ref) {
+ uint32_t* out_last_ref) const {
if (in_out_value->dataType == Res_value::TYPE_ATTRIBUTE) {
uint32_t new_flags;
cookie = GetAttribute(in_out_value->data, in_out_value, &new_flags);
diff --git a/libs/androidfw/AttributeResolution.cpp b/libs/androidfw/AttributeResolution.cpp
index 60e3845..f912af4 100644
--- a/libs/androidfw/AttributeResolution.cpp
+++ b/libs/androidfw/AttributeResolution.cpp
@@ -20,13 +20,18 @@
#include <log/log.h>
+#include "androidfw/AssetManager2.h"
#include "androidfw/AttributeFinder.h"
-#include "androidfw/ResourceTypes.h"
constexpr bool kDebugStyles = false;
namespace android {
+// Java asset cookies have 0 as an invalid cookie, but TypedArray expects < 0.
+static uint32_t ApkAssetsCookieToJavaCookie(ApkAssetsCookie cookie) {
+ return cookie != kInvalidCookie ? static_cast<uint32_t>(cookie + 1) : static_cast<uint32_t>(-1);
+}
+
class XmlAttributeFinder
: public BackTrackingAttributeFinder<XmlAttributeFinder, size_t> {
public:
@@ -44,58 +49,53 @@
};
class BagAttributeFinder
- : public BackTrackingAttributeFinder<BagAttributeFinder, const ResTable::bag_entry*> {
+ : public BackTrackingAttributeFinder<BagAttributeFinder, const ResolvedBag::Entry*> {
public:
- BagAttributeFinder(const ResTable::bag_entry* start,
- const ResTable::bag_entry* end)
- : BackTrackingAttributeFinder(start, end) {}
+ BagAttributeFinder(const ResolvedBag* bag)
+ : BackTrackingAttributeFinder(bag != nullptr ? bag->entries : nullptr,
+ bag != nullptr ? bag->entries + bag->entry_count : nullptr) {
+ }
- inline uint32_t GetAttribute(const ResTable::bag_entry* entry) const {
- return entry->map.name.ident;
+ inline uint32_t GetAttribute(const ResolvedBag::Entry* entry) const {
+ return entry->key;
}
};
-bool ResolveAttrs(ResTable::Theme* theme, uint32_t def_style_attr,
- uint32_t def_style_res, uint32_t* src_values,
- size_t src_values_length, uint32_t* attrs,
- size_t attrs_length, uint32_t* out_values,
- uint32_t* out_indices) {
+bool ResolveAttrs(Theme* theme, uint32_t def_style_attr, uint32_t def_style_res,
+ uint32_t* src_values, size_t src_values_length, uint32_t* attrs,
+ size_t attrs_length, uint32_t* out_values, uint32_t* out_indices) {
if (kDebugStyles) {
ALOGI("APPLY STYLE: theme=0x%p defStyleAttr=0x%x defStyleRes=0x%x", theme,
def_style_attr, def_style_res);
}
- const ResTable& res = theme->getResTable();
+ AssetManager2* assetmanager = theme->GetAssetManager();
ResTable_config config;
Res_value value;
int indices_idx = 0;
// Load default style from attribute, if specified...
- uint32_t def_style_bag_type_set_flags = 0;
+ uint32_t def_style_flags = 0u;
if (def_style_attr != 0) {
Res_value value;
- if (theme->getAttribute(def_style_attr, &value, &def_style_bag_type_set_flags) >= 0) {
+ if (theme->GetAttribute(def_style_attr, &value, &def_style_flags) != kInvalidCookie) {
if (value.dataType == Res_value::TYPE_REFERENCE) {
def_style_res = value.data;
}
}
}
- // Now lock down the resource object and start pulling stuff from it.
- res.lock();
-
// Retrieve the default style bag, if requested.
- const ResTable::bag_entry* def_style_start = nullptr;
- uint32_t def_style_type_set_flags = 0;
- ssize_t bag_off = def_style_res != 0
- ? res.getBagLocked(def_style_res, &def_style_start,
- &def_style_type_set_flags)
- : -1;
- def_style_type_set_flags |= def_style_bag_type_set_flags;
- const ResTable::bag_entry* const def_style_end =
- def_style_start + (bag_off >= 0 ? bag_off : 0);
- BagAttributeFinder def_style_attr_finder(def_style_start, def_style_end);
+ const ResolvedBag* default_style_bag = nullptr;
+ if (def_style_res != 0) {
+ default_style_bag = assetmanager->GetBag(def_style_res);
+ if (default_style_bag != nullptr) {
+ def_style_flags |= default_style_bag->type_spec_flags;
+ }
+ }
+
+ BagAttributeFinder def_style_attr_finder(default_style_bag);
// Now iterate through all of the attributes that the client has requested,
// filling in each with whatever data we can find.
@@ -106,7 +106,7 @@
ALOGI("RETRIEVING ATTR 0x%08x...", cur_ident);
}
- ssize_t block = -1;
+ ApkAssetsCookie cookie = kInvalidCookie;
uint32_t type_set_flags = 0;
value.dataType = Res_value::TYPE_NULL;
@@ -122,15 +122,14 @@
value.dataType = Res_value::TYPE_ATTRIBUTE;
value.data = src_values[ii];
if (kDebugStyles) {
- ALOGI("-> From values: type=0x%x, data=0x%08x", value.dataType,
- value.data);
+ ALOGI("-> From values: type=0x%x, data=0x%08x", value.dataType, value.data);
}
} else {
- const ResTable::bag_entry* const def_style_entry = def_style_attr_finder.Find(cur_ident);
- if (def_style_entry != def_style_end) {
- block = def_style_entry->stringBlock;
- type_set_flags = def_style_type_set_flags;
- value = def_style_entry->map.value;
+ const ResolvedBag::Entry* const entry = def_style_attr_finder.Find(cur_ident);
+ if (entry != def_style_attr_finder.end()) {
+ cookie = entry->cookie;
+ type_set_flags = def_style_flags;
+ value = entry->value;
if (kDebugStyles) {
ALOGI("-> From def style: type=0x%x, data=0x%08x", value.dataType, value.data);
}
@@ -140,22 +139,26 @@
uint32_t resid = 0;
if (value.dataType != Res_value::TYPE_NULL) {
// Take care of resolving the found resource to its final value.
- ssize_t new_block =
- theme->resolveAttributeReference(&value, block, &resid, &type_set_flags, &config);
- if (new_block >= 0) block = new_block;
+ ApkAssetsCookie new_cookie =
+ theme->ResolveAttributeReference(cookie, &value, &config, &type_set_flags, &resid);
+ if (new_cookie != kInvalidCookie) {
+ cookie = new_cookie;
+ }
if (kDebugStyles) {
ALOGI("-> Resolved attr: type=0x%x, data=0x%08x", value.dataType, value.data);
}
} else if (value.data != Res_value::DATA_NULL_EMPTY) {
- // If we still don't have a value for this attribute, try to find
- // it in the theme!
- ssize_t new_block = theme->getAttribute(cur_ident, &value, &type_set_flags);
- if (new_block >= 0) {
+ // If we still don't have a value for this attribute, try to find it in the theme!
+ ApkAssetsCookie new_cookie = theme->GetAttribute(cur_ident, &value, &type_set_flags);
+ if (new_cookie != kInvalidCookie) {
if (kDebugStyles) {
ALOGI("-> From theme: type=0x%x, data=0x%08x", value.dataType, value.data);
}
- new_block = res.resolveReference(&value, new_block, &resid, &type_set_flags, &config);
- if (new_block >= 0) block = new_block;
+ new_cookie =
+ assetmanager->ResolveReference(new_cookie, &value, &config, &type_set_flags, &resid);
+ if (new_cookie != kInvalidCookie) {
+ cookie = new_cookie;
+ }
if (kDebugStyles) {
ALOGI("-> Resolved theme: type=0x%x, data=0x%08x", value.dataType, value.data);
}
@@ -169,7 +172,7 @@
}
value.dataType = Res_value::TYPE_NULL;
value.data = Res_value::DATA_NULL_UNDEFINED;
- block = -1;
+ cookie = kInvalidCookie;
}
if (kDebugStyles) {
@@ -179,9 +182,7 @@
// Write the final value back to Java.
out_values[STYLE_TYPE] = value.dataType;
out_values[STYLE_DATA] = value.data;
- out_values[STYLE_ASSET_COOKIE] =
- block != -1 ? static_cast<uint32_t>(res.getTableCookie(block))
- : static_cast<uint32_t>(-1);
+ out_values[STYLE_ASSET_COOKIE] = ApkAssetsCookieToJavaCookie(cookie);
out_values[STYLE_RESOURCE_ID] = resid;
out_values[STYLE_CHANGING_CONFIGURATIONS] = type_set_flags;
out_values[STYLE_DENSITY] = config.density;
@@ -195,90 +196,80 @@
out_values += STYLE_NUM_ENTRIES;
}
- res.unlock();
-
if (out_indices != nullptr) {
out_indices[0] = indices_idx;
}
return true;
}
-void ApplyStyle(ResTable::Theme* theme, ResXMLParser* xml_parser, uint32_t def_style_attr,
- uint32_t def_style_res, const uint32_t* attrs, size_t attrs_length,
+void ApplyStyle(Theme* theme, ResXMLParser* xml_parser, uint32_t def_style_attr,
+ uint32_t def_style_resid, const uint32_t* attrs, size_t attrs_length,
uint32_t* out_values, uint32_t* out_indices) {
if (kDebugStyles) {
- ALOGI("APPLY STYLE: theme=0x%p defStyleAttr=0x%x defStyleRes=0x%x xml=0x%p",
- theme, def_style_attr, def_style_res, xml_parser);
+ ALOGI("APPLY STYLE: theme=0x%p defStyleAttr=0x%x defStyleRes=0x%x xml=0x%p", theme,
+ def_style_attr, def_style_resid, xml_parser);
}
- const ResTable& res = theme->getResTable();
+ AssetManager2* assetmanager = theme->GetAssetManager();
ResTable_config config;
Res_value value;
int indices_idx = 0;
// Load default style from attribute, if specified...
- uint32_t def_style_bag_type_set_flags = 0;
+ uint32_t def_style_flags = 0u;
if (def_style_attr != 0) {
Res_value value;
- if (theme->getAttribute(def_style_attr, &value,
- &def_style_bag_type_set_flags) >= 0) {
+ if (theme->GetAttribute(def_style_attr, &value, &def_style_flags) != kInvalidCookie) {
if (value.dataType == Res_value::TYPE_REFERENCE) {
- def_style_res = value.data;
+ def_style_resid = value.data;
}
}
}
- // Retrieve the style class associated with the current XML tag.
- int style = 0;
- uint32_t style_bag_type_set_flags = 0;
+ // Retrieve the style resource ID associated with the current XML tag's style attribute.
+ uint32_t style_resid = 0u;
+ uint32_t style_flags = 0u;
if (xml_parser != nullptr) {
ssize_t idx = xml_parser->indexOfStyle();
if (idx >= 0 && xml_parser->getAttributeValue(idx, &value) >= 0) {
if (value.dataType == value.TYPE_ATTRIBUTE) {
- if (theme->getAttribute(value.data, &value, &style_bag_type_set_flags) < 0) {
+ // Resolve the attribute with out theme.
+ if (theme->GetAttribute(value.data, &value, &style_flags) == kInvalidCookie) {
value.dataType = Res_value::TYPE_NULL;
}
}
+
if (value.dataType == value.TYPE_REFERENCE) {
- style = value.data;
+ style_resid = value.data;
}
}
}
- // Now lock down the resource object and start pulling stuff from it.
- res.lock();
-
// Retrieve the default style bag, if requested.
- const ResTable::bag_entry* def_style_attr_start = nullptr;
- uint32_t def_style_type_set_flags = 0;
- ssize_t bag_off = def_style_res != 0
- ? res.getBagLocked(def_style_res, &def_style_attr_start,
- &def_style_type_set_flags)
- : -1;
- def_style_type_set_flags |= def_style_bag_type_set_flags;
- const ResTable::bag_entry* const def_style_attr_end =
- def_style_attr_start + (bag_off >= 0 ? bag_off : 0);
- BagAttributeFinder def_style_attr_finder(def_style_attr_start,
- def_style_attr_end);
+ const ResolvedBag* default_style_bag = nullptr;
+ if (def_style_resid != 0) {
+ default_style_bag = assetmanager->GetBag(def_style_resid);
+ if (default_style_bag != nullptr) {
+ def_style_flags |= default_style_bag->type_spec_flags;
+ }
+ }
+
+ BagAttributeFinder def_style_attr_finder(default_style_bag);
// Retrieve the style class bag, if requested.
- const ResTable::bag_entry* style_attr_start = nullptr;
- uint32_t style_type_set_flags = 0;
- bag_off =
- style != 0
- ? res.getBagLocked(style, &style_attr_start, &style_type_set_flags)
- : -1;
- style_type_set_flags |= style_bag_type_set_flags;
- const ResTable::bag_entry* const style_attr_end =
- style_attr_start + (bag_off >= 0 ? bag_off : 0);
- BagAttributeFinder style_attr_finder(style_attr_start, style_attr_end);
+ const ResolvedBag* xml_style_bag = nullptr;
+ if (style_resid != 0) {
+ xml_style_bag = assetmanager->GetBag(style_resid);
+ if (xml_style_bag != nullptr) {
+ style_flags |= xml_style_bag->type_spec_flags;
+ }
+ }
+
+ BagAttributeFinder xml_style_attr_finder(xml_style_bag);
// Retrieve the XML attributes, if requested.
- static const ssize_t kXmlBlock = 0x10000000;
XmlAttributeFinder xml_attr_finder(xml_parser);
- const size_t xml_attr_end =
- xml_parser != nullptr ? xml_parser->getAttributeCount() : 0;
// Now iterate through all of the attributes that the client has requested,
// filling in each with whatever data we can find.
@@ -289,8 +280,8 @@
ALOGI("RETRIEVING ATTR 0x%08x...", cur_ident);
}
- ssize_t block = kXmlBlock;
- uint32_t type_set_flags = 0;
+ ApkAssetsCookie cookie = kInvalidCookie;
+ uint32_t type_set_flags = 0u;
value.dataType = Res_value::TYPE_NULL;
value.data = Res_value::DATA_NULL_UNDEFINED;
@@ -302,7 +293,7 @@
// Walk through the xml attributes looking for the requested attribute.
const size_t xml_attr_idx = xml_attr_finder.Find(cur_ident);
- if (xml_attr_idx != xml_attr_end) {
+ if (xml_attr_idx != xml_attr_finder.end()) {
// We found the attribute we were looking for.
xml_parser->getAttributeValue(xml_attr_idx, &value);
if (kDebugStyles) {
@@ -312,12 +303,12 @@
if (value.dataType == Res_value::TYPE_NULL && value.data != Res_value::DATA_NULL_EMPTY) {
// Walk through the style class values looking for the requested attribute.
- const ResTable::bag_entry* const style_attr_entry = style_attr_finder.Find(cur_ident);
- if (style_attr_entry != style_attr_end) {
+ const ResolvedBag::Entry* entry = xml_style_attr_finder.Find(cur_ident);
+ if (entry != xml_style_attr_finder.end()) {
// We found the attribute we were looking for.
- block = style_attr_entry->stringBlock;
- type_set_flags = style_type_set_flags;
- value = style_attr_entry->map.value;
+ cookie = entry->cookie;
+ type_set_flags = style_flags;
+ value = entry->value;
if (kDebugStyles) {
ALOGI("-> From style: type=0x%x, data=0x%08x", value.dataType, value.data);
}
@@ -326,25 +317,25 @@
if (value.dataType == Res_value::TYPE_NULL && value.data != Res_value::DATA_NULL_EMPTY) {
// Walk through the default style values looking for the requested attribute.
- const ResTable::bag_entry* const def_style_attr_entry = def_style_attr_finder.Find(cur_ident);
- if (def_style_attr_entry != def_style_attr_end) {
+ const ResolvedBag::Entry* entry = def_style_attr_finder.Find(cur_ident);
+ if (entry != def_style_attr_finder.end()) {
// We found the attribute we were looking for.
- block = def_style_attr_entry->stringBlock;
- type_set_flags = style_type_set_flags;
- value = def_style_attr_entry->map.value;
+ cookie = entry->cookie;
+ type_set_flags = def_style_flags;
+ value = entry->value;
if (kDebugStyles) {
ALOGI("-> From def style: type=0x%x, data=0x%08x", value.dataType, value.data);
}
}
}
- uint32_t resid = 0;
+ uint32_t resid = 0u;
if (value.dataType != Res_value::TYPE_NULL) {
// Take care of resolving the found resource to its final value.
- ssize_t new_block =
- theme->resolveAttributeReference(&value, block, &resid, &type_set_flags, &config);
- if (new_block >= 0) {
- block = new_block;
+ ApkAssetsCookie new_cookie =
+ theme->ResolveAttributeReference(cookie, &value, &config, &type_set_flags, &resid);
+ if (new_cookie != kInvalidCookie) {
+ cookie = new_cookie;
}
if (kDebugStyles) {
@@ -352,14 +343,15 @@
}
} else if (value.data != Res_value::DATA_NULL_EMPTY) {
// If we still don't have a value for this attribute, try to find it in the theme!
- ssize_t new_block = theme->getAttribute(cur_ident, &value, &type_set_flags);
- if (new_block >= 0) {
+ ApkAssetsCookie new_cookie = theme->GetAttribute(cur_ident, &value, &type_set_flags);
+ if (new_cookie != kInvalidCookie) {
if (kDebugStyles) {
ALOGI("-> From theme: type=0x%x, data=0x%08x", value.dataType, value.data);
}
- new_block = res.resolveReference(&value, new_block, &resid, &type_set_flags, &config);
- if (new_block >= 0) {
- block = new_block;
+ new_cookie =
+ assetmanager->ResolveReference(new_cookie, &value, &config, &type_set_flags, &resid);
+ if (new_cookie != kInvalidCookie) {
+ cookie = new_cookie;
}
if (kDebugStyles) {
@@ -375,7 +367,7 @@
}
value.dataType = Res_value::TYPE_NULL;
value.data = Res_value::DATA_NULL_UNDEFINED;
- block = kXmlBlock;
+ cookie = kInvalidCookie;
}
if (kDebugStyles) {
@@ -385,9 +377,7 @@
// Write the final value back to Java.
out_values[STYLE_TYPE] = value.dataType;
out_values[STYLE_DATA] = value.data;
- out_values[STYLE_ASSET_COOKIE] =
- block != kXmlBlock ? static_cast<uint32_t>(res.getTableCookie(block))
- : static_cast<uint32_t>(-1);
+ out_values[STYLE_ASSET_COOKIE] = ApkAssetsCookieToJavaCookie(cookie);
out_values[STYLE_RESOURCE_ID] = resid;
out_values[STYLE_CHANGING_CONFIGURATIONS] = type_set_flags;
out_values[STYLE_DENSITY] = config.density;
@@ -402,36 +392,28 @@
out_values += STYLE_NUM_ENTRIES;
}
- res.unlock();
-
// out_indices must NOT be nullptr.
out_indices[0] = indices_idx;
}
-bool RetrieveAttributes(const ResTable* res, ResXMLParser* xml_parser,
- uint32_t* attrs, size_t attrs_length,
- uint32_t* out_values, uint32_t* out_indices) {
+bool RetrieveAttributes(AssetManager2* assetmanager, ResXMLParser* xml_parser, uint32_t* attrs,
+ size_t attrs_length, uint32_t* out_values, uint32_t* out_indices) {
ResTable_config config;
Res_value value;
int indices_idx = 0;
- // Now lock down the resource object and start pulling stuff from it.
- res->lock();
-
// Retrieve the XML attributes, if requested.
const size_t xml_attr_count = xml_parser->getAttributeCount();
size_t ix = 0;
uint32_t cur_xml_attr = xml_parser->getAttributeNameResID(ix);
- static const ssize_t kXmlBlock = 0x10000000;
-
// Now iterate through all of the attributes that the client has requested,
// filling in each with whatever data we can find.
for (size_t ii = 0; ii < attrs_length; ii++) {
const uint32_t cur_ident = attrs[ii];
- ssize_t block = kXmlBlock;
- uint32_t type_set_flags = 0;
+ ApkAssetsCookie cookie = kInvalidCookie;
+ uint32_t type_set_flags = 0u;
value.dataType = Res_value::TYPE_NULL;
value.data = Res_value::DATA_NULL_UNDEFINED;
@@ -450,28 +432,27 @@
cur_xml_attr = xml_parser->getAttributeNameResID(ix);
}
- uint32_t resid = 0;
+ uint32_t resid = 0u;
if (value.dataType != Res_value::TYPE_NULL) {
// Take care of resolving the found resource to its final value.
- // printf("Resolving attribute reference\n");
- ssize_t new_block = res->resolveReference(&value, block, &resid,
- &type_set_flags, &config);
- if (new_block >= 0) block = new_block;
+ ApkAssetsCookie new_cookie =
+ assetmanager->ResolveReference(cookie, &value, &config, &type_set_flags, &resid);
+ if (new_cookie != kInvalidCookie) {
+ cookie = new_cookie;
+ }
}
// Deal with the special @null value -- it turns back to TYPE_NULL.
if (value.dataType == Res_value::TYPE_REFERENCE && value.data == 0) {
value.dataType = Res_value::TYPE_NULL;
value.data = Res_value::DATA_NULL_UNDEFINED;
- block = kXmlBlock;
+ cookie = kInvalidCookie;
}
// Write the final value back to Java.
out_values[STYLE_TYPE] = value.dataType;
out_values[STYLE_DATA] = value.data;
- out_values[STYLE_ASSET_COOKIE] =
- block != kXmlBlock ? static_cast<uint32_t>(res->getTableCookie(block))
- : static_cast<uint32_t>(-1);
+ out_values[STYLE_ASSET_COOKIE] = ApkAssetsCookieToJavaCookie(cookie);
out_values[STYLE_RESOURCE_ID] = resid;
out_values[STYLE_CHANGING_CONFIGURATIONS] = type_set_flags;
out_values[STYLE_DENSITY] = config.density;
@@ -485,8 +466,6 @@
out_values += STYLE_NUM_ENTRIES;
}
- res->unlock();
-
if (out_indices != nullptr) {
out_indices[0] = indices_idx;
}
diff --git a/libs/androidfw/LoadedArsc.cpp b/libs/androidfw/LoadedArsc.cpp
index 28548e2..04d506a 100644
--- a/libs/androidfw/LoadedArsc.cpp
+++ b/libs/androidfw/LoadedArsc.cpp
@@ -44,44 +44,6 @@
constexpr const static int kAppPackageId = 0x7f;
-// Element of a TypeSpec array. See TypeSpec.
-struct Type {
- // The configuration for which this type defines entries.
- // This is already converted to host endianness.
- ResTable_config configuration;
-
- // Pointer to the mmapped data where entry definitions are kept.
- const ResTable_type* type;
-};
-
-// TypeSpec is going to be immediately proceeded by
-// an array of Type structs, all in the same block of memory.
-struct TypeSpec {
- // Pointer to the mmapped data where flags are kept.
- // Flags denote whether the resource entry is public
- // and under which configurations it varies.
- const ResTable_typeSpec* type_spec;
-
- // Pointer to the mmapped data where the IDMAP mappings for this type
- // exist. May be nullptr if no IDMAP exists.
- const IdmapEntry_header* idmap_entries;
-
- // The number of types that follow this struct.
- // There is a type for each configuration
- // that entries are defined for.
- size_t type_count;
-
- // Trick to easily access a variable number of Type structs
- // proceeding this struct, and to ensure their alignment.
- const Type types[0];
-};
-
-// TypeSpecPtr points to the block of memory that holds
-// a TypeSpec struct, followed by an array of Type structs.
-// TypeSpecPtr is a managed pointer that knows how to delete
-// itself.
-using TypeSpecPtr = util::unique_cptr<TypeSpec>;
-
namespace {
// Builder that helps accumulate Type structs and then create a single
@@ -95,21 +57,22 @@
}
void AddType(const ResTable_type* type) {
- ResTable_config config;
- config.copyFromDtoH(type->config);
- types_.push_back(Type{config, type});
+ types_.push_back(type);
}
TypeSpecPtr Build() {
// Check for overflow.
- if ((std::numeric_limits<size_t>::max() - sizeof(TypeSpec)) / sizeof(Type) < types_.size()) {
+ using ElementType = const ResTable_type*;
+ if ((std::numeric_limits<size_t>::max() - sizeof(TypeSpec)) / sizeof(ElementType) <
+ types_.size()) {
return {};
}
- TypeSpec* type_spec = (TypeSpec*)::malloc(sizeof(TypeSpec) + (types_.size() * sizeof(Type)));
+ TypeSpec* type_spec =
+ (TypeSpec*)::malloc(sizeof(TypeSpec) + (types_.size() * sizeof(ElementType)));
type_spec->type_spec = header_;
type_spec->idmap_entries = idmap_header_;
type_spec->type_count = types_.size();
- memcpy(type_spec + 1, types_.data(), types_.size() * sizeof(Type));
+ memcpy(type_spec + 1, types_.data(), types_.size() * sizeof(ElementType));
return TypeSpecPtr(type_spec);
}
@@ -118,7 +81,7 @@
const ResTable_typeSpec* header_;
const IdmapEntry_header* idmap_header_;
- std::vector<Type> types_;
+ std::vector<const ResTable_type*> types_;
};
} // namespace
@@ -162,18 +125,17 @@
return true;
}
-static bool VerifyResTableEntry(const ResTable_type* type, uint32_t entry_offset,
- size_t entry_idx) {
+static bool VerifyResTableEntry(const ResTable_type* type, uint32_t entry_offset) {
// Check that the offset is aligned.
if (entry_offset & 0x03) {
- LOG(ERROR) << "Entry offset at index " << entry_idx << " is not 4-byte aligned.";
+ LOG(ERROR) << "Entry at offset " << entry_offset << " is not 4-byte aligned.";
return false;
}
// Check that the offset doesn't overflow.
if (entry_offset > std::numeric_limits<uint32_t>::max() - dtohl(type->entriesStart)) {
// Overflow in offset.
- LOG(ERROR) << "Entry offset at index " << entry_idx << " is too large.";
+ LOG(ERROR) << "Entry at offset " << entry_offset << " is too large.";
return false;
}
@@ -181,7 +143,7 @@
entry_offset += dtohl(type->entriesStart);
if (entry_offset > chunk_size - sizeof(ResTable_entry)) {
- LOG(ERROR) << "Entry offset at index " << entry_idx
+ LOG(ERROR) << "Entry at offset " << entry_offset
<< " is too large. No room for ResTable_entry.";
return false;
}
@@ -191,13 +153,13 @@
const size_t entry_size = dtohs(entry->size);
if (entry_size < sizeof(*entry)) {
- LOG(ERROR) << "ResTable_entry size " << entry_size << " at index " << entry_idx
+ LOG(ERROR) << "ResTable_entry size " << entry_size << " at offset " << entry_offset
<< " is too small.";
return false;
}
if (entry_size > chunk_size || entry_offset > chunk_size - entry_size) {
- LOG(ERROR) << "ResTable_entry size " << entry_size << " at index " << entry_idx
+ LOG(ERROR) << "ResTable_entry size " << entry_size << " at offset " << entry_offset
<< " is too large.";
return false;
}
@@ -205,7 +167,7 @@
if (entry_size < sizeof(ResTable_map_entry)) {
// There needs to be room for one Res_value struct.
if (entry_offset + entry_size > chunk_size - sizeof(Res_value)) {
- LOG(ERROR) << "No room for Res_value after ResTable_entry at index " << entry_idx
+ LOG(ERROR) << "No room for Res_value after ResTable_entry at offset " << entry_offset
<< " for type " << (int)type->id << ".";
return false;
}
@@ -214,12 +176,12 @@
reinterpret_cast<const Res_value*>(reinterpret_cast<const uint8_t*>(entry) + entry_size);
const size_t value_size = dtohs(value->size);
if (value_size < sizeof(Res_value)) {
- LOG(ERROR) << "Res_value at index " << entry_idx << " is too small.";
+ LOG(ERROR) << "Res_value at offset " << entry_offset << " is too small.";
return false;
}
if (value_size > chunk_size || entry_offset + entry_size > chunk_size - value_size) {
- LOG(ERROR) << "Res_value size " << value_size << " at index " << entry_idx
+ LOG(ERROR) << "Res_value size " << value_size << " at offset " << entry_offset
<< " is too large.";
return false;
}
@@ -228,119 +190,76 @@
const size_t map_entry_count = dtohl(map->count);
size_t map_entries_start = entry_offset + entry_size;
if (map_entries_start & 0x03) {
- LOG(ERROR) << "Map entries at index " << entry_idx << " start at unaligned offset.";
+ LOG(ERROR) << "Map entries at offset " << entry_offset << " start at unaligned offset.";
return false;
}
// Each entry is sizeof(ResTable_map) big.
if (map_entry_count > ((chunk_size - map_entries_start) / sizeof(ResTable_map))) {
- LOG(ERROR) << "Too many map entries in ResTable_map_entry at index " << entry_idx << ".";
+ LOG(ERROR) << "Too many map entries in ResTable_map_entry at offset " << entry_offset << ".";
return false;
}
}
return true;
}
-bool LoadedPackage::FindEntry(const TypeSpecPtr& type_spec_ptr, uint16_t entry_idx,
- const ResTable_config& config, FindEntryResult* out_entry) const {
- const ResTable_config* best_config = nullptr;
- const ResTable_type* best_type = nullptr;
- uint32_t best_offset = 0;
+const ResTable_entry* LoadedPackage::GetEntry(const ResTable_type* type_chunk,
+ uint16_t entry_index) {
+ uint32_t entry_offset = GetEntryOffset(type_chunk, entry_index);
+ if (entry_offset == ResTable_type::NO_ENTRY) {
+ return nullptr;
+ }
+ return GetEntryFromOffset(type_chunk, entry_offset);
+}
- for (uint32_t i = 0; i < type_spec_ptr->type_count; i++) {
- const Type* type = &type_spec_ptr->types[i];
- const ResTable_type* type_chunk = type->type;
+uint32_t LoadedPackage::GetEntryOffset(const ResTable_type* type_chunk, uint16_t entry_index) {
+ // The configuration matches and is better than the previous selection.
+ // Find the entry value if it exists for this configuration.
+ const size_t entry_count = dtohl(type_chunk->entryCount);
+ const size_t offsets_offset = dtohs(type_chunk->header.headerSize);
- if (type->configuration.match(config) &&
- (best_config == nullptr || type->configuration.isBetterThan(*best_config, &config))) {
- // The configuration matches and is better than the previous selection.
- // Find the entry value if it exists for this configuration.
- const size_t entry_count = dtohl(type_chunk->entryCount);
- const size_t offsets_offset = dtohs(type_chunk->header.headerSize);
+ // Check if there is the desired entry in this type.
- // Check if there is the desired entry in this type.
-
- if (type_chunk->flags & ResTable_type::FLAG_SPARSE) {
- // This is encoded as a sparse map, so perform a binary search.
- const ResTable_sparseTypeEntry* sparse_indices =
- reinterpret_cast<const ResTable_sparseTypeEntry*>(
- reinterpret_cast<const uint8_t*>(type_chunk) + offsets_offset);
- const ResTable_sparseTypeEntry* sparse_indices_end = sparse_indices + entry_count;
- const ResTable_sparseTypeEntry* result =
- std::lower_bound(sparse_indices, sparse_indices_end, entry_idx,
- [](const ResTable_sparseTypeEntry& entry, uint16_t entry_idx) {
- return dtohs(entry.idx) < entry_idx;
- });
-
- if (result == sparse_indices_end || dtohs(result->idx) != entry_idx) {
- // No entry found.
- continue;
- }
-
- // Extract the offset from the entry. Each offset must be a multiple of 4 so we store it as
- // the real offset divided by 4.
- best_offset = uint32_t{dtohs(result->offset)} * 4u;
- } else {
- if (entry_idx >= entry_count) {
- // This entry cannot be here.
- continue;
- }
-
- const uint32_t* entry_offsets = reinterpret_cast<const uint32_t*>(
+ if (type_chunk->flags & ResTable_type::FLAG_SPARSE) {
+ // This is encoded as a sparse map, so perform a binary search.
+ const ResTable_sparseTypeEntry* sparse_indices =
+ reinterpret_cast<const ResTable_sparseTypeEntry*>(
reinterpret_cast<const uint8_t*>(type_chunk) + offsets_offset);
- const uint32_t offset = dtohl(entry_offsets[entry_idx]);
- if (offset == ResTable_type::NO_ENTRY) {
- continue;
- }
+ const ResTable_sparseTypeEntry* sparse_indices_end = sparse_indices + entry_count;
+ const ResTable_sparseTypeEntry* result =
+ std::lower_bound(sparse_indices, sparse_indices_end, entry_index,
+ [](const ResTable_sparseTypeEntry& entry, uint16_t entry_idx) {
+ return dtohs(entry.idx) < entry_idx;
+ });
- // There is an entry for this resource, record it.
- best_offset = offset;
- }
-
- best_config = &type->configuration;
- best_type = type_chunk;
+ if (result == sparse_indices_end || dtohs(result->idx) != entry_index) {
+ // No entry found.
+ return ResTable_type::NO_ENTRY;
}
+
+ // Extract the offset from the entry. Each offset must be a multiple of 4 so we store it as
+ // the real offset divided by 4.
+ return uint32_t{dtohs(result->offset)} * 4u;
}
- if (best_type == nullptr) {
- return false;
+ // This type is encoded as a dense array.
+ if (entry_index >= entry_count) {
+ // This entry cannot be here.
+ return ResTable_type::NO_ENTRY;
}
- if (UNLIKELY(!VerifyResTableEntry(best_type, best_offset, entry_idx))) {
- return false;
- }
-
- const ResTable_entry* best_entry = reinterpret_cast<const ResTable_entry*>(
- reinterpret_cast<const uint8_t*>(best_type) + best_offset + dtohl(best_type->entriesStart));
-
- const uint32_t* flags = reinterpret_cast<const uint32_t*>(type_spec_ptr->type_spec + 1);
- out_entry->type_flags = dtohl(flags[entry_idx]);
- out_entry->entry = best_entry;
- out_entry->config = best_config;
- out_entry->type_string_ref = StringPoolRef(&type_string_pool_, best_type->id - 1);
- out_entry->entry_string_ref = StringPoolRef(&key_string_pool_, dtohl(best_entry->key.index));
- return true;
+ const uint32_t* entry_offsets = reinterpret_cast<const uint32_t*>(
+ reinterpret_cast<const uint8_t*>(type_chunk) + offsets_offset);
+ return dtohl(entry_offsets[entry_index]);
}
-bool LoadedPackage::FindEntry(uint8_t type_idx, uint16_t entry_idx, const ResTable_config& config,
- FindEntryResult* out_entry) const {
- ATRACE_CALL();
-
- // If the type IDs are offset in this package, we need to take that into account when searching
- // for a type.
- const TypeSpecPtr& ptr = type_specs_[type_idx - type_id_offset_];
- if (UNLIKELY(ptr == nullptr)) {
- return false;
+const ResTable_entry* LoadedPackage::GetEntryFromOffset(const ResTable_type* type_chunk,
+ uint32_t offset) {
+ if (UNLIKELY(!VerifyResTableEntry(type_chunk, offset))) {
+ return nullptr;
}
-
- // If there is an IDMAP supplied with this package, translate the entry ID.
- if (ptr->idmap_entries != nullptr) {
- if (!LoadedIdmap::Lookup(ptr->idmap_entries, entry_idx, &entry_idx)) {
- // There is no mapping, so the resource is not meant to be in this overlay package.
- return false;
- }
- }
- return FindEntry(ptr, entry_idx, config, out_entry);
+ return reinterpret_cast<const ResTable_entry*>(reinterpret_cast<const uint8_t*>(type_chunk) +
+ offset + dtohl(type_chunk->entriesStart));
}
void LoadedPackage::CollectConfigurations(bool exclude_mipmap,
@@ -348,7 +267,7 @@
const static std::u16string kMipMap = u"mipmap";
const size_t type_count = type_specs_.size();
for (size_t i = 0; i < type_count; i++) {
- const util::unique_cptr<TypeSpec>& type_spec = type_specs_[i];
+ const TypeSpecPtr& type_spec = type_specs_[i];
if (type_spec != nullptr) {
if (exclude_mipmap) {
const int type_idx = type_spec->type_spec->id - 1;
@@ -369,8 +288,11 @@
}
}
- for (size_t j = 0; j < type_spec->type_count; j++) {
- out_configs->insert(type_spec->types[j].configuration);
+ const auto iter_end = type_spec->types + type_spec->type_count;
+ for (auto iter = type_spec->types; iter != iter_end; ++iter) {
+ ResTable_config config;
+ config.copyFromDtoH((*iter)->config);
+ out_configs->insert(config);
}
}
}
@@ -380,10 +302,12 @@
char temp_locale[RESTABLE_MAX_LOCALE_LEN];
const size_t type_count = type_specs_.size();
for (size_t i = 0; i < type_count; i++) {
- const util::unique_cptr<TypeSpec>& type_spec = type_specs_[i];
+ const TypeSpecPtr& type_spec = type_specs_[i];
if (type_spec != nullptr) {
- for (size_t j = 0; j < type_spec->type_count; j++) {
- const ResTable_config& configuration = type_spec->types[j].configuration;
+ const auto iter_end = type_spec->types + type_spec->type_count;
+ for (auto iter = type_spec->types; iter != iter_end; ++iter) {
+ ResTable_config configuration;
+ configuration.copyFromDtoH((*iter)->config);
if (configuration.locale != 0) {
configuration.getBcp47Locale(temp_locale, canonicalize);
std::string locale(temp_locale);
@@ -411,17 +335,17 @@
return 0u;
}
- for (size_t ti = 0; ti < type_spec->type_count; ti++) {
- const Type* type = &type_spec->types[ti];
- size_t entry_count = dtohl(type->type->entryCount);
+ const auto iter_end = type_spec->types + type_spec->type_count;
+ for (auto iter = type_spec->types; iter != iter_end; ++iter) {
+ const ResTable_type* type = *iter;
+ size_t entry_count = dtohl(type->entryCount);
for (size_t entry_idx = 0; entry_idx < entry_count; entry_idx++) {
const uint32_t* entry_offsets = reinterpret_cast<const uint32_t*>(
- reinterpret_cast<const uint8_t*>(type->type) + dtohs(type->type->header.headerSize));
+ reinterpret_cast<const uint8_t*>(type) + dtohs(type->header.headerSize));
const uint32_t offset = dtohl(entry_offsets[entry_idx]);
if (offset != ResTable_type::NO_ENTRY) {
- const ResTable_entry* entry =
- reinterpret_cast<const ResTable_entry*>(reinterpret_cast<const uint8_t*>(type->type) +
- dtohl(type->type->entriesStart) + offset);
+ const ResTable_entry* entry = reinterpret_cast<const ResTable_entry*>(
+ reinterpret_cast<const uint8_t*>(type) + dtohl(type->entriesStart) + offset);
if (dtohl(entry->key.index) == static_cast<uint32_t>(key_idx)) {
// The package ID will be overridden by the caller (due to runtime assignment of package
// IDs for shared libraries).
@@ -433,8 +357,7 @@
return 0u;
}
-const LoadedPackage* LoadedArsc::GetPackageForId(uint32_t resid) const {
- const uint8_t package_id = get_package_id(resid);
+const LoadedPackage* LoadedArsc::GetPackageById(uint8_t package_id) const {
for (const auto& loaded_package : packages_) {
if (loaded_package->GetPackageId() == package_id) {
return loaded_package.get();
@@ -446,7 +369,7 @@
std::unique_ptr<const LoadedPackage> LoadedPackage::Load(const Chunk& chunk,
const LoadedIdmap* loaded_idmap,
bool system, bool load_as_shared_library) {
- ATRACE_CALL();
+ ATRACE_NAME("LoadedPackage::Load");
std::unique_ptr<LoadedPackage> loaded_package(new LoadedPackage());
// typeIdOffset was added at some point, but we still must recognize apps built before this
@@ -486,14 +409,10 @@
util::ReadUtf16StringFromDevice(header->name, arraysize(header->name),
&loaded_package->package_name_);
- // A TypeSpec builder. We use this to accumulate the set of Types
- // available for a TypeSpec, and later build a single, contiguous block
- // of memory that holds all the Types together with the TypeSpec.
- std::unique_ptr<TypeSpecPtrBuilder> types_builder;
-
- // Keep track of the last seen type index. Since type IDs are 1-based,
- // this records their index, which is 0-based (type ID - 1).
- uint8_t last_type_idx = 0;
+ // A map of TypeSpec builders, each associated with an type index.
+ // We use these to accumulate the set of Types available for a TypeSpec, and later build a single,
+ // contiguous block of memory that holds all the Types together with the TypeSpec.
+ std::unordered_map<int, std::unique_ptr<TypeSpecPtrBuilder>> type_builder_map;
ChunkIterator iter(chunk.data_ptr(), chunk.data_size());
while (iter.HasNext()) {
@@ -525,30 +444,6 @@
} break;
case RES_TABLE_TYPE_SPEC_TYPE: {
- ATRACE_NAME("LoadTableTypeSpec");
-
- // Starting a new TypeSpec, so finish the old one if there was one.
- if (types_builder) {
- TypeSpecPtr type_spec_ptr = types_builder->Build();
- if (type_spec_ptr == nullptr) {
- LOG(ERROR) << "Too many type configurations, overflow detected.";
- return {};
- }
-
- // We only add the type to the package if there is no IDMAP, or if the type is
- // overlaying something.
- if (loaded_idmap == nullptr || type_spec_ptr->idmap_entries != nullptr) {
- // If this is an overlay, insert it at the target type ID.
- if (type_spec_ptr->idmap_entries != nullptr) {
- last_type_idx = dtohs(type_spec_ptr->idmap_entries->target_type_id) - 1;
- }
- loaded_package->type_specs_.editItemAt(last_type_idx) = std::move(type_spec_ptr);
- }
-
- types_builder = {};
- last_type_idx = 0;
- }
-
const ResTable_typeSpec* type_spec = child_chunk.header<ResTable_typeSpec>();
if (type_spec == nullptr) {
LOG(ERROR) << "RES_TABLE_TYPE_SPEC_TYPE too small.";
@@ -583,8 +478,6 @@
return {};
}
- last_type_idx = type_spec->id - 1;
-
// If this is an overlay, associate the mapping of this type to the target type
// from the IDMAP.
const IdmapEntry_header* idmap_entry_header = nullptr;
@@ -592,7 +485,13 @@
idmap_entry_header = loaded_idmap->GetEntryMapForType(type_spec->id);
}
- types_builder = util::make_unique<TypeSpecPtrBuilder>(type_spec, idmap_entry_header);
+ std::unique_ptr<TypeSpecPtrBuilder>& builder_ptr = type_builder_map[type_spec->id - 1];
+ if (builder_ptr == nullptr) {
+ builder_ptr = util::make_unique<TypeSpecPtrBuilder>(type_spec, idmap_entry_header);
+ } else {
+ LOG(WARNING) << StringPrintf("RES_TABLE_TYPE_SPEC_TYPE already defined for ID %02x",
+ type_spec->id);
+ }
} break;
case RES_TABLE_TYPE_TYPE: {
@@ -607,12 +506,15 @@
}
// Type chunks must be preceded by their TypeSpec chunks.
- if (!types_builder || type->id - 1 != last_type_idx) {
- LOG(ERROR) << "RES_TABLE_TYPE_TYPE found without preceding RES_TABLE_TYPE_SPEC_TYPE.";
+ std::unique_ptr<TypeSpecPtrBuilder>& builder_ptr = type_builder_map[type->id - 1];
+ if (builder_ptr != nullptr) {
+ builder_ptr->AddType(type);
+ } else {
+ LOG(ERROR) << StringPrintf(
+ "RES_TABLE_TYPE_TYPE with ID %02x found without preceding RES_TABLE_TYPE_SPEC_TYPE.",
+ type->id);
return {};
}
-
- types_builder->AddType(type);
} break;
case RES_TABLE_LIBRARY_TYPE: {
@@ -638,7 +540,7 @@
arraysize(entry_iter->packageName), &package_name);
if (dtohl(entry_iter->packageId) >= std::numeric_limits<uint8_t>::max()) {
- LOG(ERROR) << base::StringPrintf(
+ LOG(ERROR) << StringPrintf(
"Package ID %02x in RES_TABLE_LIBRARY_TYPE too large for package '%s'.",
dtohl(entry_iter->packageId), package_name.c_str());
return {};
@@ -651,14 +553,20 @@
} break;
default:
- LOG(WARNING) << base::StringPrintf("Unknown chunk type '%02x'.", chunk.type());
+ LOG(WARNING) << StringPrintf("Unknown chunk type '%02x'.", chunk.type());
break;
}
}
- // Finish the last TypeSpec.
- if (types_builder) {
- TypeSpecPtr type_spec_ptr = types_builder->Build();
+ if (iter.HadError()) {
+ LOG(ERROR) << iter.GetLastError();
+ return {};
+ }
+
+ // Flatten and construct the TypeSpecs.
+ for (auto& entry : type_builder_map) {
+ uint8_t type_idx = static_cast<uint8_t>(entry.first);
+ TypeSpecPtr type_spec_ptr = entry.second->Build();
if (type_spec_ptr == nullptr) {
LOG(ERROR) << "Too many type configurations, overflow detected.";
return {};
@@ -669,43 +577,17 @@
if (loaded_idmap == nullptr || type_spec_ptr->idmap_entries != nullptr) {
// If this is an overlay, insert it at the target type ID.
if (type_spec_ptr->idmap_entries != nullptr) {
- last_type_idx = dtohs(type_spec_ptr->idmap_entries->target_type_id) - 1;
+ type_idx = dtohs(type_spec_ptr->idmap_entries->target_type_id) - 1;
}
- loaded_package->type_specs_.editItemAt(last_type_idx) = std::move(type_spec_ptr);
+ loaded_package->type_specs_.editItemAt(type_idx) = std::move(type_spec_ptr);
}
}
- if (iter.HadError()) {
- LOG(ERROR) << iter.GetLastError();
- return {};
- }
return std::move(loaded_package);
}
-bool LoadedArsc::FindEntry(uint32_t resid, const ResTable_config& config,
- FindEntryResult* out_entry) const {
- ATRACE_CALL();
-
- const uint8_t package_id = get_package_id(resid);
- const uint8_t type_id = get_type_id(resid);
- const uint16_t entry_id = get_entry_id(resid);
-
- if (UNLIKELY(type_id == 0)) {
- LOG(ERROR) << base::StringPrintf("Invalid ID 0x%08x.", resid);
- return false;
- }
-
- for (const auto& loaded_package : packages_) {
- if (loaded_package->GetPackageId() == package_id) {
- return loaded_package->FindEntry(type_id - 1, entry_id, config, out_entry);
- }
- }
- return false;
-}
-
bool LoadedArsc::LoadTable(const Chunk& chunk, const LoadedIdmap* loaded_idmap,
bool load_as_shared_library) {
- ATRACE_CALL();
const ResTable_header* header = chunk.header<ResTable_header>();
if (header == nullptr) {
LOG(ERROR) << "RES_TABLE_TYPE too small.";
@@ -752,7 +634,7 @@
} break;
default:
- LOG(WARNING) << base::StringPrintf("Unknown chunk type '%02x'.", chunk.type());
+ LOG(WARNING) << StringPrintf("Unknown chunk type '%02x'.", chunk.type());
break;
}
}
@@ -767,7 +649,7 @@
std::unique_ptr<const LoadedArsc> LoadedArsc::Load(const StringPiece& data,
const LoadedIdmap* loaded_idmap, bool system,
bool load_as_shared_library) {
- ATRACE_CALL();
+ ATRACE_NAME("LoadedArsc::LoadTable");
// Not using make_unique because the constructor is private.
std::unique_ptr<LoadedArsc> loaded_arsc(new LoadedArsc());
@@ -784,7 +666,7 @@
break;
default:
- LOG(WARNING) << base::StringPrintf("Unknown chunk type '%02x'.", chunk.type());
+ LOG(WARNING) << StringPrintf("Unknown chunk type '%02x'.", chunk.type());
break;
}
}
diff --git a/libs/androidfw/OWNERS b/libs/androidfw/OWNERS
new file mode 100644
index 0000000..23ec5ab
--- /dev/null
+++ b/libs/androidfw/OWNERS
@@ -0,0 +1,2 @@
+set noparent
+toddke@google.com
diff --git a/libs/androidfw/include/androidfw/AssetManager2.h b/libs/androidfw/include/androidfw/AssetManager2.h
index b033137..ef08897 100644
--- a/libs/androidfw/include/androidfw/AssetManager2.h
+++ b/libs/androidfw/include/androidfw/AssetManager2.h
@@ -69,6 +69,8 @@
Entry entries[0];
};
+struct FindEntryResult;
+
// AssetManager2 is the main entry point for accessing assets and resources.
// AssetManager2 provides caching of resources retrieved via the underlying ApkAssets.
class AssetManager2 {
@@ -127,7 +129,7 @@
// If `exclude_mipmap` is set to true, resource configurations defined for resource type 'mipmap'
// will be excluded from the list.
std::set<ResTable_config> GetResourceConfigurations(bool exclude_system = false,
- bool exclude_mipmap = false);
+ bool exclude_mipmap = false) const;
// Returns all the locales for which there are resources defined. This includes resource
// locales in all the ApkAssets set for this AssetManager.
@@ -136,24 +138,24 @@
// If `merge_equivalent_languages` is set to true, resource locales will be canonicalized
// and de-duped in the resulting list.
std::set<std::string> GetResourceLocales(bool exclude_system = false,
- bool merge_equivalent_languages = false);
+ bool merge_equivalent_languages = false) const;
// Searches the set of APKs loaded by this AssetManager and opens the first one found located
// in the assets/ directory.
// `mode` controls how the file is opened.
//
// NOTE: The loaded APKs are searched in reverse order.
- std::unique_ptr<Asset> Open(const std::string& filename, Asset::AccessMode mode);
+ std::unique_ptr<Asset> Open(const std::string& filename, Asset::AccessMode mode) const;
// Opens a file within the assets/ directory of the APK specified by `cookie`.
// `mode` controls how the file is opened.
std::unique_ptr<Asset> Open(const std::string& filename, ApkAssetsCookie cookie,
- Asset::AccessMode mode);
+ Asset::AccessMode mode) const;
// Opens the directory specified by `dirname`. The result is an AssetDir that is the combination
// of all directories matching `dirname` under the assets/ directory of every ApkAssets loaded.
// The entries are sorted by their ASCII name.
- std::unique_ptr<AssetDir> OpenDir(const std::string& dirname);
+ std::unique_ptr<AssetDir> OpenDir(const std::string& dirname) const;
// Searches the set of APKs loaded by this AssetManager and opens the first one found.
// `mode` controls how the file is opened.
@@ -161,24 +163,24 @@
//
// NOTE: The loaded APKs are searched in reverse order.
std::unique_ptr<Asset> OpenNonAsset(const std::string& filename, Asset::AccessMode mode,
- ApkAssetsCookie* out_cookie = nullptr);
+ ApkAssetsCookie* out_cookie = nullptr) const;
// Opens a file in the APK specified by `cookie`. `mode` controls how the file is opened.
// This is typically used to open a specific AndroidManifest.xml, or a binary XML file
// referenced by a resource lookup with GetResource().
std::unique_ptr<Asset> OpenNonAsset(const std::string& filename, ApkAssetsCookie cookie,
- Asset::AccessMode mode);
+ Asset::AccessMode mode) const;
// Populates the `out_name` parameter with resource name information.
// Utf8 strings are preferred, and only if they are unavailable are
// the Utf16 variants populated.
// Returns false if the resource was not found or the name was missing/corrupt.
- bool GetResourceName(uint32_t resid, ResourceName* out_name);
+ bool GetResourceName(uint32_t resid, ResourceName* out_name) const;
// Populates `out_flags` with the bitmask of configuration axis that this resource varies with.
// See ResTable_config for the list of configuration axis.
// Returns false if the resource was not found.
- bool GetResourceFlags(uint32_t resid, uint32_t* out_flags);
+ bool GetResourceFlags(uint32_t resid, uint32_t* out_flags) const;
// Finds the resource ID assigned to `resource_name`.
// `resource_name` must be of the form '[package:][type/]entry'.
@@ -186,7 +188,7 @@
// If no type is specified in `resource_name`, then `fallback_type` is used as the type.
// Returns 0x0 if no resource by that name was found.
uint32_t GetResourceId(const std::string& resource_name, const std::string& fallback_type = {},
- const std::string& fallback_package = {});
+ const std::string& fallback_package = {}) const;
// Retrieves the best matching resource with ID `resid`. The resource value is filled into
// `out_value` and the configuration for the selected value is populated in `out_selected_config`.
@@ -199,7 +201,7 @@
// this function logs if the resource was a map/bag type before returning kInvalidCookie.
ApkAssetsCookie GetResource(uint32_t resid, bool may_be_bag, uint16_t density_override,
Res_value* out_value, ResTable_config* out_selected_config,
- uint32_t* out_flags);
+ uint32_t* out_flags) const;
// Resolves the resource reference in `in_out_value` if the data type is
// Res_value::TYPE_REFERENCE.
@@ -215,7 +217,7 @@
// it was not found.
ApkAssetsCookie ResolveReference(ApkAssetsCookie cookie, Res_value* in_out_value,
ResTable_config* in_out_selected_config, uint32_t* in_out_flags,
- uint32_t* out_last_reference);
+ uint32_t* out_last_reference) const;
// Retrieves the best matching bag/map resource with ID `resid`.
// This method will resolve all parent references for this bag and merge keys with the child.
@@ -233,9 +235,9 @@
std::unique_ptr<Theme> NewTheme();
template <typename Func>
- void ForEachPackage(Func func) {
+ void ForEachPackage(Func func) const {
for (const PackageGroup& package_group : package_groups_) {
- func(package_group.packages_.front()->GetPackageName(),
+ func(package_group.packages_.front().loaded_package_->GetPackageName(),
package_group.dynamic_ref_table.mAssignedPackageId);
}
}
@@ -260,7 +262,7 @@
// NOTE: FindEntry takes care of ensuring that structs within FindEntryResult have been properly
// bounds-checked. Callers of FindEntry are free to trust the data if this method succeeds.
ApkAssetsCookie FindEntry(uint32_t resid, uint16_t density_override, bool stop_at_first_match,
- FindEntryResult* out_entry);
+ FindEntryResult* out_entry) const;
// Assigns package IDs to all shared library ApkAssets.
// Should be called whenever the ApkAssets are changed.
@@ -270,13 +272,43 @@
// bitmask `diff`.
void InvalidateCaches(uint32_t diff);
+ // Triggers the re-construction of lists of types that match the set configuration.
+ // This should always be called when mutating the AssetManager's configuration or ApkAssets set.
+ void RebuildFilterList();
+
// The ordered list of ApkAssets to search. These are not owned by the AssetManager, and must
// have a longer lifetime.
std::vector<const ApkAssets*> apk_assets_;
+ // A collection of configurations and their associated ResTable_type that match the current
+ // AssetManager configuration.
+ struct FilteredConfigGroup {
+ std::vector<ResTable_config> configurations;
+ std::vector<const ResTable_type*> types;
+ };
+
+ // Represents an single package.
+ struct ConfiguredPackage {
+ // A pointer to the immutable, loaded package info.
+ const LoadedPackage* loaded_package_;
+
+ // A mutable AssetManager-specific list of configurations that match the AssetManager's
+ // current configuration. This is used as an optimization to avoid checking every single
+ // candidate configuration when looking up resources.
+ ByteBucketArray<FilteredConfigGroup> filtered_configs_;
+ };
+
+ // Represents a logical package, which can be made up of many individual packages. Each package
+ // in a PackageGroup shares the same package name and package ID.
struct PackageGroup {
- std::vector<const LoadedPackage*> packages_;
+ // The set of packages that make-up this group.
+ std::vector<ConfiguredPackage> packages_;
+
+ // The cookies associated with each package in the group. They share the same order as
+ // packages_.
std::vector<ApkAssetsCookie> cookies_;
+
+ // A library reference table that contains build-package ID to runtime-package ID mappings.
DynamicRefTable dynamic_ref_table;
};
@@ -350,7 +382,7 @@
ApkAssetsCookie ResolveAttributeReference(ApkAssetsCookie cookie, Res_value* in_out_value,
ResTable_config* in_out_selected_config = nullptr,
uint32_t* in_out_type_spec_flags = nullptr,
- uint32_t* out_last_ref = nullptr);
+ uint32_t* out_last_ref = nullptr) const;
private:
DISALLOW_COPY_AND_ASSIGN(Theme);
diff --git a/libs/androidfw/include/androidfw/AttributeFinder.h b/libs/androidfw/include/androidfw/AttributeFinder.h
index f281921..03fad49 100644
--- a/libs/androidfw/include/androidfw/AttributeFinder.h
+++ b/libs/androidfw/include/androidfw/AttributeFinder.h
@@ -58,6 +58,7 @@
BackTrackingAttributeFinder(const Iterator& begin, const Iterator& end);
Iterator Find(uint32_t attr);
+ inline Iterator end();
private:
void JumpToClosestAttribute(uint32_t package_id);
@@ -201,6 +202,11 @@
return end_;
}
+template <typename Derived, typename Iterator>
+Iterator BackTrackingAttributeFinder<Derived, Iterator>::end() {
+ return end_;
+}
+
} // namespace android
#endif // ANDROIDFW_ATTRIBUTE_FINDER_H
diff --git a/libs/androidfw/include/androidfw/AttributeResolution.h b/libs/androidfw/include/androidfw/AttributeResolution.h
index 69b76041..35ef98d 100644
--- a/libs/androidfw/include/androidfw/AttributeResolution.h
+++ b/libs/androidfw/include/androidfw/AttributeResolution.h
@@ -17,7 +17,8 @@
#ifndef ANDROIDFW_ATTRIBUTERESOLUTION_H
#define ANDROIDFW_ATTRIBUTERESOLUTION_H
-#include <androidfw/ResourceTypes.h>
+#include "androidfw/AssetManager2.h"
+#include "androidfw/ResourceTypes.h"
namespace android {
@@ -42,19 +43,19 @@
// `out_values` must NOT be nullptr.
// `out_indices` may be nullptr.
-bool ResolveAttrs(ResTable::Theme* theme, uint32_t def_style_attr, uint32_t def_style_res,
+bool ResolveAttrs(Theme* theme, uint32_t def_style_attr, uint32_t def_style_resid,
uint32_t* src_values, size_t src_values_length, uint32_t* attrs,
size_t attrs_length, uint32_t* out_values, uint32_t* out_indices);
// `out_values` must NOT be nullptr.
// `out_indices` is NOT optional and must NOT be nullptr.
-void ApplyStyle(ResTable::Theme* theme, ResXMLParser* xml_parser, uint32_t def_style_attr,
- uint32_t def_style_res, const uint32_t* attrs, size_t attrs_length,
+void ApplyStyle(Theme* theme, ResXMLParser* xml_parser, uint32_t def_style_attr,
+ uint32_t def_style_resid, const uint32_t* attrs, size_t attrs_length,
uint32_t* out_values, uint32_t* out_indices);
// `out_values` must NOT be nullptr.
// `out_indices` may be nullptr.
-bool RetrieveAttributes(const ResTable* res, ResXMLParser* xml_parser, uint32_t* attrs,
+bool RetrieveAttributes(AssetManager2* assetmanager, ResXMLParser* xml_parser, uint32_t* attrs,
size_t attrs_length, uint32_t* out_values, uint32_t* out_indices);
} // namespace android
diff --git a/libs/androidfw/include/androidfw/LoadedArsc.h b/libs/androidfw/include/androidfw/LoadedArsc.h
index 965e2db..35ae5fc 100644
--- a/libs/androidfw/include/androidfw/LoadedArsc.h
+++ b/libs/androidfw/include/androidfw/LoadedArsc.h
@@ -41,32 +41,40 @@
int package_id = 0;
};
-struct FindEntryResult {
- // A pointer to the resource table entry for this resource.
- // If the size of the entry is > sizeof(ResTable_entry), it can be cast to
- // a ResTable_map_entry and processed as a bag/map.
- const ResTable_entry* entry = nullptr;
+// TypeSpec is going to be immediately proceeded by
+// an array of Type structs, all in the same block of memory.
+struct TypeSpec {
+ // Pointer to the mmapped data where flags are kept.
+ // Flags denote whether the resource entry is public
+ // and under which configurations it varies.
+ const ResTable_typeSpec* type_spec;
- // The configuration for which the resulting entry was defined.
- const ResTable_config* config = nullptr;
+ // Pointer to the mmapped data where the IDMAP mappings for this type
+ // exist. May be nullptr if no IDMAP exists.
+ const IdmapEntry_header* idmap_entries;
- // Stores the resulting bitmask of configuration axis with which the resource value varies.
- uint32_t type_flags = 0u;
+ // The number of types that follow this struct.
+ // There is a type for each configuration that entries are defined for.
+ size_t type_count;
- // The dynamic package ID map for the package from which this resource came from.
- const DynamicRefTable* dynamic_ref_table = nullptr;
+ // Trick to easily access a variable number of Type structs
+ // proceeding this struct, and to ensure their alignment.
+ const ResTable_type* types[0];
- // The string pool reference to the type's name. This uses a different string pool than
- // the global string pool, but this is hidden from the caller.
- StringPoolRef type_string_ref;
+ inline uint32_t GetFlagsForEntryIndex(uint16_t entry_index) const {
+ if (entry_index >= dtohl(type_spec->entryCount)) {
+ return 0u;
+ }
- // The string pool reference to the entry's name. This uses a different string pool than
- // the global string pool, but this is hidden from the caller.
- StringPoolRef entry_string_ref;
+ const uint32_t* flags = reinterpret_cast<const uint32_t*>(type_spec + 1);
+ return flags[entry_index];
+ }
};
-struct TypeSpec;
-class LoadedArsc;
+// TypeSpecPtr points to a block of memory that holds a TypeSpec struct, followed by an array of
+// ResTable_type pointers.
+// TypeSpecPtr is a managed pointer that knows how to delete itself.
+using TypeSpecPtr = util::unique_cptr<TypeSpec>;
class LoadedPackage {
public:
@@ -76,9 +84,6 @@
~LoadedPackage();
- bool FindEntry(uint8_t type_idx, uint16_t entry_idx, const ResTable_config& config,
- FindEntryResult* out_entry) const;
-
// Finds the entry with the specified type name and entry name. The names are in UTF-16 because
// the underlying ResStringPool API expects this. For now this is acceptable, but since
// the default policy in AAPT2 is to build UTF-8 string pools, this needs to change.
@@ -86,6 +91,12 @@
// for patching the correct package ID to the resource ID.
uint32_t FindEntryByName(const std::u16string& type_name, const std::u16string& entry_name) const;
+ static const ResTable_entry* GetEntry(const ResTable_type* type_chunk, uint16_t entry_index);
+
+ static uint32_t GetEntryOffset(const ResTable_type* type_chunk, uint16_t entry_index);
+
+ static const ResTable_entry* GetEntryFromOffset(const ResTable_type* type_chunk, uint32_t offset);
+
// Returns the string pool where type names are stored.
inline const ResStringPool* GetTypeStringPool() const {
return &type_string_pool_;
@@ -135,14 +146,32 @@
// before being inserted into the set. This may cause some equivalent locales to de-dupe.
void CollectLocales(bool canonicalize, std::set<std::string>* out_locales) const;
+ // type_idx is TT - 1 from 0xPPTTEEEE.
+ inline const TypeSpec* GetTypeSpecByTypeIndex(uint8_t type_index) const {
+ // If the type IDs are offset in this package, we need to take that into account when searching
+ // for a type.
+ return type_specs_[type_index - type_id_offset_].get();
+ }
+
+ template <typename Func>
+ void ForEachTypeSpec(Func f) const {
+ for (size_t i = 0; i < type_specs_.size(); i++) {
+ const TypeSpecPtr& ptr = type_specs_[i];
+ if (ptr != nullptr) {
+ uint8_t type_id = ptr->type_spec->id;
+ if (ptr->idmap_entries != nullptr) {
+ type_id = ptr->idmap_entries->target_type_id;
+ }
+ f(ptr.get(), type_id - 1);
+ }
+ }
+ }
+
private:
DISALLOW_COPY_AND_ASSIGN(LoadedPackage);
LoadedPackage();
- bool FindEntry(const util::unique_cptr<TypeSpec>& type_spec_ptr, uint16_t entry_idx,
- const ResTable_config& config, FindEntryResult* out_entry) const;
-
ResStringPool type_string_pool_;
ResStringPool key_string_pool_;
std::string package_name_;
@@ -152,7 +181,7 @@
bool system_ = false;
bool overlay_ = false;
- ByteBucketArray<util::unique_cptr<TypeSpec>> type_specs_;
+ ByteBucketArray<TypeSpecPtr> type_specs_;
std::vector<DynamicPackageEntry> dynamic_package_map_;
};
@@ -180,25 +209,20 @@
return &global_string_pool_;
}
- // Finds the resource with ID `resid` with the best value for configuration `config`.
- // The parameter `out_entry` will be filled with the resulting resource entry.
- // The resource entry can be a simple entry (ResTable_entry) or a complex bag
- // (ResTable_entry_map).
- bool FindEntry(uint32_t resid, const ResTable_config& config, FindEntryResult* out_entry) const;
-
- // Gets a pointer to the name of the package in `resid`, or nullptr if the package doesn't exist.
- const LoadedPackage* GetPackageForId(uint32_t resid) const;
-
- // Returns true if this is a system provided resource.
- inline bool IsSystem() const {
- return system_;
- }
+ // Gets a pointer to the package with the specified package ID, or nullptr if no such package
+ // exists.
+ const LoadedPackage* GetPackageById(uint8_t package_id) const;
// Returns a vector of LoadedPackage pointers, representing the packages in this LoadedArsc.
inline const std::vector<std::unique_ptr<const LoadedPackage>>& GetPackages() const {
return packages_;
}
+ // Returns true if this is a system provided resource.
+ inline bool IsSystem() const {
+ return system_;
+ }
+
private:
DISALLOW_COPY_AND_ASSIGN(LoadedArsc);
diff --git a/libs/androidfw/include/androidfw/MutexGuard.h b/libs/androidfw/include/androidfw/MutexGuard.h
new file mode 100644
index 0000000..64924f4
--- /dev/null
+++ b/libs/androidfw/include/androidfw/MutexGuard.h
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROIDFW_MUTEXGUARD_H
+#define ANDROIDFW_MUTEXGUARD_H
+
+#include <mutex>
+#include <type_traits>
+
+#include "android-base/macros.h"
+
+namespace android {
+
+template <typename T>
+class ScopedLock;
+
+// Owns the guarded object and protects access to it via a mutex.
+// The guarded object is inaccessible via this class.
+// The mutex is locked and the object accessed via the ScopedLock<T> class.
+//
+// NOTE: The template parameter T should not be a raw pointer, since ownership
+// is ambiguous and error-prone. Instead use an std::unique_ptr<>.
+//
+// Example use:
+//
+// Guarded<std::string> shared_string("hello");
+// {
+// ScopedLock<std::string> locked_string(shared_string);
+// *locked_string += " world";
+// }
+//
+template <typename T>
+class Guarded {
+ static_assert(!std::is_pointer<T>::value, "T must not be a raw pointer");
+
+ public:
+ explicit Guarded() : guarded_() {
+ }
+
+ template <typename U = T>
+ explicit Guarded(const T& guarded,
+ typename std::enable_if<std::is_copy_constructible<U>::value>::type = void())
+ : guarded_(guarded) {
+ }
+
+ template <typename U = T>
+ explicit Guarded(T&& guarded,
+ typename std::enable_if<std::is_move_constructible<U>::value>::type = void())
+ : guarded_(std::move(guarded)) {
+ }
+
+ private:
+ friend class ScopedLock<T>;
+
+ DISALLOW_COPY_AND_ASSIGN(Guarded);
+
+ std::mutex lock_;
+ T guarded_;
+};
+
+template <typename T>
+class ScopedLock {
+ public:
+ explicit ScopedLock(Guarded<T>& guarded) : lock_(guarded.lock_), guarded_(guarded.guarded_) {
+ }
+
+ T& operator*() {
+ return guarded_;
+ }
+
+ T* operator->() {
+ return &guarded_;
+ }
+
+ T* get() {
+ return &guarded_;
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(ScopedLock);
+
+ std::lock_guard<std::mutex> lock_;
+ T& guarded_;
+};
+
+} // namespace android
+
+#endif // ANDROIDFW_MUTEXGUARD_H
diff --git a/libs/androidfw/include/androidfw/ResourceUtils.h b/libs/androidfw/include/androidfw/ResourceUtils.h
index c2eae85..d94779b 100644
--- a/libs/androidfw/include/androidfw/ResourceUtils.h
+++ b/libs/androidfw/include/androidfw/ResourceUtils.h
@@ -28,7 +28,7 @@
StringPiece* out_entry);
inline uint32_t fix_package_id(uint32_t resid, uint8_t package_id) {
- return resid | (static_cast<uint32_t>(package_id) << 24);
+ return (resid & 0x00ffffffu) | (static_cast<uint32_t>(package_id) << 24);
}
inline uint8_t get_package_id(uint32_t resid) {
diff --git a/libs/androidfw/tests/ApkAssets_test.cpp b/libs/androidfw/tests/ApkAssets_test.cpp
index 6c43a67..e2b9f00 100644
--- a/libs/androidfw/tests/ApkAssets_test.cpp
+++ b/libs/androidfw/tests/ApkAssets_test.cpp
@@ -26,58 +26,56 @@
using ::android::base::unique_fd;
using ::com::android::basic::R;
+using ::testing::Eq;
+using ::testing::Ge;
+using ::testing::NotNull;
+using ::testing::SizeIs;
+using ::testing::StrEq;
namespace android {
TEST(ApkAssetsTest, LoadApk) {
std::unique_ptr<const ApkAssets> loaded_apk =
ApkAssets::Load(GetTestDataPath() + "/basic/basic.apk");
- ASSERT_NE(nullptr, loaded_apk);
+ ASSERT_THAT(loaded_apk, NotNull());
const LoadedArsc* loaded_arsc = loaded_apk->GetLoadedArsc();
- ASSERT_NE(nullptr, loaded_arsc);
-
- const LoadedPackage* loaded_package = loaded_arsc->GetPackageForId(0x7f010000);
- ASSERT_NE(nullptr, loaded_package);
-
- std::unique_ptr<Asset> asset = loaded_apk->Open("res/layout/main.xml");
- ASSERT_NE(nullptr, asset);
+ ASSERT_THAT(loaded_arsc, NotNull());
+ ASSERT_THAT(loaded_arsc->GetPackageById(0x7fu), NotNull());
+ ASSERT_THAT(loaded_apk->Open("res/layout/main.xml"), NotNull());
}
TEST(ApkAssetsTest, LoadApkFromFd) {
const std::string path = GetTestDataPath() + "/basic/basic.apk";
unique_fd fd(::open(path.c_str(), O_RDONLY | O_BINARY));
- ASSERT_GE(fd.get(), 0);
+ ASSERT_THAT(fd.get(), Ge(0));
std::unique_ptr<const ApkAssets> loaded_apk =
ApkAssets::LoadFromFd(std::move(fd), path, false /*system*/, false /*force_shared_lib*/);
- ASSERT_NE(nullptr, loaded_apk);
+ ASSERT_THAT(loaded_apk, NotNull());
const LoadedArsc* loaded_arsc = loaded_apk->GetLoadedArsc();
- ASSERT_NE(nullptr, loaded_arsc);
-
- const LoadedPackage* loaded_package = loaded_arsc->GetPackageForId(0x7f010000);
- ASSERT_NE(nullptr, loaded_package);
-
- std::unique_ptr<Asset> asset = loaded_apk->Open("res/layout/main.xml");
- ASSERT_NE(nullptr, asset);
+ ASSERT_THAT(loaded_arsc, NotNull());
+ ASSERT_THAT(loaded_arsc->GetPackageById(0x7fu), NotNull());
+ ASSERT_THAT(loaded_apk->Open("res/layout/main.xml"), NotNull());
}
TEST(ApkAssetsTest, LoadApkAsSharedLibrary) {
std::unique_ptr<const ApkAssets> loaded_apk =
ApkAssets::Load(GetTestDataPath() + "/appaslib/appaslib.apk");
- ASSERT_NE(nullptr, loaded_apk);
+ ASSERT_THAT(loaded_apk, NotNull());
+
const LoadedArsc* loaded_arsc = loaded_apk->GetLoadedArsc();
- ASSERT_NE(nullptr, loaded_arsc);
- ASSERT_EQ(1u, loaded_arsc->GetPackages().size());
+ ASSERT_THAT(loaded_arsc, NotNull());
+ ASSERT_THAT(loaded_arsc->GetPackages(), SizeIs(1u));
EXPECT_FALSE(loaded_arsc->GetPackages()[0]->IsDynamic());
loaded_apk = ApkAssets::LoadAsSharedLibrary(GetTestDataPath() + "/appaslib/appaslib.apk");
- ASSERT_NE(nullptr, loaded_apk);
+ ASSERT_THAT(loaded_apk, NotNull());
loaded_arsc = loaded_apk->GetLoadedArsc();
- ASSERT_NE(nullptr, loaded_arsc);
- ASSERT_EQ(1u, loaded_arsc->GetPackages().size());
+ ASSERT_THAT(loaded_arsc, NotNull());
+ ASSERT_THAT(loaded_arsc->GetPackages(), SizeIs(1u));
EXPECT_TRUE(loaded_arsc->GetPackages()[0]->IsDynamic());
}
@@ -86,19 +84,22 @@
ResTable target_table;
const std::string target_path = GetTestDataPath() + "/basic/basic.apk";
ASSERT_TRUE(ReadFileFromZipToString(target_path, "resources.arsc", &contents));
- ASSERT_EQ(NO_ERROR, target_table.add(contents.data(), contents.size(), 0, true /*copyData*/));
+ ASSERT_THAT(target_table.add(contents.data(), contents.size(), 0, true /*copyData*/),
+ Eq(NO_ERROR));
ResTable overlay_table;
const std::string overlay_path = GetTestDataPath() + "/overlay/overlay.apk";
ASSERT_TRUE(ReadFileFromZipToString(overlay_path, "resources.arsc", &contents));
- ASSERT_EQ(NO_ERROR, overlay_table.add(contents.data(), contents.size(), 0, true /*copyData*/));
+ ASSERT_THAT(overlay_table.add(contents.data(), contents.size(), 0, true /*copyData*/),
+ Eq(NO_ERROR));
util::unique_cptr<void> idmap_data;
void* temp_data;
size_t idmap_len;
- ASSERT_EQ(NO_ERROR, target_table.createIdmap(overlay_table, 0u, 0u, target_path.c_str(),
- overlay_path.c_str(), &temp_data, &idmap_len));
+ ASSERT_THAT(target_table.createIdmap(overlay_table, 0u, 0u, target_path.c_str(),
+ overlay_path.c_str(), &temp_data, &idmap_len),
+ Eq(NO_ERROR));
idmap_data.reset(temp_data);
TemporaryFile tf;
@@ -108,37 +109,30 @@
// Open something so that the destructor of TemporaryFile closes a valid fd.
tf.fd = open("/dev/null", O_WRONLY);
- std::unique_ptr<const ApkAssets> loaded_overlay_apk = ApkAssets::LoadOverlay(tf.path);
- ASSERT_NE(nullptr, loaded_overlay_apk);
+ ASSERT_THAT(ApkAssets::LoadOverlay(tf.path), NotNull());
}
TEST(ApkAssetsTest, CreateAndDestroyAssetKeepsApkAssetsOpen) {
std::unique_ptr<const ApkAssets> loaded_apk =
ApkAssets::Load(GetTestDataPath() + "/basic/basic.apk");
- ASSERT_NE(nullptr, loaded_apk);
+ ASSERT_THAT(loaded_apk, NotNull());
- {
- std::unique_ptr<Asset> assets = loaded_apk->Open("res/layout/main.xml", Asset::ACCESS_BUFFER);
- ASSERT_NE(nullptr, assets);
- }
+ { ASSERT_THAT(loaded_apk->Open("res/layout/main.xml", Asset::ACCESS_BUFFER), NotNull()); }
- {
- std::unique_ptr<Asset> assets = loaded_apk->Open("res/layout/main.xml", Asset::ACCESS_BUFFER);
- ASSERT_NE(nullptr, assets);
- }
+ { ASSERT_THAT(loaded_apk->Open("res/layout/main.xml", Asset::ACCESS_BUFFER), NotNull()); }
}
TEST(ApkAssetsTest, OpenUncompressedAssetFd) {
std::unique_ptr<const ApkAssets> loaded_apk =
ApkAssets::Load(GetTestDataPath() + "/basic/basic.apk");
- ASSERT_NE(nullptr, loaded_apk);
+ ASSERT_THAT(loaded_apk, NotNull());
auto asset = loaded_apk->Open("assets/uncompressed.txt", Asset::ACCESS_UNKNOWN);
- ASSERT_NE(nullptr, asset);
+ ASSERT_THAT(asset, NotNull());
off64_t start, length;
unique_fd fd(asset->openFileDescriptor(&start, &length));
- EXPECT_GE(fd.get(), 0);
+ ASSERT_THAT(fd.get(), Ge(0));
lseek64(fd.get(), start, SEEK_SET);
@@ -146,7 +140,7 @@
buffer.resize(length);
ASSERT_TRUE(base::ReadFully(fd.get(), &*buffer.begin(), length));
- EXPECT_EQ("This should be uncompressed.\n\n", buffer);
+ EXPECT_THAT(buffer, StrEq("This should be uncompressed.\n\n"));
}
} // namespace android
diff --git a/libs/androidfw/tests/AssetManager2_bench.cpp b/libs/androidfw/tests/AssetManager2_bench.cpp
index 85e8f25..437e147 100644
--- a/libs/androidfw/tests/AssetManager2_bench.cpp
+++ b/libs/androidfw/tests/AssetManager2_bench.cpp
@@ -81,17 +81,18 @@
}
BENCHMARK(BM_AssetManagerLoadFrameworkAssetsOld);
-static void BM_AssetManagerGetResource(benchmark::State& state) {
- GetResourceBenchmark({GetTestDataPath() + "/basic/basic.apk"}, nullptr /*config*/,
- basic::R::integer::number1, state);
+static void BM_AssetManagerGetResource(benchmark::State& state, uint32_t resid) {
+ GetResourceBenchmark({GetTestDataPath() + "/basic/basic.apk"}, nullptr /*config*/, resid, state);
}
-BENCHMARK(BM_AssetManagerGetResource);
+BENCHMARK_CAPTURE(BM_AssetManagerGetResource, number1, basic::R::integer::number1);
+BENCHMARK_CAPTURE(BM_AssetManagerGetResource, deep_ref, basic::R::integer::deep_ref);
-static void BM_AssetManagerGetResourceOld(benchmark::State& state) {
- GetResourceBenchmarkOld({GetTestDataPath() + "/basic/basic.apk"}, nullptr /*config*/,
- basic::R::integer::number1, state);
+static void BM_AssetManagerGetResourceOld(benchmark::State& state, uint32_t resid) {
+ GetResourceBenchmarkOld({GetTestDataPath() + "/basic/basic.apk"}, nullptr /*config*/, resid,
+ state);
}
-BENCHMARK(BM_AssetManagerGetResourceOld);
+BENCHMARK_CAPTURE(BM_AssetManagerGetResourceOld, number1, basic::R::integer::number1);
+BENCHMARK_CAPTURE(BM_AssetManagerGetResourceOld, deep_ref, basic::R::integer::deep_ref);
static void BM_AssetManagerGetLibraryResource(benchmark::State& state) {
GetResourceBenchmark(
@@ -196,7 +197,7 @@
static void BM_AssetManagerGetResourceLocalesOld(benchmark::State& state) {
AssetManager assets;
if (!assets.addAssetPath(String8(kFrameworkPath), nullptr /*cookie*/, false /*appAsLib*/,
- false /*isSystemAssets*/)) {
+ true /*isSystemAssets*/)) {
state.SkipWithError("Failed to load assets");
return;
}
@@ -211,4 +212,44 @@
}
BENCHMARK(BM_AssetManagerGetResourceLocalesOld);
+static void BM_AssetManagerSetConfigurationFramework(benchmark::State& state) {
+ std::unique_ptr<const ApkAssets> apk = ApkAssets::Load(kFrameworkPath);
+ if (apk == nullptr) {
+ state.SkipWithError("Failed to load assets");
+ return;
+ }
+
+ AssetManager2 assets;
+ assets.SetApkAssets({apk.get()});
+
+ ResTable_config config;
+ memset(&config, 0, sizeof(config));
+
+ while (state.KeepRunning()) {
+ config.sdkVersion = ~config.sdkVersion;
+ assets.SetConfiguration(config);
+ }
+}
+BENCHMARK(BM_AssetManagerSetConfigurationFramework);
+
+static void BM_AssetManagerSetConfigurationFrameworkOld(benchmark::State& state) {
+ AssetManager assets;
+ if (!assets.addAssetPath(String8(kFrameworkPath), nullptr /*cookie*/, false /*appAsLib*/,
+ true /*isSystemAssets*/)) {
+ state.SkipWithError("Failed to load assets");
+ return;
+ }
+
+ const ResTable& table = assets.getResources(true);
+
+ ResTable_config config;
+ memset(&config, 0, sizeof(config));
+
+ while (state.KeepRunning()) {
+ config.sdkVersion = ~config.sdkVersion;
+ assets.setConfiguration(config);
+ }
+}
+BENCHMARK(BM_AssetManagerSetConfigurationFrameworkOld);
+
} // namespace android
diff --git a/libs/androidfw/tests/AssetManager2_test.cpp b/libs/androidfw/tests/AssetManager2_test.cpp
index 92462a6..7cac2b3 100644
--- a/libs/androidfw/tests/AssetManager2_test.cpp
+++ b/libs/androidfw/tests/AssetManager2_test.cpp
@@ -36,6 +36,10 @@
namespace lib_two = com::android::lib_two;
namespace libclient = com::android::libclient;
+using ::testing::Eq;
+using ::testing::NotNull;
+using ::testing::StrEq;
+
namespace android {
class AssetManager2Test : public ::testing::Test {
@@ -59,11 +63,14 @@
libclient_assets_ = ApkAssets::Load(GetTestDataPath() + "/libclient/libclient.apk");
ASSERT_NE(nullptr, libclient_assets_);
- appaslib_assets_ = ApkAssets::Load(GetTestDataPath() + "/appaslib/appaslib.apk");
+ appaslib_assets_ = ApkAssets::LoadAsSharedLibrary(GetTestDataPath() + "/appaslib/appaslib.apk");
ASSERT_NE(nullptr, appaslib_assets_);
system_assets_ = ApkAssets::Load(GetTestDataPath() + "/system/system.apk", true /*system*/);
ASSERT_NE(nullptr, system_assets_);
+
+ app_assets_ = ApkAssets::Load(GetTestDataPath() + "/app/app.apk");
+ ASSERT_THAT(app_assets_, NotNull());
}
protected:
@@ -75,6 +82,7 @@
std::unique_ptr<const ApkAssets> libclient_assets_;
std::unique_ptr<const ApkAssets> appaslib_assets_;
std::unique_ptr<const ApkAssets> system_assets_;
+ std::unique_ptr<const ApkAssets> app_assets_;
};
TEST_F(AssetManager2Test, FindsResourceFromSingleApkAssets) {
@@ -233,6 +241,25 @@
assetmanager.SetApkAssets(
{lib_two_assets_.get(), lib_one_assets_.get(), libclient_assets_.get()});
+ const ResolvedBag* bag = assetmanager.GetBag(fix_package_id(lib_one::R::style::Theme, 0x03));
+ ASSERT_NE(nullptr, bag);
+ ASSERT_GE(bag->entry_count, 2u);
+
+ // First two attributes come from lib_one.
+ EXPECT_EQ(1, bag->entries[0].cookie);
+ EXPECT_EQ(0x03, get_package_id(bag->entries[0].key));
+ EXPECT_EQ(1, bag->entries[1].cookie);
+ EXPECT_EQ(0x03, get_package_id(bag->entries[1].key));
+}
+
+TEST_F(AssetManager2Test, FindsStyleResourceWithParentFromSharedLibrary) {
+ AssetManager2 assetmanager;
+
+ // libclient is built with lib_one and then lib_two in order.
+ // Reverse the order to test that proper package ID re-assignment is happening.
+ assetmanager.SetApkAssets(
+ {lib_two_assets_.get(), lib_one_assets_.get(), libclient_assets_.get()});
+
const ResolvedBag* bag = assetmanager.GetBag(libclient::R::style::Theme);
ASSERT_NE(nullptr, bag);
ASSERT_GE(bag->entry_count, 2u);
@@ -446,8 +473,68 @@
assetmanager.GetResourceId("main", "layout", "com.android.basic"));
}
-TEST_F(AssetManager2Test, OpensFileFromSingleApkAssets) {}
+TEST_F(AssetManager2Test, OpensFileFromSingleApkAssets) {
+ AssetManager2 assetmanager;
+ assetmanager.SetApkAssets({system_assets_.get()});
-TEST_F(AssetManager2Test, OpensFileFromMultipleApkAssets) {}
+ std::unique_ptr<Asset> asset = assetmanager.Open("file.txt", Asset::ACCESS_BUFFER);
+ ASSERT_THAT(asset, NotNull());
+
+ const char* data = reinterpret_cast<const char*>(asset->getBuffer(false /*wordAligned*/));
+ ASSERT_THAT(data, NotNull());
+ EXPECT_THAT(std::string(data, asset->getLength()), StrEq("file\n"));
+}
+
+TEST_F(AssetManager2Test, OpensFileFromMultipleApkAssets) {
+ AssetManager2 assetmanager;
+ assetmanager.SetApkAssets({system_assets_.get(), app_assets_.get()});
+
+ std::unique_ptr<Asset> asset = assetmanager.Open("file.txt", Asset::ACCESS_BUFFER);
+ ASSERT_THAT(asset, NotNull());
+
+ const char* data = reinterpret_cast<const char*>(asset->getBuffer(false /*wordAligned*/));
+ ASSERT_THAT(data, NotNull());
+ EXPECT_THAT(std::string(data, asset->getLength()), StrEq("app override file\n"));
+}
+
+TEST_F(AssetManager2Test, OpenDir) {
+ AssetManager2 assetmanager;
+ assetmanager.SetApkAssets({system_assets_.get()});
+
+ std::unique_ptr<AssetDir> asset_dir = assetmanager.OpenDir("");
+ ASSERT_THAT(asset_dir, NotNull());
+ ASSERT_THAT(asset_dir->getFileCount(), Eq(2u));
+
+ EXPECT_THAT(asset_dir->getFileName(0), Eq(String8("file.txt")));
+ EXPECT_THAT(asset_dir->getFileType(0), Eq(FileType::kFileTypeRegular));
+
+ EXPECT_THAT(asset_dir->getFileName(1), Eq(String8("subdir")));
+ EXPECT_THAT(asset_dir->getFileType(1), Eq(FileType::kFileTypeDirectory));
+
+ asset_dir = assetmanager.OpenDir("subdir");
+ ASSERT_THAT(asset_dir, NotNull());
+ ASSERT_THAT(asset_dir->getFileCount(), Eq(1u));
+
+ EXPECT_THAT(asset_dir->getFileName(0), Eq(String8("subdir_file.txt")));
+ EXPECT_THAT(asset_dir->getFileType(0), Eq(FileType::kFileTypeRegular));
+}
+
+TEST_F(AssetManager2Test, OpenDirFromManyApks) {
+ AssetManager2 assetmanager;
+ assetmanager.SetApkAssets({system_assets_.get(), app_assets_.get()});
+
+ std::unique_ptr<AssetDir> asset_dir = assetmanager.OpenDir("");
+ ASSERT_THAT(asset_dir, NotNull());
+ ASSERT_THAT(asset_dir->getFileCount(), Eq(3u));
+
+ EXPECT_THAT(asset_dir->getFileName(0), Eq(String8("app_file.txt")));
+ EXPECT_THAT(asset_dir->getFileType(0), Eq(FileType::kFileTypeRegular));
+
+ EXPECT_THAT(asset_dir->getFileName(1), Eq(String8("file.txt")));
+ EXPECT_THAT(asset_dir->getFileType(1), Eq(FileType::kFileTypeRegular));
+
+ EXPECT_THAT(asset_dir->getFileName(2), Eq(String8("subdir")));
+ EXPECT_THAT(asset_dir->getFileType(2), Eq(FileType::kFileTypeDirectory));
+}
} // namespace android
diff --git a/libs/androidfw/tests/AttributeResolution_bench.cpp b/libs/androidfw/tests/AttributeResolution_bench.cpp
new file mode 100644
index 0000000..fa300c5
--- /dev/null
+++ b/libs/androidfw/tests/AttributeResolution_bench.cpp
@@ -0,0 +1,175 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "benchmark/benchmark.h"
+
+//#include "android-base/stringprintf.h"
+#include "androidfw/ApkAssets.h"
+#include "androidfw/AssetManager.h"
+#include "androidfw/AssetManager2.h"
+#include "androidfw/AttributeResolution.h"
+#include "androidfw/ResourceTypes.h"
+
+#include "BenchmarkHelpers.h"
+#include "data/basic/R.h"
+#include "data/styles/R.h"
+
+namespace app = com::android::app;
+namespace basic = com::android::basic;
+
+namespace android {
+
+constexpr const static char* kFrameworkPath = "/system/framework/framework-res.apk";
+constexpr const static uint32_t Theme_Material_Light = 0x01030237u;
+
+static void BM_ApplyStyle(benchmark::State& state) {
+ std::unique_ptr<const ApkAssets> styles_apk =
+ ApkAssets::Load(GetTestDataPath() + "/styles/styles.apk");
+ if (styles_apk == nullptr) {
+ state.SkipWithError("failed to load assets");
+ return;
+ }
+
+ AssetManager2 assetmanager;
+ assetmanager.SetApkAssets({styles_apk.get()});
+
+ std::unique_ptr<Asset> asset =
+ assetmanager.OpenNonAsset("res/layout/layout.xml", Asset::ACCESS_BUFFER);
+ if (asset == nullptr) {
+ state.SkipWithError("failed to load layout");
+ return;
+ }
+
+ ResXMLTree xml_tree;
+ if (xml_tree.setTo(asset->getBuffer(true), asset->getLength(), false /*copyData*/) != NO_ERROR) {
+ state.SkipWithError("corrupt xml layout");
+ return;
+ }
+
+ // Skip to the first tag.
+ while (xml_tree.next() != ResXMLParser::START_TAG) {
+ }
+
+ std::unique_ptr<Theme> theme = assetmanager.NewTheme();
+ theme->ApplyStyle(app::R::style::StyleTwo);
+
+ std::array<uint32_t, 6> attrs{{app::R::attr::attr_one, app::R::attr::attr_two,
+ app::R::attr::attr_three, app::R::attr::attr_four,
+ app::R::attr::attr_five, app::R::attr::attr_empty}};
+ std::array<uint32_t, attrs.size() * STYLE_NUM_ENTRIES> values;
+ std::array<uint32_t, attrs.size() + 1> indices;
+
+ while (state.KeepRunning()) {
+ ApplyStyle(theme.get(), &xml_tree, 0u /*def_style_attr*/, 0u /*def_style_res*/, attrs.data(),
+ attrs.size(), values.data(), indices.data());
+ }
+}
+BENCHMARK(BM_ApplyStyle);
+
+static void BM_ApplyStyleFramework(benchmark::State& state) {
+ std::unique_ptr<const ApkAssets> framework_apk = ApkAssets::Load(kFrameworkPath);
+ if (framework_apk == nullptr) {
+ state.SkipWithError("failed to load framework assets");
+ return;
+ }
+
+ std::unique_ptr<const ApkAssets> basic_apk =
+ ApkAssets::Load(GetTestDataPath() + "/basic/basic.apk");
+ if (basic_apk == nullptr) {
+ state.SkipWithError("failed to load assets");
+ return;
+ }
+
+ AssetManager2 assetmanager;
+ assetmanager.SetApkAssets({framework_apk.get(), basic_apk.get()});
+
+ ResTable_config device_config;
+ memset(&device_config, 0, sizeof(device_config));
+ device_config.language[0] = 'e';
+ device_config.language[1] = 'n';
+ device_config.country[0] = 'U';
+ device_config.country[1] = 'S';
+ device_config.orientation = ResTable_config::ORIENTATION_PORT;
+ device_config.smallestScreenWidthDp = 700;
+ device_config.screenWidthDp = 700;
+ device_config.screenHeightDp = 1024;
+ device_config.sdkVersion = 27;
+
+ Res_value value;
+ ResTable_config config;
+ uint32_t flags = 0u;
+ ApkAssetsCookie cookie =
+ assetmanager.GetResource(basic::R::layout::layoutt, false /*may_be_bag*/,
+ 0u /*density_override*/, &value, &config, &flags);
+ if (cookie == kInvalidCookie) {
+ state.SkipWithError("failed to find R.layout.layout");
+ return;
+ }
+
+ size_t len = 0u;
+ const char* layout_path =
+ assetmanager.GetStringPoolForCookie(cookie)->string8At(value.data, &len);
+ if (layout_path == nullptr || len == 0u) {
+ state.SkipWithError("failed to lookup layout path");
+ return;
+ }
+
+ std::unique_ptr<Asset> asset = assetmanager.OpenNonAsset(
+ StringPiece(layout_path, len).to_string(), cookie, Asset::ACCESS_BUFFER);
+ if (asset == nullptr) {
+ state.SkipWithError("failed to load layout");
+ return;
+ }
+
+ ResXMLTree xml_tree;
+ if (xml_tree.setTo(asset->getBuffer(true), asset->getLength(), false /*copyData*/) != NO_ERROR) {
+ state.SkipWithError("corrupt xml layout");
+ return;
+ }
+
+ // Skip to the first tag.
+ while (xml_tree.next() != ResXMLParser::START_TAG) {
+ }
+
+ std::unique_ptr<Theme> theme = assetmanager.NewTheme();
+ theme->ApplyStyle(Theme_Material_Light);
+
+ std::array<uint32_t, 92> attrs{
+ {0x0101000e, 0x01010034, 0x01010095, 0x01010096, 0x01010097, 0x01010098, 0x01010099,
+ 0x0101009a, 0x0101009b, 0x010100ab, 0x010100af, 0x010100b0, 0x010100b1, 0x0101011f,
+ 0x01010120, 0x0101013f, 0x01010140, 0x0101014e, 0x0101014f, 0x01010150, 0x01010151,
+ 0x01010152, 0x01010153, 0x01010154, 0x01010155, 0x01010156, 0x01010157, 0x01010158,
+ 0x01010159, 0x0101015a, 0x0101015b, 0x0101015c, 0x0101015d, 0x0101015e, 0x0101015f,
+ 0x01010160, 0x01010161, 0x01010162, 0x01010163, 0x01010164, 0x01010165, 0x01010166,
+ 0x01010167, 0x01010168, 0x01010169, 0x0101016a, 0x0101016b, 0x0101016c, 0x0101016d,
+ 0x0101016e, 0x0101016f, 0x01010170, 0x01010171, 0x01010217, 0x01010218, 0x0101021d,
+ 0x01010220, 0x01010223, 0x01010224, 0x01010264, 0x01010265, 0x01010266, 0x010102c5,
+ 0x010102c6, 0x010102c7, 0x01010314, 0x01010315, 0x01010316, 0x0101035e, 0x0101035f,
+ 0x01010362, 0x01010374, 0x0101038c, 0x01010392, 0x01010393, 0x010103ac, 0x0101045d,
+ 0x010104b6, 0x010104b7, 0x010104d6, 0x010104d7, 0x010104dd, 0x010104de, 0x010104df,
+ 0x01010535, 0x01010536, 0x01010537, 0x01010538, 0x01010546, 0x01010567, 0x011100c9,
+ 0x011100ca}};
+
+ std::array<uint32_t, attrs.size() * STYLE_NUM_ENTRIES> values;
+ std::array<uint32_t, attrs.size() + 1> indices;
+ while (state.KeepRunning()) {
+ ApplyStyle(theme.get(), &xml_tree, 0x01010084u /*def_style_attr*/, 0u /*def_style_res*/,
+ attrs.data(), attrs.size(), values.data(), indices.data());
+ }
+}
+BENCHMARK(BM_ApplyStyleFramework);
+
+} // namespace android
diff --git a/libs/androidfw/tests/AttributeResolution_test.cpp b/libs/androidfw/tests/AttributeResolution_test.cpp
index 2d73ce8..c8dbe20 100644
--- a/libs/androidfw/tests/AttributeResolution_test.cpp
+++ b/libs/androidfw/tests/AttributeResolution_test.cpp
@@ -21,6 +21,8 @@
#include "android-base/file.h"
#include "android-base/logging.h"
#include "android-base/macros.h"
+#include "androidfw/AssetManager2.h"
+#include "androidfw/ResourceUtils.h"
#include "TestHelpers.h"
#include "data/styles/R.h"
@@ -32,15 +34,14 @@
class AttributeResolutionTest : public ::testing::Test {
public:
virtual void SetUp() override {
- std::string contents;
- ASSERT_TRUE(ReadFileFromZipToString(
- GetTestDataPath() + "/styles/styles.apk", "resources.arsc", &contents));
- ASSERT_EQ(NO_ERROR, table_.add(contents.data(), contents.size(),
- 1 /*cookie*/, true /*copyData*/));
+ styles_assets_ = ApkAssets::Load(GetTestDataPath() + "/styles/styles.apk");
+ ASSERT_NE(nullptr, styles_assets_);
+ assetmanager_.SetApkAssets({styles_assets_.get()});
}
protected:
- ResTable table_;
+ std::unique_ptr<const ApkAssets> styles_assets_;
+ AssetManager2 assetmanager_;
};
class AttributeResolutionXmlTest : public AttributeResolutionTest {
@@ -48,13 +49,12 @@
virtual void SetUp() override {
AttributeResolutionTest::SetUp();
- std::string contents;
- ASSERT_TRUE(
- ReadFileFromZipToString(GetTestDataPath() + "/styles/styles.apk",
- "res/layout/layout.xml", &contents));
+ std::unique_ptr<Asset> asset =
+ assetmanager_.OpenNonAsset("res/layout/layout.xml", Asset::ACCESS_BUFFER);
+ ASSERT_NE(nullptr, asset);
- ASSERT_EQ(NO_ERROR, xml_parser_.setTo(contents.data(), contents.size(),
- true /*copyData*/));
+ ASSERT_EQ(NO_ERROR,
+ xml_parser_.setTo(asset->getBuffer(true), asset->getLength(), true /*copyData*/));
// Skip to the first tag.
while (xml_parser_.next() != ResXMLParser::START_TAG) {
@@ -65,15 +65,50 @@
ResXMLTree xml_parser_;
};
+TEST(AttributeResolutionLibraryTest, ApplyStyleWithDefaultStyleResId) {
+ AssetManager2 assetmanager;
+ auto apk_assets = ApkAssets::LoadAsSharedLibrary(GetTestDataPath() + "/styles/styles.apk");
+ ASSERT_NE(nullptr, apk_assets);
+ assetmanager.SetApkAssets({apk_assets.get()});
+
+ std::unique_ptr<Theme> theme = assetmanager.NewTheme();
+
+ std::array<uint32_t, 2> attrs{
+ {fix_package_id(R::attr::attr_one, 0x02), fix_package_id(R::attr::attr_two, 0x02)}};
+ std::array<uint32_t, attrs.size() * STYLE_NUM_ENTRIES> values;
+ std::array<uint32_t, attrs.size() + 1> indices;
+ ApplyStyle(theme.get(), nullptr /*xml_parser*/, 0u /*def_style_attr*/,
+ fix_package_id(R::style::StyleOne, 0x02), attrs.data(), attrs.size(), values.data(),
+ indices.data());
+
+ const uint32_t public_flag = ResTable_typeSpec::SPEC_PUBLIC;
+
+ const uint32_t* values_cursor = values.data();
+ EXPECT_EQ(Res_value::TYPE_INT_DEC, values_cursor[STYLE_TYPE]);
+ EXPECT_EQ(1u, values_cursor[STYLE_DATA]);
+ EXPECT_EQ(0u, values_cursor[STYLE_RESOURCE_ID]);
+ EXPECT_EQ(1u, values_cursor[STYLE_ASSET_COOKIE]);
+ EXPECT_EQ(0u, values_cursor[STYLE_DENSITY]);
+ EXPECT_EQ(public_flag, values_cursor[STYLE_CHANGING_CONFIGURATIONS]);
+
+ values_cursor += STYLE_NUM_ENTRIES;
+ EXPECT_EQ(Res_value::TYPE_INT_DEC, values_cursor[STYLE_TYPE]);
+ EXPECT_EQ(2u, values_cursor[STYLE_DATA]);
+ EXPECT_EQ(0u, values_cursor[STYLE_RESOURCE_ID]);
+ EXPECT_EQ(1u, values_cursor[STYLE_ASSET_COOKIE]);
+ EXPECT_EQ(0u, values_cursor[STYLE_DENSITY]);
+ EXPECT_EQ(public_flag, values_cursor[STYLE_CHANGING_CONFIGURATIONS]);
+}
+
TEST_F(AttributeResolutionTest, Theme) {
- ResTable::Theme theme(table_);
- ASSERT_EQ(NO_ERROR, theme.applyStyle(R::style::StyleTwo));
+ std::unique_ptr<Theme> theme = assetmanager_.NewTheme();
+ ASSERT_TRUE(theme->ApplyStyle(R::style::StyleTwo));
std::array<uint32_t, 5> attrs{{R::attr::attr_one, R::attr::attr_two, R::attr::attr_three,
R::attr::attr_four, R::attr::attr_empty}};
std::array<uint32_t, attrs.size() * STYLE_NUM_ENTRIES> values;
- ASSERT_TRUE(ResolveAttrs(&theme, 0 /*def_style_attr*/, 0 /*def_style_res*/,
+ ASSERT_TRUE(ResolveAttrs(theme.get(), 0u /*def_style_attr*/, 0u /*def_style_res*/,
nullptr /*src_values*/, 0 /*src_values_length*/, attrs.data(),
attrs.size(), values.data(), nullptr /*out_indices*/));
@@ -126,8 +161,8 @@
R::attr::attr_four, R::attr::attr_empty}};
std::array<uint32_t, attrs.size() * STYLE_NUM_ENTRIES> values;
- ASSERT_TRUE(RetrieveAttributes(&table_, &xml_parser_, attrs.data(), attrs.size(), values.data(),
- nullptr /*out_indices*/));
+ ASSERT_TRUE(RetrieveAttributes(&assetmanager_, &xml_parser_, attrs.data(), attrs.size(),
+ values.data(), nullptr /*out_indices*/));
uint32_t* values_cursor = values.data();
EXPECT_EQ(Res_value::TYPE_NULL, values_cursor[STYLE_TYPE]);
@@ -171,15 +206,15 @@
}
TEST_F(AttributeResolutionXmlTest, ThemeAndXmlParser) {
- ResTable::Theme theme(table_);
- ASSERT_EQ(NO_ERROR, theme.applyStyle(R::style::StyleTwo));
+ std::unique_ptr<Theme> theme = assetmanager_.NewTheme();
+ ASSERT_TRUE(theme->ApplyStyle(R::style::StyleTwo));
std::array<uint32_t, 6> attrs{{R::attr::attr_one, R::attr::attr_two, R::attr::attr_three,
R::attr::attr_four, R::attr::attr_five, R::attr::attr_empty}};
std::array<uint32_t, attrs.size() * STYLE_NUM_ENTRIES> values;
std::array<uint32_t, attrs.size() + 1> indices;
- ApplyStyle(&theme, &xml_parser_, 0 /*def_style_attr*/, 0 /*def_style_res*/, attrs.data(),
+ ApplyStyle(theme.get(), &xml_parser_, 0u /*def_style_attr*/, 0u /*def_style_res*/, attrs.data(),
attrs.size(), values.data(), indices.data());
const uint32_t public_flag = ResTable_typeSpec::SPEC_PUBLIC;
diff --git a/libs/androidfw/tests/BenchmarkHelpers.cpp b/libs/androidfw/tests/BenchmarkHelpers.cpp
index 7149bee..faddfe5 100644
--- a/libs/androidfw/tests/BenchmarkHelpers.cpp
+++ b/libs/androidfw/tests/BenchmarkHelpers.cpp
@@ -33,19 +33,21 @@
}
}
+ // Make sure to force creation of the ResTable first, or else the configuration doesn't get set.
+ const ResTable& table = assetmanager.getResources(true);
if (config != nullptr) {
assetmanager.setConfiguration(*config);
}
- const ResTable& table = assetmanager.getResources(true);
-
Res_value value;
ResTable_config selected_config;
uint32_t flags;
+ uint32_t last_ref = 0u;
while (state.KeepRunning()) {
- table.getResource(resid, &value, false /*may_be_bag*/, 0u /*density*/, &flags,
- &selected_config);
+ ssize_t block = table.getResource(resid, &value, false /*may_be_bag*/, 0u /*density*/, &flags,
+ &selected_config);
+ table.resolveReference(&value, block, &last_ref, &flags, &selected_config);
}
}
@@ -72,10 +74,12 @@
Res_value value;
ResTable_config selected_config;
uint32_t flags;
+ uint32_t last_id = 0u;
while (state.KeepRunning()) {
- assetmanager.GetResource(resid, false /* may_be_bag */, 0u /* density_override */, &value,
- &selected_config, &flags);
+ ApkAssetsCookie cookie = assetmanager.GetResource(
+ resid, false /* may_be_bag */, 0u /* density_override */, &value, &selected_config, &flags);
+ assetmanager.ResolveReference(cookie, &value, &selected_config, &flags, &last_id);
}
}
diff --git a/libs/androidfw/tests/LoadedArsc_test.cpp b/libs/androidfw/tests/LoadedArsc_test.cpp
index 37ddafb..cae632d 100644
--- a/libs/androidfw/tests/LoadedArsc_test.cpp
+++ b/libs/androidfw/tests/LoadedArsc_test.cpp
@@ -16,6 +16,9 @@
#include "androidfw/LoadedArsc.h"
+#include "android-base/file.h"
+#include "androidfw/ResourceUtils.h"
+
#include "TestHelpers.h"
#include "data/basic/R.h"
#include "data/libclient/R.h"
@@ -27,6 +30,14 @@
namespace libclient = com::android::libclient;
namespace sparse = com::android::sparse;
+using ::android::base::ReadFileToString;
+using ::testing::Eq;
+using ::testing::Ge;
+using ::testing::IsNull;
+using ::testing::NotNull;
+using ::testing::SizeIs;
+using ::testing::StrEq;
+
namespace android {
TEST(LoadedArscTest, LoadSinglePackageArsc) {
@@ -35,39 +46,24 @@
&contents));
std::unique_ptr<const LoadedArsc> loaded_arsc = LoadedArsc::Load(StringPiece(contents));
- ASSERT_NE(nullptr, loaded_arsc);
+ ASSERT_THAT(loaded_arsc, NotNull());
- const std::vector<std::unique_ptr<const LoadedPackage>>& packages = loaded_arsc->GetPackages();
- ASSERT_EQ(1u, packages.size());
- EXPECT_EQ(std::string("com.android.app"), packages[0]->GetPackageName());
- EXPECT_EQ(0x7f, packages[0]->GetPackageId());
+ const LoadedPackage* package =
+ loaded_arsc->GetPackageById(get_package_id(app::R::string::string_one));
+ ASSERT_THAT(package, NotNull());
+ EXPECT_THAT(package->GetPackageName(), StrEq("com.android.app"));
+ EXPECT_THAT(package->GetPackageId(), Eq(0x7f));
- ResTable_config config;
- memset(&config, 0, sizeof(config));
- config.sdkVersion = 24;
+ const uint8_t type_index = get_type_id(app::R::string::string_one) - 1;
+ const uint16_t entry_index = get_entry_id(app::R::string::string_one);
- FindEntryResult entry;
+ const TypeSpec* type_spec = package->GetTypeSpecByTypeIndex(type_index);
+ ASSERT_THAT(type_spec, NotNull());
+ ASSERT_THAT(type_spec->type_count, Ge(1u));
- ASSERT_TRUE(loaded_arsc->FindEntry(app::R::string::string_one, config, &entry));
- ASSERT_NE(nullptr, entry.entry);
-}
-
-TEST(LoadedArscTest, FindDefaultEntry) {
- std::string contents;
- ASSERT_TRUE(
- ReadFileFromZipToString(GetTestDataPath() + "/basic/basic.apk", "resources.arsc", &contents));
-
- std::unique_ptr<const LoadedArsc> loaded_arsc = LoadedArsc::Load(StringPiece(contents));
- ASSERT_NE(nullptr, loaded_arsc);
-
- ResTable_config desired_config;
- memset(&desired_config, 0, sizeof(desired_config));
- desired_config.language[0] = 'd';
- desired_config.language[1] = 'e';
-
- FindEntryResult entry;
- ASSERT_TRUE(loaded_arsc->FindEntry(basic::R::string::test1, desired_config, &entry));
- ASSERT_NE(nullptr, entry.entry);
+ const ResTable_type* type = type_spec->types[0];
+ ASSERT_THAT(type, NotNull());
+ ASSERT_THAT(LoadedPackage::GetEntry(type, entry_index), NotNull());
}
TEST(LoadedArscTest, LoadSparseEntryApp) {
@@ -76,15 +72,22 @@
&contents));
std::unique_ptr<const LoadedArsc> loaded_arsc = LoadedArsc::Load(StringPiece(contents));
- ASSERT_NE(nullptr, loaded_arsc);
+ ASSERT_THAT(loaded_arsc, NotNull());
- ResTable_config config;
- memset(&config, 0, sizeof(config));
- config.sdkVersion = 26;
+ const LoadedPackage* package =
+ loaded_arsc->GetPackageById(get_package_id(sparse::R::integer::foo_9));
+ ASSERT_THAT(package, NotNull());
- FindEntryResult entry;
- ASSERT_TRUE(loaded_arsc->FindEntry(sparse::R::integer::foo_9, config, &entry));
- ASSERT_NE(nullptr, entry.entry);
+ const uint8_t type_index = get_type_id(sparse::R::integer::foo_9) - 1;
+ const uint16_t entry_index = get_entry_id(sparse::R::integer::foo_9);
+
+ const TypeSpec* type_spec = package->GetTypeSpecByTypeIndex(type_index);
+ ASSERT_THAT(type_spec, NotNull());
+ ASSERT_THAT(type_spec->type_count, Ge(1u));
+
+ const ResTable_type* type = type_spec->types[0];
+ ASSERT_THAT(type, NotNull());
+ ASSERT_THAT(LoadedPackage::GetEntry(type, entry_index), NotNull());
}
TEST(LoadedArscTest, LoadSharedLibrary) {
@@ -93,14 +96,13 @@
&contents));
std::unique_ptr<const LoadedArsc> loaded_arsc = LoadedArsc::Load(StringPiece(contents));
- ASSERT_NE(nullptr, loaded_arsc);
+ ASSERT_THAT(loaded_arsc, NotNull());
const auto& packages = loaded_arsc->GetPackages();
- ASSERT_EQ(1u, packages.size());
-
+ ASSERT_THAT(packages, SizeIs(1u));
EXPECT_TRUE(packages[0]->IsDynamic());
- EXPECT_EQ(std::string("com.android.lib_one"), packages[0]->GetPackageName());
- EXPECT_EQ(0, packages[0]->GetPackageId());
+ EXPECT_THAT(packages[0]->GetPackageName(), StrEq("com.android.lib_one"));
+ EXPECT_THAT(packages[0]->GetPackageId(), Eq(0));
const auto& dynamic_pkg_map = packages[0]->GetDynamicPackageMap();
@@ -114,25 +116,23 @@
"resources.arsc", &contents));
std::unique_ptr<const LoadedArsc> loaded_arsc = LoadedArsc::Load(StringPiece(contents));
- ASSERT_NE(nullptr, loaded_arsc);
+ ASSERT_THAT(loaded_arsc, NotNull());
const auto& packages = loaded_arsc->GetPackages();
- ASSERT_EQ(1u, packages.size());
-
+ ASSERT_THAT(packages, SizeIs(1u));
EXPECT_FALSE(packages[0]->IsDynamic());
- EXPECT_EQ(std::string("com.android.libclient"), packages[0]->GetPackageName());
- EXPECT_EQ(0x7f, packages[0]->GetPackageId());
+ EXPECT_THAT(packages[0]->GetPackageName(), StrEq("com.android.libclient"));
+ EXPECT_THAT(packages[0]->GetPackageId(), Eq(0x7f));
const auto& dynamic_pkg_map = packages[0]->GetDynamicPackageMap();
// The library has two dependencies.
- ASSERT_EQ(2u, dynamic_pkg_map.size());
+ ASSERT_THAT(dynamic_pkg_map, SizeIs(2u));
+ EXPECT_THAT(dynamic_pkg_map[0].package_name, StrEq("com.android.lib_one"));
+ EXPECT_THAT(dynamic_pkg_map[0].package_id, Eq(0x02));
- EXPECT_EQ(std::string("com.android.lib_one"), dynamic_pkg_map[0].package_name);
- EXPECT_EQ(0x02, dynamic_pkg_map[0].package_id);
-
- EXPECT_EQ(std::string("com.android.lib_two"), dynamic_pkg_map[1].package_name);
- EXPECT_EQ(0x03, dynamic_pkg_map[1].package_id);
+ EXPECT_THAT(dynamic_pkg_map[1].package_name, StrEq("com.android.lib_two"));
+ EXPECT_THAT(dynamic_pkg_map[1].package_id, Eq(0x03));
}
TEST(LoadedArscTest, LoadAppAsSharedLibrary) {
@@ -143,13 +143,12 @@
std::unique_ptr<const LoadedArsc> loaded_arsc =
LoadedArsc::Load(StringPiece(contents), nullptr /*loaded_idmap*/, false /*system*/,
true /*load_as_shared_library*/);
- ASSERT_NE(nullptr, loaded_arsc);
+ ASSERT_THAT(loaded_arsc, NotNull());
const auto& packages = loaded_arsc->GetPackages();
- ASSERT_EQ(1u, packages.size());
-
+ ASSERT_THAT(packages, SizeIs(1u));
EXPECT_TRUE(packages[0]->IsDynamic());
- EXPECT_EQ(0x7f, packages[0]->GetPackageId());
+ EXPECT_THAT(packages[0]->GetPackageId(), Eq(0x7f));
}
TEST(LoadedArscTest, LoadFeatureSplit) {
@@ -157,21 +156,67 @@
ASSERT_TRUE(ReadFileFromZipToString(GetTestDataPath() + "/feature/feature.apk", "resources.arsc",
&contents));
std::unique_ptr<const LoadedArsc> loaded_arsc = LoadedArsc::Load(StringPiece(contents));
- ASSERT_NE(nullptr, loaded_arsc);
+ ASSERT_THAT(loaded_arsc, NotNull());
- ResTable_config desired_config;
- memset(&desired_config, 0, sizeof(desired_config));
+ const LoadedPackage* package =
+ loaded_arsc->GetPackageById(get_package_id(basic::R::string::test3));
+ ASSERT_THAT(package, NotNull());
- FindEntryResult entry;
- ASSERT_TRUE(loaded_arsc->FindEntry(basic::R::string::test3, desired_config, &entry));
+ uint8_t type_index = get_type_id(basic::R::string::test3) - 1;
+ uint8_t entry_index = get_entry_id(basic::R::string::test3);
+
+ const TypeSpec* type_spec = package->GetTypeSpecByTypeIndex(type_index);
+ ASSERT_THAT(type_spec, NotNull());
+ ASSERT_THAT(type_spec->type_count, Ge(1u));
+ ASSERT_THAT(type_spec->types[0], NotNull());
size_t len;
- const char16_t* type_name16 = entry.type_string_ref.string16(&len);
- ASSERT_NE(nullptr, type_name16);
- ASSERT_NE(0u, len);
+ const char16_t* type_name16 =
+ package->GetTypeStringPool()->stringAt(type_spec->type_spec->id - 1, &len);
+ ASSERT_THAT(type_name16, NotNull());
+ EXPECT_THAT(util::Utf16ToUtf8(StringPiece16(type_name16, len)), StrEq("string"));
- std::string type_name = util::Utf16ToUtf8(StringPiece16(type_name16, len));
- EXPECT_EQ(std::string("string"), type_name);
+ ASSERT_THAT(LoadedPackage::GetEntry(type_spec->types[0], entry_index), NotNull());
+}
+
+// AAPT(2) generates resource tables with chunks in a certain order. The rule is that
+// a RES_TABLE_TYPE_TYPE with id `i` must always be preceded by a RES_TABLE_TYPE_SPEC_TYPE with
+// id `i`. The RES_TABLE_TYPE_SPEC_TYPE does not need to be directly preceding, however.
+//
+// AAPT(2) generates something like:
+// RES_TABLE_TYPE_SPEC_TYPE id=1
+// RES_TABLE_TYPE_TYPE id=1
+// RES_TABLE_TYPE_SPEC_TYPE id=2
+// RES_TABLE_TYPE_TYPE id=2
+//
+// But the following is valid too:
+// RES_TABLE_TYPE_SPEC_TYPE id=1
+// RES_TABLE_TYPE_SPEC_TYPE id=2
+// RES_TABLE_TYPE_TYPE id=1
+// RES_TABLE_TYPE_TYPE id=2
+//
+TEST(LoadedArscTest, LoadOutOfOrderTypeSpecs) {
+ std::string contents;
+ ASSERT_TRUE(
+ ReadFileFromZipToString(GetTestDataPath() + "/out_of_order_types/out_of_order_types.apk",
+ "resources.arsc", &contents));
+
+ std::unique_ptr<const LoadedArsc> loaded_arsc = LoadedArsc::Load(StringPiece(contents));
+ ASSERT_THAT(loaded_arsc, NotNull());
+
+ ASSERT_THAT(loaded_arsc->GetPackages(), SizeIs(1u));
+ const auto& package = loaded_arsc->GetPackages()[0];
+ ASSERT_THAT(package, NotNull());
+
+ const TypeSpec* type_spec = package->GetTypeSpecByTypeIndex(0);
+ ASSERT_THAT(type_spec, NotNull());
+ ASSERT_THAT(type_spec->type_count, Ge(1u));
+ ASSERT_THAT(type_spec->types[0], NotNull());
+
+ type_spec = package->GetTypeSpecByTypeIndex(1);
+ ASSERT_THAT(type_spec, NotNull());
+ ASSERT_THAT(type_spec->type_count, Ge(1u));
+ ASSERT_THAT(type_spec->types[0], NotNull());
}
class MockLoadedIdmap : public LoadedIdmap {
@@ -199,23 +244,33 @@
};
TEST(LoadedArscTest, LoadOverlay) {
- std::string contents, overlay_contents;
- ASSERT_TRUE(
- ReadFileFromZipToString(GetTestDataPath() + "/basic/basic.apk", "resources.arsc", &contents));
+ std::string contents;
ASSERT_TRUE(ReadFileFromZipToString(GetTestDataPath() + "/overlay/overlay.apk", "resources.arsc",
- &overlay_contents));
+ &contents));
MockLoadedIdmap loaded_idmap;
std::unique_ptr<const LoadedArsc> loaded_arsc =
- LoadedArsc::Load(StringPiece(overlay_contents), &loaded_idmap);
- ASSERT_NE(nullptr, loaded_arsc);
+ LoadedArsc::Load(StringPiece(contents), &loaded_idmap);
+ ASSERT_THAT(loaded_arsc, NotNull());
- ResTable_config desired_config;
- memset(&desired_config, 0, sizeof(desired_config));
+ const LoadedPackage* package = loaded_arsc->GetPackageById(0x08u);
+ ASSERT_THAT(package, NotNull());
- FindEntryResult entry;
- ASSERT_TRUE(loaded_arsc->FindEntry(0x08030001u, desired_config, &entry));
+ const TypeSpec* type_spec = package->GetTypeSpecByTypeIndex(0x03u - 1);
+ ASSERT_THAT(type_spec, NotNull());
+ ASSERT_THAT(type_spec->type_count, Ge(1u));
+ ASSERT_THAT(type_spec->types[0], NotNull());
+
+ // The entry being overlaid doesn't exist at the original entry index.
+ ASSERT_THAT(LoadedPackage::GetEntry(type_spec->types[0], 0x0001u), IsNull());
+
+ // Since this is an overlay, the actual entry ID must be mapped.
+ ASSERT_THAT(type_spec->idmap_entries, NotNull());
+ uint16_t target_entry_id = 0u;
+ ASSERT_TRUE(LoadedIdmap::Lookup(type_spec->idmap_entries, 0x0001u, &target_entry_id));
+ ASSERT_THAT(target_entry_id, Eq(0x0u));
+ ASSERT_THAT(LoadedPackage::GetEntry(type_spec->types[0], 0x0000), NotNull());
}
// structs with size fields (like Res_value, ResTable_entry) should be
diff --git a/libs/androidfw/tests/TestHelpers.h b/libs/androidfw/tests/TestHelpers.h
index 43a9955..df0c642 100644
--- a/libs/androidfw/tests/TestHelpers.h
+++ b/libs/androidfw/tests/TestHelpers.h
@@ -20,6 +20,7 @@
#include <string>
#include "androidfw/ResourceTypes.h"
+#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include "CommonHelpers.h"
diff --git a/libs/androidfw/tests/data/app/app.apk b/libs/androidfw/tests/data/app/app.apk
index ccb0824..c8ad86d 100644
--- a/libs/androidfw/tests/data/app/app.apk
+++ b/libs/androidfw/tests/data/app/app.apk
Binary files differ
diff --git a/libs/androidfw/tests/data/app/assets/app_file.txt b/libs/androidfw/tests/data/app/assets/app_file.txt
new file mode 100644
index 0000000..b214e06
--- /dev/null
+++ b/libs/androidfw/tests/data/app/assets/app_file.txt
@@ -0,0 +1 @@
+app file
diff --git a/libs/androidfw/tests/data/app/assets/file.txt b/libs/androidfw/tests/data/app/assets/file.txt
new file mode 100644
index 0000000..0811542
--- /dev/null
+++ b/libs/androidfw/tests/data/app/assets/file.txt
@@ -0,0 +1 @@
+app override file
diff --git a/libs/androidfw/tests/data/app/build b/libs/androidfw/tests/data/app/build
index d418158..09af842 100755
--- a/libs/androidfw/tests/data/app/build
+++ b/libs/androidfw/tests/data/app/build
@@ -17,4 +17,11 @@
set -e
-aapt package -I ../system/system.apk -M AndroidManifest.xml -S res -F app.apk -f
+aapt2 compile --dir res -o compiled.flata
+aapt2 link \
+ --manifest AndroidManifest.xml \
+ -I ../system/system.apk \
+ -A assets \
+ -o app.apk \
+ compiled.flata
+rm compiled.flata
diff --git a/libs/androidfw/tests/data/basic/R.h b/libs/androidfw/tests/data/basic/R.h
index 94a2a14..b7e814f 100644
--- a/libs/androidfw/tests/data/basic/R.h
+++ b/libs/androidfw/tests/data/basic/R.h
@@ -34,6 +34,7 @@
struct layout {
enum : uint32_t {
main = 0x7f020000,
+ layoutt = 0x7f020001,
};
};
@@ -55,6 +56,7 @@
number2 = 0x7f040001,
ref1 = 0x7f040002,
ref2 = 0x7f040003,
+ deep_ref = 0x7f040004,
// From feature
number3 = 0x80030000,
diff --git a/libs/androidfw/tests/data/basic/basic.apk b/libs/androidfw/tests/data/basic/basic.apk
index 18ef75e..1733b6a 100644
--- a/libs/androidfw/tests/data/basic/basic.apk
+++ b/libs/androidfw/tests/data/basic/basic.apk
Binary files differ
diff --git a/libs/androidfw/tests/data/basic/res/layout/layout.xml b/libs/androidfw/tests/data/basic/res/layout/layout.xml
new file mode 100644
index 0000000..045ede4
--- /dev/null
+++ b/libs/androidfw/tests/data/basic/res/layout/layout.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2018 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<Button xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/ok"
+ android:layout_width="0sp"
+ android:layout_height="fill_parent"
+ android:layout_weight="1"
+ android:layout_marginStart="2dip"
+ android:layout_marginEnd="2dip"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:textStyle="bold"
+ android:text="@android:string/ok" />
\ No newline at end of file
diff --git a/libs/androidfw/tests/data/basic/res/values/values.xml b/libs/androidfw/tests/data/basic/res/values/values.xml
index 6c47459..b343562 100644
--- a/libs/androidfw/tests/data/basic/res/values/values.xml
+++ b/libs/androidfw/tests/data/basic/res/values/values.xml
@@ -22,6 +22,7 @@
<attr name="attr2" format="reference|integer" />
<public type="layout" name="main" id="0x7f020000" />
+ <public type="layout" name="layout" id="0x7f020001" />
<public type="string" name="test1" id="0x7f030000" />
<string name="test1">test1</string>
@@ -43,6 +44,18 @@
<public type="integer" name="ref2" id="0x7f040003" />
<integer name="ref2">12000</integer>
+ <public type="integer" name="deep_ref" id="0x7f040004" />
+ <integer name="deep_ref">@integer/deep_ref_1</integer>
+ <integer name="deep_ref_1">@integer/deep_ref_2</integer>
+ <integer name="deep_ref_2">@integer/deep_ref_3</integer>
+ <integer name="deep_ref_3">@integer/deep_ref_4</integer>
+ <integer name="deep_ref_4">@integer/deep_ref_5</integer>
+ <integer name="deep_ref_5">@integer/deep_ref_6</integer>
+ <integer name="deep_ref_6">@integer/deep_ref_7</integer>
+ <integer name="deep_ref_7">@integer/deep_ref_8</integer>
+ <integer name="deep_ref_8">@integer/deep_ref_9</integer>
+ <integer name="deep_ref_9">100</integer>
+
<public type="style" name="Theme1" id="0x7f050000" />
<style name="Theme1">
<item name="com.android.basic:attr1">100</item>
diff --git a/libs/androidfw/tests/data/out_of_order_types/AndroidManifest.xml b/libs/androidfw/tests/data/out_of_order_types/AndroidManifest.xml
new file mode 100644
index 0000000..34016db
--- /dev/null
+++ b/libs/androidfw/tests/data/out_of_order_types/AndroidManifest.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2018 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.app" />
diff --git a/libs/androidfw/tests/data/out_of_order_types/build b/libs/androidfw/tests/data/out_of_order_types/build
new file mode 100755
index 0000000..8496f81
--- /dev/null
+++ b/libs/androidfw/tests/data/out_of_order_types/build
@@ -0,0 +1,22 @@
+#!/bin/bash
+#
+# Copyright (C) 2018 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+set -e
+
+aapt2 compile --dir res -o compiled.flata
+aapt2 link --manifest AndroidManifest.xml -o out_of_order_types.apk compiled.flata
+rm compiled.flata
diff --git a/libs/androidfw/tests/data/out_of_order_types/edited_resources.arsc.txt b/libs/androidfw/tests/data/out_of_order_types/edited_resources.arsc.txt
new file mode 100644
index 0000000..eca8f47
--- /dev/null
+++ b/libs/androidfw/tests/data/out_of_order_types/edited_resources.arsc.txt
@@ -0,0 +1,43 @@
+00000000: 0200 0c00 ac02 0000 0100 0000 0100 1c00 ................
+00000010: 1c00 0000 0000 0000 0000 0000 0001 0000 ................
+00000020: 1c00 0000 0000 0000 0002 2001 8402 0000 .......... .....
+00000030: 7f00 0000 6300 6f00 6d00 2e00 6100 6e00 ....c.o.m...a.n.
+00000040: 6400 7200 6f00 6900 6400 2e00 6100 7000 d.r.o.i.d...a.p.
+00000050: 7000 0000 0000 0000 0000 0000 0000 0000 p...............
+00000060: 0000 0000 0000 0000 0000 0000 0000 0000 ................
+00000070: 0000 0000 0000 0000 0000 0000 0000 0000 ................
+00000080: 0000 0000 0000 0000 0000 0000 0000 0000 ................
+00000090: 0000 0000 0000 0000 0000 0000 0000 0000 ................
+000000a0: 0000 0000 0000 0000 0000 0000 0000 0000 ................
+000000b0: 0000 0000 0000 0000 0000 0000 0000 0000 ................
+000000c0: 0000 0000 0000 0000 0000 0000 0000 0000 ................
+000000d0: 0000 0000 0000 0000 0000 0000 0000 0000 ................
+000000e0: 0000 0000 0000 0000 0000 0000 0000 0000 ................
+000000f0: 0000 0000 0000 0000 0000 0000 0000 0000 ................
+00000100: 0000 0000 0000 0000 0000 0000 0000 0000 ................
+00000110: 0000 0000 0000 0000 0000 0000 0000 0000 ................
+00000120: 0000 0000 0000 0000 0000 0000 0000 0000 ................
+00000130: 0000 0000 2001 0000 0000 0000 6401 0000 .... .......d...
+00000140: 0000 0000 0000 0000 0100 1c00 4400 0000 ............D...
+00000150: 0200 0000 0000 0000 0000 0000 2400 0000 ............$...
+00000160: 0000 0000 0000 0000 0c00 0000 0400 6200 ..............b.
+00000170: 6f00 6f00 6c00 0000 0700 6900 6e00 7400 o.o.l.....i.n.t.
+00000180: 6500 6700 6500 7200 0000 0000 0100 1c00 e.g.e.r.........
+00000190: 2800 0000 0100 0000 0000 0000 0001 0000 (...............
+000001a0: 2000 0000 0000 0000 0000 0000 0404 7465 .............te
+000001b0: 7374 0000 0202 1000 1400 0000 0100 0000 st..............
+000001c0: 0100 0000 0000 0000 0202 1000 1400 0000
+000001d0: 0200 0000 0100 0000 0000 0000 0102 5400
+000001e0: 6800 0000 0100 0000 0100 0000 5800 0000
+000001f0: 4000 0000 0000 0000 0000 0000 0000 0000
+00000200: 0000 0000 0000 0000 0000 0000 0000 0000
+00000210: 0000 0000 0000 0000 0000 0000 0000 0000
+00000220: 0000 0000 0000 0000 0000 0000 0000 0000
+00000230: 0000 0000 0800 0000 0000 0000 0800 0012
+00000240: ffff ffff 0102 5400 6800 0000 0200 0000 ......T.h.......
+00000250: 0100 0000 5800 0000 4000 0000 0000 0000 ....X...@.......
+00000260: 0000 0000 0000 0000 0000 0000 0000 0000 ................
+00000270: 0000 0000 0000 0000 0000 0000 0000 0000 ................
+00000280: 0000 0000 0000 0000 0000 0000 0000 0000 ................
+00000290: 0000 0000 0000 0000 0000 0000 0800 0000 ................
+000002a0: 0000 0000 0800 0010 0100 0000 ............
diff --git a/libs/androidfw/tests/data/out_of_order_types/out_of_order_types.apk b/libs/androidfw/tests/data/out_of_order_types/out_of_order_types.apk
new file mode 100644
index 0000000..75146e0
--- /dev/null
+++ b/libs/androidfw/tests/data/out_of_order_types/out_of_order_types.apk
Binary files differ
diff --git a/libs/androidfw/tests/data/out_of_order_types/res/values/values.xml b/libs/androidfw/tests/data/out_of_order_types/res/values/values.xml
new file mode 100644
index 0000000..7c54fba
--- /dev/null
+++ b/libs/androidfw/tests/data/out_of_order_types/res/values/values.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2018 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<resources>
+ <bool name="test">true</bool>
+ <integer name="test">1</integer>
+</resources>
diff --git a/libs/androidfw/tests/data/system/assets/file.txt b/libs/androidfw/tests/data/system/assets/file.txt
new file mode 100644
index 0000000..f73f309
--- /dev/null
+++ b/libs/androidfw/tests/data/system/assets/file.txt
@@ -0,0 +1 @@
+file
diff --git a/libs/androidfw/tests/data/system/assets/subdir/subdir_file.txt b/libs/androidfw/tests/data/system/assets/subdir/subdir_file.txt
new file mode 100644
index 0000000..3f74eb6
--- /dev/null
+++ b/libs/androidfw/tests/data/system/assets/subdir/subdir_file.txt
@@ -0,0 +1 @@
+subdir file
diff --git a/libs/androidfw/tests/data/system/build b/libs/androidfw/tests/data/system/build
index bfbdf4c..b65145a 100755
--- a/libs/androidfw/tests/data/system/build
+++ b/libs/androidfw/tests/data/system/build
@@ -17,4 +17,6 @@
set -e
-aapt package -x -M AndroidManifest.xml -S res -F system.apk -f
+aapt2 compile --dir res -o compiled.flata
+aapt2 link --manifest AndroidManifest.xml -A assets -o system.apk compiled.flata
+rm compiled.flata
diff --git a/libs/androidfw/tests/data/system/res/values-sv/values.xml b/libs/androidfw/tests/data/system/res/values-sv/values.xml
index b97bdb6..5f60d21 100644
--- a/libs/androidfw/tests/data/system/res/values-sv/values.xml
+++ b/libs/androidfw/tests/data/system/res/values-sv/values.xml
@@ -15,6 +15,5 @@
-->
<resources>
- <public type="integer" name="number" id="0x01030000" />
<integer name="number">1</integer>
</resources>
diff --git a/libs/androidfw/tests/data/system/res/values/themes.xml b/libs/androidfw/tests/data/system/res/values/themes.xml
index 35d43c7..7893c94 100644
--- a/libs/androidfw/tests/data/system/res/values/themes.xml
+++ b/libs/androidfw/tests/data/system/res/values/themes.xml
@@ -18,6 +18,7 @@
<public name="background" type="attr" id="0x01010000"/>
<public name="foreground" type="attr" id="0x01010001"/>
<public name="Theme.One" type="style" id="0x01020000"/>
+ <public type="integer" name="number" id="0x01030000" />
<attr name="background" format="color|reference"/>
<attr name="foreground" format="color|reference"/>
diff --git a/libs/androidfw/tests/data/system/system.apk b/libs/androidfw/tests/data/system/system.apk
index 1299016..9045d6c 100644
--- a/libs/androidfw/tests/data/system/system.apk
+++ b/libs/androidfw/tests/data/system/system.apk
Binary files differ
diff --git a/location/java/android/location/LocationManager.java b/location/java/android/location/LocationManager.java
index 7d2ad91..2dd8c36 100644
--- a/location/java/android/location/LocationManager.java
+++ b/location/java/android/location/LocationManager.java
@@ -1246,7 +1246,6 @@
*
* @param enabled true to enable location. false to disable location
* @param userHandle the user to set
- * @return true if the value was set, false on database errors
*
* @hide
*/
diff --git a/media/java/android/media/MediaBrowser2.java b/media/java/android/media/MediaBrowser2.java
index dea38a8..35edc4a 100644
--- a/media/java/android/media/MediaBrowser2.java
+++ b/media/java/android/media/MediaBrowser2.java
@@ -46,12 +46,13 @@
* {@code rootMediaId} and {@code rootExtra} can be {@code null} if the library root isn't
* available.
*
+ * @param browser the browser for this event
* @param rootHints rootHints that you previously requested.
* @param rootMediaId media id of the library root. Can be {@code null}
* @param rootExtra extra of the library root. Can be {@code null}
*/
- public void onGetLibraryRootDone(Bundle rootHints, @Nullable String rootMediaId,
- @Nullable Bundle rootExtra) { }
+ public void onGetLibraryRootDone(@NonNull MediaBrowser2 browser, @Nullable Bundle rootHints,
+ @Nullable String rootMediaId, @Nullable Bundle rootExtra) { }
/**
* Called when there's change in the parent's children.
@@ -60,18 +61,20 @@
* {@link MediaLibrarySession#notifyChildrenChanged(ControllerInfo, String, int, Bundle)} or
* {@link MediaLibrarySession#notifyChildrenChanged(String, int, Bundle)} for the parent.
*
+ * @param browser the browser for this event
* @param parentId parent id that you've specified with {@link #subscribe(String, Bundle)}
* @param itemCount number of children
* @param extras extra bundle from the library service. Can be differ from extras that
* you've specified with {@link #subscribe(String, Bundle)}.
*/
- public void onChildrenChanged(@NonNull String parentId, int itemCount,
- @Nullable Bundle extras) { }
+ public void onChildrenChanged(@NonNull MediaBrowser2 browser, @NonNull String parentId,
+ int itemCount, @Nullable Bundle extras) { }
/**
* Called when the list of items has been returned by the library service for the previous
* {@link MediaBrowser2#getChildren(String, int, int, Bundle)}.
*
+ * @param browser the browser for this event
* @param parentId parent id
* @param page page number that you've specified with
* {@link #getChildren(String, int, int, Bundle)}
@@ -80,8 +83,9 @@
* @param result result. Can be {@code null}
* @param extras extra bundle from the library service
*/
- public void onGetChildrenDone(@NonNull String parentId, int page, int pageSize,
- @Nullable List<MediaItem2> result, @Nullable Bundle extras) { }
+ public void onGetChildrenDone(@NonNull MediaBrowser2 browser, @NonNull String parentId,
+ int page, int pageSize, @Nullable List<MediaItem2> result,
+ @Nullable Bundle extras) { }
/**
* Called when the item has been returned by the library service for the previous
@@ -89,21 +93,24 @@
* <p>
* Result can be null if there had been error.
*
+ * @param browser the browser for this event
* @param mediaId media id
* @param result result. Can be {@code null}
*/
- public void onGetItemDone(@NonNull String mediaId, @Nullable MediaItem2 result) { }
+ public void onGetItemDone(@NonNull MediaBrowser2 browser, @NonNull String mediaId,
+ @Nullable MediaItem2 result) { }
/**
* Called when there's change in the search result requested by the previous
* {@link MediaBrowser2#search(String, Bundle)}.
*
+ * @param browser the browser for this event
* @param query search query that you've specified with {@link #search(String, Bundle)}
* @param itemCount The item count for the search result
* @param extras extra bundle from the library service
*/
- public void onSearchResultChanged(@NonNull String query, int itemCount,
- @Nullable Bundle extras) { }
+ public void onSearchResultChanged(@NonNull MediaBrowser2 browser, @NonNull String query,
+ int itemCount, @Nullable Bundle extras) { }
/**
* Called when the search result has been returned by the library service for the previous
@@ -111,6 +118,7 @@
* <p>
* Result can be null if there had been error.
*
+ * @param browser the browser for this event
* @param query search query that you've specified with
* {@link #getSearchResult(String, int, int, Bundle)}
* @param page page number that you've specified with
@@ -120,8 +128,9 @@
* @param result result. Can be {@code null}.
* @param extras extra bundle from the library service
*/
- public void onGetSearchResultDone(@NonNull String query, int page, int pageSize,
- @Nullable List<MediaItem2> result, @Nullable Bundle extras) { }
+ public void onGetSearchResultDone(@NonNull MediaBrowser2 browser, @NonNull String query,
+ int page, int pageSize, @Nullable List<MediaItem2> result,
+ @Nullable Bundle extras) { }
}
public MediaBrowser2(@NonNull Context context, @NonNull SessionToken2 token,
@@ -139,10 +148,10 @@
/**
* Get the library root. Result would be sent back asynchronously with the
- * {@link BrowserCallback#onGetLibraryRootDone(Bundle, String, Bundle)}.
+ * {@link BrowserCallback#onGetLibraryRootDone(MediaBrowser2, Bundle, String, Bundle)}.
*
* @param rootHints hint for the root
- * @see BrowserCallback#onGetLibraryRootDone(Bundle, String, Bundle)
+ * @see BrowserCallback#onGetLibraryRootDone(MediaBrowser2, Bundle, String, Bundle)
*/
public void getLibraryRoot(Bundle rootHints) {
mProvider.getLibraryRoot_impl(rootHints);
@@ -150,9 +159,9 @@
/**
* Subscribe to a parent id for the change in its children. When there's a change,
- * {@link BrowserCallback#onChildrenChanged(String, int, Bundle)} will be called with the bundle
- * that you've specified. You should call {@link #getChildren(String, int, int, Bundle)} to get
- * the actual contents for the parent.
+ * {@link BrowserCallback#onChildrenChanged(MediaBrowser2, String, int, Bundle)} will be called
+ * with the bundle that you've specified. You should call
+ * {@link #getChildren(String, int, int, Bundle)} to get the actual contents for the parent.
*
* @param parentId parent id
* @param extras extra bundle
@@ -176,7 +185,7 @@
/**
* Get list of children under the parent. Result would be sent back asynchronously with the
- * {@link BrowserCallback#onGetChildrenDone(String, int, int, List, Bundle)}.
+ * {@link BrowserCallback#onGetChildrenDone(MediaBrowser2, String, int, int, List, Bundle)}.
*
* @param parentId parent id for getting the children.
* @param page page number to get the result. Starts from {@code 1}
@@ -189,7 +198,7 @@
/**
* Get the media item with the given media id. Result would be sent back asynchronously with the
- * {@link BrowserCallback#onGetItemDone(String, MediaItem2)}.
+ * {@link BrowserCallback#onGetItemDone(MediaBrowser2, String, MediaItem2)}.
*
* @param mediaId media id for specifying the item
*/
@@ -199,8 +208,9 @@
/**
* Send a search request to the library service. When the search result is changed,
- * {@link BrowserCallback#onSearchResultChanged(String, int, Bundle)} will be called. You should
- * call {@link #getSearchResult(String, int, int, Bundle)} to get the actual search result.
+ * {@link BrowserCallback#onSearchResultChanged(MediaBrowser2, String, int, Bundle)} will be
+ * called. You should call {@link #getSearchResult(String, int, int, Bundle)} to get the actual
+ * search result.
*
* @param query search query. Should not be an empty string.
* @param extras extra bundle
@@ -211,7 +221,8 @@
/**
* Get the search result from lhe library service. Result would be sent back asynchronously with
- * the {@link BrowserCallback#onGetSearchResultDone(String, int, int, List, Bundle)}.
+ * the
+ * {@link BrowserCallback#onGetSearchResultDone(MediaBrowser2, String, int, int, List, Bundle)}.
*
* @param query search query that you've specified with {@link #search(String, Bundle)}
* @param page page number to get search result. Starts from {@code 1}
diff --git a/media/java/android/media/MediaController2.java b/media/java/android/media/MediaController2.java
index 38d5000..da2b8e0 100644
--- a/media/java/android/media/MediaController2.java
+++ b/media/java/android/media/MediaController2.java
@@ -51,9 +51,9 @@
* <p>
* When controlling {@link MediaSessionService2}, the {@link MediaController2} would be
* available only if the session service allows this controller by
- * {@link MediaSession2.SessionCallback#onConnect(ControllerInfo)} for the service. Wait
- * {@link ControllerCallback#onConnected(CommandGroup)} or
- * {@link ControllerCallback#onDisconnected()} for the result.
+ * {@link MediaSession2.SessionCallback#onConnect(MediaSession2, ControllerInfo)} for the service.
+ * Wait {@link ControllerCallback#onConnected(MediaController2, CommandGroup)} or
+ * {@link ControllerCallback#onDisconnected(MediaController2)} for the result.
* <p>
* A controller can be created through token from {@link MediaSessionManager} if you hold the
* signature|privileged permission "android.permission.MEDIA_CONTENT_CONTROL" permission or are
@@ -75,9 +75,11 @@
* Called when the controller is successfully connected to the session. The controller
* becomes available afterwards.
*
+ * @param controller the controller for this event
* @param allowedCommands commands that's allowed by the session.
*/
- public void onConnected(CommandGroup allowedCommands) { }
+ public void onConnected(@NonNull MediaController2 controller,
+ @NonNull CommandGroup allowedCommands) { }
/**
* Called when the session refuses the controller or the controller is disconnected from
@@ -86,113 +88,149 @@
* <p>
* It will be also called after the {@link #close()}, so you can put clean up code here.
* You don't need to call {@link #close()} after this.
+ *
+ * @param controller the controller for this event
+ * @param controller controller for this event
*/
- public void onDisconnected() { }
+ public void onDisconnected(@NonNull MediaController2 controller) { }
/**
* Called when the session set the custom layout through the
* {@link MediaSession2#setCustomLayout(ControllerInfo, List)}.
* <p>
- * Can be called before {@link #onConnected(CommandGroup)} is called.
+ * Can be called before {@link #onConnected(MediaController2, CommandGroup)} is called.
*
+ * @param controller the controller for this event
* @param layout
*/
- public void onCustomLayoutChanged(List<CommandButton> layout) { }
+ public void onCustomLayoutChanged(@NonNull MediaController2 controller,
+ @NonNull List<CommandButton> layout) { }
/**
* Called when the session has changed anything related with the {@link PlaybackInfo}.
*
+ * @param controller the controller for this event
* @param info new playback info
*/
- public void onPlaybackInfoChanged(PlaybackInfo info) { }
+ public void onPlaybackInfoChanged(@NonNull MediaController2 controller,
+ @NonNull PlaybackInfo info) { }
/**
* Called when the allowed commands are changed by session.
*
+ * @param controller the controller for this event
* @param commands newly allowed commands
*/
- public void onAllowedCommandsChanged(CommandGroup commands) { }
+ public void onAllowedCommandsChanged(@NonNull MediaController2 controller,
+ @NonNull CommandGroup commands) { }
/**
* Called when the session sent a custom command.
*
+ * @param controller the controller for this event
* @param command
* @param args
* @param receiver
*/
- public void onCustomCommand(Command command, @Nullable Bundle args,
+ public void onCustomCommand(@NonNull MediaController2 controller,
+ @NonNull Command command, @Nullable Bundle args,
@Nullable ResultReceiver receiver) { }
/**
* Called when the playlist is changed.
* <p>
- * When it's called, you should invalidate previous playback information such as position,
- * player state, current item, etc.
+ * If the previously playing media item is gone, you should invalidate previous playback
+ * information and wait for later callbacks.
*
+ * @param controller the controller for this event
* @param playlist A new playlist set by the session.
+ * @see #onPositionChanged(long, long)
+ * @see #onBufferedPositionChanged(long)
+ * @see #onCurrentPlaylistItemChanged(MediaItem2)
*/
- // TODO(jaewan): Enhance doc
- public void onPlaylistChanged(@NonNull List<MediaItem2> playlist) { }
+ public void onPlaylistChanged(@NonNull MediaController2 controller,
+ @NonNull List<MediaItem2> playlist) { }
/**
* Called when the playback state is changed.
*
+ * @param controller the controller for this event
* @param state latest playback state
* @hide
*/
- // TODo(jaewan): Remove
- public void onPlaybackStateChanged(@NonNull PlaybackState2 state) { }
+ // TODO(jaewan): Remove (b/73971431)
+ public void onPlaybackStateChanged(@NonNull MediaController2 controller,
+ @NonNull PlaybackState2 state) { }
/**
* Called when the player state is changed.
*
+ * @param controller the controller for this event
* @param state
*/
- public void onPlayerStateChanged(int state) { }
+ public void onPlayerStateChanged(@NonNull MediaController2 controller, int state) { }
/**
* Called when the player's position is changed
*
- * @param updateTimeMs timestamp when the position information is sent from the session
+ * @param controller the controller for this event
+ * @param eventTimeMs timestamp when the position information is sent from the session
* @param positionMs position in millis
*/
- public void onPositionChanged(long updateTimeMs, long positionMs) { }
+ public void onPositionChanged(@NonNull MediaController2 controller,
+ long eventTimeMs, long positionMs) { }
/**
* Called when playback speed is changed.
*
+ * @param controller the controller for this event
* @param speed speed
*/
- public void onPlaybackSpeedChanged(float speed) { }
+ public void onPlaybackSpeedChanged(@NonNull MediaController2 controller,
+ float speed) { }
/**
* Called when the player's buffering position
*
+ * @param controller the controller for this event
* @param positionMs buffering position in millis
*/
- public void onBufferedPositionChanged(long positionMs) { }
+ public void onBufferedPositionChanged(@NonNull MediaController2 controller,
+ long positionMs) { }
/**
* Called when a error from
*
+ * @param controller the controller for this event
* @param errorCode error code
* @param extras extra information
*/
- public void onError(@ErrorCode int errorCode, @Nullable Bundle extras) { }
+ public void onError(@NonNull MediaController2 controller, @ErrorCode int errorCode,
+ @Nullable Bundle extras) { }
/**
* Called when the player's current playing item is changed
+ * <p>
+ * When it's called, you should invalidate previous playback information and wait for later
+ * callbacks.
*
+ * @param controller the controller for this event
* @param item new item
+ * @see #onPositionChanged(long, long)
+ * @see #onBufferedPositionChanged(long)
+ * @see #onCurrentPlaylistItemChanged(MediaItem2)
*/
- public void onCurrentPlaylistItemChanged(MediaItem2 item) { }
+ public void onCurrentPlaylistItemChanged(@NonNull MediaController2 controller,
+ @NonNull MediaItem2 item) { }
/**
* Called when the playlist parameters are changed.
*
+ * @param controller the controller for this event
* @param params The new play list parameters.
*/
- public void onPlaylistParamsChanged(@NonNull PlaylistParams params) { }
+ public void onPlaylistParamsChanged(@NonNull MediaController2 controller,
+ @NonNull PlaylistParams params) { }
}
/**
@@ -295,7 +333,6 @@
* @param executor executor to run callbacks on.
* @param callback controller callback to receive changes in
*/
- // TODO(jaewan): Put @CallbackExecutor to the constructor.
public MediaController2(@NonNull Context context, @NonNull SessionToken2 token,
@NonNull @CallbackExecutor Executor executor, @NonNull ControllerCallback callback) {
super();
@@ -577,7 +614,7 @@
/**
* Get the lastly cached {@link PlaybackState2} from
- * {@link ControllerCallback#onPlaybackStateChanged(PlaybackState2)}.
+ * {@link ControllerCallback#onPlaybackStateChanged(MediaController2, PlaybackState2)}.
* <p>
* It may return {@code null} before the first callback or session has sent {@code null}
* playback state.
@@ -590,7 +627,8 @@
}
/**
- * Get the lastly cached player state from {@link ControllerCallback#onPlayerStateChanged(int)}.
+ * Get the lastly cached player state from
+ * {@link ControllerCallback#onPlayerStateChanged(MediaController2, int)}.
*
* @return player state
*/
@@ -599,7 +637,8 @@
}
/**
- * Get the lastly cached position from {@link ControllerCallback#onPositionChanged(long, long)}.
+ * Get the lastly cached position from
+ * {@link ControllerCallback#onPositionChanged(MediaController2, long, long)}.
* <p>
* This returns the calculated value of the position, based on the difference between the
* update time and current time.
@@ -612,7 +651,7 @@
/**
* Get the lastly cached playback speed from
- * {@link ControllerCallback#onPlaybackSpeedChanged(float)}.
+ * {@link ControllerCallback#onPlaybackSpeedChanged(MediaController2, float)}.
*
* @return speed
*/
@@ -624,12 +663,12 @@
* Set the playback speed.
*/
public void setPlaybackSpeed(float speed) {
- // TODO: implement this
+ // TODO(jaewan): implement this (b/74093080)
}
/**
* Get the lastly cached buffered position from
- * {@link ControllerCallback#onBufferedPositionChanged(long)}.
+ * {@link ControllerCallback#onBufferedPositionChanged(MediaController2, long)}.
*
* @return buffering position in millis
*/
@@ -639,7 +678,7 @@
/**
* Get the lastly cached current item from
- * {@link ControllerCallback#onCurrentPlaylistItemChanged(MediaItem2)}.
+ * {@link ControllerCallback#onCurrentPlaylistItemChanged(MediaController2, MediaItem2)}.
*
* @return index of the current item
*/
diff --git a/media/java/android/media/MediaItem2.java b/media/java/android/media/MediaItem2.java
index f9eceab..f6edd0c 100644
--- a/media/java/android/media/MediaItem2.java
+++ b/media/java/android/media/MediaItem2.java
@@ -70,7 +70,6 @@
* @return a new bundle instance
*/
public Bundle toBundle() {
- // TODO(jaewan): Fill here when we rebase.
return mProvider.toBundle_impl();
}
diff --git a/media/java/android/media/MediaLibraryService2.java b/media/java/android/media/MediaLibraryService2.java
index 5917190..2372685 100644
--- a/media/java/android/media/MediaLibraryService2.java
+++ b/media/java/android/media/MediaLibraryService2.java
@@ -85,6 +85,7 @@
* should return null if the client is not allowed to access this
* information.
*
+ * @param session the session for this event
* @param controllerInfo information of the controller requesting access to browse media.
* @param rootHints An optional bundle of service-specific arguments to send
* to the media library service when connecting and retrieving the
@@ -95,8 +96,8 @@
* @see LibraryRoot#EXTRA_OFFLINE
* @see LibraryRoot#EXTRA_SUGGESTED
*/
- public @Nullable LibraryRoot onGetLibraryRoot(@NonNull ControllerInfo controllerInfo,
- @Nullable Bundle rootHints) {
+ public @Nullable LibraryRoot onGetLibraryRoot(@NonNull MediaLibrarySession session,
+ @NonNull ControllerInfo controllerInfo, @Nullable Bundle rootHints) {
return null;
}
@@ -105,11 +106,12 @@
* <p>
* Return {@code null} for no result or error.
*
+ * @param session the session for this event
* @param mediaId item id to get media item.
* @return a media item. {@code null} for no result or error.
*/
- public @Nullable MediaItem2 onGetItem(@NonNull ControllerInfo controllerInfo,
- @NonNull String mediaId) {
+ public @Nullable MediaItem2 onGetItem(@NonNull MediaLibrarySession session,
+ @NonNull ControllerInfo controllerInfo, @NonNull String mediaId) {
return null;
}
@@ -118,14 +120,16 @@
* <p>
* Return an empty list for no children, and return {@code null} for the error.
*
+ * @param session the session for this event
* @param parentId parent id to get children
* @param page number of page
* @param pageSize size of the page
* @param extras extra bundle
* @return list of children. Can be {@code null}.
*/
- public @Nullable List<MediaItem2> onGetChildren(@NonNull ControllerInfo controller,
- @NonNull String parentId, int page, int pageSize, @Nullable Bundle extras) {
+ public @Nullable List<MediaItem2> onGetChildren(@NonNull MediaLibrarySession session,
+ @NonNull ControllerInfo controller, @NonNull String parentId, int page,
+ int pageSize, @Nullable Bundle extras) {
return null;
}
@@ -136,32 +140,37 @@
* {@link MediaLibrarySession#notifyChildrenChanged(ControllerInfo, String, int, Bundle)}
* when the parent is changed.
*
+ * @param session the session for this event
* @param controller controller
* @param parentId parent id
* @param extras extra bundle
*/
- public void onSubscribe(@NonNull ControllerInfo controller, @NonNull String parentId,
+ public void onSubscribe(@NonNull MediaLibrarySession session,
+ @NonNull ControllerInfo controller, @NonNull String parentId,
@Nullable Bundle extras) {
}
/**
* Called when a controller unsubscribes to the parent.
*
+ * @param session the session for this event
* @param controller controller
* @param parentId parent id
*/
- public void onUnsubscribe(@NonNull ControllerInfo controller,
- @NonNull String parentId) {
+ public void onUnsubscribe(@NonNull MediaLibrarySession session,
+ @NonNull ControllerInfo controller, @NonNull String parentId) {
}
/**
* Called when a controller requests search.
*
+ * @param session the session for this event
* @param query The search query sent from the media browser. It contains keywords
* separated by space.
* @param extras The bundle of service-specific arguments sent from the media browser.
*/
- public void onSearch(@NonNull ControllerInfo controllerInfo, @NonNull String query,
+ public void onSearch(@NonNull MediaLibrarySession session,
+ @NonNull ControllerInfo controllerInfo, @NonNull String query,
@Nullable Bundle extras) {
}
@@ -171,17 +180,18 @@
* <p>
* Return an empty list for no search result, and return {@code null} for the error.
*
+ * @param session the session for this event
* @param controllerInfo Information of the controller requesting the search result.
* @param query The search query which was previously sent through
- * {@link #onSearch(ControllerInfo, String, Bundle)} call.
+ * {@link #onSearch(MediaLibrarySession, ControllerInfo, String, Bundle)}.
* @param page page number. Starts from {@code 1}.
* @param pageSize page size. Should be greater or equal to {@code 1}.
* @param extras The bundle of service-specific arguments sent from the media browser.
* @return search result. {@code null} for error.
*/
public @Nullable List<MediaItem2> onGetSearchResult(
- @NonNull ControllerInfo controllerInfo, @NonNull String query, int page,
- int pageSize, @Nullable Bundle extras) {
+ @NonNull MediaLibrarySession session, @NonNull ControllerInfo controllerInfo,
+ @NonNull String query, int page, int pageSize, @Nullable Bundle extras) {
return null;
}
}
@@ -335,8 +345,8 @@
* supplied as a root hint for retrieving media items that are recently played.
* If the media library service can provide such media items, the implementation must return
* the key in the root hint when
- * {@link MediaLibrarySessionCallback#onGetLibraryRoot(ControllerInfo, Bundle)} is called
- * back.
+ * {@link MediaLibrarySessionCallback#onGetLibraryRoot(MediaLibrarySession, ControllerInfo, Bundle)}
+ * is called back.
*
* <p>The root hint may contain multiple keys.
*
@@ -354,8 +364,8 @@
* internet connection.
* If the media library service can provide such media items, the implementation must return
* the key in the root hint when
- * {@link MediaLibrarySessionCallback#onGetLibraryRoot(ControllerInfo, Bundle)} is called
- * back.
+ * {@link MediaLibrarySessionCallback#onGetLibraryRoot(MediaLibrarySession, ControllerInfo, Bundle)}
+ * is called back.
*
* <p>The root hint may contain multiple keys.
*
@@ -374,8 +384,8 @@
* suggestion.
* If the media library service can provide such media items, the implementation must return
* the key in the root hint when
- * {@link MediaLibrarySessionCallback#onGetLibraryRoot(ControllerInfo, Bundle)} is called
- * back.
+ * {@link MediaLibrarySessionCallback#onGetLibraryRoot(MediaLibrarySession, ControllerInfo, Bundle)}
+ * is called back.
*
* <p>The root hint may contain multiple keys.
*
diff --git a/media/java/android/media/MediaMetadata2.java b/media/java/android/media/MediaMetadata2.java
index 07367bb..502f929 100644
--- a/media/java/android/media/MediaMetadata2.java
+++ b/media/java/android/media/MediaMetadata2.java
@@ -37,7 +37,6 @@
// - Don't implement Parcelable for updatable support.
// - Also support MediaDescription features. MediaDescription is deprecated instead because
// it was insufficient for controller to display media contents.
-// TODO(jaewan): Add @see for APIs from MediaDescription
public final class MediaMetadata2 {
/**
* The metadata key for a {@link CharSequence} or {@link String} typed value to retrieve the
diff --git a/media/java/android/media/MediaPlayer2.java b/media/java/android/media/MediaPlayer2.java
index e0047d6..0d472ab 100644
--- a/media/java/android/media/MediaPlayer2.java
+++ b/media/java/android/media/MediaPlayer2.java
@@ -1339,6 +1339,7 @@
* this method, you will have to initialize it again by setting the
* data source and calling prepare().
*/
+ @Override
public abstract void reset();
/**
diff --git a/media/java/android/media/MediaPlayer2Impl.java b/media/java/android/media/MediaPlayer2Impl.java
index 50bf738..50e3543 100644
--- a/media/java/android/media/MediaPlayer2Impl.java
+++ b/media/java/android/media/MediaPlayer2Impl.java
@@ -109,18 +109,21 @@
private boolean mBypassInterruptionPolicy;
private final CloseGuard mGuard = CloseGuard.get();
- private final Object mPlLock = new Object();
+ private final Object mSrcLock = new Object();
+ //--- guarded by |mSrcLock| start
+ private long mSrcIdGenerator = 0;
private DataSourceDesc mCurrentDSD;
- private long mCurrentSrcId = 0;
- private List<DataSourceDesc> mPlaylist;
- private long mNextSrcId = mCurrentSrcId + 1;
- private int mPlNextIndex = -1;
- private int mPlNextSourceState = NEXT_SOURCE_STATE_INIT;
- private boolean mPlNextSourcePlayPending = false;
+ private long mCurrentSrcId = mSrcIdGenerator++;
+ private List<DataSourceDesc> mNextDSDs;
+ private long mNextSrcId = mSrcIdGenerator++;
+ private int mNextSourceState = NEXT_SOURCE_STATE_INIT;
+ private boolean mNextSourcePlayPending = false;
+ //--- guarded by |mSrcLock| end
// Modular DRM
- private UUID mDrmUUID;
private final Object mDrmLock = new Object();
+ //--- guarded by |mDrmLock| start
+ private UUID mDrmUUID;
private DrmInfoImpl mDrmInfoImpl;
private MediaDrm mDrmObj;
private byte[] mDrmSessionId;
@@ -130,6 +133,7 @@
private boolean mDrmProvisioningInProgress;
private boolean mPrepareDrmInProgress;
private ProvisioningThread mDrmProvisioningThread;
+ //--- guarded by |mDrmLock| end
/**
* Default constructor.
@@ -277,12 +281,6 @@
* Gets the current player state.
*
* @return the current player state, one of the following:
- * <ul>
- * <li>{@link #PLAYER_STATE_IDLE}
- * <li>{@link #PLAYER_STATE_PAUSED}
- * <li>{@link #PLAYER_STATE_PLAYING}
- * <li>{@link #PLAYER_STATE_ERROR}
- * </ul>
* @throws IllegalStateException if the internal player engine has not been
* initialized or has been released.
*/
@@ -297,12 +295,6 @@
* During buffering, see {@link #getBufferedPosition()} for the quantifying the amount already
* buffered.
* @return the buffering state, one of the following:
- * <ul>
- * <li>{@link #BUFFERING_STATE_UNKNOWN}
- * <li>{@link #BUFFERING_STATE_BUFFERING_AND_PLAYABLE}
- * <li>{@link #BUFFERING_STATE_BUFFERING_AND_STARVED}
- * <li>{@link #BUFFERING_STATE_BUFFERING_COMPLETE}
- * </ul>
* @throws IllegalStateException if the internal player engine has not been
* initialized or has been released.
*/
@@ -353,10 +345,12 @@
@Override
public void setDataSource(@NonNull DataSourceDesc dsd) {
Preconditions.checkNotNull(dsd, "the DataSourceDesc cannot be null");
- synchronized (mPlLock) {
+ // TODO: setDataSource could update exist data source
+ synchronized (mSrcLock) {
mCurrentDSD = dsd;
+ mCurrentSrcId = mSrcIdGenerator++;
try {
- handleDataSource(true /* isCurrent */, dsd);
+ handleDataSource(true /* isCurrent */, dsd, mCurrentSrcId);
} catch (IOException e) {
}
}
@@ -374,7 +368,19 @@
public void setNextDataSource(@NonNull DataSourceDesc dsd) {
Preconditions.checkNotNull(dsd, "the DataSourceDesc cannot be null");
- // TODO: save dsd in a list
+ synchronized (mSrcLock) {
+ mNextDSDs = new ArrayList<DataSourceDesc>(1);
+ mNextDSDs.add(dsd);
+ mNextSrcId = mSrcIdGenerator++;
+ mNextSourceState = NEXT_SOURCE_STATE_INIT;
+ mNextSourcePlayPending = false;
+ }
+ int state = getMediaPlayer2State();
+ if (state != MEDIAPLAYER2_STATE_IDLE) {
+ synchronized (mSrcLock) {
+ prepareNextDataSource_l();
+ }
+ }
}
/**
@@ -386,45 +392,33 @@
*/
@Override
public void setNextDataSources(@NonNull List<DataSourceDesc> dsds) {
- // TODO: save the list.
- /*
if (dsds == null || dsds.size() == 0) {
throw new IllegalArgumentException("data source list cannot be null or empty.");
}
- HashSet ids = new HashSet(pl.size());
- for (DataSourceDesc dsd : pl) {
+ for (DataSourceDesc dsd : dsds) {
if (dsd == null) {
- throw new IllegalArgumentException("DataSourceDesc in playlist cannot be null.");
- }
- if (ids.add(dsd.getId()) == false) {
- throw new IllegalArgumentException("DataSourceDesc Id in playlist should be unique.");
+ throw new IllegalArgumentException(
+ "DataSourceDesc in the source list cannot be null.");
}
}
- if (startIndex < 0) {
- startIndex = 0;
- } else if (startIndex >= pl.size()) {
- startIndex = pl.size() - 1;
+ synchronized (mSrcLock) {
+ mNextDSDs = new ArrayList(dsds);
+ mNextSrcId = mSrcIdGenerator++;
+ mNextSourceState = NEXT_SOURCE_STATE_INIT;
+ mNextSourcePlayPending = false;
}
-
- synchronized (mPlLock) {
- mPlaylist = Collections.synchronizedList(new ArrayList(pl));
- handleDataSource(true, mPlaylist.get(startIndex));
- // TODO: handle the preparation of next source in the playlist.
- // It should be processed after current source is prepared.
- mPlNextIndex = getNextIndex_l();
+ int state = getMediaPlayer2State();
+ if (state != MEDIAPLAYER2_STATE_IDLE) {
+ synchronized (mSrcLock) {
+ prepareNextDataSource_l();
+ }
}
- */
}
- /**
- * Gets the current data source as described by a DataSourceDesc.
- *
- * @return the current DataSourceDesc
- */
@Override
public @NonNull DataSourceDesc getCurrentDataSource() {
- synchronized (mPlLock) {
+ synchronized (mSrcLock) {
return mCurrentDSD;
}
}
@@ -701,20 +695,20 @@
public void clearPendingCommands() {
}
- private void handleDataSource(boolean isCurrent, @NonNull DataSourceDesc dsd)
+ private void handleDataSource(boolean isCurrent, @NonNull DataSourceDesc dsd, long srcId)
throws IOException {
Preconditions.checkNotNull(dsd, "the DataSourceDesc cannot be null");
switch (dsd.getType()) {
case DataSourceDesc.TYPE_CALLBACK:
handleDataSource(isCurrent,
- 0, // TODO: get mapped Id
+ srcId,
dsd.getMedia2DataSource());
break;
case DataSourceDesc.TYPE_FD:
handleDataSource(isCurrent,
- 0, // TODO: get mapped Id
+ srcId,
dsd.getFileDescriptor(),
dsd.getFileDescriptorOffset(),
dsd.getFileDescriptorLength());
@@ -722,7 +716,7 @@
case DataSourceDesc.TYPE_URI:
handleDataSource(isCurrent,
- 0, // TODO: get mapped Id
+ srcId,
dsd.getUriContext(),
dsd.getUri(),
dsd.getUriHeaders(),
@@ -899,16 +893,17 @@
private native void nativeHandleDataSourceCallback(
boolean isCurrent, long srcId, Media2DataSource dataSource);
- // This function shall be called with |mPlLock| acquired.
+ // This function shall be called with |mSrcLock| acquired.
private void prepareNextDataSource_l() {
- if (mPlNextIndex < 0 || mPlNextSourceState != NEXT_SOURCE_STATE_INIT) {
+ if (mNextDSDs == null || mNextDSDs.isEmpty()
+ || mNextSourceState != NEXT_SOURCE_STATE_INIT) {
// There is no next source or it's in preparing or prepared state.
return;
}
try {
- mPlNextSourceState = NEXT_SOURCE_STATE_PREPARING;
- handleDataSource(false /* isCurrent */, mPlaylist.get(0));
+ mNextSourceState = NEXT_SOURCE_STATE_PREPARING;
+ handleDataSource(false /* isCurrent */, mNextDSDs.get(0), mNextSrcId);
} catch (Exception e) {
Message msg2 = mEventHandler.obtainMessage(
MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, MEDIA_ERROR_UNSUPPORTED, null);
@@ -922,18 +917,20 @@
}
}
- // This function shall be called with |mPlLock| acquired.
+ // This function shall be called with |mSrcLock| acquired.
private void playNextDataSource_l() {
- if (mPlNextIndex < 0) {
+ if (mNextDSDs == null || mNextDSDs.isEmpty()) {
return;
}
- if (mPlNextSourceState == NEXT_SOURCE_STATE_PREPARED) {
+ if (mNextSourceState == NEXT_SOURCE_STATE_PREPARED) {
// Switch to next source only when it's in prepared state.
+ mCurrentDSD = mNextDSDs.get(0);
mCurrentSrcId = mNextSrcId;
- mNextSrcId = 0; // TODO; fix it
- mPlNextSourceState = NEXT_SOURCE_STATE_INIT;
- mPlNextSourcePlayPending = false;
+ mNextDSDs.remove(0);
+ mNextSrcId = mSrcIdGenerator++; // make it different from mCurrentSrcId
+ mNextSourceState = NEXT_SOURCE_STATE_INIT;
+ mNextSourcePlayPending = false;
long srcId = mCurrentSrcId;
try {
@@ -951,10 +948,10 @@
// Wait for MEDIA2_INFO_STARTED_AS_NEXT to prepare next source.
} else {
- if (mPlNextSourceState == NEXT_SOURCE_STATE_INIT) {
+ if (mNextSourceState == NEXT_SOURCE_STATE_INIT) {
prepareNextDataSource_l();
}
- mPlNextSourcePlayPending = true;
+ mNextSourcePlayPending = true;
}
}
@@ -1245,26 +1242,13 @@
@Override
public native boolean isPlaying();
- /**
- * Gets the current MediaPlayer2 state.
- *
- * @return the current MediaPlayer2 state, one of the following:
- * <ul>
- * <li>{@link #MEDIAPLAYER2_STATE_IDLE}
- * <li>{@link #MEDIAPLAYER2_STATE_PREPARED}
- * <li>{@link #MEDIAPLAYER2_STATE_PAUSED}
- * <li>{@link #MEDIAPLAYER2_STATE_PLAYING}
- * <li>{@link #MEDIAPLAYER2_STATE_ERROR}
- * </ul>
- * @throws IllegalStateException if the internal player engine has not been
- * initialized or has been released.
- */
@Override
public @MediaPlayer2State int getMediaPlayer2State() {
- // TODO: get state from native layer or cached value.
- return MEDIAPLAYER2_STATE_IDLE;
+ return native_getMediaPlayer2State();
}
+ private native int native_getMediaPlayer2State();
+
/**
* Gets the current buffering management params used by the source component.
* Calling it only after {@code setDataSource} has been called.
@@ -2612,8 +2596,10 @@
}
final int what = msg.arg1;
final int extra = msg.arg2;
+
switch(msg.what) {
case MEDIA_PREPARED:
+ {
try {
scanInternalSubtitleTracks();
} catch (RuntimeException e) {
@@ -2626,32 +2612,37 @@
}
final DataSourceDesc dsd;
- synchronized (mPlLock) {
+ synchronized (mSrcLock) {
Log.i(TAG, "MEDIA_PREPARED: srcId=" + srcId
+ ", currentSrcId=" + mCurrentSrcId + ", nextSrcId=" + mNextSrcId);
if (srcId == mCurrentSrcId) {
- prepareNextDataSource_l();
dsd = mCurrentDSD;
- } else if (mPlNextIndex >= 0 && srcId == mNextSrcId) {
- mPlNextSourceState = NEXT_SOURCE_STATE_PREPARED;
- if (mPlNextSourcePlayPending) {
+ prepareNextDataSource_l();
+ } else if (mNextDSDs != null && !mNextDSDs.isEmpty()
+ && srcId == mNextSrcId) {
+ dsd = mNextDSDs.get(0);
+ mNextSourceState = NEXT_SOURCE_STATE_PREPARED;
+ if (mNextSourcePlayPending) {
playNextDataSource_l();
}
- dsd = mPlaylist.get(0);
} else {
dsd = null;
}
}
- synchronized (mEventCbLock) {
- for (Pair<Executor, MediaPlayer2EventCallback> cb : mEventCallbackRecords) {
- cb.first.execute(() -> cb.second.onInfo(
- mMediaPlayer, dsd, MEDIA_INFO_PREPARED, 0));
+ if (dsd != null) {
+ synchronized (mEventCbLock) {
+ for (Pair<Executor, MediaPlayer2EventCallback> cb : mEventCallbackRecords) {
+ cb.first.execute(() -> cb.second.onInfo(
+ mMediaPlayer, dsd, MEDIA_INFO_PREPARED, 0));
+ }
}
}
return;
+ }
case MEDIA_DRM_INFO:
+ {
if (msg.obj == null) {
Log.w(TAG, "MEDIA_DRM_INFO msg.obj=NULL");
} else if (msg.obj instanceof Parcel) {
@@ -2679,9 +2670,12 @@
Log.w(TAG, "MEDIA_DRM_INFO msg.obj of unexpected type " + msg.obj);
}
return;
+ }
case MEDIA_PLAYBACK_COMPLETE:
- synchronized (mPlLock) {
+ {
+ final DataSourceDesc dsd = mCurrentDSD;
+ synchronized (mSrcLock) {
if (srcId == mCurrentSrcId) {
Log.i(TAG, "MEDIA_PLAYBACK_COMPLETE: srcId=" + srcId
+ ", currentSrcId=" + mCurrentSrcId + ", nextSrcId=" + mNextSrcId);
@@ -2692,32 +2686,34 @@
synchronized (mEventCbLock) {
for (Pair<Executor, MediaPlayer2EventCallback> cb : mEventCallbackRecords) {
cb.first.execute(() -> cb.second.onInfo(
- mMediaPlayer, mCurrentDSD, MEDIA_INFO_PLAYBACK_COMPLETE, 0));
+ mMediaPlayer, dsd, MEDIA_INFO_PLAYBACK_COMPLETE, 0));
}
}
stayAwake(false);
return;
+ }
case MEDIA_STOPPED:
- {
- TimeProvider timeProvider = mTimeProvider;
- if (timeProvider != null) {
- timeProvider.onStopped();
- }
+ {
+ TimeProvider timeProvider = mTimeProvider;
+ if (timeProvider != null) {
+ timeProvider.onStopped();
}
break;
+ }
case MEDIA_STARTED:
case MEDIA_PAUSED:
- {
- TimeProvider timeProvider = mTimeProvider;
- if (timeProvider != null) {
- timeProvider.onPaused(msg.what == MEDIA_PAUSED);
- }
+ {
+ TimeProvider timeProvider = mTimeProvider;
+ if (timeProvider != null) {
+ timeProvider.onPaused(msg.what == MEDIA_PAUSED);
}
break;
+ }
case MEDIA_BUFFERING_UPDATE:
+ {
final int percent = msg.arg1;
synchronized (mEventCbLock) {
for (Pair<Executor, MediaPlayer2EventCallback> cb : mEventCallbackRecords) {
@@ -2726,26 +2722,30 @@
}
}
return;
+ }
case MEDIA_SEEK_COMPLETE:
+ {
synchronized (mEventCbLock) {
for (Pair<Executor, MediaPlayer2EventCallback> cb : mEventCallbackRecords) {
cb.first.execute(() -> cb.second.onCallComplete(
mMediaPlayer, mCurrentDSD, MEDIA_CALL_SEEK_TO, 0));
}
}
+ }
// fall through
case MEDIA_SKIPPED:
- {
- TimeProvider timeProvider = mTimeProvider;
- if (timeProvider != null) {
- timeProvider.onSeekComplete(mMediaPlayer);
- }
+ {
+ TimeProvider timeProvider = mTimeProvider;
+ if (timeProvider != null) {
+ timeProvider.onSeekComplete(mMediaPlayer);
}
return;
+ }
case MEDIA_SET_VIDEO_SIZE:
+ {
final int width = msg.arg1;
final int height = msg.arg2;
synchronized (mEventCbLock) {
@@ -2755,8 +2755,10 @@
}
}
return;
+ }
case MEDIA_ERROR:
+ {
Log.e(TAG, "Error (" + msg.arg1 + "," + msg.arg2 + ")");
synchronized (mEventCbLock) {
for (Pair<Executor, MediaPlayer2EventCallback> cb : mEventCallbackRecords) {
@@ -2768,8 +2770,10 @@
}
stayAwake(false);
return;
+ }
case MEDIA_INFO:
+ {
switch (msg.arg1) {
case MEDIA_INFO_STARTED_AS_NEXT:
if (srcId == mCurrentSrcId) {
@@ -2817,15 +2821,19 @@
}
// No real default action so far.
return;
+ }
case MEDIA_NOTIFY_TIME:
- TimeProvider timeProvider = mTimeProvider;
- if (timeProvider != null) {
- timeProvider.onNotifyTime();
- }
+ {
+ TimeProvider timeProvider = mTimeProvider;
+ if (timeProvider != null) {
+ timeProvider.onNotifyTime();
+ }
return;
+ }
case MEDIA_TIMED_TEXT:
+ {
final TimedText text;
if (msg.obj instanceof Parcel) {
Parcel parcel = (Parcel)msg.obj;
@@ -2841,8 +2849,10 @@
}
}
return;
+ }
case MEDIA_SUBTITLE_DATA:
+ {
OnSubtitleDataListener onSubtitleDataListener = mOnSubtitleDataListener;
if (onSubtitleDataListener == null) {
return;
@@ -2854,8 +2864,10 @@
onSubtitleDataListener.onSubtitleData(mMediaPlayer, data);
}
return;
+ }
case MEDIA_META_DATA:
+ {
final TimedMetaData data;
if (msg.obj instanceof Parcel) {
Parcel parcel = (Parcel) msg.obj;
@@ -2872,11 +2884,15 @@
}
}
return;
+ }
case MEDIA_NOP: // interface test message - ignore
+ {
break;
+ }
case MEDIA_AUDIO_ROUTING_CHANGED:
+ {
AudioManager.resetAudioPortGeneration();
synchronized (mRoutingChangeListeners) {
for (NativeRoutingEventHandlerDelegate delegate
@@ -2885,11 +2901,14 @@
}
}
return;
+ }
default:
+ {
Log.e(TAG, "Unknown message type " + msg.what);
return;
}
+ }
}
}
@@ -3184,7 +3203,7 @@
try {
// only creating the DRM object to allow pre-openSession configuration
- prepareDrm(uuid);
+ prepareDrm_createDrmStep(uuid);
} catch (Exception e) {
Log.w(TAG, "prepareDrm(): Exception ", e);
mPrepareDrmInProgress = false;
diff --git a/media/java/android/media/MediaPlayerBase.java b/media/java/android/media/MediaPlayerBase.java
index 3739847..24274f1 100644
--- a/media/java/android/media/MediaPlayerBase.java
+++ b/media/java/android/media/MediaPlayerBase.java
@@ -114,6 +114,11 @@
public abstract void pause();
/**
+ * Resets the MediaPlayerBase to its uninitialized state.
+ */
+ public abstract void reset();
+
+ /**
*
*/
public abstract void skipToNext();
diff --git a/media/java/android/media/MediaSession2.java b/media/java/android/media/MediaSession2.java
index ae5a8c6..d94be66 100644
--- a/media/java/android/media/MediaSession2.java
+++ b/media/java/android/media/MediaSession2.java
@@ -24,7 +24,6 @@
import android.content.Context;
import android.content.Intent;
import android.media.MediaPlayerBase.PlayerEventCallback;
-import android.media.MediaPlaylistController;
import android.media.session.MediaSession;
import android.media.session.MediaSession.Callback;
import android.media.session.PlaybackState;
@@ -82,10 +81,6 @@
public class MediaSession2 implements AutoCloseable, MediaPlaylistController {
private final MediaSession2Provider mProvider;
- // TODO(jaewan): Should we define IntDef? Currently we don't have to allow subclass to add more.
- // TODO(jaewan): Shouldn't we pull out?
- // TODO(jaewan): Should we also protect getters not related with metadata?
- // Getters are getPlaybackState(), getSessionActivity(), getPlaylistParams()
// Next ID: 23
/**
* Command code for the custom command which can be defined by string action in the
@@ -97,7 +92,7 @@
* Command code for {@link MediaController2#play()}.
* <p>
* Command would be sent directly to the player if the session doesn't reject the request
- * through the {@link SessionCallback#onCommandRequest(ControllerInfo, Command)}.
+ * through the {@link SessionCallback#onCommandRequest(MediaSession2, ControllerInfo, Command)}.
*/
public static final int COMMAND_CODE_PLAYBACK_PLAY = 1;
@@ -105,7 +100,7 @@
* Command code for {@link MediaController2#pause()}.
* <p>
* Command would be sent directly to the player if the session doesn't reject the request
- * through the {@link SessionCallback#onCommandRequest(ControllerInfo, Command)}.
+ * through the {@link SessionCallback#onCommandRequest(MediaSession2, ControllerInfo, Command)}.
*/
public static final int COMMAND_CODE_PLAYBACK_PAUSE = 2;
@@ -113,7 +108,7 @@
* Command code for {@link MediaController2#stop()}.
* <p>
* Command would be sent directly to the player if the session doesn't reject the request
- * through the {@link SessionCallback#onCommandRequest(ControllerInfo, Command)}.
+ * through the {@link SessionCallback#onCommandRequest(MediaSession2, ControllerInfo, Command)}.
*/
public static final int COMMAND_CODE_PLAYBACK_STOP = 3;
@@ -121,7 +116,7 @@
* Command code for {@link MediaController2#skipToNext()}.
* <p>
* Command would be sent directly to the player if the session doesn't reject the request
- * through the {@link SessionCallback#onCommandRequest(ControllerInfo, Command)}.
+ * through the {@link SessionCallback#onCommandRequest(MediaSession2, ControllerInfo, Command)}.
*/
public static final int COMMAND_CODE_PLAYBACK_SKIP_NEXT_ITEM = 4;
@@ -129,7 +124,7 @@
* Command code for {@link MediaController2#skipToPrevious()}.
* <p>
* Command would be sent directly to the player if the session doesn't reject the request
- * through the {@link SessionCallback#onCommandRequest(ControllerInfo, Command)}.
+ * through the {@link SessionCallback#onCommandRequest(MediaSession2, ControllerInfo, Command)}.
*/
public static final int COMMAND_CODE_PLAYBACK_SKIP_PREV_ITEM = 5;
@@ -137,7 +132,7 @@
* Command code for {@link MediaController2#prepare()}.
* <p>
* Command would be sent directly to the player if the session doesn't reject the request
- * through the {@link SessionCallback#onCommandRequest(ControllerInfo, Command)}.
+ * through the {@link SessionCallback#onCommandRequest(MediaSession2, ControllerInfo, Command)}.
*/
public static final int COMMAND_CODE_PLAYBACK_PREPARE = 6;
@@ -146,7 +141,7 @@
* <p>
* This is transport control command. Command would be sent directly to the player if the
* session doesn't reject the request through the
- * {@link SessionCallback#onCommandRequest(ControllerInfo, Command)}.
+ * {@link SessionCallback#onCommandRequest(MediaSession2, ControllerInfo, Command)}.
*/
public static final int COMMAND_CODE_PLAYBACK_FAST_FORWARD = 7;
@@ -154,7 +149,7 @@
* Command code for {@link MediaController2#rewind()}.
* <p>
* Command would be sent directly to the player if the session doesn't reject the request
- * through the {@link SessionCallback#onCommandRequest(ControllerInfo, Command)}.
+ * through the {@link SessionCallback#onCommandRequest(MediaSession2, ControllerInfo, Command)}.
*/
public static final int COMMAND_CODE_PLAYBACK_REWIND = 8;
@@ -162,14 +157,14 @@
* Command code for {@link MediaController2#seekTo(long)}.
* <p>
* Command would be sent directly to the player if the session doesn't reject the request
- * through the {@link SessionCallback#onCommandRequest(ControllerInfo, Command)}.
+ * through the {@link SessionCallback#onCommandRequest(MediaSession2, ControllerInfo, Command)}.
*/
public static final int COMMAND_CODE_PLAYBACK_SEEK_TO = 9;
/**
* Command code for {@link MediaController2#skipToPlaylistItem(MediaItem2)}.
* <p>
* Command would be sent directly to the player if the session doesn't reject the request
- * through the {@link SessionCallback#onCommandRequest(ControllerInfo, Command)}.
+ * through the {@link SessionCallback#onCommandRequest(MediaSession2, ControllerInfo, Command)}.
*/
public static final int COMMAND_CODE_PLAYBACK_SKIP_TO_PLAYLIST_ITEM = 10;
@@ -177,7 +172,7 @@
* Command code for {@link MediaController2#setPlaylistParams(PlaylistParams)}.
* <p>
* Command would be sent directly to the player if the session doesn't reject the request
- * through the {@link SessionCallback#onCommandRequest(ControllerInfo, Command)}.
+ * through the {@link SessionCallback#onCommandRequest(MediaSession2, ControllerInfo, Command)}.
*/
public static final int COMMAND_CODE_PLAYBACK_SET_PLAYLIST_PARAMS = 11;
@@ -185,7 +180,7 @@
* Command code for {@link MediaController2#addPlaylistItem(int, MediaItem2)}.
* <p>
* Command would be sent directly to the player if the session doesn't reject the request
- * through the {@link SessionCallback#onCommandRequest(ControllerInfo, Command)}.
+ * through the {@link SessionCallback#onCommandRequest(MediaSession2, ControllerInfo, Command)}.
*/
public static final int COMMAND_CODE_PLAYLIST_ADD = 12;
@@ -193,7 +188,7 @@
* Command code for {@link MediaController2#addPlaylistItem(int, MediaItem2)}.
* <p>
* Command would be sent directly to the player if the session doesn't reject the request
- * through the {@link SessionCallback#onCommandRequest(ControllerInfo, Command)}.
+ * through the {@link SessionCallback#onCommandRequest(MediaSession2, ControllerInfo, Command)}.
*/
public static final int COMMAND_CODE_PLAYLIST_REMOVE = 13;
@@ -201,7 +196,7 @@
* Command code for {@link MediaController2#getPlaylist()}.
* <p>
* Command would be sent directly to the player if the session doesn't reject the request
- * through the {@link SessionCallback#onCommandRequest(ControllerInfo, Command)}.
+ * through the {@link SessionCallback#onCommandRequest(MediaSession2, ControllerInfo, Command)}.
*/
public static final int COMMAND_CODE_PLAYLIST_GET = 14;
@@ -211,7 +206,7 @@
* <p>
* Command would adjust the volume or sent to the volume provider directly if the session
* doesn't reject the request through the
- * {@link SessionCallback#onCommandRequest(ControllerInfo, Command)}.
+ * {@link SessionCallback#onCommandRequest(MediaSession2, ControllerInfo, Command)}.
*/
public static final int COMMAND_CODE_SET_VOLUME = 15;
@@ -339,7 +334,6 @@
* If {@link #getCommandCode()} is {@link #COMMAND_CODE_CUSTOM}), it's custom command and
* {@link #getCustomCommand()} shouldn't be {@code null}.
*/
- // TODO(jaewan): Move this into the updatable.
public static final class Command {
private final CommandProvider mProvider;
@@ -435,8 +429,7 @@
}
public List<Command> getCommands() {
- // TODO: implement this
- return null;
+ return mProvider.getCommands_impl();
}
/**
@@ -470,7 +463,7 @@
* If it's not set, the session will accept all controllers and all incoming commands by
* default.
*/
- // TODO(jaewan): Can we move this inside of the updatable for default implementation.
+ // TODO(jaewan): Move this to updatable for default implementation (b/74091963)
public static abstract class SessionCallback {
private final Context mContext;
@@ -483,13 +476,15 @@
* controller. By default it allows all connection requests and commands.
* <p>
* You can reject the connection by return {@code null}. In that case, controller receives
- * {@link MediaController2.ControllerCallback#onDisconnected()} and cannot be usable.
+ * {@link MediaController2.ControllerCallback#onDisconnected(MediaController2)} and cannot
+ * be usable.
*
+ * @param session the session for this event
* @param controller controller information.
* @return allowed commands. Can be {@code null} to reject coonnection.
*/
- // TODO(jaewan): Change return type. Once we do, null is for reject.
- public @Nullable CommandGroup onConnect(@NonNull ControllerInfo controller) {
+ public @Nullable CommandGroup onConnect(@NonNull MediaSession2 session,
+ @NonNull ControllerInfo controller) {
CommandGroup commands = new CommandGroup(mContext);
commands.addAllPredefinedCommands();
return commands;
@@ -498,14 +493,17 @@
/**
* Called when a controller is disconnected
*
+ * @param session the session for this event
* @param controller controller information
*/
- public void onDisconnected(@NonNull ControllerInfo controller) { }
+ public void onDisconnected(@NonNull MediaSession2 session,
+ @NonNull ControllerInfo controller) { }
/**
* Called when a controller sent a command that will be sent directly to the player. Return
* {@code false} here to reject the request and stop sending command to the player.
*
+ * @param session the session for this event
* @param controller controller information.
* @param command a command. This method will be called for every single command.
* @return {@code true} if you want to accept incoming command. {@code false} otherwise.
@@ -525,8 +523,8 @@
* @see #COMMAND_CODE_PLAYLIST_GET
* @see #COMMAND_CODE_SET_VOLUME
*/
- public boolean onCommandRequest(@NonNull ControllerInfo controller,
- @NonNull Command command) {
+ public boolean onCommandRequest(@NonNull MediaSession2 session,
+ @NonNull ControllerInfo controller, @NonNull Command command) {
return true;
}
@@ -539,37 +537,41 @@
* in order to provide possible rating style for controller. Controller will follow the
* rating style.
*
+ * @param session the session for this event
* @param controller controller information
* @param mediaId media id from the controller
* @param rating new rating from the controller
*/
- public void onSetRating(@NonNull ControllerInfo controller, @NonNull String mediaId,
- @NonNull Rating2 rating) { }
+ public void onSetRating(@NonNull MediaSession2 session, @NonNull ControllerInfo controller,
+ @NonNull String mediaId, @NonNull Rating2 rating) { }
/**
* Called when a controller sent a custom command through
* {@link MediaController2#sendCustomCommand(Command, Bundle, ResultReceiver)}.
*
+ * @param session the session for this event
* @param controller controller information
* @param customCommand custom command.
* @param args optional arguments
* @param cb optional result receiver
*/
- public void onCustomCommand(@NonNull ControllerInfo controller,
- @NonNull Command customCommand, @Nullable Bundle args,
- @Nullable ResultReceiver cb) { }
+ public void onCustomCommand(@NonNull MediaSession2 session,
+ @NonNull ControllerInfo controller, @NonNull Command customCommand,
+ @Nullable Bundle args, @Nullable ResultReceiver cb) { }
/**
* Called when a controller requested to play a specific mediaId through
* {@link MediaController2#playFromMediaId(String, Bundle)}.
*
+ * @param session the session for this event
* @param controller controller information
* @param mediaId media id
* @param extras optional extra bundle
* @see #COMMAND_CODE_PLAY_FROM_MEDIA_ID
*/
- public void onPlayFromMediaId(@NonNull ControllerInfo controller,
- @NonNull String mediaId, @Nullable Bundle extras) { }
+ public void onPlayFromMediaId(@NonNull MediaSession2 session,
+ @NonNull ControllerInfo controller, @NonNull String mediaId,
+ @Nullable Bundle extras) { }
/**
* Called when a controller requested to begin playback from a search query through
@@ -578,25 +580,29 @@
* An empty query indicates that the app may play any music. The implementation should
* attempt to make a smart choice about what to play.
*
+ * @param session the session for this event
* @param controller controller information
* @param query query string. Can be empty to indicate any suggested media
* @param extras optional extra bundle
* @see #COMMAND_CODE_PLAY_FROM_SEARCH
*/
- public void onPlayFromSearch(@NonNull ControllerInfo controller,
- @NonNull String query, @Nullable Bundle extras) { }
+ public void onPlayFromSearch(@NonNull MediaSession2 session,
+ @NonNull ControllerInfo controller, @NonNull String query,
+ @Nullable Bundle extras) { }
/**
* Called when a controller requested to play a specific media item represented by a URI
* through {@link MediaController2#playFromUri(Uri, Bundle)}
*
+ * @param session the session for this event
* @param controller controller information
* @param uri uri
* @param extras optional extra bundle
* @see #COMMAND_CODE_PLAY_FROM_URI
*/
- public void onPlayFromUri(@NonNull ControllerInfo controller,
- @NonNull Uri uri, @Nullable Bundle extras) { }
+ public void onPlayFromUri(@NonNull MediaSession2 session,
+ @NonNull ControllerInfo controller, @NonNull Uri uri,
+ @Nullable Bundle extras) { }
/**
* Called when a controller requested to prepare for playing a specific mediaId through
@@ -612,13 +618,15 @@
* Override {@link #onPlayFromMediaId} to handle requests for starting
* playback without preparation.
*
+ * @param session the session for this event
* @param controller controller information
* @param mediaId media id to prepare
* @param extras optional extra bundle
* @see #COMMAND_CODE_PREPARE_FROM_MEDIA_ID
*/
- public void onPrepareFromMediaId(@NonNull ControllerInfo controller,
- @NonNull String mediaId, @Nullable Bundle extras) { }
+ public void onPrepareFromMediaId(@NonNull MediaSession2 session,
+ @NonNull ControllerInfo controller, @NonNull String mediaId,
+ @Nullable Bundle extras) { }
/**
* Called when a controller requested to prepare playback from a search query through
@@ -634,13 +642,15 @@
* Override {@link #onPlayFromSearch} to handle requests for starting playback without
* preparation.
*
+ * @param session the session for this event
* @param controller controller information
* @param query query string. Can be empty to indicate any suggested media
* @param extras optional extra bundle
* @see #COMMAND_CODE_PREPARE_FROM_SEARCH
*/
- public void onPrepareFromSearch(@NonNull ControllerInfo controller,
- @NonNull String query, @Nullable Bundle extras) { }
+ public void onPrepareFromSearch(@NonNull MediaSession2 session,
+ @NonNull ControllerInfo controller, @NonNull String query,
+ @Nullable Bundle extras) { }
/**
* Called when a controller requested to prepare a specific media item represented by a URI
@@ -656,13 +666,14 @@
* Override {@link #onPlayFromUri} to handle requests for starting playback without
* preparation.
*
+ * @param session the session for this event
* @param controller controller information
* @param uri uri
* @param extras optional extra bundle
* @see #COMMAND_CODE_PREPARE_FROM_URI
*/
- public void onPrepareFromUri(@NonNull ControllerInfo controller,
- @NonNull Uri uri, @Nullable Bundle extras) { }
+ public void onPrepareFromUri(@NonNull MediaSession2 session,
+ @NonNull ControllerInfo controller, @NonNull Uri uri, @Nullable Bundle extras) { }
};
/**
@@ -698,7 +709,7 @@
* @param player a {@link MediaPlayerBase} that handles actual media playback in your app.
*/
U setPlayer(@NonNull MediaPlayerBase player) {
- // TODO: Change the provider properly
+ // TODO(jaewan): Change the provider properly (b/74093082)
mProvider.setPlayer_impl(player, null, null);
return (U) this;
}
@@ -711,7 +722,7 @@
* {@code player.}
*/
U setPlaylistController(@NonNull MediaPlaylistController mplc) {
- // TODO: implement this
+ // TODO(jaewan): implement this (b/74093082)
return (U) this;
}
@@ -722,7 +733,7 @@
* @param volumeProvider The provider that will receive volume button events.
*/
U setVolumeProvider(@NonNull VolumeProvider2 volumeProvider) {
- // TODO: implement this
+ // TODO(jaewan): implement this (b/74093082)
return (U) this;
}
@@ -847,7 +858,6 @@
/**
* @hide
*/
- // TODO(jaewan): Also accept componentName to check notificaiton listener.
public ControllerInfo(Context context, int uid, int pid, String packageName,
IInterface callback) {
mProvider = ApiLoader.getProvider(context)
@@ -894,18 +904,12 @@
@Override
public boolean equals(Object obj) {
- if (!(obj instanceof ControllerInfo)) {
- return false;
- }
- ControllerInfo other = (ControllerInfo) obj;
- return mProvider.equals_impl(other.mProvider);
+ return mProvider.equals_impl(obj);
}
@Override
public String toString() {
- // TODO(jaewan): Move this to updatable.
- return "ControllerInfo {pkg=" + getPackageName() + ", uid=" + getUid() + ", trusted="
- + isTrusted() + "}";
+ return mProvider.toString_impl();
}
}
@@ -1175,14 +1179,13 @@
*
* @param player a {@link MediaPlayerBase} that handles actual media playback in your app.
* @param mplc a {@link MediaPlaylistController} that manages playlist of the
- * {@code player.}
+ * {@code player}
* @param volumeProvider The provider that will receive volume button events. If
* {@code null}, system will adjust the appropriate stream volume for this session's player.
*/
public void updatePlayer(@NonNull MediaPlayerBase player,
- @Nullable MediaPlaylistController mplc, @NonNull VolumeProvider2 volumeProvider) {
- // TODO: rename setPlayer_impl to updatePlayer_impl
- mProvider.setPlayer_impl(player, mplc, volumeProvider);
+ @Nullable MediaPlaylistController mplc, @Nullable VolumeProvider2 volumeProvider) {
+ mProvider.updatePlayer_impl(player, mplc, volumeProvider);
}
@Override
@@ -1201,19 +1204,16 @@
/**
* @return playlist controller
*/
- public @Nullable
- MediaPlaylistController getMediaPlaylistController() {
- // TODO: implement this
+ public @Nullable MediaPlaylistController getMediaPlaylistController() {
+ // TODO(jaewan): implement this (b/74090741)
return null;
}
/**
* @return volume provider
*/
- public @Nullable
- VolumeProvider2 getVolumeProvider() {
- // TODO: implement this
- return null;
+ public @Nullable VolumeProvider2 getVolumeProvider() {
+ return mProvider.getVolumeProvider_impl();
}
/**
@@ -1234,7 +1234,7 @@
* @param afr the full request parameters
*/
public void setAudioFocusRequest(AudioFocusRequest afr) {
- // TODO: implement this
+ // TODO(jaewan): implement this (b/72529899)
// mProvider.setAudioFocusRequest_impl(focusGain);
}
@@ -1252,7 +1252,7 @@
* expanded row: layout[5] layout[6] layout[7] layout[8] layout[9]
* main row: layout[3] layout[1] layout[0] layout[2] layout[4]
* <p>
- * This API can be called in the {@link SessionCallback#onConnect(ControllerInfo)}.
+ * This API can be called in the {@link SessionCallback#onConnect(MediaSession2, ControllerInfo)}.
*
* @param controller controller to specify layout.
* @param layout oredered list of layout.
@@ -1408,8 +1408,6 @@
*
* @throws IllegalArgumentException if the play list is null
*/
- // TODO(jaewan): Remove with index was previously rejected by council (b/36524925)
- // TODO(jaewan): Should we also add movePlaylistItem from index to index?
public void removePlaylistItem(MediaItem2 item) {
mProvider.removePlaylistItem_impl(item);
}
@@ -1500,7 +1498,7 @@
* @throws IllegalArgumentException if executor or callback is {@code null}.
* @hide
*/
- // TODO(jaewan): Unhide or remove
+ // TODO(jaewan): Remove (b/74157064)
public void registerPlayerEventCallback(@NonNull @CallbackExecutor Executor executor,
@NonNull PlayerEventCallback callback) {
mProvider.registerPlayerEventCallback_impl(executor, callback);
@@ -1513,7 +1511,7 @@
* @throws IllegalArgumentException if the callback is {@code null}.
* @hide
*/
- // TODO(jaewan): Unhide or remove
+ // TODO(jaewan): Remove (b/74157064)
public void unregisterPlayerEventCallback(@NonNull PlayerEventCallback callback) {
mProvider.unregisterPlayerEventCallback_impl(callback);
}
@@ -1534,7 +1532,7 @@
* @return speed
*/
public float getPlaybackSpeed() {
- // TODO: implement this
+ // TODO(jaewan): implement this (b/74093080)
return -1;
}
@@ -1542,6 +1540,6 @@
* Set the playback speed.
*/
public void setPlaybackSpeed(float speed) {
- // TODO: implement this
+ // TODO(jaewan): implement this (b/74093080)
}
}
diff --git a/media/java/android/media/MediaSessionService2.java b/media/java/android/media/MediaSessionService2.java
index 56e8e5d..9032e0e 100644
--- a/media/java/android/media/MediaSessionService2.java
+++ b/media/java/android/media/MediaSessionService2.java
@@ -85,7 +85,8 @@
* session service, the controller binds to the session service. {@link #onCreateSession(String)}
* may be called after the {@link #onCreate} if the service hasn't created yet.
* <p>
- * After the binding, session's {@link MediaSession2.SessionCallback#onConnect(ControllerInfo)}
+ * After the binding, session's {@link MediaSession2.SessionCallback#onConnect(MediaSession2, ControllerInfo)}
+ *
* will be called to accept or reject connection request from a controller. If the connection is
* rejected, the controller will unbind. If it's accepted, the controller will be available to use
* and keep binding.
@@ -99,7 +100,7 @@
* <p>
* Any app can bind to the session service with controller, but the controller can be used only if
* the session service accepted the connection request through
- * {@link MediaSession2.SessionCallback#onConnect(ControllerInfo)}.
+ * {@link MediaSession2.SessionCallback#onConnect(MediaSession2, ControllerInfo)}.
*/
public abstract class MediaSessionService2 extends Service {
private final MediaSessionService2Provider mProvider;
diff --git a/media/java/android/media/PlaybackState2.java b/media/java/android/media/PlaybackState2.java
index 7afb579..afc2bfa 100644
--- a/media/java/android/media/PlaybackState2.java
+++ b/media/java/android/media/PlaybackState2.java
@@ -33,7 +33,7 @@
* the current playback position and extra.
* @hide
*/
-// TODO(jaewan): Remove this.
+// TODO(jaewan): Remove this (b/73971431)
public final class PlaybackState2 {
// Similar to the PlaybackState with following changes
// - Not implement Parcelable and added from/toBundle()
@@ -76,7 +76,6 @@
// - Removed actions and custom actions.
// - Removed error string
// - Repeat mode / shuffle mode is now in the PlaylistParams
- // TODO(jaewan): Replace states from MediaPlayer2
/**
* @hide
*/
diff --git a/media/java/android/media/update/MediaSession2Provider.java b/media/java/android/media/update/MediaSession2Provider.java
index d0ec104..f97a6f0 100644
--- a/media/java/android/media/update/MediaSession2Provider.java
+++ b/media/java/android/media/update/MediaSession2Provider.java
@@ -44,9 +44,10 @@
*/
public interface MediaSession2Provider extends TransportControlProvider {
void close_impl();
- void setPlayer_impl(MediaPlayerBase player, MediaPlaylistController mplc,
+ void updatePlayer_impl(MediaPlayerBase player, MediaPlaylistController mplc,
VolumeProvider2 volumeProvider);
MediaPlayerBase getPlayer_impl();
+ VolumeProvider2 getVolumeProvider_impl();
SessionToken2 getToken_impl();
List<ControllerInfo> getConnectedControllers_impl();
void setCustomLayout_impl(ControllerInfo controller, List<CommandButton> layout);
@@ -84,6 +85,7 @@
void removeCommand_impl(Command command);
boolean hasCommand_impl(Command command);
boolean hasCommand_impl(int code);
+ List<Command> getCommands_impl();
Bundle toBundle_impl();
}
@@ -109,7 +111,8 @@
int getUid_impl();
boolean isTrusted_impl();
int hashCode_impl();
- boolean equals_impl(ControllerInfoProvider obj);
+ boolean equals_impl(Object obj);
+ String toString_impl();
}
interface PlaylistParamsProvider {
diff --git a/media/jni/android_media_MediaPlayer2.cpp b/media/jni/android_media_MediaPlayer2.cpp
index b0936fb..af78777 100644
--- a/media/jni/android_media_MediaPlayer2.cpp
+++ b/media/jni/android_media_MediaPlayer2.cpp
@@ -777,6 +777,16 @@
}
static jint
+android_media_MediaPlayer2_getMediaPlayer2State(JNIEnv *env, jobject thiz)
+{
+ sp<MediaPlayer2> mp = getMediaPlayer(env, thiz);
+ if (mp == NULL) {
+ return MEDIAPLAYER2_STATE_IDLE;
+ }
+ return (jint)mp->getMediaPlayer2State();
+}
+
+static jint
android_media_MediaPlayer2_getVideoWidth(JNIEnv *env, jobject thiz)
{
sp<MediaPlayer2> mp = getMediaPlayer(env, thiz);
@@ -1483,6 +1493,7 @@
{"prepare", "()V", (void *)android_media_MediaPlayer2_prepare},
{"_start", "()V", (void *)android_media_MediaPlayer2_start},
{"_stop", "()V", (void *)android_media_MediaPlayer2_stop},
+ {"native_getMediaPlayer2State", "()I", (void *)android_media_MediaPlayer2_getMediaPlayer2State},
{"getVideoWidth", "()I", (void *)android_media_MediaPlayer2_getVideoWidth},
{"getVideoHeight", "()I", (void *)android_media_MediaPlayer2_getVideoHeight},
{"native_getMetrics", "()Landroid/os/PersistableBundle;", (void *)android_media_MediaPlayer2_native_getMetrics},
diff --git a/native/android/asset_manager.cpp b/native/android/asset_manager.cpp
index 98e9a42..e70d5ea 100644
--- a/native/android/asset_manager.cpp
+++ b/native/android/asset_manager.cpp
@@ -18,9 +18,11 @@
#include <utils/Log.h>
#include <android/asset_manager_jni.h>
+#include <android_runtime/android_util_AssetManager.h>
#include <androidfw/Asset.h>
#include <androidfw/AssetDir.h>
#include <androidfw/AssetManager.h>
+#include <androidfw/AssetManager2.h>
#include <utils/threads.h>
#include "jni.h"
@@ -35,21 +37,20 @@
// -----
struct AAssetDir {
- AssetDir* mAssetDir;
+ std::unique_ptr<AssetDir> mAssetDir;
size_t mCurFileIndex;
String8 mCachedFileName;
- explicit AAssetDir(AssetDir* dir) : mAssetDir(dir), mCurFileIndex(0) { }
- ~AAssetDir() { delete mAssetDir; }
+ explicit AAssetDir(std::unique_ptr<AssetDir> dir) :
+ mAssetDir(std::move(dir)), mCurFileIndex(0) { }
};
// -----
struct AAsset {
- Asset* mAsset;
+ std::unique_ptr<Asset> mAsset;
- explicit AAsset(Asset* asset) : mAsset(asset) { }
- ~AAsset() { delete mAsset; }
+ explicit AAsset(std::unique_ptr<Asset> asset) : mAsset(std::move(asset)) { }
};
// -------------------- Public native C API --------------------
@@ -104,19 +105,18 @@
return NULL;
}
- AssetManager* mgr = static_cast<AssetManager*>(amgr);
- Asset* asset = mgr->open(filename, amMode);
- if (asset == NULL) {
- return NULL;
+ ScopedLock<AssetManager2> locked_mgr(*AssetManagerForNdkAssetManager(amgr));
+ std::unique_ptr<Asset> asset = locked_mgr->Open(filename, amMode);
+ if (asset == nullptr) {
+ return nullptr;
}
-
- return new AAsset(asset);
+ return new AAsset(std::move(asset));
}
AAssetDir* AAssetManager_openDir(AAssetManager* amgr, const char* dirName)
{
- AssetManager* mgr = static_cast<AssetManager*>(amgr);
- return new AAssetDir(mgr->openDir(dirName));
+ ScopedLock<AssetManager2> locked_mgr(*AssetManagerForNdkAssetManager(amgr));
+ return new AAssetDir(locked_mgr->OpenDir(dirName));
}
/**
diff --git a/native/android/configuration.cpp b/native/android/configuration.cpp
index 77237ae..87fe9ed 100644
--- a/native/android/configuration.cpp
+++ b/native/android/configuration.cpp
@@ -17,9 +17,10 @@
#define LOG_TAG "Configuration"
#include <utils/Log.h>
-#include <androidfw/AssetManager.h>
+#include <androidfw/AssetManager2.h>
#include <android_runtime/android_content_res_Configuration.h>
+#include <android_runtime/android_util_AssetManager.h>
using namespace android;
@@ -34,7 +35,11 @@
}
void AConfiguration_fromAssetManager(AConfiguration* out, AAssetManager* am) {
- ((AssetManager*)am)->getConfiguration(out);
+ ScopedLock<AssetManager2> locked_mgr(*AssetManagerForNdkAssetManager(am));
+ ResTable_config config = locked_mgr->GetConfiguration();
+
+ // AConfiguration is not a virtual subclass, so we can memcpy.
+ memcpy(out, &config, sizeof(config));
}
void AConfiguration_copy(AConfiguration* dest, AConfiguration* src) {
diff --git a/nfc-extras/Android.mk b/nfc-extras/Android.mk
index dc45a50..03de00c 100644
--- a/nfc-extras/Android.mk
+++ b/nfc-extras/Android.mk
@@ -1,13 +1,33 @@
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
-
+LOCAL_MODULE := com.android.nfc_extras
LOCAL_MODULE_TAGS := optional
-
-LOCAL_SRC_FILES := $(call all-java-files-under, java)
-
-LOCAL_MODULE:= com.android.nfc_extras
-
+LOCAL_SRC_FILES := $(call all-java-files-under,java)
include $(BUILD_JAVA_LIBRARY)
+include $(CLEAR_VARS)
+LOCAL_MODULE := com.android.nfc_extras-stubs-gen
+LOCAL_MODULE_CLASS := JAVA_LIBRARIES
+LOCAL_SRC_FILES := $(call all-java-files-under,java)
+# This is to reference SdkConstant annotation; not part of this lib.
+LOCAL_DROIDDOC_SOURCE_PATH := frameworks/base/core/java/android/annotation
+LOCAL_DROIDDOC_STUB_OUT_DIR := $(TARGET_OUT_COMMON_INTERMEDIATES)/JAVA_LIBRARIES/com.android.nfc_extras.stubs_intermediates/src
+LOCAL_DROIDDOC_OPTIONS:= \
+ -hide 111 -hide 113 -hide 125 -hide 126 -hide 127 -hide 128 \
+ -stubpackages com.android.nfc_extras \
+ -nodocs
+LOCAL_UNINSTALLABLE_MODULE := true
+include $(BUILD_DROIDDOC)
+com_android_nfc_extras_gen_stamp := $(full_target)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := com.android.nfc_extras.stubs
+# This is to reference SdkConstant annotation; not part of this lib.
+LOCAL_SRC_FILES := ../core/java/android/annotation/SdkConstant.java
+LOCAL_SDK_VERSION := current
+LOCAL_ADDITIONAL_DEPENDENCIES := $(com_android_nfc_extras_gen_stamp)
+com_android_nfc_extras_gen_stamp :=
+include $(BUILD_STATIC_JAVA_LIBRARY)
+
include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/nfc-extras/tests/Android.mk b/nfc-extras/tests/Android.mk
index 51396d3..8bba3ba 100644
--- a/nfc-extras/tests/Android.mk
+++ b/nfc-extras/tests/Android.mk
@@ -20,7 +20,7 @@
LOCAL_JAVA_LIBRARIES := \
android.test.runner.stubs \
- com.android.nfc_extras \
+ com.android.nfc_extras.stubs \
android.test.base.stubs
LOCAL_STATIC_JAVA_LIBRARIES := junit
diff --git a/packages/SettingsLib/res/values-af/strings.xml b/packages/SettingsLib/res/values-af/strings.xml
index c166016..1d72349 100644
--- a/packages/SettingsLib/res/values-af/strings.xml
+++ b/packages/SettingsLib/res/values-af/strings.xml
@@ -220,7 +220,8 @@
<string name="select_private_dns_configuration_title" msgid="3700456559305263922">"Private DNS"</string>
<string name="select_private_dns_configuration_dialog_title" msgid="9221994415765826811">"Kies private DNS-modus"</string>
<string name="private_dns_mode_off" msgid="8236575187318721684">"Af"</string>
- <string name="private_dns_mode_opportunistic" msgid="7608409735589131766">"Opportunisties"</string>
+ <!-- no translation found for private_dns_mode_opportunistic (8314986739896927399) -->
+ <skip />
<string name="private_dns_mode_provider" msgid="8354935160639360804">"Gasheernaam van private DNS-verskaffer"</string>
<string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"Voer gasheernaam van DNS-verskaffer in"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Wys opsies vir draadlose skermsertifisering"</string>
@@ -356,22 +357,41 @@
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Hierdie kenmerk is eksperimenteel en kan werkverrigting beïnvloed."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"Geneutraliseer deur <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="power_remaining_duration_only" msgid="845431008899029842">"Omtrent <xliff:g id="TIME">%1$s</xliff:g> oor"</string>
+ <!-- no translation found for power_discharging_duration (6655472132189365839) -->
+ <skip />
<string name="power_remaining_duration_only_enhanced" msgid="5992456722677973678">"Ongeveer <xliff:g id="TIME">%1$s</xliff:g> oor gegrond op jou gebruik"</string>
- <string name="power_remaining_charging_duration_only" msgid="1421102457410268886">"<xliff:g id="TIME">%1$s</xliff:g> oor tot vol gelaai"</string>
+ <!-- no translation found for power_discharging_duration_enhanced (5726302316642148671) -->
+ <skip />
<string name="power_remaining_duration_only_short" msgid="5329694252258605547">"<xliff:g id="TIME">%1$s</xliff:g> oor"</string>
+ <!-- no translation found for power_discharge_by_enhanced (8788299408879961465) -->
+ <skip />
+ <!-- no translation found for power_discharge_by_only_enhanced (7692297898877104416) -->
+ <skip />
+ <!-- no translation found for power_discharge_by (6427074755635635749) -->
+ <skip />
+ <!-- no translation found for power_discharge_by_only (5888058889261108064) -->
+ <skip />
<string name="power_remaining_less_than_duration_only" msgid="5996752448813295329">"Minder as <xliff:g id="THRESHOLD">%1$s</xliff:g> oor"</string>
- <string name="power_remaining_less_than_duration" msgid="7967078125657859046">"<xliff:g id="LEVEL">%1$s</xliff:g> – minder as <xliff:g id="THRESHOLD">%2$s</xliff:g> oor"</string>
- <string name="power_remaining_more_than_subtext" msgid="6846716609975752316">"<xliff:g id="LEVEL">%1$s</xliff:g>meer as <xliff:g id="TIME_REMAINING">%2$s</xliff:g> oor"</string>
- <string name="power_remaining_only_more_than_subtext" msgid="8884488700395194194">"meer as <xliff:g id="TIME_REMAINING">%1$s</xliff:g> oor"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="default" msgid="8168317165722752881">"foon kan binnekort afgaan"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="tablet" msgid="5957064378548718872">"tablet kan binnekort afgaan"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="device" msgid="9055596817716471373">"toestel kan binnekort afgaan"</string>
- <string name="power_discharging_duration" msgid="2843747179907396142">"<xliff:g id="LEVEL">%1$s</xliff:g> – omtrent <xliff:g id="TIME">%2$s</xliff:g> oor"</string>
- <string name="power_discharging_duration_enhanced" msgid="4401782117770255046">"<xliff:g id="LEVEL">%1$s</xliff:g> – ongeveer <xliff:g id="TIME">%2$s</xliff:g> oor gegrond op jou gebruik"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="default" msgid="7679005631124015335">"<xliff:g id="LEVEL">%1$s</xliff:g> – foon kan binnekort afgaan"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="tablet" msgid="261050880878965621">"<xliff:g id="LEVEL">%1$s</xliff:g> – tablet kan binnekort afgaan"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="device" msgid="2020049829798578618">"<xliff:g id="LEVEL">%1$s</xliff:g> – toestel kan binnekort afgaan"</string>
+ <!-- no translation found for power_remaining_less_than_duration (5751885147712659423) -->
+ <skip />
+ <!-- no translation found for power_remaining_more_than_subtext (3176771815132876675) -->
+ <skip />
+ <!-- no translation found for power_remaining_only_more_than_subtext (8931654680569617380) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (1181059207608751924) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (2606370266981054691) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (2918084807716859985) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (3090926004324573908) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (7466484148515796216) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (603933521600231649) -->
+ <skip />
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string>
+ <string name="power_remaining_charging_duration_only" msgid="1421102457410268886">"<xliff:g id="TIME">%1$s</xliff:g> oor tot vol gelaai"</string>
<string name="power_charging_duration" msgid="4676999980973411875">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> tot vol gelaai"</string>
<string name="battery_info_status_unknown" msgid="196130600938058547">"Onbekend"</string>
<string name="battery_info_status_charging" msgid="1705179948350365604">"Laai"</string>
diff --git a/packages/SettingsLib/res/values-am/strings.xml b/packages/SettingsLib/res/values-am/strings.xml
index 6c8c69a..a8b48aa 100644
--- a/packages/SettingsLib/res/values-am/strings.xml
+++ b/packages/SettingsLib/res/values-am/strings.xml
@@ -220,7 +220,8 @@
<string name="select_private_dns_configuration_title" msgid="3700456559305263922">"የግል ዲኤንኤስ"</string>
<string name="select_private_dns_configuration_dialog_title" msgid="9221994415765826811">"የግል ዲኤንኤስ ሁነታ ይምረጡ"</string>
<string name="private_dns_mode_off" msgid="8236575187318721684">"ጠፍቷል"</string>
- <string name="private_dns_mode_opportunistic" msgid="7608409735589131766">"አድርባይ"</string>
+ <!-- no translation found for private_dns_mode_opportunistic (8314986739896927399) -->
+ <skip />
<string name="private_dns_mode_provider" msgid="8354935160639360804">"የግል ዲኤንኤስ አቅራቢ አስተናጋጅ ስም"</string>
<string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"የዲኤንኤስ አቅራቢ አስተናጋጅ ስም ያስገቡ"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"የገመድ አልባ ማሳያ እውቅና ማረጋገጫ አማራጮችን አሳይ"</string>
@@ -356,22 +357,41 @@
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"ይህ ባህሪ የሙከራ ነውና አፈጻጸም ላይ ተጽዕኖ ሊኖረው ይችላል።"</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"በ<xliff:g id="TITLE">%1$s</xliff:g> ተሽሯል"</string>
<string name="power_remaining_duration_only" msgid="845431008899029842">"<xliff:g id="TIME">%1$s</xliff:g> አካባቢ ቀርቷል"</string>
+ <!-- no translation found for power_discharging_duration (6655472132189365839) -->
+ <skip />
<string name="power_remaining_duration_only_enhanced" msgid="5992456722677973678">"በእርስዎ አጠቃቀም ላይ በመመስረት <xliff:g id="TIME">%1$s</xliff:g> ገደማ ቀርቷል"</string>
- <string name="power_remaining_charging_duration_only" msgid="1421102457410268886">"ሙሉ ኃይል እስኪሞላ ድረስ <xliff:g id="TIME">%1$s</xliff:g>"</string>
+ <!-- no translation found for power_discharging_duration_enhanced (5726302316642148671) -->
+ <skip />
<string name="power_remaining_duration_only_short" msgid="5329694252258605547">"<xliff:g id="TIME">%1$s</xliff:g> ቀርቷል"</string>
+ <!-- no translation found for power_discharge_by_enhanced (8788299408879961465) -->
+ <skip />
+ <!-- no translation found for power_discharge_by_only_enhanced (7692297898877104416) -->
+ <skip />
+ <!-- no translation found for power_discharge_by (6427074755635635749) -->
+ <skip />
+ <!-- no translation found for power_discharge_by_only (5888058889261108064) -->
+ <skip />
<string name="power_remaining_less_than_duration_only" msgid="5996752448813295329">"ከ<xliff:g id="THRESHOLD">%1$s</xliff:g> ያነሰ ይቀራል"</string>
- <string name="power_remaining_less_than_duration" msgid="7967078125657859046">"<xliff:g id="LEVEL">%1$s</xliff:g> - ከ<xliff:g id="THRESHOLD">%2$s</xliff:g> በታች ይቀራል"</string>
- <string name="power_remaining_more_than_subtext" msgid="6846716609975752316">"<xliff:g id="LEVEL">%1$s</xliff:g>ከ<xliff:g id="TIME_REMAINING">%2$s</xliff:g> የበለጠ ይቀራል"</string>
- <string name="power_remaining_only_more_than_subtext" msgid="8884488700395194194">"ከ<xliff:g id="TIME_REMAINING">%1$s</xliff:g> በላይ ይቀራል"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="default" msgid="8168317165722752881">"ስልኩ በቅርቡ ሊዘጋ ይችላል"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="tablet" msgid="5957064378548718872">"ጡባዊ በቅርቡ ሊዘጋ ይችል ይሆናል"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="device" msgid="9055596817716471373">"መሣሪያ በቅርቡ ሊዘጋ ይችል ይሆናል"</string>
- <string name="power_discharging_duration" msgid="2843747179907396142">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> አካባቢ ይቀራል"</string>
- <string name="power_discharging_duration_enhanced" msgid="4401782117770255046">"<xliff:g id="LEVEL">%1$s</xliff:g> - በእርስዎ አጠቃቀም ላይ በመመስረት <xliff:g id="TIME">%2$s</xliff:g> ገደማ ቀርቷል"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="default" msgid="7679005631124015335">"<xliff:g id="LEVEL">%1$s</xliff:g> - ስልክ በቅርቡ ሊዘጋ ይችል ይሆናል"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="tablet" msgid="261050880878965621">"<xliff:g id="LEVEL">%1$s</xliff:g> - ጡባዊ በቅርቡ ሊዘጋ ይችል ይሆናል"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="device" msgid="2020049829798578618">"<xliff:g id="LEVEL">%1$s</xliff:g> - መሣሪያ በቅርቡ ሊዘጋ ይችል ይሆናል"</string>
+ <!-- no translation found for power_remaining_less_than_duration (5751885147712659423) -->
+ <skip />
+ <!-- no translation found for power_remaining_more_than_subtext (3176771815132876675) -->
+ <skip />
+ <!-- no translation found for power_remaining_only_more_than_subtext (8931654680569617380) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (1181059207608751924) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (2606370266981054691) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (2918084807716859985) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (3090926004324573908) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (7466484148515796216) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (603933521600231649) -->
+ <skip />
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
+ <string name="power_remaining_charging_duration_only" msgid="1421102457410268886">"ሙሉ ኃይል እስኪሞላ ድረስ <xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="4676999980973411875">"<xliff:g id="LEVEL">%1$s</xliff:g> - ሙሉ ለሙሉ እስኪሞላ ድረስ <xliff:g id="TIME">%2$s</xliff:g>"</string>
<string name="battery_info_status_unknown" msgid="196130600938058547">"ያልታወቀ"</string>
<string name="battery_info_status_charging" msgid="1705179948350365604">"ኃይል በመሙላት ላይ"</string>
diff --git a/packages/SettingsLib/res/values-ar/strings.xml b/packages/SettingsLib/res/values-ar/strings.xml
index 40c16b9..7f4d643 100644
--- a/packages/SettingsLib/res/values-ar/strings.xml
+++ b/packages/SettingsLib/res/values-ar/strings.xml
@@ -220,7 +220,8 @@
<string name="select_private_dns_configuration_title" msgid="3700456559305263922">"نظام أسماء النطاقات الخاص"</string>
<string name="select_private_dns_configuration_dialog_title" msgid="9221994415765826811">"اختر وضع نظام أسماء النطاقات الخاص"</string>
<string name="private_dns_mode_off" msgid="8236575187318721684">"غير مفعّل"</string>
- <string name="private_dns_mode_opportunistic" msgid="7608409735589131766">"انتهازي"</string>
+ <!-- no translation found for private_dns_mode_opportunistic (8314986739896927399) -->
+ <skip />
<string name="private_dns_mode_provider" msgid="8354935160639360804">"اسم مضيف مزوّد نظام أسماء النطاقات الخاص"</string>
<string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"أدخل اسم مضيف مزوّد نظام أسماء النطاقات"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"عرض خيارات شهادة عرض شاشة لاسلكي"</string>
@@ -356,22 +357,41 @@
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"هذه الميزة تجريبية وقد تؤثر في الأداء."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"تم الاستبدال بـ <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="power_remaining_duration_only" msgid="845431008899029842">"يتبقى حوالي <xliff:g id="TIME">%1$s</xliff:g> لإتمام شحن البطارية"</string>
+ <!-- no translation found for power_discharging_duration (6655472132189365839) -->
+ <skip />
<string name="power_remaining_duration_only_enhanced" msgid="5992456722677973678">"يتبقى <xliff:g id="TIME">%1$s</xliff:g> تقريبًا بناءً على استخدامك"</string>
- <string name="power_remaining_charging_duration_only" msgid="1421102457410268886">"يتبقى <xliff:g id="TIME">%1$s</xliff:g> لشحن البطارية بالكامل"</string>
+ <!-- no translation found for power_discharging_duration_enhanced (5726302316642148671) -->
+ <skip />
<string name="power_remaining_duration_only_short" msgid="5329694252258605547">"يتبقى <xliff:g id="TIME">%1$s</xliff:g>"</string>
+ <!-- no translation found for power_discharge_by_enhanced (8788299408879961465) -->
+ <skip />
+ <!-- no translation found for power_discharge_by_only_enhanced (7692297898877104416) -->
+ <skip />
+ <!-- no translation found for power_discharge_by (6427074755635635749) -->
+ <skip />
+ <!-- no translation found for power_discharge_by_only (5888058889261108064) -->
+ <skip />
<string name="power_remaining_less_than_duration_only" msgid="5996752448813295329">"يتبقى أقل من <xliff:g id="THRESHOLD">%1$s</xliff:g>."</string>
- <string name="power_remaining_less_than_duration" msgid="7967078125657859046">"<xliff:g id="LEVEL">%1$s</xliff:g> - يتبقى أقل من <xliff:g id="THRESHOLD">%2$s</xliff:g>."</string>
- <string name="power_remaining_more_than_subtext" msgid="6846716609975752316">"<xliff:g id="LEVEL">%1$s</xliff:g>يتبقى أكثر من <xliff:g id="TIME_REMAINING">%2$s</xliff:g>."</string>
- <string name="power_remaining_only_more_than_subtext" msgid="8884488700395194194">"يتبقى أكثر من <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="default" msgid="8168317165722752881">"قد يتم إغلاق الهاتف بعد قليل."</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="tablet" msgid="5957064378548718872">"قد يتم إغلاق الجهاز اللوحي بعد قليل."</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="device" msgid="9055596817716471373">"قد يتم إغلاق الجهاز بعد قليل."</string>
- <string name="power_discharging_duration" msgid="2843747179907396142">"<xliff:g id="LEVEL">%1$s</xliff:g> - يتبقى <xliff:g id="TIME">%2$s</xliff:g> تقريبًا"</string>
- <string name="power_discharging_duration_enhanced" msgid="4401782117770255046">"<xliff:g id="LEVEL">%1$s</xliff:g> - يتبقى <xliff:g id="TIME">%2$s</xliff:g> تقريبًا بناءً على استخدامك"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="default" msgid="7679005631124015335">"<xliff:g id="LEVEL">%1$s</xliff:g> - قد يتم إغلاق الهاتف بعد قليل."</string>
- <string name="power_remaining_duration_shutdown_imminent" product="tablet" msgid="261050880878965621">"<xliff:g id="LEVEL">%1$s</xliff:g> - قد يتم إغلاق الجهاز اللوحي بعد قليل."</string>
- <string name="power_remaining_duration_shutdown_imminent" product="device" msgid="2020049829798578618">"<xliff:g id="LEVEL">%1$s</xliff:g> - قد يتم إغلاق الجهاز بعد قليل."</string>
+ <!-- no translation found for power_remaining_less_than_duration (5751885147712659423) -->
+ <skip />
+ <!-- no translation found for power_remaining_more_than_subtext (3176771815132876675) -->
+ <skip />
+ <!-- no translation found for power_remaining_only_more_than_subtext (8931654680569617380) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (1181059207608751924) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (2606370266981054691) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (2918084807716859985) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (3090926004324573908) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (7466484148515796216) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (603933521600231649) -->
+ <skip />
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
+ <string name="power_remaining_charging_duration_only" msgid="1421102457410268886">"يتبقى <xliff:g id="TIME">%1$s</xliff:g> لشحن البطارية بالكامل"</string>
<string name="power_charging_duration" msgid="4676999980973411875">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> حتى يكتمل الشحن"</string>
<string name="battery_info_status_unknown" msgid="196130600938058547">"غير معروف"</string>
<string name="battery_info_status_charging" msgid="1705179948350365604">"جارٍ الشحن"</string>
diff --git a/packages/SettingsLib/res/values-as/strings.xml b/packages/SettingsLib/res/values-as/strings.xml
index b4d1af8..c9dd0da 100644
--- a/packages/SettingsLib/res/values-as/strings.xml
+++ b/packages/SettingsLib/res/values-as/strings.xml
@@ -233,7 +233,8 @@
<string name="select_private_dns_configuration_title" msgid="3700456559305263922">"ব্যক্তিগত DNS"</string>
<string name="select_private_dns_configuration_dialog_title" msgid="9221994415765826811">"ব্যক্তিগত DNS ম\'ড বাছনি কৰক"</string>
<string name="private_dns_mode_off" msgid="8236575187318721684">"অফ"</string>
- <string name="private_dns_mode_opportunistic" msgid="7608409735589131766">"সুবিধাবাদী"</string>
+ <!-- no translation found for private_dns_mode_opportunistic (8314986739896927399) -->
+ <skip />
<string name="private_dns_mode_provider" msgid="8354935160639360804">"ব্যক্তিগত ডিএনএছ প্ৰদানকাৰীৰ হোষ্টনাম"</string>
<string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"ডিএনএছ সেৱা যোগানকাৰীৰ হ\'ষ্টনাম দিয়ক"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"বেতাঁৰ ডিছপ্লে প্ৰমাণপত্ৰৰ বাবে বিকল্পসমূহ দেখুৱাওক"</string>
@@ -372,32 +373,42 @@
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"এই সুবিধাটো পৰীক্ষামূলক, সেয়ে ই কাৰ্যক্ষমতাৰ ওপৰত প্ৰভাৱ পেলাব পাৰে।"</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"<xliff:g id="TITLE">%1$s</xliff:g>ৰ দ্বাৰা অগ্ৰাহ্য কৰা হৈছে"</string>
<string name="power_remaining_duration_only" msgid="845431008899029842">"প্ৰায় <xliff:g id="TIME">%1$s</xliff:g> বাকী আছে"</string>
+ <!-- no translation found for power_discharging_duration (6655472132189365839) -->
+ <skip />
<string name="power_remaining_duration_only_enhanced" msgid="5992456722677973678">"আপোনাৰ ব্যৱহাৰৰ ওপৰত ভিত্তি কৰি প্ৰায় <xliff:g id="TIME">%1$s</xliff:g> বাকী আছে"</string>
- <string name="power_remaining_charging_duration_only" msgid="1421102457410268886">"সম্পূৰ্ণকৈ চ্চাৰ্জ হ\'বলৈ <xliff:g id="TIME">%1$s</xliff:g> বাকী"</string>
+ <!-- no translation found for power_discharging_duration_enhanced (5726302316642148671) -->
+ <skip />
<string name="power_remaining_duration_only_short" msgid="5329694252258605547">"<xliff:g id="TIME">%1$s</xliff:g> বাকী"</string>
+ <!-- no translation found for power_discharge_by_enhanced (8788299408879961465) -->
+ <skip />
+ <!-- no translation found for power_discharge_by_only_enhanced (7692297898877104416) -->
+ <skip />
+ <!-- no translation found for power_discharge_by (6427074755635635749) -->
+ <skip />
+ <!-- no translation found for power_discharge_by_only (5888058889261108064) -->
+ <skip />
<!-- no translation found for power_remaining_less_than_duration_only (5996752448813295329) -->
<skip />
- <!-- no translation found for power_remaining_less_than_duration (7967078125657859046) -->
+ <!-- no translation found for power_remaining_less_than_duration (5751885147712659423) -->
<skip />
- <!-- no translation found for power_remaining_more_than_subtext (6846716609975752316) -->
+ <!-- no translation found for power_remaining_more_than_subtext (3176771815132876675) -->
<skip />
- <!-- no translation found for power_remaining_only_more_than_subtext (8884488700395194194) -->
+ <!-- no translation found for power_remaining_only_more_than_subtext (8931654680569617380) -->
<skip />
- <!-- no translation found for power_remaining_duration_only_shutdown_imminent (8168317165722752881) -->
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (1181059207608751924) -->
<skip />
- <!-- no translation found for power_remaining_duration_only_shutdown_imminent (5957064378548718872) -->
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (2606370266981054691) -->
<skip />
- <!-- no translation found for power_remaining_duration_only_shutdown_imminent (9055596817716471373) -->
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (2918084807716859985) -->
<skip />
- <string name="power_discharging_duration" msgid="2843747179907396142">"<xliff:g id="LEVEL">%1$s</xliff:g> - প্ৰায় <xliff:g id="TIME">%2$s</xliff:g> বাকী আছে"</string>
- <string name="power_discharging_duration_enhanced" msgid="4401782117770255046">"<xliff:g id="LEVEL">%1$s</xliff:g> - আপোনাৰ ব্যৱহাৰক ভিত্তি কৰি প্ৰায় <xliff:g id="TIME">%2$s</xliff:g> বাকী আছে"</string>
- <!-- no translation found for power_remaining_duration_shutdown_imminent (7679005631124015335) -->
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (3090926004324573908) -->
<skip />
- <!-- no translation found for power_remaining_duration_shutdown_imminent (261050880878965621) -->
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (7466484148515796216) -->
<skip />
- <!-- no translation found for power_remaining_duration_shutdown_imminent (2020049829798578618) -->
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (603933521600231649) -->
<skip />
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
+ <string name="power_remaining_charging_duration_only" msgid="1421102457410268886">"সম্পূৰ্ণকৈ চ্চাৰ্জ হ\'বলৈ <xliff:g id="TIME">%1$s</xliff:g> বাকী"</string>
<string name="power_charging_duration" msgid="4676999980973411875">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> সম্পূৰ্ণৰূপে চ্চাৰ্জ হোৱা পৰ্যন্ত"</string>
<string name="battery_info_status_unknown" msgid="196130600938058547">"অজ্ঞাত"</string>
<string name="battery_info_status_charging" msgid="1705179948350365604">"চাৰ্জ কৰি থকা হৈছে"</string>
diff --git a/packages/SettingsLib/res/values-az/strings.xml b/packages/SettingsLib/res/values-az/strings.xml
index 97e3570..2d235dd 100644
--- a/packages/SettingsLib/res/values-az/strings.xml
+++ b/packages/SettingsLib/res/values-az/strings.xml
@@ -220,7 +220,8 @@
<string name="select_private_dns_configuration_title" msgid="3700456559305263922">"Şəxsi DNS"</string>
<string name="select_private_dns_configuration_dialog_title" msgid="9221994415765826811">"Şəxsi DNS Rejimini Seçin"</string>
<string name="private_dns_mode_off" msgid="8236575187318721684">"Deaktiv"</string>
- <string name="private_dns_mode_opportunistic" msgid="7608409735589131766">"Geniş imkanlar"</string>
+ <!-- no translation found for private_dns_mode_opportunistic (8314986739896927399) -->
+ <skip />
<string name="private_dns_mode_provider" msgid="8354935160639360804">"Şəxsi DNS provayderinin host adı"</string>
<string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"DNS provayderinin host adını daxil edin"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Simsiz displey sertifikatlaşması üçün seçimləri göstərir"</string>
@@ -356,22 +357,41 @@
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Bu funksiya eksperimentaldır və performansa təsir edə bilər."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"<xliff:g id="TITLE">%1$s</xliff:g> tərəfindən qəbul edilmir"</string>
<string name="power_remaining_duration_only" msgid="845431008899029842">"Təxminən <xliff:g id="TIME">%1$s</xliff:g> qalıb"</string>
+ <!-- no translation found for power_discharging_duration (6655472132189365839) -->
+ <skip />
<string name="power_remaining_duration_only_enhanced" msgid="5992456722677973678">"İstifadəyə əsasən təxminən <xliff:g id="TIME">%1$s</xliff:g> qalıb"</string>
- <string name="power_remaining_charging_duration_only" msgid="1421102457410268886">"Tam enerji yığmağına <xliff:g id="TIME">%1$s</xliff:g> qalıb"</string>
+ <!-- no translation found for power_discharging_duration_enhanced (5726302316642148671) -->
+ <skip />
<string name="power_remaining_duration_only_short" msgid="5329694252258605547">"<xliff:g id="TIME">%1$s</xliff:g> qalıb"</string>
+ <!-- no translation found for power_discharge_by_enhanced (8788299408879961465) -->
+ <skip />
+ <!-- no translation found for power_discharge_by_only_enhanced (7692297898877104416) -->
+ <skip />
+ <!-- no translation found for power_discharge_by (6427074755635635749) -->
+ <skip />
+ <!-- no translation found for power_discharge_by_only (5888058889261108064) -->
+ <skip />
<string name="power_remaining_less_than_duration_only" msgid="5996752448813295329">"Qalan vaxt <xliff:g id="THRESHOLD">%1$s</xliff:g> və daha azdır"</string>
- <string name="power_remaining_less_than_duration" msgid="7967078125657859046">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="THRESHOLD">%2$s</xliff:g> və daha az vaxt qalır"</string>
- <string name="power_remaining_more_than_subtext" msgid="6846716609975752316">"<xliff:g id="LEVEL">%1$s</xliff:g> - Qalan vaxt <xliff:g id="TIME_REMAINING">%2$s</xliff:g> və daha azdır"</string>
- <string name="power_remaining_only_more_than_subtext" msgid="8884488700395194194">"Qalan vaxt <xliff:g id="TIME_REMAINING">%1$s</xliff:g> və daha çoxdur"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="default" msgid="8168317165722752881">"telefon tezliklə sönə bilər"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="tablet" msgid="5957064378548718872">"planşet tezliklə sönə bilər"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="device" msgid="9055596817716471373">"cihaz tezliklə sönə bilər"</string>
- <string name="power_discharging_duration" msgid="2843747179907396142">"<xliff:g id="LEVEL">%1$s</xliff:g> - təxminən <xliff:g id="TIME">%2$s</xliff:g> qalıb"</string>
- <string name="power_discharging_duration_enhanced" msgid="4401782117770255046">"<xliff:g id="LEVEL">%1$s</xliff:g> - istifadəyə əsasən təxminən <xliff:g id="TIME">%2$s</xliff:g> qalıb"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="default" msgid="7679005631124015335">"<xliff:g id="LEVEL">%1$s</xliff:g> - telefon tezliklə sönə bilər"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="tablet" msgid="261050880878965621">"<xliff:g id="LEVEL">%1$s</xliff:g> - planşet tezliklə sönə bilər"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="device" msgid="2020049829798578618">"<xliff:g id="LEVEL">%1$s</xliff:g> - cihaz tezliklə sönə bilər"</string>
+ <!-- no translation found for power_remaining_less_than_duration (5751885147712659423) -->
+ <skip />
+ <!-- no translation found for power_remaining_more_than_subtext (3176771815132876675) -->
+ <skip />
+ <!-- no translation found for power_remaining_only_more_than_subtext (8931654680569617380) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (1181059207608751924) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (2606370266981054691) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (2918084807716859985) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (3090926004324573908) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (7466484148515796216) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (603933521600231649) -->
+ <skip />
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
+ <string name="power_remaining_charging_duration_only" msgid="1421102457410268886">"Tam enerji yığmağına <xliff:g id="TIME">%1$s</xliff:g> qalıb"</string>
<string name="power_charging_duration" msgid="4676999980973411875">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> tam enerji yığana kimi"</string>
<string name="battery_info_status_unknown" msgid="196130600938058547">"Naməlum"</string>
<string name="battery_info_status_charging" msgid="1705179948350365604">"Enerji doldurma"</string>
diff --git a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
index dd7043d..1ea7931 100644
--- a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
+++ b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
@@ -220,7 +220,8 @@
<string name="select_private_dns_configuration_title" msgid="3700456559305263922">"Privatni DNS"</string>
<string name="select_private_dns_configuration_dialog_title" msgid="9221994415765826811">"Izaberite režim privatnog DNS-a"</string>
<string name="private_dns_mode_off" msgid="8236575187318721684">"Isključeno"</string>
- <string name="private_dns_mode_opportunistic" msgid="7608409735589131766">"Opportunistički"</string>
+ <!-- no translation found for private_dns_mode_opportunistic (8314986739896927399) -->
+ <skip />
<string name="private_dns_mode_provider" msgid="8354935160639360804">"Ime hosta dobavljača usluge privatnog DNS-a"</string>
<string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"Unesite ime hosta dobavljača usluge DNS-a"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Prikaz opcija za sertifikaciju bežičnog ekrana"</string>
@@ -356,22 +357,41 @@
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Ova funkcija je eksperimentalna i može da utiče na kvalitet rada."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"Zamenjuje ga <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="power_remaining_duration_only" msgid="845431008899029842">"Još oko <xliff:g id="TIME">%1$s</xliff:g>"</string>
+ <!-- no translation found for power_discharging_duration (6655472132189365839) -->
+ <skip />
<string name="power_remaining_duration_only_enhanced" msgid="5992456722677973678">"Na osnovu potrošnje imate još otprilike <xliff:g id="TIME">%1$s</xliff:g>"</string>
- <string name="power_remaining_charging_duration_only" msgid="1421102457410268886">"<xliff:g id="TIME">%1$s</xliff:g> do potpunog punjenja"</string>
+ <!-- no translation found for power_discharging_duration_enhanced (5726302316642148671) -->
+ <skip />
<string name="power_remaining_duration_only_short" msgid="5329694252258605547">"Preostalo vreme: <xliff:g id="TIME">%1$s</xliff:g>"</string>
+ <!-- no translation found for power_discharge_by_enhanced (8788299408879961465) -->
+ <skip />
+ <!-- no translation found for power_discharge_by_only_enhanced (7692297898877104416) -->
+ <skip />
+ <!-- no translation found for power_discharge_by (6427074755635635749) -->
+ <skip />
+ <!-- no translation found for power_discharge_by_only (5888058889261108064) -->
+ <skip />
<string name="power_remaining_less_than_duration_only" msgid="5996752448813295329">"Preostalo je manje od <xliff:g id="THRESHOLD">%1$s</xliff:g>"</string>
- <string name="power_remaining_less_than_duration" msgid="7967078125657859046">"<xliff:g id="LEVEL">%1$s</xliff:g> – preostalo je manje od <xliff:g id="THRESHOLD">%2$s</xliff:g>"</string>
- <string name="power_remaining_more_than_subtext" msgid="6846716609975752316">"<xliff:g id="LEVEL">%1$s</xliff:g> – preostalo je više od <xliff:g id="TIME_REMAINING">%2$s</xliff:g>"</string>
- <string name="power_remaining_only_more_than_subtext" msgid="8884488700395194194">"preostalo je više od <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="default" msgid="8168317165722752881">"telefon će se uskoro isključiti"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="tablet" msgid="5957064378548718872">"tablet će se uskoro isključiti"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="device" msgid="9055596817716471373">"uređaj će se uskoro isključiti"</string>
- <string name="power_discharging_duration" msgid="2843747179907396142">"<xliff:g id="LEVEL">%1$s</xliff:g> – ostalo je oko <xliff:g id="TIME">%2$s</xliff:g>"</string>
- <string name="power_discharging_duration_enhanced" msgid="4401782117770255046">"<xliff:g id="LEVEL">%1$s</xliff:g> – na osnovu potrošnje imate još otprilike <xliff:g id="TIME">%2$s</xliff:g>"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="default" msgid="7679005631124015335">"<xliff:g id="LEVEL">%1$s</xliff:g> – telefon će se uskoro isključiti"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="tablet" msgid="261050880878965621">"<xliff:g id="LEVEL">%1$s</xliff:g> – tablet će se uskoro isključiti"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="device" msgid="2020049829798578618">"<xliff:g id="LEVEL">%1$s</xliff:g> – uređaj će se uskoro isključiti"</string>
+ <!-- no translation found for power_remaining_less_than_duration (5751885147712659423) -->
+ <skip />
+ <!-- no translation found for power_remaining_more_than_subtext (3176771815132876675) -->
+ <skip />
+ <!-- no translation found for power_remaining_only_more_than_subtext (8931654680569617380) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (1181059207608751924) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (2606370266981054691) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (2918084807716859985) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (3090926004324573908) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (7466484148515796216) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (603933521600231649) -->
+ <skip />
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string>
+ <string name="power_remaining_charging_duration_only" msgid="1421102457410268886">"<xliff:g id="TIME">%1$s</xliff:g> do potpunog punjenja"</string>
<string name="power_charging_duration" msgid="4676999980973411875">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> do potpunog punjenja"</string>
<string name="battery_info_status_unknown" msgid="196130600938058547">"Nepoznato"</string>
<string name="battery_info_status_charging" msgid="1705179948350365604">"Punjenje"</string>
diff --git a/packages/SettingsLib/res/values-be/strings.xml b/packages/SettingsLib/res/values-be/strings.xml
index 1a0a251..23a785c 100644
--- a/packages/SettingsLib/res/values-be/strings.xml
+++ b/packages/SettingsLib/res/values-be/strings.xml
@@ -220,7 +220,8 @@
<string name="select_private_dns_configuration_title" msgid="3700456559305263922">"Прыватная DNS"</string>
<string name="select_private_dns_configuration_dialog_title" msgid="9221994415765826811">"Выберыце рэжым прыватнай DNS"</string>
<string name="private_dns_mode_off" msgid="8236575187318721684">"Выключана"</string>
- <string name="private_dns_mode_opportunistic" msgid="7608409735589131766">"Гібкі"</string>
+ <!-- no translation found for private_dns_mode_opportunistic (8314986739896927399) -->
+ <skip />
<string name="private_dns_mode_provider" msgid="8354935160639360804">"Імя вузла аператара прыватнай DNS"</string>
<string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"Увядзіце імя вузла аператара DNS"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Паказаць опцыі сертыфікацыі бесправаднога дысплея"</string>
@@ -356,22 +357,41 @@
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Гэта функцыя з\'яўляецца эксперыментальнай і можа паўплываць на прадукцыйнасць."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"Перавызначаны <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="power_remaining_duration_only" msgid="845431008899029842">"Засталося каля <xliff:g id="TIME">%1$s</xliff:g>"</string>
+ <!-- no translation found for power_discharging_duration (6655472132189365839) -->
+ <skip />
<string name="power_remaining_duration_only_enhanced" msgid="5992456722677973678">"Засталося каля <xliff:g id="TIME">%1$s</xliff:g> на аснове вашага выкарыстання"</string>
- <string name="power_remaining_charging_duration_only" msgid="1421102457410268886">"Да поўнай зарадкі засталося <xliff:g id="TIME">%1$s</xliff:g>"</string>
+ <!-- no translation found for power_discharging_duration_enhanced (5726302316642148671) -->
+ <skip />
<string name="power_remaining_duration_only_short" msgid="5329694252258605547">"Засталося <xliff:g id="TIME">%1$s</xliff:g>"</string>
+ <!-- no translation found for power_discharge_by_enhanced (8788299408879961465) -->
+ <skip />
+ <!-- no translation found for power_discharge_by_only_enhanced (7692297898877104416) -->
+ <skip />
+ <!-- no translation found for power_discharge_by (6427074755635635749) -->
+ <skip />
+ <!-- no translation found for power_discharge_by_only (5888058889261108064) -->
+ <skip />
<string name="power_remaining_less_than_duration_only" msgid="5996752448813295329">"Засталося менш за <xliff:g id="THRESHOLD">%1$s</xliff:g>"</string>
- <string name="power_remaining_less_than_duration" msgid="7967078125657859046">"<xliff:g id="LEVEL">%1$s</xliff:g> – засталося менш за <xliff:g id="THRESHOLD">%2$s</xliff:g>"</string>
- <string name="power_remaining_more_than_subtext" msgid="6846716609975752316">"<xliff:g id="LEVEL">%1$s</xliff:g> – засталося больш за <xliff:g id="TIME_REMAINING">%2$s</xliff:g>"</string>
- <string name="power_remaining_only_more_than_subtext" msgid="8884488700395194194">"засталося больш за <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="default" msgid="8168317165722752881">"тэлефон у хуткім часе выключыцца"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="tablet" msgid="5957064378548718872">"планшэт у хуткім часе выключыцца"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="device" msgid="9055596817716471373">"прылада ў хуткім часе выключыцца"</string>
- <string name="power_discharging_duration" msgid="2843747179907396142">"<xliff:g id="LEVEL">%1$s</xliff:g> – засталося каля <xliff:g id="TIME">%2$s</xliff:g>"</string>
- <string name="power_discharging_duration_enhanced" msgid="4401782117770255046">"<xliff:g id="LEVEL">%1$s</xliff:g> – засталося каля <xliff:g id="TIME">%2$s</xliff:g> на аснове вашага выкарыстання"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="default" msgid="7679005631124015335">"<xliff:g id="LEVEL">%1$s</xliff:g> – тэлефон у хуткім часе выключыцца"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="tablet" msgid="261050880878965621">"<xliff:g id="LEVEL">%1$s</xliff:g> – планшэт у хуткім часе выключыцца"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="device" msgid="2020049829798578618">"<xliff:g id="LEVEL">%1$s</xliff:g> – прылада ў хуткім часе выключыцца"</string>
+ <!-- no translation found for power_remaining_less_than_duration (5751885147712659423) -->
+ <skip />
+ <!-- no translation found for power_remaining_more_than_subtext (3176771815132876675) -->
+ <skip />
+ <!-- no translation found for power_remaining_only_more_than_subtext (8931654680569617380) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (1181059207608751924) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (2606370266981054691) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (2918084807716859985) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (3090926004324573908) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (7466484148515796216) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (603933521600231649) -->
+ <skip />
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string>
+ <string name="power_remaining_charging_duration_only" msgid="1421102457410268886">"Да поўнай зарадкі засталося <xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="4676999980973411875">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> да поўнай зарадкі"</string>
<string name="battery_info_status_unknown" msgid="196130600938058547">"Невядома"</string>
<string name="battery_info_status_charging" msgid="1705179948350365604">"Зарадка"</string>
diff --git a/packages/SettingsLib/res/values-bg/strings.xml b/packages/SettingsLib/res/values-bg/strings.xml
index d071c64..5cd345a 100644
--- a/packages/SettingsLib/res/values-bg/strings.xml
+++ b/packages/SettingsLib/res/values-bg/strings.xml
@@ -220,7 +220,8 @@
<string name="select_private_dns_configuration_title" msgid="3700456559305263922">"Частен DNS"</string>
<string name="select_private_dns_configuration_dialog_title" msgid="9221994415765826811">"Изберете режим на частния DNS"</string>
<string name="private_dns_mode_off" msgid="8236575187318721684">"Изкл."</string>
- <string name="private_dns_mode_opportunistic" msgid="7608409735589131766">"При възможност"</string>
+ <!-- no translation found for private_dns_mode_opportunistic (8314986739896927399) -->
+ <skip />
<string name="private_dns_mode_provider" msgid="8354935160639360804">"Име на хоста на доставчика на частния DNS"</string>
<string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"Въведете името на хоста на DNS доставчика"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Показване на опциите за сертифициране на безжичния дисплей"</string>
@@ -356,22 +357,41 @@
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Тази функция е експериментална и може да се отрази на ефективността."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"Заменено от „<xliff:g id="TITLE">%1$s</xliff:g>“"</string>
<string name="power_remaining_duration_only" msgid="845431008899029842">"Оставащо време: около <xliff:g id="TIME">%1$s</xliff:g>"</string>
+ <!-- no translation found for power_discharging_duration (6655472132189365839) -->
+ <skip />
<string name="power_remaining_duration_only_enhanced" msgid="5992456722677973678">"Още около <xliff:g id="TIME">%1$s</xliff:g> въз основа на използването"</string>
- <string name="power_remaining_charging_duration_only" msgid="1421102457410268886">"Оставащо време до пълно зареждане: <xliff:g id="TIME">%1$s</xliff:g>"</string>
+ <!-- no translation found for power_discharging_duration_enhanced (5726302316642148671) -->
+ <skip />
<string name="power_remaining_duration_only_short" msgid="5329694252258605547">"Оставащо време: <xliff:g id="TIME">%1$s</xliff:g>"</string>
+ <!-- no translation found for power_discharge_by_enhanced (8788299408879961465) -->
+ <skip />
+ <!-- no translation found for power_discharge_by_only_enhanced (7692297898877104416) -->
+ <skip />
+ <!-- no translation found for power_discharge_by (6427074755635635749) -->
+ <skip />
+ <!-- no translation found for power_discharge_by_only (5888058889261108064) -->
+ <skip />
<string name="power_remaining_less_than_duration_only" msgid="5996752448813295329">"Остава/т по-малко от <xliff:g id="THRESHOLD">%1$s</xliff:g>"</string>
- <string name="power_remaining_less_than_duration" msgid="7967078125657859046">"<xliff:g id="LEVEL">%1$s</xliff:g> – остава/т по-малко от <xliff:g id="THRESHOLD">%2$s</xliff:g>"</string>
- <string name="power_remaining_more_than_subtext" msgid="6846716609975752316">"<xliff:g id="LEVEL">%1$s</xliff:g> – остава/т повече от <xliff:g id="TIME_REMAINING">%2$s</xliff:g>"</string>
- <string name="power_remaining_only_more_than_subtext" msgid="8884488700395194194">"остава/т повече от <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="default" msgid="8168317165722752881">"възможно е телефонът да се изключи скоро"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="tablet" msgid="5957064378548718872">"възможно е таблетът да се изключи скоро"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="device" msgid="9055596817716471373">"възможно е устройството да се изключи скоро"</string>
- <string name="power_discharging_duration" msgid="2843747179907396142">"<xliff:g id="LEVEL">%1$s</xliff:g> – около <xliff:g id="TIME">%2$s</xliff:g> оставащо време"</string>
- <string name="power_discharging_duration_enhanced" msgid="4401782117770255046">"<xliff:g id="LEVEL">%1$s</xliff:g> – още около <xliff:g id="TIME">%2$s</xliff:g> въз основа на използването"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="default" msgid="7679005631124015335">"<xliff:g id="LEVEL">%1$s</xliff:g> – възможно е телефонът да се изключи скоро"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="tablet" msgid="261050880878965621">"<xliff:g id="LEVEL">%1$s</xliff:g> – възможно е таблетът да се изключи скоро"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="device" msgid="2020049829798578618">"<xliff:g id="LEVEL">%1$s</xliff:g> – възможно е устройството да се изключи скоро"</string>
+ <!-- no translation found for power_remaining_less_than_duration (5751885147712659423) -->
+ <skip />
+ <!-- no translation found for power_remaining_more_than_subtext (3176771815132876675) -->
+ <skip />
+ <!-- no translation found for power_remaining_only_more_than_subtext (8931654680569617380) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (1181059207608751924) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (2606370266981054691) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (2918084807716859985) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (3090926004324573908) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (7466484148515796216) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (603933521600231649) -->
+ <skip />
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string>
+ <string name="power_remaining_charging_duration_only" msgid="1421102457410268886">"Оставащо време до пълно зареждане: <xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="4676999980973411875">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> до пълно зареждане"</string>
<string name="battery_info_status_unknown" msgid="196130600938058547">"Неизвестно"</string>
<string name="battery_info_status_charging" msgid="1705179948350365604">"Зарежда се"</string>
diff --git a/packages/SettingsLib/res/values-bn/strings.xml b/packages/SettingsLib/res/values-bn/strings.xml
index baa31e6..1e56cf6 100644
--- a/packages/SettingsLib/res/values-bn/strings.xml
+++ b/packages/SettingsLib/res/values-bn/strings.xml
@@ -220,7 +220,8 @@
<string name="select_private_dns_configuration_title" msgid="3700456559305263922">"ব্যক্তিগত ডিএনএস"</string>
<string name="select_private_dns_configuration_dialog_title" msgid="9221994415765826811">"ব্যক্তিগত ডিএনএস মোড বেছে নিন"</string>
<string name="private_dns_mode_off" msgid="8236575187318721684">"বন্ধ আছে"</string>
- <string name="private_dns_mode_opportunistic" msgid="7608409735589131766">"সুবিধাবাদী"</string>
+ <!-- no translation found for private_dns_mode_opportunistic (8314986739896927399) -->
+ <skip />
<string name="private_dns_mode_provider" msgid="8354935160639360804">"ব্যক্তিগত ডিএনএস প্রদানকারীর হোস্টনেম"</string>
<string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"ডিএনএস প্রদানকারীর হোস্টনেম লিখুন"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"ওয়্যারলেস প্রদর্শন সার্টিফিকেশন জন্য বিকল্পগুলি দেখান"</string>
@@ -356,22 +357,41 @@
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"এই বৈশিষ্ট্যটি পরীক্ষামূলক এবং এটি কার্য-সম্পাদনা প্রভাবিত করতে পারে।"</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"<xliff:g id="TITLE">%1$s</xliff:g> এর দ্বারা ওভাররাইড করা হয়েছে"</string>
<string name="power_remaining_duration_only" msgid="845431008899029842">"প্রায় <xliff:g id="TIME">%1$s</xliff:g> বাকি"</string>
+ <!-- no translation found for power_discharging_duration (6655472132189365839) -->
+ <skip />
<string name="power_remaining_duration_only_enhanced" msgid="5992456722677973678">"বর্তমান ব্যাটারি ব্যবহার অনুযায়ী আর <xliff:g id="TIME">%1$s</xliff:g> বাকি"</string>
- <string name="power_remaining_charging_duration_only" msgid="1421102457410268886">"সম্পূর্ণ চার্জ হতে <xliff:g id="TIME">%1$s</xliff:g> বাকি"</string>
+ <!-- no translation found for power_discharging_duration_enhanced (5726302316642148671) -->
+ <skip />
<string name="power_remaining_duration_only_short" msgid="5329694252258605547">"<xliff:g id="TIME">%1$s</xliff:g> বাকী আছে"</string>
+ <!-- no translation found for power_discharge_by_enhanced (8788299408879961465) -->
+ <skip />
+ <!-- no translation found for power_discharge_by_only_enhanced (7692297898877104416) -->
+ <skip />
+ <!-- no translation found for power_discharge_by (6427074755635635749) -->
+ <skip />
+ <!-- no translation found for power_discharge_by_only (5888058889261108064) -->
+ <skip />
<string name="power_remaining_less_than_duration_only" msgid="5996752448813295329">"<xliff:g id="THRESHOLD">%1$s</xliff:g> এর থেকেও কম বাকি আছে"</string>
- <string name="power_remaining_less_than_duration" msgid="7967078125657859046">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="THRESHOLD">%2$s</xliff:g> এর থেকেও কম বাকি আছে"</string>
- <string name="power_remaining_more_than_subtext" msgid="6846716609975752316">"<xliff:g id="LEVEL">%1$s</xliff:g><xliff:g id="TIME_REMAINING">%2$s</xliff:g> এর থেকে বেশি বাকি আছে"</string>
- <string name="power_remaining_only_more_than_subtext" msgid="8884488700395194194">"<xliff:g id="TIME_REMAINING">%1$s</xliff:g> এর থেকে বেশি বাকি আছে"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="default" msgid="8168317165722752881">"ফোন শীঘ্রই বন্ধ হয়ে যেতে পারে"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="tablet" msgid="5957064378548718872">"ট্যাবলেট শীঘ্রই বন্ধ হয়ে যেতে পারে"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="device" msgid="9055596817716471373">"ডিভাইসটি শীঘ্রই বন্ধ হয়ে যেতে পারে"</string>
- <string name="power_discharging_duration" msgid="2843747179907396142">"<xliff:g id="LEVEL">%1$s</xliff:g> - প্রায় <xliff:g id="TIME">%2$s</xliff:g> বাকি আছে"</string>
- <string name="power_discharging_duration_enhanced" msgid="4401782117770255046">"<xliff:g id="LEVEL">%1$s</xliff:g> - বর্তমান ব্যাটারি ব্যবহার অনুযায়ী আর <xliff:g id="TIME">%2$s</xliff:g> বাকি"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="default" msgid="7679005631124015335">"<xliff:g id="LEVEL">%1$s</xliff:g> - ফোন শীঘ্রই বন্ধ হয়ে যেতে পারে"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="tablet" msgid="261050880878965621">"<xliff:g id="LEVEL">%1$s</xliff:g> - ট্যাবলেট শীঘ্রই বন্ধ হয়ে যেতে পারে"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="device" msgid="2020049829798578618">"<xliff:g id="LEVEL">%1$s</xliff:g> - ডিভাইসটি শীঘ্রই বন্ধ হয়ে যেতে পারে"</string>
+ <!-- no translation found for power_remaining_less_than_duration (5751885147712659423) -->
+ <skip />
+ <!-- no translation found for power_remaining_more_than_subtext (3176771815132876675) -->
+ <skip />
+ <!-- no translation found for power_remaining_only_more_than_subtext (8931654680569617380) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (1181059207608751924) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (2606370266981054691) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (2918084807716859985) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (3090926004324573908) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (7466484148515796216) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (603933521600231649) -->
+ <skip />
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
+ <string name="power_remaining_charging_duration_only" msgid="1421102457410268886">"সম্পূর্ণ চার্জ হতে <xliff:g id="TIME">%1$s</xliff:g> বাকি"</string>
<string name="power_charging_duration" msgid="4676999980973411875">"<xliff:g id="LEVEL">%1$s</xliff:g> - সম্পূর্ণ চার্জ হতে <xliff:g id="TIME">%2$s</xliff:g> লাগবে"</string>
<string name="battery_info_status_unknown" msgid="196130600938058547">"অজানা"</string>
<string name="battery_info_status_charging" msgid="1705179948350365604">"চার্জ হচ্ছে"</string>
diff --git a/packages/SettingsLib/res/values-bs/strings.xml b/packages/SettingsLib/res/values-bs/strings.xml
index c54a5dc..3c09c9d 100644
--- a/packages/SettingsLib/res/values-bs/strings.xml
+++ b/packages/SettingsLib/res/values-bs/strings.xml
@@ -220,7 +220,8 @@
<string name="select_private_dns_configuration_title" msgid="3700456559305263922">"Privatni DNS"</string>
<string name="select_private_dns_configuration_dialog_title" msgid="9221994415765826811">"Odaberite način rada privatnog DNS-a"</string>
<string name="private_dns_mode_off" msgid="8236575187318721684">"Isključeno"</string>
- <string name="private_dns_mode_opportunistic" msgid="7608409735589131766">"Oportunistički"</string>
+ <!-- no translation found for private_dns_mode_opportunistic (8314986739896927399) -->
+ <skip />
<string name="private_dns_mode_provider" msgid="8354935160639360804">"Naziv host računara privatnog DNS-a"</string>
<string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"Unesite naziv host računara pružaoca DNS-a"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Pokaži opcije za certifikaciju Bežičnog prikaza"</string>
@@ -356,22 +357,41 @@
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Ova funkcija je eksperimentalna i može uticati na performanse."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"Zamjenjuje <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="power_remaining_duration_only" msgid="845431008899029842">"Preostalo je otprilike još <xliff:g id="TIME">%1$s</xliff:g>"</string>
+ <!-- no translation found for power_discharging_duration (6655472132189365839) -->
+ <skip />
<string name="power_remaining_duration_only_enhanced" msgid="5992456722677973678">"Preostalo je još oko <xliff:g id="TIME">%1$s</xliff:g>, na osnovu vašeg korištenja"</string>
- <string name="power_remaining_charging_duration_only" msgid="1421102457410268886">"Još <xliff:g id="TIME">%1$s</xliff:g> do potpune napunjenosti"</string>
+ <!-- no translation found for power_discharging_duration_enhanced (5726302316642148671) -->
+ <skip />
<string name="power_remaining_duration_only_short" msgid="5329694252258605547">"Imate još <xliff:g id="TIME">%1$s</xliff:g>"</string>
+ <!-- no translation found for power_discharge_by_enhanced (8788299408879961465) -->
+ <skip />
+ <!-- no translation found for power_discharge_by_only_enhanced (7692297898877104416) -->
+ <skip />
+ <!-- no translation found for power_discharge_by (6427074755635635749) -->
+ <skip />
+ <!-- no translation found for power_discharge_by_only (5888058889261108064) -->
+ <skip />
<string name="power_remaining_less_than_duration_only" msgid="5996752448813295329">"Preostalo je manje od <xliff:g id="THRESHOLD">%1$s</xliff:g>"</string>
- <string name="power_remaining_less_than_duration" msgid="7967078125657859046">"<xliff:g id="LEVEL">%1$s</xliff:g> – Preostalo je manje od <xliff:g id="THRESHOLD">%2$s</xliff:g>"</string>
- <string name="power_remaining_more_than_subtext" msgid="6846716609975752316">"<xliff:g id="LEVEL">%1$s</xliff:g>preostalo je više od <xliff:g id="TIME_REMAINING">%2$s</xliff:g>"</string>
- <string name="power_remaining_only_more_than_subtext" msgid="8884488700395194194">"preostalo je više od <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="default" msgid="8168317165722752881">"telefon će se uskoro isključiti"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="tablet" msgid="5957064378548718872">"tablet će se uskoro isključiti"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="device" msgid="9055596817716471373">"uređaj će se uskoro isključiti"</string>
- <string name="power_discharging_duration" msgid="2843747179907396142">"<xliff:g id="LEVEL">%1$s</xliff:g> - imate još <xliff:g id="TIME">%2$s</xliff:g>"</string>
- <string name="power_discharging_duration_enhanced" msgid="4401782117770255046">"<xliff:g id="LEVEL">%1$s</xliff:g> - preostalo je još oko <xliff:g id="TIME">%2$s</xliff:g>, na osnovu vašeg korištenja"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="default" msgid="7679005631124015335">"<xliff:g id="LEVEL">%1$s</xliff:g> – telefon će se uskoro isključiti"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="tablet" msgid="261050880878965621">"<xliff:g id="LEVEL">%1$s</xliff:g> – tablet će se uskoro isključiti"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="device" msgid="2020049829798578618">"<xliff:g id="LEVEL">%1$s</xliff:g> – uređaj će se uskoro isključiti"</string>
+ <!-- no translation found for power_remaining_less_than_duration (5751885147712659423) -->
+ <skip />
+ <!-- no translation found for power_remaining_more_than_subtext (3176771815132876675) -->
+ <skip />
+ <!-- no translation found for power_remaining_only_more_than_subtext (8931654680569617380) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (1181059207608751924) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (2606370266981054691) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (2918084807716859985) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (3090926004324573908) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (7466484148515796216) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (603933521600231649) -->
+ <skip />
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string>
+ <string name="power_remaining_charging_duration_only" msgid="1421102457410268886">"Još <xliff:g id="TIME">%1$s</xliff:g> do potpune napunjenosti"</string>
<string name="power_charging_duration" msgid="4676999980973411875">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> do potpune napunjenosti"</string>
<string name="battery_info_status_unknown" msgid="196130600938058547">"Nepoznato"</string>
<string name="battery_info_status_charging" msgid="1705179948350365604">"Punjenje"</string>
diff --git a/packages/SettingsLib/res/values-ca/strings.xml b/packages/SettingsLib/res/values-ca/strings.xml
index fc312cf..545dc10 100644
--- a/packages/SettingsLib/res/values-ca/strings.xml
+++ b/packages/SettingsLib/res/values-ca/strings.xml
@@ -220,7 +220,8 @@
<string name="select_private_dns_configuration_title" msgid="3700456559305263922">"DNS privat"</string>
<string name="select_private_dns_configuration_dialog_title" msgid="9221994415765826811">"Selecciona el mode de DNS privat"</string>
<string name="private_dns_mode_off" msgid="8236575187318721684">"Desactivat"</string>
- <string name="private_dns_mode_opportunistic" msgid="7608409735589131766">"Oportunista"</string>
+ <!-- no translation found for private_dns_mode_opportunistic (8314986739896927399) -->
+ <skip />
<string name="private_dns_mode_provider" msgid="8354935160639360804">"Nom d\'amfitrió del proveïdor de DNS privat"</string>
<string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"Introdueix el nom d\'amfitrió del proveïdor de DNS"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Mostra les opcions de certificació de pantalla sense fil"</string>
@@ -356,22 +357,41 @@
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Aquesta funció és experimental i pot afectar el rendiment."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"S\'ha substituït per <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="power_remaining_duration_only" msgid="845431008899029842">"Temps restant aproximat: <xliff:g id="TIME">%1$s</xliff:g>"</string>
+ <!-- no translation found for power_discharging_duration (6655472132189365839) -->
+ <skip />
<string name="power_remaining_duration_only_enhanced" msgid="5992456722677973678">"Temps restant aproximat segons l\'ús que en fas: <xliff:g id="TIME">%1$s</xliff:g>"</string>
- <string name="power_remaining_charging_duration_only" msgid="1421102457410268886">"<xliff:g id="TIME">%1$s</xliff:g> per completar la càrrega"</string>
+ <!-- no translation found for power_discharging_duration_enhanced (5726302316642148671) -->
+ <skip />
<string name="power_remaining_duration_only_short" msgid="5329694252258605547">"Temps restant: <xliff:g id="TIME">%1$s</xliff:g>"</string>
+ <!-- no translation found for power_discharge_by_enhanced (8788299408879961465) -->
+ <skip />
+ <!-- no translation found for power_discharge_by_only_enhanced (7692297898877104416) -->
+ <skip />
+ <!-- no translation found for power_discharge_by (6427074755635635749) -->
+ <skip />
+ <!-- no translation found for power_discharge_by_only (5888058889261108064) -->
+ <skip />
<string name="power_remaining_less_than_duration_only" msgid="5996752448813295329">"Queda menys d\'un <xliff:g id="THRESHOLD">%1$s</xliff:g>"</string>
- <string name="power_remaining_less_than_duration" msgid="7967078125657859046">"<xliff:g id="LEVEL">%1$s</xliff:g>: queda menys d\'un <xliff:g id="THRESHOLD">%2$s</xliff:g>"</string>
- <string name="power_remaining_more_than_subtext" msgid="6846716609975752316">"<xliff:g id="LEVEL">%1$s</xliff:g>: el temps restant és superior a <xliff:g id="TIME_REMAINING">%2$s</xliff:g>"</string>
- <string name="power_remaining_only_more_than_subtext" msgid="8884488700395194194">"el temps restant és superior a <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="default" msgid="8168317165722752881">"és possible que el telèfon s\'apagui aviat"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="tablet" msgid="5957064378548718872">"és possible que la tauleta s\'apagui aviat"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="device" msgid="9055596817716471373">"és possible que el dispositiu s\'apagui aviat"</string>
- <string name="power_discharging_duration" msgid="2843747179907396142">"<xliff:g id="LEVEL">%1$s</xliff:g>: <xliff:g id="TIME">%2$s</xliff:g> aproximadament per esgotar la bateria"</string>
- <string name="power_discharging_duration_enhanced" msgid="4401782117770255046">"<xliff:g id="LEVEL">%1$s</xliff:g>; temps restant aproximat segons l\'ús que en fas: <xliff:g id="TIME">%2$s</xliff:g>"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="default" msgid="7679005631124015335">"<xliff:g id="LEVEL">%1$s</xliff:g>: és possible que el telèfon s\'apagui aviat"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="tablet" msgid="261050880878965621">"<xliff:g id="LEVEL">%1$s</xliff:g>: és possible que la tauleta s\'apagui aviat"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="device" msgid="2020049829798578618">"<xliff:g id="LEVEL">%1$s</xliff:g>: és possible que el dispositiu s\'apagui aviat"</string>
+ <!-- no translation found for power_remaining_less_than_duration (5751885147712659423) -->
+ <skip />
+ <!-- no translation found for power_remaining_more_than_subtext (3176771815132876675) -->
+ <skip />
+ <!-- no translation found for power_remaining_only_more_than_subtext (8931654680569617380) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (1181059207608751924) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (2606370266981054691) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (2918084807716859985) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (3090926004324573908) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (7466484148515796216) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (603933521600231649) -->
+ <skip />
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g>: <xliff:g id="STATE">%2$s</xliff:g>"</string>
+ <string name="power_remaining_charging_duration_only" msgid="1421102457410268886">"<xliff:g id="TIME">%1$s</xliff:g> per completar la càrrega"</string>
<string name="power_charging_duration" msgid="4676999980973411875">"<xliff:g id="LEVEL">%1$s</xliff:g>: <xliff:g id="TIME">%2$s</xliff:g> per completar la càrrega"</string>
<string name="battery_info_status_unknown" msgid="196130600938058547">"Desconegut"</string>
<string name="battery_info_status_charging" msgid="1705179948350365604">"S\'està carregant"</string>
diff --git a/packages/SettingsLib/res/values-cs/strings.xml b/packages/SettingsLib/res/values-cs/strings.xml
index e6000c1..98455dd 100644
--- a/packages/SettingsLib/res/values-cs/strings.xml
+++ b/packages/SettingsLib/res/values-cs/strings.xml
@@ -220,7 +220,8 @@
<string name="select_private_dns_configuration_title" msgid="3700456559305263922">"Soukromé DNS"</string>
<string name="select_private_dns_configuration_dialog_title" msgid="9221994415765826811">"Vyberte soukromý režim DNS"</string>
<string name="private_dns_mode_off" msgid="8236575187318721684">"Vypnuto"</string>
- <string name="private_dns_mode_opportunistic" msgid="7608409735589131766">"Příležitostné"</string>
+ <!-- no translation found for private_dns_mode_opportunistic (8314986739896927399) -->
+ <skip />
<string name="private_dns_mode_provider" msgid="8354935160639360804">"Název hostitele poskytovatele soukromého DNS"</string>
<string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"Zadejte název hostitele poskytovatele DNS"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Zobrazit možnosti certifikace bezdrátového displeje"</string>
@@ -356,22 +357,41 @@
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Funkce je experimentální a může mít vliv na výkon."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"Přepsáno nastavením <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="power_remaining_duration_only" msgid="845431008899029842">"Zbývá asi <xliff:g id="TIME">%1$s</xliff:g>"</string>
+ <!-- no translation found for power_discharging_duration (6655472132189365839) -->
+ <skip />
<string name="power_remaining_duration_only_enhanced" msgid="5992456722677973678">"Při vašem obvyklém využití zbývá asi <xliff:g id="TIME">%1$s</xliff:g>"</string>
- <string name="power_remaining_charging_duration_only" msgid="1421102457410268886">"Plně se nabije za <xliff:g id="TIME">%1$s</xliff:g>"</string>
+ <!-- no translation found for power_discharging_duration_enhanced (5726302316642148671) -->
+ <skip />
<string name="power_remaining_duration_only_short" msgid="5329694252258605547">"Zbývající čas: <xliff:g id="TIME">%1$s</xliff:g>"</string>
+ <!-- no translation found for power_discharge_by_enhanced (8788299408879961465) -->
+ <skip />
+ <!-- no translation found for power_discharge_by_only_enhanced (7692297898877104416) -->
+ <skip />
+ <!-- no translation found for power_discharge_by (6427074755635635749) -->
+ <skip />
+ <!-- no translation found for power_discharge_by_only (5888058889261108064) -->
+ <skip />
<string name="power_remaining_less_than_duration_only" msgid="5996752448813295329">"Zbývá méně než <xliff:g id="THRESHOLD">%1$s</xliff:g>"</string>
- <string name="power_remaining_less_than_duration" msgid="7967078125657859046">"<xliff:g id="LEVEL">%1$s</xliff:g> – zbývá méně než <xliff:g id="THRESHOLD">%2$s</xliff:g>"</string>
- <string name="power_remaining_more_than_subtext" msgid="6846716609975752316">"<xliff:g id="LEVEL">%1$s</xliff:g> – zbývá více než <xliff:g id="TIME_REMAINING">%2$s</xliff:g>"</string>
- <string name="power_remaining_only_more_than_subtext" msgid="8884488700395194194">"zbývá více než <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="default" msgid="8168317165722752881">"telefon se brzy vypne"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="tablet" msgid="5957064378548718872">"tablet se brzy vypne"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="device" msgid="9055596817716471373">"zařízení se brzy vypne"</string>
- <string name="power_discharging_duration" msgid="2843747179907396142">"<xliff:g id="LEVEL">%1$s</xliff:g> – zbývá přibližně <xliff:g id="TIME">%2$s</xliff:g>"</string>
- <string name="power_discharging_duration_enhanced" msgid="4401782117770255046">"<xliff:g id="LEVEL">%1$s</xliff:g> – při vašem obvyklém využití zbývá asi <xliff:g id="TIME">%2$s</xliff:g>"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="default" msgid="7679005631124015335">"<xliff:g id="LEVEL">%1$s</xliff:g> – telefon se brzy vypne"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="tablet" msgid="261050880878965621">"<xliff:g id="LEVEL">%1$s</xliff:g> – tablet se brzy vypne"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="device" msgid="2020049829798578618">"<xliff:g id="LEVEL">%1$s</xliff:g> – zařízení se brzy vypne"</string>
+ <!-- no translation found for power_remaining_less_than_duration (5751885147712659423) -->
+ <skip />
+ <!-- no translation found for power_remaining_more_than_subtext (3176771815132876675) -->
+ <skip />
+ <!-- no translation found for power_remaining_only_more_than_subtext (8931654680569617380) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (1181059207608751924) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (2606370266981054691) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (2918084807716859985) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (3090926004324573908) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (7466484148515796216) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (603933521600231649) -->
+ <skip />
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string>
+ <string name="power_remaining_charging_duration_only" msgid="1421102457410268886">"Plně se nabije za <xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="4676999980973411875">"<xliff:g id="LEVEL">%1$s</xliff:g> – plně se nabije za <xliff:g id="TIME">%2$s</xliff:g>"</string>
<string name="battery_info_status_unknown" msgid="196130600938058547">"Neznámé"</string>
<string name="battery_info_status_charging" msgid="1705179948350365604">"Nabíjí se"</string>
diff --git a/packages/SettingsLib/res/values-da/strings.xml b/packages/SettingsLib/res/values-da/strings.xml
index aa3e6b4..291d4ab 100644
--- a/packages/SettingsLib/res/values-da/strings.xml
+++ b/packages/SettingsLib/res/values-da/strings.xml
@@ -220,7 +220,8 @@
<string name="select_private_dns_configuration_title" msgid="3700456559305263922">"Privat DNS"</string>
<string name="select_private_dns_configuration_dialog_title" msgid="9221994415765826811">"Vælg privat DNS-tilstand"</string>
<string name="private_dns_mode_off" msgid="8236575187318721684">"Fra"</string>
- <string name="private_dns_mode_opportunistic" msgid="7608409735589131766">"Opportunistisk"</string>
+ <!-- no translation found for private_dns_mode_opportunistic (8314986739896927399) -->
+ <skip />
<string name="private_dns_mode_provider" msgid="8354935160639360804">"Hostname for privat DNS-udbyder"</string>
<string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"Angiv hostname for DNS-udbyder"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Vis valgmuligheder for certificering af trådløs skærm"</string>
@@ -356,22 +357,41 @@
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Denne funktion er eksperimentel og kan påvirke ydeevnen."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"Tilsidesat af <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="power_remaining_duration_only" msgid="845431008899029842">"Ca. <xliff:g id="TIME">%1$s</xliff:g> tilbage"</string>
+ <!-- no translation found for power_discharging_duration (6655472132189365839) -->
+ <skip />
<string name="power_remaining_duration_only_enhanced" msgid="5992456722677973678">"Der er ca. <xliff:g id="TIME">%1$s</xliff:g> tilbage, alt efter hvordan du bruger enheden"</string>
- <string name="power_remaining_charging_duration_only" msgid="1421102457410268886">"<xliff:g id="TIME">%1$s</xliff:g> til det er fuldt opladet"</string>
+ <!-- no translation found for power_discharging_duration_enhanced (5726302316642148671) -->
+ <skip />
<string name="power_remaining_duration_only_short" msgid="5329694252258605547">"<xliff:g id="TIME">%1$s</xliff:g> tilbage"</string>
+ <!-- no translation found for power_discharge_by_enhanced (8788299408879961465) -->
+ <skip />
+ <!-- no translation found for power_discharge_by_only_enhanced (7692297898877104416) -->
+ <skip />
+ <!-- no translation found for power_discharge_by (6427074755635635749) -->
+ <skip />
+ <!-- no translation found for power_discharge_by_only (5888058889261108064) -->
+ <skip />
<string name="power_remaining_less_than_duration_only" msgid="5996752448813295329">"Der er mindre end <xliff:g id="THRESHOLD">%1$s</xliff:g> tilbage"</string>
- <string name="power_remaining_less_than_duration" msgid="7967078125657859046">"<xliff:g id="LEVEL">%1$s</xliff:g> – der er mindre end <xliff:g id="THRESHOLD">%2$s</xliff:g> tilbage"</string>
- <string name="power_remaining_more_than_subtext" msgid="6846716609975752316">"<xliff:g id="LEVEL">%1$s</xliff:g> – der er mere end <xliff:g id="TIME_REMAINING">%2$s</xliff:g> tilbage"</string>
- <string name="power_remaining_only_more_than_subtext" msgid="8884488700395194194">"der er mere end <xliff:g id="TIME_REMAINING">%1$s</xliff:g> tilbage"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="default" msgid="8168317165722752881">"telefonen lukker muligvis snart ned"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="tablet" msgid="5957064378548718872">"denne tablet lukker muligvis snart ned"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="device" msgid="9055596817716471373">"enheden lukker muligvis snart ned"</string>
- <string name="power_discharging_duration" msgid="2843747179907396142">"<xliff:g id="LEVEL">%1$s</xliff:g> – ca. <xliff:g id="TIME">%2$s</xliff:g> tilbage"</string>
- <string name="power_discharging_duration_enhanced" msgid="4401782117770255046">"<xliff:g id="LEVEL">%1$s</xliff:g> – der er ca. <xliff:g id="TIME">%2$s</xliff:g> tilbage, alt efter hvordan du bruger enheden"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="default" msgid="7679005631124015335">"<xliff:g id="LEVEL">%1$s</xliff:g> – telefonen lukker muligvis snart ned"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="tablet" msgid="261050880878965621">"<xliff:g id="LEVEL">%1$s</xliff:g> – denne tablet lukker muligvis snart ned"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="device" msgid="2020049829798578618">"<xliff:g id="LEVEL">%1$s</xliff:g> – enheden lukker muligvis snart ned"</string>
+ <!-- no translation found for power_remaining_less_than_duration (5751885147712659423) -->
+ <skip />
+ <!-- no translation found for power_remaining_more_than_subtext (3176771815132876675) -->
+ <skip />
+ <!-- no translation found for power_remaining_only_more_than_subtext (8931654680569617380) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (1181059207608751924) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (2606370266981054691) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (2918084807716859985) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (3090926004324573908) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (7466484148515796216) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (603933521600231649) -->
+ <skip />
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string>
+ <string name="power_remaining_charging_duration_only" msgid="1421102457410268886">"<xliff:g id="TIME">%1$s</xliff:g> til det er fuldt opladet"</string>
<string name="power_charging_duration" msgid="4676999980973411875">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> til det er fuldt opladet"</string>
<string name="battery_info_status_unknown" msgid="196130600938058547">"Ukendt"</string>
<string name="battery_info_status_charging" msgid="1705179948350365604">"Oplader"</string>
diff --git a/packages/SettingsLib/res/values-de/strings.xml b/packages/SettingsLib/res/values-de/strings.xml
index 5210419..84e33bc 100644
--- a/packages/SettingsLib/res/values-de/strings.xml
+++ b/packages/SettingsLib/res/values-de/strings.xml
@@ -56,14 +56,14 @@
<string name="bluetooth_connected" msgid="5427152882755735944">"Mit <xliff:g id="ACTIVE_DEVICE">%1$s</xliff:g> verbunden"</string>
<string name="bluetooth_pairing" msgid="1426882272690346242">"Verbindung wird hergestellt…"</string>
<string name="bluetooth_connected_no_headset" msgid="616068069034994802">"Mit <xliff:g id="ACTIVE_DEVICE">%1$s</xliff:g> verbunden (kein Telefon-Audio)"</string>
- <string name="bluetooth_connected_no_a2dp" msgid="3736431800395923868">"Mit <xliff:g id="ACTIVE_DEVICE">%1$s</xliff:g> verbunden (kein Media-Audio)"</string>
+ <string name="bluetooth_connected_no_a2dp" msgid="3736431800395923868">"Mit <xliff:g id="ACTIVE_DEVICE">%1$s</xliff:g> verbunden (kein Medien-Audio)"</string>
<string name="bluetooth_connected_no_map" msgid="3200033913678466453">"Mit <xliff:g id="ACTIVE_DEVICE">%1$s</xliff:g> verbunden (kein Nachrichtenzugriff)"</string>
- <string name="bluetooth_connected_no_headset_no_a2dp" msgid="2047403011284187056">"Mit <xliff:g id="ACTIVE_DEVICE">%1$s</xliff:g> verbunden (weder Telefon- noch Media-Audio)"</string>
+ <string name="bluetooth_connected_no_headset_no_a2dp" msgid="2047403011284187056">"Mit <xliff:g id="ACTIVE_DEVICE">%1$s</xliff:g> verbunden (weder Telefon- noch Medien-Audio)"</string>
<string name="bluetooth_connected_battery_level" msgid="5162924691231307748">"Mit <xliff:g id="ACTIVE_DEVICE">%2$s</xliff:g> verbunden, Akkustand bei <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
<string name="bluetooth_connected_no_headset_battery_level" msgid="1610296229139400266">"Mit <xliff:g id="ACTIVE_DEVICE">%2$s</xliff:g> verbunden (kein Telefon-Audio), Akkustand bei <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
- <string name="bluetooth_connected_no_a2dp_battery_level" msgid="3908466636369853652">"Mit <xliff:g id="ACTIVE_DEVICE">%2$s</xliff:g> verbunden (kein Media-Audio), Akkustand bei <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
- <string name="bluetooth_connected_no_headset_no_a2dp_battery_level" msgid="1163440823807659316">"Mit <xliff:g id="ACTIVE_DEVICE">%2$s</xliff:g> verbunden (weder Telefon- noch Media-Audio), Akkustand bei <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
- <string name="bluetooth_profile_a2dp" msgid="2031475486179830674">"Media-Audio"</string>
+ <string name="bluetooth_connected_no_a2dp_battery_level" msgid="3908466636369853652">"Mit <xliff:g id="ACTIVE_DEVICE">%2$s</xliff:g> verbunden (kein Medien-Audio), Akkustand bei <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
+ <string name="bluetooth_connected_no_headset_no_a2dp_battery_level" msgid="1163440823807659316">"Mit <xliff:g id="ACTIVE_DEVICE">%2$s</xliff:g> verbunden (weder Telefon- noch Medien-Audio), Akkustand bei <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
+ <string name="bluetooth_profile_a2dp" msgid="2031475486179830674">"Medien-Audio"</string>
<string name="bluetooth_profile_headset" msgid="7815495680863246034">"Telefonanrufe"</string>
<string name="bluetooth_profile_opp" msgid="9168139293654233697">"Dateiübertragung"</string>
<string name="bluetooth_profile_hid" msgid="3680729023366986480">"Eingabegerät"</string>
@@ -77,8 +77,8 @@
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="8510588052415438887">"HD-Audio"</string>
<string name="bluetooth_profile_hearing_aid" msgid="7999237886427812595">"Hörhilfe"</string>
<string name="bluetooth_hearing_aid_profile_summary_connected" msgid="7188282786730266159">"Mit Hörhilfe verbunden"</string>
- <string name="bluetooth_a2dp_profile_summary_connected" msgid="963376081347721598">"Verbunden mit Audiosystem von Medien"</string>
- <string name="bluetooth_headset_profile_summary_connected" msgid="7661070206715520671">"Verbunden mit Audiosystem des Telefons"</string>
+ <string name="bluetooth_a2dp_profile_summary_connected" msgid="963376081347721598">"Verbunden mit Medien-Audio"</string>
+ <string name="bluetooth_headset_profile_summary_connected" msgid="7661070206715520671">"Verbunden mit Telefon-Audio"</string>
<string name="bluetooth_opp_profile_summary_connected" msgid="2611913495968309066">"Mit Dateiübertragungsserver verbunden"</string>
<string name="bluetooth_map_profile_summary_connected" msgid="8191407438851351713">"Mit Karte verbunden"</string>
<string name="bluetooth_sap_profile_summary_connected" msgid="8561765057453083838">"Mit SAP verbunden"</string>
@@ -89,8 +89,8 @@
<string name="bluetooth_pan_profile_summary_use_for" msgid="5736111170225304239">"Für Internetzugriff verwenden"</string>
<string name="bluetooth_map_profile_summary_use_for" msgid="5154200119919927434">"Für Karte verwenden"</string>
<string name="bluetooth_sap_profile_summary_use_for" msgid="7085362712786907993">"Für SIM-Zugriff verwenden"</string>
- <string name="bluetooth_a2dp_profile_summary_use_for" msgid="4630849022250168427">"Für Audiosystem von Medien verwenden"</string>
- <string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"Für Audiosystem des Telefons verwenden"</string>
+ <string name="bluetooth_a2dp_profile_summary_use_for" msgid="4630849022250168427">"Für Medien-Audio verwenden"</string>
+ <string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"Für Telefon-Audio verwenden"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"Für Dateiübertragung verwenden"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="232727040453645139">"Für Eingabe verwenden"</string>
<string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="908775281788309484">"Für Hörhilfe verwenden"</string>
@@ -220,7 +220,8 @@
<string name="select_private_dns_configuration_title" msgid="3700456559305263922">"Privates DNS"</string>
<string name="select_private_dns_configuration_dialog_title" msgid="9221994415765826811">"Privaten DNS-Modus auswählen"</string>
<string name="private_dns_mode_off" msgid="8236575187318721684">"Aus"</string>
- <string name="private_dns_mode_opportunistic" msgid="7608409735589131766">"Opportunistisch"</string>
+ <!-- no translation found for private_dns_mode_opportunistic (8314986739896927399) -->
+ <skip />
<string name="private_dns_mode_provider" msgid="8354935160639360804">"Hostname des privaten DNS-Anbieters"</string>
<string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"Hostname des DNS-Anbieters eingeben"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Optionen zur Zertifizierung für kabellose Übertragung anzeigen"</string>
@@ -356,22 +357,41 @@
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Hierbei handelt es sich um eine experimentelle Funktion, die sich auf die Leistung auswirken kann."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"Außer Kraft gesetzt von \"<xliff:g id="TITLE">%1$s</xliff:g>\""</string>
<string name="power_remaining_duration_only" msgid="845431008899029842">"Ca. <xliff:g id="TIME">%1$s</xliff:g> übrig"</string>
+ <!-- no translation found for power_discharging_duration (6655472132189365839) -->
+ <skip />
<string name="power_remaining_duration_only_enhanced" msgid="5992456722677973678">"Noch ca. <xliff:g id="TIME">%1$s</xliff:g>, basierend auf deiner Nutzung"</string>
- <string name="power_remaining_charging_duration_only" msgid="1421102457410268886">"<xliff:g id="TIME">%1$s</xliff:g> bis zur vollständigen Aufladung"</string>
+ <!-- no translation found for power_discharging_duration_enhanced (5726302316642148671) -->
+ <skip />
<string name="power_remaining_duration_only_short" msgid="5329694252258605547">"Noch <xliff:g id="TIME">%1$s</xliff:g>"</string>
+ <!-- no translation found for power_discharge_by_enhanced (8788299408879961465) -->
+ <skip />
+ <!-- no translation found for power_discharge_by_only_enhanced (7692297898877104416) -->
+ <skip />
+ <!-- no translation found for power_discharge_by (6427074755635635749) -->
+ <skip />
+ <!-- no translation found for power_discharge_by_only (5888058889261108064) -->
+ <skip />
<string name="power_remaining_less_than_duration_only" msgid="5996752448813295329">"Weniger als <xliff:g id="THRESHOLD">%1$s</xliff:g> verbleibend"</string>
- <string name="power_remaining_less_than_duration" msgid="7967078125657859046">"<xliff:g id="LEVEL">%1$s</xliff:g> – weniger als <xliff:g id="THRESHOLD">%2$s</xliff:g> verbleibend"</string>
- <string name="power_remaining_more_than_subtext" msgid="6846716609975752316">"<xliff:g id="LEVEL">%1$s</xliff:g> – mehr als <xliff:g id="TIME_REMAINING">%2$s</xliff:g> verbleibend"</string>
- <string name="power_remaining_only_more_than_subtext" msgid="8884488700395194194">"mehr als <xliff:g id="TIME_REMAINING">%1$s</xliff:g> verbleibend"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="default" msgid="8168317165722752881">"Smartphone wird bald ausgeschaltet"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="tablet" msgid="5957064378548718872">"Tablet wird bald ausgeschaltet"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="device" msgid="9055596817716471373">"Gerät wird bald ausgeschaltet"</string>
- <string name="power_discharging_duration" msgid="2843747179907396142">"<xliff:g id="LEVEL">%1$s</xliff:g> – ungefähr noch <xliff:g id="TIME">%2$s</xliff:g>"</string>
- <string name="power_discharging_duration_enhanced" msgid="4401782117770255046">"<xliff:g id="LEVEL">%1$s</xliff:g> – noch ca. <xliff:g id="TIME">%2$s</xliff:g>, basierend auf deiner Nutzung"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="default" msgid="7679005631124015335">"<xliff:g id="LEVEL">%1$s</xliff:g> – Smartphone wird bald ausgeschaltet"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="tablet" msgid="261050880878965621">"<xliff:g id="LEVEL">%1$s</xliff:g> – Tablet wird bald ausgeschaltet"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="device" msgid="2020049829798578618">"<xliff:g id="LEVEL">%1$s</xliff:g> – Gerät wird bald ausgeschaltet"</string>
+ <!-- no translation found for power_remaining_less_than_duration (5751885147712659423) -->
+ <skip />
+ <!-- no translation found for power_remaining_more_than_subtext (3176771815132876675) -->
+ <skip />
+ <!-- no translation found for power_remaining_only_more_than_subtext (8931654680569617380) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (1181059207608751924) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (2606370266981054691) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (2918084807716859985) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (3090926004324573908) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (7466484148515796216) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (603933521600231649) -->
+ <skip />
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string>
+ <string name="power_remaining_charging_duration_only" msgid="1421102457410268886">"<xliff:g id="TIME">%1$s</xliff:g> bis zur vollständigen Aufladung"</string>
<string name="power_charging_duration" msgid="4676999980973411875">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> bis vollständig geladen"</string>
<string name="battery_info_status_unknown" msgid="196130600938058547">"Unbekannt"</string>
<string name="battery_info_status_charging" msgid="1705179948350365604">"Wird aufgeladen"</string>
diff --git a/packages/SettingsLib/res/values-el/strings.xml b/packages/SettingsLib/res/values-el/strings.xml
index fe1c6bc..55b0171 100644
--- a/packages/SettingsLib/res/values-el/strings.xml
+++ b/packages/SettingsLib/res/values-el/strings.xml
@@ -220,7 +220,8 @@
<string name="select_private_dns_configuration_title" msgid="3700456559305263922">"Ιδιωτικό DNS"</string>
<string name="select_private_dns_configuration_dialog_title" msgid="9221994415765826811">"Επιλέξτε τη λειτουργία ιδιωτικού DNS"</string>
<string name="private_dns_mode_off" msgid="8236575187318721684">"Ανενεργή"</string>
- <string name="private_dns_mode_opportunistic" msgid="7608409735589131766">"Καιροσκοπική"</string>
+ <!-- no translation found for private_dns_mode_opportunistic (8314986739896927399) -->
+ <skip />
<string name="private_dns_mode_provider" msgid="8354935160639360804">"Όνομα κεντρικού υπολογιστή παρόχου DNS"</string>
<string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"Εισαγάγετε το όνομα κεντρικού υπολογιστή του παρόχου DNS"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Εμφάνιση επιλογών για πιστοποίηση ασύρματης οθόνης"</string>
@@ -356,22 +357,41 @@
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Αυτή η λειτουργία είναι πειραματική και ενδεχομένως να επηρεάσει τις επιδόσεις."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"Αντικαταστάθηκε από <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="power_remaining_duration_only" msgid="845431008899029842">"Απομένουν περίπου <xliff:g id="TIME">%1$s</xliff:g>"</string>
+ <!-- no translation found for power_discharging_duration (6655472132189365839) -->
+ <skip />
<string name="power_remaining_duration_only_enhanced" msgid="5992456722677973678">"Απομένει/ουν περίπου <xliff:g id="TIME">%1$s</xliff:g> με βάση τη χρήση σας"</string>
- <string name="power_remaining_charging_duration_only" msgid="1421102457410268886">"Απομένουν <xliff:g id="TIME">%1$s</xliff:g> έως την πλήρη φόρτιση"</string>
+ <!-- no translation found for power_discharging_duration_enhanced (5726302316642148671) -->
+ <skip />
<string name="power_remaining_duration_only_short" msgid="5329694252258605547">"Απομένει/ουν <xliff:g id="TIME">%1$s</xliff:g>"</string>
+ <!-- no translation found for power_discharge_by_enhanced (8788299408879961465) -->
+ <skip />
+ <!-- no translation found for power_discharge_by_only_enhanced (7692297898877104416) -->
+ <skip />
+ <!-- no translation found for power_discharge_by (6427074755635635749) -->
+ <skip />
+ <!-- no translation found for power_discharge_by_only (5888058889261108064) -->
+ <skip />
<string name="power_remaining_less_than_duration_only" msgid="5996752448813295329">"Απομένει/ουν λιγότερo/α από <xliff:g id="THRESHOLD">%1$s</xliff:g>"</string>
- <string name="power_remaining_less_than_duration" msgid="7967078125657859046">"<xliff:g id="LEVEL">%1$s</xliff:g> - Απομένει λιγότερo από <xliff:g id="THRESHOLD">%2$s</xliff:g>"</string>
- <string name="power_remaining_more_than_subtext" msgid="6846716609975752316">"<xliff:g id="LEVEL">%1$s</xliff:g> - Απομένει περισσότερο από <xliff:g id="TIME_REMAINING">%2$s</xliff:g>"</string>
- <string name="power_remaining_only_more_than_subtext" msgid="8884488700395194194">"απομένουν περισσότερα/ες από <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="default" msgid="8168317165722752881">"το τηλέφωνο μπορεί να απενεργοποιηθεί σύντομα"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="tablet" msgid="5957064378548718872">"το tablet μπορεί να απενεργοποιηθεί σύντομα"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="device" msgid="9055596817716471373">"η συσκευή μπορεί να απενεργοποιηθεί σύντομα"</string>
- <string name="power_discharging_duration" msgid="2843747179907396142">"<xliff:g id="LEVEL">%1$s</xliff:g> - απομένουν περίπου <xliff:g id="TIME">%2$s</xliff:g>"</string>
- <string name="power_discharging_duration_enhanced" msgid="4401782117770255046">"<xliff:g id="LEVEL">%1$s</xliff:g> - Απομένει/ουν περίπου <xliff:g id="TIME">%2$s</xliff:g> με βάση τη χρήση σας"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="default" msgid="7679005631124015335">"<xliff:g id="LEVEL">%1$s</xliff:g> - το τηλέφωνο μπορεί να απενεργοποιηθεί σύντομα"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="tablet" msgid="261050880878965621">"<xliff:g id="LEVEL">%1$s</xliff:g> - το tablet μπορεί να απενεργοποιηθεί σύντομα"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="device" msgid="2020049829798578618">"<xliff:g id="LEVEL">%1$s</xliff:g> - η συσκευή μπορεί να απενεργοποιηθεί σύντομα"</string>
+ <!-- no translation found for power_remaining_less_than_duration (5751885147712659423) -->
+ <skip />
+ <!-- no translation found for power_remaining_more_than_subtext (3176771815132876675) -->
+ <skip />
+ <!-- no translation found for power_remaining_only_more_than_subtext (8931654680569617380) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (1181059207608751924) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (2606370266981054691) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (2918084807716859985) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (3090926004324573908) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (7466484148515796216) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (603933521600231649) -->
+ <skip />
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
+ <string name="power_remaining_charging_duration_only" msgid="1421102457410268886">"Απομένουν <xliff:g id="TIME">%1$s</xliff:g> έως την πλήρη φόρτιση"</string>
<string name="power_charging_duration" msgid="4676999980973411875">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> για πλήρη φόρτιση"</string>
<string name="battery_info_status_unknown" msgid="196130600938058547">"Άγνωστο"</string>
<string name="battery_info_status_charging" msgid="1705179948350365604">"Φόρτιση"</string>
diff --git a/packages/SettingsLib/res/values-en-rAU/strings.xml b/packages/SettingsLib/res/values-en-rAU/strings.xml
index 5b8adcf..8ff83b0 100644
--- a/packages/SettingsLib/res/values-en-rAU/strings.xml
+++ b/packages/SettingsLib/res/values-en-rAU/strings.xml
@@ -220,7 +220,8 @@
<string name="select_private_dns_configuration_title" msgid="3700456559305263922">"Private DNS"</string>
<string name="select_private_dns_configuration_dialog_title" msgid="9221994415765826811">"Select private DNS mode"</string>
<string name="private_dns_mode_off" msgid="8236575187318721684">"Off"</string>
- <string name="private_dns_mode_opportunistic" msgid="7608409735589131766">"Opportunistic"</string>
+ <!-- no translation found for private_dns_mode_opportunistic (8314986739896927399) -->
+ <skip />
<string name="private_dns_mode_provider" msgid="8354935160639360804">"Private DNS provider hostname"</string>
<string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"Enter hostname of DNS provider"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Show options for wireless display certification"</string>
@@ -356,22 +357,41 @@
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"This feature is experimental and may affect performance."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"Overridden by <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="power_remaining_duration_only" msgid="845431008899029842">"About <xliff:g id="TIME">%1$s</xliff:g> left"</string>
+ <!-- no translation found for power_discharging_duration (6655472132189365839) -->
+ <skip />
<string name="power_remaining_duration_only_enhanced" msgid="5992456722677973678">"About <xliff:g id="TIME">%1$s</xliff:g> left based on your usage"</string>
- <string name="power_remaining_charging_duration_only" msgid="1421102457410268886">"<xliff:g id="TIME">%1$s</xliff:g> left until fully charged"</string>
+ <!-- no translation found for power_discharging_duration_enhanced (5726302316642148671) -->
+ <skip />
<string name="power_remaining_duration_only_short" msgid="5329694252258605547">"<xliff:g id="TIME">%1$s</xliff:g> left"</string>
+ <!-- no translation found for power_discharge_by_enhanced (8788299408879961465) -->
+ <skip />
+ <!-- no translation found for power_discharge_by_only_enhanced (7692297898877104416) -->
+ <skip />
+ <!-- no translation found for power_discharge_by (6427074755635635749) -->
+ <skip />
+ <!-- no translation found for power_discharge_by_only (5888058889261108064) -->
+ <skip />
<string name="power_remaining_less_than_duration_only" msgid="5996752448813295329">"Less than <xliff:g id="THRESHOLD">%1$s</xliff:g> remaining"</string>
- <string name="power_remaining_less_than_duration" msgid="7967078125657859046">"<xliff:g id="LEVEL">%1$s</xliff:g> - Less than <xliff:g id="THRESHOLD">%2$s</xliff:g> remaining"</string>
- <string name="power_remaining_more_than_subtext" msgid="6846716609975752316">"<xliff:g id="LEVEL">%1$s</xliff:g>more than <xliff:g id="TIME_REMAINING">%2$s</xliff:g> remaining"</string>
- <string name="power_remaining_only_more_than_subtext" msgid="8884488700395194194">"more than <xliff:g id="TIME_REMAINING">%1$s</xliff:g> remaining"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="default" msgid="8168317165722752881">"phone may shutdown soon"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="tablet" msgid="5957064378548718872">"tablet may shutdown soon"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="device" msgid="9055596817716471373">"device may shutdown soon"</string>
- <string name="power_discharging_duration" msgid="2843747179907396142">"<xliff:g id="LEVEL">%1$s</xliff:g> – about <xliff:g id="TIME">%2$s</xliff:g> left"</string>
- <string name="power_discharging_duration_enhanced" msgid="4401782117770255046">"<xliff:g id="LEVEL">%1$s</xliff:g> - about <xliff:g id="TIME">%2$s</xliff:g> left based on your usage"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="default" msgid="7679005631124015335">"<xliff:g id="LEVEL">%1$s</xliff:g> - phone may shutdown soon"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="tablet" msgid="261050880878965621">"<xliff:g id="LEVEL">%1$s</xliff:g> - tablet may shutdown soon"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="device" msgid="2020049829798578618">"<xliff:g id="LEVEL">%1$s</xliff:g> - device may shutdown soon"</string>
+ <!-- no translation found for power_remaining_less_than_duration (5751885147712659423) -->
+ <skip />
+ <!-- no translation found for power_remaining_more_than_subtext (3176771815132876675) -->
+ <skip />
+ <!-- no translation found for power_remaining_only_more_than_subtext (8931654680569617380) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (1181059207608751924) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (2606370266981054691) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (2918084807716859985) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (3090926004324573908) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (7466484148515796216) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (603933521600231649) -->
+ <skip />
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
+ <string name="power_remaining_charging_duration_only" msgid="1421102457410268886">"<xliff:g id="TIME">%1$s</xliff:g> left until fully charged"</string>
<string name="power_charging_duration" msgid="4676999980973411875">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> until fully charged"</string>
<string name="battery_info_status_unknown" msgid="196130600938058547">"Unknown"</string>
<string name="battery_info_status_charging" msgid="1705179948350365604">"Charging"</string>
diff --git a/packages/SettingsLib/res/values-en-rCA/strings.xml b/packages/SettingsLib/res/values-en-rCA/strings.xml
index 5b8adcf..8ff83b0 100644
--- a/packages/SettingsLib/res/values-en-rCA/strings.xml
+++ b/packages/SettingsLib/res/values-en-rCA/strings.xml
@@ -220,7 +220,8 @@
<string name="select_private_dns_configuration_title" msgid="3700456559305263922">"Private DNS"</string>
<string name="select_private_dns_configuration_dialog_title" msgid="9221994415765826811">"Select private DNS mode"</string>
<string name="private_dns_mode_off" msgid="8236575187318721684">"Off"</string>
- <string name="private_dns_mode_opportunistic" msgid="7608409735589131766">"Opportunistic"</string>
+ <!-- no translation found for private_dns_mode_opportunistic (8314986739896927399) -->
+ <skip />
<string name="private_dns_mode_provider" msgid="8354935160639360804">"Private DNS provider hostname"</string>
<string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"Enter hostname of DNS provider"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Show options for wireless display certification"</string>
@@ -356,22 +357,41 @@
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"This feature is experimental and may affect performance."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"Overridden by <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="power_remaining_duration_only" msgid="845431008899029842">"About <xliff:g id="TIME">%1$s</xliff:g> left"</string>
+ <!-- no translation found for power_discharging_duration (6655472132189365839) -->
+ <skip />
<string name="power_remaining_duration_only_enhanced" msgid="5992456722677973678">"About <xliff:g id="TIME">%1$s</xliff:g> left based on your usage"</string>
- <string name="power_remaining_charging_duration_only" msgid="1421102457410268886">"<xliff:g id="TIME">%1$s</xliff:g> left until fully charged"</string>
+ <!-- no translation found for power_discharging_duration_enhanced (5726302316642148671) -->
+ <skip />
<string name="power_remaining_duration_only_short" msgid="5329694252258605547">"<xliff:g id="TIME">%1$s</xliff:g> left"</string>
+ <!-- no translation found for power_discharge_by_enhanced (8788299408879961465) -->
+ <skip />
+ <!-- no translation found for power_discharge_by_only_enhanced (7692297898877104416) -->
+ <skip />
+ <!-- no translation found for power_discharge_by (6427074755635635749) -->
+ <skip />
+ <!-- no translation found for power_discharge_by_only (5888058889261108064) -->
+ <skip />
<string name="power_remaining_less_than_duration_only" msgid="5996752448813295329">"Less than <xliff:g id="THRESHOLD">%1$s</xliff:g> remaining"</string>
- <string name="power_remaining_less_than_duration" msgid="7967078125657859046">"<xliff:g id="LEVEL">%1$s</xliff:g> - Less than <xliff:g id="THRESHOLD">%2$s</xliff:g> remaining"</string>
- <string name="power_remaining_more_than_subtext" msgid="6846716609975752316">"<xliff:g id="LEVEL">%1$s</xliff:g>more than <xliff:g id="TIME_REMAINING">%2$s</xliff:g> remaining"</string>
- <string name="power_remaining_only_more_than_subtext" msgid="8884488700395194194">"more than <xliff:g id="TIME_REMAINING">%1$s</xliff:g> remaining"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="default" msgid="8168317165722752881">"phone may shutdown soon"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="tablet" msgid="5957064378548718872">"tablet may shutdown soon"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="device" msgid="9055596817716471373">"device may shutdown soon"</string>
- <string name="power_discharging_duration" msgid="2843747179907396142">"<xliff:g id="LEVEL">%1$s</xliff:g> – about <xliff:g id="TIME">%2$s</xliff:g> left"</string>
- <string name="power_discharging_duration_enhanced" msgid="4401782117770255046">"<xliff:g id="LEVEL">%1$s</xliff:g> - about <xliff:g id="TIME">%2$s</xliff:g> left based on your usage"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="default" msgid="7679005631124015335">"<xliff:g id="LEVEL">%1$s</xliff:g> - phone may shutdown soon"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="tablet" msgid="261050880878965621">"<xliff:g id="LEVEL">%1$s</xliff:g> - tablet may shutdown soon"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="device" msgid="2020049829798578618">"<xliff:g id="LEVEL">%1$s</xliff:g> - device may shutdown soon"</string>
+ <!-- no translation found for power_remaining_less_than_duration (5751885147712659423) -->
+ <skip />
+ <!-- no translation found for power_remaining_more_than_subtext (3176771815132876675) -->
+ <skip />
+ <!-- no translation found for power_remaining_only_more_than_subtext (8931654680569617380) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (1181059207608751924) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (2606370266981054691) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (2918084807716859985) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (3090926004324573908) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (7466484148515796216) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (603933521600231649) -->
+ <skip />
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
+ <string name="power_remaining_charging_duration_only" msgid="1421102457410268886">"<xliff:g id="TIME">%1$s</xliff:g> left until fully charged"</string>
<string name="power_charging_duration" msgid="4676999980973411875">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> until fully charged"</string>
<string name="battery_info_status_unknown" msgid="196130600938058547">"Unknown"</string>
<string name="battery_info_status_charging" msgid="1705179948350365604">"Charging"</string>
diff --git a/packages/SettingsLib/res/values-en-rGB/strings.xml b/packages/SettingsLib/res/values-en-rGB/strings.xml
index 5b8adcf..8ff83b0 100644
--- a/packages/SettingsLib/res/values-en-rGB/strings.xml
+++ b/packages/SettingsLib/res/values-en-rGB/strings.xml
@@ -220,7 +220,8 @@
<string name="select_private_dns_configuration_title" msgid="3700456559305263922">"Private DNS"</string>
<string name="select_private_dns_configuration_dialog_title" msgid="9221994415765826811">"Select private DNS mode"</string>
<string name="private_dns_mode_off" msgid="8236575187318721684">"Off"</string>
- <string name="private_dns_mode_opportunistic" msgid="7608409735589131766">"Opportunistic"</string>
+ <!-- no translation found for private_dns_mode_opportunistic (8314986739896927399) -->
+ <skip />
<string name="private_dns_mode_provider" msgid="8354935160639360804">"Private DNS provider hostname"</string>
<string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"Enter hostname of DNS provider"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Show options for wireless display certification"</string>
@@ -356,22 +357,41 @@
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"This feature is experimental and may affect performance."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"Overridden by <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="power_remaining_duration_only" msgid="845431008899029842">"About <xliff:g id="TIME">%1$s</xliff:g> left"</string>
+ <!-- no translation found for power_discharging_duration (6655472132189365839) -->
+ <skip />
<string name="power_remaining_duration_only_enhanced" msgid="5992456722677973678">"About <xliff:g id="TIME">%1$s</xliff:g> left based on your usage"</string>
- <string name="power_remaining_charging_duration_only" msgid="1421102457410268886">"<xliff:g id="TIME">%1$s</xliff:g> left until fully charged"</string>
+ <!-- no translation found for power_discharging_duration_enhanced (5726302316642148671) -->
+ <skip />
<string name="power_remaining_duration_only_short" msgid="5329694252258605547">"<xliff:g id="TIME">%1$s</xliff:g> left"</string>
+ <!-- no translation found for power_discharge_by_enhanced (8788299408879961465) -->
+ <skip />
+ <!-- no translation found for power_discharge_by_only_enhanced (7692297898877104416) -->
+ <skip />
+ <!-- no translation found for power_discharge_by (6427074755635635749) -->
+ <skip />
+ <!-- no translation found for power_discharge_by_only (5888058889261108064) -->
+ <skip />
<string name="power_remaining_less_than_duration_only" msgid="5996752448813295329">"Less than <xliff:g id="THRESHOLD">%1$s</xliff:g> remaining"</string>
- <string name="power_remaining_less_than_duration" msgid="7967078125657859046">"<xliff:g id="LEVEL">%1$s</xliff:g> - Less than <xliff:g id="THRESHOLD">%2$s</xliff:g> remaining"</string>
- <string name="power_remaining_more_than_subtext" msgid="6846716609975752316">"<xliff:g id="LEVEL">%1$s</xliff:g>more than <xliff:g id="TIME_REMAINING">%2$s</xliff:g> remaining"</string>
- <string name="power_remaining_only_more_than_subtext" msgid="8884488700395194194">"more than <xliff:g id="TIME_REMAINING">%1$s</xliff:g> remaining"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="default" msgid="8168317165722752881">"phone may shutdown soon"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="tablet" msgid="5957064378548718872">"tablet may shutdown soon"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="device" msgid="9055596817716471373">"device may shutdown soon"</string>
- <string name="power_discharging_duration" msgid="2843747179907396142">"<xliff:g id="LEVEL">%1$s</xliff:g> – about <xliff:g id="TIME">%2$s</xliff:g> left"</string>
- <string name="power_discharging_duration_enhanced" msgid="4401782117770255046">"<xliff:g id="LEVEL">%1$s</xliff:g> - about <xliff:g id="TIME">%2$s</xliff:g> left based on your usage"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="default" msgid="7679005631124015335">"<xliff:g id="LEVEL">%1$s</xliff:g> - phone may shutdown soon"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="tablet" msgid="261050880878965621">"<xliff:g id="LEVEL">%1$s</xliff:g> - tablet may shutdown soon"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="device" msgid="2020049829798578618">"<xliff:g id="LEVEL">%1$s</xliff:g> - device may shutdown soon"</string>
+ <!-- no translation found for power_remaining_less_than_duration (5751885147712659423) -->
+ <skip />
+ <!-- no translation found for power_remaining_more_than_subtext (3176771815132876675) -->
+ <skip />
+ <!-- no translation found for power_remaining_only_more_than_subtext (8931654680569617380) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (1181059207608751924) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (2606370266981054691) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (2918084807716859985) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (3090926004324573908) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (7466484148515796216) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (603933521600231649) -->
+ <skip />
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
+ <string name="power_remaining_charging_duration_only" msgid="1421102457410268886">"<xliff:g id="TIME">%1$s</xliff:g> left until fully charged"</string>
<string name="power_charging_duration" msgid="4676999980973411875">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> until fully charged"</string>
<string name="battery_info_status_unknown" msgid="196130600938058547">"Unknown"</string>
<string name="battery_info_status_charging" msgid="1705179948350365604">"Charging"</string>
diff --git a/packages/SettingsLib/res/values-en-rIN/strings.xml b/packages/SettingsLib/res/values-en-rIN/strings.xml
index 5b8adcf..8ff83b0 100644
--- a/packages/SettingsLib/res/values-en-rIN/strings.xml
+++ b/packages/SettingsLib/res/values-en-rIN/strings.xml
@@ -220,7 +220,8 @@
<string name="select_private_dns_configuration_title" msgid="3700456559305263922">"Private DNS"</string>
<string name="select_private_dns_configuration_dialog_title" msgid="9221994415765826811">"Select private DNS mode"</string>
<string name="private_dns_mode_off" msgid="8236575187318721684">"Off"</string>
- <string name="private_dns_mode_opportunistic" msgid="7608409735589131766">"Opportunistic"</string>
+ <!-- no translation found for private_dns_mode_opportunistic (8314986739896927399) -->
+ <skip />
<string name="private_dns_mode_provider" msgid="8354935160639360804">"Private DNS provider hostname"</string>
<string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"Enter hostname of DNS provider"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Show options for wireless display certification"</string>
@@ -356,22 +357,41 @@
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"This feature is experimental and may affect performance."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"Overridden by <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="power_remaining_duration_only" msgid="845431008899029842">"About <xliff:g id="TIME">%1$s</xliff:g> left"</string>
+ <!-- no translation found for power_discharging_duration (6655472132189365839) -->
+ <skip />
<string name="power_remaining_duration_only_enhanced" msgid="5992456722677973678">"About <xliff:g id="TIME">%1$s</xliff:g> left based on your usage"</string>
- <string name="power_remaining_charging_duration_only" msgid="1421102457410268886">"<xliff:g id="TIME">%1$s</xliff:g> left until fully charged"</string>
+ <!-- no translation found for power_discharging_duration_enhanced (5726302316642148671) -->
+ <skip />
<string name="power_remaining_duration_only_short" msgid="5329694252258605547">"<xliff:g id="TIME">%1$s</xliff:g> left"</string>
+ <!-- no translation found for power_discharge_by_enhanced (8788299408879961465) -->
+ <skip />
+ <!-- no translation found for power_discharge_by_only_enhanced (7692297898877104416) -->
+ <skip />
+ <!-- no translation found for power_discharge_by (6427074755635635749) -->
+ <skip />
+ <!-- no translation found for power_discharge_by_only (5888058889261108064) -->
+ <skip />
<string name="power_remaining_less_than_duration_only" msgid="5996752448813295329">"Less than <xliff:g id="THRESHOLD">%1$s</xliff:g> remaining"</string>
- <string name="power_remaining_less_than_duration" msgid="7967078125657859046">"<xliff:g id="LEVEL">%1$s</xliff:g> - Less than <xliff:g id="THRESHOLD">%2$s</xliff:g> remaining"</string>
- <string name="power_remaining_more_than_subtext" msgid="6846716609975752316">"<xliff:g id="LEVEL">%1$s</xliff:g>more than <xliff:g id="TIME_REMAINING">%2$s</xliff:g> remaining"</string>
- <string name="power_remaining_only_more_than_subtext" msgid="8884488700395194194">"more than <xliff:g id="TIME_REMAINING">%1$s</xliff:g> remaining"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="default" msgid="8168317165722752881">"phone may shutdown soon"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="tablet" msgid="5957064378548718872">"tablet may shutdown soon"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="device" msgid="9055596817716471373">"device may shutdown soon"</string>
- <string name="power_discharging_duration" msgid="2843747179907396142">"<xliff:g id="LEVEL">%1$s</xliff:g> – about <xliff:g id="TIME">%2$s</xliff:g> left"</string>
- <string name="power_discharging_duration_enhanced" msgid="4401782117770255046">"<xliff:g id="LEVEL">%1$s</xliff:g> - about <xliff:g id="TIME">%2$s</xliff:g> left based on your usage"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="default" msgid="7679005631124015335">"<xliff:g id="LEVEL">%1$s</xliff:g> - phone may shutdown soon"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="tablet" msgid="261050880878965621">"<xliff:g id="LEVEL">%1$s</xliff:g> - tablet may shutdown soon"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="device" msgid="2020049829798578618">"<xliff:g id="LEVEL">%1$s</xliff:g> - device may shutdown soon"</string>
+ <!-- no translation found for power_remaining_less_than_duration (5751885147712659423) -->
+ <skip />
+ <!-- no translation found for power_remaining_more_than_subtext (3176771815132876675) -->
+ <skip />
+ <!-- no translation found for power_remaining_only_more_than_subtext (8931654680569617380) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (1181059207608751924) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (2606370266981054691) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (2918084807716859985) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (3090926004324573908) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (7466484148515796216) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (603933521600231649) -->
+ <skip />
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
+ <string name="power_remaining_charging_duration_only" msgid="1421102457410268886">"<xliff:g id="TIME">%1$s</xliff:g> left until fully charged"</string>
<string name="power_charging_duration" msgid="4676999980973411875">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> until fully charged"</string>
<string name="battery_info_status_unknown" msgid="196130600938058547">"Unknown"</string>
<string name="battery_info_status_charging" msgid="1705179948350365604">"Charging"</string>
diff --git a/packages/SettingsLib/res/values-en-rXC/strings.xml b/packages/SettingsLib/res/values-en-rXC/strings.xml
index b7ca84a..56e97e4 100644
--- a/packages/SettingsLib/res/values-en-rXC/strings.xml
+++ b/packages/SettingsLib/res/values-en-rXC/strings.xml
@@ -220,7 +220,8 @@
<string name="select_private_dns_configuration_title" msgid="3700456559305263922">"Private DNS"</string>
<string name="select_private_dns_configuration_dialog_title" msgid="9221994415765826811">"Select Private DNS Mode"</string>
<string name="private_dns_mode_off" msgid="8236575187318721684">"Off"</string>
- <string name="private_dns_mode_opportunistic" msgid="7608409735589131766">"Opportunistic"</string>
+ <!-- no translation found for private_dns_mode_opportunistic (8314986739896927399) -->
+ <skip />
<string name="private_dns_mode_provider" msgid="8354935160639360804">"Private DNS provider hostname"</string>
<string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"Enter hostname of DNS provider"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Show options for wireless display certification"</string>
@@ -356,22 +357,41 @@
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"This feature is experimental and may affect performance."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"Overridden by <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="power_remaining_duration_only" msgid="845431008899029842">"About <xliff:g id="TIME">%1$s</xliff:g> left"</string>
+ <!-- no translation found for power_discharging_duration (6655472132189365839) -->
+ <skip />
<string name="power_remaining_duration_only_enhanced" msgid="5992456722677973678">"About <xliff:g id="TIME">%1$s</xliff:g> left based on your usage"</string>
- <string name="power_remaining_charging_duration_only" msgid="1421102457410268886">"<xliff:g id="TIME">%1$s</xliff:g> left until fully charged"</string>
+ <!-- no translation found for power_discharging_duration_enhanced (5726302316642148671) -->
+ <skip />
<string name="power_remaining_duration_only_short" msgid="5329694252258605547">"<xliff:g id="TIME">%1$s</xliff:g> left"</string>
+ <!-- no translation found for power_discharge_by_enhanced (8788299408879961465) -->
+ <skip />
+ <!-- no translation found for power_discharge_by_only_enhanced (7692297898877104416) -->
+ <skip />
+ <!-- no translation found for power_discharge_by (6427074755635635749) -->
+ <skip />
+ <!-- no translation found for power_discharge_by_only (5888058889261108064) -->
+ <skip />
<string name="power_remaining_less_than_duration_only" msgid="5996752448813295329">"Less than <xliff:g id="THRESHOLD">%1$s</xliff:g> remaining"</string>
- <string name="power_remaining_less_than_duration" msgid="7967078125657859046">"<xliff:g id="LEVEL">%1$s</xliff:g> - Less than <xliff:g id="THRESHOLD">%2$s</xliff:g> remaining"</string>
- <string name="power_remaining_more_than_subtext" msgid="6846716609975752316">"<xliff:g id="LEVEL">%1$s</xliff:g>more than <xliff:g id="TIME_REMAINING">%2$s</xliff:g> remaining"</string>
- <string name="power_remaining_only_more_than_subtext" msgid="8884488700395194194">"more than <xliff:g id="TIME_REMAINING">%1$s</xliff:g> remaining"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="default" msgid="8168317165722752881">"phone may shutdown soon"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="tablet" msgid="5957064378548718872">"tablet may shutdown soon"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="device" msgid="9055596817716471373">"device may shutdown soon"</string>
- <string name="power_discharging_duration" msgid="2843747179907396142">"<xliff:g id="LEVEL">%1$s</xliff:g> - about <xliff:g id="TIME">%2$s</xliff:g> left"</string>
- <string name="power_discharging_duration_enhanced" msgid="4401782117770255046">"<xliff:g id="LEVEL">%1$s</xliff:g> - about <xliff:g id="TIME">%2$s</xliff:g> left based on your usage"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="default" msgid="7679005631124015335">"<xliff:g id="LEVEL">%1$s</xliff:g> - phone may shutdown soon"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="tablet" msgid="261050880878965621">"<xliff:g id="LEVEL">%1$s</xliff:g> - tablet may shutdown soon"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="device" msgid="2020049829798578618">"<xliff:g id="LEVEL">%1$s</xliff:g> - device may shutdown soon"</string>
+ <!-- no translation found for power_remaining_less_than_duration (5751885147712659423) -->
+ <skip />
+ <!-- no translation found for power_remaining_more_than_subtext (3176771815132876675) -->
+ <skip />
+ <!-- no translation found for power_remaining_only_more_than_subtext (8931654680569617380) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (1181059207608751924) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (2606370266981054691) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (2918084807716859985) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (3090926004324573908) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (7466484148515796216) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (603933521600231649) -->
+ <skip />
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
+ <string name="power_remaining_charging_duration_only" msgid="1421102457410268886">"<xliff:g id="TIME">%1$s</xliff:g> left until fully charged"</string>
<string name="power_charging_duration" msgid="4676999980973411875">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> until fully charged"</string>
<string name="battery_info_status_unknown" msgid="196130600938058547">"Unknown"</string>
<string name="battery_info_status_charging" msgid="1705179948350365604">"Charging"</string>
diff --git a/packages/SettingsLib/res/values-es-rUS/strings.xml b/packages/SettingsLib/res/values-es-rUS/strings.xml
index bf62e59..bdff9a0 100644
--- a/packages/SettingsLib/res/values-es-rUS/strings.xml
+++ b/packages/SettingsLib/res/values-es-rUS/strings.xml
@@ -220,7 +220,8 @@
<string name="select_private_dns_configuration_title" msgid="3700456559305263922">"DNS privado"</string>
<string name="select_private_dns_configuration_dialog_title" msgid="9221994415765826811">"Selecciona el modo de DNS privado"</string>
<string name="private_dns_mode_off" msgid="8236575187318721684">"Desactivado"</string>
- <string name="private_dns_mode_opportunistic" msgid="7608409735589131766">"Oportunista"</string>
+ <!-- no translation found for private_dns_mode_opportunistic (8314986739896927399) -->
+ <skip />
<string name="private_dns_mode_provider" msgid="8354935160639360804">"Nombre de host del proveedor de DNS privado"</string>
<string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"Ingresa el nombre de host del proveedor de DNS"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Mostrar opciones de certificación de pantalla inalámbrica"</string>
@@ -356,22 +357,41 @@
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Esta función es experimental y puede afectar el rendimiento."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"Reemplazado por <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="power_remaining_duration_only" msgid="845431008899029842">"Tiempo restante aproximado: <xliff:g id="TIME">%1$s</xliff:g>"</string>
+ <!-- no translation found for power_discharging_duration (6655472132189365839) -->
+ <skip />
<string name="power_remaining_duration_only_enhanced" msgid="5992456722677973678">"Aproximadamente <xliff:g id="TIME">%1$s</xliff:g> restantes en función del uso"</string>
- <string name="power_remaining_charging_duration_only" msgid="1421102457410268886">"<xliff:g id="TIME">%1$s</xliff:g> para completar la carga"</string>
+ <!-- no translation found for power_discharging_duration_enhanced (5726302316642148671) -->
+ <skip />
<string name="power_remaining_duration_only_short" msgid="5329694252258605547">"Tiempo restante: <xliff:g id="TIME">%1$s</xliff:g>"</string>
+ <!-- no translation found for power_discharge_by_enhanced (8788299408879961465) -->
+ <skip />
+ <!-- no translation found for power_discharge_by_only_enhanced (7692297898877104416) -->
+ <skip />
+ <!-- no translation found for power_discharge_by (6427074755635635749) -->
+ <skip />
+ <!-- no translation found for power_discharge_by_only (5888058889261108064) -->
+ <skip />
<string name="power_remaining_less_than_duration_only" msgid="5996752448813295329">"Tiempo restante: menos de <xliff:g id="THRESHOLD">%1$s</xliff:g>"</string>
- <string name="power_remaining_less_than_duration" msgid="7967078125657859046">"<xliff:g id="LEVEL">%1$s</xliff:g> (tiempo restante: menos de <xliff:g id="THRESHOLD">%2$s</xliff:g>)"</string>
- <string name="power_remaining_more_than_subtext" msgid="6846716609975752316">"<xliff:g id="LEVEL">%1$s</xliff:g> (tiempo restante: más de <xliff:g id="TIME_REMAINING">%2$s</xliff:g>)"</string>
- <string name="power_remaining_only_more_than_subtext" msgid="8884488700395194194">"Tiempo restante: más de <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="default" msgid="8168317165722752881">"es posible que pronto se apague el teléfono"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="tablet" msgid="5957064378548718872">"es posible que pronto se apague la tablet"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="device" msgid="9055596817716471373">"es posible que pronto se apague el dispositivo"</string>
- <string name="power_discharging_duration" msgid="2843747179907396142">"<xliff:g id="LEVEL">%1$s</xliff:g> (tiempo restante: <xliff:g id="TIME">%2$s</xliff:g>)"</string>
- <string name="power_discharging_duration_enhanced" msgid="4401782117770255046">"<xliff:g id="LEVEL">%1$s</xliff:g> (aproximadamente <xliff:g id="TIME">%2$s</xliff:g> restantes en función del uso)"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="default" msgid="7679005631124015335">"<xliff:g id="LEVEL">%1$s</xliff:g>: es posible que pronto se apague el teléfono"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="tablet" msgid="261050880878965621">"<xliff:g id="LEVEL">%1$s</xliff:g>: es posible que pronto se apague la tablet"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="device" msgid="2020049829798578618">"<xliff:g id="LEVEL">%1$s</xliff:g>: es posible que pronto se apague el dispositivo"</string>
+ <!-- no translation found for power_remaining_less_than_duration (5751885147712659423) -->
+ <skip />
+ <!-- no translation found for power_remaining_more_than_subtext (3176771815132876675) -->
+ <skip />
+ <!-- no translation found for power_remaining_only_more_than_subtext (8931654680569617380) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (1181059207608751924) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (2606370266981054691) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (2918084807716859985) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (3090926004324573908) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (7466484148515796216) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (603933521600231649) -->
+ <skip />
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g>: <xliff:g id="STATE">%2$s</xliff:g>"</string>
+ <string name="power_remaining_charging_duration_only" msgid="1421102457410268886">"<xliff:g id="TIME">%1$s</xliff:g> para completar la carga"</string>
<string name="power_charging_duration" msgid="4676999980973411875">"<xliff:g id="LEVEL">%1$s</xliff:g> (<xliff:g id="TIME">%2$s</xliff:g> para completar la carga)"</string>
<string name="battery_info_status_unknown" msgid="196130600938058547">"Desconocido"</string>
<string name="battery_info_status_charging" msgid="1705179948350365604">"Cargando"</string>
diff --git a/packages/SettingsLib/res/values-es/strings.xml b/packages/SettingsLib/res/values-es/strings.xml
index 5a9b873..940c84f 100644
--- a/packages/SettingsLib/res/values-es/strings.xml
+++ b/packages/SettingsLib/res/values-es/strings.xml
@@ -220,7 +220,8 @@
<string name="select_private_dns_configuration_title" msgid="3700456559305263922">"DNS privado"</string>
<string name="select_private_dns_configuration_dialog_title" msgid="9221994415765826811">"Selecciona el modo de DNS privado"</string>
<string name="private_dns_mode_off" msgid="8236575187318721684">"No"</string>
- <string name="private_dns_mode_opportunistic" msgid="7608409735589131766">"Oportunista"</string>
+ <!-- no translation found for private_dns_mode_opportunistic (8314986739896927399) -->
+ <skip />
<string name="private_dns_mode_provider" msgid="8354935160639360804">"Nombre de host de proveedor de DNS privado"</string>
<string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"Introduce el nombre de host del proveedor de DNS"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Mostrar opciones para la certificación de la pantalla inalámbrica"</string>
@@ -356,22 +357,41 @@
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Esta función es experimental y puede afectar al rendimiento."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"Anulado por <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="power_remaining_duration_only" msgid="845431008899029842">"Tiempo restante aproximado: <xliff:g id="TIME">%1$s</xliff:g>"</string>
+ <!-- no translation found for power_discharging_duration (6655472132189365839) -->
+ <skip />
<string name="power_remaining_duration_only_enhanced" msgid="5992456722677973678">"Tiempo restante aproximado según tu uso: <xliff:g id="TIME">%1$s</xliff:g>"</string>
- <string name="power_remaining_charging_duration_only" msgid="1421102457410268886">"Tiempo restante hasta carga completa: <xliff:g id="TIME">%1$s</xliff:g>"</string>
+ <!-- no translation found for power_discharging_duration_enhanced (5726302316642148671) -->
+ <skip />
<string name="power_remaining_duration_only_short" msgid="5329694252258605547">"Tiempo restante: <xliff:g id="TIME">%1$s</xliff:g>"</string>
+ <!-- no translation found for power_discharge_by_enhanced (8788299408879961465) -->
+ <skip />
+ <!-- no translation found for power_discharge_by_only_enhanced (7692297898877104416) -->
+ <skip />
+ <!-- no translation found for power_discharge_by (6427074755635635749) -->
+ <skip />
+ <!-- no translation found for power_discharge_by_only (5888058889261108064) -->
+ <skip />
<string name="power_remaining_less_than_duration_only" msgid="5996752448813295329">"Tiempo restante: menos de <xliff:g id="THRESHOLD">%1$s</xliff:g>"</string>
- <string name="power_remaining_less_than_duration" msgid="7967078125657859046">"<xliff:g id="LEVEL">%1$s</xliff:g> (tiempo restante: menos de <xliff:g id="THRESHOLD">%2$s</xliff:g>)"</string>
- <string name="power_remaining_more_than_subtext" msgid="6846716609975752316">"<xliff:g id="LEVEL">%1$s</xliff:g> (tiempo restante: más de <xliff:g id="TIME_REMAINING">%2$s</xliff:g>)"</string>
- <string name="power_remaining_only_more_than_subtext" msgid="8884488700395194194">"Tiempo restante: más de <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="default" msgid="8168317165722752881">"es posible que el teléfono se apague pronto"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="tablet" msgid="5957064378548718872">"es posible que el tablet se apague pronto"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="device" msgid="9055596817716471373">"es posible que el dispositivo se apague pronto"</string>
- <string name="power_discharging_duration" msgid="2843747179907396142">"<xliff:g id="LEVEL">%1$s</xliff:g> - tiempo aproximado restante: <xliff:g id="TIME">%2$s</xliff:g>"</string>
- <string name="power_discharging_duration_enhanced" msgid="4401782117770255046">"<xliff:g id="LEVEL">%1$s</xliff:g> (tiempo restante aproximado según tu uso: <xliff:g id="TIME">%2$s</xliff:g>)"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="default" msgid="7679005631124015335">"<xliff:g id="LEVEL">%1$s</xliff:g>: es posible que el teléfono se apague pronto"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="tablet" msgid="261050880878965621">"<xliff:g id="LEVEL">%1$s</xliff:g>: es posible que el tablet se apague pronto"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="device" msgid="2020049829798578618">"<xliff:g id="LEVEL">%1$s</xliff:g>: es posible que el dispositivo se apague pronto"</string>
+ <!-- no translation found for power_remaining_less_than_duration (5751885147712659423) -->
+ <skip />
+ <!-- no translation found for power_remaining_more_than_subtext (3176771815132876675) -->
+ <skip />
+ <!-- no translation found for power_remaining_only_more_than_subtext (8931654680569617380) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (1181059207608751924) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (2606370266981054691) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (2918084807716859985) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (3090926004324573908) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (7466484148515796216) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (603933521600231649) -->
+ <skip />
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
+ <string name="power_remaining_charging_duration_only" msgid="1421102457410268886">"Tiempo restante hasta carga completa: <xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="4676999980973411875">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> para completar la carga"</string>
<string name="battery_info_status_unknown" msgid="196130600938058547">"Desconocido"</string>
<string name="battery_info_status_charging" msgid="1705179948350365604">"Cargando"</string>
diff --git a/packages/SettingsLib/res/values-et/strings.xml b/packages/SettingsLib/res/values-et/strings.xml
index 77d55ff..a53b894 100644
--- a/packages/SettingsLib/res/values-et/strings.xml
+++ b/packages/SettingsLib/res/values-et/strings.xml
@@ -220,7 +220,8 @@
<string name="select_private_dns_configuration_title" msgid="3700456559305263922">"Privaatne DNS"</string>
<string name="select_private_dns_configuration_dialog_title" msgid="9221994415765826811">"Valige privaatse DNS-i režiim"</string>
<string name="private_dns_mode_off" msgid="8236575187318721684">"Väljas"</string>
- <string name="private_dns_mode_opportunistic" msgid="7608409735589131766">"Oportunistlik"</string>
+ <!-- no translation found for private_dns_mode_opportunistic (8314986739896927399) -->
+ <skip />
<string name="private_dns_mode_provider" msgid="8354935160639360804">"Privaatse DNS-i teenusepakkuja hostinimi"</string>
<string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"Sisestage DNS-i teenusepakkuja hostinimi"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Juhtmeta ekraaniühenduse sertifitseerimisvalikute kuvamine"</string>
@@ -356,22 +357,41 @@
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"See funktsioon on katseline ja võib mõjutada toimivust."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"Alistas <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="power_remaining_duration_only" msgid="845431008899029842">"Umbes <xliff:g id="TIME">%1$s</xliff:g> on jäänud"</string>
+ <!-- no translation found for power_discharging_duration (6655472132189365839) -->
+ <skip />
<string name="power_remaining_duration_only_enhanced" msgid="5992456722677973678">"Teie kasutuse alusel on jäänud ligikaudu <xliff:g id="TIME">%1$s</xliff:g>"</string>
- <string name="power_remaining_charging_duration_only" msgid="1421102457410268886">"<xliff:g id="TIME">%1$s</xliff:g> täislaadimiseni"</string>
+ <!-- no translation found for power_discharging_duration_enhanced (5726302316642148671) -->
+ <skip />
<string name="power_remaining_duration_only_short" msgid="5329694252258605547">"<xliff:g id="TIME">%1$s</xliff:g> on jäänud"</string>
+ <!-- no translation found for power_discharge_by_enhanced (8788299408879961465) -->
+ <skip />
+ <!-- no translation found for power_discharge_by_only_enhanced (7692297898877104416) -->
+ <skip />
+ <!-- no translation found for power_discharge_by (6427074755635635749) -->
+ <skip />
+ <!-- no translation found for power_discharge_by_only (5888058889261108064) -->
+ <skip />
<string name="power_remaining_less_than_duration_only" msgid="5996752448813295329">"Jäänud on alla <xliff:g id="THRESHOLD">%1$s</xliff:g>"</string>
- <string name="power_remaining_less_than_duration" msgid="7967078125657859046">"<xliff:g id="LEVEL">%1$s</xliff:g> – jäänud on alla <xliff:g id="THRESHOLD">%2$s</xliff:g>"</string>
- <string name="power_remaining_more_than_subtext" msgid="6846716609975752316">"<xliff:g id="LEVEL">%1$s</xliff:g>jäänud on üle <xliff:g id="TIME_REMAINING">%2$s</xliff:g>"</string>
- <string name="power_remaining_only_more_than_subtext" msgid="8884488700395194194">"jäänud on üle <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="default" msgid="8168317165722752881">"telefon võib peagi välja lülituda"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="tablet" msgid="5957064378548718872">"tahvelarvuti võib peagi välja lülituda"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="device" msgid="9055596817716471373">"seade võib peagi välja lülituda"</string>
- <string name="power_discharging_duration" msgid="2843747179907396142">"<xliff:g id="LEVEL">%1$s</xliff:g> – umbes <xliff:g id="TIME">%2$s</xliff:g> on jäänud"</string>
- <string name="power_discharging_duration_enhanced" msgid="4401782117770255046">"<xliff:g id="LEVEL">%1$s</xliff:g> – teie kasutuse alusel on jäänud ligikaudu <xliff:g id="TIME">%2$s</xliff:g>"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="default" msgid="7679005631124015335">"<xliff:g id="LEVEL">%1$s</xliff:g> – telefon võib peagi välja lülituda"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="tablet" msgid="261050880878965621">"<xliff:g id="LEVEL">%1$s</xliff:g> – tahvelarvuti võib peagi välja lülituda"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="device" msgid="2020049829798578618">"<xliff:g id="LEVEL">%1$s</xliff:g> – seade võib peagi välja lülituda"</string>
+ <!-- no translation found for power_remaining_less_than_duration (5751885147712659423) -->
+ <skip />
+ <!-- no translation found for power_remaining_more_than_subtext (3176771815132876675) -->
+ <skip />
+ <!-- no translation found for power_remaining_only_more_than_subtext (8931654680569617380) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (1181059207608751924) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (2606370266981054691) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (2918084807716859985) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (3090926004324573908) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (7466484148515796216) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (603933521600231649) -->
+ <skip />
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string>
+ <string name="power_remaining_charging_duration_only" msgid="1421102457410268886">"<xliff:g id="TIME">%1$s</xliff:g> täislaadimiseni"</string>
<string name="power_charging_duration" msgid="4676999980973411875">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> täislaadimiseni"</string>
<string name="battery_info_status_unknown" msgid="196130600938058547">"Tundmatu"</string>
<string name="battery_info_status_charging" msgid="1705179948350365604">"Laadimine"</string>
diff --git a/packages/SettingsLib/res/values-eu/strings.xml b/packages/SettingsLib/res/values-eu/strings.xml
index 7da1e76..bcaf79c 100644
--- a/packages/SettingsLib/res/values-eu/strings.xml
+++ b/packages/SettingsLib/res/values-eu/strings.xml
@@ -200,7 +200,7 @@
<string name="wifi_display_certification" msgid="8611569543791307533">"Hari gabeko bistaratze-egiaztatzea"</string>
<string name="wifi_verbose_logging" msgid="4203729756047242344">"Gaitu Wi-Fi sareetan saioa hasteko modu xehatua"</string>
<string name="wifi_connected_mac_randomization" msgid="3168165236877957767">"Konektatutako MAC helbideak ausaz aukeratzea"</string>
- <string name="mobile_data_always_on" msgid="8774857027458200434">"Datu mugikorrak beti aktibo"</string>
+ <string name="mobile_data_always_on" msgid="8774857027458200434">"Datu-konexioa beti aktibo"</string>
<string name="tethering_hardware_offload" msgid="7470077827090325814">"Konexioa partekatzeko hardwarearen azelerazioa"</string>
<string name="bluetooth_show_devices_without_names" msgid="4708446092962060176">"Erakutsi Bluetooth gailuak izenik gabe"</string>
<string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Desgaitu bolumen absolutua"</string>
@@ -220,7 +220,8 @@
<string name="select_private_dns_configuration_title" msgid="3700456559305263922">"DNS pribatua"</string>
<string name="select_private_dns_configuration_dialog_title" msgid="9221994415765826811">"Hautatu DNS pribatuaren modua"</string>
<string name="private_dns_mode_off" msgid="8236575187318721684">"Desaktibatuta"</string>
- <string name="private_dns_mode_opportunistic" msgid="7608409735589131766">"Ahal bada"</string>
+ <!-- no translation found for private_dns_mode_opportunistic (8314986739896927399) -->
+ <skip />
<string name="private_dns_mode_provider" msgid="8354935160639360804">"DNS hornitzaile pribatuaren ostalari-izena"</string>
<string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"Idatzi DNS hornitzailearen ostalari-izena"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Erakutsi hari gabeko bistaratze-egiaztapenaren aukerak"</string>
@@ -356,22 +357,41 @@
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Eginbidea esperimentala da eta eragina izan dezake funtzionamenduan."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"<xliff:g id="TITLE">%1$s</xliff:g> hobespena gainjarri zaio"</string>
<string name="power_remaining_duration_only" msgid="845431008899029842">"<xliff:g id="TIME">%1$s</xliff:g> inguru gelditzen dira"</string>
+ <!-- no translation found for power_discharging_duration (6655472132189365839) -->
+ <skip />
<string name="power_remaining_duration_only_enhanced" msgid="5992456722677973678">"<xliff:g id="TIME">%1$s</xliff:g> inguru gelditzen dira, erabileraren arabera"</string>
- <string name="power_remaining_charging_duration_only" msgid="1421102457410268886">"<xliff:g id="TIME">%1$s</xliff:g> falta dira guztiz kargatu arte"</string>
+ <!-- no translation found for power_discharging_duration_enhanced (5726302316642148671) -->
+ <skip />
<string name="power_remaining_duration_only_short" msgid="5329694252258605547">"<xliff:g id="TIME">%1$s</xliff:g> guztiz kargatu arte"</string>
+ <!-- no translation found for power_discharge_by_enhanced (8788299408879961465) -->
+ <skip />
+ <!-- no translation found for power_discharge_by_only_enhanced (7692297898877104416) -->
+ <skip />
+ <!-- no translation found for power_discharge_by (6427074755635635749) -->
+ <skip />
+ <!-- no translation found for power_discharge_by_only (5888058889261108064) -->
+ <skip />
<string name="power_remaining_less_than_duration_only" msgid="5996752448813295329">"<xliff:g id="THRESHOLD">%1$s</xliff:g> baino gutxiago gelditzen dira"</string>
- <string name="power_remaining_less_than_duration" msgid="7967078125657859046">"<xliff:g id="LEVEL">%1$s</xliff:g>: <xliff:g id="THRESHOLD">%2$s</xliff:g> baino gutxiago gelditzen dira"</string>
- <string name="power_remaining_more_than_subtext" msgid="6846716609975752316">"<xliff:g id="LEVEL">%1$s</xliff:g>: <xliff:g id="TIME_REMAINING">%2$s</xliff:g> baino gehiago gelditzen dira"</string>
- <string name="power_remaining_only_more_than_subtext" msgid="8884488700395194194">"<xliff:g id="TIME_REMAINING">%1$s</xliff:g> baino gehiago gelditzen dira"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="default" msgid="8168317165722752881">"baliteke telefonoa laster itzaltzea"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="tablet" msgid="5957064378548718872">"baliteke tableta laster itzaltzea"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="device" msgid="9055596817716471373">"baliteke gailua laster itzaltzea"</string>
- <string name="power_discharging_duration" msgid="2843747179907396142">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> inguru gelditzen dira"</string>
- <string name="power_discharging_duration_enhanced" msgid="4401782117770255046">"<xliff:g id="LEVEL">%1$s</xliff:g>: <xliff:g id="TIME">%2$s</xliff:g> inguru gelditzen dira, erabileraren arabera"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="default" msgid="7679005631124015335">"<xliff:g id="LEVEL">%1$s</xliff:g>: baliteke telefonoa laster itzaltzea"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="tablet" msgid="261050880878965621">"<xliff:g id="LEVEL">%1$s</xliff:g>: baliteke tableta laster itzaltzea"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="device" msgid="2020049829798578618">"<xliff:g id="LEVEL">%1$s</xliff:g>: baliteke gailua laster itzaltzea"</string>
+ <!-- no translation found for power_remaining_less_than_duration (5751885147712659423) -->
+ <skip />
+ <!-- no translation found for power_remaining_more_than_subtext (3176771815132876675) -->
+ <skip />
+ <!-- no translation found for power_remaining_only_more_than_subtext (8931654680569617380) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (1181059207608751924) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (2606370266981054691) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (2918084807716859985) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (3090926004324573908) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (7466484148515796216) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (603933521600231649) -->
+ <skip />
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
+ <string name="power_remaining_charging_duration_only" msgid="1421102457410268886">"<xliff:g id="TIME">%1$s</xliff:g> falta dira guztiz kargatu arte"</string>
<string name="power_charging_duration" msgid="4676999980973411875">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> guztiz kargatu arte"</string>
<string name="battery_info_status_unknown" msgid="196130600938058547">"Ezezaguna"</string>
<string name="battery_info_status_charging" msgid="1705179948350365604">"Kargatzen"</string>
diff --git a/packages/SettingsLib/res/values-fa/strings.xml b/packages/SettingsLib/res/values-fa/strings.xml
index 2e5d699..14e942d 100644
--- a/packages/SettingsLib/res/values-fa/strings.xml
+++ b/packages/SettingsLib/res/values-fa/strings.xml
@@ -220,7 +220,8 @@
<string name="select_private_dns_configuration_title" msgid="3700456559305263922">"DNS خصوصی"</string>
<string name="select_private_dns_configuration_dialog_title" msgid="9221994415765826811">"حالت DNS خصوصی را انتخاب کنید"</string>
<string name="private_dns_mode_off" msgid="8236575187318721684">"خاموش"</string>
- <string name="private_dns_mode_opportunistic" msgid="7608409735589131766">"فرصتطلب"</string>
+ <!-- no translation found for private_dns_mode_opportunistic (8314986739896927399) -->
+ <skip />
<string name="private_dns_mode_provider" msgid="8354935160639360804">"نام میزبان ارائهدهنده DNS خصوصی"</string>
<string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"نام میزبان ارائهدهنده DNS خصوصی را وارد کنید"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"نمایش گزینهها برای گواهینامه نمایش بیسیم"</string>
@@ -356,22 +357,41 @@
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"این قابلیت آزمایشی است و ممکن است عملکرد را تحت تأثیر قرار دهد."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"توسط <xliff:g id="TITLE">%1$s</xliff:g> لغو شد"</string>
<string name="power_remaining_duration_only" msgid="845431008899029842">"حدود <xliff:g id="TIME">%1$s</xliff:g> باقی مانده است"</string>
+ <!-- no translation found for power_discharging_duration (6655472132189365839) -->
+ <skip />
<string name="power_remaining_duration_only_enhanced" msgid="5992456722677973678">"براساس میزان مصرف شما، <xliff:g id="TIME">%1$s</xliff:g> باقیمانده است"</string>
- <string name="power_remaining_charging_duration_only" msgid="1421102457410268886">"<xliff:g id="TIME">%1$s</xliff:g> تا شارژ شدن کامل باقی مانده است"</string>
+ <!-- no translation found for power_discharging_duration_enhanced (5726302316642148671) -->
+ <skip />
<string name="power_remaining_duration_only_short" msgid="5329694252258605547">"<xliff:g id="TIME">%1$s</xliff:g> باقی مانده"</string>
+ <!-- no translation found for power_discharge_by_enhanced (8788299408879961465) -->
+ <skip />
+ <!-- no translation found for power_discharge_by_only_enhanced (7692297898877104416) -->
+ <skip />
+ <!-- no translation found for power_discharge_by (6427074755635635749) -->
+ <skip />
+ <!-- no translation found for power_discharge_by_only (5888058889261108064) -->
+ <skip />
<string name="power_remaining_less_than_duration_only" msgid="5996752448813295329">"کمتر از <xliff:g id="THRESHOLD">%1$s</xliff:g> باقی مانده"</string>
- <string name="power_remaining_less_than_duration" msgid="7967078125657859046">"<xliff:g id="LEVEL">%1$s</xliff:g> - کمتر از <xliff:g id="THRESHOLD">%2$s</xliff:g> باقی مانده"</string>
- <string name="power_remaining_more_than_subtext" msgid="6846716609975752316">"<xliff:g id="LEVEL">%1$s</xliff:g>بیشتر از <xliff:g id="TIME_REMAINING">%2$s</xliff:g> باقی مانده"</string>
- <string name="power_remaining_only_more_than_subtext" msgid="8884488700395194194">"بیشتر از <xliff:g id="TIME_REMAINING">%1$s</xliff:g> باقی مانده"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="default" msgid="8168317165722752881">"ممکن است تلفن بهزودی خاموش شود"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="tablet" msgid="5957064378548718872">"ممکن است رایانه لوحی بهزودی خاموش شود"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="device" msgid="9055596817716471373">"ممکن است دستگاه بهزودی خاموش شود"</string>
- <string name="power_discharging_duration" msgid="2843747179907396142">"<xliff:g id="LEVEL">%1$s</xliff:g> - تقریباً <xliff:g id="TIME">%2$s</xliff:g> باقی مانده است"</string>
- <string name="power_discharging_duration_enhanced" msgid="4401782117770255046">"<xliff:g id="LEVEL">%1$s</xliff:g> - براساس میزان مصرف شما، <xliff:g id="TIME">%2$s</xliff:g> باقیمانده است"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="default" msgid="7679005631124015335">"<xliff:g id="LEVEL">%1$s</xliff:g> - ممکن است تلفن بهزودی خاموش شود"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="tablet" msgid="261050880878965621">"<xliff:g id="LEVEL">%1$s</xliff:g> - ممکن است رایانه لوحی بهزودی خاموش شود"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="device" msgid="2020049829798578618">"<xliff:g id="LEVEL">%1$s</xliff:g> - ممکن است دستگاه بهزودی خاموش شود"</string>
+ <!-- no translation found for power_remaining_less_than_duration (5751885147712659423) -->
+ <skip />
+ <!-- no translation found for power_remaining_more_than_subtext (3176771815132876675) -->
+ <skip />
+ <!-- no translation found for power_remaining_only_more_than_subtext (8931654680569617380) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (1181059207608751924) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (2606370266981054691) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (2918084807716859985) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (3090926004324573908) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (7466484148515796216) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (603933521600231649) -->
+ <skip />
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
+ <string name="power_remaining_charging_duration_only" msgid="1421102457410268886">"<xliff:g id="TIME">%1$s</xliff:g> تا شارژ شدن کامل باقی مانده است"</string>
<string name="power_charging_duration" msgid="4676999980973411875">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> مانده تا شارژ کامل"</string>
<string name="battery_info_status_unknown" msgid="196130600938058547">"ناشناس"</string>
<string name="battery_info_status_charging" msgid="1705179948350365604">"در حال شارژ شدن"</string>
diff --git a/packages/SettingsLib/res/values-fi/strings.xml b/packages/SettingsLib/res/values-fi/strings.xml
index 28d14a5..040a475 100644
--- a/packages/SettingsLib/res/values-fi/strings.xml
+++ b/packages/SettingsLib/res/values-fi/strings.xml
@@ -220,7 +220,8 @@
<string name="select_private_dns_configuration_title" msgid="3700456559305263922">"Yksityinen DNS"</string>
<string name="select_private_dns_configuration_dialog_title" msgid="9221994415765826811">"Valitse yksityinen DNS-tila"</string>
<string name="private_dns_mode_off" msgid="8236575187318721684">"Pois käytöstä"</string>
- <string name="private_dns_mode_opportunistic" msgid="7608409735589131766">"Opportunistinen"</string>
+ <!-- no translation found for private_dns_mode_opportunistic (8314986739896927399) -->
+ <skip />
<string name="private_dns_mode_provider" msgid="8354935160639360804">"Yksityisen DNS-tarjoajan isäntänimi"</string>
<string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"Anna isäntänimi tai DNS-tarjoaja."</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Näytä langattoman näytön sertifiointiin liittyvät asetukset"</string>
@@ -356,22 +357,41 @@
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Tämä ominaisuus on kokeellinen ja voi vaikuttaa suorituskykyyn."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"Tämän ohittaa <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="power_remaining_duration_only" msgid="845431008899029842">"Noin <xliff:g id="TIME">%1$s</xliff:g> jäljellä"</string>
+ <!-- no translation found for power_discharging_duration (6655472132189365839) -->
+ <skip />
<string name="power_remaining_duration_only_enhanced" msgid="5992456722677973678">"Noin <xliff:g id="TIME">%1$s</xliff:g> jäljellä käytön perusteella"</string>
- <string name="power_remaining_charging_duration_only" msgid="1421102457410268886">"<xliff:g id="TIME">%1$s</xliff:g> kunnes täynnä"</string>
+ <!-- no translation found for power_discharging_duration_enhanced (5726302316642148671) -->
+ <skip />
<string name="power_remaining_duration_only_short" msgid="5329694252258605547">"<xliff:g id="TIME">%1$s</xliff:g> jäljellä"</string>
+ <!-- no translation found for power_discharge_by_enhanced (8788299408879961465) -->
+ <skip />
+ <!-- no translation found for power_discharge_by_only_enhanced (7692297898877104416) -->
+ <skip />
+ <!-- no translation found for power_discharge_by (6427074755635635749) -->
+ <skip />
+ <!-- no translation found for power_discharge_by_only (5888058889261108064) -->
+ <skip />
<string name="power_remaining_less_than_duration_only" msgid="5996752448813295329">"Alle <xliff:g id="THRESHOLD">%1$s</xliff:g> jäljellä"</string>
- <string name="power_remaining_less_than_duration" msgid="7967078125657859046">"<xliff:g id="LEVEL">%1$s</xliff:g> – Alle <xliff:g id="THRESHOLD">%2$s</xliff:g> jäljellä"</string>
- <string name="power_remaining_more_than_subtext" msgid="6846716609975752316">"<xliff:g id="LEVEL">%1$s</xliff:g> yli <xliff:g id="TIME_REMAINING">%2$s</xliff:g> jäljellä"</string>
- <string name="power_remaining_only_more_than_subtext" msgid="8884488700395194194">"yli <xliff:g id="TIME_REMAINING">%1$s</xliff:g> jäljellä"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="default" msgid="8168317165722752881">"puhelin voi pian sammua"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="tablet" msgid="5957064378548718872">"tabletti voi pian sammua"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="device" msgid="9055596817716471373">"laite voi pian sammua"</string>
- <string name="power_discharging_duration" msgid="2843747179907396142">"<xliff:g id="LEVEL">%1$s</xliff:g> – noin <xliff:g id="TIME">%2$s</xliff:g> jäljellä"</string>
- <string name="power_discharging_duration_enhanced" msgid="4401782117770255046">"<xliff:g id="LEVEL">%1$s</xliff:g> – noin <xliff:g id="TIME">%2$s</xliff:g> jäljellä käytön perusteella"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="default" msgid="7679005631124015335">"<xliff:g id="LEVEL">%1$s</xliff:g> – puhelin voi pian sammua"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="tablet" msgid="261050880878965621">"<xliff:g id="LEVEL">%1$s</xliff:g> – tabletti voi pian sammua"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="device" msgid="2020049829798578618">"<xliff:g id="LEVEL">%1$s</xliff:g> – laite voi pian sammua"</string>
+ <!-- no translation found for power_remaining_less_than_duration (5751885147712659423) -->
+ <skip />
+ <!-- no translation found for power_remaining_more_than_subtext (3176771815132876675) -->
+ <skip />
+ <!-- no translation found for power_remaining_only_more_than_subtext (8931654680569617380) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (1181059207608751924) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (2606370266981054691) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (2918084807716859985) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (3090926004324573908) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (7466484148515796216) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (603933521600231649) -->
+ <skip />
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string>
+ <string name="power_remaining_charging_duration_only" msgid="1421102457410268886">"<xliff:g id="TIME">%1$s</xliff:g> kunnes täynnä"</string>
<string name="power_charging_duration" msgid="4676999980973411875">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> täyteen lataukseen"</string>
<string name="battery_info_status_unknown" msgid="196130600938058547">"Tuntematon"</string>
<string name="battery_info_status_charging" msgid="1705179948350365604">"Ladataan"</string>
diff --git a/packages/SettingsLib/res/values-fr-rCA/strings.xml b/packages/SettingsLib/res/values-fr-rCA/strings.xml
index ed6581d..2e9caa6 100644
--- a/packages/SettingsLib/res/values-fr-rCA/strings.xml
+++ b/packages/SettingsLib/res/values-fr-rCA/strings.xml
@@ -220,7 +220,8 @@
<string name="select_private_dns_configuration_title" msgid="3700456559305263922">"DNS privé"</string>
<string name="select_private_dns_configuration_dialog_title" msgid="9221994415765826811">"Sélectionnez le mode DNS privé"</string>
<string name="private_dns_mode_off" msgid="8236575187318721684">"Désactivé"</string>
- <string name="private_dns_mode_opportunistic" msgid="7608409735589131766">"Opportuniste"</string>
+ <!-- no translation found for private_dns_mode_opportunistic (8314986739896927399) -->
+ <skip />
<string name="private_dns_mode_provider" msgid="8354935160639360804">"Nom d\'hôte du fournisseur DNS privé"</string>
<string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"Entrez le nom d\'hôte du fournisseur DNS"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Afficher les options pour la certification d\'affichage sans fil"</string>
@@ -356,22 +357,41 @@
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Cette fonctionnalité est expérimentale et peut affecter les performances."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"Remplacé par <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="power_remaining_duration_only" msgid="845431008899029842">"Il reste environ <xliff:g id="TIME">%1$s</xliff:g>"</string>
+ <!-- no translation found for power_discharging_duration (6655472132189365839) -->
+ <skip />
<string name="power_remaining_duration_only_enhanced" msgid="5992456722677973678">"Il reste environ <xliff:g id="TIME">%1$s</xliff:g> en fonction de votre usage"</string>
- <string name="power_remaining_charging_duration_only" msgid="1421102457410268886">"<xliff:g id="TIME">%1$s</xliff:g> jusqu\'à la charge complète"</string>
+ <!-- no translation found for power_discharging_duration_enhanced (5726302316642148671) -->
+ <skip />
<string name="power_remaining_duration_only_short" msgid="5329694252258605547">"Temps restant : <xliff:g id="TIME">%1$s</xliff:g>"</string>
+ <!-- no translation found for power_discharge_by_enhanced (8788299408879961465) -->
+ <skip />
+ <!-- no translation found for power_discharge_by_only_enhanced (7692297898877104416) -->
+ <skip />
+ <!-- no translation found for power_discharge_by (6427074755635635749) -->
+ <skip />
+ <!-- no translation found for power_discharge_by_only (5888058889261108064) -->
+ <skip />
<string name="power_remaining_less_than_duration_only" msgid="5996752448813295329">"Il reste moins de <xliff:g id="THRESHOLD">%1$s</xliff:g>"</string>
- <string name="power_remaining_less_than_duration" msgid="7967078125657859046">"<xliff:g id="LEVEL">%1$s</xliff:g> : il reste moins de <xliff:g id="THRESHOLD">%2$s</xliff:g>"</string>
- <string name="power_remaining_more_than_subtext" msgid="6846716609975752316">"<xliff:g id="LEVEL">%1$s</xliff:g> : il reste plus de <xliff:g id="TIME_REMAINING">%2$s</xliff:g>"</string>
- <string name="power_remaining_only_more_than_subtext" msgid="8884488700395194194">"il reste plus de <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="default" msgid="8168317165722752881">"il se peut que le téléphone s\'éteigne bientôt"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="tablet" msgid="5957064378548718872">"il se peut que la tablette s\'éteigne bientôt"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="device" msgid="9055596817716471373">"il se peut que l\'appareil s\'éteigne bientôt"</string>
- <string name="power_discharging_duration" msgid="2843747179907396142">"<xliff:g id="LEVEL">%1$s</xliff:g> : il reste environ <xliff:g id="TIME">%2$s</xliff:g>"</string>
- <string name="power_discharging_duration_enhanced" msgid="4401782117770255046">"<xliff:g id="LEVEL">%1$s</xliff:g> : il reste environ <xliff:g id="TIME">%2$s</xliff:g> en fonction de votre usage"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="default" msgid="7679005631124015335">"<xliff:g id="LEVEL">%1$s</xliff:g> : il se peut que le téléphone s\'éteigne bientôt"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="tablet" msgid="261050880878965621">"<xliff:g id="LEVEL">%1$s</xliff:g>: il se peut que la tablette s\'éteigne bientôt"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="device" msgid="2020049829798578618">"<xliff:g id="LEVEL">%1$s</xliff:g> : il se peut que l\'appareil s\'éteigne bientôt"</string>
+ <!-- no translation found for power_remaining_less_than_duration (5751885147712659423) -->
+ <skip />
+ <!-- no translation found for power_remaining_more_than_subtext (3176771815132876675) -->
+ <skip />
+ <!-- no translation found for power_remaining_only_more_than_subtext (8931654680569617380) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (1181059207608751924) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (2606370266981054691) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (2918084807716859985) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (3090926004324573908) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (7466484148515796216) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (603933521600231649) -->
+ <skip />
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
+ <string name="power_remaining_charging_duration_only" msgid="1421102457410268886">"<xliff:g id="TIME">%1$s</xliff:g> jusqu\'à la charge complète"</string>
<string name="power_charging_duration" msgid="4676999980973411875">"<xliff:g id="LEVEL">%1$s</xliff:g> : <xliff:g id="TIME">%2$s</xliff:g> jusqu\'à la charge complète"</string>
<string name="battery_info_status_unknown" msgid="196130600938058547">"Inconnu"</string>
<string name="battery_info_status_charging" msgid="1705179948350365604">"Charge en cours…"</string>
diff --git a/packages/SettingsLib/res/values-fr/strings.xml b/packages/SettingsLib/res/values-fr/strings.xml
index 39d7aec..8225c4d 100644
--- a/packages/SettingsLib/res/values-fr/strings.xml
+++ b/packages/SettingsLib/res/values-fr/strings.xml
@@ -220,7 +220,8 @@
<string name="select_private_dns_configuration_title" msgid="3700456559305263922">"DNS privé"</string>
<string name="select_private_dns_configuration_dialog_title" msgid="9221994415765826811">"Sélectionner le mode DNS privé"</string>
<string name="private_dns_mode_off" msgid="8236575187318721684">"Désactivé"</string>
- <string name="private_dns_mode_opportunistic" msgid="7608409735589131766">"Opportuniste"</string>
+ <!-- no translation found for private_dns_mode_opportunistic (8314986739896927399) -->
+ <skip />
<string name="private_dns_mode_provider" msgid="8354935160639360804">"Nom d\'hôte du fournisseur DNS privé"</string>
<string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"Saisissez le nom d\'hôte du fournisseur DNS"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Afficher les options de la certification de l\'affichage sans fil"</string>
@@ -356,22 +357,41 @@
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Cette fonctionnalité est expérimentale et peut affecter les performances."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"Remplacé par <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="power_remaining_duration_only" msgid="845431008899029842">"Il reste environ <xliff:g id="TIME">%1$s</xliff:g>"</string>
+ <!-- no translation found for power_discharging_duration (6655472132189365839) -->
+ <skip />
<string name="power_remaining_duration_only_enhanced" msgid="5992456722677973678">"Temps restant en fonction de votre utilisation : environ <xliff:g id="TIME">%1$s</xliff:g>"</string>
- <string name="power_remaining_charging_duration_only" msgid="1421102457410268886">"<xliff:g id="TIME">%1$s</xliff:g> avant charge complète"</string>
+ <!-- no translation found for power_discharging_duration_enhanced (5726302316642148671) -->
+ <skip />
<string name="power_remaining_duration_only_short" msgid="5329694252258605547">"Temps restant : <xliff:g id="TIME">%1$s</xliff:g>"</string>
+ <!-- no translation found for power_discharge_by_enhanced (8788299408879961465) -->
+ <skip />
+ <!-- no translation found for power_discharge_by_only_enhanced (7692297898877104416) -->
+ <skip />
+ <!-- no translation found for power_discharge_by (6427074755635635749) -->
+ <skip />
+ <!-- no translation found for power_discharge_by_only (5888058889261108064) -->
+ <skip />
<string name="power_remaining_less_than_duration_only" msgid="5996752448813295329">"Il reste moins de <xliff:g id="THRESHOLD">%1$s</xliff:g>"</string>
- <string name="power_remaining_less_than_duration" msgid="7967078125657859046">"<xliff:g id="LEVEL">%1$s</xliff:g> – Il reste moins de <xliff:g id="THRESHOLD">%2$s</xliff:g>"</string>
- <string name="power_remaining_more_than_subtext" msgid="6846716609975752316">"<xliff:g id="LEVEL">%1$s</xliff:g> – Il reste plus de <xliff:g id="TIME_REMAINING">%2$s</xliff:g>"</string>
- <string name="power_remaining_only_more_than_subtext" msgid="8884488700395194194">"Il reste plus de <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="default" msgid="8168317165722752881">"Il est possible que le téléphone s\'éteigne bientôt"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="tablet" msgid="5957064378548718872">"Il est possible que la tablette s\'éteigne bientôt"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="device" msgid="9055596817716471373">"Il est possible que l\'appareil s\'éteigne bientôt"</string>
- <string name="power_discharging_duration" msgid="2843747179907396142">"<xliff:g id="LEVEL">%1$s</xliff:g> - encore environ <xliff:g id="TIME">%2$s</xliff:g>"</string>
- <string name="power_discharging_duration_enhanced" msgid="4401782117770255046">"<xliff:g id="LEVEL">%1$s</xliff:g> – Temps restant en fonction de votre utilisation : environ <xliff:g id="TIME">%2$s</xliff:g>"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="default" msgid="7679005631124015335">"<xliff:g id="LEVEL">%1$s</xliff:g> – Il est possible que le téléphone s\'éteigne bientôt"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="tablet" msgid="261050880878965621">"<xliff:g id="LEVEL">%1$s</xliff:g> – Il est possible que la tablette s\'éteigne bientôt"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="device" msgid="2020049829798578618">"<xliff:g id="LEVEL">%1$s</xliff:g> – Il est possible que l\'appareil s\'éteigne bientôt"</string>
+ <!-- no translation found for power_remaining_less_than_duration (5751885147712659423) -->
+ <skip />
+ <!-- no translation found for power_remaining_more_than_subtext (3176771815132876675) -->
+ <skip />
+ <!-- no translation found for power_remaining_only_more_than_subtext (8931654680569617380) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (1181059207608751924) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (2606370266981054691) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (2918084807716859985) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (3090926004324573908) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (7466484148515796216) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (603933521600231649) -->
+ <skip />
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string>
+ <string name="power_remaining_charging_duration_only" msgid="1421102457410268886">"<xliff:g id="TIME">%1$s</xliff:g> avant charge complète"</string>
<string name="power_charging_duration" msgid="4676999980973411875">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> jusqu\'à la charge complète"</string>
<string name="battery_info_status_unknown" msgid="196130600938058547">"Inconnu"</string>
<string name="battery_info_status_charging" msgid="1705179948350365604">"Batterie en charge"</string>
diff --git a/packages/SettingsLib/res/values-gl/strings.xml b/packages/SettingsLib/res/values-gl/strings.xml
index effcd47..839a25e 100644
--- a/packages/SettingsLib/res/values-gl/strings.xml
+++ b/packages/SettingsLib/res/values-gl/strings.xml
@@ -93,7 +93,7 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"Utilízase para o audio do teléfono"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"Utilízase para a transferencia de ficheiros"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="232727040453645139">"Utilízase para a entrada"</string>
- <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="908775281788309484">"Usar para o audiófono"</string>
+ <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="908775281788309484">"Usar para os audiófonos"</string>
<string name="bluetooth_pairing_accept" msgid="6163520056536604875">"Sincronizar"</string>
<string name="bluetooth_pairing_accept_all_caps" msgid="6061699265220789149">"SINCRONIZAR"</string>
<string name="bluetooth_pairing_decline" msgid="4185420413578948140">"Cancelar"</string>
@@ -220,7 +220,8 @@
<string name="select_private_dns_configuration_title" msgid="3700456559305263922">"DNS privado"</string>
<string name="select_private_dns_configuration_dialog_title" msgid="9221994415765826811">"Selecciona o modo de DNS privado"</string>
<string name="private_dns_mode_off" msgid="8236575187318721684">"Desactivar"</string>
- <string name="private_dns_mode_opportunistic" msgid="7608409735589131766">"Oportunista"</string>
+ <!-- no translation found for private_dns_mode_opportunistic (8314986739896927399) -->
+ <skip />
<string name="private_dns_mode_provider" msgid="8354935160639360804">"Nome de host de provedor de DNS privado"</string>
<string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"Introduce o nome de host de provedor de DNS"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Mostra opcións para o certificado de visualización sen fíos"</string>
@@ -356,22 +357,41 @@
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Esta función é experimental e pode afectar ao rendemento."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"Anulado por <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="power_remaining_duration_only" msgid="845431008899029842">"Tempo que queda aproximadamente: <xliff:g id="TIME">%1$s</xliff:g>"</string>
+ <!-- no translation found for power_discharging_duration (6655472132189365839) -->
+ <skip />
<string name="power_remaining_duration_only_enhanced" msgid="5992456722677973678">"Tempo restante aproximado en función do uso: <xliff:g id="TIME">%1$s</xliff:g>"</string>
- <string name="power_remaining_charging_duration_only" msgid="1421102457410268886">"Tempo que queda ata cargar de todo: <xliff:g id="TIME">%1$s</xliff:g>"</string>
+ <!-- no translation found for power_discharging_duration_enhanced (5726302316642148671) -->
+ <skip />
<string name="power_remaining_duration_only_short" msgid="5329694252258605547">"Tempo restante: <xliff:g id="TIME">%1$s</xliff:g>"</string>
+ <!-- no translation found for power_discharge_by_enhanced (8788299408879961465) -->
+ <skip />
+ <!-- no translation found for power_discharge_by_only_enhanced (7692297898877104416) -->
+ <skip />
+ <!-- no translation found for power_discharge_by (6427074755635635749) -->
+ <skip />
+ <!-- no translation found for power_discharge_by_only (5888058889261108064) -->
+ <skip />
<string name="power_remaining_less_than_duration_only" msgid="5996752448813295329">"Tempo restante inferior a <xliff:g id="THRESHOLD">%1$s</xliff:g>"</string>
- <string name="power_remaining_less_than_duration" msgid="7967078125657859046">"<xliff:g id="LEVEL">%1$s</xliff:g>: tempo restante inferior a <xliff:g id="THRESHOLD">%2$s</xliff:g>"</string>
- <string name="power_remaining_more_than_subtext" msgid="6846716609975752316">"<xliff:g id="LEVEL">%1$s</xliff:g>: tempo restante superior a <xliff:g id="TIME_REMAINING">%2$s</xliff:g>"</string>
- <string name="power_remaining_only_more_than_subtext" msgid="8884488700395194194">"tempo restante superior a: <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="default" msgid="8168317165722752881">"é posible que o teléfono se apague en breve"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="tablet" msgid="5957064378548718872">"é posible que a tableta se apague en breve"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="device" msgid="9055596817716471373">"é posible que o dispositivo se apague en breve"</string>
- <string name="power_discharging_duration" msgid="2843747179907396142">"<xliff:g id="LEVEL">%1$s</xliff:g> (tempo restante aproximado: <xliff:g id="TIME">%2$s</xliff:g>)"</string>
- <string name="power_discharging_duration_enhanced" msgid="4401782117770255046">"<xliff:g id="LEVEL">%1$s</xliff:g> - Tempo restante aproximado en función do uso: <xliff:g id="TIME">%2$s</xliff:g>"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="default" msgid="7679005631124015335">"<xliff:g id="LEVEL">%1$s</xliff:g>: é posible que o teléfono se apague en breve"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="tablet" msgid="261050880878965621">"<xliff:g id="LEVEL">%1$s</xliff:g>: é posible que a tableta se apague en breve"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="device" msgid="2020049829798578618">"<xliff:g id="LEVEL">%1$s</xliff:g>: é posible que o dispositivo se apague en breve"</string>
+ <!-- no translation found for power_remaining_less_than_duration (5751885147712659423) -->
+ <skip />
+ <!-- no translation found for power_remaining_more_than_subtext (3176771815132876675) -->
+ <skip />
+ <!-- no translation found for power_remaining_only_more_than_subtext (8931654680569617380) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (1181059207608751924) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (2606370266981054691) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (2918084807716859985) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (3090926004324573908) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (7466484148515796216) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (603933521600231649) -->
+ <skip />
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
+ <string name="power_remaining_charging_duration_only" msgid="1421102457410268886">"Tempo que queda ata cargar de todo: <xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="4676999980973411875">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> ata completar a carga"</string>
<string name="battery_info_status_unknown" msgid="196130600938058547">"Descoñecido"</string>
<string name="battery_info_status_charging" msgid="1705179948350365604">"Cargando"</string>
diff --git a/packages/SettingsLib/res/values-gu/strings.xml b/packages/SettingsLib/res/values-gu/strings.xml
index c517b8b..9b54fa6 100644
--- a/packages/SettingsLib/res/values-gu/strings.xml
+++ b/packages/SettingsLib/res/values-gu/strings.xml
@@ -220,7 +220,8 @@
<string name="select_private_dns_configuration_title" msgid="3700456559305263922">"ખાનગી DNS"</string>
<string name="select_private_dns_configuration_dialog_title" msgid="9221994415765826811">"ખાનગી DNS મોડને પસંદ કરો"</string>
<string name="private_dns_mode_off" msgid="8236575187318721684">"બંધ"</string>
- <string name="private_dns_mode_opportunistic" msgid="7608409735589131766">"તકવાદી"</string>
+ <!-- no translation found for private_dns_mode_opportunistic (8314986739896927399) -->
+ <skip />
<string name="private_dns_mode_provider" msgid="8354935160639360804">"ખાનગી DNS પ્રદાતા હોસ્ટનું નામ"</string>
<string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"DNS પ્રદાતાના હોસ્ટનું નામ દાખલ કરો"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"વાયરલેસ ડિસ્પ્લે પ્રમાણપત્ર માટેના વિકલ્પો બતાવો"</string>
@@ -356,22 +357,41 @@
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"આ સુવિધા પ્રાયોગિક છે અને કામગીરી પર અસર કરી શકે છે."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"<xliff:g id="TITLE">%1$s</xliff:g> દ્વારા ઓવરરાઇડ થયું"</string>
<string name="power_remaining_duration_only" msgid="845431008899029842">"અંદાજે <xliff:g id="TIME">%1$s</xliff:g> બાકી"</string>
+ <!-- no translation found for power_discharging_duration (6655472132189365839) -->
+ <skip />
<string name="power_remaining_duration_only_enhanced" msgid="5992456722677973678">"તમારા વપરાશનાં આધારે લગભગ <xliff:g id="TIME">%1$s</xliff:g> બાકી છે"</string>
- <string name="power_remaining_charging_duration_only" msgid="1421102457410268886">"સંપૂર્ણપણે ચાર્જ થવામાં <xliff:g id="TIME">%1$s</xliff:g> બાકી"</string>
+ <!-- no translation found for power_discharging_duration_enhanced (5726302316642148671) -->
+ <skip />
<string name="power_remaining_duration_only_short" msgid="5329694252258605547">"<xliff:g id="TIME">%1$s</xliff:g> બાકી"</string>
+ <!-- no translation found for power_discharge_by_enhanced (8788299408879961465) -->
+ <skip />
+ <!-- no translation found for power_discharge_by_only_enhanced (7692297898877104416) -->
+ <skip />
+ <!-- no translation found for power_discharge_by (6427074755635635749) -->
+ <skip />
+ <!-- no translation found for power_discharge_by_only (5888058889261108064) -->
+ <skip />
<string name="power_remaining_less_than_duration_only" msgid="5996752448813295329">"<xliff:g id="THRESHOLD">%1$s</xliff:g> કરતાં ઓછો સમય બાકી છે"</string>
- <string name="power_remaining_less_than_duration" msgid="7967078125657859046">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="THRESHOLD">%2$s</xliff:g> કરતાં ઓછો સમય બાકી છે"</string>
- <string name="power_remaining_more_than_subtext" msgid="6846716609975752316">"<xliff:g id="LEVEL">%1$s</xliff:g><xliff:g id="TIME_REMAINING">%2$s</xliff:g> કરતાં વધુ સમય બાકી છે"</string>
- <string name="power_remaining_only_more_than_subtext" msgid="8884488700395194194">"<xliff:g id="TIME_REMAINING">%1$s</xliff:g> કરતાં વધુ સમય બાકી છે"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="default" msgid="8168317165722752881">"ફોન થોડી વારમાં બંધ થઈ શકે છે"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="tablet" msgid="5957064378548718872">"ટૅબ્લેટ થોડી વારમાં બંધ થઈ શકે છે"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="device" msgid="9055596817716471373">"ઉપકરણ થોડી વારમાં બંધ થઈ શકે છે"</string>
- <string name="power_discharging_duration" msgid="2843747179907396142">"<xliff:g id="LEVEL">%1$s</xliff:g> - લગભગ <xliff:g id="TIME">%2$s</xliff:g> બાકી"</string>
- <string name="power_discharging_duration_enhanced" msgid="4401782117770255046">"<xliff:g id="LEVEL">%1$s</xliff:g> - તમારા વપરાશનાં આધારે લગભગ <xliff:g id="TIME">%2$s</xliff:g> બાકી છે"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="default" msgid="7679005631124015335">"<xliff:g id="LEVEL">%1$s</xliff:g> - ફોન થોડી વારમાં બંધ થઈ શકે છે"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="tablet" msgid="261050880878965621">"<xliff:g id="LEVEL">%1$s</xliff:g> - ટૅબ્લેટ થોડી વારમાં બંધ થઈ શકે છે"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="device" msgid="2020049829798578618">"<xliff:g id="LEVEL">%1$s</xliff:g> - ઉપકરણ થોડી વારમાં બંધ થઈ શકે છે"</string>
+ <!-- no translation found for power_remaining_less_than_duration (5751885147712659423) -->
+ <skip />
+ <!-- no translation found for power_remaining_more_than_subtext (3176771815132876675) -->
+ <skip />
+ <!-- no translation found for power_remaining_only_more_than_subtext (8931654680569617380) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (1181059207608751924) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (2606370266981054691) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (2918084807716859985) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (3090926004324573908) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (7466484148515796216) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (603933521600231649) -->
+ <skip />
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
+ <string name="power_remaining_charging_duration_only" msgid="1421102457410268886">"સંપૂર્ણપણે ચાર્જ થવામાં <xliff:g id="TIME">%1$s</xliff:g> બાકી"</string>
<string name="power_charging_duration" msgid="4676999980973411875">"<xliff:g id="LEVEL">%1$s</xliff:g> - સંપૂર્ણપણે ચાર્જ થવા માટે <xliff:g id="TIME">%2$s</xliff:g>"</string>
<string name="battery_info_status_unknown" msgid="196130600938058547">"અજાણ્યું"</string>
<string name="battery_info_status_charging" msgid="1705179948350365604">"ચાર્જ થઈ રહ્યું છે"</string>
diff --git a/packages/SettingsLib/res/values-hi/strings.xml b/packages/SettingsLib/res/values-hi/strings.xml
index 2726c46..9179f2e 100644
--- a/packages/SettingsLib/res/values-hi/strings.xml
+++ b/packages/SettingsLib/res/values-hi/strings.xml
@@ -220,7 +220,8 @@
<string name="select_private_dns_configuration_title" msgid="3700456559305263922">"निजी DNS"</string>
<string name="select_private_dns_configuration_dialog_title" msgid="9221994415765826811">"निजी DNS मोड चुनें"</string>
<string name="private_dns_mode_off" msgid="8236575187318721684">"बंद"</string>
- <string name="private_dns_mode_opportunistic" msgid="7608409735589131766">"मौका मिलते ही काम करने वाला"</string>
+ <!-- no translation found for private_dns_mode_opportunistic (8314986739896927399) -->
+ <skip />
<string name="private_dns_mode_provider" msgid="8354935160639360804">"निजी DNS सेवा देने वाले का होस्टनाम"</string>
<string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"DNS सेवा देने वाले का होस्टनाम डालें"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"वायरलेस दिखाई देने के लिए प्रमाणन विकल्प दिखाएं"</string>
@@ -356,22 +357,41 @@
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"यह सुविधा प्रायोगिक है और निष्पादन को प्रभावित कर सकती है."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"<xliff:g id="TITLE">%1$s</xliff:g> के द्वारा ओवरराइड किया गया"</string>
<string name="power_remaining_duration_only" msgid="845431008899029842">"लगभग <xliff:g id="TIME">%1$s</xliff:g> शेष"</string>
+ <!-- no translation found for power_discharging_duration (6655472132189365839) -->
+ <skip />
<string name="power_remaining_duration_only_enhanced" msgid="5992456722677973678">"आपके उपयोग के आधार पर लगभग <xliff:g id="TIME">%1$s</xliff:g> का समय बचा है"</string>
- <string name="power_remaining_charging_duration_only" msgid="1421102457410268886">"पूरी तरह से चार्ज होने में <xliff:g id="TIME">%1$s</xliff:g> शेष"</string>
+ <!-- no translation found for power_discharging_duration_enhanced (5726302316642148671) -->
+ <skip />
<string name="power_remaining_duration_only_short" msgid="5329694252258605547">"<xliff:g id="TIME">%1$s</xliff:g> शेष"</string>
+ <!-- no translation found for power_discharge_by_enhanced (8788299408879961465) -->
+ <skip />
+ <!-- no translation found for power_discharge_by_only_enhanced (7692297898877104416) -->
+ <skip />
+ <!-- no translation found for power_discharge_by (6427074755635635749) -->
+ <skip />
+ <!-- no translation found for power_discharge_by_only (5888058889261108064) -->
+ <skip />
<string name="power_remaining_less_than_duration_only" msgid="5996752448813295329">"<xliff:g id="THRESHOLD">%1$s</xliff:g> से कम समय बचा है"</string>
- <string name="power_remaining_less_than_duration" msgid="7967078125657859046">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="THRESHOLD">%2$s</xliff:g> से कम बैटरी बची है"</string>
- <string name="power_remaining_more_than_subtext" msgid="6846716609975752316">"<xliff:g id="LEVEL">%1$s</xliff:g> <xliff:g id="TIME_REMAINING">%2$s</xliff:g> से ज़्यादा बैटरी बची है"</string>
- <string name="power_remaining_only_more_than_subtext" msgid="8884488700395194194">"<xliff:g id="TIME_REMAINING">%1$s</xliff:g> से ज़्यादा बैटरी बची है"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="default" msgid="8168317165722752881">"फ़ोन जल्दी ही बंद हो सकता है"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="tablet" msgid="5957064378548718872">"टैबलेट जल्दी ही बंद हो सकता है"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="device" msgid="9055596817716471373">"डिवाइस जल्दी ही बंद हो सकता है"</string>
- <string name="power_discharging_duration" msgid="2843747179907396142">"<xliff:g id="LEVEL">%1$s</xliff:g> - लगभग <xliff:g id="TIME">%2$s</xliff:g> शेष"</string>
- <string name="power_discharging_duration_enhanced" msgid="4401782117770255046">"<xliff:g id="LEVEL">%1$s</xliff:g> - आपके उपयोग के आधार पर लगभग <xliff:g id="TIME">%2$s</xliff:g> का समय बचा है"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="default" msgid="7679005631124015335">"<xliff:g id="LEVEL">%1$s</xliff:g> - फ़ोन जल्दी ही बंद हो सकता है"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="tablet" msgid="261050880878965621">"<xliff:g id="LEVEL">%1$s</xliff:g> - टैबलेट जल्दी ही बंद हो सकता है"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="device" msgid="2020049829798578618">"<xliff:g id="LEVEL">%1$s</xliff:g> - डिवाइस जल्दी ही बंद हो सकता है"</string>
+ <!-- no translation found for power_remaining_less_than_duration (5751885147712659423) -->
+ <skip />
+ <!-- no translation found for power_remaining_more_than_subtext (3176771815132876675) -->
+ <skip />
+ <!-- no translation found for power_remaining_only_more_than_subtext (8931654680569617380) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (1181059207608751924) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (2606370266981054691) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (2918084807716859985) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (3090926004324573908) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (7466484148515796216) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (603933521600231649) -->
+ <skip />
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
+ <string name="power_remaining_charging_duration_only" msgid="1421102457410268886">"पूरी तरह से चार्ज होने में <xliff:g id="TIME">%1$s</xliff:g> शेष"</string>
<string name="power_charging_duration" msgid="4676999980973411875">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> पूरी तरह से चार्ज होने तक"</string>
<string name="battery_info_status_unknown" msgid="196130600938058547">"अज्ञात"</string>
<string name="battery_info_status_charging" msgid="1705179948350365604">"चार्ज हो रही है"</string>
diff --git a/packages/SettingsLib/res/values-hr/strings.xml b/packages/SettingsLib/res/values-hr/strings.xml
index f7d59f0..f0a7fc4 100644
--- a/packages/SettingsLib/res/values-hr/strings.xml
+++ b/packages/SettingsLib/res/values-hr/strings.xml
@@ -220,7 +220,8 @@
<string name="select_private_dns_configuration_title" msgid="3700456559305263922">"Privatni DNS"</string>
<string name="select_private_dns_configuration_dialog_title" msgid="9221994415765826811">"Odaberite način privatnog DNS-a"</string>
<string name="private_dns_mode_off" msgid="8236575187318721684">"Isključeno"</string>
- <string name="private_dns_mode_opportunistic" msgid="7608409735589131766">"Oportunistički"</string>
+ <!-- no translation found for private_dns_mode_opportunistic (8314986739896927399) -->
+ <skip />
<string name="private_dns_mode_provider" msgid="8354935160639360804">"Naziv hosta davatelja usluge privatnog DNS-a"</string>
<string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"Unesite naziv hosta davatelja usluge DNS-a"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Prikaži opcije za certifikaciju bežičnog prikaza"</string>
@@ -356,22 +357,41 @@
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Ova je značajka eksperimentalna i može utjecati na performanse."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"Premošćeno postavkom <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="power_remaining_duration_only" msgid="845431008899029842">"Još otprilike <xliff:g id="TIME">%1$s</xliff:g>"</string>
+ <!-- no translation found for power_discharging_duration (6655472132189365839) -->
+ <skip />
<string name="power_remaining_duration_only_enhanced" msgid="5992456722677973678">"Još otprilike <xliff:g id="TIME">%1$s</xliff:g> na temelju vaše upotrebe"</string>
- <string name="power_remaining_charging_duration_only" msgid="1421102457410268886">"Još <xliff:g id="TIME">%1$s</xliff:g> do potpune napunjenosti"</string>
+ <!-- no translation found for power_discharging_duration_enhanced (5726302316642148671) -->
+ <skip />
<string name="power_remaining_duration_only_short" msgid="5329694252258605547">"Još <xliff:g id="TIME">%1$s</xliff:g>"</string>
+ <!-- no translation found for power_discharge_by_enhanced (8788299408879961465) -->
+ <skip />
+ <!-- no translation found for power_discharge_by_only_enhanced (7692297898877104416) -->
+ <skip />
+ <!-- no translation found for power_discharge_by (6427074755635635749) -->
+ <skip />
+ <!-- no translation found for power_discharge_by_only (5888058889261108064) -->
+ <skip />
<string name="power_remaining_less_than_duration_only" msgid="5996752448813295329">"Preostalo je manje od <xliff:g id="THRESHOLD">%1$s</xliff:g>"</string>
- <string name="power_remaining_less_than_duration" msgid="7967078125657859046">"<xliff:g id="LEVEL">%1$s</xliff:g> – preostalo je manje od <xliff:g id="THRESHOLD">%2$s</xliff:g>"</string>
- <string name="power_remaining_more_than_subtext" msgid="6846716609975752316">"<xliff:g id="LEVEL">%1$s</xliff:g> – preostalo je više od <xliff:g id="TIME_REMAINING">%2$s</xliff:g>"</string>
- <string name="power_remaining_only_more_than_subtext" msgid="8884488700395194194">"preostalo je više od <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="default" msgid="8168317165722752881">"telefon bi se uskoro mogao isključiti"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="tablet" msgid="5957064378548718872">"tablet bi se uskoro mogao isključiti"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="device" msgid="9055596817716471373">"uređaj bi se uskoro mogao isključiti"</string>
- <string name="power_discharging_duration" msgid="2843747179907396142">"<xliff:g id="LEVEL">%1$s</xliff:g> – preostalo je približno <xliff:g id="TIME">%2$s</xliff:g>"</string>
- <string name="power_discharging_duration_enhanced" msgid="4401782117770255046">"<xliff:g id="LEVEL">%1$s</xliff:g> – još otprilike <xliff:g id="TIME">%2$s</xliff:g> na temelju vaše upotrebe"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="default" msgid="7679005631124015335">"<xliff:g id="LEVEL">%1$s</xliff:g> – telefon bi se uskoro mogao isključiti"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="tablet" msgid="261050880878965621">"<xliff:g id="LEVEL">%1$s</xliff:g> – tablet bi se uskoro mogao isključiti"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="device" msgid="2020049829798578618">"<xliff:g id="LEVEL">%1$s</xliff:g> – uređaj bi se uskoro mogao isključiti"</string>
+ <!-- no translation found for power_remaining_less_than_duration (5751885147712659423) -->
+ <skip />
+ <!-- no translation found for power_remaining_more_than_subtext (3176771815132876675) -->
+ <skip />
+ <!-- no translation found for power_remaining_only_more_than_subtext (8931654680569617380) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (1181059207608751924) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (2606370266981054691) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (2918084807716859985) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (3090926004324573908) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (7466484148515796216) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (603933521600231649) -->
+ <skip />
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string>
+ <string name="power_remaining_charging_duration_only" msgid="1421102457410268886">"Još <xliff:g id="TIME">%1$s</xliff:g> do potpune napunjenosti"</string>
<string name="power_charging_duration" msgid="4676999980973411875">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> do potpune napunjenosti"</string>
<string name="battery_info_status_unknown" msgid="196130600938058547">"Nepoznato"</string>
<string name="battery_info_status_charging" msgid="1705179948350365604">"Punjenje"</string>
diff --git a/packages/SettingsLib/res/values-hu/strings.xml b/packages/SettingsLib/res/values-hu/strings.xml
index 35a5560..b354ea9 100644
--- a/packages/SettingsLib/res/values-hu/strings.xml
+++ b/packages/SettingsLib/res/values-hu/strings.xml
@@ -220,7 +220,8 @@
<string name="select_private_dns_configuration_title" msgid="3700456559305263922">"Privát DNS"</string>
<string name="select_private_dns_configuration_dialog_title" msgid="9221994415765826811">"„Privát DNS” mód kiválasztása"</string>
<string name="private_dns_mode_off" msgid="8236575187318721684">"Ki"</string>
- <string name="private_dns_mode_opportunistic" msgid="7608409735589131766">"Opportunista"</string>
+ <!-- no translation found for private_dns_mode_opportunistic (8314986739896927399) -->
+ <skip />
<string name="private_dns_mode_provider" msgid="8354935160639360804">"Privát DNS-szolgáltató gazdagépneve"</string>
<string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"Adja meg a DNS-szolgáltató gazdagépnevét"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Vezeték nélküli kijelző tanúsítványával kapcsolatos lehetőségek megjelenítése"</string>
@@ -356,22 +357,41 @@
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Ez egy kísérleti funkció, és hatással lehet a teljesítményre."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"Felülírva erre: <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="power_remaining_duration_only" msgid="845431008899029842">"Körülbelül <xliff:g id="TIME">%1$s</xliff:g> maradt hátra"</string>
+ <!-- no translation found for power_discharging_duration (6655472132189365839) -->
+ <skip />
<string name="power_remaining_duration_only_enhanced" msgid="5992456722677973678">"Körülbelül <xliff:g id="TIME">%1$s</xliff:g> van hátra az eszköz igénybevétele alapján"</string>
- <string name="power_remaining_charging_duration_only" msgid="1421102457410268886">"<xliff:g id="TIME">%1$s</xliff:g> a teljes töltöttségig"</string>
+ <!-- no translation found for power_discharging_duration_enhanced (5726302316642148671) -->
+ <skip />
<string name="power_remaining_duration_only_short" msgid="5329694252258605547">"<xliff:g id="TIME">%1$s</xliff:g> van hátra"</string>
+ <!-- no translation found for power_discharge_by_enhanced (8788299408879961465) -->
+ <skip />
+ <!-- no translation found for power_discharge_by_only_enhanced (7692297898877104416) -->
+ <skip />
+ <!-- no translation found for power_discharge_by (6427074755635635749) -->
+ <skip />
+ <!-- no translation found for power_discharge_by_only (5888058889261108064) -->
+ <skip />
<string name="power_remaining_less_than_duration_only" msgid="5996752448813295329">"Kevesebb mint <xliff:g id="THRESHOLD">%1$s</xliff:g> van hátra"</string>
- <string name="power_remaining_less_than_duration" msgid="7967078125657859046">"<xliff:g id="LEVEL">%1$s</xliff:g> – kevesebb mint <xliff:g id="THRESHOLD">%2$s</xliff:g> van hátra"</string>
- <string name="power_remaining_more_than_subtext" msgid="6846716609975752316">"<xliff:g id="LEVEL">%1$s</xliff:g> – több mint <xliff:g id="TIME_REMAINING">%2$s</xliff:g> van hátra"</string>
- <string name="power_remaining_only_more_than_subtext" msgid="8884488700395194194">"több mint <xliff:g id="TIME_REMAINING">%1$s</xliff:g> van hátra"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="default" msgid="8168317165722752881">"előfordulhat, hogy a telefon hamarosan leáll"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="tablet" msgid="5957064378548718872">"előfordulhat, hogy a táblagép hamarosan leáll"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="device" msgid="9055596817716471373">"előfordulhat, hogy az eszköz hamarosan leáll"</string>
- <string name="power_discharging_duration" msgid="2843747179907396142">"<xliff:g id="LEVEL">%1$s</xliff:g> - körülbelül <xliff:g id="TIME">%2$s</xliff:g> van hátra"</string>
- <string name="power_discharging_duration_enhanced" msgid="4401782117770255046">"<xliff:g id="LEVEL">%1$s</xliff:g> – körülbelül <xliff:g id="TIME">%2$s</xliff:g> van hátra az eszköz igénybevétele alapján"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="default" msgid="7679005631124015335">"<xliff:g id="LEVEL">%1$s</xliff:g> – előfordulhat, hogy a telefon hamarosan leáll"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="tablet" msgid="261050880878965621">"<xliff:g id="LEVEL">%1$s</xliff:g> – előfordulhat, hogy a táblagép hamarosan leáll"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="device" msgid="2020049829798578618">"<xliff:g id="LEVEL">%1$s</xliff:g> – előfordulhat, hogy az eszköz hamarosan leáll"</string>
+ <!-- no translation found for power_remaining_less_than_duration (5751885147712659423) -->
+ <skip />
+ <!-- no translation found for power_remaining_more_than_subtext (3176771815132876675) -->
+ <skip />
+ <!-- no translation found for power_remaining_only_more_than_subtext (8931654680569617380) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (1181059207608751924) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (2606370266981054691) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (2918084807716859985) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (3090926004324573908) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (7466484148515796216) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (603933521600231649) -->
+ <skip />
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string>
+ <string name="power_remaining_charging_duration_only" msgid="1421102457410268886">"<xliff:g id="TIME">%1$s</xliff:g> a teljes töltöttségig"</string>
<string name="power_charging_duration" msgid="4676999980973411875">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> a teljes feltöltésig"</string>
<string name="battery_info_status_unknown" msgid="196130600938058547">"Ismeretlen"</string>
<string name="battery_info_status_charging" msgid="1705179948350365604">"Töltés"</string>
diff --git a/packages/SettingsLib/res/values-hy/strings.xml b/packages/SettingsLib/res/values-hy/strings.xml
index 44a1714..8e52ceb 100644
--- a/packages/SettingsLib/res/values-hy/strings.xml
+++ b/packages/SettingsLib/res/values-hy/strings.xml
@@ -220,7 +220,8 @@
<string name="select_private_dns_configuration_title" msgid="3700456559305263922">"Անհատական DNS"</string>
<string name="select_private_dns_configuration_dialog_title" msgid="9221994415765826811">"Ընտրեք անհատական DNS սերվերի ռեժիմը"</string>
<string name="private_dns_mode_off" msgid="8236575187318721684">"Անջատված է"</string>
- <string name="private_dns_mode_opportunistic" msgid="7608409735589131766">"Ճկուն"</string>
+ <!-- no translation found for private_dns_mode_opportunistic (8314986739896927399) -->
+ <skip />
<string name="private_dns_mode_provider" msgid="8354935160639360804">"Անհատական DNS ծառայության մատակարարի խնամորդի անունը"</string>
<string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"Մուտքագրեք DNS ծառայության մատակարարի խնամորդի անունը"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Ցույց տալ անլար էկրանի հավաստագրման ընտրանքները"</string>
@@ -356,22 +357,41 @@
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Սա փորձնական գործառույթ է և կարող է ազդել սարքի աշխատանքի վրա:"</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"Գերազանցված է <xliff:g id="TITLE">%1$s</xliff:g>-ից"</string>
<string name="power_remaining_duration_only" msgid="845431008899029842">"Մնացել է մոտ <xliff:g id="TIME">%1$s</xliff:g>"</string>
+ <!-- no translation found for power_discharging_duration (6655472132189365839) -->
+ <skip />
<string name="power_remaining_duration_only_enhanced" msgid="5992456722677973678">"Մնացել է մոտ <xliff:g id="TIME">%1$s</xliff:g>՝ օգտագործման եղանակից կախված"</string>
- <string name="power_remaining_charging_duration_only" msgid="1421102457410268886">"Մինչև լրիվ լիցքավորումը մնացել է <xliff:g id="TIME">%1$s</xliff:g>"</string>
+ <!-- no translation found for power_discharging_duration_enhanced (5726302316642148671) -->
+ <skip />
<string name="power_remaining_duration_only_short" msgid="5329694252258605547">"Մնացել է <xliff:g id="TIME">%1$s</xliff:g>"</string>
+ <!-- no translation found for power_discharge_by_enhanced (8788299408879961465) -->
+ <skip />
+ <!-- no translation found for power_discharge_by_only_enhanced (7692297898877104416) -->
+ <skip />
+ <!-- no translation found for power_discharge_by (6427074755635635749) -->
+ <skip />
+ <!-- no translation found for power_discharge_by_only (5888058889261108064) -->
+ <skip />
<string name="power_remaining_less_than_duration_only" msgid="5996752448813295329">"Մնացել է <xliff:g id="THRESHOLD">%1$s</xliff:g>-ից պակաս"</string>
- <string name="power_remaining_less_than_duration" msgid="7967078125657859046">"<xliff:g id="LEVEL">%1$s</xliff:g>՝ մնացել է <xliff:g id="THRESHOLD">%2$s</xliff:g>-ից պակաս"</string>
- <string name="power_remaining_more_than_subtext" msgid="6846716609975752316">"<xliff:g id="LEVEL">%1$s</xliff:g>՝ մնացել է ավելի քան <xliff:g id="TIME_REMAINING">%2$s</xliff:g>"</string>
- <string name="power_remaining_only_more_than_subtext" msgid="8884488700395194194">"մնացել է ավելի քան <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="default" msgid="8168317165722752881">"հնարավոր է հեռախոսը շուտով կանջատվի"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="tablet" msgid="5957064378548718872">"հնարավոր է պլանշետը շուտով կանջատվի"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="device" msgid="9055596817716471373">"հնարավոր է սարքը շուտով կանջատվի"</string>
- <string name="power_discharging_duration" msgid="2843747179907396142">"<xliff:g id="LEVEL">%1$s</xliff:g> – մնացել է մոտ <xliff:g id="TIME">%2$s</xliff:g>"</string>
- <string name="power_discharging_duration_enhanced" msgid="4401782117770255046">"<xliff:g id="LEVEL">%1$s</xliff:g> - մնացել է մոտ <xliff:g id="TIME">%2$s</xliff:g>՝ օգտագործման եղանակից կախված"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="default" msgid="7679005631124015335">"<xliff:g id="LEVEL">%1$s</xliff:g>՝ հնարավոր է հեռախոսը շուտով կանջատվի"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="tablet" msgid="261050880878965621">"<xliff:g id="LEVEL">%1$s</xliff:g>՝ հնարավոր է պլանշետը շուտով կանջատվի"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="device" msgid="2020049829798578618">"<xliff:g id="LEVEL">%1$s</xliff:g>՝ հնարավոր է սարքը շուտով կանջատվի"</string>
+ <!-- no translation found for power_remaining_less_than_duration (5751885147712659423) -->
+ <skip />
+ <!-- no translation found for power_remaining_more_than_subtext (3176771815132876675) -->
+ <skip />
+ <!-- no translation found for power_remaining_only_more_than_subtext (8931654680569617380) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (1181059207608751924) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (2606370266981054691) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (2918084807716859985) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (3090926004324573908) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (7466484148515796216) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (603933521600231649) -->
+ <skip />
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
+ <string name="power_remaining_charging_duration_only" msgid="1421102457410268886">"Մինչև լրիվ լիցքավորումը մնացել է <xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="4676999980973411875">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> մինչև լրիվ լիցքավորումը"</string>
<string name="battery_info_status_unknown" msgid="196130600938058547">"Անհայտ"</string>
<string name="battery_info_status_charging" msgid="1705179948350365604">"Լիցքավորում"</string>
diff --git a/packages/SettingsLib/res/values-in/strings.xml b/packages/SettingsLib/res/values-in/strings.xml
index c02bd90..3e8c676 100644
--- a/packages/SettingsLib/res/values-in/strings.xml
+++ b/packages/SettingsLib/res/values-in/strings.xml
@@ -220,7 +220,8 @@
<string name="select_private_dns_configuration_title" msgid="3700456559305263922">"DNS Pribadi"</string>
<string name="select_private_dns_configuration_dialog_title" msgid="9221994415765826811">"Pilih Mode DNS Pribadi"</string>
<string name="private_dns_mode_off" msgid="8236575187318721684">"Nonaktif"</string>
- <string name="private_dns_mode_opportunistic" msgid="7608409735589131766">"Oportunistik"</string>
+ <!-- no translation found for private_dns_mode_opportunistic (8314986739896927399) -->
+ <skip />
<string name="private_dns_mode_provider" msgid="8354935160639360804">"Hostname penyedia DNS pribadi"</string>
<string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"Masukkan hostname penyedia DNS"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Tampilkan opsi untuk sertifikasi layar nirkabel"</string>
@@ -356,22 +357,41 @@
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Fitur ini bersifat eksperimental dan dapat memengaruhi kinerja."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"Digantikan oleh <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="power_remaining_duration_only" msgid="845431008899029842">"Sekitar <xliff:g id="TIME">%1$s</xliff:g> lagi"</string>
+ <!-- no translation found for power_discharging_duration (6655472132189365839) -->
+ <skip />
<string name="power_remaining_duration_only_enhanced" msgid="5992456722677973678">"Kira-kira <xliff:g id="TIME">%1$s</xliff:g> lagi berdasarkan penggunaan Anda"</string>
- <string name="power_remaining_charging_duration_only" msgid="1421102457410268886">"<xliff:g id="TIME">%1$s</xliff:g> lagi hingga terisi penuh"</string>
+ <!-- no translation found for power_discharging_duration_enhanced (5726302316642148671) -->
+ <skip />
<string name="power_remaining_duration_only_short" msgid="5329694252258605547">"<xliff:g id="TIME">%1$s</xliff:g> tersisa"</string>
+ <!-- no translation found for power_discharge_by_enhanced (8788299408879961465) -->
+ <skip />
+ <!-- no translation found for power_discharge_by_only_enhanced (7692297898877104416) -->
+ <skip />
+ <!-- no translation found for power_discharge_by (6427074755635635749) -->
+ <skip />
+ <!-- no translation found for power_discharge_by_only (5888058889261108064) -->
+ <skip />
<string name="power_remaining_less_than_duration_only" msgid="5996752448813295329">"Tersisa kurang dari <xliff:g id="THRESHOLD">%1$s</xliff:g>"</string>
- <string name="power_remaining_less_than_duration" msgid="7967078125657859046">"<xliff:g id="LEVEL">%1$s</xliff:g> - Tersisa kurang dari <xliff:g id="THRESHOLD">%2$s</xliff:g>"</string>
- <string name="power_remaining_more_than_subtext" msgid="6846716609975752316">"<xliff:g id="LEVEL">%1$s</xliff:g>tersisa lebih dari <xliff:g id="TIME_REMAINING">%2$s</xliff:g>"</string>
- <string name="power_remaining_only_more_than_subtext" msgid="8884488700395194194">"tersisa lebih dari <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="default" msgid="8168317165722752881">"ponsel mungkin segera dimatikan"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="tablet" msgid="5957064378548718872">"tablet mungkin segera dimatikan"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="device" msgid="9055596817716471373">"perangkat mungkin segera dimatikan"</string>
- <string name="power_discharging_duration" msgid="2843747179907396142">"<xliff:g id="LEVEL">%1$s</xliff:g> - kira-kira <xliff:g id="TIME">%2$s</xliff:g> lagi"</string>
- <string name="power_discharging_duration_enhanced" msgid="4401782117770255046">"<xliff:g id="LEVEL">%1$s</xliff:g> - kira-kira <xliff:g id="TIME">%2$s</xliff:g> lagi berdasarkan penggunaan Anda"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="default" msgid="7679005631124015335">"<xliff:g id="LEVEL">%1$s</xliff:g> - ponsel mungkin segera dimatikan"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="tablet" msgid="261050880878965621">"<xliff:g id="LEVEL">%1$s</xliff:g> - tablet mungkin segera dimatikan"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="device" msgid="2020049829798578618">"<xliff:g id="LEVEL">%1$s</xliff:g> - perangkat mungkin segera dimatikan"</string>
+ <!-- no translation found for power_remaining_less_than_duration (5751885147712659423) -->
+ <skip />
+ <!-- no translation found for power_remaining_more_than_subtext (3176771815132876675) -->
+ <skip />
+ <!-- no translation found for power_remaining_only_more_than_subtext (8931654680569617380) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (1181059207608751924) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (2606370266981054691) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (2918084807716859985) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (3090926004324573908) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (7466484148515796216) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (603933521600231649) -->
+ <skip />
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
+ <string name="power_remaining_charging_duration_only" msgid="1421102457410268886">"<xliff:g id="TIME">%1$s</xliff:g> lagi hingga terisi penuh"</string>
<string name="power_charging_duration" msgid="4676999980973411875">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> lagi terisi penuh"</string>
<string name="battery_info_status_unknown" msgid="196130600938058547">"Tidak diketahui"</string>
<string name="battery_info_status_charging" msgid="1705179948350365604">"Mengisi daya"</string>
diff --git a/packages/SettingsLib/res/values-is/strings.xml b/packages/SettingsLib/res/values-is/strings.xml
index 36baf6c..0e90dd6 100644
--- a/packages/SettingsLib/res/values-is/strings.xml
+++ b/packages/SettingsLib/res/values-is/strings.xml
@@ -220,7 +220,8 @@
<string name="select_private_dns_configuration_title" msgid="3700456559305263922">"Lokað DNS"</string>
<string name="select_private_dns_configuration_dialog_title" msgid="9221994415765826811">"Velja lokaða DNS-stillingu"</string>
<string name="private_dns_mode_off" msgid="8236575187318721684">"Slökkt"</string>
- <string name="private_dns_mode_opportunistic" msgid="7608409735589131766">"Eftir hentugleika"</string>
+ <!-- no translation found for private_dns_mode_opportunistic (8314986739896927399) -->
+ <skip />
<string name="private_dns_mode_provider" msgid="8354935160639360804">"Hýsilheiti lokaðrar DNS-veitu"</string>
<string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"Slá inn hýsilheiti DNS-veitu"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Sýna valkosti fyrir vottun þráðlausra skjáa"</string>
@@ -356,22 +357,41 @@
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Þessi eiginleiki er á tilraunastigi og getur haft áhrif á frammistöðu."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"Hnekkt af <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="power_remaining_duration_only" msgid="845431008899029842">"Um það bil <xliff:g id="TIME">%1$s</xliff:g> eftir"</string>
+ <!-- no translation found for power_discharging_duration (6655472132189365839) -->
+ <skip />
<string name="power_remaining_duration_only_enhanced" msgid="5992456722677973678">"U.þ.b. <xliff:g id="TIME">%1$s</xliff:g> eftir miðað við notkun þína"</string>
- <string name="power_remaining_charging_duration_only" msgid="1421102457410268886">"<xliff:g id="TIME">%1$s</xliff:g> þar til hleðslu er lokið"</string>
+ <!-- no translation found for power_discharging_duration_enhanced (5726302316642148671) -->
+ <skip />
<string name="power_remaining_duration_only_short" msgid="5329694252258605547">"<xliff:g id="TIME">%1$s</xliff:g> eftir"</string>
+ <!-- no translation found for power_discharge_by_enhanced (8788299408879961465) -->
+ <skip />
+ <!-- no translation found for power_discharge_by_only_enhanced (7692297898877104416) -->
+ <skip />
+ <!-- no translation found for power_discharge_by (6427074755635635749) -->
+ <skip />
+ <!-- no translation found for power_discharge_by_only (5888058889261108064) -->
+ <skip />
<string name="power_remaining_less_than_duration_only" msgid="5996752448813295329">"Minna en <xliff:g id="THRESHOLD">%1$s</xliff:g> eftir"</string>
- <string name="power_remaining_less_than_duration" msgid="7967078125657859046">"<xliff:g id="LEVEL">%1$s</xliff:g> – Minna en <xliff:g id="THRESHOLD">%2$s</xliff:g> eftir"</string>
- <string name="power_remaining_more_than_subtext" msgid="6846716609975752316">"<xliff:g id="LEVEL">%1$s</xliff:g>meira en <xliff:g id="TIME_REMAINING">%2$s</xliff:g> eftir"</string>
- <string name="power_remaining_only_more_than_subtext" msgid="8884488700395194194">"meira en <xliff:g id="TIME_REMAINING">%1$s</xliff:g> eftir"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="default" msgid="8168317165722752881">"síminn gæti slökkt á sér fljótlega"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="tablet" msgid="5957064378548718872">"spjaldtölvan gæti slökkt á sér fljótlega"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="device" msgid="9055596817716471373">"tækið gæti slökkt á sér fljótlega"</string>
- <string name="power_discharging_duration" msgid="2843747179907396142">"<xliff:g id="LEVEL">%1$s</xliff:g> – um <xliff:g id="TIME">%2$s</xliff:g> eftir"</string>
- <string name="power_discharging_duration_enhanced" msgid="4401782117770255046">"<xliff:g id="LEVEL">%1$s</xliff:g> – u.þ.b. <xliff:g id="TIME">%2$s</xliff:g> eftir miðað við notkun þína"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="default" msgid="7679005631124015335">"<xliff:g id="LEVEL">%1$s</xliff:g> – síminn gæti slökkt á sér fljótlega"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="tablet" msgid="261050880878965621">"<xliff:g id="LEVEL">%1$s</xliff:g> – spjaldtölvan gæti slökkt á sér fljótlega"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="device" msgid="2020049829798578618">"<xliff:g id="LEVEL">%1$s</xliff:g> – tækið gæti slökkt á sér fljótlega"</string>
+ <!-- no translation found for power_remaining_less_than_duration (5751885147712659423) -->
+ <skip />
+ <!-- no translation found for power_remaining_more_than_subtext (3176771815132876675) -->
+ <skip />
+ <!-- no translation found for power_remaining_only_more_than_subtext (8931654680569617380) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (1181059207608751924) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (2606370266981054691) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (2918084807716859985) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (3090926004324573908) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (7466484148515796216) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (603933521600231649) -->
+ <skip />
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string>
+ <string name="power_remaining_charging_duration_only" msgid="1421102457410268886">"<xliff:g id="TIME">%1$s</xliff:g> þar til hleðslu er lokið"</string>
<string name="power_charging_duration" msgid="4676999980973411875">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> þar til fullri hleðslu er náð"</string>
<string name="battery_info_status_unknown" msgid="196130600938058547">"Óþekkt"</string>
<string name="battery_info_status_charging" msgid="1705179948350365604">"Í hleðslu"</string>
diff --git a/packages/SettingsLib/res/values-it/strings.xml b/packages/SettingsLib/res/values-it/strings.xml
index f19c14c..0ac2b8e 100644
--- a/packages/SettingsLib/res/values-it/strings.xml
+++ b/packages/SettingsLib/res/values-it/strings.xml
@@ -220,7 +220,8 @@
<string name="select_private_dns_configuration_title" msgid="3700456559305263922">"DNS privato"</string>
<string name="select_private_dns_configuration_dialog_title" msgid="9221994415765826811">"Seleziona modalità DNS privato"</string>
<string name="private_dns_mode_off" msgid="8236575187318721684">"Non attiva"</string>
- <string name="private_dns_mode_opportunistic" msgid="7608409735589131766">"Opportunistica"</string>
+ <!-- no translation found for private_dns_mode_opportunistic (8314986739896927399) -->
+ <skip />
<string name="private_dns_mode_provider" msgid="8354935160639360804">"Nome host del provider DNS privato"</string>
<string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"Inserisci il nome host del provider DNS"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Mostra opzioni per la certificazione display wireless"</string>
@@ -356,22 +357,41 @@
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Questa funzione è sperimentale e potrebbe influire sulle prestazioni."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"Valore sostituito da <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="power_remaining_duration_only" msgid="845431008899029842">"Tempo approssimativo rimanente: <xliff:g id="TIME">%1$s</xliff:g>"</string>
+ <!-- no translation found for power_discharging_duration (6655472132189365839) -->
+ <skip />
<string name="power_remaining_duration_only_enhanced" msgid="5992456722677973678">"Tempo rimanente in base al tuo utilizzo: <xliff:g id="TIME">%1$s</xliff:g> circa"</string>
- <string name="power_remaining_charging_duration_only" msgid="1421102457410268886">"Tempo rimanente alla carica completa: <xliff:g id="TIME">%1$s</xliff:g>"</string>
+ <!-- no translation found for power_discharging_duration_enhanced (5726302316642148671) -->
+ <skip />
<string name="power_remaining_duration_only_short" msgid="5329694252258605547">"Tempo rimanente: <xliff:g id="TIME">%1$s</xliff:g>"</string>
+ <!-- no translation found for power_discharge_by_enhanced (8788299408879961465) -->
+ <skip />
+ <!-- no translation found for power_discharge_by_only_enhanced (7692297898877104416) -->
+ <skip />
+ <!-- no translation found for power_discharge_by (6427074755635635749) -->
+ <skip />
+ <!-- no translation found for power_discharge_by_only (5888058889261108064) -->
+ <skip />
<string name="power_remaining_less_than_duration_only" msgid="5996752448813295329">"Tempo rimanente: meno di <xliff:g id="THRESHOLD">%1$s</xliff:g>"</string>
- <string name="power_remaining_less_than_duration" msgid="7967078125657859046">"<xliff:g id="LEVEL">%1$s</xliff:g> - Tempo rimanente: meno di <xliff:g id="THRESHOLD">%2$s</xliff:g>"</string>
- <string name="power_remaining_more_than_subtext" msgid="6846716609975752316">"<xliff:g id="LEVEL">%1$s</xliff:g> - Tempo rimanente: più di <xliff:g id="TIME_REMAINING">%2$s</xliff:g>"</string>
- <string name="power_remaining_only_more_than_subtext" msgid="8884488700395194194">"Tempo rimanente: più di <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="default" msgid="8168317165722752881">"Il telefono potrebbe spegnersi a breve"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="tablet" msgid="5957064378548718872">"Il tablet potrebbe spegnersi a breve"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="device" msgid="9055596817716471373">"Il dispositivo potrebbe spegnersi a breve"</string>
- <string name="power_discharging_duration" msgid="2843747179907396142">"<xliff:g id="LEVEL">%1$s</xliff:g> - ancora circa <xliff:g id="TIME">%2$s</xliff:g>"</string>
- <string name="power_discharging_duration_enhanced" msgid="4401782117770255046">"<xliff:g id="LEVEL">%1$s</xliff:g> - Tempo rimanente in base al tuo utilizzo: <xliff:g id="TIME">%2$s</xliff:g> circa"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="default" msgid="7679005631124015335">"<xliff:g id="LEVEL">%1$s</xliff:g>: il telefono potrebbe spegnersi a breve"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="tablet" msgid="261050880878965621">"<xliff:g id="LEVEL">%1$s</xliff:g>: il tablet potrebbe spegnersi a breve"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="device" msgid="2020049829798578618">"<xliff:g id="LEVEL">%1$s</xliff:g>: il dispositivo potrebbe spegnersi a breve"</string>
+ <!-- no translation found for power_remaining_less_than_duration (5751885147712659423) -->
+ <skip />
+ <!-- no translation found for power_remaining_more_than_subtext (3176771815132876675) -->
+ <skip />
+ <!-- no translation found for power_remaining_only_more_than_subtext (8931654680569617380) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (1181059207608751924) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (2606370266981054691) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (2918084807716859985) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (3090926004324573908) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (7466484148515796216) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (603933521600231649) -->
+ <skip />
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
+ <string name="power_remaining_charging_duration_only" msgid="1421102457410268886">"Tempo rimanente alla carica completa: <xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="4676999980973411875">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> alla carica completa"</string>
<string name="battery_info_status_unknown" msgid="196130600938058547">"Sconosciuta"</string>
<string name="battery_info_status_charging" msgid="1705179948350365604">"In carica"</string>
diff --git a/packages/SettingsLib/res/values-iw/strings.xml b/packages/SettingsLib/res/values-iw/strings.xml
index 81307f7..7c4eb7c 100644
--- a/packages/SettingsLib/res/values-iw/strings.xml
+++ b/packages/SettingsLib/res/values-iw/strings.xml
@@ -220,7 +220,8 @@
<string name="select_private_dns_configuration_title" msgid="3700456559305263922">"DNS פרטי"</string>
<string name="select_private_dns_configuration_dialog_title" msgid="9221994415765826811">"צריך לבחור במצב DNS פרטי"</string>
<string name="private_dns_mode_off" msgid="8236575187318721684">"מושבת"</string>
- <string name="private_dns_mode_opportunistic" msgid="7608409735589131766">"אופרטוניסטי"</string>
+ <!-- no translation found for private_dns_mode_opportunistic (8314986739896927399) -->
+ <skip />
<string name="private_dns_mode_provider" msgid="8354935160639360804">"שם מארח של ספק DNS פרטי"</string>
<string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"צריך להזין את שם המארח של ספק DNS"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"הצג אפשרויות עבור אישור של תצוגת WiFi"</string>
@@ -356,22 +357,41 @@
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"תכונה זו היא ניסיונית ועשויה להשפיע על הביצועים."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"נעקף על ידי <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="power_remaining_duration_only" msgid="845431008899029842">"עוד <xliff:g id="TIME">%1$s</xliff:g> בקירוב"</string>
+ <!-- no translation found for power_discharging_duration (6655472132189365839) -->
+ <skip />
<string name="power_remaining_duration_only_enhanced" msgid="5992456722677973678">"על סמך השימוש במכשיר, הסוללה תתרוקן בעוד <xliff:g id="TIME">%1$s</xliff:g>, בקירוב"</string>
- <string name="power_remaining_charging_duration_only" msgid="1421102457410268886">"<xliff:g id="TIME">%1$s</xliff:g> עד לטעינה מלאה"</string>
+ <!-- no translation found for power_discharging_duration_enhanced (5726302316642148671) -->
+ <skip />
<string name="power_remaining_duration_only_short" msgid="5329694252258605547">"נותרו <xliff:g id="TIME">%1$s</xliff:g>"</string>
+ <!-- no translation found for power_discharge_by_enhanced (8788299408879961465) -->
+ <skip />
+ <!-- no translation found for power_discharge_by_only_enhanced (7692297898877104416) -->
+ <skip />
+ <!-- no translation found for power_discharge_by (6427074755635635749) -->
+ <skip />
+ <!-- no translation found for power_discharge_by_only (5888058889261108064) -->
+ <skip />
<string name="power_remaining_less_than_duration_only" msgid="5996752448813295329">"נותרו פחות מ-<xliff:g id="THRESHOLD">%1$s</xliff:g>"</string>
- <string name="power_remaining_less_than_duration" msgid="7967078125657859046">"<xliff:g id="LEVEL">%1$s</xliff:g> - הזמן שנותר, פחות מ-<xliff:g id="THRESHOLD">%2$s</xliff:g>"</string>
- <string name="power_remaining_more_than_subtext" msgid="6846716609975752316">"<xliff:g id="LEVEL">%1$s</xliff:g>הזמן שנותר: יותר מ-<xliff:g id="TIME_REMAINING">%2$s</xliff:g>"</string>
- <string name="power_remaining_only_more_than_subtext" msgid="8884488700395194194">"הזמן שנותר: יותר מ-<xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="default" msgid="8168317165722752881">"ייתכן שהטלפון ייכבה בקרוב"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="tablet" msgid="5957064378548718872">"ייתכן שהטאבלט ייכבה בקרוב"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="device" msgid="9055596817716471373">"ייתכן שהמכשיר ייכבה בקרוב"</string>
- <string name="power_discharging_duration" msgid="2843747179907396142">"<xliff:g id="LEVEL">%1$s</xliff:g> - הזמן הנותר: בערך <xliff:g id="TIME">%2$s</xliff:g>"</string>
- <string name="power_discharging_duration_enhanced" msgid="4401782117770255046">"<xliff:g id="LEVEL">%1$s</xliff:g> - על סמך השימוש במכשיר, הסוללה תתרוקן בעוד <xliff:g id="TIME">%2$s</xliff:g>, בקירוב"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="default" msgid="7679005631124015335">"<xliff:g id="LEVEL">%1$s</xliff:g> - ייתכן שהטלפון ייכבה בקרוב"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="tablet" msgid="261050880878965621">"<xliff:g id="LEVEL">%1$s</xliff:g> - ייתכן שהטאבלט ייכבה בקרוב"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="device" msgid="2020049829798578618">"<xliff:g id="LEVEL">%1$s</xliff:g> - ייתכן שהמכשיר ייכבה בקרוב"</string>
+ <!-- no translation found for power_remaining_less_than_duration (5751885147712659423) -->
+ <skip />
+ <!-- no translation found for power_remaining_more_than_subtext (3176771815132876675) -->
+ <skip />
+ <!-- no translation found for power_remaining_only_more_than_subtext (8931654680569617380) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (1181059207608751924) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (2606370266981054691) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (2918084807716859985) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (3090926004324573908) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (7466484148515796216) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (603933521600231649) -->
+ <skip />
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
+ <string name="power_remaining_charging_duration_only" msgid="1421102457410268886">"<xliff:g id="TIME">%1$s</xliff:g> עד לטעינה מלאה"</string>
<string name="power_charging_duration" msgid="4676999980973411875">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> עד לטעינה מלאה"</string>
<string name="battery_info_status_unknown" msgid="196130600938058547">"לא ידוע"</string>
<string name="battery_info_status_charging" msgid="1705179948350365604">"טוען"</string>
diff --git a/packages/SettingsLib/res/values-ja/strings.xml b/packages/SettingsLib/res/values-ja/strings.xml
index 346a96d..c5836d6 100644
--- a/packages/SettingsLib/res/values-ja/strings.xml
+++ b/packages/SettingsLib/res/values-ja/strings.xml
@@ -220,7 +220,8 @@
<string name="select_private_dns_configuration_title" msgid="3700456559305263922">"プライベート DNS"</string>
<string name="select_private_dns_configuration_dialog_title" msgid="9221994415765826811">"プライベート DNS モードを選択"</string>
<string name="private_dns_mode_off" msgid="8236575187318721684">"OFF"</string>
- <string name="private_dns_mode_opportunistic" msgid="7608409735589131766">"日和見"</string>
+ <!-- no translation found for private_dns_mode_opportunistic (8314986739896927399) -->
+ <skip />
<string name="private_dns_mode_provider" msgid="8354935160639360804">"プライベート DNS プロバイダのホスト名"</string>
<string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"DNS プロバイダのホスト名を入力"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"ワイヤレスディスプレイ認証のオプションを表示"</string>
@@ -356,22 +357,41 @@
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"この機能は試験運用機能であり、パフォーマンスに影響することがあります。"</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"<xliff:g id="TITLE">%1$s</xliff:g>によって上書き済み"</string>
<string name="power_remaining_duration_only" msgid="845431008899029842">"あと約 <xliff:g id="TIME">%1$s</xliff:g>"</string>
+ <!-- no translation found for power_discharging_duration (6655472132189365839) -->
+ <skip />
<string name="power_remaining_duration_only_enhanced" msgid="5992456722677973678">"残り時間: 約 <xliff:g id="TIME">%1$s</xliff:g>(使用状況に基づく)"</string>
- <string name="power_remaining_charging_duration_only" msgid="1421102457410268886">"フル充電まであと <xliff:g id="TIME">%1$s</xliff:g>"</string>
+ <!-- no translation found for power_discharging_duration_enhanced (5726302316642148671) -->
+ <skip />
<string name="power_remaining_duration_only_short" msgid="5329694252258605547">"<xliff:g id="TIME">%1$s</xliff:g>(残り時間)"</string>
+ <!-- no translation found for power_discharge_by_enhanced (8788299408879961465) -->
+ <skip />
+ <!-- no translation found for power_discharge_by_only_enhanced (7692297898877104416) -->
+ <skip />
+ <!-- no translation found for power_discharge_by (6427074755635635749) -->
+ <skip />
+ <!-- no translation found for power_discharge_by_only (5888058889261108064) -->
+ <skip />
<string name="power_remaining_less_than_duration_only" msgid="5996752448813295329">"残り時間: <xliff:g id="THRESHOLD">%1$s</xliff:g>未満"</string>
- <string name="power_remaining_less_than_duration" msgid="7967078125657859046">"<xliff:g id="LEVEL">%1$s</xliff:g> - 残り時間: <xliff:g id="THRESHOLD">%2$s</xliff:g>未満"</string>
- <string name="power_remaining_more_than_subtext" msgid="6846716609975752316">"<xliff:g id="LEVEL">%1$s</xliff:g> ー 残り時間: <xliff:g id="TIME_REMAINING">%2$s</xliff:g>以上"</string>
- <string name="power_remaining_only_more_than_subtext" msgid="8884488700395194194">"残り時間: <xliff:g id="TIME_REMAINING">%1$s</xliff:g>以上"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="default" msgid="8168317165722752881">"スマートフォンの電源がもうすぐ切れます"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="tablet" msgid="5957064378548718872">"タブレットの電源がもうすぐ切れます"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="device" msgid="9055596817716471373">"端末の電源がもうすぐ切れます"</string>
- <string name="power_discharging_duration" msgid="2843747179907396142">"<xliff:g id="LEVEL">%1$s</xliff:g> - 残り約 <xliff:g id="TIME">%2$s</xliff:g>"</string>
- <string name="power_discharging_duration_enhanced" msgid="4401782117770255046">"<xliff:g id="LEVEL">%1$s</xliff:g> - 残り時間: 約 <xliff:g id="TIME">%2$s</xliff:g>(使用状況に基づく)"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="default" msgid="7679005631124015335">"<xliff:g id="LEVEL">%1$s</xliff:g> - スマートフォンの電源がもうすぐ切れます"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="tablet" msgid="261050880878965621">"<xliff:g id="LEVEL">%1$s</xliff:g> - タブレットの電源がもうすぐ切れます"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="device" msgid="2020049829798578618">"<xliff:g id="LEVEL">%1$s</xliff:g> - 端末の電源がもうすぐ切れます"</string>
+ <!-- no translation found for power_remaining_less_than_duration (5751885147712659423) -->
+ <skip />
+ <!-- no translation found for power_remaining_more_than_subtext (3176771815132876675) -->
+ <skip />
+ <!-- no translation found for power_remaining_only_more_than_subtext (8931654680569617380) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (1181059207608751924) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (2606370266981054691) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (2918084807716859985) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (3090926004324573908) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (7466484148515796216) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (603933521600231649) -->
+ <skip />
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
+ <string name="power_remaining_charging_duration_only" msgid="1421102457410268886">"フル充電まであと <xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="4676999980973411875">"<xliff:g id="LEVEL">%1$s</xliff:g> - フル充電まで <xliff:g id="TIME">%2$s</xliff:g>"</string>
<string name="battery_info_status_unknown" msgid="196130600938058547">"不明"</string>
<string name="battery_info_status_charging" msgid="1705179948350365604">"充電中"</string>
diff --git a/packages/SettingsLib/res/values-ka/strings.xml b/packages/SettingsLib/res/values-ka/strings.xml
index db03069..caf15cc 100644
--- a/packages/SettingsLib/res/values-ka/strings.xml
+++ b/packages/SettingsLib/res/values-ka/strings.xml
@@ -220,7 +220,8 @@
<string name="select_private_dns_configuration_title" msgid="3700456559305263922">"პირადი DNS"</string>
<string name="select_private_dns_configuration_dialog_title" msgid="9221994415765826811">"აირჩიეთ პირადი DNS რეჟიმი"</string>
<string name="private_dns_mode_off" msgid="8236575187318721684">"გამორთული"</string>
- <string name="private_dns_mode_opportunistic" msgid="7608409735589131766">"ოპორტუნისტული"</string>
+ <!-- no translation found for private_dns_mode_opportunistic (8314986739896927399) -->
+ <skip />
<string name="private_dns_mode_provider" msgid="8354935160639360804">"პირადი DNS პროვაიდერის სერვერის სახელი"</string>
<string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"შეიყვანეთ DNS პროვაიდერის სერვერის სახელი"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"უსადენო ეკრანის სერტიფიცირების ვარიანტების ჩვენება"</string>
@@ -356,22 +357,41 @@
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"ეს ფუნქცია საცდელია და შეიძლება გავლენა იქონიოს ფუნქციონალობაზე."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"უკუგებულია <xliff:g id="TITLE">%1$s</xliff:g>-ის მიერ"</string>
<string name="power_remaining_duration_only" msgid="845431008899029842">"დარჩა დაახლოებით <xliff:g id="TIME">%1$s</xliff:g>"</string>
+ <!-- no translation found for power_discharging_duration (6655472132189365839) -->
+ <skip />
<string name="power_remaining_duration_only_enhanced" msgid="5992456722677973678">"დარჩა დაახლოებით <xliff:g id="TIME">%1$s</xliff:g>, ბატარეის მოხმარების გათვალისწინებით"</string>
- <string name="power_remaining_charging_duration_only" msgid="1421102457410268886">"სრულ დატენვამდე დარჩენილია <xliff:g id="TIME">%1$s</xliff:g>"</string>
+ <!-- no translation found for power_discharging_duration_enhanced (5726302316642148671) -->
+ <skip />
<string name="power_remaining_duration_only_short" msgid="5329694252258605547">"დარჩენილია <xliff:g id="TIME">%1$s</xliff:g>"</string>
+ <!-- no translation found for power_discharge_by_enhanced (8788299408879961465) -->
+ <skip />
+ <!-- no translation found for power_discharge_by_only_enhanced (7692297898877104416) -->
+ <skip />
+ <!-- no translation found for power_discharge_by (6427074755635635749) -->
+ <skip />
+ <!-- no translation found for power_discharge_by_only (5888058889261108064) -->
+ <skip />
<string name="power_remaining_less_than_duration_only" msgid="5996752448813295329">"დარჩენილია <xliff:g id="THRESHOLD">%1$s</xliff:g>-ზე ნაკლები"</string>
- <string name="power_remaining_less_than_duration" msgid="7967078125657859046">"<xliff:g id="LEVEL">%1$s</xliff:g> — დარჩენილია <xliff:g id="THRESHOLD">%2$s</xliff:g>-ზე ნაკლები"</string>
- <string name="power_remaining_more_than_subtext" msgid="6846716609975752316">"<xliff:g id="LEVEL">%1$s</xliff:g>დარჩენილია <xliff:g id="TIME_REMAINING">%2$s</xliff:g>-ზე მეტი"</string>
- <string name="power_remaining_only_more_than_subtext" msgid="8884488700395194194">"დარჩენილია <xliff:g id="TIME_REMAINING">%1$s</xliff:g>-ზე მეტი"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="default" msgid="8168317165722752881">"ტელეფონი შეიძლება მალე გაითიშოს"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="tablet" msgid="5957064378548718872">"ტაბლეტი შეიძლება მალე გაითიშოს"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="device" msgid="9055596817716471373">"მოწყობილობა შეიძლება მალე გაითიშოს"</string>
- <string name="power_discharging_duration" msgid="2843747179907396142">"<xliff:g id="LEVEL">%1$s</xliff:g> — დარჩა დაახლოებით <xliff:g id="TIME">%2$s</xliff:g>"</string>
- <string name="power_discharging_duration_enhanced" msgid="4401782117770255046">"<xliff:g id="LEVEL">%1$s</xliff:g> — დარჩა დაახლოებით <xliff:g id="TIME">%2$s</xliff:g>, ბატარეის მოხმარების გათვალისწინებით"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="default" msgid="7679005631124015335">"<xliff:g id="LEVEL">%1$s</xliff:g> — ტელეფონი შეიძლება მალე გაითიშოს"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="tablet" msgid="261050880878965621">"<xliff:g id="LEVEL">%1$s</xliff:g> — ტაბლეტი შეიძლება მალე გაითიშოს"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="device" msgid="2020049829798578618">"<xliff:g id="LEVEL">%1$s</xliff:g> — მოწყობილობა შეიძლება მალე გაითიშოს"</string>
+ <!-- no translation found for power_remaining_less_than_duration (5751885147712659423) -->
+ <skip />
+ <!-- no translation found for power_remaining_more_than_subtext (3176771815132876675) -->
+ <skip />
+ <!-- no translation found for power_remaining_only_more_than_subtext (8931654680569617380) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (1181059207608751924) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (2606370266981054691) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (2918084807716859985) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (3090926004324573908) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (7466484148515796216) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (603933521600231649) -->
+ <skip />
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
+ <string name="power_remaining_charging_duration_only" msgid="1421102457410268886">"სრულ დატენვამდე დარჩენილია <xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="4676999980973411875">"<xliff:g id="LEVEL">%1$s</xliff:g> — სრულ დატენვამდე დარჩა <xliff:g id="TIME">%2$s</xliff:g>"</string>
<string name="battery_info_status_unknown" msgid="196130600938058547">"უცნობი"</string>
<string name="battery_info_status_charging" msgid="1705179948350365604">"იტენება"</string>
diff --git a/packages/SettingsLib/res/values-kk/strings.xml b/packages/SettingsLib/res/values-kk/strings.xml
index acd7d87..08733ae 100644
--- a/packages/SettingsLib/res/values-kk/strings.xml
+++ b/packages/SettingsLib/res/values-kk/strings.xml
@@ -220,7 +220,8 @@
<string name="select_private_dns_configuration_title" msgid="3700456559305263922">"Жеке DNS"</string>
<string name="select_private_dns_configuration_dialog_title" msgid="9221994415765826811">"Жеке DNS режимін таңдаңыз"</string>
<string name="private_dns_mode_off" msgid="8236575187318721684">"Өшіру"</string>
- <string name="private_dns_mode_opportunistic" msgid="7608409735589131766">"Кездейсоқ"</string>
+ <!-- no translation found for private_dns_mode_opportunistic (8314986739896927399) -->
+ <skip />
<string name="private_dns_mode_provider" msgid="8354935160639360804">"Жеке DNS провайдерінің хост атауы"</string>
<string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"DNS провайдерінің хост атауын енгізіңіз"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Сымсыз дисплей растау опцияларын көрсету"</string>
@@ -356,22 +357,41 @@
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Бұл мүмкіндік эксперименттік болып табылады және өнімділікке әсер етуі мүмкін."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"<xliff:g id="TITLE">%1$s</xliff:g> үстінен басқан"</string>
<string name="power_remaining_duration_only" msgid="845431008899029842">"Қалған <xliff:g id="TIME">%1$s</xliff:g> туралы"</string>
+ <!-- no translation found for power_discharging_duration (6655472132189365839) -->
+ <skip />
<string name="power_remaining_duration_only_enhanced" msgid="5992456722677973678">"Пайдалану негізінде шамамен <xliff:g id="TIME">%1$s</xliff:g> қалды"</string>
- <string name="power_remaining_charging_duration_only" msgid="1421102457410268886">"Толық зарядқа <xliff:g id="TIME">%1$s</xliff:g> қалды"</string>
+ <!-- no translation found for power_discharging_duration_enhanced (5726302316642148671) -->
+ <skip />
<string name="power_remaining_duration_only_short" msgid="5329694252258605547">"<xliff:g id="TIME">%1$s</xliff:g> қалды"</string>
+ <!-- no translation found for power_discharge_by_enhanced (8788299408879961465) -->
+ <skip />
+ <!-- no translation found for power_discharge_by_only_enhanced (7692297898877104416) -->
+ <skip />
+ <!-- no translation found for power_discharge_by (6427074755635635749) -->
+ <skip />
+ <!-- no translation found for power_discharge_by_only (5888058889261108064) -->
+ <skip />
<string name="power_remaining_less_than_duration_only" msgid="5996752448813295329">"<xliff:g id="THRESHOLD">%1$s</xliff:g> шамасынан аз қалды"</string>
- <string name="power_remaining_less_than_duration" msgid="7967078125657859046">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="THRESHOLD">%2$s</xliff:g> шамасынан аз қалды"</string>
- <string name="power_remaining_more_than_subtext" msgid="6846716609975752316">"<xliff:g id="LEVEL">%1$s</xliff:g><xliff:g id="TIME_REMAINING">%2$s</xliff:g> үстінде қалды"</string>
- <string name="power_remaining_only_more_than_subtext" msgid="8884488700395194194">"<xliff:g id="TIME_REMAINING">%1$s</xliff:g> үстінде қалды"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="default" msgid="8168317165722752881">"телефон көп ұзамай өшуі мүмкін"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="tablet" msgid="5957064378548718872">"планшет көп ұзамай өшуі мүмкін"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="device" msgid="9055596817716471373">"құрылғы көп ұзамай өшуі мүмкін"</string>
- <string name="power_discharging_duration" msgid="2843747179907396142">"<xliff:g id="LEVEL">%1$s</xliff:g> – шамамен <xliff:g id="TIME">%2$s</xliff:g> қалды"</string>
- <string name="power_discharging_duration_enhanced" msgid="4401782117770255046">"<xliff:g id="LEVEL">%1$s</xliff:g> - пайдалану негізінде шамамен <xliff:g id="TIME">%2$s</xliff:g> қалды"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="default" msgid="7679005631124015335">"<xliff:g id="LEVEL">%1$s</xliff:g> – телефон көп ұзамай өшуі мүмкін"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="tablet" msgid="261050880878965621">"<xliff:g id="LEVEL">%1$s</xliff:g> – планшет көп ұзамай өшуі мүмкін"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="device" msgid="2020049829798578618">"<xliff:g id="LEVEL">%1$s</xliff:g> – құрылғы көп ұзамай өшуі мүмкін"</string>
+ <!-- no translation found for power_remaining_less_than_duration (5751885147712659423) -->
+ <skip />
+ <!-- no translation found for power_remaining_more_than_subtext (3176771815132876675) -->
+ <skip />
+ <!-- no translation found for power_remaining_only_more_than_subtext (8931654680569617380) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (1181059207608751924) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (2606370266981054691) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (2918084807716859985) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (3090926004324573908) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (7466484148515796216) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (603933521600231649) -->
+ <skip />
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
+ <string name="power_remaining_charging_duration_only" msgid="1421102457410268886">"Толық зарядқа <xliff:g id="TIME">%1$s</xliff:g> қалды"</string>
<string name="power_charging_duration" msgid="4676999980973411875">"<xliff:g id="LEVEL">%1$s</xliff:g> – толық зарядталғанға дейін <xliff:g id="TIME">%2$s</xliff:g>"</string>
<string name="battery_info_status_unknown" msgid="196130600938058547">"Белгісіз"</string>
<string name="battery_info_status_charging" msgid="1705179948350365604">"Зарядталуда"</string>
diff --git a/packages/SettingsLib/res/values-km/strings.xml b/packages/SettingsLib/res/values-km/strings.xml
index 3da3758..57022a8 100644
--- a/packages/SettingsLib/res/values-km/strings.xml
+++ b/packages/SettingsLib/res/values-km/strings.xml
@@ -220,7 +220,8 @@
<string name="select_private_dns_configuration_title" msgid="3700456559305263922">"DNS ឯកជន"</string>
<string name="select_private_dns_configuration_dialog_title" msgid="9221994415765826811">"ជ្រើសរើសមុខងារ DNS ឯកជន"</string>
<string name="private_dns_mode_off" msgid="8236575187318721684">"បិទ"</string>
- <string name="private_dns_mode_opportunistic" msgid="7608409735589131766">"Opportunistic"</string>
+ <!-- no translation found for private_dns_mode_opportunistic (8314986739896927399) -->
+ <skip />
<string name="private_dns_mode_provider" msgid="8354935160639360804">"ឈ្មោះម៉ាស៊ីនក្រុមហ៊ុនផ្ដល់សេវា DNS ឯកជន"</string>
<string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"បញ្ចូលឈ្មោះម៉ាស៊ីនរបស់ក្រុមហ៊ុនផ្ដល់សេវា DNS"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"បង្ហាញជម្រើសសម្រាប់វិញ្ញាបនបត្របង្ហាញឥតខ្សែ"</string>
@@ -356,22 +357,41 @@
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"មុខងារនេះគឺជាការពិសោធន៍ ហើយអាចប៉ះពាល់ដំណើរការ។"</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"បដិសេធដោយ <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="power_remaining_duration_only" msgid="845431008899029842">"សល់ប្រហែល <xliff:g id="TIME">%1$s</xliff:g>"</string>
+ <!-- no translation found for power_discharging_duration (6655472132189365839) -->
+ <skip />
<string name="power_remaining_duration_only_enhanced" msgid="5992456722677973678">"សល់ប្រហែល <xliff:g id="TIME">%1$s</xliff:g> ទៀតផ្អែកលើការប្រើប្រាស់របស់អ្នក"</string>
- <string name="power_remaining_charging_duration_only" msgid="1421102457410268886">"សល់ <xliff:g id="TIME">%1$s</xliff:g> ទើបសាកថ្មពេញ"</string>
+ <!-- no translation found for power_discharging_duration_enhanced (5726302316642148671) -->
+ <skip />
<string name="power_remaining_duration_only_short" msgid="5329694252258605547">"នៅសល់ <xliff:g id="TIME">%1$s</xliff:g>"</string>
+ <!-- no translation found for power_discharge_by_enhanced (8788299408879961465) -->
+ <skip />
+ <!-- no translation found for power_discharge_by_only_enhanced (7692297898877104416) -->
+ <skip />
+ <!-- no translation found for power_discharge_by (6427074755635635749) -->
+ <skip />
+ <!-- no translation found for power_discharge_by_only (5888058889261108064) -->
+ <skip />
<string name="power_remaining_less_than_duration_only" msgid="5996752448813295329">"នៅសល់តិចជាង <xliff:g id="THRESHOLD">%1$s</xliff:g>"</string>
- <string name="power_remaining_less_than_duration" msgid="7967078125657859046">"<xliff:g id="LEVEL">%1$s</xliff:g>៖ នៅសល់តិចជាង <xliff:g id="THRESHOLD">%2$s</xliff:g>"</string>
- <string name="power_remaining_more_than_subtext" msgid="6846716609975752316">"<xliff:g id="LEVEL">%1$s</xliff:g>៖ នៅសល់ច្រើនជាង <xliff:g id="TIME_REMAINING">%2$s</xliff:g>"</string>
- <string name="power_remaining_only_more_than_subtext" msgid="8884488700395194194">"នៅសល់ច្រើនជាង <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="default" msgid="8168317165722752881">"ទូរសព្ទអាចនឹងបិទក្នុងពេលបន្តិចទៀត"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="tablet" msgid="5957064378548718872">"ថេប្លេតអាចនឹងបិទក្នុងពេលបន្តិចទៀត"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="device" msgid="9055596817716471373">"ឧបករណ៍អាចនឹងបិទក្នុងពេលបន្តិចទៀត"</string>
- <string name="power_discharging_duration" msgid="2843747179907396142">"<xliff:g id="LEVEL">%1$s</xliff:g> - សល់ប្រហែល <xliff:g id="TIME">%2$s</xliff:g>"</string>
- <string name="power_discharging_duration_enhanced" msgid="4401782117770255046">"<xliff:g id="LEVEL">%1$s</xliff:g> - សល់ប្រហែល <xliff:g id="TIME">%2$s</xliff:g> ទៀតផ្អែកលើការប្រើប្រាស់របស់អ្នក"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="default" msgid="7679005631124015335">"<xliff:g id="LEVEL">%1$s</xliff:g>៖ ទូរសព្ទអាចនឹងបិទក្នុងពេលបន្តិចទៀត"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="tablet" msgid="261050880878965621">"<xliff:g id="LEVEL">%1$s</xliff:g>៖ ថេប្លេតអាចនឹងបិទក្នុងពេលបន្តិចទៀត"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="device" msgid="2020049829798578618">"<xliff:g id="LEVEL">%1$s</xliff:g>៖ ឧបករណ៍អាចនឹងបិទក្នុងពេលបន្តិចទៀត"</string>
+ <!-- no translation found for power_remaining_less_than_duration (5751885147712659423) -->
+ <skip />
+ <!-- no translation found for power_remaining_more_than_subtext (3176771815132876675) -->
+ <skip />
+ <!-- no translation found for power_remaining_only_more_than_subtext (8931654680569617380) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (1181059207608751924) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (2606370266981054691) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (2918084807716859985) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (3090926004324573908) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (7466484148515796216) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (603933521600231649) -->
+ <skip />
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
+ <string name="power_remaining_charging_duration_only" msgid="1421102457410268886">"សល់ <xliff:g id="TIME">%1$s</xliff:g> ទើបសាកថ្មពេញ"</string>
<string name="power_charging_duration" msgid="4676999980973411875">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> រហូតដល់សាកពេញ"</string>
<string name="battery_info_status_unknown" msgid="196130600938058547">"មិនស្គាល់"</string>
<string name="battery_info_status_charging" msgid="1705179948350365604">"កំពុងបញ្ចូលថ្ម"</string>
diff --git a/packages/SettingsLib/res/values-kn/strings.xml b/packages/SettingsLib/res/values-kn/strings.xml
index 9f55983..8a5b251 100644
--- a/packages/SettingsLib/res/values-kn/strings.xml
+++ b/packages/SettingsLib/res/values-kn/strings.xml
@@ -220,7 +220,8 @@
<string name="select_private_dns_configuration_title" msgid="3700456559305263922">"ಖಾಸಗಿ DNS"</string>
<string name="select_private_dns_configuration_dialog_title" msgid="9221994415765826811">"ಖಾಸಗಿ DNS ಮೋಡ್ ಆಯ್ಕೆಮಾಡಿ"</string>
<string name="private_dns_mode_off" msgid="8236575187318721684">"ಆಫ್"</string>
- <string name="private_dns_mode_opportunistic" msgid="7608409735589131766">"ಅವಕಾಶವಾದಿ"</string>
+ <!-- no translation found for private_dns_mode_opportunistic (8314986739896927399) -->
+ <skip />
<string name="private_dns_mode_provider" msgid="8354935160639360804">"ಖಾಸಗಿ DNS ಪೂರೈಕೆದಾರರ ಹೋಸ್ಟ್ಹೆಸರು"</string>
<string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"DNS ಪೂರೈಕೆದಾರರ ಹೋಸ್ಟ್ಹೆಸರನ್ನು ನಮೂದಿಸಿ"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"ವೈರ್ಲೆಸ್ ಪ್ರದರ್ಶನ ಪ್ರಮಾಣೀಕರಣಕ್ಕಾಗಿ ಆಯ್ಕೆಗಳನ್ನು ತೋರಿಸು"</string>
@@ -356,22 +357,41 @@
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"ಇದು ಪ್ರಾಯೋಗಿಕ ವೈಶಿಷ್ಟ್ಯವಾಗಿದೆ. ಕಾರ್ಯಕ್ಷಮತೆ ಮೇಲೆ ಪರಿಣಾಮ ಬೀರಬಹುದು."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"<xliff:g id="TITLE">%1$s</xliff:g> ಮೂಲಕ ಅತಿಕ್ರಮಿಸುತ್ತದೆ"</string>
<string name="power_remaining_duration_only" msgid="845431008899029842">"ಸುಮಾರು <xliff:g id="TIME">%1$s</xliff:g> ಬಾಕಿಯಿದೆ"</string>
+ <!-- no translation found for power_discharging_duration (6655472132189365839) -->
+ <skip />
<string name="power_remaining_duration_only_enhanced" msgid="5992456722677973678">"ನಿಮ್ಮ ಬಳಕೆಯ ಆಧಾರದ ಮೇಲೆ ಸುಮಾರು <xliff:g id="TIME">%1$s</xliff:g> ಉಳಿದಿದೆ"</string>
- <string name="power_remaining_charging_duration_only" msgid="1421102457410268886">"ಸಂಪೂರ್ಣ ಚಾರ್ಜ್ ಆಗಲು <xliff:g id="TIME">%1$s</xliff:g>"</string>
+ <!-- no translation found for power_discharging_duration_enhanced (5726302316642148671) -->
+ <skip />
<string name="power_remaining_duration_only_short" msgid="5329694252258605547">"<xliff:g id="TIME">%1$s</xliff:g> ಉಳಿದಿದೆ"</string>
+ <!-- no translation found for power_discharge_by_enhanced (8788299408879961465) -->
+ <skip />
+ <!-- no translation found for power_discharge_by_only_enhanced (7692297898877104416) -->
+ <skip />
+ <!-- no translation found for power_discharge_by (6427074755635635749) -->
+ <skip />
+ <!-- no translation found for power_discharge_by_only (5888058889261108064) -->
+ <skip />
<string name="power_remaining_less_than_duration_only" msgid="5996752448813295329">"<xliff:g id="THRESHOLD">%1$s</xliff:g> ನಿಮಿಷಕ್ಕಿಂತ ಕಡಿಮೆ ಸಮಯ ಉಳಿದಿದೆ"</string>
- <string name="power_remaining_less_than_duration" msgid="7967078125657859046">"<xliff:g id="LEVEL">%1$s</xliff:g> - ರಷ್ಟು <xliff:g id="THRESHOLD">%2$s</xliff:g> ಕ್ಕಿಂತ ಕಡಿಮೆ ಸಮಯ ಬಾಕಿ ಉಳಿದಿದೆ"</string>
- <string name="power_remaining_more_than_subtext" msgid="6846716609975752316">"<xliff:g id="LEVEL">%1$s</xliff:g> ರಷ್ಟು <xliff:g id="TIME_REMAINING">%2$s</xliff:g> ಕ್ಕಿಂತ ಹೆಚ್ಚು ಸಮಯ ಬಾಕಿ ಉಳಿದಿದೆ"</string>
- <string name="power_remaining_only_more_than_subtext" msgid="8884488700395194194">"<xliff:g id="TIME_REMAINING">%1$s</xliff:g> ಕ್ಕಿಂತ ಹೆಚ್ಚು ಸಮಯ ಉಳಿದಿದೆ"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="default" msgid="8168317165722752881">"ಫೋನ್ ಶೀಘ್ರದಲ್ಲೇ ಶಟ್ ಡೌನ್ ಆಗಬಹುದು"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="tablet" msgid="5957064378548718872">"ಟ್ಯಾಬ್ಲೆಟ್ ಶೀಘ್ರದಲ್ಲೇ ಶಟ್ ಡೌನ್ ಆಗಬಹುದು"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="device" msgid="9055596817716471373">"ಸಾಧನವು ಶೀಘ್ರದಲ್ಲೇ ಶಟ್ ಡೌನ್ ಆಗಬಹುದು"</string>
- <string name="power_discharging_duration" msgid="2843747179907396142">"<xliff:g id="LEVEL">%1$s</xliff:g> - ಸುಮಾರು <xliff:g id="TIME">%2$s</xliff:g> ಬಾಕಿಯಿದೆ"</string>
- <string name="power_discharging_duration_enhanced" msgid="4401782117770255046">"<xliff:g id="LEVEL">%1$s</xliff:g> - ನಿಮ್ಮ ಬಳಕೆಯ ಆಧಾರದ ಮೇಲೆ <xliff:g id="TIME">%2$s</xliff:g> ಉಳಿದಿದೆ"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="default" msgid="7679005631124015335">"<xliff:g id="LEVEL">%1$s</xliff:g> - ಫೋನ್ ಶೀಘ್ರದಲ್ಲೇ ಶಟ್ ಡೌನ್ ಆಗಬಹುದು"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="tablet" msgid="261050880878965621">"<xliff:g id="LEVEL">%1$s</xliff:g> - ಟ್ಯಾಬ್ಲೆಟ್ ಶೀಘ್ರದಲ್ಲೇ ಶಟ್ ಡೌನ್ ಆಗಬಹುದು"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="device" msgid="2020049829798578618">"<xliff:g id="LEVEL">%1$s</xliff:g> - ಸಾಧನವು ಶೀಘ್ರದಲ್ಲೇ ಶಟ್ ಡೌನ್ ಆಗಬಹುದು"</string>
+ <!-- no translation found for power_remaining_less_than_duration (5751885147712659423) -->
+ <skip />
+ <!-- no translation found for power_remaining_more_than_subtext (3176771815132876675) -->
+ <skip />
+ <!-- no translation found for power_remaining_only_more_than_subtext (8931654680569617380) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (1181059207608751924) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (2606370266981054691) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (2918084807716859985) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (3090926004324573908) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (7466484148515796216) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (603933521600231649) -->
+ <skip />
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
+ <string name="power_remaining_charging_duration_only" msgid="1421102457410268886">"ಸಂಪೂರ್ಣ ಚಾರ್ಜ್ ಆಗಲು <xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="4676999980973411875">"<xliff:g id="LEVEL">%1$s</xliff:g> - ಸಂಪೂರ್ಣ ಚಾರ್ಜ್ ಆಗಲು <xliff:g id="TIME">%2$s</xliff:g>"</string>
<string name="battery_info_status_unknown" msgid="196130600938058547">"ಅಪರಿಚಿತ"</string>
<string name="battery_info_status_charging" msgid="1705179948350365604">"ಚಾರ್ಜ್ ಆಗುತ್ತಿದೆ"</string>
diff --git a/packages/SettingsLib/res/values-ko/strings.xml b/packages/SettingsLib/res/values-ko/strings.xml
index 35a2867..af1859a 100644
--- a/packages/SettingsLib/res/values-ko/strings.xml
+++ b/packages/SettingsLib/res/values-ko/strings.xml
@@ -220,7 +220,8 @@
<string name="select_private_dns_configuration_title" msgid="3700456559305263922">"비공개 DNS"</string>
<string name="select_private_dns_configuration_dialog_title" msgid="9221994415765826811">"비공개 DNS 모드 선택"</string>
<string name="private_dns_mode_off" msgid="8236575187318721684">"사용 안함"</string>
- <string name="private_dns_mode_opportunistic" msgid="7608409735589131766">"기회주의적"</string>
+ <!-- no translation found for private_dns_mode_opportunistic (8314986739896927399) -->
+ <skip />
<string name="private_dns_mode_provider" msgid="8354935160639360804">"비공개 DNS 제공업체 호스트 이름"</string>
<string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"DNS 제공업체의 호스트 이름 입력"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"무선 디스플레이 인증서 옵션 표시"</string>
@@ -356,22 +357,41 @@
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"실험실 기능이며 성능에 영향을 줄 수 있습니다."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"<xliff:g id="TITLE">%1$s</xliff:g> 우선 적용됨"</string>
<string name="power_remaining_duration_only" msgid="845431008899029842">"약 <xliff:g id="TIME">%1$s</xliff:g> 남음"</string>
+ <!-- no translation found for power_discharging_duration (6655472132189365839) -->
+ <skip />
<string name="power_remaining_duration_only_enhanced" msgid="5992456722677973678">"내 사용량을 기준으로 약 <xliff:g id="TIME">%1$s</xliff:g> 남음"</string>
- <string name="power_remaining_charging_duration_only" msgid="1421102457410268886">"충전 완료까지 <xliff:g id="TIME">%1$s</xliff:g> 남음"</string>
+ <!-- no translation found for power_discharging_duration_enhanced (5726302316642148671) -->
+ <skip />
<string name="power_remaining_duration_only_short" msgid="5329694252258605547">"<xliff:g id="TIME">%1$s</xliff:g> 남음"</string>
+ <!-- no translation found for power_discharge_by_enhanced (8788299408879961465) -->
+ <skip />
+ <!-- no translation found for power_discharge_by_only_enhanced (7692297898877104416) -->
+ <skip />
+ <!-- no translation found for power_discharge_by (6427074755635635749) -->
+ <skip />
+ <!-- no translation found for power_discharge_by_only (5888058889261108064) -->
+ <skip />
<string name="power_remaining_less_than_duration_only" msgid="5996752448813295329">"<xliff:g id="THRESHOLD">%1$s</xliff:g> 미만 남음"</string>
- <string name="power_remaining_less_than_duration" msgid="7967078125657859046">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="THRESHOLD">%2$s</xliff:g> 미만 남음"</string>
- <string name="power_remaining_more_than_subtext" msgid="6846716609975752316">"<xliff:g id="LEVEL">%1$s</xliff:g><xliff:g id="TIME_REMAINING">%2$s</xliff:g> 이상 남음"</string>
- <string name="power_remaining_only_more_than_subtext" msgid="8884488700395194194">"<xliff:g id="TIME_REMAINING">%1$s</xliff:g> 이상 남음"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="default" msgid="8168317165722752881">"휴대전화가 곧 종료될 수 있음"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="tablet" msgid="5957064378548718872">"태블릿이 곧 종료될 수 있음"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="device" msgid="9055596817716471373">"기기가 곧 종료될 수 있음"</string>
- <string name="power_discharging_duration" msgid="2843747179907396142">"<xliff:g id="LEVEL">%1$s</xliff:g> - 약 <xliff:g id="TIME">%2$s</xliff:g> 남음"</string>
- <string name="power_discharging_duration_enhanced" msgid="4401782117770255046">"<xliff:g id="LEVEL">%1$s</xliff:g> - 내 사용량을 기준으로 약 <xliff:g id="TIME">%2$s</xliff:g> 남음"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="default" msgid="7679005631124015335">"<xliff:g id="LEVEL">%1$s</xliff:g> - 휴대전화가 곧 종료될 수 있음"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="tablet" msgid="261050880878965621">"<xliff:g id="LEVEL">%1$s</xliff:g> - 태블릿이 곧 종료될 수 있음"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="device" msgid="2020049829798578618">"<xliff:g id="LEVEL">%1$s</xliff:g> - 기기가 곧 종료될 수 있음"</string>
+ <!-- no translation found for power_remaining_less_than_duration (5751885147712659423) -->
+ <skip />
+ <!-- no translation found for power_remaining_more_than_subtext (3176771815132876675) -->
+ <skip />
+ <!-- no translation found for power_remaining_only_more_than_subtext (8931654680569617380) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (1181059207608751924) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (2606370266981054691) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (2918084807716859985) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (3090926004324573908) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (7466484148515796216) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (603933521600231649) -->
+ <skip />
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
+ <string name="power_remaining_charging_duration_only" msgid="1421102457410268886">"충전 완료까지 <xliff:g id="TIME">%1$s</xliff:g> 남음"</string>
<string name="power_charging_duration" msgid="4676999980973411875">"<xliff:g id="LEVEL">%1$s</xliff:g> - 충전 완료까지 <xliff:g id="TIME">%2$s</xliff:g> 남음"</string>
<string name="battery_info_status_unknown" msgid="196130600938058547">"알 수 없음"</string>
<string name="battery_info_status_charging" msgid="1705179948350365604">"충전 중"</string>
diff --git a/packages/SettingsLib/res/values-ky/strings.xml b/packages/SettingsLib/res/values-ky/strings.xml
index c1f73cc..baf2753 100644
--- a/packages/SettingsLib/res/values-ky/strings.xml
+++ b/packages/SettingsLib/res/values-ky/strings.xml
@@ -220,7 +220,8 @@
<string name="select_private_dns_configuration_title" msgid="3700456559305263922">"Купуя DNS"</string>
<string name="select_private_dns_configuration_dialog_title" msgid="9221994415765826811">"Купуя DNS режимин тандаңыз"</string>
<string name="private_dns_mode_off" msgid="8236575187318721684">"Өчүк"</string>
- <string name="private_dns_mode_opportunistic" msgid="7608409735589131766">"Ийкемдүү"</string>
+ <!-- no translation found for private_dns_mode_opportunistic (8314986739896927399) -->
+ <skip />
<string name="private_dns_mode_provider" msgid="8354935160639360804">"Купуя DNS түйүндүн аталышы"</string>
<string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"DNS түйүндүн аталышын киргизиңиз"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Зымсыз дисплейди сертификатто мүмкүнчүлүктөрүн көргөзүү"</string>
@@ -356,22 +357,41 @@
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Бул сынамык мүмкүнчүлүк болгондуктан, түзмөктүн иштешине таасир этиши мүмкүн."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"<xliff:g id="TITLE">%1$s</xliff:g> менен алмаштырылган"</string>
<string name="power_remaining_duration_only" msgid="845431008899029842">"Батарея түгөнгөнгө чейин калган убакыт: <xliff:g id="TIME">%1$s</xliff:g>"</string>
+ <!-- no translation found for power_discharging_duration (6655472132189365839) -->
+ <skip />
<string name="power_remaining_duration_only_enhanced" msgid="5992456722677973678">"Колдонушуңузга караганда болжол менен <xliff:g id="TIME">%1$s</xliff:g> калды"</string>
- <string name="power_remaining_charging_duration_only" msgid="1421102457410268886">"Батарея толгонго чейин калган убакыт: <xliff:g id="TIME">%1$s</xliff:g>"</string>
+ <!-- no translation found for power_discharging_duration_enhanced (5726302316642148671) -->
+ <skip />
<string name="power_remaining_duration_only_short" msgid="5329694252258605547">"<xliff:g id="TIME">%1$s</xliff:g> калды"</string>
+ <!-- no translation found for power_discharge_by_enhanced (8788299408879961465) -->
+ <skip />
+ <!-- no translation found for power_discharge_by_only_enhanced (7692297898877104416) -->
+ <skip />
+ <!-- no translation found for power_discharge_by (6427074755635635749) -->
+ <skip />
+ <!-- no translation found for power_discharge_by_only (5888058889261108064) -->
+ <skip />
<string name="power_remaining_less_than_duration_only" msgid="5996752448813295329">"<xliff:g id="THRESHOLD">%1$s</xliff:g> жетпеген убакыт калды"</string>
- <string name="power_remaining_less_than_duration" msgid="7967078125657859046">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="THRESHOLD">%2$s</xliff:g> жетпеген убакыт калды"</string>
- <string name="power_remaining_more_than_subtext" msgid="6846716609975752316">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME_REMAINING">%2$s</xliff:g> көп убакыт калды"</string>
- <string name="power_remaining_only_more_than_subtext" msgid="8884488700395194194">"<xliff:g id="TIME_REMAINING">%1$s</xliff:g> көп убакыт калды"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="default" msgid="8168317165722752881">"телефон бир аздан кийин өчүп калышы мүмкүн"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="tablet" msgid="5957064378548718872">"планшет бир аздан кийин өчүп калышы мүмкүн"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="device" msgid="9055596817716471373">"түзмөк бир аздан кийин өчүп калышы мүмкүн"</string>
- <string name="power_discharging_duration" msgid="2843747179907396142">"<xliff:g id="LEVEL">%1$s</xliff:g> – болжол менен <xliff:g id="TIME">%2$s</xliff:g> калды"</string>
- <string name="power_discharging_duration_enhanced" msgid="4401782117770255046">"<xliff:g id="LEVEL">%1$s</xliff:g> - колдонушуңузга караганда болжол менен <xliff:g id="TIME">%2$s</xliff:g> калды"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="default" msgid="7679005631124015335">"<xliff:g id="LEVEL">%1$s</xliff:g> – телефон бир аздан кийин өчүп калышы мүмкүн"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="tablet" msgid="261050880878965621">"<xliff:g id="LEVEL">%1$s</xliff:g> – планшет бир аздан кийин өчүп калышы мүмкүн"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="device" msgid="2020049829798578618">"<xliff:g id="LEVEL">%1$s</xliff:g> – түзмөк бир аздан кийин өчүп калышы мүмкүн"</string>
+ <!-- no translation found for power_remaining_less_than_duration (5751885147712659423) -->
+ <skip />
+ <!-- no translation found for power_remaining_more_than_subtext (3176771815132876675) -->
+ <skip />
+ <!-- no translation found for power_remaining_only_more_than_subtext (8931654680569617380) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (1181059207608751924) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (2606370266981054691) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (2918084807716859985) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (3090926004324573908) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (7466484148515796216) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (603933521600231649) -->
+ <skip />
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
+ <string name="power_remaining_charging_duration_only" msgid="1421102457410268886">"Батарея толгонго чейин калган убакыт: <xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="4676999980973411875">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> кийин толук кубатталат"</string>
<string name="battery_info_status_unknown" msgid="196130600938058547">"Белгисиз"</string>
<string name="battery_info_status_charging" msgid="1705179948350365604">"Кубатталууда"</string>
diff --git a/packages/SettingsLib/res/values-lo/strings.xml b/packages/SettingsLib/res/values-lo/strings.xml
index a5c8d56..5f673f2b 100644
--- a/packages/SettingsLib/res/values-lo/strings.xml
+++ b/packages/SettingsLib/res/values-lo/strings.xml
@@ -220,7 +220,8 @@
<string name="select_private_dns_configuration_title" msgid="3700456559305263922">"DNS ສ່ວນຕົວ"</string>
<string name="select_private_dns_configuration_dialog_title" msgid="9221994415765826811">"ເລືອກໂໝດ DNS ສ່ວນຕົວ"</string>
<string name="private_dns_mode_off" msgid="8236575187318721684">"ປິດ"</string>
- <string name="private_dns_mode_opportunistic" msgid="7608409735589131766">"ກ່ຽວກັບໂອກາດ"</string>
+ <!-- no translation found for private_dns_mode_opportunistic (8314986739896927399) -->
+ <skip />
<string name="private_dns_mode_provider" msgid="8354935160639360804">"ຊື່ໂຮສຜູ້ໃຫ້ບໍລິການ DNS ສ່ວນຕົວ"</string>
<string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"ລະບຸຊື່ໂຮສຂອງຜູ້ໃຫ້ບໍລິການ DNS"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"ສະແດງໂຕເລືອກສຳລັບການສະແດງການຮັບຮອງລະບົບໄຮ້ສາຍ"</string>
@@ -356,22 +357,41 @@
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"ຄຸນສົມບັດນີ້ກຳລັງຢູ່ໃນການທົດລອງແລະອາດມີຜົນຕໍ່ປະສິດທິພາບ."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"ຖືກແທນໂດຍ <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="power_remaining_duration_only" msgid="845431008899029842">"ອີກປະມານ <xliff:g id="TIME">%1$s</xliff:g>"</string>
+ <!-- no translation found for power_discharging_duration (6655472132189365839) -->
+ <skip />
<string name="power_remaining_duration_only_enhanced" msgid="5992456722677973678">"ເຫຼືອອີກປະມານ <xliff:g id="TIME">%1$s</xliff:g> ໂດຍອ້າງອີງຈາກການນຳໃຊ້ຂອງທ່ານ"</string>
- <string name="power_remaining_charging_duration_only" msgid="1421102457410268886">"<xliff:g id="TIME">%1$s</xliff:g> ຈົນກວ່າຈະສາກເຕັມ"</string>
+ <!-- no translation found for power_discharging_duration_enhanced (5726302316642148671) -->
+ <skip />
<string name="power_remaining_duration_only_short" msgid="5329694252258605547">"ຍັງເຫຼືອ <xliff:g id="TIME">%1$s</xliff:g>"</string>
+ <!-- no translation found for power_discharge_by_enhanced (8788299408879961465) -->
+ <skip />
+ <!-- no translation found for power_discharge_by_only_enhanced (7692297898877104416) -->
+ <skip />
+ <!-- no translation found for power_discharge_by (6427074755635635749) -->
+ <skip />
+ <!-- no translation found for power_discharge_by_only (5888058889261108064) -->
+ <skip />
<string name="power_remaining_less_than_duration_only" msgid="5996752448813295329">"ຍັງເຫຼືອໜ້ອຍກວ່າ <xliff:g id="THRESHOLD">%1$s</xliff:g>"</string>
- <string name="power_remaining_less_than_duration" msgid="7967078125657859046">"<xliff:g id="LEVEL">%1$s</xliff:g> - ຍັງເຫຼືອໜ້ອຍກວ່າ <xliff:g id="THRESHOLD">%2$s</xliff:g>"</string>
- <string name="power_remaining_more_than_subtext" msgid="6846716609975752316">"<xliff:g id="LEVEL">%1$s</xliff:g>ຍັງເຫຼືອຫຼາຍກວ່າ <xliff:g id="TIME_REMAINING">%2$s</xliff:g>"</string>
- <string name="power_remaining_only_more_than_subtext" msgid="8884488700395194194">"ຍັງເຫຼືອຫຼາຍກວ່າ <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="default" msgid="8168317165722752881">"ໂທລະສັບອາດຈະປິດໃນໄວໆນີ້"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="tablet" msgid="5957064378548718872">"ແທັຍເລັດອາດຈະປິດໃນໄວໆນີ້"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="device" msgid="9055596817716471373">"ອຸປະກອນອາດຈະປິດໃນໄວໆນີ້"</string>
- <string name="power_discharging_duration" msgid="2843747179907396142">"<xliff:g id="LEVEL">%1$s</xliff:g> - ຍັງເຫຼືອປະມານ <xliff:g id="TIME">%2$s</xliff:g>"</string>
- <string name="power_discharging_duration_enhanced" msgid="4401782117770255046">"<xliff:g id="LEVEL">%1$s</xliff:g> - ເຫຼືອອີກປະມານ <xliff:g id="TIME">%2$s</xliff:g> ໂດຍອ້າງອີງຈາກການນຳໃຊ້ຂອງທ່ານ"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="default" msgid="7679005631124015335">"<xliff:g id="LEVEL">%1$s</xliff:g> - ໂທລະສັບອາດຈະປິດໃນໄວໆນີ້"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="tablet" msgid="261050880878965621">"<xliff:g id="LEVEL">%1$s</xliff:g> - ແທັບເລັດອາດຈະປິດໃນໄວໆນີ້"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="device" msgid="2020049829798578618">"<xliff:g id="LEVEL">%1$s</xliff:g> - ອຸປະກອນອາດຈະປິດໃນໄວໆນີ້"</string>
+ <!-- no translation found for power_remaining_less_than_duration (5751885147712659423) -->
+ <skip />
+ <!-- no translation found for power_remaining_more_than_subtext (3176771815132876675) -->
+ <skip />
+ <!-- no translation found for power_remaining_only_more_than_subtext (8931654680569617380) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (1181059207608751924) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (2606370266981054691) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (2918084807716859985) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (3090926004324573908) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (7466484148515796216) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (603933521600231649) -->
+ <skip />
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
+ <string name="power_remaining_charging_duration_only" msgid="1421102457410268886">"<xliff:g id="TIME">%1$s</xliff:g> ຈົນກວ່າຈະສາກເຕັມ"</string>
<string name="power_charging_duration" msgid="4676999980973411875">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> ຈົນກວ່າຈະສາກເຕັມ"</string>
<string name="battery_info_status_unknown" msgid="196130600938058547">"ບໍ່ຮູ້ຈັກ"</string>
<string name="battery_info_status_charging" msgid="1705179948350365604">"ກຳລັງສາກໄຟ"</string>
diff --git a/packages/SettingsLib/res/values-lt/strings.xml b/packages/SettingsLib/res/values-lt/strings.xml
index 8eced2d..eb48b7f 100644
--- a/packages/SettingsLib/res/values-lt/strings.xml
+++ b/packages/SettingsLib/res/values-lt/strings.xml
@@ -220,7 +220,8 @@
<string name="select_private_dns_configuration_title" msgid="3700456559305263922">"Privatus DNS"</string>
<string name="select_private_dns_configuration_dialog_title" msgid="9221994415765826811">"Pasirinkite privataus DNS režimą"</string>
<string name="private_dns_mode_off" msgid="8236575187318721684">"Išjungta"</string>
- <string name="private_dns_mode_opportunistic" msgid="7608409735589131766">"Oportunistinis"</string>
+ <!-- no translation found for private_dns_mode_opportunistic (8314986739896927399) -->
+ <skip />
<string name="private_dns_mode_provider" msgid="8354935160639360804">"Privataus DNS teikėjo prieglobos serverio pavadinimas"</string>
<string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"Įveskite DNS teikėjo prieglobos serverio pavadinimą"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Rodyti belaidžio rodymo sertifikavimo parinktis"</string>
@@ -356,22 +357,41 @@
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Ši funkcija yra eksperimentinė ir ji gali turėti įtakos našumui."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"Nepaisyta naudojant nuostatą „<xliff:g id="TITLE">%1$s</xliff:g>“"</string>
<string name="power_remaining_duration_only" msgid="845431008899029842">"Liko maždaug <xliff:g id="TIME">%1$s</xliff:g>"</string>
+ <!-- no translation found for power_discharging_duration (6655472132189365839) -->
+ <skip />
<string name="power_remaining_duration_only_enhanced" msgid="5992456722677973678">"Liko maždaug <xliff:g id="TIME">%1$s</xliff:g>, atsižvelgiant į naudojimą"</string>
- <string name="power_remaining_charging_duration_only" msgid="1421102457410268886">"Iki visiškos įkrovos liko <xliff:g id="TIME">%1$s</xliff:g>"</string>
+ <!-- no translation found for power_discharging_duration_enhanced (5726302316642148671) -->
+ <skip />
<string name="power_remaining_duration_only_short" msgid="5329694252258605547">"Liko <xliff:g id="TIME">%1$s</xliff:g>"</string>
+ <!-- no translation found for power_discharge_by_enhanced (8788299408879961465) -->
+ <skip />
+ <!-- no translation found for power_discharge_by_only_enhanced (7692297898877104416) -->
+ <skip />
+ <!-- no translation found for power_discharge_by (6427074755635635749) -->
+ <skip />
+ <!-- no translation found for power_discharge_by_only (5888058889261108064) -->
+ <skip />
<string name="power_remaining_less_than_duration_only" msgid="5996752448813295329">"Liko mažiau nei <xliff:g id="THRESHOLD">%1$s</xliff:g>"</string>
- <string name="power_remaining_less_than_duration" msgid="7967078125657859046">"<xliff:g id="LEVEL">%1$s</xliff:g> – liko mažiau nei <xliff:g id="THRESHOLD">%2$s</xliff:g>"</string>
- <string name="power_remaining_more_than_subtext" msgid="6846716609975752316">"<xliff:g id="LEVEL">%1$s</xliff:g> – liko daugiau nei <xliff:g id="TIME_REMAINING">%2$s</xliff:g>"</string>
- <string name="power_remaining_only_more_than_subtext" msgid="8884488700395194194">"Liko daugiau nei <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="default" msgid="8168317165722752881">"telefonas netrukus gali būti išjungtas"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="tablet" msgid="5957064378548718872">"planšetinis komp. netrukus gali būti išjungtas"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="device" msgid="9055596817716471373">"įrenginys netrukus gali būti išjungtas"</string>
- <string name="power_discharging_duration" msgid="2843747179907396142">"<xliff:g id="LEVEL">%1$s</xliff:g> – liko maždaug <xliff:g id="TIME">%2$s</xliff:g>"</string>
- <string name="power_discharging_duration_enhanced" msgid="4401782117770255046">"<xliff:g id="LEVEL">%1$s</xliff:g> – liko maždaug <xliff:g id="TIME">%2$s</xliff:g>, atsižvelgiant į naudojimą"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="default" msgid="7679005631124015335">"<xliff:g id="LEVEL">%1$s</xliff:g> – telefonas netrukus gali būti išjungtas"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="tablet" msgid="261050880878965621">"<xliff:g id="LEVEL">%1$s</xliff:g> – planšetinis kompiuteris netrukus gali būti išjungtas"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="device" msgid="2020049829798578618">"<xliff:g id="LEVEL">%1$s</xliff:g> – įrenginys netrukus gali būti išjungtas"</string>
+ <!-- no translation found for power_remaining_less_than_duration (5751885147712659423) -->
+ <skip />
+ <!-- no translation found for power_remaining_more_than_subtext (3176771815132876675) -->
+ <skip />
+ <!-- no translation found for power_remaining_only_more_than_subtext (8931654680569617380) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (1181059207608751924) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (2606370266981054691) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (2918084807716859985) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (3090926004324573908) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (7466484148515796216) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (603933521600231649) -->
+ <skip />
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string>
+ <string name="power_remaining_charging_duration_only" msgid="1421102457410268886">"Iki visiškos įkrovos liko <xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="4676999980973411875">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> iki visiško įkrovimo"</string>
<string name="battery_info_status_unknown" msgid="196130600938058547">"Nežinomas"</string>
<string name="battery_info_status_charging" msgid="1705179948350365604">"Kraunasi..."</string>
diff --git a/packages/SettingsLib/res/values-lv/strings.xml b/packages/SettingsLib/res/values-lv/strings.xml
index 24cc69e..96a9d1e 100644
--- a/packages/SettingsLib/res/values-lv/strings.xml
+++ b/packages/SettingsLib/res/values-lv/strings.xml
@@ -220,7 +220,8 @@
<string name="select_private_dns_configuration_title" msgid="3700456559305263922">"Privāts DNS"</string>
<string name="select_private_dns_configuration_dialog_title" msgid="9221994415765826811">"Atlasiet privāta DNS režīmu"</string>
<string name="private_dns_mode_off" msgid="8236575187318721684">"Izslēgts"</string>
- <string name="private_dns_mode_opportunistic" msgid="7608409735589131766">"Oportūnistisks"</string>
+ <!-- no translation found for private_dns_mode_opportunistic (8314986739896927399) -->
+ <skip />
<string name="private_dns_mode_provider" msgid="8354935160639360804">"Privātā DNS pakalpojumu sniedzēja saimniekdatora nosaukums"</string>
<string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"Ievadiet DNS pakalpojumu sniedzēja saimniekdatora nosaukumu"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Rādīt bezvadu attēlošanas sertifikācijas iespējas"</string>
@@ -356,22 +357,41 @@
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Šī funkcija ir eksperimentāla un var ietekmēt veiktspēju."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"Jaunā preference: <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="power_remaining_duration_only" msgid="845431008899029842">"Atlikušais laiks: aptuveni <xliff:g id="TIME">%1$s</xliff:g>"</string>
+ <!-- no translation found for power_discharging_duration (6655472132189365839) -->
+ <skip />
<string name="power_remaining_duration_only_enhanced" msgid="5992456722677973678">"Atlikušais laiks: aptuveni <xliff:g id="TIME">%1$s</xliff:g> (ņemot vērā lietojumu)"</string>
- <string name="power_remaining_charging_duration_only" msgid="1421102457410268886">"Atlikušais laiks līdz pilnai uzlādei: <xliff:g id="TIME">%1$s</xliff:g>"</string>
+ <!-- no translation found for power_discharging_duration_enhanced (5726302316642148671) -->
+ <skip />
<string name="power_remaining_duration_only_short" msgid="5329694252258605547">"Atlicis: <xliff:g id="TIME">%1$s</xliff:g>"</string>
+ <!-- no translation found for power_discharge_by_enhanced (8788299408879961465) -->
+ <skip />
+ <!-- no translation found for power_discharge_by_only_enhanced (7692297898877104416) -->
+ <skip />
+ <!-- no translation found for power_discharge_by (6427074755635635749) -->
+ <skip />
+ <!-- no translation found for power_discharge_by_only (5888058889261108064) -->
+ <skip />
<string name="power_remaining_less_than_duration_only" msgid="5996752448813295329">"Atlikušais laiks — mazāk nekā <xliff:g id="THRESHOLD">%1$s</xliff:g>"</string>
- <string name="power_remaining_less_than_duration" msgid="7967078125657859046">"<xliff:g id="LEVEL">%1$s</xliff:g> — atlikušais laiks ir mazāk nekā <xliff:g id="THRESHOLD">%2$s</xliff:g>"</string>
- <string name="power_remaining_more_than_subtext" msgid="6846716609975752316">"<xliff:g id="LEVEL">%1$s</xliff:g> — atlikušais laiks ir vairāk nekā <xliff:g id="TIME_REMAINING">%2$s</xliff:g>"</string>
- <string name="power_remaining_only_more_than_subtext" msgid="8884488700395194194">"Atlikušais laiks — vairāk nekā <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="default" msgid="8168317165722752881">"Tālrunis, iespējams, drīz izslēgsies."</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="tablet" msgid="5957064378548718872">"Planšetdators, iespējams, drīz izslēgsies."</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="device" msgid="9055596817716471373">"Ierīce, iespējams, drīz izslēgsies."</string>
- <string name="power_discharging_duration" msgid="2843747179907396142">"<xliff:g id="LEVEL">%1$s</xliff:g> - vēl apmēram <xliff:g id="TIME">%2$s</xliff:g>"</string>
- <string name="power_discharging_duration_enhanced" msgid="4401782117770255046">"<xliff:g id="LEVEL">%1$s</xliff:g> — atlikušais laiks: aptuveni <xliff:g id="TIME">%2$s</xliff:g> (ņemot vērā lietojumu)"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="default" msgid="7679005631124015335">"<xliff:g id="LEVEL">%1$s</xliff:g> — tālrunis, iespējams, drīz izslēgsies."</string>
- <string name="power_remaining_duration_shutdown_imminent" product="tablet" msgid="261050880878965621">"<xliff:g id="LEVEL">%1$s</xliff:g> — planšetdators, iespējams, drīz izslēgsies."</string>
- <string name="power_remaining_duration_shutdown_imminent" product="device" msgid="2020049829798578618">"<xliff:g id="LEVEL">%1$s</xliff:g> — ierīce, iespējams, drīz izslēgsies."</string>
+ <!-- no translation found for power_remaining_less_than_duration (5751885147712659423) -->
+ <skip />
+ <!-- no translation found for power_remaining_more_than_subtext (3176771815132876675) -->
+ <skip />
+ <!-- no translation found for power_remaining_only_more_than_subtext (8931654680569617380) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (1181059207608751924) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (2606370266981054691) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (2918084807716859985) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (3090926004324573908) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (7466484148515796216) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (603933521600231649) -->
+ <skip />
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> — <xliff:g id="STATE">%2$s</xliff:g>"</string>
+ <string name="power_remaining_charging_duration_only" msgid="1421102457410268886">"Atlikušais laiks līdz pilnai uzlādei: <xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="4676999980973411875">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g>, kamēr pilnībā uzlādēts"</string>
<string name="battery_info_status_unknown" msgid="196130600938058547">"Nezināms"</string>
<string name="battery_info_status_charging" msgid="1705179948350365604">"Uzlāde"</string>
diff --git a/packages/SettingsLib/res/values-mk/strings.xml b/packages/SettingsLib/res/values-mk/strings.xml
index 4798a6f..534e994 100644
--- a/packages/SettingsLib/res/values-mk/strings.xml
+++ b/packages/SettingsLib/res/values-mk/strings.xml
@@ -220,7 +220,8 @@
<string name="select_private_dns_configuration_title" msgid="3700456559305263922">"Приватен DNS"</string>
<string name="select_private_dns_configuration_dialog_title" msgid="9221994415765826811">"Изберете режим на приватен DNS"</string>
<string name="private_dns_mode_off" msgid="8236575187318721684">"Исклучено"</string>
- <string name="private_dns_mode_opportunistic" msgid="7608409735589131766">"Опортунистички"</string>
+ <!-- no translation found for private_dns_mode_opportunistic (8314986739896927399) -->
+ <skip />
<string name="private_dns_mode_provider" msgid="8354935160639360804">"Име на хост на оператор на приватен DNS"</string>
<string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"Внесете име на хост на операторот на DNS"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Покажи ги опциите за безжичен приказ на сертификат"</string>
@@ -356,22 +357,41 @@
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Функцијата е експериментална и може да влијае на изведбата."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"Прескокнато според <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="power_remaining_duration_only" msgid="845431008899029842">"Преостануваат околу <xliff:g id="TIME">%1$s</xliff:g>"</string>
+ <!-- no translation found for power_discharging_duration (6655472132189365839) -->
+ <skip />
<string name="power_remaining_duration_only_enhanced" msgid="5992456722677973678">"Уште околу <xliff:g id="TIME">%1$s</xliff:g> според користењето"</string>
- <string name="power_remaining_charging_duration_only" msgid="1421102457410268886">"Преостануваат <xliff:g id="TIME">%1$s</xliff:g> дури се наполни целосно"</string>
+ <!-- no translation found for power_discharging_duration_enhanced (5726302316642148671) -->
+ <skip />
<string name="power_remaining_duration_only_short" msgid="5329694252258605547">"уште <xliff:g id="TIME">%1$s</xliff:g>"</string>
+ <!-- no translation found for power_discharge_by_enhanced (8788299408879961465) -->
+ <skip />
+ <!-- no translation found for power_discharge_by_only_enhanced (7692297898877104416) -->
+ <skip />
+ <!-- no translation found for power_discharge_by (6427074755635635749) -->
+ <skip />
+ <!-- no translation found for power_discharge_by_only (5888058889261108064) -->
+ <skip />
<string name="power_remaining_less_than_duration_only" msgid="5996752448813295329">"Уште помалку од <xliff:g id="THRESHOLD">%1$s</xliff:g>"</string>
- <string name="power_remaining_less_than_duration" msgid="7967078125657859046">"<xliff:g id="LEVEL">%1$s</xliff:g> - Уште помалку од <xliff:g id="THRESHOLD">%2$s</xliff:g>"</string>
- <string name="power_remaining_more_than_subtext" msgid="6846716609975752316">"<xliff:g id="LEVEL">%1$s</xliff:g>- Уште повеќе од <xliff:g id="TIME_REMAINING">%2$s</xliff:g>"</string>
- <string name="power_remaining_only_more_than_subtext" msgid="8884488700395194194">"Уште повеќе од <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="default" msgid="8168317165722752881">"телефонот може да се исклучи наскоро"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="tablet" msgid="5957064378548718872">"таблетот може да се исклучи наскоро"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="device" msgid="9055596817716471373">"уредот може да се исклучи наскоро"</string>
- <string name="power_discharging_duration" msgid="2843747179907396142">"<xliff:g id="LEVEL">%1$s</xliff:g> - уште околу <xliff:g id="TIME">%2$s</xliff:g>"</string>
- <string name="power_discharging_duration_enhanced" msgid="4401782117770255046">"<xliff:g id="LEVEL">%1$s</xliff:g> - уште околу <xliff:g id="TIME">%2$s</xliff:g> според користењето"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="default" msgid="7679005631124015335">"<xliff:g id="LEVEL">%1$s</xliff:g> - телефонот може да се исклучи наскоро"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="tablet" msgid="261050880878965621">"<xliff:g id="LEVEL">%1$s</xliff:g> - таблетот може да се исклучи наскоро"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="device" msgid="2020049829798578618">"<xliff:g id="LEVEL">%1$s</xliff:g> - уредот може да се исклучи наскоро"</string>
+ <!-- no translation found for power_remaining_less_than_duration (5751885147712659423) -->
+ <skip />
+ <!-- no translation found for power_remaining_more_than_subtext (3176771815132876675) -->
+ <skip />
+ <!-- no translation found for power_remaining_only_more_than_subtext (8931654680569617380) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (1181059207608751924) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (2606370266981054691) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (2918084807716859985) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (3090926004324573908) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (7466484148515796216) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (603933521600231649) -->
+ <skip />
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string>
+ <string name="power_remaining_charging_duration_only" msgid="1421102457410268886">"Преостануваат <xliff:g id="TIME">%1$s</xliff:g> дури се наполни целосно"</string>
<string name="power_charging_duration" msgid="4676999980973411875">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> дури се наполни целосно"</string>
<string name="battery_info_status_unknown" msgid="196130600938058547">"Непознато"</string>
<string name="battery_info_status_charging" msgid="1705179948350365604">"Се полни"</string>
diff --git a/packages/SettingsLib/res/values-ml/strings.xml b/packages/SettingsLib/res/values-ml/strings.xml
index 04b08f4..20a1e29 100644
--- a/packages/SettingsLib/res/values-ml/strings.xml
+++ b/packages/SettingsLib/res/values-ml/strings.xml
@@ -220,7 +220,8 @@
<string name="select_private_dns_configuration_title" msgid="3700456559305263922">"സ്വകാര്യ DNS"</string>
<string name="select_private_dns_configuration_dialog_title" msgid="9221994415765826811">"സ്വകാര്യ DNS മോഡ് തിരഞ്ഞെടുക്കുക"</string>
<string name="private_dns_mode_off" msgid="8236575187318721684">"ഓഫ്"</string>
- <string name="private_dns_mode_opportunistic" msgid="7608409735589131766">"അവസരവാദപരം"</string>
+ <!-- no translation found for private_dns_mode_opportunistic (8314986739896927399) -->
+ <skip />
<string name="private_dns_mode_provider" msgid="8354935160639360804">"സ്വകാര്യ DNS ദാതാവിന്റെ ഹോസ്റ്റുനാമം"</string>
<string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"DNS ദാതാവിന്റെ ഹോസ്റ്റുനാമം നൽകുക"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"വയർലെസ് ഡിസ്പ്ലേ സർട്ടിഫിക്കേഷനായി ഓപ്ഷനുകൾ ദൃശ്യമാക്കുക"</string>
@@ -356,22 +357,41 @@
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"ഈ ഫീച്ചർ പരീക്ഷണാത്മകമായതിനാൽ പ്രകടനത്തെ ബാധിച്ചേക്കാം."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"<xliff:g id="TITLE">%1$s</xliff:g> ഉപയോഗിച്ച് അസാധുവാക്കി"</string>
<string name="power_remaining_duration_only" msgid="845431008899029842">"ഏകദേശം <xliff:g id="TIME">%1$s</xliff:g> ശേഷിക്കുന്നു"</string>
+ <!-- no translation found for power_discharging_duration (6655472132189365839) -->
+ <skip />
<string name="power_remaining_duration_only_enhanced" msgid="5992456722677973678">"നിങ്ങളുടെ ഉപയോഗത്തെ അടിസ്ഥാനമാക്കി ഏതാണ്ട് <xliff:g id="TIME">%1$s</xliff:g> ശേഷിക്കുന്നു"</string>
- <string name="power_remaining_charging_duration_only" msgid="1421102457410268886">"മുഴുവൻ ചാർജാകാൻ <xliff:g id="TIME">%1$s</xliff:g> ശേഷിക്കുന്നു"</string>
+ <!-- no translation found for power_discharging_duration_enhanced (5726302316642148671) -->
+ <skip />
<string name="power_remaining_duration_only_short" msgid="5329694252258605547">"<xliff:g id="TIME">%1$s</xliff:g> ശേഷിക്കുന്നു"</string>
+ <!-- no translation found for power_discharge_by_enhanced (8788299408879961465) -->
+ <skip />
+ <!-- no translation found for power_discharge_by_only_enhanced (7692297898877104416) -->
+ <skip />
+ <!-- no translation found for power_discharge_by (6427074755635635749) -->
+ <skip />
+ <!-- no translation found for power_discharge_by_only (5888058889261108064) -->
+ <skip />
<string name="power_remaining_less_than_duration_only" msgid="5996752448813295329">"<xliff:g id="THRESHOLD">%1$s</xliff:g>-ൽ കുറവ് സമയം ശേഷിക്കുന്നു"</string>
- <string name="power_remaining_less_than_duration" msgid="7967078125657859046">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="THRESHOLD">%2$s</xliff:g>-ൽ കുറവ് സമയം ശേഷിക്കുന്നു"</string>
- <string name="power_remaining_more_than_subtext" msgid="6846716609975752316">"<xliff:g id="LEVEL">%1$s</xliff:g><xliff:g id="TIME_REMAINING">%2$s</xliff:g>-ൽ കൂടുതൽ സമയം ശേഷിക്കുന്നു"</string>
- <string name="power_remaining_only_more_than_subtext" msgid="8884488700395194194">"<xliff:g id="TIME_REMAINING">%1$s</xliff:g>-ൽ കൂടുതൽ സമയം ശേഷിക്കുന്നു"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="default" msgid="8168317165722752881">"ഫോൺ ഉടൻ ഷട്ട് ഡൗൺ ആയേക്കാം"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="tablet" msgid="5957064378548718872">"ടാബ്ലെറ്റ് ഉടൻ ഷട്ട് ഡൗൺ ആയേക്കാം"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="device" msgid="9055596817716471373">"ഉപകരണം ഉടൻ ഷട്ട്ഡൗൺ ആയേക്കാം"</string>
- <string name="power_discharging_duration" msgid="2843747179907396142">"<xliff:g id="LEVEL">%1$s</xliff:g> - ഏതാണ്ട് <xliff:g id="TIME">%2$s</xliff:g> ശേഷിക്കുന്നു"</string>
- <string name="power_discharging_duration_enhanced" msgid="4401782117770255046">"<xliff:g id="LEVEL">%1$s</xliff:g> - നിങ്ങളുടെ ഉപയോഗത്തെ അടിസ്ഥാനമാക്കി ഏതാണ്ട് <xliff:g id="TIME">%2$s</xliff:g> ശേഷിക്കുന്നു"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="default" msgid="7679005631124015335">"<xliff:g id="LEVEL">%1$s</xliff:g> - ഫോൺ ഉടൻ ഷട്ട് ഡൗൺ ആയേക്കാം"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="tablet" msgid="261050880878965621">"<xliff:g id="LEVEL">%1$s</xliff:g> - ടാബ്ലെറ്റ് ഉടൻ ഷട്ട് ഡൗൺ ആയേക്കാം"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="device" msgid="2020049829798578618">"<xliff:g id="LEVEL">%1$s</xliff:g> - ഉപകരണം ഉടൻ ഷട്ട്ഡൗൺ ആയേക്കാം"</string>
+ <!-- no translation found for power_remaining_less_than_duration (5751885147712659423) -->
+ <skip />
+ <!-- no translation found for power_remaining_more_than_subtext (3176771815132876675) -->
+ <skip />
+ <!-- no translation found for power_remaining_only_more_than_subtext (8931654680569617380) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (1181059207608751924) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (2606370266981054691) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (2918084807716859985) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (3090926004324573908) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (7466484148515796216) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (603933521600231649) -->
+ <skip />
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
+ <string name="power_remaining_charging_duration_only" msgid="1421102457410268886">"മുഴുവൻ ചാർജാകാൻ <xliff:g id="TIME">%1$s</xliff:g> ശേഷിക്കുന്നു"</string>
<string name="power_charging_duration" msgid="4676999980973411875">"<xliff:g id="LEVEL">%1$s</xliff:g> - ഫുൾ ചാർജാകാൻ <xliff:g id="TIME">%2$s</xliff:g>"</string>
<string name="battery_info_status_unknown" msgid="196130600938058547">"അജ്ഞാതം"</string>
<string name="battery_info_status_charging" msgid="1705179948350365604">"ചാർജ്ജുചെയ്യുന്നു"</string>
diff --git a/packages/SettingsLib/res/values-mn/strings.xml b/packages/SettingsLib/res/values-mn/strings.xml
index 596d103..04ca84ac 100644
--- a/packages/SettingsLib/res/values-mn/strings.xml
+++ b/packages/SettingsLib/res/values-mn/strings.xml
@@ -220,7 +220,8 @@
<string name="select_private_dns_configuration_title" msgid="3700456559305263922">"Хувийн DNS"</string>
<string name="select_private_dns_configuration_dialog_title" msgid="9221994415765826811">"Хувийн DNS Горимыг сонгох"</string>
<string name="private_dns_mode_off" msgid="8236575187318721684">"Унтраалттай"</string>
- <string name="private_dns_mode_opportunistic" msgid="7608409735589131766">"Оппортунист үзэлтэн"</string>
+ <!-- no translation found for private_dns_mode_opportunistic (8314986739896927399) -->
+ <skip />
<string name="private_dns_mode_provider" msgid="8354935160639360804">"Хувийн DNS-н үйлчилгээ үзүүлэгчийн хостын нэр"</string>
<string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"DNS-н үйлчилгээ үзүүлэгчийн хостын нэрийг оруулах"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Утасгүй дэлгэцийн сертификатын сонголтыг харуулах"</string>
@@ -356,22 +357,41 @@
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Энэ функц туршилтынх бөгөөд ажиллагаанд нөлөөлж болзошгүй."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"Давхарласан <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="power_remaining_duration_only" msgid="845431008899029842">"Ойролцоогоор <xliff:g id="TIME">%1$s</xliff:g> үлдсэн"</string>
+ <!-- no translation found for power_discharging_duration (6655472132189365839) -->
+ <skip />
<string name="power_remaining_duration_only_enhanced" msgid="5992456722677973678">"Таны хэрэглээнд тулгуурлан <xliff:g id="TIME">%1$s</xliff:g> орчмын хугацаа үлдсэн байна"</string>
- <string name="power_remaining_charging_duration_only" msgid="1421102457410268886">"Бүрэн цэнэглэх хүртэл <xliff:g id="TIME">%1$s</xliff:g> үлдсэн"</string>
+ <!-- no translation found for power_discharging_duration_enhanced (5726302316642148671) -->
+ <skip />
<string name="power_remaining_duration_only_short" msgid="5329694252258605547">"<xliff:g id="TIME">%1$s</xliff:g> үлдсэн"</string>
+ <!-- no translation found for power_discharge_by_enhanced (8788299408879961465) -->
+ <skip />
+ <!-- no translation found for power_discharge_by_only_enhanced (7692297898877104416) -->
+ <skip />
+ <!-- no translation found for power_discharge_by (6427074755635635749) -->
+ <skip />
+ <!-- no translation found for power_discharge_by_only (5888058889261108064) -->
+ <skip />
<string name="power_remaining_less_than_duration_only" msgid="5996752448813295329">"<xliff:g id="THRESHOLD">%1$s</xliff:g>-с бага хугацаа үлдсэн"</string>
- <string name="power_remaining_less_than_duration" msgid="7967078125657859046">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="THRESHOLD">%2$s</xliff:g>-с бага хугацаа үлдсэн"</string>
- <string name="power_remaining_more_than_subtext" msgid="6846716609975752316">"<xliff:g id="LEVEL">%1$s</xliff:g><xliff:g id="TIME_REMAINING">%2$s</xliff:g>-с их хугацаа үлдсэн"</string>
- <string name="power_remaining_only_more_than_subtext" msgid="8884488700395194194">"<xliff:g id="TIME_REMAINING">%1$s</xliff:g>-с их хугацаа үлдсэн"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="default" msgid="8168317165722752881">"утас удахгүй унтарч болзошгүй"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="tablet" msgid="5957064378548718872">"таблет удахгүй унтарч болзошгүй"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="device" msgid="9055596817716471373">"төхөөрөмж удахгүй унтарч болзошгүй"</string>
- <string name="power_discharging_duration" msgid="2843747179907396142">"<xliff:g id="LEVEL">%1$s</xliff:g>-с <xliff:g id="TIME">%2$s</xliff:g> үлдсэн"</string>
- <string name="power_discharging_duration_enhanced" msgid="4401782117770255046">"<xliff:g id="LEVEL">%1$s</xliff:g> - таны хэрэглээнд тулгуурлан <xliff:g id="TIME">%2$s</xliff:g> орчмын хугацаа үлдсэн байна"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="default" msgid="7679005631124015335">"<xliff:g id="LEVEL">%1$s</xliff:g> - утас удахгүй унтарч болзошгүй"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="tablet" msgid="261050880878965621">"<xliff:g id="LEVEL">%1$s</xliff:g> - таблет удахгүй унтарч болзошгүй"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="device" msgid="2020049829798578618">"<xliff:g id="LEVEL">%1$s</xliff:g> - төхөөрөмж удахгүй унтарч болзошгүй"</string>
+ <!-- no translation found for power_remaining_less_than_duration (5751885147712659423) -->
+ <skip />
+ <!-- no translation found for power_remaining_more_than_subtext (3176771815132876675) -->
+ <skip />
+ <!-- no translation found for power_remaining_only_more_than_subtext (8931654680569617380) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (1181059207608751924) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (2606370266981054691) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (2918084807716859985) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (3090926004324573908) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (7466484148515796216) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (603933521600231649) -->
+ <skip />
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
+ <string name="power_remaining_charging_duration_only" msgid="1421102457410268886">"Бүрэн цэнэглэх хүртэл <xliff:g id="TIME">%1$s</xliff:g> үлдсэн"</string>
<string name="power_charging_duration" msgid="4676999980973411875">"бүрэн цэнэглэх хүртэл <xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g>"</string>
<string name="battery_info_status_unknown" msgid="196130600938058547">"Тодорхойгүй"</string>
<string name="battery_info_status_charging" msgid="1705179948350365604">"Цэнэглэж байна"</string>
diff --git a/packages/SettingsLib/res/values-mr/strings.xml b/packages/SettingsLib/res/values-mr/strings.xml
index 26f4344..de93282 100644
--- a/packages/SettingsLib/res/values-mr/strings.xml
+++ b/packages/SettingsLib/res/values-mr/strings.xml
@@ -220,7 +220,8 @@
<string name="select_private_dns_configuration_title" msgid="3700456559305263922">"खाजगी DNS"</string>
<string name="select_private_dns_configuration_dialog_title" msgid="9221994415765826811">"खाजगी DNS मोड निवडा"</string>
<string name="private_dns_mode_off" msgid="8236575187318721684">"बंद"</string>
- <string name="private_dns_mode_opportunistic" msgid="7608409735589131766">"संधिसाधू"</string>
+ <!-- no translation found for private_dns_mode_opportunistic (8314986739896927399) -->
+ <skip />
<string name="private_dns_mode_provider" msgid="8354935160639360804">"खाजगी DNS पुरवठादार होस्ट नाव"</string>
<string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"DNS पुरवठादाराचे होस्टनाव टाका"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"वायरलेस डिस्प्ले प्रमाणिकरणाचे पर्याय दाखवा"</string>
@@ -356,22 +357,41 @@
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"हे वैशिष्ट्य प्रायोगिक आहे आणि कदाचित कार्यप्रदर्शन प्रभावित करू शकते."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"<xliff:g id="TITLE">%1$s</xliff:g> द्वारे अधिलिखित"</string>
<string name="power_remaining_duration_only" msgid="845431008899029842">"सुमारे <xliff:g id="TIME">%1$s</xliff:g> शिल्लक"</string>
+ <!-- no translation found for power_discharging_duration (6655472132189365839) -->
+ <skip />
<string name="power_remaining_duration_only_enhanced" msgid="5992456722677973678">"तुमच्या वापरानुसार अंदाजे <xliff:g id="TIME">%1$s</xliff:g> पुरेल इतकी बॅटरी शिल्लक आहे"</string>
- <string name="power_remaining_charging_duration_only" msgid="1421102457410268886">"पूर्णपणे चार्ज होण्यास <xliff:g id="TIME">%1$s</xliff:g> शिल्लक"</string>
+ <!-- no translation found for power_discharging_duration_enhanced (5726302316642148671) -->
+ <skip />
<string name="power_remaining_duration_only_short" msgid="5329694252258605547">"<xliff:g id="TIME">%1$s</xliff:g> शिल्लक"</string>
+ <!-- no translation found for power_discharge_by_enhanced (8788299408879961465) -->
+ <skip />
+ <!-- no translation found for power_discharge_by_only_enhanced (7692297898877104416) -->
+ <skip />
+ <!-- no translation found for power_discharge_by (6427074755635635749) -->
+ <skip />
+ <!-- no translation found for power_discharge_by_only (5888058889261108064) -->
+ <skip />
<string name="power_remaining_less_than_duration_only" msgid="5996752448813295329">"<xliff:g id="THRESHOLD">%1$s</xliff:g> पेक्षा कमी शिल्लक आहे"</string>
- <string name="power_remaining_less_than_duration" msgid="7967078125657859046">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="THRESHOLD">%2$s</xliff:g> पेक्षा कमी शिल्लक आहे"</string>
- <string name="power_remaining_more_than_subtext" msgid="6846716609975752316">"<xliff:g id="LEVEL">%1$s</xliff:g><xliff:g id="TIME_REMAINING">%2$s</xliff:g> पेक्षा जास्त शिल्लक आहे"</string>
- <string name="power_remaining_only_more_than_subtext" msgid="8884488700395194194">"<xliff:g id="TIME_REMAINING">%1$s</xliff:g> पेक्षा जास्त शिल्लक आहे"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="default" msgid="8168317165722752881">"फोन लवकरच बंद होऊ शकतो"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="tablet" msgid="5957064378548718872">"टॅबलेट लवकरच बंद होऊ शकतो"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="device" msgid="9055596817716471373">"डिव्हाइस लवकरच बंद होऊ शकते"</string>
- <string name="power_discharging_duration" msgid="2843747179907396142">"<xliff:g id="LEVEL">%1$s</xliff:g> - सुमारे <xliff:g id="TIME">%2$s</xliff:g> शिल्लक"</string>
- <string name="power_discharging_duration_enhanced" msgid="4401782117770255046">"<xliff:g id="LEVEL">%1$s</xliff:g> - तुमच्या वापरानुसार अंदाजे <xliff:g id="TIME">%2$s</xliff:g> पुरेल इतकी बॅटरी शिल्लक आहे"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="default" msgid="7679005631124015335">"<xliff:g id="LEVEL">%1$s</xliff:g> - फोन लवकरच बंद होऊ शकतो"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="tablet" msgid="261050880878965621">"<xliff:g id="LEVEL">%1$s</xliff:g> - टॅबलेट लवकरच बंद होऊ शकतो"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="device" msgid="2020049829798578618">"<xliff:g id="LEVEL">%1$s</xliff:g> - डिव्हाइस लवकरच बंद होऊ शकते"</string>
+ <!-- no translation found for power_remaining_less_than_duration (5751885147712659423) -->
+ <skip />
+ <!-- no translation found for power_remaining_more_than_subtext (3176771815132876675) -->
+ <skip />
+ <!-- no translation found for power_remaining_only_more_than_subtext (8931654680569617380) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (1181059207608751924) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (2606370266981054691) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (2918084807716859985) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (3090926004324573908) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (7466484148515796216) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (603933521600231649) -->
+ <skip />
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
+ <string name="power_remaining_charging_duration_only" msgid="1421102457410268886">"पूर्णपणे चार्ज होण्यास <xliff:g id="TIME">%1$s</xliff:g> शिल्लक"</string>
<string name="power_charging_duration" msgid="4676999980973411875">"<xliff:g id="LEVEL">%1$s</xliff:g> - पूर्णपणे चार्ज होण्यात <xliff:g id="TIME">%2$s</xliff:g>"</string>
<string name="battery_info_status_unknown" msgid="196130600938058547">"अज्ञात"</string>
<string name="battery_info_status_charging" msgid="1705179948350365604">"चार्ज होत आहे"</string>
diff --git a/packages/SettingsLib/res/values-ms/strings.xml b/packages/SettingsLib/res/values-ms/strings.xml
index 8e24cee..99f6c0a 100644
--- a/packages/SettingsLib/res/values-ms/strings.xml
+++ b/packages/SettingsLib/res/values-ms/strings.xml
@@ -220,7 +220,8 @@
<string name="select_private_dns_configuration_title" msgid="3700456559305263922">"DNS Peribadi"</string>
<string name="select_private_dns_configuration_dialog_title" msgid="9221994415765826811">"Pilih Mod DNS Peribadi"</string>
<string name="private_dns_mode_off" msgid="8236575187318721684">"Mati"</string>
- <string name="private_dns_mode_opportunistic" msgid="7608409735589131766">"Oportunistik"</string>
+ <!-- no translation found for private_dns_mode_opportunistic (8314986739896927399) -->
+ <skip />
<string name="private_dns_mode_provider" msgid="8354935160639360804">"Nama hos pembekal DNS peribadi"</string>
<string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"Masukkan nama hos pembekal DNS"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Tunjukkan pilihan untuk pensijilan paparan wayarles"</string>
@@ -356,22 +357,41 @@
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Ciri ini adalah percubaan dan boleh menjejaskan prestasi."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"Diatasi oleh <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="power_remaining_duration_only" msgid="845431008899029842">"Kira-kira <xliff:g id="TIME">%1$s</xliff:g> lagi"</string>
+ <!-- no translation found for power_discharging_duration (6655472132189365839) -->
+ <skip />
<string name="power_remaining_duration_only_enhanced" msgid="5992456722677973678">"Tinggal kira-kira <xliff:g id="TIME">%1$s</xliff:g> berdasarkan penggunaan anda"</string>
- <string name="power_remaining_charging_duration_only" msgid="1421102457410268886">"<xliff:g id="TIME">%1$s</xliff:g> lagi sehingga dicas penuh"</string>
+ <!-- no translation found for power_discharging_duration_enhanced (5726302316642148671) -->
+ <skip />
<string name="power_remaining_duration_only_short" msgid="5329694252258605547">"<xliff:g id="TIME">%1$s</xliff:g> lagi"</string>
+ <!-- no translation found for power_discharge_by_enhanced (8788299408879961465) -->
+ <skip />
+ <!-- no translation found for power_discharge_by_only_enhanced (7692297898877104416) -->
+ <skip />
+ <!-- no translation found for power_discharge_by (6427074755635635749) -->
+ <skip />
+ <!-- no translation found for power_discharge_by_only (5888058889261108064) -->
+ <skip />
<string name="power_remaining_less_than_duration_only" msgid="5996752448813295329">"Tinggal kurang daripada <xliff:g id="THRESHOLD">%1$s</xliff:g>"</string>
- <string name="power_remaining_less_than_duration" msgid="7967078125657859046">"<xliff:g id="LEVEL">%1$s</xliff:g> - Tinggal kurang daripada <xliff:g id="THRESHOLD">%2$s</xliff:g>"</string>
- <string name="power_remaining_more_than_subtext" msgid="6846716609975752316">"<xliff:g id="LEVEL">%1$s</xliff:g>tinggal lebih daripada <xliff:g id="TIME_REMAINING">%2$s</xliff:g>"</string>
- <string name="power_remaining_only_more_than_subtext" msgid="8884488700395194194">"tinggal lebih daripada <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="default" msgid="8168317165722752881">"telefon mungkin ditutup tidak lama lagi"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="tablet" msgid="5957064378548718872">"tablet mungkin ditutup tidak lama lagi"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="device" msgid="9055596817716471373">"peranti mungkin ditutup tidak lama lagi"</string>
- <string name="power_discharging_duration" msgid="2843747179907396142">"<xliff:g id="LEVEL">%1$s</xliff:g> - kira-kira <xliff:g id="TIME">%2$s</xliff:g> lagi"</string>
- <string name="power_discharging_duration_enhanced" msgid="4401782117770255046">"<xliff:g id="LEVEL">%1$s</xliff:g> - tinggal kira-kira <xliff:g id="TIME">%2$s</xliff:g> berdasarkan penggunaan anda"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="default" msgid="7679005631124015335">"<xliff:g id="LEVEL">%1$s</xliff:g> - telefon mungkin ditutup tidak lama lagi"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="tablet" msgid="261050880878965621">"<xliff:g id="LEVEL">%1$s</xliff:g> - tablet mungkin ditutup tidak lama lagi"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="device" msgid="2020049829798578618">"<xliff:g id="LEVEL">%1$s</xliff:g> - peranti mungkin ditutup tidak lama lagi"</string>
+ <!-- no translation found for power_remaining_less_than_duration (5751885147712659423) -->
+ <skip />
+ <!-- no translation found for power_remaining_more_than_subtext (3176771815132876675) -->
+ <skip />
+ <!-- no translation found for power_remaining_only_more_than_subtext (8931654680569617380) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (1181059207608751924) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (2606370266981054691) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (2918084807716859985) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (3090926004324573908) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (7466484148515796216) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (603933521600231649) -->
+ <skip />
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
+ <string name="power_remaining_charging_duration_only" msgid="1421102457410268886">"<xliff:g id="TIME">%1$s</xliff:g> lagi sehingga dicas penuh"</string>
<string name="power_charging_duration" msgid="4676999980973411875">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> sehingga dicas penuh"</string>
<string name="battery_info_status_unknown" msgid="196130600938058547">"Tidak diketahui"</string>
<string name="battery_info_status_charging" msgid="1705179948350365604">"Mengecas"</string>
diff --git a/packages/SettingsLib/res/values-my/strings.xml b/packages/SettingsLib/res/values-my/strings.xml
index c1ca0ab..aedb291 100644
--- a/packages/SettingsLib/res/values-my/strings.xml
+++ b/packages/SettingsLib/res/values-my/strings.xml
@@ -45,7 +45,7 @@
<string name="available_via_carrier" msgid="1469036129740799053">"%1$s မှတစ်ဆင့် ရနိုင်သည်"</string>
<string name="speed_label_very_slow" msgid="1867055264243608530">"အလွန်နှေး"</string>
<string name="speed_label_slow" msgid="813109590815810235">"နှေး"</string>
- <string name="speed_label_okay" msgid="2331665440671174858">"အိုကေ"</string>
+ <string name="speed_label_okay" msgid="2331665440671174858">"OK"</string>
<string name="speed_label_medium" msgid="3175763313268941953">"အတော်အသင့်"</string>
<string name="speed_label_fast" msgid="7715732164050975057">"မြန်"</string>
<string name="speed_label_very_fast" msgid="2265363430784523409">"အလွန်မြန်"</string>
@@ -220,7 +220,8 @@
<string name="select_private_dns_configuration_title" msgid="3700456559305263922">"သီးသန့် DNS"</string>
<string name="select_private_dns_configuration_dialog_title" msgid="9221994415765826811">"သီးသန့် DNS မုဒ်ကို ရွေးပါ"</string>
<string name="private_dns_mode_off" msgid="8236575187318721684">"ပိတ်ရန်"</string>
- <string name="private_dns_mode_opportunistic" msgid="7608409735589131766">"အခွင့်အရေးသမား"</string>
+ <!-- no translation found for private_dns_mode_opportunistic (8314986739896927399) -->
+ <skip />
<string name="private_dns_mode_provider" msgid="8354935160639360804">"သီးသန့် DNS ပံ့ပိုးသူ၏ အင်တာနက်လက်ခံဝန်ဆောင်ပေးသူအမည်"</string>
<string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"DNS ဝန်ဆောင်မှုပေးသူ၏ အင်တာနက်လက်ခံဝန်ဆောင်ပေးသူအမည်ကို ထည့်ပါ"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"ကြိုးမဲ့ အခင်းအကျင်း အသိအမှတ်ပြုလက်မှတ်အတွက် ရွေးချယ်စရာများပြရန်"</string>
@@ -356,22 +357,41 @@
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"ဤဝန်ဆောင်မှုမှာ စမ်းသပ်အဆင့်သာဖြစ်၍ လုပ်ဆောင်မှုအားနည်းနိုင်သည်။"</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"<xliff:g id="TITLE">%1$s</xliff:g> မှ ကျော်၍ လုပ်ထားသည်။"</string>
<string name="power_remaining_duration_only" msgid="845431008899029842">"<xliff:g id="TIME">%1$s</xliff:g> ခန့်လိုပါသည်"</string>
+ <!-- no translation found for power_discharging_duration (6655472132189365839) -->
+ <skip />
<string name="power_remaining_duration_only_enhanced" msgid="5992456722677973678">"သင့်အသုံးပြုမှုအရ <xliff:g id="TIME">%1$s</xliff:g> ခန့် ကျန်ပါသည်"</string>
- <string name="power_remaining_charging_duration_only" msgid="1421102457410268886">"အားပြည့်ရန် <xliff:g id="TIME">%1$s</xliff:g> လိုပါသည်"</string>
+ <!-- no translation found for power_discharging_duration_enhanced (5726302316642148671) -->
+ <skip />
<string name="power_remaining_duration_only_short" msgid="5329694252258605547">"<xliff:g id="TIME">%1$s</xliff:g> ကျန်သည်"</string>
+ <!-- no translation found for power_discharge_by_enhanced (8788299408879961465) -->
+ <skip />
+ <!-- no translation found for power_discharge_by_only_enhanced (7692297898877104416) -->
+ <skip />
+ <!-- no translation found for power_discharge_by (6427074755635635749) -->
+ <skip />
+ <!-- no translation found for power_discharge_by_only (5888058889261108064) -->
+ <skip />
<string name="power_remaining_less_than_duration_only" msgid="5996752448813295329">"<xliff:g id="THRESHOLD">%1$s</xliff:g> ခန့်သာ ကျန်တော့သည်"</string>
- <string name="power_remaining_less_than_duration" msgid="7967078125657859046">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="THRESHOLD">%2$s</xliff:g> ခန့်သာ ကျန်တော့သည်"</string>
- <string name="power_remaining_more_than_subtext" msgid="6846716609975752316">"<xliff:g id="LEVEL">%1$s</xliff:g><xliff:g id="TIME_REMAINING">%2$s</xliff:g> ကျော် ကျန်သေးသည်"</string>
- <string name="power_remaining_only_more_than_subtext" msgid="8884488700395194194">"<xliff:g id="TIME_REMAINING">%1$s</xliff:g> ကျော် ကျန်သေးသည်"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="default" msgid="8168317165722752881">"မကြာမီ ဖုန်းပိတ်သွားနိုင်သည်"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="tablet" msgid="5957064378548718872">"မကြာမီ တက်ဘလက်ပိတ်သွားနိုင်သည်"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="device" msgid="9055596817716471373">"မကြာမီ စက်ပိတ်သွားနိုင်သည်"</string>
- <string name="power_discharging_duration" msgid="2843747179907396142">"<xliff:g id="LEVEL">%1$s</xliff:g> − <xliff:g id="TIME">%2$s</xliff:g> ခန့်ကျန်သည်"</string>
- <string name="power_discharging_duration_enhanced" msgid="4401782117770255046">"<xliff:g id="LEVEL">%1$s</xliff:g> - သင့်အသုံးပြုမှုအရ <xliff:g id="TIME">%2$s</xliff:g> ခန့် ကျန်ပါသည်"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="default" msgid="7679005631124015335">"<xliff:g id="LEVEL">%1$s</xliff:g> - မကြာမီ ဖုန်းပိတ်သွားနိင်သည်"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="tablet" msgid="261050880878965621">"<xliff:g id="LEVEL">%1$s</xliff:g> - မကြာမီ တက်ဘလက်ပိတ်သွားနိင်သည်"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="device" msgid="2020049829798578618">"<xliff:g id="LEVEL">%1$s</xliff:g> - မကြာမီ စက်ပိတ်သွားနိင်သည်"</string>
+ <!-- no translation found for power_remaining_less_than_duration (5751885147712659423) -->
+ <skip />
+ <!-- no translation found for power_remaining_more_than_subtext (3176771815132876675) -->
+ <skip />
+ <!-- no translation found for power_remaining_only_more_than_subtext (8931654680569617380) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (1181059207608751924) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (2606370266981054691) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (2918084807716859985) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (3090926004324573908) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (7466484148515796216) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (603933521600231649) -->
+ <skip />
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
+ <string name="power_remaining_charging_duration_only" msgid="1421102457410268886">"အားပြည့်ရန် <xliff:g id="TIME">%1$s</xliff:g> လိုပါသည်"</string>
<string name="power_charging_duration" msgid="4676999980973411875">"<xliff:g id="LEVEL">%1$s</xliff:g> − အားပြည့်ရန် <xliff:g id="TIME">%2$s</xliff:g> ကျန်သည်"</string>
<string name="battery_info_status_unknown" msgid="196130600938058547">"အကြောင်းအရာ မသိရှိ"</string>
<string name="battery_info_status_charging" msgid="1705179948350365604">"အားသွင်းနေပါသည်"</string>
diff --git a/packages/SettingsLib/res/values-nb/strings.xml b/packages/SettingsLib/res/values-nb/strings.xml
index 0b54624..fadf154 100644
--- a/packages/SettingsLib/res/values-nb/strings.xml
+++ b/packages/SettingsLib/res/values-nb/strings.xml
@@ -220,7 +220,8 @@
<string name="select_private_dns_configuration_title" msgid="3700456559305263922">"Privat DNS"</string>
<string name="select_private_dns_configuration_dialog_title" msgid="9221994415765826811">"Velg Privat DNS-modus"</string>
<string name="private_dns_mode_off" msgid="8236575187318721684">"Av"</string>
- <string name="private_dns_mode_opportunistic" msgid="7608409735589131766">"Opportunistisk"</string>
+ <!-- no translation found for private_dns_mode_opportunistic (8314986739896927399) -->
+ <skip />
<string name="private_dns_mode_provider" msgid="8354935160639360804">"Vertsnavn for privat DNS-leverandør"</string>
<string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"Skriv inn vertsnavnet til DNS-leverandøren"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Vis alternativer for sertifisering av trådløs skjerm"</string>
@@ -356,22 +357,41 @@
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Dette er en eksperimentell funksjon som kan gjøre at telefonen ikke fungerer optimalt."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"Overstyres av <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="power_remaining_duration_only" msgid="845431008899029842">"Omtrent <xliff:g id="TIME">%1$s</xliff:g> gjenstår"</string>
+ <!-- no translation found for power_discharging_duration (6655472132189365839) -->
+ <skip />
<string name="power_remaining_duration_only_enhanced" msgid="5992456722677973678">"Omtrent <xliff:g id="TIME">%1$s</xliff:g> igjen basert på bruken din"</string>
- <string name="power_remaining_charging_duration_only" msgid="1421102457410268886">"<xliff:g id="TIME">%1$s</xliff:g> til det er fulladet"</string>
+ <!-- no translation found for power_discharging_duration_enhanced (5726302316642148671) -->
+ <skip />
<string name="power_remaining_duration_only_short" msgid="5329694252258605547">"<xliff:g id="TIME">%1$s</xliff:g> gjenstår"</string>
+ <!-- no translation found for power_discharge_by_enhanced (8788299408879961465) -->
+ <skip />
+ <!-- no translation found for power_discharge_by_only_enhanced (7692297898877104416) -->
+ <skip />
+ <!-- no translation found for power_discharge_by (6427074755635635749) -->
+ <skip />
+ <!-- no translation found for power_discharge_by_only (5888058889261108064) -->
+ <skip />
<string name="power_remaining_less_than_duration_only" msgid="5996752448813295329">"Mindre enn <xliff:g id="THRESHOLD">%1$s</xliff:g> gjenstår"</string>
- <string name="power_remaining_less_than_duration" msgid="7967078125657859046">"<xliff:g id="LEVEL">%1$s</xliff:g> – mindre enn <xliff:g id="THRESHOLD">%2$s</xliff:g> gjenstår"</string>
- <string name="power_remaining_more_than_subtext" msgid="6846716609975752316">"<xliff:g id="LEVEL">%1$s</xliff:g> mindre enn <xliff:g id="TIME_REMAINING">%2$s</xliff:g> gjenstår"</string>
- <string name="power_remaining_only_more_than_subtext" msgid="8884488700395194194">"mer enn <xliff:g id="TIME_REMAINING">%1$s</xliff:g> gjenstår"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="default" msgid="8168317165722752881">"telefonen slås kanskje av snart"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="tablet" msgid="5957064378548718872">"nettbrettet slås kanskje av snart"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="device" msgid="9055596817716471373">"enheten slås kanskje av snart"</string>
- <string name="power_discharging_duration" msgid="2843747179907396142">"<xliff:g id="LEVEL">%1$s</xliff:g> – omtrent <xliff:g id="TIME">%2$s</xliff:g> gjenstår"</string>
- <string name="power_discharging_duration_enhanced" msgid="4401782117770255046">"<xliff:g id="LEVEL">%1$s</xliff:g> – omtrent <xliff:g id="TIME">%2$s</xliff:g> igjen basert på bruken din"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="default" msgid="7679005631124015335">"<xliff:g id="LEVEL">%1$s</xliff:g> – telefonen slås kanskje av snart"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="tablet" msgid="261050880878965621">"<xliff:g id="LEVEL">%1$s</xliff:g> – nettbrettet slås kanskje av snart"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="device" msgid="2020049829798578618">"<xliff:g id="LEVEL">%1$s</xliff:g> – enheten slås kanskje av snart"</string>
+ <!-- no translation found for power_remaining_less_than_duration (5751885147712659423) -->
+ <skip />
+ <!-- no translation found for power_remaining_more_than_subtext (3176771815132876675) -->
+ <skip />
+ <!-- no translation found for power_remaining_only_more_than_subtext (8931654680569617380) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (1181059207608751924) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (2606370266981054691) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (2918084807716859985) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (3090926004324573908) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (7466484148515796216) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (603933521600231649) -->
+ <skip />
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string>
+ <string name="power_remaining_charging_duration_only" msgid="1421102457410268886">"<xliff:g id="TIME">%1$s</xliff:g> til det er fulladet"</string>
<string name="power_charging_duration" msgid="4676999980973411875">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> til det er fulladet"</string>
<string name="battery_info_status_unknown" msgid="196130600938058547">"Ukjent"</string>
<string name="battery_info_status_charging" msgid="1705179948350365604">"Lader"</string>
diff --git a/packages/SettingsLib/res/values-ne/strings.xml b/packages/SettingsLib/res/values-ne/strings.xml
index 7b78009..e778c8e 100644
--- a/packages/SettingsLib/res/values-ne/strings.xml
+++ b/packages/SettingsLib/res/values-ne/strings.xml
@@ -220,7 +220,8 @@
<string name="select_private_dns_configuration_title" msgid="3700456559305263922">"निजी DNS"</string>
<string name="select_private_dns_configuration_dialog_title" msgid="9221994415765826811">"निजी DNS मोड चयन गर्नुहोस्"</string>
<string name="private_dns_mode_off" msgid="8236575187318721684">"निष्क्रिय छ"</string>
- <string name="private_dns_mode_opportunistic" msgid="7608409735589131766">"अवसरवादी"</string>
+ <!-- no translation found for private_dns_mode_opportunistic (8314986739896927399) -->
+ <skip />
<string name="private_dns_mode_provider" msgid="8354935160639360804">"निजी DNS प्रदायकको होस्टनाम"</string>
<string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"DNS प्रदायकको होस्टनाम प्रविष्ट गर्नुहोस्"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"ताररहित प्रदर्शन प्रमाणीकरणका लागि विकल्पहरू देखाउनुहोस्"</string>
@@ -356,22 +357,41 @@
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"यो सुविधा प्रयोगात्मक छ र प्रदर्शनमा असर गर्न सक्छ।"</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"<xliff:g id="TITLE">%1$s</xliff:g> द्वारा अधिरोहित"</string>
<string name="power_remaining_duration_only" msgid="845431008899029842">"लगभग <xliff:g id="TIME">%1$s</xliff:g> बाँकी"</string>
+ <!-- no translation found for power_discharging_duration (6655472132189365839) -->
+ <skip />
<string name="power_remaining_duration_only_enhanced" msgid="5992456722677973678">"तपाईंको प्रयोगका आधारमा लगभग <xliff:g id="TIME">%1$s</xliff:g> बाँकी"</string>
- <string name="power_remaining_charging_duration_only" msgid="1421102457410268886">"पूर्णरूपमा चार्ज हुन <xliff:g id="TIME">%1$s</xliff:g> बाँकी"</string>
+ <!-- no translation found for power_discharging_duration_enhanced (5726302316642148671) -->
+ <skip />
<string name="power_remaining_duration_only_short" msgid="5329694252258605547">"बाँकी समय <xliff:g id="TIME">%1$s</xliff:g>"</string>
+ <!-- no translation found for power_discharge_by_enhanced (8788299408879961465) -->
+ <skip />
+ <!-- no translation found for power_discharge_by_only_enhanced (7692297898877104416) -->
+ <skip />
+ <!-- no translation found for power_discharge_by (6427074755635635749) -->
+ <skip />
+ <!-- no translation found for power_discharge_by_only (5888058889261108064) -->
+ <skip />
<string name="power_remaining_less_than_duration_only" msgid="5996752448813295329">"<xliff:g id="THRESHOLD">%1$s</xliff:g> भन्दा कम समय बाँकी छ"</string>
- <string name="power_remaining_less_than_duration" msgid="7967078125657859046">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="THRESHOLD">%2$s</xliff:g> भन्दा कम समय बाँकी छ"</string>
- <string name="power_remaining_more_than_subtext" msgid="6846716609975752316">"<xliff:g id="LEVEL">%1$s</xliff:g> <xliff:g id="TIME_REMAINING">%2$s</xliff:g> भन्दा बढी समय बाँकी छ"</string>
- <string name="power_remaining_only_more_than_subtext" msgid="8884488700395194194">"<xliff:g id="TIME_REMAINING">%1$s</xliff:g> भन्दा बढी समय बाँकी छ"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="default" msgid="8168317165722752881">"फोन चाँडै बन्द हुन सक्छ"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="tablet" msgid="5957064378548718872">"ट्याब्लेट चाँडै बन्द हुन सक्छ"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="device" msgid="9055596817716471373">"यन्त्र चाँडै बन्द हुन सक्छ"</string>
- <string name="power_discharging_duration" msgid="2843747179907396142">"<xliff:g id="LEVEL">%1$s</xliff:g> - करिब <xliff:g id="TIME">%2$s</xliff:g> बाँकी"</string>
- <string name="power_discharging_duration_enhanced" msgid="4401782117770255046">"<xliff:g id="LEVEL">%1$s</xliff:g> - तपाईंको प्रयोगका आधारमा लगभग <xliff:g id="TIME">%2$s</xliff:g> बाँकी"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="default" msgid="7679005631124015335">"<xliff:g id="LEVEL">%1$s</xliff:g> - फोन चाँडै बन्द हुन सक्छ"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="tablet" msgid="261050880878965621">"<xliff:g id="LEVEL">%1$s</xliff:g> - ट्याब्लेट चाँडै बन्द हुन सक्छ"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="device" msgid="2020049829798578618">"<xliff:g id="LEVEL">%1$s</xliff:g> - यन्त्र चाँडै बन्द हुन सक्छ"</string>
+ <!-- no translation found for power_remaining_less_than_duration (5751885147712659423) -->
+ <skip />
+ <!-- no translation found for power_remaining_more_than_subtext (3176771815132876675) -->
+ <skip />
+ <!-- no translation found for power_remaining_only_more_than_subtext (8931654680569617380) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (1181059207608751924) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (2606370266981054691) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (2918084807716859985) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (3090926004324573908) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (7466484148515796216) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (603933521600231649) -->
+ <skip />
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
+ <string name="power_remaining_charging_duration_only" msgid="1421102457410268886">"पूर्णरूपमा चार्ज हुन <xliff:g id="TIME">%1$s</xliff:g> बाँकी"</string>
<string name="power_charging_duration" msgid="4676999980973411875">"<xliff:g id="LEVEL">%1$s</xliff:g> - पूर्णरूपमा चार्ज हुन <xliff:g id="TIME">%2$s</xliff:g> बाँकी"</string>
<string name="battery_info_status_unknown" msgid="196130600938058547">"अज्ञात"</string>
<string name="battery_info_status_charging" msgid="1705179948350365604">"चार्ज हुँदै"</string>
diff --git a/packages/SettingsLib/res/values-nl/strings.xml b/packages/SettingsLib/res/values-nl/strings.xml
index c6577e6..dc56ac4 100644
--- a/packages/SettingsLib/res/values-nl/strings.xml
+++ b/packages/SettingsLib/res/values-nl/strings.xml
@@ -220,7 +220,8 @@
<string name="select_private_dns_configuration_title" msgid="3700456559305263922">"Privé-DNS"</string>
<string name="select_private_dns_configuration_dialog_title" msgid="9221994415765826811">"Selecteer de modus Privé-DNS"</string>
<string name="private_dns_mode_off" msgid="8236575187318721684">"Uit"</string>
- <string name="private_dns_mode_opportunistic" msgid="7608409735589131766">"Opportunistisch"</string>
+ <!-- no translation found for private_dns_mode_opportunistic (8314986739896927399) -->
+ <skip />
<string name="private_dns_mode_provider" msgid="8354935160639360804">"Hostnaam van privé-DNS-provider"</string>
<string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"Geef hostnaam van DNS-provider op"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Opties weergeven voor certificering van draadloze weergave"</string>
@@ -356,22 +357,41 @@
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Deze functie is experimenteel en kan invloed hebben op de prestaties."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"Overschreven door <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="power_remaining_duration_only" msgid="845431008899029842">"Nog ongeveer <xliff:g id="TIME">%1$s</xliff:g>"</string>
+ <!-- no translation found for power_discharging_duration (6655472132189365839) -->
+ <skip />
<string name="power_remaining_duration_only_enhanced" msgid="5992456722677973678">"Nog ongeveer <xliff:g id="TIME">%1$s</xliff:g> over op basis van je gebruik"</string>
- <string name="power_remaining_charging_duration_only" msgid="1421102457410268886">"Nog <xliff:g id="TIME">%1$s</xliff:g> tot volledig opgeladen"</string>
+ <!-- no translation found for power_discharging_duration_enhanced (5726302316642148671) -->
+ <skip />
<string name="power_remaining_duration_only_short" msgid="5329694252258605547">"<xliff:g id="TIME">%1$s</xliff:g> resterend"</string>
+ <!-- no translation found for power_discharge_by_enhanced (8788299408879961465) -->
+ <skip />
+ <!-- no translation found for power_discharge_by_only_enhanced (7692297898877104416) -->
+ <skip />
+ <!-- no translation found for power_discharge_by (6427074755635635749) -->
+ <skip />
+ <!-- no translation found for power_discharge_by_only (5888058889261108064) -->
+ <skip />
<string name="power_remaining_less_than_duration_only" msgid="5996752448813295329">"Minder dan <xliff:g id="THRESHOLD">%1$s</xliff:g> resterend"</string>
- <string name="power_remaining_less_than_duration" msgid="7967078125657859046">"<xliff:g id="LEVEL">%1$s</xliff:g> - Minder dan <xliff:g id="THRESHOLD">%2$s</xliff:g> resterend"</string>
- <string name="power_remaining_more_than_subtext" msgid="6846716609975752316">"<xliff:g id="LEVEL">%1$s</xliff:g> - meer dan <xliff:g id="TIME_REMAINING">%2$s</xliff:g> resterend"</string>
- <string name="power_remaining_only_more_than_subtext" msgid="8884488700395194194">"meer dan <xliff:g id="TIME_REMAINING">%1$s</xliff:g> resterend"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="default" msgid="8168317165722752881">"telefoon wordt binnenkort mogelijk uitgeschakeld"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="tablet" msgid="5957064378548718872">"tablet wordt binnenkort mogelijk uitgeschakeld"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="device" msgid="9055596817716471373">"apparaat wordt binnenkort mogelijk uitgeschakeld"</string>
- <string name="power_discharging_duration" msgid="2843747179907396142">"<xliff:g id="LEVEL">%1$s</xliff:g> - ongeveer <xliff:g id="TIME">%2$s</xliff:g> resterend"</string>
- <string name="power_discharging_duration_enhanced" msgid="4401782117770255046">"<xliff:g id="LEVEL">%1$s</xliff:g>: nog ongeveer <xliff:g id="TIME">%2$s</xliff:g> over op basis van je gebruik"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="default" msgid="7679005631124015335">"<xliff:g id="LEVEL">%1$s</xliff:g> - telefoon wordt binnenkort mogelijk uitgeschakeld"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="tablet" msgid="261050880878965621">"<xliff:g id="LEVEL">%1$s</xliff:g> - tablet wordt binnenkort mogelijk uitgeschakeld"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="device" msgid="2020049829798578618">"<xliff:g id="LEVEL">%1$s</xliff:g> - apparaat wordt binnenkort mogelijk uitgeschakeld"</string>
+ <!-- no translation found for power_remaining_less_than_duration (5751885147712659423) -->
+ <skip />
+ <!-- no translation found for power_remaining_more_than_subtext (3176771815132876675) -->
+ <skip />
+ <!-- no translation found for power_remaining_only_more_than_subtext (8931654680569617380) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (1181059207608751924) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (2606370266981054691) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (2918084807716859985) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (3090926004324573908) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (7466484148515796216) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (603933521600231649) -->
+ <skip />
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
+ <string name="power_remaining_charging_duration_only" msgid="1421102457410268886">"Nog <xliff:g id="TIME">%1$s</xliff:g> tot volledig opgeladen"</string>
<string name="power_charging_duration" msgid="4676999980973411875">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> tot volledig opgeladen"</string>
<string name="battery_info_status_unknown" msgid="196130600938058547">"Onbekend"</string>
<string name="battery_info_status_charging" msgid="1705179948350365604">"Opladen"</string>
diff --git a/packages/SettingsLib/res/values-or/strings.xml b/packages/SettingsLib/res/values-or/strings.xml
index 0c2cbda..ab7e9fa 100644
--- a/packages/SettingsLib/res/values-or/strings.xml
+++ b/packages/SettingsLib/res/values-or/strings.xml
@@ -233,7 +233,8 @@
<string name="select_private_dns_configuration_title" msgid="3700456559305263922">"ବ୍ୟକ୍ତିଗତ DNS"</string>
<string name="select_private_dns_configuration_dialog_title" msgid="9221994415765826811">"ବ୍ୟକ୍ତିଗତ DNS ମୋଡ୍ ବାଛନ୍ତୁ"</string>
<string name="private_dns_mode_off" msgid="8236575187318721684">"ଅଫ୍"</string>
- <string name="private_dns_mode_opportunistic" msgid="7608409735589131766">"ସୁଯୋଗବାଦୀ"</string>
+ <!-- no translation found for private_dns_mode_opportunistic (8314986739896927399) -->
+ <skip />
<string name="private_dns_mode_provider" msgid="8354935160639360804">"ବ୍ୟକ୍ତିଗତ DNS ପ୍ରଦାତା ହୋଷ୍ଟନାମ"</string>
<string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"DNS ପ୍ରଦାନକାରୀଙ୍କ ହୋଷ୍ଟନାମ ପ୍ରବେଶ କରନ୍ତୁ"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"ୱେୟାରଲେସ୍ ପ୍ରଦର୍ଶନ ସାର୍ଟିଫିକେସନ୍ ପାଇଁ ବିକଳ୍ପଗୁଡିକ ଦେଖାନ୍ତୁ"</string>
@@ -372,32 +373,42 @@
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"ଏହି ପରୀକ୍ଷାମୂଳକ ବୈଶିଷ୍ଟ୍ୟ ପର୍ଫର୍ମେନ୍ସକୁ ପ୍ରଭାବିତ କରିପାରେ।"</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"<xliff:g id="TITLE">%1$s</xliff:g> ଦ୍ୱାରା ଓଭର୍ରାଇଡ୍ କରାଯାଇଛି"</string>
<string name="power_remaining_duration_only" msgid="845431008899029842">"ପ୍ରାୟ <xliff:g id="TIME">%1$s</xliff:g> ଅବଶିଷ୍ଟ ରହିଛି"</string>
+ <!-- no translation found for power_discharging_duration (6655472132189365839) -->
+ <skip />
<string name="power_remaining_duration_only_enhanced" msgid="5992456722677973678">"ଆପଣଙ୍କ ବ୍ୟବହାରକୁ ଆଧାର କରି ପ୍ରାୟ <xliff:g id="TIME">%1$s</xliff:g> ଅବଶିଷ୍ଟ"</string>
- <string name="power_remaining_charging_duration_only" msgid="1421102457410268886">"ସମ୍ପୂର୍ଣ୍ଣ ଚାର୍ଜ ହେବାପାଇଁ <xliff:g id="TIME">%1$s</xliff:g> ଅବଶିଷ୍ଟ ଅଛି"</string>
+ <!-- no translation found for power_discharging_duration_enhanced (5726302316642148671) -->
+ <skip />
<string name="power_remaining_duration_only_short" msgid="5329694252258605547">"<xliff:g id="TIME">%1$s</xliff:g> ଅବଶିଷ୍ଟ"</string>
+ <!-- no translation found for power_discharge_by_enhanced (8788299408879961465) -->
+ <skip />
+ <!-- no translation found for power_discharge_by_only_enhanced (7692297898877104416) -->
+ <skip />
+ <!-- no translation found for power_discharge_by (6427074755635635749) -->
+ <skip />
+ <!-- no translation found for power_discharge_by_only (5888058889261108064) -->
+ <skip />
<!-- no translation found for power_remaining_less_than_duration_only (5996752448813295329) -->
<skip />
- <!-- no translation found for power_remaining_less_than_duration (7967078125657859046) -->
+ <!-- no translation found for power_remaining_less_than_duration (5751885147712659423) -->
<skip />
- <!-- no translation found for power_remaining_more_than_subtext (6846716609975752316) -->
+ <!-- no translation found for power_remaining_more_than_subtext (3176771815132876675) -->
<skip />
- <!-- no translation found for power_remaining_only_more_than_subtext (8884488700395194194) -->
+ <!-- no translation found for power_remaining_only_more_than_subtext (8931654680569617380) -->
<skip />
- <!-- no translation found for power_remaining_duration_only_shutdown_imminent (8168317165722752881) -->
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (1181059207608751924) -->
<skip />
- <!-- no translation found for power_remaining_duration_only_shutdown_imminent (5957064378548718872) -->
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (2606370266981054691) -->
<skip />
- <!-- no translation found for power_remaining_duration_only_shutdown_imminent (9055596817716471373) -->
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (2918084807716859985) -->
<skip />
- <string name="power_discharging_duration" msgid="2843747179907396142">"<xliff:g id="LEVEL">%1$s</xliff:g> - ପ୍ରାୟ <xliff:g id="TIME">%2$s</xliff:g> ଅବଶିଷ୍ଟ ରହିଛି"</string>
- <string name="power_discharging_duration_enhanced" msgid="4401782117770255046">"<xliff:g id="LEVEL">%1$s</xliff:g> - ଆପଣଙ୍କ ବ୍ୟବହାରକୁ ଆଧାର କରି ପ୍ରାୟ <xliff:g id="TIME">%2$s</xliff:g> ଅବଶିଷ୍ଟ"</string>
- <!-- no translation found for power_remaining_duration_shutdown_imminent (7679005631124015335) -->
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (3090926004324573908) -->
<skip />
- <!-- no translation found for power_remaining_duration_shutdown_imminent (261050880878965621) -->
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (7466484148515796216) -->
<skip />
- <!-- no translation found for power_remaining_duration_shutdown_imminent (2020049829798578618) -->
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (603933521600231649) -->
<skip />
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
+ <string name="power_remaining_charging_duration_only" msgid="1421102457410268886">"ସମ୍ପୂର୍ଣ୍ଣ ଚାର୍ଜ ହେବାପାଇଁ <xliff:g id="TIME">%1$s</xliff:g> ଅବଶିଷ୍ଟ ଅଛି"</string>
<string name="power_charging_duration" msgid="4676999980973411875">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> ପୂର୍ଣ୍ଣ ଚାର୍ଜ ହେବା ପର୍ଯ୍ୟନ୍ତ"</string>
<string name="battery_info_status_unknown" msgid="196130600938058547">"ଅଜ୍ଞାତ"</string>
<string name="battery_info_status_charging" msgid="1705179948350365604">"ଚାର୍ଜ ହେଉଛି"</string>
diff --git a/packages/SettingsLib/res/values-pa/strings.xml b/packages/SettingsLib/res/values-pa/strings.xml
index 6549861..2287d23 100644
--- a/packages/SettingsLib/res/values-pa/strings.xml
+++ b/packages/SettingsLib/res/values-pa/strings.xml
@@ -220,7 +220,8 @@
<string name="select_private_dns_configuration_title" msgid="3700456559305263922">"ਨਿੱਜੀ DNS"</string>
<string name="select_private_dns_configuration_dialog_title" msgid="9221994415765826811">"ਨਿੱਜੀ DNS ਮੋਡ ਚੁਣੋ"</string>
<string name="private_dns_mode_off" msgid="8236575187318721684">"ਬੰਦ"</string>
- <string name="private_dns_mode_opportunistic" msgid="7608409735589131766">"ਮੌਕਾਪ੍ਰਸਤ"</string>
+ <!-- no translation found for private_dns_mode_opportunistic (8314986739896927399) -->
+ <skip />
<string name="private_dns_mode_provider" msgid="8354935160639360804">"ਨਿੱਜੀ DNS ਪ੍ਰਦਾਨਕ ਹੋਸਟਨਾਮ"</string>
<string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"DNS ਪ੍ਰਦਾਨਕ ਦਾ ਹੋਸਟਨਾਮ ਦਾਖਲ ਕਰੋ"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"ਵਾਇਰਲੈੱਸ ਡਿਸਪਲੇ ਪ੍ਰਮਾਣੀਕਰਨ ਲਈ ਚੋਣਾਂ ਪ੍ਰਦਰਸ਼ਿਤ ਕਰੋ"</string>
@@ -356,22 +357,41 @@
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"ਇਹ ਵਿਸ਼ੇਸ਼ਤਾ ਪ੍ਰਯੋਗਾਤਮਿਕ ਹੈ ਅਤੇ ਪ੍ਰਦਰਸ਼ਨ ਤੇ ਅਸਰ ਪਾ ਸਕਦੀ ਹੈ।"</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"<xliff:g id="TITLE">%1$s</xliff:g> ਦੁਆਰਾ ਓਵਰਰਾਈਡ ਕੀਤਾ"</string>
<string name="power_remaining_duration_only" msgid="845431008899029842">"ਲਗਭਗ <xliff:g id="TIME">%1$s</xliff:g> ਬਾਕੀ"</string>
+ <!-- no translation found for power_discharging_duration (6655472132189365839) -->
+ <skip />
<string name="power_remaining_duration_only_enhanced" msgid="5992456722677973678">"ਤੁਹਾਡੀ ਵਰਤੋਂ ਦੇ ਆਧਾਰ \'ਤੇ ਲਗਭਗ <xliff:g id="TIME">%1$s</xliff:g> ਬਾਕੀ"</string>
- <string name="power_remaining_charging_duration_only" msgid="1421102457410268886">"ਪੂਰੀ ਤਰ੍ਹਾਂ ਚਾਰਜ ਹੋਣ ਲਈ <xliff:g id="TIME">%1$s</xliff:g> ਬਾਕੀ"</string>
+ <!-- no translation found for power_discharging_duration_enhanced (5726302316642148671) -->
+ <skip />
<string name="power_remaining_duration_only_short" msgid="5329694252258605547">"<xliff:g id="TIME">%1$s</xliff:g> ਬਾਕੀ"</string>
+ <!-- no translation found for power_discharge_by_enhanced (8788299408879961465) -->
+ <skip />
+ <!-- no translation found for power_discharge_by_only_enhanced (7692297898877104416) -->
+ <skip />
+ <!-- no translation found for power_discharge_by (6427074755635635749) -->
+ <skip />
+ <!-- no translation found for power_discharge_by_only (5888058889261108064) -->
+ <skip />
<string name="power_remaining_less_than_duration_only" msgid="5996752448813295329">"<xliff:g id="THRESHOLD">%1$s</xliff:g> ਤੋਂ ਘੱਟ ਸਮਾਂ ਬਾਕੀ"</string>
- <string name="power_remaining_less_than_duration" msgid="7967078125657859046">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="THRESHOLD">%2$s</xliff:g> ਤੋਂ ਘੱਟ ਸਮਾਂ ਬਾਕੀ"</string>
- <string name="power_remaining_more_than_subtext" msgid="6846716609975752316">"<xliff:g id="LEVEL">%1$s</xliff:g><xliff:g id="TIME_REMAINING">%2$s</xliff:g> ਤੋਂ ਵੱਧ ਸਮਾਂ ਬਾਕੀ"</string>
- <string name="power_remaining_only_more_than_subtext" msgid="8884488700395194194">"<xliff:g id="TIME_REMAINING">%1$s</xliff:g> ਤੋਂ ਵੱਧ ਸਮਾਂ ਬਾਕੀ"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="default" msgid="8168317165722752881">"ਫ਼ੋਨ ਛੇਤੀ ਹੀ ਬੰਦ ਹੋ ਸਕਦਾ ਹੈ"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="tablet" msgid="5957064378548718872">"ਟੈਬਲੈੱਟ ਛੇਤੀ ਹੀ ਬੰਦ ਹੋ ਸਕਦਾ ਹੈ"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="device" msgid="9055596817716471373">"ਡੀਵਾਈਸ ਛੇਤੀ ਹੀ ਬੰਦ ਹੋ ਸਕਦਾ ਹੈ"</string>
- <string name="power_discharging_duration" msgid="2843747179907396142">"<xliff:g id="LEVEL">%1$s</xliff:g> - ਲਗਭਗ <xliff:g id="TIME">%2$s</xliff:g> ਬਾਕੀ"</string>
- <string name="power_discharging_duration_enhanced" msgid="4401782117770255046">"<xliff:g id="LEVEL">%1$s</xliff:g> - ਤੁਹਾਡੀ ਵਰਤੋਂ ਦੇ ਆਧਾਰ \'ਤੇ ਲਗਭਗ <xliff:g id="TIME">%2$s</xliff:g> ਬਾਕੀ"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="default" msgid="7679005631124015335">"<xliff:g id="LEVEL">%1$s</xliff:g> - ਫ਼ੋਨ ਛੇਤੀ ਹੀ ਬੰਦ ਹੋ ਸਕਦਾ ਹੈ"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="tablet" msgid="261050880878965621">"<xliff:g id="LEVEL">%1$s</xliff:g> - ਟੈਬਲੈੱਟ ਛੇਤੀ ਹੀ ਬੰਦ ਹੋ ਸਕਦਾ ਹੈ"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="device" msgid="2020049829798578618">"<xliff:g id="LEVEL">%1$s</xliff:g> - ਡੀਵਾਈਸ ਛੇਤੀ ਹੀ ਬੰਦ ਹੋ ਸਕਦਾ ਹੈ"</string>
+ <!-- no translation found for power_remaining_less_than_duration (5751885147712659423) -->
+ <skip />
+ <!-- no translation found for power_remaining_more_than_subtext (3176771815132876675) -->
+ <skip />
+ <!-- no translation found for power_remaining_only_more_than_subtext (8931654680569617380) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (1181059207608751924) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (2606370266981054691) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (2918084807716859985) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (3090926004324573908) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (7466484148515796216) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (603933521600231649) -->
+ <skip />
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
+ <string name="power_remaining_charging_duration_only" msgid="1421102457410268886">"ਪੂਰੀ ਤਰ੍ਹਾਂ ਚਾਰਜ ਹੋਣ ਲਈ <xliff:g id="TIME">%1$s</xliff:g> ਬਾਕੀ"</string>
<string name="power_charging_duration" msgid="4676999980973411875">"ਪੂਰੀ ਤਰ੍ਹਾਂ ਚਾਰਜ ਹੋਣ ਤੱਕ <xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g>"</string>
<string name="battery_info_status_unknown" msgid="196130600938058547">"ਅਗਿਆਤ"</string>
<string name="battery_info_status_charging" msgid="1705179948350365604">"ਚਾਰਜ ਹੋ ਰਿਹਾ ਹੈ"</string>
diff --git a/packages/SettingsLib/res/values-pl/strings.xml b/packages/SettingsLib/res/values-pl/strings.xml
index c7deb56..45c44c6 100644
--- a/packages/SettingsLib/res/values-pl/strings.xml
+++ b/packages/SettingsLib/res/values-pl/strings.xml
@@ -220,7 +220,8 @@
<string name="select_private_dns_configuration_title" msgid="3700456559305263922">"Prywatny DNS"</string>
<string name="select_private_dns_configuration_dialog_title" msgid="9221994415765826811">"Wybierz tryb prywatnego DNS"</string>
<string name="private_dns_mode_off" msgid="8236575187318721684">"Wyłączony"</string>
- <string name="private_dns_mode_opportunistic" msgid="7608409735589131766">"Oportunistyczny"</string>
+ <!-- no translation found for private_dns_mode_opportunistic (8314986739896927399) -->
+ <skip />
<string name="private_dns_mode_provider" msgid="8354935160639360804">"Nazwa hosta dostawcy prywatnego DNS"</string>
<string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"Wpisz nazwę hosta dostawcy DNS"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Pokaż opcje certyfikacji wyświetlacza bezprzewodowego"</string>
@@ -356,22 +357,41 @@
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"To jest funkcja eksperymentalna i może wpływać na działanie urządzenia."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"Nadpisana przez <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="power_remaining_duration_only" msgid="845431008899029842">"Pozostało: <xliff:g id="TIME">%1$s</xliff:g>"</string>
+ <!-- no translation found for power_discharging_duration (6655472132189365839) -->
+ <skip />
<string name="power_remaining_duration_only_enhanced" msgid="5992456722677973678">"Jeszcze około <xliff:g id="TIME">%1$s</xliff:g> (na podstawie Twojego sposobu korzystania)"</string>
- <string name="power_remaining_charging_duration_only" msgid="1421102457410268886">"<xliff:g id="TIME">%1$s</xliff:g> do pełnego naładowania"</string>
+ <!-- no translation found for power_discharging_duration_enhanced (5726302316642148671) -->
+ <skip />
<string name="power_remaining_duration_only_short" msgid="5329694252258605547">"Zostało <xliff:g id="TIME">%1$s</xliff:g>"</string>
+ <!-- no translation found for power_discharge_by_enhanced (8788299408879961465) -->
+ <skip />
+ <!-- no translation found for power_discharge_by_only_enhanced (7692297898877104416) -->
+ <skip />
+ <!-- no translation found for power_discharge_by (6427074755635635749) -->
+ <skip />
+ <!-- no translation found for power_discharge_by_only (5888058889261108064) -->
+ <skip />
<string name="power_remaining_less_than_duration_only" msgid="5996752448813295329">"Pozostało mniej niż <xliff:g id="THRESHOLD">%1$s</xliff:g>"</string>
- <string name="power_remaining_less_than_duration" msgid="7967078125657859046">"<xliff:g id="LEVEL">%1$s</xliff:g> – pozostało mniej niż <xliff:g id="THRESHOLD">%2$s</xliff:g>"</string>
- <string name="power_remaining_more_than_subtext" msgid="6846716609975752316">"<xliff:g id="LEVEL">%1$s</xliff:g> – pozostało ponad <xliff:g id="TIME_REMAINING">%2$s</xliff:g>"</string>
- <string name="power_remaining_only_more_than_subtext" msgid="8884488700395194194">"pozostało ponad <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="default" msgid="8168317165722752881">"telefon może się wkrótce wyłączyć"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="tablet" msgid="5957064378548718872">"tablet może się wkrótce wyłączyć"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="device" msgid="9055596817716471373">"urządzenie może się wkrótce wyłączyć"</string>
- <string name="power_discharging_duration" msgid="2843747179907396142">"<xliff:g id="LEVEL">%1$s</xliff:g> – pozostało około <xliff:g id="TIME">%2$s</xliff:g>"</string>
- <string name="power_discharging_duration_enhanced" msgid="4401782117770255046">"<xliff:g id="LEVEL">%1$s</xliff:g> – jeszcze około <xliff:g id="TIME">%2$s</xliff:g> (na podstawie Twojego sposobu korzystania)"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="default" msgid="7679005631124015335">"<xliff:g id="LEVEL">%1$s</xliff:g> – telefon może się wkrótce wyłączyć"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="tablet" msgid="261050880878965621">"<xliff:g id="LEVEL">%1$s</xliff:g> – tablet może się wkrótce wyłączyć"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="device" msgid="2020049829798578618">"<xliff:g id="LEVEL">%1$s</xliff:g> – urządzenie może się wkrótce wyłączyć"</string>
+ <!-- no translation found for power_remaining_less_than_duration (5751885147712659423) -->
+ <skip />
+ <!-- no translation found for power_remaining_more_than_subtext (3176771815132876675) -->
+ <skip />
+ <!-- no translation found for power_remaining_only_more_than_subtext (8931654680569617380) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (1181059207608751924) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (2606370266981054691) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (2918084807716859985) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (3090926004324573908) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (7466484148515796216) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (603933521600231649) -->
+ <skip />
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string>
+ <string name="power_remaining_charging_duration_only" msgid="1421102457410268886">"<xliff:g id="TIME">%1$s</xliff:g> do pełnego naładowania"</string>
<string name="power_charging_duration" msgid="4676999980973411875">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> do pełnego naładowania"</string>
<string name="battery_info_status_unknown" msgid="196130600938058547">"Nieznane"</string>
<string name="battery_info_status_charging" msgid="1705179948350365604">"Ładowanie"</string>
diff --git a/packages/SettingsLib/res/values-pt-rBR/strings.xml b/packages/SettingsLib/res/values-pt-rBR/strings.xml
index 7693a54..bc9c82e 100644
--- a/packages/SettingsLib/res/values-pt-rBR/strings.xml
+++ b/packages/SettingsLib/res/values-pt-rBR/strings.xml
@@ -135,7 +135,7 @@
<string name="tts_settings_title" msgid="1237820681016639683">"Conversão de texto em voz"</string>
<string name="tts_default_rate_title" msgid="6030550998379310088">"Taxa de fala"</string>
<string name="tts_default_rate_summary" msgid="4061815292287182801">"Velocidade em que o texto é falado"</string>
- <string name="tts_default_pitch_title" msgid="6135942113172488671">"Frequência do som"</string>
+ <string name="tts_default_pitch_title" msgid="6135942113172488671">"Tom da fala"</string>
<string name="tts_default_pitch_summary" msgid="1944885882882650009">"Afeta o tom da voz sintetizada"</string>
<string name="tts_default_lang_title" msgid="8018087612299820556">"Idioma"</string>
<string name="tts_lang_use_system" msgid="2679252467416513208">"Usar idioma do sistema"</string>
@@ -157,7 +157,7 @@
<string name="tts_engine_settings_button" msgid="1030512042040722285">"Iniciar configurações do mecanismo"</string>
<string name="tts_engine_preference_section_title" msgid="448294500990971413">"Mecanismo preferencial"</string>
<string name="tts_general_section_title" msgid="4402572014604490502">"Gerais"</string>
- <string name="tts_reset_speech_pitch_title" msgid="5789394019544785915">"Redefinir a frequência do som da fala"</string>
+ <string name="tts_reset_speech_pitch_title" msgid="5789394019544785915">"Redefinir o tom da fala"</string>
<string name="tts_reset_speech_pitch_summary" msgid="8700539616245004418">"Redefinir o tom no qual o texto é falado para o padrão."</string>
<string-array name="tts_rate_entries">
<item msgid="6695494874362656215">"Muito devagar"</item>
@@ -220,7 +220,8 @@
<string name="select_private_dns_configuration_title" msgid="3700456559305263922">"DNS particular"</string>
<string name="select_private_dns_configuration_dialog_title" msgid="9221994415765826811">"Selecione o modo DNS particular"</string>
<string name="private_dns_mode_off" msgid="8236575187318721684">"Desativado"</string>
- <string name="private_dns_mode_opportunistic" msgid="7608409735589131766">"Oportunista"</string>
+ <!-- no translation found for private_dns_mode_opportunistic (8314986739896927399) -->
+ <skip />
<string name="private_dns_mode_provider" msgid="8354935160639360804">"Nome do host do provedor de DNS particular"</string>
<string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"Informe o nome do host do provedor de DNS"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Mostrar opções de certificação de Display sem fio"</string>
@@ -356,22 +357,41 @@
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Este recurso é experimental e pode afetar o desempenho."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"Substituído por <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="power_remaining_duration_only" msgid="845431008899029842">"Cerca de <xliff:g id="TIME">%1$s</xliff:g> restante(s)"</string>
+ <!-- no translation found for power_discharging_duration (6655472132189365839) -->
+ <skip />
<string name="power_remaining_duration_only_enhanced" msgid="5992456722677973678">"Cerca de <xliff:g id="TIME">%1$s</xliff:g> restante(s) com base no seu uso"</string>
- <string name="power_remaining_charging_duration_only" msgid="1421102457410268886">"<xliff:g id="TIME">%1$s</xliff:g> restante(s) até a carga completa"</string>
+ <!-- no translation found for power_discharging_duration_enhanced (5726302316642148671) -->
+ <skip />
<string name="power_remaining_duration_only_short" msgid="5329694252258605547">"<xliff:g id="TIME">%1$s</xliff:g> restante(s)"</string>
+ <!-- no translation found for power_discharge_by_enhanced (8788299408879961465) -->
+ <skip />
+ <!-- no translation found for power_discharge_by_only_enhanced (7692297898877104416) -->
+ <skip />
+ <!-- no translation found for power_discharge_by (6427074755635635749) -->
+ <skip />
+ <!-- no translation found for power_discharge_by_only (5888058889261108064) -->
+ <skip />
<string name="power_remaining_less_than_duration_only" msgid="5996752448813295329">"Menos de <xliff:g id="THRESHOLD">%1$s</xliff:g> restante(s)"</string>
- <string name="power_remaining_less_than_duration" msgid="7967078125657859046">"<xliff:g id="LEVEL">%1$s</xliff:g>: menos de <xliff:g id="THRESHOLD">%2$s</xliff:g> restante(s)"</string>
- <string name="power_remaining_more_than_subtext" msgid="6846716609975752316">"<xliff:g id="LEVEL">%1$s</xliff:g>mais de <xliff:g id="TIME_REMAINING">%2$s</xliff:g> restante(s)"</string>
- <string name="power_remaining_only_more_than_subtext" msgid="8884488700395194194">"mais de <xliff:g id="TIME_REMAINING">%1$s</xliff:g> restante(s)"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="default" msgid="8168317165722752881">"o smartphone pode ser desligado em breve"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="tablet" msgid="5957064378548718872">"o tablet pode ser desligado em breve"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="device" msgid="9055596817716471373">"o dispositivo pode ser desligado em breve"</string>
- <string name="power_discharging_duration" msgid="2843747179907396142">"<xliff:g id="LEVEL">%1$s</xliff:g> - cerca de <xliff:g id="TIME">%2$s</xliff:g> restante(s)"</string>
- <string name="power_discharging_duration_enhanced" msgid="4401782117770255046">"<xliff:g id="LEVEL">%1$s</xliff:g>: cerca de <xliff:g id="TIME">%2$s</xliff:g> restante(s) com base no seu uso"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="default" msgid="7679005631124015335">"<xliff:g id="LEVEL">%1$s</xliff:g>: o smartphone pode ser desligado em breve"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="tablet" msgid="261050880878965621">"<xliff:g id="LEVEL">%1$s</xliff:g>: o tablet pode ser desligado em breve"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="device" msgid="2020049829798578618">"<xliff:g id="LEVEL">%1$s</xliff:g>: o dispositivo pode ser desligado em breve"</string>
+ <!-- no translation found for power_remaining_less_than_duration (5751885147712659423) -->
+ <skip />
+ <!-- no translation found for power_remaining_more_than_subtext (3176771815132876675) -->
+ <skip />
+ <!-- no translation found for power_remaining_only_more_than_subtext (8931654680569617380) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (1181059207608751924) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (2606370266981054691) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (2918084807716859985) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (3090926004324573908) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (7466484148515796216) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (603933521600231649) -->
+ <skip />
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
+ <string name="power_remaining_charging_duration_only" msgid="1421102457410268886">"<xliff:g id="TIME">%1$s</xliff:g> restante(s) até a carga completa"</string>
<string name="power_charging_duration" msgid="4676999980973411875">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> até a carga completa"</string>
<string name="battery_info_status_unknown" msgid="196130600938058547">"Desconhecido"</string>
<string name="battery_info_status_charging" msgid="1705179948350365604">"Carregando"</string>
diff --git a/packages/SettingsLib/res/values-pt-rPT/strings.xml b/packages/SettingsLib/res/values-pt-rPT/strings.xml
index a4987a1..5b2ad1d 100644
--- a/packages/SettingsLib/res/values-pt-rPT/strings.xml
+++ b/packages/SettingsLib/res/values-pt-rPT/strings.xml
@@ -220,7 +220,8 @@
<string name="select_private_dns_configuration_title" msgid="3700456559305263922">"DNS privado"</string>
<string name="select_private_dns_configuration_dialog_title" msgid="9221994415765826811">"Selecionar modo DNS privado"</string>
<string name="private_dns_mode_off" msgid="8236575187318721684">"Desativado"</string>
- <string name="private_dns_mode_opportunistic" msgid="7608409735589131766">"Oportunista"</string>
+ <!-- no translation found for private_dns_mode_opportunistic (8314986739896927399) -->
+ <skip />
<string name="private_dns_mode_provider" msgid="8354935160639360804">"Nome de anfitrião do fornecedor DNS privado"</string>
<string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"Introduza o nome de anfitrião do fornecedor DNS."</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Mostrar opções da certificação de display sem fios"</string>
@@ -356,22 +357,41 @@
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Esta funcionalidade é experimental e pode afetar o desempenho."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"Substituído por <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="power_remaining_duration_only" msgid="845431008899029842">"Falta(m) cerca de <xliff:g id="TIME">%1$s</xliff:g>"</string>
+ <!-- no translation found for power_discharging_duration (6655472132189365839) -->
+ <skip />
<string name="power_remaining_duration_only_enhanced" msgid="5992456722677973678">"Resta(m) cerca de <xliff:g id="TIME">%1$s</xliff:g> com base na sua utilização"</string>
- <string name="power_remaining_charging_duration_only" msgid="1421102457410268886">"Falta(m) <xliff:g id="TIME">%1$s</xliff:g> para concluir o carregamento"</string>
+ <!-- no translation found for power_discharging_duration_enhanced (5726302316642148671) -->
+ <skip />
<string name="power_remaining_duration_only_short" msgid="5329694252258605547">"Resta(m) <xliff:g id="TIME">%1$s</xliff:g>"</string>
+ <!-- no translation found for power_discharge_by_enhanced (8788299408879961465) -->
+ <skip />
+ <!-- no translation found for power_discharge_by_only_enhanced (7692297898877104416) -->
+ <skip />
+ <!-- no translation found for power_discharge_by (6427074755635635749) -->
+ <skip />
+ <!-- no translation found for power_discharge_by_only (5888058889261108064) -->
+ <skip />
<string name="power_remaining_less_than_duration_only" msgid="5996752448813295329">"Resta(m) menos de <xliff:g id="THRESHOLD">%1$s</xliff:g>."</string>
- <string name="power_remaining_less_than_duration" msgid="7967078125657859046">"<xliff:g id="LEVEL">%1$s</xliff:g> – Resta(m) menos de <xliff:g id="THRESHOLD">%2$s</xliff:g>."</string>
- <string name="power_remaining_more_than_subtext" msgid="6846716609975752316">"<xliff:g id="LEVEL">%1$s</xliff:g> – Resta(m) mais de <xliff:g id="TIME_REMAINING">%2$s</xliff:g>."</string>
- <string name="power_remaining_only_more_than_subtext" msgid="8884488700395194194">"Resta(m) mais de <xliff:g id="TIME_REMAINING">%1$s</xliff:g>."</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="default" msgid="8168317165722752881">"O telemóvel poderá ser encerrado em breve."</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="tablet" msgid="5957064378548718872">"O tablet poderá ser encerrado em breve."</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="device" msgid="9055596817716471373">"O dispositivo poderá ser encerrado em breve."</string>
- <string name="power_discharging_duration" msgid="2843747179907396142">"<xliff:g id="LEVEL">%1$s</xliff:g> – falta(m) cerca de <xliff:g id="TIME">%2$s</xliff:g>"</string>
- <string name="power_discharging_duration_enhanced" msgid="4401782117770255046">"<xliff:g id="LEVEL">%1$s</xliff:g> – resta(m) cerca de <xliff:g id="TIME">%2$s</xliff:g> com base na sua utilização"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="default" msgid="7679005631124015335">"<xliff:g id="LEVEL">%1$s</xliff:g> – O telemóvel poderá ser encerrado em breve."</string>
- <string name="power_remaining_duration_shutdown_imminent" product="tablet" msgid="261050880878965621">"<xliff:g id="LEVEL">%1$s</xliff:g> – O tablet poderá ser encerrado em breve."</string>
- <string name="power_remaining_duration_shutdown_imminent" product="device" msgid="2020049829798578618">"<xliff:g id="LEVEL">%1$s</xliff:g> – O dispositivo poderá ser encerrado em breve."</string>
+ <!-- no translation found for power_remaining_less_than_duration (5751885147712659423) -->
+ <skip />
+ <!-- no translation found for power_remaining_more_than_subtext (3176771815132876675) -->
+ <skip />
+ <!-- no translation found for power_remaining_only_more_than_subtext (8931654680569617380) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (1181059207608751924) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (2606370266981054691) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (2918084807716859985) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (3090926004324573908) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (7466484148515796216) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (603933521600231649) -->
+ <skip />
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string>
+ <string name="power_remaining_charging_duration_only" msgid="1421102457410268886">"Falta(m) <xliff:g id="TIME">%1$s</xliff:g> para concluir o carregamento"</string>
<string name="power_charging_duration" msgid="4676999980973411875">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> até ficar totalmente carregada"</string>
<string name="battery_info_status_unknown" msgid="196130600938058547">"Desconhecido"</string>
<string name="battery_info_status_charging" msgid="1705179948350365604">"A carregar"</string>
diff --git a/packages/SettingsLib/res/values-pt/strings.xml b/packages/SettingsLib/res/values-pt/strings.xml
index 7693a54..bc9c82e 100644
--- a/packages/SettingsLib/res/values-pt/strings.xml
+++ b/packages/SettingsLib/res/values-pt/strings.xml
@@ -135,7 +135,7 @@
<string name="tts_settings_title" msgid="1237820681016639683">"Conversão de texto em voz"</string>
<string name="tts_default_rate_title" msgid="6030550998379310088">"Taxa de fala"</string>
<string name="tts_default_rate_summary" msgid="4061815292287182801">"Velocidade em que o texto é falado"</string>
- <string name="tts_default_pitch_title" msgid="6135942113172488671">"Frequência do som"</string>
+ <string name="tts_default_pitch_title" msgid="6135942113172488671">"Tom da fala"</string>
<string name="tts_default_pitch_summary" msgid="1944885882882650009">"Afeta o tom da voz sintetizada"</string>
<string name="tts_default_lang_title" msgid="8018087612299820556">"Idioma"</string>
<string name="tts_lang_use_system" msgid="2679252467416513208">"Usar idioma do sistema"</string>
@@ -157,7 +157,7 @@
<string name="tts_engine_settings_button" msgid="1030512042040722285">"Iniciar configurações do mecanismo"</string>
<string name="tts_engine_preference_section_title" msgid="448294500990971413">"Mecanismo preferencial"</string>
<string name="tts_general_section_title" msgid="4402572014604490502">"Gerais"</string>
- <string name="tts_reset_speech_pitch_title" msgid="5789394019544785915">"Redefinir a frequência do som da fala"</string>
+ <string name="tts_reset_speech_pitch_title" msgid="5789394019544785915">"Redefinir o tom da fala"</string>
<string name="tts_reset_speech_pitch_summary" msgid="8700539616245004418">"Redefinir o tom no qual o texto é falado para o padrão."</string>
<string-array name="tts_rate_entries">
<item msgid="6695494874362656215">"Muito devagar"</item>
@@ -220,7 +220,8 @@
<string name="select_private_dns_configuration_title" msgid="3700456559305263922">"DNS particular"</string>
<string name="select_private_dns_configuration_dialog_title" msgid="9221994415765826811">"Selecione o modo DNS particular"</string>
<string name="private_dns_mode_off" msgid="8236575187318721684">"Desativado"</string>
- <string name="private_dns_mode_opportunistic" msgid="7608409735589131766">"Oportunista"</string>
+ <!-- no translation found for private_dns_mode_opportunistic (8314986739896927399) -->
+ <skip />
<string name="private_dns_mode_provider" msgid="8354935160639360804">"Nome do host do provedor de DNS particular"</string>
<string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"Informe o nome do host do provedor de DNS"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Mostrar opções de certificação de Display sem fio"</string>
@@ -356,22 +357,41 @@
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Este recurso é experimental e pode afetar o desempenho."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"Substituído por <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="power_remaining_duration_only" msgid="845431008899029842">"Cerca de <xliff:g id="TIME">%1$s</xliff:g> restante(s)"</string>
+ <!-- no translation found for power_discharging_duration (6655472132189365839) -->
+ <skip />
<string name="power_remaining_duration_only_enhanced" msgid="5992456722677973678">"Cerca de <xliff:g id="TIME">%1$s</xliff:g> restante(s) com base no seu uso"</string>
- <string name="power_remaining_charging_duration_only" msgid="1421102457410268886">"<xliff:g id="TIME">%1$s</xliff:g> restante(s) até a carga completa"</string>
+ <!-- no translation found for power_discharging_duration_enhanced (5726302316642148671) -->
+ <skip />
<string name="power_remaining_duration_only_short" msgid="5329694252258605547">"<xliff:g id="TIME">%1$s</xliff:g> restante(s)"</string>
+ <!-- no translation found for power_discharge_by_enhanced (8788299408879961465) -->
+ <skip />
+ <!-- no translation found for power_discharge_by_only_enhanced (7692297898877104416) -->
+ <skip />
+ <!-- no translation found for power_discharge_by (6427074755635635749) -->
+ <skip />
+ <!-- no translation found for power_discharge_by_only (5888058889261108064) -->
+ <skip />
<string name="power_remaining_less_than_duration_only" msgid="5996752448813295329">"Menos de <xliff:g id="THRESHOLD">%1$s</xliff:g> restante(s)"</string>
- <string name="power_remaining_less_than_duration" msgid="7967078125657859046">"<xliff:g id="LEVEL">%1$s</xliff:g>: menos de <xliff:g id="THRESHOLD">%2$s</xliff:g> restante(s)"</string>
- <string name="power_remaining_more_than_subtext" msgid="6846716609975752316">"<xliff:g id="LEVEL">%1$s</xliff:g>mais de <xliff:g id="TIME_REMAINING">%2$s</xliff:g> restante(s)"</string>
- <string name="power_remaining_only_more_than_subtext" msgid="8884488700395194194">"mais de <xliff:g id="TIME_REMAINING">%1$s</xliff:g> restante(s)"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="default" msgid="8168317165722752881">"o smartphone pode ser desligado em breve"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="tablet" msgid="5957064378548718872">"o tablet pode ser desligado em breve"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="device" msgid="9055596817716471373">"o dispositivo pode ser desligado em breve"</string>
- <string name="power_discharging_duration" msgid="2843747179907396142">"<xliff:g id="LEVEL">%1$s</xliff:g> - cerca de <xliff:g id="TIME">%2$s</xliff:g> restante(s)"</string>
- <string name="power_discharging_duration_enhanced" msgid="4401782117770255046">"<xliff:g id="LEVEL">%1$s</xliff:g>: cerca de <xliff:g id="TIME">%2$s</xliff:g> restante(s) com base no seu uso"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="default" msgid="7679005631124015335">"<xliff:g id="LEVEL">%1$s</xliff:g>: o smartphone pode ser desligado em breve"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="tablet" msgid="261050880878965621">"<xliff:g id="LEVEL">%1$s</xliff:g>: o tablet pode ser desligado em breve"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="device" msgid="2020049829798578618">"<xliff:g id="LEVEL">%1$s</xliff:g>: o dispositivo pode ser desligado em breve"</string>
+ <!-- no translation found for power_remaining_less_than_duration (5751885147712659423) -->
+ <skip />
+ <!-- no translation found for power_remaining_more_than_subtext (3176771815132876675) -->
+ <skip />
+ <!-- no translation found for power_remaining_only_more_than_subtext (8931654680569617380) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (1181059207608751924) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (2606370266981054691) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (2918084807716859985) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (3090926004324573908) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (7466484148515796216) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (603933521600231649) -->
+ <skip />
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
+ <string name="power_remaining_charging_duration_only" msgid="1421102457410268886">"<xliff:g id="TIME">%1$s</xliff:g> restante(s) até a carga completa"</string>
<string name="power_charging_duration" msgid="4676999980973411875">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> até a carga completa"</string>
<string name="battery_info_status_unknown" msgid="196130600938058547">"Desconhecido"</string>
<string name="battery_info_status_charging" msgid="1705179948350365604">"Carregando"</string>
diff --git a/packages/SettingsLib/res/values-ro/strings.xml b/packages/SettingsLib/res/values-ro/strings.xml
index 1db376e..4af2ba15 100644
--- a/packages/SettingsLib/res/values-ro/strings.xml
+++ b/packages/SettingsLib/res/values-ro/strings.xml
@@ -220,7 +220,8 @@
<string name="select_private_dns_configuration_title" msgid="3700456559305263922">"DNS privat"</string>
<string name="select_private_dns_configuration_dialog_title" msgid="9221994415765826811">"Selectați modul DNS privat"</string>
<string name="private_dns_mode_off" msgid="8236575187318721684">"Dezactivat"</string>
- <string name="private_dns_mode_opportunistic" msgid="7608409735589131766">"Oportunist"</string>
+ <!-- no translation found for private_dns_mode_opportunistic (8314986739896927399) -->
+ <skip />
<string name="private_dns_mode_provider" msgid="8354935160639360804">"Nume de gazdă al furnizorului de DNS privat"</string>
<string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"Introduceți numele de gazdă al furnizorului de DNS"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Afișați opțiunile pentru certificarea Ecran wireless"</string>
@@ -356,22 +357,41 @@
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Această funcție este experimentală și poate afecta performanțele."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"Valoare înlocuită de <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="power_remaining_duration_only" msgid="845431008899029842">"Timp rămas: aproximativ <xliff:g id="TIME">%1$s</xliff:g>"</string>
+ <!-- no translation found for power_discharging_duration (6655472132189365839) -->
+ <skip />
<string name="power_remaining_duration_only_enhanced" msgid="5992456722677973678">"În baza utilizării, timpul aproximativ rămas este: <xliff:g id="TIME">%1$s</xliff:g>"</string>
- <string name="power_remaining_charging_duration_only" msgid="1421102457410268886">"Timp rămas până la încărcarea completă: <xliff:g id="TIME">%1$s</xliff:g>"</string>
+ <!-- no translation found for power_discharging_duration_enhanced (5726302316642148671) -->
+ <skip />
<string name="power_remaining_duration_only_short" msgid="5329694252258605547">"Timp rămas: <xliff:g id="TIME">%1$s</xliff:g>"</string>
+ <!-- no translation found for power_discharge_by_enhanced (8788299408879961465) -->
+ <skip />
+ <!-- no translation found for power_discharge_by_only_enhanced (7692297898877104416) -->
+ <skip />
+ <!-- no translation found for power_discharge_by (6427074755635635749) -->
+ <skip />
+ <!-- no translation found for power_discharge_by_only (5888058889261108064) -->
+ <skip />
<string name="power_remaining_less_than_duration_only" msgid="5996752448813295329">"a mai rămas mai puțin de <xliff:g id="THRESHOLD">%1$s</xliff:g>"</string>
- <string name="power_remaining_less_than_duration" msgid="7967078125657859046">"<xliff:g id="LEVEL">%1$s</xliff:g> - a mai rămas mai puțin de <xliff:g id="THRESHOLD">%2$s</xliff:g>"</string>
- <string name="power_remaining_more_than_subtext" msgid="6846716609975752316">"<xliff:g id="LEVEL">%1$s</xliff:g> - a mai rămas mai mult de <xliff:g id="TIME_REMAINING">%2$s</xliff:g>"</string>
- <string name="power_remaining_only_more_than_subtext" msgid="8884488700395194194">"a mai rămas mai mult de <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="default" msgid="8168317165722752881">"telefonul să poate închide în curând"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="tablet" msgid="5957064378548718872">"tableta se poate închide în curând"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="device" msgid="9055596817716471373">"dispozitivul se poate închide în curând"</string>
- <string name="power_discharging_duration" msgid="2843747179907396142">"<xliff:g id="LEVEL">%1$s</xliff:g> - încă aproximativ <xliff:g id="TIME">%2$s</xliff:g>"</string>
- <string name="power_discharging_duration_enhanced" msgid="4401782117770255046">"<xliff:g id="LEVEL">%1$s</xliff:g> – în baza utilizării, timpul aproximativ rămas este: <xliff:g id="TIME">%2$s</xliff:g>"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="default" msgid="7679005631124015335">"<xliff:g id="LEVEL">%1$s</xliff:g> - telefonul se poate închide în curând"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="tablet" msgid="261050880878965621">"<xliff:g id="LEVEL">%1$s</xliff:g> - tableta se poate închide în curând"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="device" msgid="2020049829798578618">"<xliff:g id="LEVEL">%1$s</xliff:g> - dispozitivul se poate închide în curând"</string>
+ <!-- no translation found for power_remaining_less_than_duration (5751885147712659423) -->
+ <skip />
+ <!-- no translation found for power_remaining_more_than_subtext (3176771815132876675) -->
+ <skip />
+ <!-- no translation found for power_remaining_only_more_than_subtext (8931654680569617380) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (1181059207608751924) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (2606370266981054691) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (2918084807716859985) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (3090926004324573908) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (7466484148515796216) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (603933521600231649) -->
+ <skip />
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
+ <string name="power_remaining_charging_duration_only" msgid="1421102457410268886">"Timp rămas până la încărcarea completă: <xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="4676999980973411875">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> până la încărcarea completă"</string>
<string name="battery_info_status_unknown" msgid="196130600938058547">"Necunoscut"</string>
<string name="battery_info_status_charging" msgid="1705179948350365604">"Se încarcă"</string>
diff --git a/packages/SettingsLib/res/values-ru/strings.xml b/packages/SettingsLib/res/values-ru/strings.xml
index be08b05..46d40aa 100644
--- a/packages/SettingsLib/res/values-ru/strings.xml
+++ b/packages/SettingsLib/res/values-ru/strings.xml
@@ -220,7 +220,8 @@
<string name="select_private_dns_configuration_title" msgid="3700456559305263922">"Персональный DNS-сервер"</string>
<string name="select_private_dns_configuration_dialog_title" msgid="9221994415765826811">"Выберите режим персонального DNS-сервера"</string>
<string name="private_dns_mode_off" msgid="8236575187318721684">"ВЫКЛ"</string>
- <string name="private_dns_mode_opportunistic" msgid="7608409735589131766">"Гибкий"</string>
+ <!-- no translation found for private_dns_mode_opportunistic (8314986739896927399) -->
+ <skip />
<string name="private_dns_mode_provider" msgid="8354935160639360804">"Имя хоста поставщика персонального DNS-сервера"</string>
<string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"Введите имя хоста поставщика услуг DNS"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Показывать параметры сертификации беспроводных мониторов"</string>
@@ -356,22 +357,41 @@
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Это экспериментальная функция, она может снизить производительность устройства."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"Новая настройка: <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="power_remaining_duration_only" msgid="845431008899029842">"Осталось примерно <xliff:g id="TIME">%1$s</xliff:g>"</string>
+ <!-- no translation found for power_discharging_duration (6655472132189365839) -->
+ <skip />
<string name="power_remaining_duration_only_enhanced" msgid="5992456722677973678">"Осталось примерно <xliff:g id="TIME">%1$s</xliff:g> при текущем уровне использования"</string>
- <string name="power_remaining_charging_duration_only" msgid="1421102457410268886">"Ещё <xliff:g id="TIME">%1$s</xliff:g> до полной зарядки"</string>
+ <!-- no translation found for power_discharging_duration_enhanced (5726302316642148671) -->
+ <skip />
<string name="power_remaining_duration_only_short" msgid="5329694252258605547">"Осталось: <xliff:g id="TIME">%1$s</xliff:g>"</string>
+ <!-- no translation found for power_discharge_by_enhanced (8788299408879961465) -->
+ <skip />
+ <!-- no translation found for power_discharge_by_only_enhanced (7692297898877104416) -->
+ <skip />
+ <!-- no translation found for power_discharge_by (6427074755635635749) -->
+ <skip />
+ <!-- no translation found for power_discharge_by_only (5888058889261108064) -->
+ <skip />
<string name="power_remaining_less_than_duration_only" msgid="5996752448813295329">"Осталось менее <xliff:g id="THRESHOLD">%1$s</xliff:g>"</string>
- <string name="power_remaining_less_than_duration" msgid="7967078125657859046">"Уровень заряда батареи <xliff:g id="LEVEL">%1$s</xliff:g>. Осталось менее <xliff:g id="THRESHOLD">%2$s</xliff:g>."</string>
- <string name="power_remaining_more_than_subtext" msgid="6846716609975752316">"Уровень заряда батареи <xliff:g id="LEVEL">%1$s</xliff:g>. Осталось более <xliff:g id="TIME_REMAINING">%2$s</xliff:g>."</string>
- <string name="power_remaining_only_more_than_subtext" msgid="8884488700395194194">"Осталось более <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="default" msgid="8168317165722752881">"телефон скоро завершит работу"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="tablet" msgid="5957064378548718872">"планшет скоро завершит работу"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="device" msgid="9055596817716471373">"устройство скоро завершит работу"</string>
- <string name="power_discharging_duration" msgid="2843747179907396142">"<xliff:g id="LEVEL">%1$s</xliff:g> – осталось примерно <xliff:g id="TIME">%2$s</xliff:g>"</string>
- <string name="power_discharging_duration_enhanced" msgid="4401782117770255046">"<xliff:g id="LEVEL">%1$s</xliff:g> (осталось примерно <xliff:g id="TIME">%2$s</xliff:g> при текущем уровне использования)"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="default" msgid="7679005631124015335">"Уровень заряда батареи <xliff:g id="LEVEL">%1$s</xliff:g>. Телефон скоро завершит работу."</string>
- <string name="power_remaining_duration_shutdown_imminent" product="tablet" msgid="261050880878965621">"Уровень заряда батареи <xliff:g id="LEVEL">%1$s</xliff:g>. Планшет скоро завершит работу."</string>
- <string name="power_remaining_duration_shutdown_imminent" product="device" msgid="2020049829798578618">"Уровень заряда батареи <xliff:g id="LEVEL">%1$s</xliff:g>. Устройство скоро завершит работу."</string>
+ <!-- no translation found for power_remaining_less_than_duration (5751885147712659423) -->
+ <skip />
+ <!-- no translation found for power_remaining_more_than_subtext (3176771815132876675) -->
+ <skip />
+ <!-- no translation found for power_remaining_only_more_than_subtext (8931654680569617380) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (1181059207608751924) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (2606370266981054691) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (2918084807716859985) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (3090926004324573908) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (7466484148515796216) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (603933521600231649) -->
+ <skip />
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string>
+ <string name="power_remaining_charging_duration_only" msgid="1421102457410268886">"Ещё <xliff:g id="TIME">%1$s</xliff:g> до полной зарядки"</string>
<string name="power_charging_duration" msgid="4676999980973411875">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> до полной зарядки"</string>
<string name="battery_info_status_unknown" msgid="196130600938058547">"Неизвестно"</string>
<string name="battery_info_status_charging" msgid="1705179948350365604">"Идет зарядка"</string>
diff --git a/packages/SettingsLib/res/values-si/strings.xml b/packages/SettingsLib/res/values-si/strings.xml
index 7d63e47..1b387c3 100644
--- a/packages/SettingsLib/res/values-si/strings.xml
+++ b/packages/SettingsLib/res/values-si/strings.xml
@@ -220,7 +220,8 @@
<string name="select_private_dns_configuration_title" msgid="3700456559305263922">"පුද්ගලික DNS"</string>
<string name="select_private_dns_configuration_dialog_title" msgid="9221994415765826811">"පුද්ගලික DNS ප්රකාරය තෝරන්න"</string>
<string name="private_dns_mode_off" msgid="8236575187318721684">"ක්රියාවිරහිතයි"</string>
- <string name="private_dns_mode_opportunistic" msgid="7608409735589131766">"අවස්ථාවාදී"</string>
+ <!-- no translation found for private_dns_mode_opportunistic (8314986739896927399) -->
+ <skip />
<string name="private_dns_mode_provider" msgid="8354935160639360804">"පුද්ගලික DNS සැපයුම්කරු සත්කාරක නම"</string>
<string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"DNS සැපයුම්කරුගේ සත්කාරක නම ඇතුළු කරන්න"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"නොරැහැන් සංදර්ශක සහතිකය සඳහා විකල්ප පෙන්වන්න"</string>
@@ -356,22 +357,41 @@
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"මෙම විශේෂාංගය පරීක්ෂණාත්මක සහ ඇතැම් විට ක්රියාකාරිත්වයට බලපෑ හැක."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"<xliff:g id="TITLE">%1$s</xliff:g> මගින් ඉක්මවන ලදී"</string>
<string name="power_remaining_duration_only" msgid="845431008899029842">"<xliff:g id="TIME">%1$s</xliff:g> පමණ ඉතිරියි"</string>
+ <!-- no translation found for power_discharging_duration (6655472132189365839) -->
+ <skip />
<string name="power_remaining_duration_only_enhanced" msgid="5992456722677973678">"ඔබගේ භාවිතය මත පදනම්ව <xliff:g id="TIME">%1$s</xliff:g> පමණ ඉතිරිව ඇත"</string>
- <string name="power_remaining_charging_duration_only" msgid="1421102457410268886">"පූර්ණව ආරෝපණය වන තෙක් <xliff:g id="TIME">%1$s</xliff:g> ඉතිරියි"</string>
+ <!-- no translation found for power_discharging_duration_enhanced (5726302316642148671) -->
+ <skip />
<string name="power_remaining_duration_only_short" msgid="5329694252258605547">"ඉතිරි <xliff:g id="TIME">%1$s</xliff:g>"</string>
+ <!-- no translation found for power_discharge_by_enhanced (8788299408879961465) -->
+ <skip />
+ <!-- no translation found for power_discharge_by_only_enhanced (7692297898877104416) -->
+ <skip />
+ <!-- no translation found for power_discharge_by (6427074755635635749) -->
+ <skip />
+ <!-- no translation found for power_discharge_by_only (5888058889261108064) -->
+ <skip />
<string name="power_remaining_less_than_duration_only" msgid="5996752448813295329">"<xliff:g id="THRESHOLD">%1$s</xliff:g>ට වඩා අඩුවෙන් ඉතිරිව ඇත"</string>
- <string name="power_remaining_less_than_duration" msgid="7967078125657859046">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="THRESHOLD">%2$s</xliff:g>ට වඩා අඩුවෙන් ඉතිරිව ඇත"</string>
- <string name="power_remaining_more_than_subtext" msgid="6846716609975752316">"<xliff:g id="LEVEL">%1$s</xliff:g><xliff:g id="TIME_REMAINING">%2$s</xliff:g>ට වඩා වැඩියෙන් ඉතිරිව ඇත"</string>
- <string name="power_remaining_only_more_than_subtext" msgid="8884488700395194194">"<xliff:g id="TIME_REMAINING">%1$s</xliff:g>ට වඩා වැඩියෙන් ඉතිරිව ඇත"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="default" msgid="8168317165722752881">"දුරකථනය ඉක්මනින් වැසිය හැකිය"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="tablet" msgid="5957064378548718872">"ටැබ්ලට් උපාංගය ඉක්මනින් වැසිය හැකිය"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="device" msgid="9055596817716471373">"උපාංගය ඉක්මනින් වැසිය හැකිය"</string>
- <string name="power_discharging_duration" msgid="2843747179907396142">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g>ක් පමණ ඇත"</string>
- <string name="power_discharging_duration_enhanced" msgid="4401782117770255046">"<xliff:g id="LEVEL">%1$s</xliff:g> - ඔබගේ භාවිතය මත පදනම්ව <xliff:g id="TIME">%2$s</xliff:g> පමණ ඉතිරිව ඇත"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="default" msgid="7679005631124015335">"<xliff:g id="LEVEL">%1$s</xliff:g> - දුරකථනය ඉක්මනින් වැසිය හැකිය"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="tablet" msgid="261050880878965621">"<xliff:g id="LEVEL">%1$s</xliff:g> - ටැබ්ලට් පරිගණකය ඉක්මනින් වැසිය හැකිය"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="device" msgid="2020049829798578618">"<xliff:g id="LEVEL">%1$s</xliff:g> - උපාංගය ඉක්මනින් වැසිය හැකිය"</string>
+ <!-- no translation found for power_remaining_less_than_duration (5751885147712659423) -->
+ <skip />
+ <!-- no translation found for power_remaining_more_than_subtext (3176771815132876675) -->
+ <skip />
+ <!-- no translation found for power_remaining_only_more_than_subtext (8931654680569617380) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (1181059207608751924) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (2606370266981054691) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (2918084807716859985) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (3090926004324573908) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (7466484148515796216) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (603933521600231649) -->
+ <skip />
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
+ <string name="power_remaining_charging_duration_only" msgid="1421102457410268886">"පූර්ණව ආරෝපණය වන තෙක් <xliff:g id="TIME">%1$s</xliff:g> ඉතිරියි"</string>
<string name="power_charging_duration" msgid="4676999980973411875">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> සම්පූර්ණයෙන් ආරෝපණය වන තෙක්"</string>
<string name="battery_info_status_unknown" msgid="196130600938058547">"නොදනී"</string>
<string name="battery_info_status_charging" msgid="1705179948350365604">"ආරෝපණය වෙමින්"</string>
diff --git a/packages/SettingsLib/res/values-sk/strings.xml b/packages/SettingsLib/res/values-sk/strings.xml
index aa40fef..6502d1a 100644
--- a/packages/SettingsLib/res/values-sk/strings.xml
+++ b/packages/SettingsLib/res/values-sk/strings.xml
@@ -220,7 +220,8 @@
<string name="select_private_dns_configuration_title" msgid="3700456559305263922">"Súkromné DNS"</string>
<string name="select_private_dns_configuration_dialog_title" msgid="9221994415765826811">"Výber súkromného režimu DNS"</string>
<string name="private_dns_mode_off" msgid="8236575187318721684">"Vypnuté"</string>
- <string name="private_dns_mode_opportunistic" msgid="7608409735589131766">"Príležitostné"</string>
+ <!-- no translation found for private_dns_mode_opportunistic (8314986739896927399) -->
+ <skip />
<string name="private_dns_mode_provider" msgid="8354935160639360804">"Súkromný názov hostiteľa poskytovateľa DNS"</string>
<string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"Zadajte názov hostiteľa poskytovateľa DNS"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Zobraziť možnosti certifikácie bezdrôtového zobrazenia"</string>
@@ -356,22 +357,41 @@
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Funkcia je experimentálna a môže mať vplyv na výkonnosť."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"Prekonané predvoľbou <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="power_remaining_duration_only" msgid="845431008899029842">"Približný zostávajúci čas: <xliff:g id="TIME">%1$s</xliff:g>"</string>
+ <!-- no translation found for power_discharging_duration (6655472132189365839) -->
+ <skip />
<string name="power_remaining_duration_only_enhanced" msgid="5992456722677973678">"Zostáva približne <xliff:g id="TIME">%1$s</xliff:g> v závislosti od intenzity využitia"</string>
- <string name="power_remaining_charging_duration_only" msgid="1421102457410268886">"Zostávajúci čas do úplného nabitia: <xliff:g id="TIME">%1$s</xliff:g>"</string>
+ <!-- no translation found for power_discharging_duration_enhanced (5726302316642148671) -->
+ <skip />
<string name="power_remaining_duration_only_short" msgid="5329694252258605547">"Zostávajúci čas: <xliff:g id="TIME">%1$s</xliff:g>"</string>
+ <!-- no translation found for power_discharge_by_enhanced (8788299408879961465) -->
+ <skip />
+ <!-- no translation found for power_discharge_by_only_enhanced (7692297898877104416) -->
+ <skip />
+ <!-- no translation found for power_discharge_by (6427074755635635749) -->
+ <skip />
+ <!-- no translation found for power_discharge_by_only (5888058889261108064) -->
+ <skip />
<string name="power_remaining_less_than_duration_only" msgid="5996752448813295329">"Zostáva menej ako <xliff:g id="THRESHOLD">%1$s</xliff:g>"</string>
- <string name="power_remaining_less_than_duration" msgid="7967078125657859046">"<xliff:g id="LEVEL">%1$s</xliff:g> – zostáva menej ako <xliff:g id="THRESHOLD">%2$s</xliff:g>"</string>
- <string name="power_remaining_more_than_subtext" msgid="6846716609975752316">"<xliff:g id="LEVEL">%1$s</xliff:g> – zostáva viac ako <xliff:g id="TIME_REMAINING">%2$s</xliff:g>"</string>
- <string name="power_remaining_only_more_than_subtext" msgid="8884488700395194194">"zostáva viac ako <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="default" msgid="8168317165722752881">"telefón sa môže čoskoro vypnúť"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="tablet" msgid="5957064378548718872">"tablet sa môže čoskoro vypnúť"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="device" msgid="9055596817716471373">"zariadenie sa môže čoskoro vypnúť"</string>
- <string name="power_discharging_duration" msgid="2843747179907396142">"<xliff:g id="LEVEL">%1$s</xliff:g> – približný zostávajúci čas: <xliff:g id="TIME">%2$s</xliff:g>"</string>
- <string name="power_discharging_duration_enhanced" msgid="4401782117770255046">"<xliff:g id="LEVEL">%1$s</xliff:g> – zostáva približne <xliff:g id="TIME">%2$s</xliff:g> v závislosti od intenzity využitia"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="default" msgid="7679005631124015335">"<xliff:g id="LEVEL">%1$s</xliff:g> – telefón sa môže čoskoro vypnúť"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="tablet" msgid="261050880878965621">"<xliff:g id="LEVEL">%1$s</xliff:g> – tablet sa môže čoskoro vypnúť"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="device" msgid="2020049829798578618">"<xliff:g id="LEVEL">%1$s</xliff:g> – zariadenie sa môže čoskoro vypnúť"</string>
+ <!-- no translation found for power_remaining_less_than_duration (5751885147712659423) -->
+ <skip />
+ <!-- no translation found for power_remaining_more_than_subtext (3176771815132876675) -->
+ <skip />
+ <!-- no translation found for power_remaining_only_more_than_subtext (8931654680569617380) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (1181059207608751924) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (2606370266981054691) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (2918084807716859985) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (3090926004324573908) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (7466484148515796216) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (603933521600231649) -->
+ <skip />
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string>
+ <string name="power_remaining_charging_duration_only" msgid="1421102457410268886">"Zostávajúci čas do úplného nabitia: <xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="4676999980973411875">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> do úplného nabitia"</string>
<string name="battery_info_status_unknown" msgid="196130600938058547">"Neznáme"</string>
<string name="battery_info_status_charging" msgid="1705179948350365604">"Nabíja sa"</string>
diff --git a/packages/SettingsLib/res/values-sl/strings.xml b/packages/SettingsLib/res/values-sl/strings.xml
index 55e4308..10dcb4d 100644
--- a/packages/SettingsLib/res/values-sl/strings.xml
+++ b/packages/SettingsLib/res/values-sl/strings.xml
@@ -220,7 +220,8 @@
<string name="select_private_dns_configuration_title" msgid="3700456559305263922">"Zasebni strežnik DNS"</string>
<string name="select_private_dns_configuration_dialog_title" msgid="9221994415765826811">"Izbira načina zasebnega strežnika DNS"</string>
<string name="private_dns_mode_off" msgid="8236575187318721684">"Izklopljeno"</string>
- <string name="private_dns_mode_opportunistic" msgid="7608409735589131766">"Priložnostno"</string>
+ <!-- no translation found for private_dns_mode_opportunistic (8314986739896927399) -->
+ <skip />
<string name="private_dns_mode_provider" msgid="8354935160639360804">"Ime gostitelja pri ponudniku zasebnega strežnika DNS"</string>
<string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"Vnesite ime gostitelja pri ponudniku strežnika DNS"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Pokaži možnosti za potrdilo brezžičnega zaslona"</string>
@@ -356,22 +357,41 @@
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"To je preskusna funkcija in lahko vpliva na učinkovitost delovanja."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"Preglasila nastavitev: <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="power_remaining_duration_only" msgid="845431008899029842">"Še približno <xliff:g id="TIME">%1$s</xliff:g>"</string>
+ <!-- no translation found for power_discharging_duration (6655472132189365839) -->
+ <skip />
<string name="power_remaining_duration_only_enhanced" msgid="5992456722677973678">"Glede na način uporabe imate na voljo še približno <xliff:g id="TIME">%1$s</xliff:g>"</string>
- <string name="power_remaining_charging_duration_only" msgid="1421102457410268886">"Še <xliff:g id="TIME">%1$s</xliff:g> do polne napolnjenosti"</string>
+ <!-- no translation found for power_discharging_duration_enhanced (5726302316642148671) -->
+ <skip />
<string name="power_remaining_duration_only_short" msgid="5329694252258605547">"Še <xliff:g id="TIME">%1$s</xliff:g>"</string>
+ <!-- no translation found for power_discharge_by_enhanced (8788299408879961465) -->
+ <skip />
+ <!-- no translation found for power_discharge_by_only_enhanced (7692297898877104416) -->
+ <skip />
+ <!-- no translation found for power_discharge_by (6427074755635635749) -->
+ <skip />
+ <!-- no translation found for power_discharge_by_only (5888058889261108064) -->
+ <skip />
<string name="power_remaining_less_than_duration_only" msgid="5996752448813295329">"Preostalo manj kot <xliff:g id="THRESHOLD">%1$s</xliff:g>"</string>
- <string name="power_remaining_less_than_duration" msgid="7967078125657859046">"<xliff:g id="LEVEL">%1$s</xliff:g> – preostalo manj kot <xliff:g id="THRESHOLD">%2$s</xliff:g>"</string>
- <string name="power_remaining_more_than_subtext" msgid="6846716609975752316">"<xliff:g id="LEVEL">%1$s</xliff:g> – preostalo več kot <xliff:g id="TIME_REMAINING">%2$s</xliff:g>"</string>
- <string name="power_remaining_only_more_than_subtext" msgid="8884488700395194194">"preostalo več kot <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="default" msgid="8168317165722752881">"telefon se bo morda kmalu zaustavil"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="tablet" msgid="5957064378548718872">"tablični računalnik se bo morda kmalu zaustavil"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="device" msgid="9055596817716471373">"naprava se bo morda kmalu zaustavila"</string>
- <string name="power_discharging_duration" msgid="2843747179907396142">"<xliff:g id="LEVEL">%1$s</xliff:g> – še približno <xliff:g id="TIME">%2$s</xliff:g>"</string>
- <string name="power_discharging_duration_enhanced" msgid="4401782117770255046">"<xliff:g id="LEVEL">%1$s</xliff:g> – glede na način uporabe imate na voljo še približno <xliff:g id="TIME">%2$s</xliff:g>"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="default" msgid="7679005631124015335">"<xliff:g id="LEVEL">%1$s</xliff:g> – telefon se bo morda kmalu zaustavil"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="tablet" msgid="261050880878965621">"<xliff:g id="LEVEL">%1$s</xliff:g> – tablični računalnik se bo morda kmalu zaustavil"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="device" msgid="2020049829798578618">"<xliff:g id="LEVEL">%1$s</xliff:g> – naprava se bo morda kmalu zaustavila"</string>
+ <!-- no translation found for power_remaining_less_than_duration (5751885147712659423) -->
+ <skip />
+ <!-- no translation found for power_remaining_more_than_subtext (3176771815132876675) -->
+ <skip />
+ <!-- no translation found for power_remaining_only_more_than_subtext (8931654680569617380) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (1181059207608751924) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (2606370266981054691) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (2918084807716859985) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (3090926004324573908) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (7466484148515796216) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (603933521600231649) -->
+ <skip />
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string>
+ <string name="power_remaining_charging_duration_only" msgid="1421102457410268886">"Še <xliff:g id="TIME">%1$s</xliff:g> do polne napolnjenosti"</string>
<string name="power_charging_duration" msgid="4676999980973411875">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> do napolnjenosti"</string>
<string name="battery_info_status_unknown" msgid="196130600938058547">"Neznano"</string>
<string name="battery_info_status_charging" msgid="1705179948350365604">"Polnjenje"</string>
diff --git a/packages/SettingsLib/res/values-sq/strings.xml b/packages/SettingsLib/res/values-sq/strings.xml
index 5524e2c..7387441 100644
--- a/packages/SettingsLib/res/values-sq/strings.xml
+++ b/packages/SettingsLib/res/values-sq/strings.xml
@@ -220,7 +220,8 @@
<string name="select_private_dns_configuration_title" msgid="3700456559305263922">"DNS-ja private"</string>
<string name="select_private_dns_configuration_dialog_title" msgid="9221994415765826811">"Zgjidh modalitetin e DNS-së private"</string>
<string name="private_dns_mode_off" msgid="8236575187318721684">"Joaktiv"</string>
- <string name="private_dns_mode_opportunistic" msgid="7608409735589131766">"Oportunist"</string>
+ <!-- no translation found for private_dns_mode_opportunistic (8314986739896927399) -->
+ <skip />
<string name="private_dns_mode_provider" msgid="8354935160639360804">"Emri i pritësit të ofruesit të DNS-së private"</string>
<string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"Fut emrin e pritësit të ofruesit të DNS-së"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Shfaq opsionet për certifikimin e ekranit valor"</string>
@@ -356,22 +357,41 @@
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Ky funksion është eksperimental dhe mund të ndikojë në veprimtari."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"Mbivendosur nga <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="power_remaining_duration_only" msgid="845431008899029842">"Rreth <xliff:g id="TIME">%1$s</xliff:g> të mbetura"</string>
+ <!-- no translation found for power_discharging_duration (6655472132189365839) -->
+ <skip />
<string name="power_remaining_duration_only_enhanced" msgid="5992456722677973678">"Rreth <xliff:g id="TIME">%1$s</xliff:g> të mbetura bazuar në përdorimin tënd"</string>
- <string name="power_remaining_charging_duration_only" msgid="1421102457410268886">"<xliff:g id="TIME">%1$s</xliff:g> të mbetura deri në ngarkimin e plotë"</string>
+ <!-- no translation found for power_discharging_duration_enhanced (5726302316642148671) -->
+ <skip />
<string name="power_remaining_duration_only_short" msgid="5329694252258605547">"<xliff:g id="TIME">%1$s</xliff:g> të mbetura"</string>
+ <!-- no translation found for power_discharge_by_enhanced (8788299408879961465) -->
+ <skip />
+ <!-- no translation found for power_discharge_by_only_enhanced (7692297898877104416) -->
+ <skip />
+ <!-- no translation found for power_discharge_by (6427074755635635749) -->
+ <skip />
+ <!-- no translation found for power_discharge_by_only (5888058889261108064) -->
+ <skip />
<string name="power_remaining_less_than_duration_only" msgid="5996752448813295329">"Më pak se <xliff:g id="THRESHOLD">%1$s</xliff:g> të mbetura"</string>
- <string name="power_remaining_less_than_duration" msgid="7967078125657859046">"<xliff:g id="LEVEL">%1$s</xliff:g> - Më pak se <xliff:g id="THRESHOLD">%2$s</xliff:g> të mbetura"</string>
- <string name="power_remaining_more_than_subtext" msgid="6846716609975752316">"<xliff:g id="LEVEL">%1$s</xliff:g>më pak se <xliff:g id="TIME_REMAINING">%2$s</xliff:g> të mbetura"</string>
- <string name="power_remaining_only_more_than_subtext" msgid="8884488700395194194">"më shumë se <xliff:g id="TIME_REMAINING">%1$s</xliff:g> të mbetura"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="default" msgid="8168317165722752881">"telefoni mund të fiket së shpejti"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="tablet" msgid="5957064378548718872">"tableti mund të fiket së shpejti"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="device" msgid="9055596817716471373">"pajisja mund të fiket së shpejti"</string>
- <string name="power_discharging_duration" msgid="2843747179907396142">"<xliff:g id="LEVEL">%1$s</xliff:g> - rreth <xliff:g id="TIME">%2$s</xliff:g> të mbetura"</string>
- <string name="power_discharging_duration_enhanced" msgid="4401782117770255046">"<xliff:g id="LEVEL">%1$s</xliff:g> - rreth <xliff:g id="TIME">%2$s</xliff:g> të mbetura bazuar në përdorimin tënd"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="default" msgid="7679005631124015335">"<xliff:g id="LEVEL">%1$s</xliff:g> - telefoni mund të fiket së shpejti"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="tablet" msgid="261050880878965621">"<xliff:g id="LEVEL">%1$s</xliff:g> - tableti mund të fiket së shpejti"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="device" msgid="2020049829798578618">"<xliff:g id="LEVEL">%1$s</xliff:g> - tableti mund të fiket së shpejti"</string>
+ <!-- no translation found for power_remaining_less_than_duration (5751885147712659423) -->
+ <skip />
+ <!-- no translation found for power_remaining_more_than_subtext (3176771815132876675) -->
+ <skip />
+ <!-- no translation found for power_remaining_only_more_than_subtext (8931654680569617380) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (1181059207608751924) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (2606370266981054691) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (2918084807716859985) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (3090926004324573908) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (7466484148515796216) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (603933521600231649) -->
+ <skip />
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
+ <string name="power_remaining_charging_duration_only" msgid="1421102457410268886">"<xliff:g id="TIME">%1$s</xliff:g> të mbetura deri në ngarkimin e plotë"</string>
<string name="power_charging_duration" msgid="4676999980973411875">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> derisa të mbushet plotësisht"</string>
<string name="battery_info_status_unknown" msgid="196130600938058547">"I panjohur"</string>
<string name="battery_info_status_charging" msgid="1705179948350365604">"Po ngarkohet"</string>
diff --git a/packages/SettingsLib/res/values-sr/strings.xml b/packages/SettingsLib/res/values-sr/strings.xml
index a01b0b6..c644eae 100644
--- a/packages/SettingsLib/res/values-sr/strings.xml
+++ b/packages/SettingsLib/res/values-sr/strings.xml
@@ -220,7 +220,8 @@
<string name="select_private_dns_configuration_title" msgid="3700456559305263922">"Приватни DNS"</string>
<string name="select_private_dns_configuration_dialog_title" msgid="9221994415765826811">"Изаберите режим приватног DNS-а"</string>
<string name="private_dns_mode_off" msgid="8236575187318721684">"Искључено"</string>
- <string name="private_dns_mode_opportunistic" msgid="7608409735589131766">"Оппортунистички"</string>
+ <!-- no translation found for private_dns_mode_opportunistic (8314986739896927399) -->
+ <skip />
<string name="private_dns_mode_provider" msgid="8354935160639360804">"Име хоста добављача услуге приватног DNS-а"</string>
<string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"Унесите име хоста добављача услуге DNS-а"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Приказ опција за сертификацију бежичног екрана"</string>
@@ -356,22 +357,41 @@
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Ова функција је експериментална и може да утиче на квалитет рада."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"Замењује га <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="power_remaining_duration_only" msgid="845431008899029842">"Још око <xliff:g id="TIME">%1$s</xliff:g>"</string>
+ <!-- no translation found for power_discharging_duration (6655472132189365839) -->
+ <skip />
<string name="power_remaining_duration_only_enhanced" msgid="5992456722677973678">"На основу потрошње имате још отприлике <xliff:g id="TIME">%1$s</xliff:g>"</string>
- <string name="power_remaining_charging_duration_only" msgid="1421102457410268886">"<xliff:g id="TIME">%1$s</xliff:g> до потпуног пуњења"</string>
+ <!-- no translation found for power_discharging_duration_enhanced (5726302316642148671) -->
+ <skip />
<string name="power_remaining_duration_only_short" msgid="5329694252258605547">"Преостало време: <xliff:g id="TIME">%1$s</xliff:g>"</string>
+ <!-- no translation found for power_discharge_by_enhanced (8788299408879961465) -->
+ <skip />
+ <!-- no translation found for power_discharge_by_only_enhanced (7692297898877104416) -->
+ <skip />
+ <!-- no translation found for power_discharge_by (6427074755635635749) -->
+ <skip />
+ <!-- no translation found for power_discharge_by_only (5888058889261108064) -->
+ <skip />
<string name="power_remaining_less_than_duration_only" msgid="5996752448813295329">"Преостало је мање од <xliff:g id="THRESHOLD">%1$s</xliff:g>"</string>
- <string name="power_remaining_less_than_duration" msgid="7967078125657859046">"<xliff:g id="LEVEL">%1$s</xliff:g> – преостало је мање од <xliff:g id="THRESHOLD">%2$s</xliff:g>"</string>
- <string name="power_remaining_more_than_subtext" msgid="6846716609975752316">"<xliff:g id="LEVEL">%1$s</xliff:g> – преостало је више од <xliff:g id="TIME_REMAINING">%2$s</xliff:g>"</string>
- <string name="power_remaining_only_more_than_subtext" msgid="8884488700395194194">"преостало је више од <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="default" msgid="8168317165722752881">"телефон ће се ускоро искључити"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="tablet" msgid="5957064378548718872">"таблет ће се ускоро искључити"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="device" msgid="9055596817716471373">"уређај ће се ускоро искључити"</string>
- <string name="power_discharging_duration" msgid="2843747179907396142">"<xliff:g id="LEVEL">%1$s</xliff:g> – остало је око <xliff:g id="TIME">%2$s</xliff:g>"</string>
- <string name="power_discharging_duration_enhanced" msgid="4401782117770255046">"<xliff:g id="LEVEL">%1$s</xliff:g> – на основу потрошње имате још отприлике <xliff:g id="TIME">%2$s</xliff:g>"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="default" msgid="7679005631124015335">"<xliff:g id="LEVEL">%1$s</xliff:g> – телефон ће се ускоро искључити"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="tablet" msgid="261050880878965621">"<xliff:g id="LEVEL">%1$s</xliff:g> – таблет ће се ускоро искључити"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="device" msgid="2020049829798578618">"<xliff:g id="LEVEL">%1$s</xliff:g> – уређај ће се ускоро искључити"</string>
+ <!-- no translation found for power_remaining_less_than_duration (5751885147712659423) -->
+ <skip />
+ <!-- no translation found for power_remaining_more_than_subtext (3176771815132876675) -->
+ <skip />
+ <!-- no translation found for power_remaining_only_more_than_subtext (8931654680569617380) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (1181059207608751924) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (2606370266981054691) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (2918084807716859985) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (3090926004324573908) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (7466484148515796216) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (603933521600231649) -->
+ <skip />
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string>
+ <string name="power_remaining_charging_duration_only" msgid="1421102457410268886">"<xliff:g id="TIME">%1$s</xliff:g> до потпуног пуњења"</string>
<string name="power_charging_duration" msgid="4676999980973411875">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> до потпуног пуњења"</string>
<string name="battery_info_status_unknown" msgid="196130600938058547">"Непознато"</string>
<string name="battery_info_status_charging" msgid="1705179948350365604">"Пуњење"</string>
diff --git a/packages/SettingsLib/res/values-sv/strings.xml b/packages/SettingsLib/res/values-sv/strings.xml
index d8c6e4d..44875f5 100644
--- a/packages/SettingsLib/res/values-sv/strings.xml
+++ b/packages/SettingsLib/res/values-sv/strings.xml
@@ -220,7 +220,8 @@
<string name="select_private_dns_configuration_title" msgid="3700456559305263922">"Privat DNS"</string>
<string name="select_private_dns_configuration_dialog_title" msgid="9221994415765826811">"Välj läget Privat DNS"</string>
<string name="private_dns_mode_off" msgid="8236575187318721684">"Av"</string>
- <string name="private_dns_mode_opportunistic" msgid="7608409735589131766">"Opportunistisk"</string>
+ <!-- no translation found for private_dns_mode_opportunistic (8314986739896927399) -->
+ <skip />
<string name="private_dns_mode_provider" msgid="8354935160639360804">"Värdnamn för leverantör av privat DNS"</string>
<string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"Ange värdnamn för DNS-leverantör"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Visa certifieringsalternativ för Wi-Fi-skärmdelning"</string>
@@ -356,22 +357,41 @@
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Den här funktionen är experimentell och kan påverka prestandan."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"Har åsidosatts av <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="power_remaining_duration_only" msgid="845431008899029842">"Cirka <xliff:g id="TIME">%1$s</xliff:g> återstår"</string>
+ <!-- no translation found for power_discharging_duration (6655472132189365839) -->
+ <skip />
<string name="power_remaining_duration_only_enhanced" msgid="5992456722677973678">"Cirka <xliff:g id="TIME">%1$s</xliff:g> kvar utifrån din användning"</string>
- <string name="power_remaining_charging_duration_only" msgid="1421102457410268886">"Batteriet är fulladdat om <xliff:g id="TIME">%1$s</xliff:g>"</string>
+ <!-- no translation found for power_discharging_duration_enhanced (5726302316642148671) -->
+ <skip />
<string name="power_remaining_duration_only_short" msgid="5329694252258605547">"<xliff:g id="TIME">%1$s</xliff:g> kvar"</string>
+ <!-- no translation found for power_discharge_by_enhanced (8788299408879961465) -->
+ <skip />
+ <!-- no translation found for power_discharge_by_only_enhanced (7692297898877104416) -->
+ <skip />
+ <!-- no translation found for power_discharge_by (6427074755635635749) -->
+ <skip />
+ <!-- no translation found for power_discharge_by_only (5888058889261108064) -->
+ <skip />
<string name="power_remaining_less_than_duration_only" msgid="5996752448813295329">"Mindre än <xliff:g id="THRESHOLD">%1$s</xliff:g> återstår"</string>
- <string name="power_remaining_less_than_duration" msgid="7967078125657859046">"<xliff:g id="LEVEL">%1$s</xliff:g> – Mindre än <xliff:g id="THRESHOLD">%2$s</xliff:g> återstår"</string>
- <string name="power_remaining_more_than_subtext" msgid="6846716609975752316">"<xliff:g id="LEVEL">%1$s</xliff:g>mer än <xliff:g id="TIME_REMAINING">%2$s</xliff:g> återstår"</string>
- <string name="power_remaining_only_more_than_subtext" msgid="8884488700395194194">"mer än <xliff:g id="TIME_REMAINING">%1$s</xliff:g> återstår"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="default" msgid="8168317165722752881">"mobilen kan stängas av snart"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="tablet" msgid="5957064378548718872">"surfplattan kan stängas av snart"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="device" msgid="9055596817716471373">"enheten kan stängas av snart"</string>
- <string name="power_discharging_duration" msgid="2843747179907396142">"<xliff:g id="LEVEL">%1$s</xliff:g> – cirka <xliff:g id="TIME">%2$s</xliff:g> kvar"</string>
- <string name="power_discharging_duration_enhanced" msgid="4401782117770255046">"<xliff:g id="LEVEL">%1$s</xliff:g> – cirka <xliff:g id="TIME">%2$s</xliff:g> kvar utifrån din användning"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="default" msgid="7679005631124015335">"<xliff:g id="LEVEL">%1$s</xliff:g> – mobilen kan stängas av snart"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="tablet" msgid="261050880878965621">"<xliff:g id="LEVEL">%1$s</xliff:g> – surfplattan kan stängas av snart"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="device" msgid="2020049829798578618">"<xliff:g id="LEVEL">%1$s</xliff:g> – enheten kan stängas av snart"</string>
+ <!-- no translation found for power_remaining_less_than_duration (5751885147712659423) -->
+ <skip />
+ <!-- no translation found for power_remaining_more_than_subtext (3176771815132876675) -->
+ <skip />
+ <!-- no translation found for power_remaining_only_more_than_subtext (8931654680569617380) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (1181059207608751924) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (2606370266981054691) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (2918084807716859985) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (3090926004324573908) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (7466484148515796216) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (603933521600231649) -->
+ <skip />
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string>
+ <string name="power_remaining_charging_duration_only" msgid="1421102457410268886">"Batteriet är fulladdat om <xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="4676999980973411875">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> tills det är fulladdat"</string>
<string name="battery_info_status_unknown" msgid="196130600938058547">"Okänd"</string>
<string name="battery_info_status_charging" msgid="1705179948350365604">"Laddar"</string>
diff --git a/packages/SettingsLib/res/values-sw/strings.xml b/packages/SettingsLib/res/values-sw/strings.xml
index fd91e5b..6305fde 100644
--- a/packages/SettingsLib/res/values-sw/strings.xml
+++ b/packages/SettingsLib/res/values-sw/strings.xml
@@ -220,7 +220,8 @@
<string name="select_private_dns_configuration_title" msgid="3700456559305263922">"DNS ya Faragha"</string>
<string name="select_private_dns_configuration_dialog_title" msgid="9221994415765826811">"Chagua Hali ya DNS ya Faragha"</string>
<string name="private_dns_mode_off" msgid="8236575187318721684">"Imezimwa"</string>
- <string name="private_dns_mode_opportunistic" msgid="7608409735589131766">"Inayojitokeza"</string>
+ <!-- no translation found for private_dns_mode_opportunistic (8314986739896927399) -->
+ <skip />
<string name="private_dns_mode_provider" msgid="8354935160639360804">"Jina la mpangishi wa huduma za DNS ya faragha"</string>
<string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"Weka jina la mpangishi wa huduma za DNS"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Onyesha chaguo za cheti cha kuonyesha pasiwaya"</string>
@@ -356,22 +357,41 @@
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Kipengele hiki ni cha majaribio na huenda kikaathiri utendaji wa kifaa chako."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"Imetanguliwa na <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="power_remaining_duration_only" msgid="845431008899029842">"Zimesalia takribani <xliff:g id="TIME">%1$s</xliff:g>"</string>
+ <!-- no translation found for power_discharging_duration (6655472132189365839) -->
+ <skip />
<string name="power_remaining_duration_only_enhanced" msgid="5992456722677973678">"Takriban <xliff:g id="TIME">%1$s</xliff:g> zimesalia kulingana na matumizi yako"</string>
- <string name="power_remaining_charging_duration_only" msgid="1421102457410268886">"Imebaki <xliff:g id="TIME">%1$s</xliff:g> chaji ijae"</string>
+ <!-- no translation found for power_discharging_duration_enhanced (5726302316642148671) -->
+ <skip />
<string name="power_remaining_duration_only_short" msgid="5329694252258605547">"Zimesalia <xliff:g id="TIME">%1$s</xliff:g>"</string>
+ <!-- no translation found for power_discharge_by_enhanced (8788299408879961465) -->
+ <skip />
+ <!-- no translation found for power_discharge_by_only_enhanced (7692297898877104416) -->
+ <skip />
+ <!-- no translation found for power_discharge_by (6427074755635635749) -->
+ <skip />
+ <!-- no translation found for power_discharge_by_only (5888058889261108064) -->
+ <skip />
<string name="power_remaining_less_than_duration_only" msgid="5996752448813295329">"Zimesalia chini ya <xliff:g id="THRESHOLD">%1$s</xliff:g>"</string>
- <string name="power_remaining_less_than_duration" msgid="7967078125657859046">"<xliff:g id="LEVEL">%1$s</xliff:g> - Zimesalia chini ya <xliff:g id="THRESHOLD">%2$s</xliff:g>"</string>
- <string name="power_remaining_more_than_subtext" msgid="6846716609975752316">"<xliff:g id="LEVEL">%1$s</xliff:g> zimesalia zaidi ya <xliff:g id="TIME_REMAINING">%2$s</xliff:g>"</string>
- <string name="power_remaining_only_more_than_subtext" msgid="8884488700395194194">"zimesalia zaidi ya <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="default" msgid="8168317165722752881">"simu inakaribia kuzimika"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="tablet" msgid="5957064378548718872">"kompyuta kibao inakaribia kuzimika"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="device" msgid="9055596817716471373">"kifaa kinakaribia kuzimika"</string>
- <string name="power_discharging_duration" msgid="2843747179907396142">"<xliff:g id="LEVEL">%1$s</xliff:g> - imesalia takribani <xliff:g id="TIME">%2$s</xliff:g>"</string>
- <string name="power_discharging_duration_enhanced" msgid="4401782117770255046">"<xliff:g id="LEVEL">%1$s</xliff:g> - takriban <xliff:g id="TIME">%2$s</xliff:g> zimesalia kulingana na matumizi yako"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="default" msgid="7679005631124015335">"<xliff:g id="LEVEL">%1$s</xliff:g> - simu inakaribia kuzimika"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="tablet" msgid="261050880878965621">"<xliff:g id="LEVEL">%1$s</xliff:g> - kompyuta kibao inakaribia kuzimika"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="device" msgid="2020049829798578618">"<xliff:g id="LEVEL">%1$s</xliff:g> - kifaa kinakaribia kuzimika"</string>
+ <!-- no translation found for power_remaining_less_than_duration (5751885147712659423) -->
+ <skip />
+ <!-- no translation found for power_remaining_more_than_subtext (3176771815132876675) -->
+ <skip />
+ <!-- no translation found for power_remaining_only_more_than_subtext (8931654680569617380) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (1181059207608751924) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (2606370266981054691) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (2918084807716859985) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (3090926004324573908) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (7466484148515796216) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (603933521600231649) -->
+ <skip />
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
+ <string name="power_remaining_charging_duration_only" msgid="1421102457410268886">"Imebaki <xliff:g id="TIME">%1$s</xliff:g> chaji ijae"</string>
<string name="power_charging_duration" msgid="4676999980973411875">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> hadi ijae chaji"</string>
<string name="battery_info_status_unknown" msgid="196130600938058547">"Haijulikani"</string>
<string name="battery_info_status_charging" msgid="1705179948350365604">"Inachaji"</string>
diff --git a/packages/SettingsLib/res/values-ta/strings.xml b/packages/SettingsLib/res/values-ta/strings.xml
index b417cfb..ff983b7 100644
--- a/packages/SettingsLib/res/values-ta/strings.xml
+++ b/packages/SettingsLib/res/values-ta/strings.xml
@@ -76,7 +76,7 @@
<string name="bluetooth_profile_a2dp_high_quality" msgid="5444517801472820055">"HD ஆடியோ: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="8510588052415438887">"HD ஆடியோ"</string>
<string name="bluetooth_profile_hearing_aid" msgid="7999237886427812595">"செவித்துணைக் கருவி"</string>
- <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="7188282786730266159">"செவித்துணைக் கருவியுடன் இணைக்கப்பட்டிருக்கும்போது"</string>
+ <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="7188282786730266159">"செவித்துணைக் கருவியுடன் இணைக்கப்பட்டிருக்கிறது"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="963376081347721598">"மீடியா ஆடியோவுடன் இணைக்கப்பட்டது"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="7661070206715520671">"மொபைல் ஆடியோவுடன் இணைக்கப்பட்டது"</string>
<string name="bluetooth_opp_profile_summary_connected" msgid="2611913495968309066">"கோப்பைப் பரிமாற்றும் சேவையகத்துடன் இணைக்கப்பட்டது"</string>
@@ -220,7 +220,8 @@
<string name="select_private_dns_configuration_title" msgid="3700456559305263922">"தனிப்பட்ட DNS"</string>
<string name="select_private_dns_configuration_dialog_title" msgid="9221994415765826811">"தனிப்பட்ட DNS பயன்முறையைத் தேர்ந்தெடுக்கவும்"</string>
<string name="private_dns_mode_off" msgid="8236575187318721684">"ஆஃப்"</string>
- <string name="private_dns_mode_opportunistic" msgid="7608409735589131766">"சந்தர்ப்பவாதம்"</string>
+ <!-- no translation found for private_dns_mode_opportunistic (8314986739896927399) -->
+ <skip />
<string name="private_dns_mode_provider" msgid="8354935160639360804">"தனிப்பட்ட DNS வழங்குநரின் ஹோஸ்ட் பெயர்"</string>
<string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"DNS வழங்குநரின் ஹோஸ்ட் பெயரை உள்ளிடவும்"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"வயர்லெஸ் காட்சி சான்றுக்கான விருப்பங்களைக் காட்டு"</string>
@@ -356,22 +357,41 @@
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"இது சோதனை முறையிலான அம்சம், இது செயல்திறனைப் பாதிக்கலாம்."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"<xliff:g id="TITLE">%1$s</xliff:g> மூலம் மேலெழுதப்பட்டது"</string>
<string name="power_remaining_duration_only" msgid="845431008899029842">"கிட்டத்தட்ட <xliff:g id="TIME">%1$s</xliff:g> உள்ளது"</string>
+ <!-- no translation found for power_discharging_duration (6655472132189365839) -->
+ <skip />
<string name="power_remaining_duration_only_enhanced" msgid="5992456722677973678">"உபயோகத்தின் அடிப்படையில் கிட்டத்தட்ட <xliff:g id="TIME">%1$s</xliff:g> மீதமுள்ளது"</string>
- <string name="power_remaining_charging_duration_only" msgid="1421102457410268886">"முழு சார்ஜாக <xliff:g id="TIME">%1$s</xliff:g> ஆகும்"</string>
+ <!-- no translation found for power_discharging_duration_enhanced (5726302316642148671) -->
+ <skip />
<string name="power_remaining_duration_only_short" msgid="5329694252258605547">"<xliff:g id="TIME">%1$s</xliff:g> மீதமுள்ளது"</string>
+ <!-- no translation found for power_discharge_by_enhanced (8788299408879961465) -->
+ <skip />
+ <!-- no translation found for power_discharge_by_only_enhanced (7692297898877104416) -->
+ <skip />
+ <!-- no translation found for power_discharge_by (6427074755635635749) -->
+ <skip />
+ <!-- no translation found for power_discharge_by_only (5888058889261108064) -->
+ <skip />
<string name="power_remaining_less_than_duration_only" msgid="5996752448813295329">"<xliff:g id="THRESHOLD">%1$s</xliff:g>க்கும் குறைவாகவே பயன்படுத்த முடியும்"</string>
- <string name="power_remaining_less_than_duration" msgid="7967078125657859046">"<xliff:g id="LEVEL">%1$s</xliff:g> பேட்டரி மட்டுமே உள்ளது, <xliff:g id="THRESHOLD">%2$s</xliff:g>க்கும் குறைவாகவே பயன்படுத்தமுடியும்"</string>
- <string name="power_remaining_more_than_subtext" msgid="6846716609975752316">"பேட்டரி <xliff:g id="LEVEL">%1$s</xliff:g> உள்ளது, <xliff:g id="TIME_REMAINING">%2$s</xliff:g>க்கு மேல் பயன்படுத்த முடியும்"</string>
- <string name="power_remaining_only_more_than_subtext" msgid="8884488700395194194">"<xliff:g id="TIME_REMAINING">%1$s</xliff:g>க்கு மேல் பயன்படுத்த முடியும்"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="default" msgid="8168317165722752881">"மொபைல் விரைவில் ஆஃப் ஆகக்கூடும்"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="tablet" msgid="5957064378548718872">"டேப்லெட் விரைவில் ஆஃப் ஆகக்கூடும்"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="device" msgid="9055596817716471373">"சாதனம் விரைவில் ஆஃப் ஆகக்கூடும்"</string>
- <string name="power_discharging_duration" msgid="2843747179907396142">"<xliff:g id="LEVEL">%1$s</xliff:g> - கிட்டத்தட்ட <xliff:g id="TIME">%2$s</xliff:g> மீதமுள்ளது"</string>
- <string name="power_discharging_duration_enhanced" msgid="4401782117770255046">"<xliff:g id="LEVEL">%1$s</xliff:g> - உபயோகத்தின் அடிப்படையில் கிட்டத்தட்ட <xliff:g id="TIME">%2$s</xliff:g> மீதமுள்ளது"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="default" msgid="7679005631124015335">"<xliff:g id="LEVEL">%1$s</xliff:g> - மொபைல் விரைவில் ஆஃப் ஆகக்கூடும்"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="tablet" msgid="261050880878965621">"<xliff:g id="LEVEL">%1$s</xliff:g> - டேப்லெட் விரைவில் ஆஃப் ஆகக்கூடும்"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="device" msgid="2020049829798578618">"<xliff:g id="LEVEL">%1$s</xliff:g> - சாதனம் விரைவில் ஆஃப் ஆகக்கூடும்"</string>
+ <!-- no translation found for power_remaining_less_than_duration (5751885147712659423) -->
+ <skip />
+ <!-- no translation found for power_remaining_more_than_subtext (3176771815132876675) -->
+ <skip />
+ <!-- no translation found for power_remaining_only_more_than_subtext (8931654680569617380) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (1181059207608751924) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (2606370266981054691) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (2918084807716859985) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (3090926004324573908) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (7466484148515796216) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (603933521600231649) -->
+ <skip />
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
+ <string name="power_remaining_charging_duration_only" msgid="1421102457410268886">"முழு சார்ஜாக <xliff:g id="TIME">%1$s</xliff:g> ஆகும்"</string>
<string name="power_charging_duration" msgid="4676999980973411875">"<xliff:g id="LEVEL">%1$s</xliff:g> - முழு சார்ஜாக <xliff:g id="TIME">%2$s</xliff:g> ஆகும்"</string>
<string name="battery_info_status_unknown" msgid="196130600938058547">"அறியப்படாத"</string>
<string name="battery_info_status_charging" msgid="1705179948350365604">"சார்ஜ் ஆகிறது"</string>
diff --git a/packages/SettingsLib/res/values-te/strings.xml b/packages/SettingsLib/res/values-te/strings.xml
index 99a35a3..bccb11e 100644
--- a/packages/SettingsLib/res/values-te/strings.xml
+++ b/packages/SettingsLib/res/values-te/strings.xml
@@ -220,7 +220,8 @@
<string name="select_private_dns_configuration_title" msgid="3700456559305263922">"ప్రైవేట్ DNS"</string>
<string name="select_private_dns_configuration_dialog_title" msgid="9221994415765826811">"ప్రైవేట్ DNS మోడ్ను ఎంచుకోండి"</string>
<string name="private_dns_mode_off" msgid="8236575187318721684">"ఆఫ్"</string>
- <string name="private_dns_mode_opportunistic" msgid="7608409735589131766">"అవకాశవాదం"</string>
+ <!-- no translation found for private_dns_mode_opportunistic (8314986739896927399) -->
+ <skip />
<string name="private_dns_mode_provider" msgid="8354935160639360804">"ప్రైవేట్ DNS ప్రదాత హోస్ట్పేరు"</string>
<string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"DNS ప్రదాత యొక్క హోస్ట్పేరును నమోదు చేయండి"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"వైర్లెస్ ప్రదర్శన సర్టిఫికెట్ కోసం ఎంపికలను చూపు"</string>
@@ -356,22 +357,41 @@
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"ఈ లక్షణం ప్రయోగాత్మకమైనది మరియు పనితీరుపై ప్రభావం చూపవచ్చు."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"<xliff:g id="TITLE">%1$s</xliff:g> ద్వారా భర్తీ చేయబడింది"</string>
<string name="power_remaining_duration_only" msgid="845431008899029842">"మిగిలి ఉన్న సమయం, <xliff:g id="TIME">%1$s</xliff:g>"</string>
+ <!-- no translation found for power_discharging_duration (6655472132189365839) -->
+ <skip />
<string name="power_remaining_duration_only_enhanced" msgid="5992456722677973678">"మీ వినియోగం ఆధారంగా సుమారు <xliff:g id="TIME">%1$s</xliff:g> సమయం మిగిలి ఉంది"</string>
- <string name="power_remaining_charging_duration_only" msgid="1421102457410268886">"పూర్తిగా ఛార్జ్ కావడానికి <xliff:g id="TIME">%1$s</xliff:g> పడుతుంది"</string>
+ <!-- no translation found for power_discharging_duration_enhanced (5726302316642148671) -->
+ <skip />
<string name="power_remaining_duration_only_short" msgid="5329694252258605547">"<xliff:g id="TIME">%1$s</xliff:g> మిగిలి ఉంది"</string>
+ <!-- no translation found for power_discharge_by_enhanced (8788299408879961465) -->
+ <skip />
+ <!-- no translation found for power_discharge_by_only_enhanced (7692297898877104416) -->
+ <skip />
+ <!-- no translation found for power_discharge_by (6427074755635635749) -->
+ <skip />
+ <!-- no translation found for power_discharge_by_only (5888058889261108064) -->
+ <skip />
<string name="power_remaining_less_than_duration_only" msgid="5996752448813295329">"<xliff:g id="THRESHOLD">%1$s</xliff:g> కంటే తక్కువ సమయం మిగిలి ఉంది"</string>
- <string name="power_remaining_less_than_duration" msgid="7967078125657859046">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="THRESHOLD">%2$s</xliff:g> కంటే తక్కువ సమయం మిగిలి ఉంది"</string>
- <string name="power_remaining_more_than_subtext" msgid="6846716609975752316">"<xliff:g id="LEVEL">%1$s</xliff:g><xliff:g id="TIME_REMAINING">%2$s</xliff:g> కంటే ఎక్కువ సమయం మిగిలి ఉంది"</string>
- <string name="power_remaining_only_more_than_subtext" msgid="8884488700395194194">"<xliff:g id="TIME_REMAINING">%1$s</xliff:g> కంటే ఎక్కువ సమయం మిగిలి ఉంది"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="default" msgid="8168317165722752881">"ఫోన్ త్వరలో షట్డౌన్ కావచ్చు"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="tablet" msgid="5957064378548718872">"టాబ్లెట్ త్వరలో షట్డౌన్ కావచ్చు"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="device" msgid="9055596817716471373">"పరికరం త్వరలో షట్డౌన్ కావచ్చు"</string>
- <string name="power_discharging_duration" msgid="2843747179907396142">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> పని చేస్తుంది"</string>
- <string name="power_discharging_duration_enhanced" msgid="4401782117770255046">"<xliff:g id="LEVEL">%1$s</xliff:g> - మీ వినియోగం ఆధారంగా సుమారు <xliff:g id="TIME">%2$s</xliff:g> సమయం మిగిలి ఉంది"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="default" msgid="7679005631124015335">"<xliff:g id="LEVEL">%1$s</xliff:g> - ఫోన్ త్వరలో షట్డౌన్ కావచ్చు"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="tablet" msgid="261050880878965621">"<xliff:g id="LEVEL">%1$s</xliff:g> - టాబ్లెట్ త్వరలో షట్డౌన్ కావచ్చు"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="device" msgid="2020049829798578618">"<xliff:g id="LEVEL">%1$s</xliff:g> - పరికరం త్వరలో షట్డౌన్ కావచ్చు"</string>
+ <!-- no translation found for power_remaining_less_than_duration (5751885147712659423) -->
+ <skip />
+ <!-- no translation found for power_remaining_more_than_subtext (3176771815132876675) -->
+ <skip />
+ <!-- no translation found for power_remaining_only_more_than_subtext (8931654680569617380) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (1181059207608751924) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (2606370266981054691) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (2918084807716859985) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (3090926004324573908) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (7466484148515796216) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (603933521600231649) -->
+ <skip />
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
+ <string name="power_remaining_charging_duration_only" msgid="1421102457410268886">"పూర్తిగా ఛార్జ్ కావడానికి <xliff:g id="TIME">%1$s</xliff:g> పడుతుంది"</string>
<string name="power_charging_duration" msgid="4676999980973411875">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g>లో పూర్తిగా ఛార్జ్ అవుతుంది"</string>
<string name="battery_info_status_unknown" msgid="196130600938058547">"తెలియదు"</string>
<string name="battery_info_status_charging" msgid="1705179948350365604">"ఛార్జ్ అవుతోంది"</string>
diff --git a/packages/SettingsLib/res/values-th/strings.xml b/packages/SettingsLib/res/values-th/strings.xml
index aab479e..2cedcfcf 100644
--- a/packages/SettingsLib/res/values-th/strings.xml
+++ b/packages/SettingsLib/res/values-th/strings.xml
@@ -220,7 +220,8 @@
<string name="select_private_dns_configuration_title" msgid="3700456559305263922">"DNS ส่วนตัว"</string>
<string name="select_private_dns_configuration_dialog_title" msgid="9221994415765826811">"เลือกโหมด DNS ส่วนตัว"</string>
<string name="private_dns_mode_off" msgid="8236575187318721684">"ปิด"</string>
- <string name="private_dns_mode_opportunistic" msgid="7608409735589131766">"ที่ใช้โอกาส"</string>
+ <!-- no translation found for private_dns_mode_opportunistic (8314986739896927399) -->
+ <skip />
<string name="private_dns_mode_provider" msgid="8354935160639360804">"ชื่อโฮสต์ของผู้ให้บริการ DNS ส่วนตัว"</string>
<string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"ป้อนชื่อโฮสต์ของผู้ให้บริการ DNS"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"แสดงตัวเลือกสำหรับการรับรองการแสดงผล แบบไร้สาย"</string>
@@ -356,22 +357,41 @@
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"ฟีเจอร์นี้เป็นแบบทดลองและอาจส่งผลต่อประสิทธิภาพการทำงาน"</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"แทนที่โดย <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="power_remaining_duration_only" msgid="845431008899029842">"อีกประมาณ <xliff:g id="TIME">%1$s</xliff:g>"</string>
+ <!-- no translation found for power_discharging_duration (6655472132189365839) -->
+ <skip />
<string name="power_remaining_duration_only_enhanced" msgid="5992456722677973678">"เหลืออีกราว <xliff:g id="TIME">%1$s</xliff:g> ขึ้นอยู่กับการใช้งานของคุณ"</string>
- <string name="power_remaining_charging_duration_only" msgid="1421102457410268886">"อีก <xliff:g id="TIME">%1$s</xliff:g> จึงจะชาร์จเต็ม"</string>
+ <!-- no translation found for power_discharging_duration_enhanced (5726302316642148671) -->
+ <skip />
<string name="power_remaining_duration_only_short" msgid="5329694252258605547">"เหลืออีก <xliff:g id="TIME">%1$s</xliff:g>"</string>
+ <!-- no translation found for power_discharge_by_enhanced (8788299408879961465) -->
+ <skip />
+ <!-- no translation found for power_discharge_by_only_enhanced (7692297898877104416) -->
+ <skip />
+ <!-- no translation found for power_discharge_by (6427074755635635749) -->
+ <skip />
+ <!-- no translation found for power_discharge_by_only (5888058889261108064) -->
+ <skip />
<string name="power_remaining_less_than_duration_only" msgid="5996752448813295329">"เหลืออีกไม่ถึง <xliff:g id="THRESHOLD">%1$s</xliff:g>"</string>
- <string name="power_remaining_less_than_duration" msgid="7967078125657859046">"<xliff:g id="LEVEL">%1$s</xliff:g> - เหลืออีกไม่ถึง <xliff:g id="THRESHOLD">%2$s</xliff:g>"</string>
- <string name="power_remaining_more_than_subtext" msgid="6846716609975752316">"<xliff:g id="LEVEL">%1$s</xliff:g> - เหลือเวลามากกว่า <xliff:g id="TIME_REMAINING">%2$s</xliff:g>"</string>
- <string name="power_remaining_only_more_than_subtext" msgid="8884488700395194194">"เหลือเวลามากกว่า <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="default" msgid="8168317165722752881">"โทรศัพท์อาจปิดเครื่องในไม่ช้า"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="tablet" msgid="5957064378548718872">"แท็บเล็ตอาจปิดเครื่องในไม่ช้า"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="device" msgid="9055596817716471373">"อุปกรณ์อาจปิดเครื่องในไม่ช้า"</string>
- <string name="power_discharging_duration" msgid="2843747179907396142">"<xliff:g id="LEVEL">%1$s</xliff:g> - เหลือเวลาประมาณ <xliff:g id="TIME">%2$s</xliff:g>"</string>
- <string name="power_discharging_duration_enhanced" msgid="4401782117770255046">"<xliff:g id="LEVEL">%1$s</xliff:g> - เหลืออีกราว <xliff:g id="TIME">%2$s</xliff:g> ขึ้นอยู่กับการใช้งานของคุณ"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="default" msgid="7679005631124015335">"<xliff:g id="LEVEL">%1$s</xliff:g> - โทรศัพท์อาจปิดเครื่องในไม่ช้า"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="tablet" msgid="261050880878965621">"<xliff:g id="LEVEL">%1$s</xliff:g> - แท็บเล็ตอาจปิดเครื่องในไม่ช้า"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="device" msgid="2020049829798578618">"<xliff:g id="LEVEL">%1$s</xliff:g> - อุปกรณ์อาจปิดเครื่องในไม่ช้า"</string>
+ <!-- no translation found for power_remaining_less_than_duration (5751885147712659423) -->
+ <skip />
+ <!-- no translation found for power_remaining_more_than_subtext (3176771815132876675) -->
+ <skip />
+ <!-- no translation found for power_remaining_only_more_than_subtext (8931654680569617380) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (1181059207608751924) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (2606370266981054691) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (2918084807716859985) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (3090926004324573908) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (7466484148515796216) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (603933521600231649) -->
+ <skip />
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
+ <string name="power_remaining_charging_duration_only" msgid="1421102457410268886">"อีก <xliff:g id="TIME">%1$s</xliff:g> จึงจะชาร์จเต็ม"</string>
<string name="power_charging_duration" msgid="4676999980973411875">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> จนกว่าจะชาร์จเต็ม"</string>
<string name="battery_info_status_unknown" msgid="196130600938058547">"ไม่ทราบ"</string>
<string name="battery_info_status_charging" msgid="1705179948350365604">"กำลังชาร์จ"</string>
diff --git a/packages/SettingsLib/res/values-tl/strings.xml b/packages/SettingsLib/res/values-tl/strings.xml
index 6403213..dd774d2 100644
--- a/packages/SettingsLib/res/values-tl/strings.xml
+++ b/packages/SettingsLib/res/values-tl/strings.xml
@@ -220,7 +220,8 @@
<string name="select_private_dns_configuration_title" msgid="3700456559305263922">"Pribadong DNS"</string>
<string name="select_private_dns_configuration_dialog_title" msgid="9221994415765826811">"Pumili ng Pribadong DNS Mode"</string>
<string name="private_dns_mode_off" msgid="8236575187318721684">"Naka-off"</string>
- <string name="private_dns_mode_opportunistic" msgid="7608409735589131766">"Oportunista"</string>
+ <!-- no translation found for private_dns_mode_opportunistic (8314986739896927399) -->
+ <skip />
<string name="private_dns_mode_provider" msgid="8354935160639360804">"Hostname ng provider ng pribadong DNS"</string>
<string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"Ilagay ang hostname ng DNS provider"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Ipakita ang mga opsyon para sa certification ng wireless display"</string>
@@ -356,22 +357,41 @@
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Ang feature na ito ay pinag-eeksperimentuhan at maaaring makaapekto sa performance."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"Na-override ng <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="power_remaining_duration_only" msgid="845431008899029842">"Humigit-kumulang <xliff:g id="TIME">%1$s</xliff:g> ang natitira"</string>
+ <!-- no translation found for power_discharging_duration (6655472132189365839) -->
+ <skip />
<string name="power_remaining_duration_only_enhanced" msgid="5992456722677973678">"Humigit-kumulang <xliff:g id="TIME">%1$s</xliff:g> ang natitira batay sa iyong paggamit"</string>
- <string name="power_remaining_charging_duration_only" msgid="1421102457410268886">"<xliff:g id="TIME">%1$s</xliff:g> ang natitira bago makumpleto ang charge"</string>
+ <!-- no translation found for power_discharging_duration_enhanced (5726302316642148671) -->
+ <skip />
<string name="power_remaining_duration_only_short" msgid="5329694252258605547">"<xliff:g id="TIME">%1$s</xliff:g> pa"</string>
+ <!-- no translation found for power_discharge_by_enhanced (8788299408879961465) -->
+ <skip />
+ <!-- no translation found for power_discharge_by_only_enhanced (7692297898877104416) -->
+ <skip />
+ <!-- no translation found for power_discharge_by (6427074755635635749) -->
+ <skip />
+ <!-- no translation found for power_discharge_by_only (5888058889261108064) -->
+ <skip />
<string name="power_remaining_less_than_duration_only" msgid="5996752448813295329">"Wala nang <xliff:g id="THRESHOLD">%1$s</xliff:g> ang natitira"</string>
- <string name="power_remaining_less_than_duration" msgid="7967078125657859046">"<xliff:g id="LEVEL">%1$s</xliff:g> - Wala nang <xliff:g id="THRESHOLD">%2$s</xliff:g> ang natitira"</string>
- <string name="power_remaining_more_than_subtext" msgid="6846716609975752316">"<xliff:g id="LEVEL">%1$s</xliff:g>may mahigit <xliff:g id="TIME_REMAINING">%2$s</xliff:g> pa"</string>
- <string name="power_remaining_only_more_than_subtext" msgid="8884488700395194194">"may mahigit <xliff:g id="TIME_REMAINING">%1$s</xliff:g> pa"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="default" msgid="8168317165722752881">"malapit nang mag-shut down ang telepono"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="tablet" msgid="5957064378548718872">"malapit nang mag-shut down ang tablet"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="device" msgid="9055596817716471373">"malapit nang mag-shut down ang device"</string>
- <string name="power_discharging_duration" msgid="2843747179907396142">"<xliff:g id="LEVEL">%1$s</xliff:g> - humigit-kumulang <xliff:g id="TIME">%2$s</xliff:g> pa ang natitira"</string>
- <string name="power_discharging_duration_enhanced" msgid="4401782117770255046">"<xliff:g id="LEVEL">%1$s</xliff:g> - humigit-kumulang <xliff:g id="TIME">%2$s</xliff:g> ang natitira batay sa iyong paggamit"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="default" msgid="7679005631124015335">"<xliff:g id="LEVEL">%1$s</xliff:g> - malapit nang mag-shut down ang telepono"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="tablet" msgid="261050880878965621">"<xliff:g id="LEVEL">%1$s</xliff:g> - malapit nang mag-shut down ang tablet"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="device" msgid="2020049829798578618">"<xliff:g id="LEVEL">%1$s</xliff:g> - malapit nang mag-shut down ang device"</string>
+ <!-- no translation found for power_remaining_less_than_duration (5751885147712659423) -->
+ <skip />
+ <!-- no translation found for power_remaining_more_than_subtext (3176771815132876675) -->
+ <skip />
+ <!-- no translation found for power_remaining_only_more_than_subtext (8931654680569617380) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (1181059207608751924) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (2606370266981054691) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (2918084807716859985) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (3090926004324573908) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (7466484148515796216) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (603933521600231649) -->
+ <skip />
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
+ <string name="power_remaining_charging_duration_only" msgid="1421102457410268886">"<xliff:g id="TIME">%1$s</xliff:g> ang natitira bago makumpleto ang charge"</string>
<string name="power_charging_duration" msgid="4676999980973411875">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> hanggang sa makumpleto ang charge"</string>
<string name="battery_info_status_unknown" msgid="196130600938058547">"Hindi Kilala"</string>
<string name="battery_info_status_charging" msgid="1705179948350365604">"Nagcha-charge"</string>
diff --git a/packages/SettingsLib/res/values-tr/strings.xml b/packages/SettingsLib/res/values-tr/strings.xml
index 9fdeb4a..21707f4 100644
--- a/packages/SettingsLib/res/values-tr/strings.xml
+++ b/packages/SettingsLib/res/values-tr/strings.xml
@@ -220,7 +220,8 @@
<string name="select_private_dns_configuration_title" msgid="3700456559305263922">"Gizli DNS"</string>
<string name="select_private_dns_configuration_dialog_title" msgid="9221994415765826811">"Gizli DNS Modunu Seçin"</string>
<string name="private_dns_mode_off" msgid="8236575187318721684">"Kapalı"</string>
- <string name="private_dns_mode_opportunistic" msgid="7608409735589131766">"Fırsatçı"</string>
+ <!-- no translation found for private_dns_mode_opportunistic (8314986739896927399) -->
+ <skip />
<string name="private_dns_mode_provider" msgid="8354935160639360804">"Gizli DNS sağlayıcının ana makine adı"</string>
<string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"DNS sağlayıcının ana makine adını gir"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Kablosuz ekran sertifikası seçeneklerini göster"</string>
@@ -356,22 +357,41 @@
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Bu özellik deneyseldir ve performansı etkileyebilir."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"<xliff:g id="TITLE">%1$s</xliff:g> tarafından geçersiz kılındı"</string>
<string name="power_remaining_duration_only" msgid="845431008899029842">"Yaklaşık <xliff:g id="TIME">%1$s</xliff:g> kaldı"</string>
+ <!-- no translation found for power_discharging_duration (6655472132189365839) -->
+ <skip />
<string name="power_remaining_duration_only_enhanced" msgid="5992456722677973678">"Kullanımınıza dayalı olarak yaklaşık <xliff:g id="TIME">%1$s</xliff:g> kaldı"</string>
- <string name="power_remaining_charging_duration_only" msgid="1421102457410268886">"Tam olarak şarj olmasına <xliff:g id="TIME">%1$s</xliff:g> kaldı"</string>
+ <!-- no translation found for power_discharging_duration_enhanced (5726302316642148671) -->
+ <skip />
<string name="power_remaining_duration_only_short" msgid="5329694252258605547">"<xliff:g id="TIME">%1$s</xliff:g> kaldı"</string>
+ <!-- no translation found for power_discharge_by_enhanced (8788299408879961465) -->
+ <skip />
+ <!-- no translation found for power_discharge_by_only_enhanced (7692297898877104416) -->
+ <skip />
+ <!-- no translation found for power_discharge_by (6427074755635635749) -->
+ <skip />
+ <!-- no translation found for power_discharge_by_only (5888058889261108064) -->
+ <skip />
<string name="power_remaining_less_than_duration_only" msgid="5996752448813295329">"En fazla <xliff:g id="THRESHOLD">%1$s</xliff:g> kaldı"</string>
- <string name="power_remaining_less_than_duration" msgid="7967078125657859046">"<xliff:g id="LEVEL">%1$s</xliff:g> - En fazla <xliff:g id="THRESHOLD">%2$s</xliff:g> kaldı"</string>
- <string name="power_remaining_more_than_subtext" msgid="6846716609975752316">"<xliff:g id="LEVEL">%1$s</xliff:g> - en az <xliff:g id="TIME_REMAINING">%2$s</xliff:g> kaldı"</string>
- <string name="power_remaining_only_more_than_subtext" msgid="8884488700395194194">"en az <xliff:g id="TIME_REMAINING">%1$s</xliff:g> kaldı"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="default" msgid="8168317165722752881">"telefon kısa süre içinde kapanabilir"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="tablet" msgid="5957064378548718872">"tablet kısa süre içinde kapanabilir"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="device" msgid="9055596817716471373">"cihaz kısa süre içinde kapanabilir"</string>
- <string name="power_discharging_duration" msgid="2843747179907396142">"<xliff:g id="LEVEL">%1$s</xliff:g> - yaklaşık <xliff:g id="TIME">%2$s</xliff:g> kaldı"</string>
- <string name="power_discharging_duration_enhanced" msgid="4401782117770255046">"<xliff:g id="LEVEL">%1$s</xliff:g> - kullanımınıza dayalı olarak yaklaşık <xliff:g id="TIME">%2$s</xliff:g> kaldı"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="default" msgid="7679005631124015335">"<xliff:g id="LEVEL">%1$s</xliff:g> - telefon kısa süre içinde kapanabilir"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="tablet" msgid="261050880878965621">"<xliff:g id="LEVEL">%1$s</xliff:g> - tablet kısa süre içinde kapanabilir"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="device" msgid="2020049829798578618">"<xliff:g id="LEVEL">%1$s</xliff:g> - cihaz kısa süre içinde kapanabilir"</string>
+ <!-- no translation found for power_remaining_less_than_duration (5751885147712659423) -->
+ <skip />
+ <!-- no translation found for power_remaining_more_than_subtext (3176771815132876675) -->
+ <skip />
+ <!-- no translation found for power_remaining_only_more_than_subtext (8931654680569617380) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (1181059207608751924) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (2606370266981054691) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (2918084807716859985) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (3090926004324573908) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (7466484148515796216) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (603933521600231649) -->
+ <skip />
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
+ <string name="power_remaining_charging_duration_only" msgid="1421102457410268886">"Tam olarak şarj olmasına <xliff:g id="TIME">%1$s</xliff:g> kaldı"</string>
<string name="power_charging_duration" msgid="4676999980973411875">"<xliff:g id="LEVEL">%1$s</xliff:g> - Tam şarj olmasına <xliff:g id="TIME">%2$s</xliff:g> kaldı"</string>
<string name="battery_info_status_unknown" msgid="196130600938058547">"Bilinmiyor"</string>
<string name="battery_info_status_charging" msgid="1705179948350365604">"Şarj oluyor"</string>
diff --git a/packages/SettingsLib/res/values-uk/strings.xml b/packages/SettingsLib/res/values-uk/strings.xml
index 1c85633..d1e68e1 100644
--- a/packages/SettingsLib/res/values-uk/strings.xml
+++ b/packages/SettingsLib/res/values-uk/strings.xml
@@ -220,7 +220,8 @@
<string name="select_private_dns_configuration_title" msgid="3700456559305263922">"Приватна DNS"</string>
<string name="select_private_dns_configuration_dialog_title" msgid="9221994415765826811">"Виберіть режим \"Приватна DNS\""</string>
<string name="private_dns_mode_off" msgid="8236575187318721684">"Вимкнено"</string>
- <string name="private_dns_mode_opportunistic" msgid="7608409735589131766">"Періодично доступно"</string>
+ <!-- no translation found for private_dns_mode_opportunistic (8314986739896927399) -->
+ <skip />
<string name="private_dns_mode_provider" msgid="8354935160639360804">"Ім’я хосту приватного постачальника послуг DNS"</string>
<string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"Введіть ім’я хосту постачальника послуг DNS"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Показати параметри сертифікації бездротового екрана"</string>
@@ -356,22 +357,41 @@
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Це експериментальна функція. Вона може вплинути на продуктивність."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"Замінено на <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="power_remaining_duration_only" msgid="845431008899029842">"Залишилося близько <xliff:g id="TIME">%1$s</xliff:g>"</string>
+ <!-- no translation found for power_discharging_duration (6655472132189365839) -->
+ <skip />
<string name="power_remaining_duration_only_enhanced" msgid="5992456722677973678">"На основі використання залишилося близько <xliff:g id="TIME">%1$s</xliff:g>"</string>
- <string name="power_remaining_charging_duration_only" msgid="1421102457410268886">"До повного зарядження залишилося <xliff:g id="TIME">%1$s</xliff:g>"</string>
+ <!-- no translation found for power_discharging_duration_enhanced (5726302316642148671) -->
+ <skip />
<string name="power_remaining_duration_only_short" msgid="5329694252258605547">"Залишилося <xliff:g id="TIME">%1$s</xliff:g>"</string>
+ <!-- no translation found for power_discharge_by_enhanced (8788299408879961465) -->
+ <skip />
+ <!-- no translation found for power_discharge_by_only_enhanced (7692297898877104416) -->
+ <skip />
+ <!-- no translation found for power_discharge_by (6427074755635635749) -->
+ <skip />
+ <!-- no translation found for power_discharge_by_only (5888058889261108064) -->
+ <skip />
<string name="power_remaining_less_than_duration_only" msgid="5996752448813295329">"Залишилося менше ніж <xliff:g id="THRESHOLD">%1$s</xliff:g>"</string>
- <string name="power_remaining_less_than_duration" msgid="7967078125657859046">"<xliff:g id="LEVEL">%1$s</xliff:g> – залишилося менше ніж <xliff:g id="THRESHOLD">%2$s</xliff:g>"</string>
- <string name="power_remaining_more_than_subtext" msgid="6846716609975752316">"<xliff:g id="LEVEL">%1$s</xliff:g> – залишилося більше ніж <xliff:g id="TIME_REMAINING">%2$s</xliff:g>"</string>
- <string name="power_remaining_only_more_than_subtext" msgid="8884488700395194194">"залишилося більше ніж <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="default" msgid="8168317165722752881">"телефон може невдовзі вимкнутися"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="tablet" msgid="5957064378548718872">"планшет може невдовзі вимкнутися"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="device" msgid="9055596817716471373">"пристрій може невдовзі вимкнутися"</string>
- <string name="power_discharging_duration" msgid="2843747179907396142">"<xliff:g id="LEVEL">%1$s</xliff:g> – ще <xliff:g id="TIME">%2$s</xliff:g>"</string>
- <string name="power_discharging_duration_enhanced" msgid="4401782117770255046">"<xliff:g id="LEVEL">%1$s</xliff:g> – на основі використання залишилося близько <xliff:g id="TIME">%2$s</xliff:g>"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="default" msgid="7679005631124015335">"<xliff:g id="LEVEL">%1$s</xliff:g> – телефон може невдовзі вимкнутися"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="tablet" msgid="261050880878965621">"<xliff:g id="LEVEL">%1$s</xliff:g> – планшет може невдовзі вимкнутися"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="device" msgid="2020049829798578618">"<xliff:g id="LEVEL">%1$s</xliff:g> – пристрій може невдовзі вимкнутися"</string>
+ <!-- no translation found for power_remaining_less_than_duration (5751885147712659423) -->
+ <skip />
+ <!-- no translation found for power_remaining_more_than_subtext (3176771815132876675) -->
+ <skip />
+ <!-- no translation found for power_remaining_only_more_than_subtext (8931654680569617380) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (1181059207608751924) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (2606370266981054691) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (2918084807716859985) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (3090926004324573908) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (7466484148515796216) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (603933521600231649) -->
+ <skip />
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string>
+ <string name="power_remaining_charging_duration_only" msgid="1421102457410268886">"До повного зарядження залишилося <xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="4676999980973411875">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> до повного заряду"</string>
<string name="battery_info_status_unknown" msgid="196130600938058547">"Невідомо"</string>
<string name="battery_info_status_charging" msgid="1705179948350365604">"Заряджається"</string>
diff --git a/packages/SettingsLib/res/values-ur/strings.xml b/packages/SettingsLib/res/values-ur/strings.xml
index 7c221d7..82686bd 100644
--- a/packages/SettingsLib/res/values-ur/strings.xml
+++ b/packages/SettingsLib/res/values-ur/strings.xml
@@ -220,7 +220,8 @@
<string name="select_private_dns_configuration_title" msgid="3700456559305263922">"نجی DNS"</string>
<string name="select_private_dns_configuration_dialog_title" msgid="9221994415765826811">"نجی DNS وضع منتخب کریں"</string>
<string name="private_dns_mode_off" msgid="8236575187318721684">"آف"</string>
- <string name="private_dns_mode_opportunistic" msgid="7608409735589131766">"موقع پرست"</string>
+ <!-- no translation found for private_dns_mode_opportunistic (8314986739896927399) -->
+ <skip />
<string name="private_dns_mode_provider" msgid="8354935160639360804">"نجی DNS فراہم کنندہ میزبان کا نام"</string>
<string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"DNS فراہم کنندہ کے میزبان کا نام درج کریں"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"وائرلیس ڈسپلے سرٹیفیکیشن کیلئے اختیارات دکھائیں"</string>
@@ -356,22 +357,41 @@
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"یہ خصوصیت تجرباتی ہے اور اس کی وجہ سے کاکردگی متاثر ہو سکتی ہے۔"</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"<xliff:g id="TITLE">%1$s</xliff:g> کے ذریعہ منسوخ کردیا گیا"</string>
<string name="power_remaining_duration_only" msgid="845431008899029842">"تقریبًا <xliff:g id="TIME">%1$s</xliff:g> باقی ہے"</string>
+ <!-- no translation found for power_discharging_duration (6655472132189365839) -->
+ <skip />
<string name="power_remaining_duration_only_enhanced" msgid="5992456722677973678">"آپ کے استعمال کی بنیاد پر تقریباً <xliff:g id="TIME">%1$s</xliff:g> باقی ہے"</string>
- <string name="power_remaining_charging_duration_only" msgid="1421102457410268886">"پوری طرح چارج ہونے میں <xliff:g id="TIME">%1$s</xliff:g> باقی ہے"</string>
+ <!-- no translation found for power_discharging_duration_enhanced (5726302316642148671) -->
+ <skip />
<string name="power_remaining_duration_only_short" msgid="5329694252258605547">"<xliff:g id="TIME">%1$s</xliff:g> باقی ہے"</string>
+ <!-- no translation found for power_discharge_by_enhanced (8788299408879961465) -->
+ <skip />
+ <!-- no translation found for power_discharge_by_only_enhanced (7692297898877104416) -->
+ <skip />
+ <!-- no translation found for power_discharge_by (6427074755635635749) -->
+ <skip />
+ <!-- no translation found for power_discharge_by_only (5888058889261108064) -->
+ <skip />
<string name="power_remaining_less_than_duration_only" msgid="5996752448813295329">"<xliff:g id="THRESHOLD">%1$s</xliff:g> سے کم باقی ہے"</string>
- <string name="power_remaining_less_than_duration" msgid="7967078125657859046">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="THRESHOLD">%2$s</xliff:g> سے کم باقی ہے"</string>
- <string name="power_remaining_more_than_subtext" msgid="6846716609975752316">"<xliff:g id="LEVEL">%1$s</xliff:g> <xliff:g id="TIME_REMAINING">%2$s</xliff:g> سے زیادہ باقی ہے"</string>
- <string name="power_remaining_only_more_than_subtext" msgid="8884488700395194194">"<xliff:g id="TIME_REMAINING">%1$s</xliff:g> سے زیادہ باقی ہے"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="default" msgid="8168317165722752881">"فون جلد ہی بند ہو سکتا ہے"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="tablet" msgid="5957064378548718872">"ٹیبلیٹ جلد ہی بند ہو سکتا ہے"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="device" msgid="9055596817716471373">"آلہ جلد ہی بند ہو سکتا ہے"</string>
- <string name="power_discharging_duration" msgid="2843747179907396142">"<xliff:g id="LEVEL">%1$s</xliff:g> - تقریباً <xliff:g id="TIME">%2$s</xliff:g> باقی ہے"</string>
- <string name="power_discharging_duration_enhanced" msgid="4401782117770255046">"<xliff:g id="LEVEL">%1$s</xliff:g> - آپ کے استعمال کی بنیاد پر تقریباً <xliff:g id="TIME">%2$s</xliff:g> باقی ہے"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="default" msgid="7679005631124015335">"<xliff:g id="LEVEL">%1$s</xliff:g> - فون جلد ہی بند ہو سکتا ہے"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="tablet" msgid="261050880878965621">"<xliff:g id="LEVEL">%1$s</xliff:g> - ٹیبلیٹ جلد ہی بند ہو سکتا ہے"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="device" msgid="2020049829798578618">"<xliff:g id="LEVEL">%1$s</xliff:g> - آلہ جلد ہی بند ہو سکتا ہے"</string>
+ <!-- no translation found for power_remaining_less_than_duration (5751885147712659423) -->
+ <skip />
+ <!-- no translation found for power_remaining_more_than_subtext (3176771815132876675) -->
+ <skip />
+ <!-- no translation found for power_remaining_only_more_than_subtext (8931654680569617380) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (1181059207608751924) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (2606370266981054691) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (2918084807716859985) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (3090926004324573908) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (7466484148515796216) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (603933521600231649) -->
+ <skip />
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
+ <string name="power_remaining_charging_duration_only" msgid="1421102457410268886">"پوری طرح چارج ہونے میں <xliff:g id="TIME">%1$s</xliff:g> باقی ہے"</string>
<string name="power_charging_duration" msgid="4676999980973411875">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> پوری طرح چارج ہونے تک"</string>
<string name="battery_info_status_unknown" msgid="196130600938058547">"نامعلوم"</string>
<string name="battery_info_status_charging" msgid="1705179948350365604">"چارج ہو رہا ہے"</string>
diff --git a/packages/SettingsLib/res/values-uz/strings.xml b/packages/SettingsLib/res/values-uz/strings.xml
index 725d92f..4043e98 100644
--- a/packages/SettingsLib/res/values-uz/strings.xml
+++ b/packages/SettingsLib/res/values-uz/strings.xml
@@ -220,7 +220,8 @@
<string name="select_private_dns_configuration_title" msgid="3700456559305263922">"Shaxsiy DNS"</string>
<string name="select_private_dns_configuration_dialog_title" msgid="9221994415765826811">"Shaxsiy DNS rejimini tanlang"</string>
<string name="private_dns_mode_off" msgid="8236575187318721684">"O‘chiq"</string>
- <string name="private_dns_mode_opportunistic" msgid="7608409735589131766">"Moslashuvchan"</string>
+ <!-- no translation found for private_dns_mode_opportunistic (8314986739896927399) -->
+ <skip />
<string name="private_dns_mode_provider" msgid="8354935160639360804">"Shaxsiy DNS provayderining host nomi"</string>
<string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"DNS provayderining host nomini kiriting"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Simsiz monitorlarni sertifikatlash parametrini ko‘rsatish"</string>
@@ -356,22 +357,41 @@
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Bu funksiya tajribaviy bo‘lib, u qurilma unumdorligiga ta’sir qilishi mumkin."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"<xliff:g id="TITLE">%1$s</xliff:g> bilan almashtirildi"</string>
<string name="power_remaining_duration_only" msgid="845431008899029842">"Taxminan <xliff:g id="TIME">%1$s</xliff:g> qoldi"</string>
+ <!-- no translation found for power_discharging_duration (6655472132189365839) -->
+ <skip />
<string name="power_remaining_duration_only_enhanced" msgid="5992456722677973678">"Joriy holatda taxminan <xliff:g id="TIME">%1$s</xliff:g> qoldi"</string>
- <string name="power_remaining_charging_duration_only" msgid="1421102457410268886">"To‘lishiga <xliff:g id="TIME">%1$s</xliff:g> qoldi"</string>
+ <!-- no translation found for power_discharging_duration_enhanced (5726302316642148671) -->
+ <skip />
<string name="power_remaining_duration_only_short" msgid="5329694252258605547">"<xliff:g id="TIME">%1$s</xliff:g> qoldi"</string>
+ <!-- no translation found for power_discharge_by_enhanced (8788299408879961465) -->
+ <skip />
+ <!-- no translation found for power_discharge_by_only_enhanced (7692297898877104416) -->
+ <skip />
+ <!-- no translation found for power_discharge_by (6427074755635635749) -->
+ <skip />
+ <!-- no translation found for power_discharge_by_only (5888058889261108064) -->
+ <skip />
<string name="power_remaining_less_than_duration_only" msgid="5996752448813295329">"<xliff:g id="THRESHOLD">%1$s</xliff:g>dan kamroq vaqt qoldi"</string>
- <string name="power_remaining_less_than_duration" msgid="7967078125657859046">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="THRESHOLD">%2$s</xliff:g>dan kamroq vaqt qoldi"</string>
- <string name="power_remaining_more_than_subtext" msgid="6846716609975752316">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME_REMAINING">%2$s</xliff:g>dan ko‘proq vaqt qoldi"</string>
- <string name="power_remaining_only_more_than_subtext" msgid="8884488700395194194">"<xliff:g id="TIME_REMAINING">%1$s</xliff:g>dan ko‘proq vaqt qoldi"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="default" msgid="8168317165722752881">"telefon tez orada o‘chib qolishi mumkin"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="tablet" msgid="5957064378548718872">"planshet tez orada o‘chib qolishi mumkin"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="device" msgid="9055596817716471373">"qurilma tez orada o‘chib qolishi mumkin"</string>
- <string name="power_discharging_duration" msgid="2843747179907396142">"<xliff:g id="LEVEL">%1$s</xliff:g> – taxminan <xliff:g id="TIME">%2$s</xliff:g> qoldi"</string>
- <string name="power_discharging_duration_enhanced" msgid="4401782117770255046">"<xliff:g id="LEVEL">%1$s</xliff:g> (joriy holatda taxminan <xliff:g id="TIME">%2$s</xliff:g> qoldi)"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="default" msgid="7679005631124015335">"<xliff:g id="LEVEL">%1$s</xliff:g> – telefon tez orada o‘chib qolishi mumkin"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="tablet" msgid="261050880878965621">"<xliff:g id="LEVEL">%1$s</xliff:g> – planshet tez orada o‘chib qolishi mumkin"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="device" msgid="2020049829798578618">"<xliff:g id="LEVEL">%1$s</xliff:g> – qurilma tez orada o‘chib qolishi mumkin"</string>
+ <!-- no translation found for power_remaining_less_than_duration (5751885147712659423) -->
+ <skip />
+ <!-- no translation found for power_remaining_more_than_subtext (3176771815132876675) -->
+ <skip />
+ <!-- no translation found for power_remaining_only_more_than_subtext (8931654680569617380) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (1181059207608751924) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (2606370266981054691) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (2918084807716859985) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (3090926004324573908) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (7466484148515796216) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (603933521600231649) -->
+ <skip />
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string>
+ <string name="power_remaining_charging_duration_only" msgid="1421102457410268886">"To‘lishiga <xliff:g id="TIME">%1$s</xliff:g> qoldi"</string>
<string name="power_charging_duration" msgid="4676999980973411875">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> ichida to‘ladi"</string>
<string name="battery_info_status_unknown" msgid="196130600938058547">"Noma’lum"</string>
<string name="battery_info_status_charging" msgid="1705179948350365604">"Quvvat olmoqda"</string>
diff --git a/packages/SettingsLib/res/values-vi/strings.xml b/packages/SettingsLib/res/values-vi/strings.xml
index 74bac0a..f05a1a8 100644
--- a/packages/SettingsLib/res/values-vi/strings.xml
+++ b/packages/SettingsLib/res/values-vi/strings.xml
@@ -220,7 +220,8 @@
<string name="select_private_dns_configuration_title" msgid="3700456559305263922">"DNS riêng tư"</string>
<string name="select_private_dns_configuration_dialog_title" msgid="9221994415765826811">"Chọn chế độ DNS riêng tư"</string>
<string name="private_dns_mode_off" msgid="8236575187318721684">"Tắt"</string>
- <string name="private_dns_mode_opportunistic" msgid="7608409735589131766">"Cơ hội"</string>
+ <!-- no translation found for private_dns_mode_opportunistic (8314986739896927399) -->
+ <skip />
<string name="private_dns_mode_provider" msgid="8354935160639360804">"Tên máy chủ của nhà cung cấp DNS riêng tư"</string>
<string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"Nhập tên máy chủ của nhà cung cấp DNS"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Hiển thị tùy chọn chứng nhận hiển thị không dây"</string>
@@ -356,22 +357,41 @@
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Tính năng này là tính năng thử nghiệm và có thể ảnh hưởng đến hoạt động."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"Bị ghi đè bởi <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="power_remaining_duration_only" msgid="845431008899029842">"Còn khoảng <xliff:g id="TIME">%1$s</xliff:g>"</string>
+ <!-- no translation found for power_discharging_duration (6655472132189365839) -->
+ <skip />
<string name="power_remaining_duration_only_enhanced" msgid="5992456722677973678">"Còn khoảng <xliff:g id="TIME">%1$s</xliff:g> dựa trên mức sử dụng của bạn"</string>
- <string name="power_remaining_charging_duration_only" msgid="1421102457410268886">"Còn <xliff:g id="TIME">%1$s</xliff:g> cho tới khi được sạc đầy"</string>
+ <!-- no translation found for power_discharging_duration_enhanced (5726302316642148671) -->
+ <skip />
<string name="power_remaining_duration_only_short" msgid="5329694252258605547">"Còn lại <xliff:g id="TIME">%1$s</xliff:g>"</string>
+ <!-- no translation found for power_discharge_by_enhanced (8788299408879961465) -->
+ <skip />
+ <!-- no translation found for power_discharge_by_only_enhanced (7692297898877104416) -->
+ <skip />
+ <!-- no translation found for power_discharge_by (6427074755635635749) -->
+ <skip />
+ <!-- no translation found for power_discharge_by_only (5888058889261108064) -->
+ <skip />
<string name="power_remaining_less_than_duration_only" msgid="5996752448813295329">"Còn lại không đến <xliff:g id="THRESHOLD">%1$s</xliff:g>"</string>
- <string name="power_remaining_less_than_duration" msgid="7967078125657859046">"<xliff:g id="LEVEL">%1$s</xliff:g> - Còn lại không đến <xliff:g id="THRESHOLD">%2$s</xliff:g>"</string>
- <string name="power_remaining_more_than_subtext" msgid="6846716609975752316">"<xliff:g id="LEVEL">%1$s</xliff:g> còn lại hơn <xliff:g id="TIME_REMAINING">%2$s</xliff:g>"</string>
- <string name="power_remaining_only_more_than_subtext" msgid="8884488700395194194">"còn lại hơn <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="default" msgid="8168317165722752881">"điện thoại có thể sắp tắt"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="tablet" msgid="5957064378548718872">"máy tính bảng có thể sắp tắt"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="device" msgid="9055596817716471373">"thiết bị có thể sắp tắt"</string>
- <string name="power_discharging_duration" msgid="2843747179907396142">"<xliff:g id="LEVEL">%1$s</xliff:g> - còn khoảng <xliff:g id="TIME">%2$s</xliff:g>"</string>
- <string name="power_discharging_duration_enhanced" msgid="4401782117770255046">"<xliff:g id="LEVEL">%1$s</xliff:g> - còn khoảng <xliff:g id="TIME">%2$s</xliff:g> dựa trên mức sử dụng của bạn"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="default" msgid="7679005631124015335">"<xliff:g id="LEVEL">%1$s</xliff:g> - điện thoại có thể sắp tắt"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="tablet" msgid="261050880878965621">"<xliff:g id="LEVEL">%1$s</xliff:g> - máy tính bảng có thể sắp tắt"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="device" msgid="2020049829798578618">"<xliff:g id="LEVEL">%1$s</xliff:g> - thiết bị có thể sắp tắt"</string>
+ <!-- no translation found for power_remaining_less_than_duration (5751885147712659423) -->
+ <skip />
+ <!-- no translation found for power_remaining_more_than_subtext (3176771815132876675) -->
+ <skip />
+ <!-- no translation found for power_remaining_only_more_than_subtext (8931654680569617380) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (1181059207608751924) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (2606370266981054691) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (2918084807716859985) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (3090926004324573908) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (7466484148515796216) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (603933521600231649) -->
+ <skip />
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
+ <string name="power_remaining_charging_duration_only" msgid="1421102457410268886">"Còn <xliff:g id="TIME">%1$s</xliff:g> cho tới khi được sạc đầy"</string>
<string name="power_charging_duration" msgid="4676999980973411875">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> cho tới khi được sạc đầy"</string>
<string name="battery_info_status_unknown" msgid="196130600938058547">"Không xác định"</string>
<string name="battery_info_status_charging" msgid="1705179948350365604">"Đang sạc"</string>
diff --git a/packages/SettingsLib/res/values-zh-rCN/strings.xml b/packages/SettingsLib/res/values-zh-rCN/strings.xml
index 3590ace..8c2342e 100644
--- a/packages/SettingsLib/res/values-zh-rCN/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rCN/strings.xml
@@ -220,7 +220,8 @@
<string name="select_private_dns_configuration_title" msgid="3700456559305263922">"私人 DNS"</string>
<string name="select_private_dns_configuration_dialog_title" msgid="9221994415765826811">"选择私人 DNS 模式"</string>
<string name="private_dns_mode_off" msgid="8236575187318721684">"关闭"</string>
- <string name="private_dns_mode_opportunistic" msgid="7608409735589131766">"随机"</string>
+ <!-- no translation found for private_dns_mode_opportunistic (8314986739896927399) -->
+ <skip />
<string name="private_dns_mode_provider" msgid="8354935160639360804">"私人 DNS 提供商主机名"</string>
<string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"输入 DNS 提供商的主机名"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"显示无线显示认证选项"</string>
@@ -356,22 +357,41 @@
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"这是实验性功能,性能可能不稳定。"</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"已被“<xliff:g id="TITLE">%1$s</xliff:g>”覆盖"</string>
<string name="power_remaining_duration_only" msgid="845431008899029842">"还剩大约 <xliff:g id="TIME">%1$s</xliff:g>"</string>
+ <!-- no translation found for power_discharging_duration (6655472132189365839) -->
+ <skip />
<string name="power_remaining_duration_only_enhanced" msgid="5992456722677973678">"根据您的使用情况,大约还可使用 <xliff:g id="TIME">%1$s</xliff:g>"</string>
- <string name="power_remaining_charging_duration_only" msgid="1421102457410268886">"还需 <xliff:g id="TIME">%1$s</xliff:g>充满电"</string>
+ <!-- no translation found for power_discharging_duration_enhanced (5726302316642148671) -->
+ <skip />
<string name="power_remaining_duration_only_short" msgid="5329694252258605547">"还可用 <xliff:g id="TIME">%1$s</xliff:g>"</string>
+ <!-- no translation found for power_discharge_by_enhanced (8788299408879961465) -->
+ <skip />
+ <!-- no translation found for power_discharge_by_only_enhanced (7692297898877104416) -->
+ <skip />
+ <!-- no translation found for power_discharge_by (6427074755635635749) -->
+ <skip />
+ <!-- no translation found for power_discharge_by_only (5888058889261108064) -->
+ <skip />
<string name="power_remaining_less_than_duration_only" msgid="5996752448813295329">"剩余电池续航时间不到 <xliff:g id="THRESHOLD">%1$s</xliff:g>"</string>
- <string name="power_remaining_less_than_duration" msgid="7967078125657859046">"<xliff:g id="LEVEL">%1$s</xliff:g> - 剩余电池续航时间不到 <xliff:g id="THRESHOLD">%2$s</xliff:g>"</string>
- <string name="power_remaining_more_than_subtext" msgid="6846716609975752316">"<xliff:g id="LEVEL">%1$s</xliff:g> - 剩余电池续航时间超过 <xliff:g id="TIME_REMAINING">%2$s</xliff:g>"</string>
- <string name="power_remaining_only_more_than_subtext" msgid="8884488700395194194">"剩余电池续航时间超过 <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="default" msgid="8168317165722752881">"手机可能即将关机"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="tablet" msgid="5957064378548718872">"平板电脑可能即将关机"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="device" msgid="9055596817716471373">"设备可能即将关机"</string>
- <string name="power_discharging_duration" msgid="2843747179907396142">"<xliff:g id="LEVEL">%1$s</xliff:g> - 大约还剩 <xliff:g id="TIME">%2$s</xliff:g>"</string>
- <string name="power_discharging_duration_enhanced" msgid="4401782117770255046">"<xliff:g id="LEVEL">%1$s</xliff:g> - 根据您的使用情况,大约还可使用 <xliff:g id="TIME">%2$s</xliff:g>"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="default" msgid="7679005631124015335">"<xliff:g id="LEVEL">%1$s</xliff:g> - 手机可能即将关机"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="tablet" msgid="261050880878965621">"<xliff:g id="LEVEL">%1$s</xliff:g> - 平板电脑可能即将关机"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="device" msgid="2020049829798578618">"<xliff:g id="LEVEL">%1$s</xliff:g> - 设备可能即将关机"</string>
+ <!-- no translation found for power_remaining_less_than_duration (5751885147712659423) -->
+ <skip />
+ <!-- no translation found for power_remaining_more_than_subtext (3176771815132876675) -->
+ <skip />
+ <!-- no translation found for power_remaining_only_more_than_subtext (8931654680569617380) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (1181059207608751924) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (2606370266981054691) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (2918084807716859985) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (3090926004324573908) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (7466484148515796216) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (603933521600231649) -->
+ <skip />
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
+ <string name="power_remaining_charging_duration_only" msgid="1421102457410268886">"还需 <xliff:g id="TIME">%1$s</xliff:g>充满电"</string>
<string name="power_charging_duration" msgid="4676999980973411875">"<xliff:g id="LEVEL">%1$s</xliff:g> - 还需 <xliff:g id="TIME">%2$s</xliff:g>充满"</string>
<string name="battery_info_status_unknown" msgid="196130600938058547">"未知"</string>
<string name="battery_info_status_charging" msgid="1705179948350365604">"正在充电"</string>
diff --git a/packages/SettingsLib/res/values-zh-rHK/strings.xml b/packages/SettingsLib/res/values-zh-rHK/strings.xml
index f2162f4..6f03f0b 100644
--- a/packages/SettingsLib/res/values-zh-rHK/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rHK/strings.xml
@@ -220,7 +220,8 @@
<string name="select_private_dns_configuration_title" msgid="3700456559305263922">"不公開的網域名稱系統 (DNS)"</string>
<string name="select_private_dns_configuration_dialog_title" msgid="9221994415765826811">"選取不公開的網域名稱系統 (DNS) 模式"</string>
<string name="private_dns_mode_off" msgid="8236575187318721684">"停用"</string>
- <string name="private_dns_mode_opportunistic" msgid="7608409735589131766">"隨機"</string>
+ <!-- no translation found for private_dns_mode_opportunistic (8314986739896927399) -->
+ <skip />
<string name="private_dns_mode_provider" msgid="8354935160639360804">"不公開的網域名稱系統 (DNS) 供應商主機名稱"</string>
<string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"輸入網域名稱系統 (DNS) 供應商的主機名稱"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"顯示無線螢幕分享認證的選項"</string>
@@ -356,22 +357,41 @@
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"這是實驗性功能,效能尚待改善。"</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"已由「<xliff:g id="TITLE">%1$s</xliff:g>」覆寫"</string>
<string name="power_remaining_duration_only" msgid="845431008899029842">"剩餘約 <xliff:g id="TIME">%1$s</xliff:g>"</string>
+ <!-- no translation found for power_discharging_duration (6655472132189365839) -->
+ <skip />
<string name="power_remaining_duration_only_enhanced" msgid="5992456722677973678">"根據您的使用情況,剩餘約 <xliff:g id="TIME">%1$s</xliff:g>"</string>
- <string name="power_remaining_charging_duration_only" msgid="1421102457410268886">"<xliff:g id="TIME">%1$s</xliff:g>後就能充滿電"</string>
+ <!-- no translation found for power_discharging_duration_enhanced (5726302316642148671) -->
+ <skip />
<string name="power_remaining_duration_only_short" msgid="5329694252258605547">"尚餘 <xliff:g id="TIME">%1$s</xliff:g>"</string>
+ <!-- no translation found for power_discharge_by_enhanced (8788299408879961465) -->
+ <skip />
+ <!-- no translation found for power_discharge_by_only_enhanced (7692297898877104416) -->
+ <skip />
+ <!-- no translation found for power_discharge_by (6427074755635635749) -->
+ <skip />
+ <!-- no translation found for power_discharge_by_only (5888058889261108064) -->
+ <skip />
<string name="power_remaining_less_than_duration_only" msgid="5996752448813295329">"剩餘電量時間少於 <xliff:g id="THRESHOLD">%1$s</xliff:g>"</string>
- <string name="power_remaining_less_than_duration" msgid="7967078125657859046">"<xliff:g id="LEVEL">%1$s</xliff:g> - 剩餘電量時間少於 <xliff:g id="THRESHOLD">%2$s</xliff:g>"</string>
- <string name="power_remaining_more_than_subtext" msgid="6846716609975752316">"<xliff:g id="LEVEL">%1$s</xliff:g> - 剩餘電量時間超過 <xliff:g id="TIME_REMAINING">%2$s</xliff:g>"</string>
- <string name="power_remaining_only_more_than_subtext" msgid="8884488700395194194">"剩餘電量時間超過 <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="default" msgid="8168317165722752881">"手機可能即將關機"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="tablet" msgid="5957064378548718872">"平板電腦可能即將關機"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="device" msgid="9055596817716471373">"裝置可能即將關機"</string>
- <string name="power_discharging_duration" msgid="2843747179907396142">"<xliff:g id="LEVEL">%1$s</xliff:g> - 剩餘約 <xliff:g id="TIME">%2$s</xliff:g>"</string>
- <string name="power_discharging_duration_enhanced" msgid="4401782117770255046">"<xliff:g id="LEVEL">%1$s</xliff:g> - 根據您的使用情況,剩餘約 <xliff:g id="TIME">%2$s</xliff:g>"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="default" msgid="7679005631124015335">"<xliff:g id="LEVEL">%1$s</xliff:g> - 手機可能即將關機"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="tablet" msgid="261050880878965621">"<xliff:g id="LEVEL">%1$s</xliff:g> - 平板電腦可能即將關機"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="device" msgid="2020049829798578618">"<xliff:g id="LEVEL">%1$s</xliff:g> - 裝置可能即將關機"</string>
+ <!-- no translation found for power_remaining_less_than_duration (5751885147712659423) -->
+ <skip />
+ <!-- no translation found for power_remaining_more_than_subtext (3176771815132876675) -->
+ <skip />
+ <!-- no translation found for power_remaining_only_more_than_subtext (8931654680569617380) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (1181059207608751924) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (2606370266981054691) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (2918084807716859985) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (3090926004324573908) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (7466484148515796216) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (603933521600231649) -->
+ <skip />
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
+ <string name="power_remaining_charging_duration_only" msgid="1421102457410268886">"<xliff:g id="TIME">%1$s</xliff:g>後就能充滿電"</string>
<string name="power_charging_duration" msgid="4676999980973411875">"<xliff:g id="LEVEL">%1$s</xliff:g> - 還需 <xliff:g id="TIME">%2$s</xliff:g>才能充滿電"</string>
<string name="battery_info_status_unknown" msgid="196130600938058547">"未知"</string>
<string name="battery_info_status_charging" msgid="1705179948350365604">"充電中"</string>
diff --git a/packages/SettingsLib/res/values-zh-rTW/strings.xml b/packages/SettingsLib/res/values-zh-rTW/strings.xml
index fa3001a..9856879 100644
--- a/packages/SettingsLib/res/values-zh-rTW/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rTW/strings.xml
@@ -220,7 +220,8 @@
<string name="select_private_dns_configuration_title" msgid="3700456559305263922">"私人 DNS"</string>
<string name="select_private_dns_configuration_dialog_title" msgid="9221994415765826811">"選取私人 DNS 模式"</string>
<string name="private_dns_mode_off" msgid="8236575187318721684">"停用"</string>
- <string name="private_dns_mode_opportunistic" msgid="7608409735589131766">"隨機"</string>
+ <!-- no translation found for private_dns_mode_opportunistic (8314986739896927399) -->
+ <skip />
<string name="private_dns_mode_provider" msgid="8354935160639360804">"私人 DNS 供應商主機名稱"</string>
<string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"輸入 DNS 供應商的主機名稱"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"顯示無線螢幕分享認證的選項"</string>
@@ -356,22 +357,41 @@
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"這是一項實驗性功能,可能會對效能造成影響。"</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"已改為<xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="power_remaining_duration_only" msgid="845431008899029842">"還有大約 <xliff:g id="TIME">%1$s</xliff:g>"</string>
+ <!-- no translation found for power_discharging_duration (6655472132189365839) -->
+ <skip />
<string name="power_remaining_duration_only_enhanced" msgid="5992456722677973678">"根據你的使用情形,剩餘時間大約還有 <xliff:g id="TIME">%1$s</xliff:g>"</string>
- <string name="power_remaining_charging_duration_only" msgid="1421102457410268886">"再過 <xliff:g id="TIME">%1$s</xliff:g>就能完成充電"</string>
+ <!-- no translation found for power_discharging_duration_enhanced (5726302316642148671) -->
+ <skip />
<string name="power_remaining_duration_only_short" msgid="5329694252258605547">"還剩 <xliff:g id="TIME">%1$s</xliff:g>"</string>
+ <!-- no translation found for power_discharge_by_enhanced (8788299408879961465) -->
+ <skip />
+ <!-- no translation found for power_discharge_by_only_enhanced (7692297898877104416) -->
+ <skip />
+ <!-- no translation found for power_discharge_by (6427074755635635749) -->
+ <skip />
+ <!-- no translation found for power_discharge_by_only (5888058889261108064) -->
+ <skip />
<string name="power_remaining_less_than_duration_only" msgid="5996752448813295329">"電池可用時間不到 <xliff:g id="THRESHOLD">%1$s</xliff:g>"</string>
- <string name="power_remaining_less_than_duration" msgid="7967078125657859046">"<xliff:g id="LEVEL">%1$s</xliff:g> - 電池可用時間不到 <xliff:g id="THRESHOLD">%2$s</xliff:g>"</string>
- <string name="power_remaining_more_than_subtext" msgid="6846716609975752316">"<xliff:g id="LEVEL">%1$s</xliff:g> - 電池可用時間超過 <xliff:g id="TIME_REMAINING">%2$s</xliff:g>"</string>
- <string name="power_remaining_only_more_than_subtext" msgid="8884488700395194194">"電池可用時間超過 <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="default" msgid="8168317165722752881">"手機可能即將關機"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="tablet" msgid="5957064378548718872">"平板電腦可能即將關機"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="device" msgid="9055596817716471373">"裝置可能即將關機"</string>
- <string name="power_discharging_duration" msgid="2843747179907396142">"<xliff:g id="LEVEL">%1$s</xliff:g> - 約剩 <xliff:g id="TIME">%2$s</xliff:g>"</string>
- <string name="power_discharging_duration_enhanced" msgid="4401782117770255046">"<xliff:g id="LEVEL">%1$s</xliff:g> - 根據你的使用情形,剩餘時間大約還有 <xliff:g id="TIME">%2$s</xliff:g>"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="default" msgid="7679005631124015335">"<xliff:g id="LEVEL">%1$s</xliff:g> - 手機可能即將關機"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="tablet" msgid="261050880878965621">"<xliff:g id="LEVEL">%1$s</xliff:g> - 平板電腦可能即將關機"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="device" msgid="2020049829798578618">"<xliff:g id="LEVEL">%1$s</xliff:g> - 裝置可能即將關機"</string>
+ <!-- no translation found for power_remaining_less_than_duration (5751885147712659423) -->
+ <skip />
+ <!-- no translation found for power_remaining_more_than_subtext (3176771815132876675) -->
+ <skip />
+ <!-- no translation found for power_remaining_only_more_than_subtext (8931654680569617380) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (1181059207608751924) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (2606370266981054691) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (2918084807716859985) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (3090926004324573908) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (7466484148515796216) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (603933521600231649) -->
+ <skip />
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
+ <string name="power_remaining_charging_duration_only" msgid="1421102457410268886">"再過 <xliff:g id="TIME">%1$s</xliff:g>就能完成充電"</string>
<string name="power_charging_duration" msgid="4676999980973411875">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g>後充飽"</string>
<string name="battery_info_status_unknown" msgid="196130600938058547">"不明"</string>
<string name="battery_info_status_charging" msgid="1705179948350365604">"充電中"</string>
diff --git a/packages/SettingsLib/res/values-zu/strings.xml b/packages/SettingsLib/res/values-zu/strings.xml
index 5a4180c..64861ec 100644
--- a/packages/SettingsLib/res/values-zu/strings.xml
+++ b/packages/SettingsLib/res/values-zu/strings.xml
@@ -220,7 +220,8 @@
<string name="select_private_dns_configuration_title" msgid="3700456559305263922">"I-DNS eyimfihlo"</string>
<string name="select_private_dns_configuration_dialog_title" msgid="9221994415765826811">"Khetha imodi ye-DNS eyimfihlo"</string>
<string name="private_dns_mode_off" msgid="8236575187318721684">"Kuvaliwe"</string>
- <string name="private_dns_mode_opportunistic" msgid="7608409735589131766">"Amathuba"</string>
+ <!-- no translation found for private_dns_mode_opportunistic (8314986739896927399) -->
+ <skip />
<string name="private_dns_mode_provider" msgid="8354935160639360804">"Igama lomsingathi womhlinzeki we-DNS"</string>
<string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"Faka igama lomsingathi womhlinzeki we-DNS"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Bonisa izinketho zokunikeza isitifiketi ukubukeka okungenantambo"</string>
@@ -356,22 +357,41 @@
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Lesi sici esesilingo futhi singathinta ukusebenza."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"Igitshezwe ngaphezulu yi-<xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="power_remaining_duration_only" msgid="845431008899029842">"Cishe u-<xliff:g id="TIME">%1$s</xliff:g> osele"</string>
+ <!-- no translation found for power_discharging_duration (6655472132189365839) -->
+ <skip />
<string name="power_remaining_duration_only_enhanced" msgid="5992456722677973678">"Cishe kusele okungu-<xliff:g id="TIME">%1$s</xliff:g> kusukela ekusetshenzisweni kwakho"</string>
- <string name="power_remaining_charging_duration_only" msgid="1421102457410268886">"<xliff:g id="TIME">%1$s</xliff:g> kushiywe ishaja"</string>
+ <!-- no translation found for power_discharging_duration_enhanced (5726302316642148671) -->
+ <skip />
<string name="power_remaining_duration_only_short" msgid="5329694252258605547">"<xliff:g id="TIME">%1$s</xliff:g> esisele"</string>
+ <!-- no translation found for power_discharge_by_enhanced (8788299408879961465) -->
+ <skip />
+ <!-- no translation found for power_discharge_by_only_enhanced (7692297898877104416) -->
+ <skip />
+ <!-- no translation found for power_discharge_by (6427074755635635749) -->
+ <skip />
+ <!-- no translation found for power_discharge_by_only (5888058889261108064) -->
+ <skip />
<string name="power_remaining_less_than_duration_only" msgid="5996752448813295329">"Kusele okungaphansi kunokungu-<xliff:g id="THRESHOLD">%1$s</xliff:g>"</string>
- <string name="power_remaining_less_than_duration" msgid="7967078125657859046">"<xliff:g id="LEVEL">%1$s</xliff:g> - Kusele okungaphansi kokungu<xliff:g id="THRESHOLD">%2$s</xliff:g>"</string>
- <string name="power_remaining_more_than_subtext" msgid="6846716609975752316">"<xliff:g id="LEVEL">%1$s</xliff:g>ngaphezu kokungu-<xliff:g id="TIME_REMAINING">%2$s</xliff:g> okusele"</string>
- <string name="power_remaining_only_more_than_subtext" msgid="8884488700395194194">"ngaphezulu kokungu-<xliff:g id="TIME_REMAINING">%1$s</xliff:g> okusele"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="default" msgid="8168317165722752881">"ifoni ingacisha maduze"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="tablet" msgid="5957064378548718872">"ithebulethi ingacisha maduze"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="device" msgid="9055596817716471373">"idivayisi ingacisha maduze"</string>
- <string name="power_discharging_duration" msgid="2843747179907396142">"<xliff:g id="LEVEL">%1$s</xliff:g> - cishe ngu-<xliff:g id="TIME">%2$s</xliff:g> osele"</string>
- <string name="power_discharging_duration_enhanced" msgid="4401782117770255046">"<xliff:g id="LEVEL">%1$s</xliff:g> - cishe ngu-<xliff:g id="TIME">%2$s</xliff:g> osele kusukela ekusetshenzisweni kwakho"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="default" msgid="7679005631124015335">"<xliff:g id="LEVEL">%1$s</xliff:g> - ifoni ingacisha maduze"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="tablet" msgid="261050880878965621">"<xliff:g id="LEVEL">%1$s</xliff:g> - ithebulethi ingacisha maduze"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="device" msgid="2020049829798578618">"<xliff:g id="LEVEL">%1$s</xliff:g> - idivayisi ingacisha maduze"</string>
+ <!-- no translation found for power_remaining_less_than_duration (5751885147712659423) -->
+ <skip />
+ <!-- no translation found for power_remaining_more_than_subtext (3176771815132876675) -->
+ <skip />
+ <!-- no translation found for power_remaining_only_more_than_subtext (8931654680569617380) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (1181059207608751924) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (2606370266981054691) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (2918084807716859985) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (3090926004324573908) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (7466484148515796216) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (603933521600231649) -->
+ <skip />
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
+ <string name="power_remaining_charging_duration_only" msgid="1421102457410268886">"<xliff:g id="TIME">%1$s</xliff:g> kushiywe ishaja"</string>
<string name="power_charging_duration" msgid="4676999980973411875">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> kuze ligcwale ngokuphelele"</string>
<string name="battery_info_status_unknown" msgid="196130600938058547">"Akwaziwa"</string>
<string name="battery_info_status_charging" msgid="1705179948350365604">"Iyashaja"</string>
diff --git a/packages/SystemUI/res/layout/signal_cluster_view.xml b/packages/SystemUI/res/layout/signal_cluster_view.xml
index 25c87d3..cfa372b 100644
--- a/packages/SystemUI/res/layout/signal_cluster_view.xml
+++ b/packages/SystemUI/res/layout/signal_cluster_view.xml
@@ -115,27 +115,6 @@
android:layout_width="wrap_content"
>
</LinearLayout>
- <FrameLayout
- android:id="@+id/no_sims_combo"
- android:layout_height="wrap_content"
- android:layout_width="wrap_content"
- android:contentDescription="@string/accessibility_no_sims">
- <com.android.systemui.statusbar.AlphaOptimizedImageView
- android:theme="?attr/lightIconTheme"
- android:id="@+id/no_sims"
- android:layout_height="wrap_content"
- android:layout_width="wrap_content"
- android:src="@drawable/stat_sys_no_sims"
- />
- <com.android.systemui.statusbar.AlphaOptimizedImageView
- android:theme="?attr/darkIconTheme"
- android:id="@+id/no_sims_dark"
- android:layout_height="wrap_content"
- android:layout_width="wrap_content"
- android:src="@drawable/stat_sys_no_sims"
- android:alpha="0.0"
- />
- </FrameLayout>
<View
android:id="@+id/wifi_airplane_spacer"
android:layout_width="@dimen/status_bar_airplane_spacer_width"
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index e506d2f..8cb68c0 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -468,7 +468,7 @@
<string name="accessibility_casting">@string/quick_settings_casting</string>
<!-- Content description of the work mode icon in the notification panel for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
- <string name="accessibility_work_mode">@string/quick_settings_work_mode_on_label</string>
+ <string name="accessibility_work_mode">@string/quick_settings_work_mode_label</string>
<!-- Content description to tell the user that this button will remove an application from recents -->
<string name="accessibility_recents_item_will_be_dismissed">Dismiss <xliff:g id="app" example="Calendar">%s</xliff:g>.</string>
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/WindowManagerWrapper.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/WindowManagerWrapper.java
index 5b49e67..a9c80c6 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/WindowManagerWrapper.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/WindowManagerWrapper.java
@@ -109,4 +109,16 @@
Log.w(TAG, "Failed to end prolonged animations: ", e);
}
}
+
+ /**
+ * Enable or disable haptic feedback on the navigation bar buttons.
+ */
+ public void setNavBarVirtualKeyHapticFeedbackEnabled(boolean enabled) {
+ try {
+ WindowManagerGlobal.getWindowManagerService()
+ .setNavBarVirtualKeyHapticFeedbackEnabled(enabled);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed to enable or disable navigation bar button haptics: ", e);
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/OverviewProxyService.java b/packages/SystemUI/src/com/android/systemui/OverviewProxyService.java
index 3c666e4..041af0e 100644
--- a/packages/SystemUI/src/com/android/systemui/OverviewProxyService.java
+++ b/packages/SystemUI/src/com/android/systemui/OverviewProxyService.java
@@ -36,6 +36,7 @@
import com.android.systemui.OverviewProxyService.OverviewProxyListener;
import com.android.systemui.recents.events.EventBus;
import com.android.systemui.recents.events.activity.DockedFirstAnimationFrameEvent;
+import com.android.systemui.recents.misc.SystemServicesProxy;
import com.android.systemui.shared.recents.IOverviewProxy;
import com.android.systemui.shared.recents.ISystemUiProxy;
import com.android.systemui.shared.system.GraphicBufferCompat;
@@ -201,15 +202,18 @@
mConnectionBackoffAttempts = 0;
mLauncherComponentName = ComponentName
.unflattenFromString(context.getString(R.string.config_overviewServiceComponent));
- mDeviceProvisionedController.addCallback(mDeviceProvisionedCallback);
// Listen for the package update changes.
- IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED);
- filter.addDataScheme("package");
- filter.addDataSchemeSpecificPart(mLauncherComponentName.getPackageName(),
- PatternMatcher.PATTERN_LITERAL);
- filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
- mContext.registerReceiver(mLauncherAddedReceiver, filter);
+ if (SystemServicesProxy.getInstance(context)
+ .isSystemUser(mDeviceProvisionedController.getCurrentUser())) {
+ mDeviceProvisionedController.addCallback(mDeviceProvisionedCallback);
+ IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED);
+ filter.addDataScheme("package");
+ filter.addDataSchemeSpecificPart(mLauncherComponentName.getPackageName(),
+ PatternMatcher.PATTERN_LITERAL);
+ filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
+ mContext.registerReceiver(mLauncherAddedReceiver, filter);
+ }
}
public void startConnectionToCurrentUser() {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/WorkModeTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/WorkModeTile.java
index 8593249..5bab3e8 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/WorkModeTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/WorkModeTile.java
@@ -21,12 +21,11 @@
import android.service.quicksettings.Tile;
import android.widget.Switch;
-import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.systemui.Dependency;
import com.android.systemui.R;
-import com.android.systemui.qs.QSHost;
import com.android.systemui.plugins.qs.QSTile.BooleanState;
+import com.android.systemui.qs.QSHost;
import com.android.systemui.qs.tileimpl.QSTileImpl;
import com.android.systemui.statusbar.phone.ManagedProfileController;
@@ -83,11 +82,15 @@
@Override
public CharSequence getTileLabel() {
- return mContext.getString(R.string.quick_settings_work_mode_on_label);
+ return mContext.getString(R.string.quick_settings_work_mode_label);
}
@Override
protected void handleUpdateState(BooleanState state, Object arg) {
+ if (!isAvailable()) {
+ onManagedProfileRemoved();
+ }
+
if (state.slash == null) {
state.slash = new SlashState();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java b/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java
index cb6e5a6..0f5e71e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java
@@ -73,9 +73,7 @@
private final NetworkController mNetworkController;
private final SecurityController mSecurityController;
- private boolean mNoSimsVisible = false;
private boolean mVpnVisible = false;
- private boolean mSimDetected;
private int mVpnIconId = 0;
private int mLastVpnIconId = -1;
private boolean mEthernetVisible = false;
@@ -86,7 +84,6 @@
private int mLastWifiStrengthId = -1;
private boolean mWifiIn;
private boolean mWifiOut;
- private int mLastWifiActivityId = -1;
private boolean mIsAirplaneMode = false;
private int mAirplaneIconId = 0;
private int mLastAirplaneIconId = -1;
@@ -99,8 +96,7 @@
private final Rect mTintArea = new Rect();
ViewGroup mEthernetGroup, mWifiGroup;
- View mNoSimsCombo;
- ImageView mVpn, mEthernet, mWifi, mAirplane, mNoSims, mEthernetDark, mWifiDark, mNoSimsDark;
+ ImageView mVpn, mEthernet, mWifi, mAirplane, mEthernetDark, mWifiDark;
ImageView mWifiActivityIn;
ImageView mWifiActivityOut;
View mWifiAirplaneSpacer;
@@ -203,9 +199,6 @@
mWifiActivityIn = findViewById(R.id.wifi_in);
mWifiActivityOut= findViewById(R.id.wifi_out);
mAirplane = findViewById(R.id.airplane);
- mNoSims = findViewById(R.id.no_sims);
- mNoSimsDark = findViewById(R.id.no_sims_dark);
- mNoSimsCombo = findViewById(R.id.no_sims_combo);
mWifiAirplaneSpacer = findViewById(R.id.wifi_airplane_spacer);
mWifiSignalSpacer = findViewById(R.id.wifi_signal_spacer);
mMobileSignalGroup = findViewById(R.id.mobile_signal_group);
@@ -224,11 +217,6 @@
}
mVpn.setImageDrawable(new ScalingDrawableWrapper(mVpn.getDrawable(), mIconScaleFactor));
-
- mNoSims.setImageDrawable(
- new ScalingDrawableWrapper(mNoSims.getDrawable(), mIconScaleFactor));
- mNoSimsDark.setImageDrawable(
- new ScalingDrawableWrapper(mNoSimsDark.getDrawable(), mIconScaleFactor));
}
@Override
@@ -333,9 +321,7 @@
@Override
public void setNoSims(boolean show, boolean simDetected) {
- mNoSimsVisible = show && !mBlockMobile;
- mSimDetected = simDetected;
- apply();
+ // Noop. Status bar no longer shows no sim icon.
}
@Override
@@ -545,38 +531,13 @@
mWifiAirplaneSpacer.setVisibility(View.GONE);
}
- if (((anyMobileVisible && firstMobileTypeId != 0) || mNoSimsVisible) && mWifiVisible) {
+ if ((anyMobileVisible && firstMobileTypeId != 0) && mWifiVisible) {
mWifiSignalSpacer.setVisibility(View.VISIBLE);
} else {
mWifiSignalSpacer.setVisibility(View.GONE);
}
- if (mNoSimsVisible) {
- mIconLogger.onIconShown(SLOT_MOBILE);
- mNoSimsCombo.setVisibility(View.VISIBLE);
- if (!Objects.equals(mSimDetected, mNoSimsCombo.getTag())) {
- mNoSimsCombo.setTag(mSimDetected);
- if (mSimDetected) {
- SignalDrawable d = new SignalDrawable(mNoSims.getContext());
- d.setDarkIntensity(0);
- mNoSims.setImageDrawable(d);
- mNoSims.setImageLevel(SignalDrawable.getEmptyState(4));
-
- SignalDrawable dark = new SignalDrawable(mNoSims.getContext());
- dark.setDarkIntensity(1);
- mNoSimsDark.setImageDrawable(dark);
- mNoSimsDark.setImageLevel(SignalDrawable.getEmptyState(4));
- } else {
- mNoSims.setImageResource(R.drawable.stat_sys_no_sims);
- mNoSimsDark.setImageResource(R.drawable.stat_sys_no_sims);
- }
- }
- } else {
- mIconLogger.onIconHidden(SLOT_MOBILE);
- mNoSimsCombo.setVisibility(View.GONE);
- }
-
- boolean anythingVisible = mNoSimsVisible || mWifiVisible || mIsAirplaneMode
+ boolean anythingVisible = mWifiVisible || mIsAirplaneMode
|| anyMobileVisible || mVpnVisible || mEthernetVisible;
setPaddingRelative(0, 0, anythingVisible ? mEndPadding : mEndPaddingNothingVisible, 0);
}
@@ -613,9 +574,6 @@
setTint(mVpn, DarkIconDispatcher.getTint(mTintArea, mVpn, mIconTint));
setTint(mAirplane, DarkIconDispatcher.getTint(mTintArea, mAirplane, mIconTint));
applyDarkIntensity(
- DarkIconDispatcher.getDarkIntensity(mTintArea, mNoSims, mDarkIntensity),
- mNoSims, mNoSimsDark);
- applyDarkIntensity(
DarkIconDispatcher.getDarkIntensity(mTintArea, mWifi, mDarkIntensity),
mWifi, mWifiDark);
setTint(mWifiActivityIn,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
index 0ed69e6..da042d2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
@@ -46,7 +46,6 @@
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.graphics.drawable.AnimatedVectorDrawable;
-import android.graphics.drawable.Drawable;
import android.inputmethodservice.InputMethodService;
import android.os.Binder;
import android.os.Bundle;
@@ -88,6 +87,7 @@
import com.android.systemui.recents.Recents;
import com.android.systemui.recents.misc.SysUiTaskStackChangeListener;
import com.android.systemui.shared.system.ActivityManagerWrapper;
+import com.android.systemui.shared.system.WindowManagerWrapper;
import com.android.systemui.stackdivider.Divider;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.CommandQueue.Callbacks;
@@ -165,6 +165,8 @@
public void onConnectionChanged(boolean isConnected) {
mNavigationBarView.onOverviewProxyConnectionChanged(isConnected);
updateScreenPinningGestures();
+ WindowManagerWrapper.getInstance()
+ .setNavBarVirtualKeyHapticFeedbackEnabled(!isConnected);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
index d8d388c..e59a6b5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
@@ -18,7 +18,6 @@
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
-import android.animation.PropertyValuesHolder;
import android.animation.ValueAnimator;
import android.app.AlarmManager;
import android.app.WallpaperManager;
@@ -72,10 +71,6 @@
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
public static final long ANIMATION_DURATION = 220;
- public static final Interpolator KEYGUARD_FADE_OUT_INTERPOLATOR
- = new PathInterpolator(0f, 0, 0.7f, 1f);
- public static final Interpolator KEYGUARD_FADE_OUT_INTERPOLATOR_LOCKED
- = new PathInterpolator(0.3f, 0f, 0.8f, 1f);
/**
* When both scrims have 0 alpha.
@@ -144,7 +139,6 @@
protected boolean mAnimateChange;
private boolean mUpdatePending;
private boolean mTracking;
- private boolean mAnimateKeyguardFadingOut;
protected long mAnimationDuration = -1;
private long mAnimationDelay;
private Runnable mOnAnimationFinished;
@@ -158,8 +152,6 @@
private int mPinnedHeadsUpCount;
private float mTopHeadsUpDragAmount;
private View mDraggedHeadsUpView;
- private boolean mKeyguardFadingOutInProgress;
- private ValueAnimator mKeyguardFadeoutAnimation;
private int mScrimsVisibility;
private final Consumer<Integer> mScrimVisibleListener;
private boolean mBlankScreen;
@@ -269,10 +261,6 @@
// to do the same when you're just showing the brightness mirror.
mNeedsDrawableColorUpdate = state != ScrimState.BRIGHTNESS_MIRROR;
- if (mKeyguardFadeoutAnimation != null) {
- mKeyguardFadeoutAnimation.cancel();
- }
-
// The device might sleep if it's entering AOD, we need to make sure that
// the animation plays properly until the last frame.
// It's important to avoid holding the wakelock unless necessary because
@@ -362,7 +350,7 @@
*
* The expansion fraction is tied to the scrim opacity.
*
- * @param fraction From 0 to 1 where 0 means collapse and 1 expanded.
+ * @param fraction From 0 to 1 where 0 means collapsed and 1 expanded.
*/
public void setPanelExpansion(float fraction) {
if (mExpansionFraction != fraction) {
@@ -381,8 +369,25 @@
if (mPinnedHeadsUpCount != 0) {
updateHeadsUpScrim(false);
}
- updateScrim(false /* animate */, mScrimInFront, mCurrentInFrontAlpha);
- updateScrim(false /* animate */, mScrimBehind, mCurrentBehindAlpha);
+
+ setOrAdaptCurrentAnimation(mScrimBehind);
+ setOrAdaptCurrentAnimation(mScrimInFront);
+ }
+ }
+
+ private void setOrAdaptCurrentAnimation(View scrim) {
+ if (!isAnimating(scrim)) {
+ updateScrimColor(scrim, getCurrentScrimAlpha(scrim), getCurrentScrimTint(scrim));
+ } else {
+ ValueAnimator previousAnimator = (ValueAnimator) scrim.getTag(TAG_KEY_ANIM);
+ float alpha = getCurrentScrimAlpha(scrim);
+ float previousEndValue = (Float) scrim.getTag(TAG_END_ALPHA);
+ float previousStartValue = (Float) scrim.getTag(TAG_START_ALPHA);
+ float relativeDiff = alpha - previousEndValue;
+ float newStartValue = previousStartValue + relativeDiff;
+ scrim.setTag(TAG_START_ALPHA, newStartValue);
+ scrim.setTag(TAG_END_ALPHA, alpha);
+ previousAnimator.setCurrentPlayTime(previousAnimator.getCurrentPlayTime());
}
}
@@ -523,14 +528,14 @@
setScrimAlpha(mScrimInFront, alpha);
}
- private void setScrimAlpha(View scrim, float alpha) {
+ private void setScrimAlpha(ScrimView scrim, float alpha) {
if (alpha == 0f) {
scrim.setClickable(false);
} else {
// Eat touch events (unless dozing).
scrim.setClickable(!(mState == ScrimState.AOD));
}
- updateScrim(mAnimateChange, scrim, alpha);
+ updateScrim(scrim, alpha);
}
private void updateScrimColor(View scrim, float alpha, int tint) {
@@ -554,41 +559,27 @@
dispatchScrimsVisible();
}
- private int getCurrentScrimTint(View scrim) {
- return scrim == mScrimInFront ? mCurrentInFrontTint : mCurrentBehindTint;
- }
-
private void startScrimAnimation(final View scrim, float current) {
ValueAnimator anim = ValueAnimator.ofFloat(0f, 1f);
final int initialScrimTint = scrim instanceof ScrimView ? ((ScrimView) scrim).getTint() :
Color.TRANSPARENT;
anim.addUpdateListener(animation -> {
+ final float startAlpha = (Float) scrim.getTag(TAG_START_ALPHA);
final float animAmount = (float) animation.getAnimatedValue();
- final int finalScrimTint = scrim == mScrimInFront ?
- mCurrentInFrontTint : mCurrentBehindTint;
- float finalScrimAlpha = scrim == mScrimInFront ?
- mCurrentInFrontAlpha : mCurrentBehindAlpha;
- float alpha = MathUtils.lerp(current, finalScrimAlpha, animAmount);
+ final int finalScrimTint = getCurrentScrimTint(scrim);
+ final float finalScrimAlpha = getCurrentScrimAlpha(scrim);
+ float alpha = MathUtils.lerp(startAlpha, finalScrimAlpha, animAmount);
+ alpha = MathUtils.constrain(alpha, 0f, 1f);
int tint = ColorUtils.blendARGB(initialScrimTint, finalScrimTint, animAmount);
updateScrimColor(scrim, alpha, tint);
dispatchScrimsVisible();
});
- anim.setInterpolator(getInterpolator());
+ anim.setInterpolator(mInterpolator);
anim.setStartDelay(mAnimationDelay);
anim.setDuration(mAnimationDuration);
anim.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
- final int finalScrimTint = scrim == mScrimInFront ?
- mCurrentInFrontTint : mCurrentBehindTint;
- float finalScrimAlpha = scrim == mScrimInFront ?
- mCurrentInFrontAlpha : mCurrentBehindAlpha;
- updateScrimColor(scrim, finalScrimAlpha, finalScrimTint);
-
- if (mKeyguardFadingOutInProgress) {
- mKeyguardFadeoutAnimation = null;
- mKeyguardFadingOutInProgress = false;
- }
onFinished();
scrim.setTag(TAG_KEY_ANIM, null);
@@ -600,21 +591,37 @@
}
}
});
- anim.start();
- if (mAnimateKeyguardFadingOut) {
- mKeyguardFadingOutInProgress = true;
- mKeyguardFadeoutAnimation = anim;
- }
+
+ // Cache alpha values because we might want to update this animator in the future if
+ // the user expands the panel while the animation is still running.
+ scrim.setTag(TAG_START_ALPHA, current);
+ scrim.setTag(TAG_END_ALPHA, getCurrentScrimAlpha(scrim));
+
scrim.setTag(TAG_KEY_ANIM, anim);
+ anim.start();
}
- protected Interpolator getInterpolator() {
- if (mAnimateKeyguardFadingOut && mKeyguardUpdateMonitor.needsSlowUnlockTransition()) {
- return KEYGUARD_FADE_OUT_INTERPOLATOR_LOCKED;
- } else if (mAnimateKeyguardFadingOut) {
- return KEYGUARD_FADE_OUT_INTERPOLATOR;
+ private float getCurrentScrimAlpha(View scrim) {
+ if (scrim == mScrimInFront) {
+ return mCurrentInFrontAlpha;
+ } else if (scrim == mScrimBehind) {
+ return mCurrentBehindAlpha;
+ } else if (scrim == mHeadsUpScrim) {
+ return calculateHeadsUpAlpha();
} else {
- return mInterpolator;
+ throw new IllegalArgumentException("Unknown scrim view");
+ }
+ }
+
+ private int getCurrentScrimTint(View scrim) {
+ if (scrim == mScrimInFront) {
+ return mCurrentInFrontTint;
+ } else if (scrim == mScrimBehind) {
+ return mCurrentBehindTint;
+ } else if (scrim == mHeadsUpScrim) {
+ return Color.TRANSPARENT;
+ } else {
+ throw new IllegalArgumentException("Unknown scrim view");
}
}
@@ -626,9 +633,11 @@
mCallback.onStart();
}
updateScrims();
-
- // Make sure that we always call the listener even if we didn't start an animation.
- endAnimateKeyguardFadingOut(false /* force */);
+ if (mOnAnimationFinished != null && !isAnimating(mScrimInFront)
+ && !isAnimating(mScrimBehind)) {
+ mOnAnimationFinished.run();
+ mOnAnimationFinished = null;
+ }
return true;
}
@@ -649,17 +658,6 @@
}
}
- private void endAnimateKeyguardFadingOut(boolean force) {
- mAnimateKeyguardFadingOut = false;
- if (force || (!isAnimating(mScrimInFront) && !isAnimating(mScrimBehind))) {
- if (mOnAnimationFinished != null) {
- mOnAnimationFinished.run();
- mOnAnimationFinished = null;
- }
- mKeyguardFadingOutInProgress = false;
- }
- }
-
private boolean isAnimating(View scrim) {
return scrim.getTag(TAG_KEY_ANIM) != null;
}
@@ -693,7 +691,13 @@
}
private void updateHeadsUpScrim(boolean animate) {
- updateScrim(animate, mHeadsUpScrim, calculateHeadsUpAlpha());
+ if (animate) {
+ mAnimationDuration = ANIMATION_DURATION;
+ cancelAnimator((ValueAnimator) mHeadsUpScrim.getTag(TAG_KEY_ANIM));
+ startScrimAnimation(mHeadsUpScrim, mHeadsUpScrim.getAlpha());
+ } else {
+ setOrAdaptCurrentAnimation(mHeadsUpScrim);
+ }
}
@VisibleForTesting
@@ -701,32 +705,28 @@
mOnAnimationFinished = onAnimationFinished;
}
- private void updateScrim(boolean animate, View scrim, float alpha) {
- final float currentAlpha = scrim instanceof ScrimView ? ((ScrimView) scrim).getViewAlpha()
- : scrim.getAlpha();
+ private void updateScrim(ScrimView scrim, float alpha) {
+ final float currentAlpha = scrim.getViewAlpha();
ValueAnimator previousAnimator = ViewState.getChildTag(scrim, TAG_KEY_ANIM);
- float animEndValue = -1;
if (previousAnimator != null) {
- if (animate || alpha == currentAlpha) {
+ if (mAnimateChange) {
// We are not done yet! Defer calling the finished listener.
- if (animate) {
- mDeferFinishedListener = true;
- }
- cancelAnimator(previousAnimator);
- mDeferFinishedListener = false;
- } else {
- animEndValue = ViewState.getChildTag(scrim, TAG_END_ALPHA);
+ mDeferFinishedListener = true;
}
+ // Previous animators should always be cancelled. Not doing so would cause
+ // overlap, especially on states that don't animate, leading to flickering,
+ // and in the worst case, an internal state that doesn't represent what
+ // transitionTo requested.
+ cancelAnimator(previousAnimator);
+ mDeferFinishedListener = false;
}
if (mPendingFrameCallback != null) {
// Display is off and we're waiting.
- cancelAnimator(previousAnimator);
return;
} else if (mBlankScreen) {
// Need to blank the display before continuing.
- cancelAnimator(previousAnimator);
blankDisplay();
return;
} else if (!mScreenBlankingCallbackCalled) {
@@ -743,37 +743,16 @@
mLightBarController.setScrimAlpha(alpha);
}
- final ScrimView scrimView = scrim instanceof ScrimView ? (ScrimView) scrim : null;
- final boolean wantsAlphaUpdate = alpha != currentAlpha && alpha != animEndValue;
- final boolean wantsTintUpdate = scrimView != null
- && scrimView.getTint() != getCurrentScrimTint(scrimView);
+ final boolean wantsAlphaUpdate = alpha != currentAlpha;
+ final boolean wantsTintUpdate = scrim.getTint() != getCurrentScrimTint(scrim);
if (wantsAlphaUpdate || wantsTintUpdate) {
- if (animate) {
- final float fromAlpha = scrimView == null ? scrim.getAlpha()
- : scrimView.getViewAlpha();
- startScrimAnimation(scrim, fromAlpha);
- scrim.setTag(TAG_START_ALPHA, currentAlpha);
- scrim.setTag(TAG_END_ALPHA, alpha);
+ if (mAnimateChange) {
+ startScrimAnimation(scrim, currentAlpha);
} else {
- if (previousAnimator != null) {
- float previousStartValue = ViewState.getChildTag(scrim, TAG_START_ALPHA);
- float previousEndValue = ViewState.getChildTag(scrim, TAG_END_ALPHA);
- // we need to increase all animation keyframes of the previous animator by the
- // relative change to the end value
- PropertyValuesHolder[] values = previousAnimator.getValues();
- float relativeDiff = alpha - previousEndValue;
- float newStartValue = previousStartValue + relativeDiff;
- newStartValue = Math.max(0, Math.min(1.0f, newStartValue));
- values[0].setFloatValues(newStartValue, alpha);
- scrim.setTag(TAG_START_ALPHA, newStartValue);
- scrim.setTag(TAG_END_ALPHA, alpha);
- previousAnimator.setCurrentPlayTime(previousAnimator.getCurrentPlayTime());
- } else {
- // update the alpha directly
- updateScrimColor(scrim, alpha, getCurrentScrimTint(scrim));
- onFinished();
- }
+ // update the alpha directly
+ updateScrimColor(scrim, alpha, getCurrentScrimTint(scrim));
+ onFinished();
}
} else {
onFinished();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
index 408cd85..e8ac326 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -3540,7 +3540,7 @@
.alpha(0f)
.setStartDelay(0)
.setDuration(FADE_KEYGUARD_DURATION_PULSING)
- .setInterpolator(ScrimController.KEYGUARD_FADE_OUT_INTERPOLATOR)
+ .setInterpolator(Interpolators.ALPHA_OUT)
.withEndAction(()-> {
hideKeyguard();
mStatusBarKeyguardViewManager.onKeyguardFadedAway();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
index e7b802d..aec05cd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
@@ -232,12 +232,7 @@
performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY);
}
mIsPressed = true;
- if (isProxyConnected) {
- // Provide small vibration for quick step or immediate down feedback
- AsyncTask.execute(() ->
- mVibrator.vibrate(VibrationEffect
- .get(VibrationEffect.EFFECT_TICK, false)));
- } else {
+ if (!isProxyConnected) {
playSoundEffect(SoundEffectConstants.CLICK);
setPressed(mIsPressed);
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
index 168d8d3..3ed2fe1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
@@ -77,7 +77,7 @@
mLightBarController = mock(LightBarController.class);
mScrimBehind = new ScrimView(getContext());
mScrimInFront = new ScrimView(getContext());
- mHeadsUpScrim = mock(View.class);
+ mHeadsUpScrim = new View(getContext());
mWakeLock = mock(WakeLock.class);
mAlarmManager = mock(AlarmManager.class);
mAlwaysOnEnabled = true;
@@ -384,6 +384,56 @@
testConservesNotificationDensity(3 /* count */, ScrimController.GRADIENT_SCRIM_ALPHA_BUSY);
}
+ @Test
+ public void testHeadsUpScrimOpacity() {
+ mScrimController.setPanelExpansion(0f);
+ mScrimController.onHeadsUpPinned(null /* row */);
+ mScrimController.finishAnimationsImmediately();
+
+ Assert.assertNotEquals("Heads-up scrim should be visible", 0f,
+ mHeadsUpScrim.getAlpha(), 0.01f);
+
+ mScrimController.onHeadsUpUnPinned(null /* row */);
+ mScrimController.finishAnimationsImmediately();
+
+ Assert.assertEquals("Heads-up scrim should have disappeared", 0f,
+ mHeadsUpScrim.getAlpha(), 0.01f);
+ }
+
+ @Test
+ public void testHeadsUpScrimCounting() {
+ mScrimController.setPanelExpansion(0f);
+ mScrimController.onHeadsUpPinned(null /* row */);
+ mScrimController.onHeadsUpPinned(null /* row */);
+ mScrimController.onHeadsUpPinned(null /* row */);
+ mScrimController.finishAnimationsImmediately();
+
+ Assert.assertNotEquals("Heads-up scrim should be visible", 0f,
+ mHeadsUpScrim.getAlpha(), 0.01f);
+
+ mScrimController.onHeadsUpUnPinned(null /* row */);
+ mScrimController.finishAnimationsImmediately();
+
+ Assert.assertEquals("Heads-up scrim should only disappear when counter reaches 0", 1f,
+ mHeadsUpScrim.getAlpha(), 0.01f);
+
+ mScrimController.onHeadsUpUnPinned(null /* row */);
+ mScrimController.onHeadsUpUnPinned(null /* row */);
+ mScrimController.finishAnimationsImmediately();
+ Assert.assertEquals("Heads-up scrim should have disappeared", 0f,
+ mHeadsUpScrim.getAlpha(), 0.01f);
+ }
+
+ @Test
+ public void testNoHeadsUpScrimExpanded() {
+ mScrimController.setPanelExpansion(1f);
+ mScrimController.onHeadsUpPinned(null /* row */);
+ mScrimController.finishAnimationsImmediately();
+
+ Assert.assertEquals("Heads-up scrim should not be visible when shade is expanded", 0f,
+ mHeadsUpScrim.getAlpha(), 0.01f);
+ }
+
/**
* Conserves old notification density after leaving state and coming back.
*
@@ -437,7 +487,7 @@
private FakeHandler mHandler;
private boolean mAnimationCancelled;
- public SynchronousScrimController(LightBarController lightBarController,
+ SynchronousScrimController(LightBarController lightBarController,
ScrimView scrimBehind, ScrimView scrimInFront, View headsUpScrim,
Consumer<Integer> scrimVisibleListener, DozeParameters dozeParameters,
AlarmManager alarmManager) {
@@ -446,7 +496,7 @@
mHandler = new FakeHandler(Looper.myLooper());
}
- public void finishAnimationsImmediately() {
+ void finishAnimationsImmediately() {
boolean[] animationFinished = {false};
setOnAnimationFinished(()-> animationFinished[0] = true);
@@ -458,19 +508,20 @@
// Force finish all animations.
endAnimation(mScrimBehind, TAG_KEY_ANIM);
endAnimation(mScrimInFront, TAG_KEY_ANIM);
+ endAnimation(mHeadsUpScrim, TAG_KEY_ANIM);
if (!animationFinished[0]) {
throw new IllegalStateException("Animation never finished");
}
}
- public boolean wasAnimationJustCancelled() {
+ boolean wasAnimationJustCancelled() {
final boolean wasCancelled = mAnimationCancelled;
mAnimationCancelled = false;
return wasCancelled;
}
- private void endAnimation(ScrimView scrimView, int tag) {
+ private void endAnimation(View scrimView, int tag) {
Animator animator = (Animator) scrimView.getTag(tag);
if (animator != null) {
animator.end();
diff --git a/proto/src/metrics_constants.proto b/proto/src/metrics_constants.proto
index 7819a80..57e3c75 100644
--- a/proto/src/metrics_constants.proto
+++ b/proto/src/metrics_constants.proto
@@ -5369,6 +5369,16 @@
// OS: P
FIELD_DEVICE_ROTATION = 1329;
+ // OPEN: TV Settings > Inputs > Input Options
+ // CATEGORY: SETTINGS
+ // OS: P
+ SETTINGS_TV_INPUT_OPTIONS_CATEGORY = 1330;
+
+ // OPEN: TV Settings > Network & Internet > Add known WIFI network
+ // CATEGORY: SETTINGS
+ // OS: P
+ SETTINGS_TV_WIFI_ADD_KNOWN_CATEGORY = 1331;
+
// ---- End P Constants, all P constants go above this line ----
// Add new aosp constants above this line.
// END OF AOSP CONSTANTS
diff --git a/rs/jni/android_renderscript_RenderScript.cpp b/rs/jni/android_renderscript_RenderScript.cpp
index b32be73..52d0e08e 100644
--- a/rs/jni/android_renderscript_RenderScript.cpp
+++ b/rs/jni/android_renderscript_RenderScript.cpp
@@ -24,8 +24,9 @@
#include <utils/misc.h>
#include <inttypes.h>
+#include <android-base/macros.h>
#include <androidfw/Asset.h>
-#include <androidfw/AssetManager.h>
+#include <androidfw/AssetManager2.h>
#include <androidfw/ResourceTypes.h>
#include <android-base/macros.h>
@@ -1664,18 +1665,22 @@
static jlong
nFileA3DCreateFromAsset(JNIEnv *_env, jobject _this, jlong con, jobject _assetMgr, jstring _path)
{
- AssetManager* mgr = assetManagerForJavaObject(_env, _assetMgr);
+ Guarded<AssetManager2>* mgr = AssetManagerForJavaObject(_env, _assetMgr);
if (mgr == nullptr) {
return 0;
}
AutoJavaStringToUTF8 str(_env, _path);
- Asset* asset = mgr->open(str.c_str(), Asset::ACCESS_BUFFER);
- if (asset == nullptr) {
- return 0;
+ std::unique_ptr<Asset> asset;
+ {
+ ScopedLock<AssetManager2> locked_mgr(*mgr);
+ asset = locked_mgr->Open(str.c_str(), Asset::ACCESS_BUFFER);
+ if (asset == nullptr) {
+ return 0;
+ }
}
- jlong id = (jlong)(uintptr_t)rsaFileA3DCreateFromAsset((RsContext)con, asset);
+ jlong id = (jlong)(uintptr_t)rsaFileA3DCreateFromAsset((RsContext)con, asset.release());
return id;
}
@@ -1752,22 +1757,25 @@
nFontCreateFromAsset(JNIEnv *_env, jobject _this, jlong con, jobject _assetMgr, jstring _path,
jfloat fontSize, jint dpi)
{
- AssetManager* mgr = assetManagerForJavaObject(_env, _assetMgr);
+ Guarded<AssetManager2>* mgr = AssetManagerForJavaObject(_env, _assetMgr);
if (mgr == nullptr) {
return 0;
}
AutoJavaStringToUTF8 str(_env, _path);
- Asset* asset = mgr->open(str.c_str(), Asset::ACCESS_BUFFER);
- if (asset == nullptr) {
- return 0;
+ std::unique_ptr<Asset> asset;
+ {
+ ScopedLock<AssetManager2> locked_mgr(*mgr);
+ asset = locked_mgr->Open(str.c_str(), Asset::ACCESS_BUFFER);
+ if (asset == nullptr) {
+ return 0;
+ }
}
jlong id = (jlong)(uintptr_t)rsFontCreateFromMemory((RsContext)con,
str.c_str(), str.length(),
fontSize, dpi,
asset->getBuffer(false), asset->getLength());
- delete asset;
return id;
}
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
index 05237af..a06490b 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
@@ -22,6 +22,7 @@
import static com.android.server.autofill.Helper.bundleToString;
import static com.android.server.autofill.Helper.sDebug;
import static com.android.server.autofill.Helper.sPartitionMaxCount;
+import static com.android.server.autofill.Helper.sVisibleDatasetsMaxCount;
import static com.android.server.autofill.Helper.sVerbose;
import android.annotation.NonNull;
@@ -463,6 +464,24 @@
}
// Called by Shell command.
+ public int getMaxVisibleDatasets() {
+ mContext.enforceCallingPermission(MANAGE_AUTO_FILL, TAG);
+
+ synchronized (mLock) {
+ return sVisibleDatasetsMaxCount;
+ }
+ }
+
+ // Called by Shell command.
+ public void setMaxVisibleDatasets(int max) {
+ mContext.enforceCallingPermission(MANAGE_AUTO_FILL, TAG);
+ Slog.i(TAG, "setMaxVisibleDatasets(): " + max);
+ synchronized (mLock) {
+ sVisibleDatasetsMaxCount = max;
+ }
+ }
+
+ // Called by Shell command.
public void getScore(@Nullable String algorithmName, @NonNull String value1,
@NonNull String value2, @NonNull RemoteCallback callback) {
mContext.enforceCallingPermission(MANAGE_AUTO_FILL, TAG);
@@ -1009,6 +1028,7 @@
pw.print("Verbose mode: "); pw.println(sVerbose);
pw.print("Disabled users: "); pw.println(mDisabledUsers);
pw.print("Max partitions per session: "); pw.println(sPartitionMaxCount);
+ pw.print("Max visible datasets: "); pw.println(sVisibleDatasetsMaxCount);
pw.println("User data constraints: "); UserData.dumpConstraints(prefix, pw);
final int size = mServicesCache.size();
pw.print("Cached services: ");
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceShellCommand.java b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceShellCommand.java
index 4d69ef9..1904061 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceShellCommand.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceShellCommand.java
@@ -77,12 +77,18 @@
pw.println(" get max_partitions");
pw.println(" Gets the maximum number of partitions per session.");
pw.println("");
+ pw.println(" get max_visible_datasets");
+ pw.println(" Gets the maximum number of visible datasets in the UI.");
+ pw.println("");
pw.println(" set log_level [off | debug | verbose]");
pw.println(" Sets the Autofill log level.");
pw.println("");
pw.println(" set max_partitions number");
pw.println(" Sets the maximum number of partitions per session.");
pw.println("");
+ pw.println(" set max_visible_datasets number");
+ pw.println(" Sets the maximum number of visible datasets in the UI.");
+ pw.println("");
pw.println(" list sessions [--user USER_ID]");
pw.println(" Lists all pending sessions.");
pw.println("");
@@ -105,6 +111,8 @@
return getLogLevel(pw);
case "max_partitions":
return getMaxPartitions(pw);
+ case "max_visible_datasets":
+ return getMaxVisibileDatasets(pw);
case "fc_score":
return getFieldClassificationScore(pw);
default:
@@ -121,6 +129,8 @@
return setLogLevel(pw);
case "max_partitions":
return setMaxPartitions();
+ case "max_visible_datasets":
+ return setMaxVisibileDatasets();
default:
pw.println("Invalid set: " + what);
return -1;
@@ -173,6 +183,16 @@
return 0;
}
+ private int getMaxVisibileDatasets(PrintWriter pw) {
+ pw.println(mService.getMaxVisibleDatasets());
+ return 0;
+ }
+
+ private int setMaxVisibileDatasets() {
+ mService.setMaxVisibleDatasets(Integer.parseInt(getNextArgRequired()));
+ return 0;
+ }
+
private int getFieldClassificationScore(PrintWriter pw) {
final String nextArg = getNextArgRequired();
final String algorithm, value1;
diff --git a/services/autofill/java/com/android/server/autofill/Helper.java b/services/autofill/java/com/android/server/autofill/Helper.java
index 5ef467d..232dfdc 100644
--- a/services/autofill/java/com/android/server/autofill/Helper.java
+++ b/services/autofill/java/com/android/server/autofill/Helper.java
@@ -61,6 +61,13 @@
*/
static int sPartitionMaxCount = 10;
+ /**
+ * Maximum number of visible datasets in the dataset picker UI.
+ *
+ * <p>Can be modified using {@code cmd autofill set max_visible_datasets}.
+ */
+ public static int sVisibleDatasetsMaxCount = 3;
+
private Helper() {
throw new UnsupportedOperationException("contains static members only");
}
diff --git a/services/autofill/java/com/android/server/autofill/ui/FillUi.java b/services/autofill/java/com/android/server/autofill/ui/FillUi.java
index dbed242..a32078c 100644
--- a/services/autofill/java/com/android/server/autofill/ui/FillUi.java
+++ b/services/autofill/java/com/android/server/autofill/ui/FillUi.java
@@ -58,6 +58,8 @@
import com.android.server.UiThread;
import com.android.server.autofill.Helper;
+import static com.android.server.autofill.Helper.sVisibleDatasetsMaxCount;
+
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Collections;
@@ -69,8 +71,6 @@
final class FillUi {
private static final String TAG = "FillUi";
- private static final int VISIBLE_OPTIONS_MAX_COUNT = 3;
-
private static final TypedValue sTempTypedValue = new TypedValue();
public static final class AutofillFrameLayout extends FrameLayout {
@@ -375,7 +375,7 @@
}
requestShowFillUi();
}
- if (mAdapter.getCount() > VISIBLE_OPTIONS_MAX_COUNT) {
+ if (mAdapter.getCount() > sVisibleDatasetsMaxCount) {
mListView.setVerticalScrollBarEnabled(true);
mListView.onVisibilityAggregated(true);
} else {
@@ -475,7 +475,7 @@
changed = true;
}
// Update the width to fit only the first items up to max count
- if (i < VISIBLE_OPTIONS_MAX_COUNT) {
+ if (i < sVisibleDatasetsMaxCount) {
final int clampedMeasuredHeight = Math.min(view.getMeasuredHeight(), maxSize.y);
final int newContentHeight = mContentHeight + clampedMeasuredHeight;
if (newContentHeight != mContentHeight) {
diff --git a/services/core/java/com/android/server/AppOpsService.java b/services/core/java/com/android/server/AppOpsService.java
index 53c9ecb..15f3a23 100644
--- a/services/core/java/com/android/server/AppOpsService.java
+++ b/services/core/java/com/android/server/AppOpsService.java
@@ -61,8 +61,8 @@
import com.android.internal.util.FastXmlSerializer;
import com.android.internal.util.Preconditions;
import com.android.internal.util.XmlUtils;
-
import com.android.internal.util.function.pooled.PooledLambda;
+
import libcore.util.EmptyArray;
import org.xmlpull.v1.XmlPullParser;
@@ -1961,10 +1961,16 @@
int mode;
int packageUid;
int nonpackageUid;
+ final static Binder sBinder = new Binder();
+ IBinder mToken;
Shell(IAppOpsService iface, AppOpsService internal) {
mInterface = iface;
mInternal = internal;
+ try {
+ mToken = mInterface.getToken(sBinder);
+ } catch (RemoteException e) {
+ }
}
@Override
@@ -2149,6 +2155,10 @@
pw.println("AppOps service (appops) commands:");
pw.println(" help");
pw.println(" Print this help text.");
+ pw.println(" start [--user <USER_ID>] <PACKAGE | UID> <OP> ");
+ pw.println(" Starts a given operation for a particular application.");
+ pw.println(" stop [--user <USER_ID>] <PACKAGE | UID> <OP> ");
+ pw.println(" Stops a given operation for a particular application.");
pw.println(" set [--user <USER_ID>] <PACKAGE | UID> <OP> <MODE>");
pw.println(" Set the mode for a particular application and operation.");
pw.println(" get [--user <USER_ID>] <PACKAGE | UID> [<OP>]");
@@ -2347,6 +2357,34 @@
}
return 0;
}
+ case "start": {
+ int res = shell.parseUserPackageOp(true, err);
+ if (res < 0) {
+ return res;
+ }
+
+ if (shell.packageName != null) {
+ shell.mInterface.startOperation(shell.mToken,
+ shell.op, shell.packageUid, shell.packageName, true);
+ } else {
+ return -1;
+ }
+ return 0;
+ }
+ case "stop": {
+ int res = shell.parseUserPackageOp(true, err);
+ if (res < 0) {
+ return res;
+ }
+
+ if (shell.packageName != null) {
+ shell.mInterface.finishOperation(shell.mToken,
+ shell.op, shell.packageUid, shell.packageName);
+ } else {
+ return -1;
+ }
+ return 0;
+ }
default:
return shell.handleDefaultCommands(cmd);
}
diff --git a/services/core/java/com/android/server/TextServicesManagerService.java b/services/core/java/com/android/server/TextServicesManagerService.java
index 965714d..26a8cf7 100644
--- a/services/core/java/com/android/server/TextServicesManagerService.java
+++ b/services/core/java/com/android/server/TextServicesManagerService.java
@@ -16,6 +16,9 @@
package com.android.server;
+import static android.view.textservice.TextServicesManager.DISABLE_PER_PROFILE_SPELL_CHECKER;
+
+import com.android.internal.annotations.GuardedBy;
import com.android.internal.content.PackageMonitor;
import com.android.internal.inputmethod.InputMethodUtils;
import com.android.internal.textservice.ISpellCheckerService;
@@ -24,6 +27,7 @@
import com.android.internal.textservice.ISpellCheckerSessionListener;
import com.android.internal.textservice.ITextServicesManager;
import com.android.internal.textservice.ITextServicesSessionListener;
+import com.android.internal.textservice.LazyIntToIntMap;
import com.android.internal.util.DumpUtils;
import org.xmlpull.v1.XmlPullParserException;
@@ -79,6 +83,10 @@
private final UserManager mUserManager;
private final Object mLock = new Object();
+ @NonNull
+ @GuardedBy("mLock")
+ private final LazyIntToIntMap mSpellCheckerOwnerUserIdMap;
+
private static class TextServicesData {
@UserIdInt
private final int mUserId;
@@ -294,6 +302,9 @@
void onStopUser(@UserIdInt int userId) {
synchronized (mLock) {
+ // Clear user ID mapping table.
+ mSpellCheckerOwnerUserIdMap.delete(userId);
+
// Clean per-user data
TextServicesData tsd = mUserData.get(userId);
if (tsd == null) return;
@@ -313,12 +324,32 @@
public TextServicesManagerService(Context context) {
mContext = context;
mUserManager = mContext.getSystemService(UserManager.class);
+ mSpellCheckerOwnerUserIdMap = new LazyIntToIntMap(callingUserId -> {
+ if (DISABLE_PER_PROFILE_SPELL_CHECKER) {
+ final long token = Binder.clearCallingIdentity();
+ try {
+ final UserInfo parent = mUserManager.getProfileParent(callingUserId);
+ return (parent != null) ? parent.id : callingUserId;
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ } else {
+ return callingUserId;
+ }
+ });
mMonitor = new TextServicesMonitor();
mMonitor.register(context, null, UserHandle.ALL, true);
}
private void initializeInternalStateLocked(@UserIdInt int userId) {
+ // When DISABLE_PER_PROFILE_SPELL_CHECKER is true, we make sure here that work profile users
+ // will never have non-null TextServicesData for their user ID.
+ if (DISABLE_PER_PROFILE_SPELL_CHECKER
+ && userId != mSpellCheckerOwnerUserIdMap.get(userId)) {
+ return;
+ }
+
TextServicesData tsd = mUserData.get(userId);
if (tsd == null) {
tsd = new TextServicesData(userId, mContext);
@@ -470,7 +501,7 @@
public SpellCheckerInfo getCurrentSpellChecker(String locale) {
int userId = UserHandle.getCallingUserId();
synchronized (mLock) {
- TextServicesData tsd = mUserData.get(userId);
+ final TextServicesData tsd = getDataFromCallingUserIdLocked(userId);
if (tsd == null) return null;
return tsd.getCurrentSpellChecker();
@@ -488,7 +519,7 @@
final int userId = UserHandle.getCallingUserId();
synchronized (mLock) {
- TextServicesData tsd = mUserData.get(userId);
+ final TextServicesData tsd = getDataFromCallingUserIdLocked(userId);
if (tsd == null) return null;
subtypeHashCode =
@@ -569,7 +600,7 @@
int callingUserId = UserHandle.getCallingUserId();
synchronized (mLock) {
- TextServicesData tsd = mUserData.get(callingUserId);
+ final TextServicesData tsd = getDataFromCallingUserIdLocked(callingUserId);
if (tsd == null) return;
HashMap<String, SpellCheckerInfo> spellCheckerMap = tsd.mSpellCheckerMap;
@@ -606,7 +637,7 @@
int userId = UserHandle.getCallingUserId();
synchronized (mLock) {
- TextServicesData tsd = mUserData.get(userId);
+ final TextServicesData tsd = getDataFromCallingUserIdLocked(userId);
if (tsd == null) return false;
return tsd.isSpellCheckerEnabled();
@@ -643,7 +674,7 @@
int callingUserId = UserHandle.getCallingUserId();
synchronized (mLock) {
- TextServicesData tsd = mUserData.get(callingUserId);
+ final TextServicesData tsd = getDataFromCallingUserIdLocked(callingUserId);
if (tsd == null) return null;
ArrayList<SpellCheckerInfo> spellCheckerList = tsd.mSpellCheckerList;
@@ -666,7 +697,7 @@
int userId = UserHandle.getCallingUserId();
synchronized (mLock) {
- TextServicesData tsd = mUserData.get(userId);
+ final TextServicesData tsd = getDataFromCallingUserIdLocked(userId);
if (tsd == null) return;
final ArrayList<SpellCheckerBindGroup> removeList = new ArrayList<>();
@@ -737,6 +768,36 @@
}
}
+ /**
+ * @param callingUserId user ID of the calling process
+ * @return {@link TextServicesData} for the given user. {@code null} if spell checker is not
+ * temporarily / permanently available for the specified user
+ */
+ @Nullable
+ private TextServicesData getDataFromCallingUserIdLocked(@UserIdInt int callingUserId) {
+ final int spellCheckerOwnerUserId = mSpellCheckerOwnerUserIdMap.get(callingUserId);
+ final TextServicesData data = mUserData.get(spellCheckerOwnerUserId);
+ if (DISABLE_PER_PROFILE_SPELL_CHECKER) {
+ if (spellCheckerOwnerUserId != callingUserId) {
+ // Calling process is running under child profile.
+ if (data == null) {
+ return null;
+ }
+ final SpellCheckerInfo info = data.getCurrentSpellChecker();
+ if (info == null) {
+ return null;
+ }
+ final ServiceInfo serviceInfo = info.getServiceInfo();
+ if ((serviceInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0) {
+ // To be conservative, non pre-installed spell checker services are not allowed
+ // to be used for child profiles.
+ return null;
+ }
+ }
+ }
+ return data;
+ }
+
private static final class SessionRequest {
public final int mUid;
@Nullable
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 0de4f86..7656453 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -192,7 +192,8 @@
import static com.android.server.am.ActivityStackSupervisor.ON_TOP;
import static com.android.server.am.ActivityStackSupervisor.PRESERVE_WINDOWS;
import static com.android.server.am.ActivityStackSupervisor.REMOVE_FROM_RECENTS;
-import static com.android.server.am.MemoryStatUtil.readMemoryStatFromMemcg;
+import static com.android.server.am.MemoryStatUtil.readMemoryStatFromFilesystem;
+import static com.android.server.am.MemoryStatUtil.hasMemcg;
import static com.android.server.am.TaskRecord.INVALID_TASK_ID;
import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_DONT_LOCK;
import static com.android.server.am.TaskRecord.REPARENT_KEEP_STACK_AT_FRONT;
@@ -685,7 +686,7 @@
private final ActivityStartController mActivityStartController;
- final ClientLifecycleManager mLifecycleManager;
+ private final ClientLifecycleManager mLifecycleManager;
final TaskChangeNotificationController mTaskChangeNotificationController;
@@ -5925,6 +5926,12 @@
Slog.d(TAG_PROCESSES, "Received spurious death notification for thread "
+ thread.asBinder());
}
+
+ // On the device which doesn't have Cgroup, log LmkStateChanged which is used as a signal
+ // for pulling memory stats of other running processes when this process died.
+ if (!hasMemcg()) {
+ StatsLog.write(StatsLog.APP_DIED, SystemClock.elapsedRealtime());
+ }
}
/**
@@ -12303,6 +12310,10 @@
return mActivityStartController;
}
+ ClientLifecycleManager getLifecycleManager() {
+ return mLifecycleManager;
+ }
+
PackageManagerInternal getPackageManagerInternalLocked() {
if (mPackageManagerInt == null) {
mPackageManagerInt = LocalServices.getService(PackageManagerInternal.class);
@@ -26155,7 +26166,7 @@
final ProcessRecord r = mPidsSelfLocked.valueAt(i);
final int pid = r.pid;
final int uid = r.uid;
- final MemoryStat memoryStat = readMemoryStatFromMemcg(uid, pid);
+ final MemoryStat memoryStat = readMemoryStatFromFilesystem(uid, pid);
if (memoryStat == null) {
continue;
}
diff --git a/services/core/java/com/android/server/am/ActivityMetricsLogger.java b/services/core/java/com/android/server/am/ActivityMetricsLogger.java
index 5d5ed55..352b757 100644
--- a/services/core/java/com/android/server/am/ActivityMetricsLogger.java
+++ b/services/core/java/com/android/server/am/ActivityMetricsLogger.java
@@ -34,7 +34,7 @@
import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.server.am.MemoryStatUtil.MemoryStat;
-import static com.android.server.am.MemoryStatUtil.readMemoryStatFromMemcg;
+import static com.android.server.am.MemoryStatUtil.readMemoryStatFromFilesystem;
import android.content.Context;
import android.content.pm.ApplicationInfo;
@@ -635,7 +635,7 @@
final int pid = info.processRecord.pid;
final int uid = info.applicationInfo.uid;
- final MemoryStat memoryStat = readMemoryStatFromMemcg(uid, pid);
+ final MemoryStat memoryStat = readMemoryStatFromFilesystem(uid, pid);
if (memoryStat == null) {
if (DEBUG_METRICS) Slog.i(TAG, "logAppStartMemoryStateCapture memoryStat null");
return;
diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java
index 519024a..e6d6fdf 100644
--- a/services/core/java/com/android/server/am/ActivityRecord.java
+++ b/services/core/java/com/android/server/am/ActivityRecord.java
@@ -665,7 +665,7 @@
"Reporting activity moved to display" + ", activityRecord=" + this
+ ", displayId=" + displayId + ", config=" + config);
- service.mLifecycleManager.scheduleTransaction(app.thread, appToken,
+ service.getLifecycleManager().scheduleTransaction(app.thread, appToken,
MoveToDisplayItem.obtain(displayId, config));
} catch (RemoteException e) {
// If process died, whatever.
@@ -683,7 +683,7 @@
if (DEBUG_CONFIGURATION) Slog.v(TAG, "Sending new config to " + this + ", config: "
+ config);
- service.mLifecycleManager.scheduleTransaction(app.thread, appToken,
+ service.getLifecycleManager().scheduleTransaction(app.thread, appToken,
ActivityConfigurationChangeItem.obtain(config));
} catch (RemoteException e) {
// If process died, whatever.
@@ -710,7 +710,7 @@
private void scheduleMultiWindowModeChanged(Configuration overrideConfig) {
try {
- service.mLifecycleManager.scheduleTransaction(app.thread, appToken,
+ service.getLifecycleManager().scheduleTransaction(app.thread, appToken,
MultiWindowModeChangeItem.obtain(mLastReportedMultiWindowMode,
overrideConfig));
} catch (Exception e) {
@@ -738,7 +738,7 @@
private void schedulePictureInPictureModeChanged(Configuration overrideConfig) {
try {
- service.mLifecycleManager.scheduleTransaction(app.thread, appToken,
+ service.getLifecycleManager().scheduleTransaction(app.thread, appToken,
PipModeChangeItem.obtain(mLastReportedPictureInPictureMode,
overrideConfig));
} catch (Exception e) {
@@ -1428,7 +1428,7 @@
try {
ArrayList<ReferrerIntent> ar = new ArrayList<>(1);
ar.add(rintent);
- service.mLifecycleManager.scheduleTransaction(app.thread, appToken,
+ service.getLifecycleManager().scheduleTransaction(app.thread, appToken,
NewIntentItem.obtain(ar, mState == PAUSED));
unsent = false;
} catch (RemoteException e) {
@@ -1615,20 +1615,30 @@
if (DEBUG_STATES) Slog.v(TAG_STATES, "State movement: " + this + " from:" + getState()
+ " to:" + state + " reason:" + reason);
+ if (state == mState) {
+ // No need to do anything if state doesn't change.
+ if (DEBUG_STATES) Slog.v(TAG_STATES, "State unchanged from:" + state);
+ return;
+ }
+
+ if (isState(DESTROYED) || (state != DESTROYED && isState(DESTROYING))) {
+ // We cannot move backwards from destroyed and destroying states.
+ throw new IllegalArgumentException("cannot move back states once destroying"
+ + "current:" + mState + " requested:" + state);
+ }
+
final ActivityState prev = mState;
- final boolean stateChanged = prev != state;
+ mState = state;
+
+ if (mRecentTransitions.size() == MAX_STORED_STATE_TRANSITIONS) {
+ mRecentTransitions.remove(0);
+ }
+
+ mRecentTransitions.add(new StateTransition(prev, state, reason));
mState = state;
- if (stateChanged) {
- if (mRecentTransitions.size() == MAX_STORED_STATE_TRANSITIONS) {
- mRecentTransitions.remove(0);
- }
-
- mRecentTransitions.add(new StateTransition(prev, state, reason));
- }
-
- if (stateChanged && isState(DESTROYING, DESTROYED)) {
+ if (isState(DESTROYING, DESTROYED)) {
makeFinishingLocked();
// When moving to the destroyed state, immediately destroy the activity in the
@@ -1726,28 +1736,32 @@
setVisible(true);
sleeping = false;
app.pendingUiClean = true;
- service.mLifecycleManager.scheduleTransaction(app.thread, appToken,
+ service.getLifecycleManager().scheduleTransaction(app.thread, appToken,
WindowVisibilityItem.obtain(true /* showWindow */));
// The activity may be waiting for stop, but that is no longer appropriate for it.
mStackSupervisor.mStoppingActivities.remove(this);
mStackSupervisor.mGoingToSleepActivities.remove(this);
- // If the activity is stopped or stopping, cycle to the paused state.
- if (isState(STOPPED, STOPPING)) {
+ // If the activity is stopped or stopping, cycle to the paused state. We avoid doing
+ // this when there is an activity waiting to become translucent as the extra binder
+ // calls will lead to noticeable jank. A later call to
+ // ActivityStack#ensureActivitiesVisibleLocked will bring the activity to the proper
+ // paused state.
+ if (isState(STOPPED, STOPPING) && stack.mTranslucentActivityWaiting == null) {
// Capture reason before state change
final String reason = getLifecycleDescription("makeVisibleIfNeeded");
// An activity must be in the {@link PAUSING} state for the system to validate
// the move to {@link PAUSED}.
setState(PAUSING, "makeVisibleIfNeeded");
- service.mLifecycleManager.scheduleTransaction(app.thread, appToken,
+ service.getLifecycleManager().scheduleTransaction(app.thread, appToken,
PauseActivityItem.obtain(finishing, false /* userLeaving */,
configChangeFlags, false /* dontReport */)
.setDescription(reason));
}
} catch (Exception e) {
// Just skip on any failure; we'll make it visible when it next restarts.
- Slog.w(TAG, "Exception thrown making visibile: " + intent.getComponent(), e);
+ Slog.w(TAG, "Exception thrown making visible: " + intent.getComponent(), e);
}
handleAlreadyVisible();
}
@@ -2708,7 +2722,7 @@
final ClientTransaction transaction = ClientTransaction.obtain(app.thread, appToken);
transaction.addCallback(callbackItem);
transaction.setLifecycleStateRequest(lifecycleItem);
- service.mLifecycleManager.scheduleTransaction(transaction);
+ service.getLifecycleManager().scheduleTransaction(transaction);
// Note: don't need to call pauseIfSleepingLocked() here, because the caller will only
// request resume if this activity is currently resumed, which implies we aren't
// sleeping.
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index 9276abe..f4a4af2 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -1472,7 +1472,7 @@
prev.shortComponentName, "userLeaving=" + userLeaving);
mService.updateUsageStats(prev, false);
- mService.mLifecycleManager.scheduleTransaction(prev.app.thread, prev.appToken,
+ mService.getLifecycleManager().scheduleTransaction(prev.app.thread, prev.appToken,
PauseActivityItem.obtain(prev.finishing, userLeaving,
prev.configChangeFlags, pauseImmediately).setDescription(
prev.getLifecycleDescription("startPausingLocked")));
@@ -2109,7 +2109,7 @@
if (r.app != null && r.app.thread != null) {
if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY,
"Scheduling invisibility: " + r);
- mService.mLifecycleManager.scheduleTransaction(r.app.thread, r.appToken,
+ mService.getLifecycleManager().scheduleTransaction(r.app.thread, r.appToken,
WindowVisibilityItem.obtain(false /* showWindow */));
}
@@ -2661,13 +2661,12 @@
next.app.pendingUiClean = true;
next.app.forceProcessStateUpTo(mService.mTopProcessState);
next.clearOptionsLocked();
-
transaction.setLifecycleStateRequest(
ResumeActivityItem.obtain(next.app.repProcState,
mService.isNextTransitionForward())
.setDescription(next.getLifecycleDescription(
"resumeTopActivityInnerLocked")));
- mService.mLifecycleManager.scheduleTransaction(transaction);
+ mService.getLifecycleManager().scheduleTransaction(transaction);
if (DEBUG_STATES) Slog.d(TAG_STATES, "resumeTopActivityLocked: Resumed "
+ next);
@@ -3317,7 +3316,7 @@
ArrayList<ResultInfo> list = new ArrayList<ResultInfo>();
list.add(new ResultInfo(resultWho, requestCode,
resultCode, data));
- mService.mLifecycleManager.scheduleTransaction(r.app.thread, r.appToken,
+ mService.getLifecycleManager().scheduleTransaction(r.app.thread, r.appToken,
ActivityResultItem.obtain(list));
return;
} catch (Exception e) {
@@ -3446,7 +3445,7 @@
}
EventLogTags.writeAmStopActivity(
r.userId, System.identityHashCode(r), r.shortComponentName);
- mService.mLifecycleManager.scheduleTransaction(r.app.thread, r.appToken,
+ mService.getLifecycleManager().scheduleTransaction(r.app.thread, r.appToken,
StopActivityItem.obtain(r.visible, r.configChangeFlags)
.setDescription(r.getLifecycleDescription("stopActivityLocked")));
if (shouldSleepOrShutDownActivities()) {
@@ -3782,6 +3781,15 @@
}
final ActivityState prevState = r.getState();
if (DEBUG_STATES) Slog.v(TAG_STATES, "Moving to FINISHING: " + r);
+
+ // We are already destroying / have already destroyed the activity. Do not continue to
+ // modify it. Note that we do not use ActivityRecord#finishing here as finishing is not
+ // indicative of destruction (though destruction is indicative of finishing) as finishing
+ // can be delayed below.
+ if (r.isState(DESTROYING, DESTROYED)) {
+ return null;
+ }
+
r.setState(FINISHING, "finishCurrentActivityLocked");
final boolean finishingActivityInNonFocusedStack
= r.getStack() != mStackSupervisor.getFocusedStack()
@@ -4232,6 +4240,13 @@
if (DEBUG_SWITCH || DEBUG_CLEANUP) Slog.v(TAG_SWITCH,
"Removing activity from " + reason + ": token=" + r
+ ", app=" + (r.app != null ? r.app.processName : "(null)"));
+
+ if (r.isState(DESTROYING, DESTROYED)) {
+ if (DEBUG_STATES) Slog.v(TAG_STATES, "activity " + r + " already finishing."
+ + "skipping request with reason:" + reason);
+ return false;
+ }
+
EventLog.writeEvent(EventLogTags.AM_DESTROY_ACTIVITY,
r.userId, System.identityHashCode(r),
r.getTask().taskId, r.shortComponentName, reason);
@@ -4265,7 +4280,7 @@
try {
if (DEBUG_SWITCH) Slog.i(TAG_SWITCH, "Destroying: " + r);
- mService.mLifecycleManager.scheduleTransaction(r.app.thread, r.appToken,
+ mService.getLifecycleManager().scheduleTransaction(r.app.thread, r.appToken,
DestroyActivityItem.obtain(r.finishing, r.configChangeFlags)
.setDescription(
r.getLifecycleDescription("destroyActivityLocked:" + reason)));
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index 26ffe95..740a312 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -1459,7 +1459,7 @@
clientTransaction.setLifecycleStateRequest(lifecycleItem);
// Schedule transaction.
- mService.mLifecycleManager.scheduleTransaction(clientTransaction);
+ mService.getLifecycleManager().scheduleTransaction(clientTransaction);
if ((app.info.privateFlags & ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE) != 0) {
diff --git a/services/core/java/com/android/server/am/MemoryStatUtil.java b/services/core/java/com/android/server/am/MemoryStatUtil.java
index a2a84ec..da36bd1 100644
--- a/services/core/java/com/android/server/am/MemoryStatUtil.java
+++ b/services/core/java/com/android/server/am/MemoryStatUtil.java
@@ -38,8 +38,12 @@
final class MemoryStatUtil {
private static final String TAG = TAG_WITH_CLASS_NAME ? "MemoryStatUtil" : TAG_AM;
+ /** Path to check if device has memcg */
+ private static final String MEMCG_TEST_PATH = "/dev/memcg/apps/memory.stat";
/** Path to memory stat file for logging app start memory state */
private static final String MEMORY_STAT_FILE_FMT = "/dev/memcg/apps/uid_%d/pid_%d/memory.stat";
+ /** Path to procfs stat file for logging app start memory state */
+ private static final String PROC_STAT_FILE_FMT = "/proc/%d/stat";
private static final Pattern PGFAULT = Pattern.compile("total_pgfault (\\d+)");
private static final Pattern PGMAJFAULT = Pattern.compile("total_pgmajfault (\\d+)");
@@ -47,24 +51,57 @@
private static final Pattern CACHE_IN_BYTES = Pattern.compile("total_cache (\\d+)");
private static final Pattern SWAP_IN_BYTES = Pattern.compile("total_swap (\\d+)");
+ private static final int PGFAULT_INDEX = 9;
+ private static final int PGMAJFAULT_INDEX = 11;
+ private static final int RSS_IN_BYTES_INDEX = 23;
+
+ /** True if device has memcg */
+ private static volatile Boolean sDeviceHasMemCg;
+
private MemoryStatUtil() {}
/**
+ * Reads memory stat for a process.
+ *
+ * Reads from memcg if available on device, else fallback to procfs.
+ * Returns null if no stats can be read.
+ */
+ @Nullable
+ static MemoryStat readMemoryStatFromFilesystem(int uid, int pid) {
+ return hasMemcg() ? readMemoryStatFromMemcg(uid, pid) : readMemoryStatFromProcfs(pid);
+ }
+
+ /**
* Reads memory.stat of a process from memcg.
+ *
+ * Returns null if file is not found in memcg or if file has unrecognized contents.
*/
@Nullable
static MemoryStat readMemoryStatFromMemcg(int uid, int pid) {
- final String memoryStatPath = String.format(Locale.US, MEMORY_STAT_FILE_FMT, uid, pid);
- final File memoryStatFile = new File(memoryStatPath);
- if (!memoryStatFile.exists()) {
- if (DEBUG_METRICS) Slog.i(TAG, memoryStatPath + " not found");
+ final String path = String.format(Locale.US, MEMORY_STAT_FILE_FMT, uid, pid);
+ return parseMemoryStatFromMemcg(readFileContents(path));
+ }
+
+ /**
+ * Reads memory stat of a process from procfs.
+ *
+ * Returns null if file is not found in procfs or if file has unrecognized contents.
+ */
+ @Nullable
+ static MemoryStat readMemoryStatFromProcfs(int pid) {
+ final String path = String.format(Locale.US, PROC_STAT_FILE_FMT, pid);
+ return parseMemoryStatFromProcfs(readFileContents(path));
+ }
+
+ private static String readFileContents(String path) {
+ final File file = new File(path);
+ if (!file.exists()) {
+ if (DEBUG_METRICS) Slog.i(TAG, path + " not found");
return null;
}
try {
- final String memoryStatContents = FileUtils.readTextFile(
- memoryStatFile, 0 /* max */, null /* ellipsis */);
- return parseMemoryStat(memoryStatContents);
+ return FileUtils.readTextFile(file, 0 /* max */, null /* ellipsis */);
} catch (IOException e) {
Slog.e(TAG, "Failed to read file:", e);
return null;
@@ -76,12 +113,12 @@
*/
@VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
@Nullable
- static MemoryStat parseMemoryStat(String memoryStatContents) {
- MemoryStat memoryStat = new MemoryStat();
- if (memoryStatContents == null) {
- return memoryStat;
+ static MemoryStat parseMemoryStatFromMemcg(String memoryStatContents) {
+ if (memoryStatContents == null || memoryStatContents.isEmpty()) {
+ return null;
}
+ final MemoryStat memoryStat = new MemoryStat();
Matcher m;
m = PGFAULT.matcher(memoryStatContents);
memoryStat.pgfault = m.find() ? Long.valueOf(m.group(1)) : 0;
@@ -96,6 +133,40 @@
return memoryStat;
}
+ /**
+ * Parses relevant statistics out from the contents of a /proc/pid/stat file in procfs.
+ */
+ @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
+ @Nullable
+ static MemoryStat parseMemoryStatFromProcfs(String procStatContents) {
+ if (procStatContents == null || procStatContents.isEmpty()) {
+ return null;
+ }
+
+ final String[] splits = procStatContents.split(" ");
+ if (splits.length < 24) {
+ return null;
+ }
+
+ final MemoryStat memoryStat = new MemoryStat();
+ memoryStat.pgfault = Long.valueOf(splits[PGFAULT_INDEX]);
+ memoryStat.pgmajfault = Long.valueOf(splits[PGMAJFAULT_INDEX]);
+ memoryStat.rssInBytes = Long.valueOf(splits[RSS_IN_BYTES_INDEX]);
+ return memoryStat;
+ }
+
+ /**
+ * Checks if memcg is available on device.
+ *
+ * Touches the filesystem to do the check.
+ */
+ static boolean hasMemcg() {
+ if (sDeviceHasMemCg == null) {
+ sDeviceHasMemCg = (new File(MEMCG_TEST_PATH)).exists();
+ }
+ return sDeviceHasMemCg;
+ }
+
static final class MemoryStat {
/** Number of page faults */
long pgfault;
@@ -108,4 +179,4 @@
/** Number of bytes of swap usage */
long swapInBytes;
}
-}
+}
\ No newline at end of file
diff --git a/services/core/java/com/android/server/fingerprint/FingerprintService.java b/services/core/java/com/android/server/fingerprint/FingerprintService.java
index 3da3551..c3259c3 100644
--- a/services/core/java/com/android/server/fingerprint/FingerprintService.java
+++ b/services/core/java/com/android/server/fingerprint/FingerprintService.java
@@ -941,9 +941,7 @@
@Override
public void sendResult(Bundle data) throws RemoteException {
- if (mWakeLock.isHeld()) {
- mWakeLock.release();
- }
+ releaseWakelock();
}
});
} catch (DeadObjectException e) {
@@ -951,6 +949,7 @@
mHandler.post(mRemoveCallbackRunnable);
} catch (RemoteException e) {
Slog.w(TAG, "Failed to invoke onLockoutReset: ", e);
+ releaseWakelock();
}
}
}
@@ -958,9 +957,7 @@
private final Runnable mRemoveCallbackRunnable = new Runnable() {
@Override
public void run() {
- if (mWakeLock.isHeld()) {
- mWakeLock.release();
- }
+ releaseWakelock();
removeLockoutResetCallback(FingerprintServiceLockoutResetMonitor.this);
}
};
@@ -970,6 +967,12 @@
Slog.e(TAG, "Lockout reset callback binder died");
mHandler.post(mRemoveCallbackRunnable);
}
+
+ private void releaseWakelock() {
+ if (mWakeLock.isHeld()) {
+ mWakeLock.release();
+ }
+ }
}
private IBiometricsFingerprintClientCallback mDaemonCallback =
diff --git a/services/core/java/com/android/server/media/MediaSessionService.java b/services/core/java/com/android/server/media/MediaSessionService.java
index 84c889c..6411ae1 100644
--- a/services/core/java/com/android/server/media/MediaSessionService.java
+++ b/services/core/java/com/android/server/media/MediaSessionService.java
@@ -136,8 +136,8 @@
private IRemoteVolumeController mRvc;
// MediaSession2 support
- // TODO(jaewan): Support multi-user and managed profile.
- // TODO(jaewan): Make it priority list for handling volume/media key.
+ // TODO(jaewan): Support multi-user and managed profile. (b/73597722)
+ // TODO(jaewan): Make it priority list for handling volume/media key. (b/73760382)
private final Map<SessionToken2, MediaController2> mSessionRecords = new ArrayMap<>();
private final List<SessionTokensListenerRecord> mSessionTokensListeners = new ArrayList<>();
@@ -184,7 +184,7 @@
updateUser();
registerPackageBroadcastReceivers();
- // TODO(jaewan): Query per users
+ // TODO(jaewan): Query per users (b/73597722)
buildMediaSessionService2List();
}
@@ -443,6 +443,7 @@
// TODO(jaewan): Only consider changed packages when building session service list
// when we make this multi-user aware. At that time,
// use PackageMonitor.getChangingUserId() to know which user has changed.
+ // (b/73597722)
IntentFilter filter = new IntentFilter();
filter.addDataScheme("package");
filter.addAction(Intent.ACTION_PACKAGE_ADDED);
@@ -465,7 +466,7 @@
}
// Check if the package is replacing (i.e. reinstalling)
final boolean isReplacing = intent.getBooleanExtra(Intent.EXTRA_REPLACING, false);
- // TODO(jaewan): Add multi-user support with this.
+ // TODO(jaewan): Add multi-user support with this. (b/73597722)
// final int uid = intent.getIntExtra(Intent.EXTRA_UID, 0);
if (DEBUG) {
@@ -506,8 +507,7 @@
if (DEBUG) {
Log.d(TAG, "buildMediaSessionService2List");
}
- // TODO(jaewan): Also query for managed profile users.
- // TODO(jaewan): Similar codes are also at the updatable. Can't we share codes?
+ // TODO(jaewan): Also query for managed profile users. (b/73597722)
PackageManager manager = getContext().getPackageManager();
List<ResolveInfo> services = new ArrayList<>();
// If multiple actions are declared for a service, browser gets higher priority.
@@ -539,7 +539,7 @@
ServiceInfo serviceInfo = services.get(i).serviceInfo;
int uid;
try {
- // TODO(jaewan): Do this per user.
+ // TODO(jaewan): Do this per user. (b/73597722)
uid = manager.getPackageUid(serviceInfo.packageName,
PackageManager.GET_META_DATA);
} catch (NameNotFoundException e) {
@@ -1490,16 +1490,6 @@
mUserRecords.valueAt(i).dumpLocked(pw, "");
}
mAudioPlayerStateMonitor.dump(getContext(), pw, "");
-
- // TODO(jaewan): Remove this debug command before ship.
- if (args != null && args.length > 0 && "--purge".equals(args[0])) {
- mSessionRecords.clear();
- }
- pw.println();
- pw.println("Session2: size=" + mSessionRecords.size());
- for (SessionToken2 token : mSessionRecords.keySet()) {
- pw.println(" " + token);
- }
}
}
@@ -1567,7 +1557,7 @@
destroySession2Internal(token);
}
- // TODO(jaewan): Protect this API with permission
+ // TODO(jaewan): Protect this API with permission (b/73226436)
@Override
public List<Bundle> getSessionTokens(boolean activeSessionOnly,
boolean sessionServiceOnly) throws RemoteException {
@@ -1587,8 +1577,8 @@
return tokens;
}
- // TODO(jaewan): Protect this API with permission
- // TODO(jaewan): "userId != calling user" needs extra protection
+ // TODO(jaewan): Protect this API with permission (b/73226436)
+ // TODO(jaewan): "userId != calling user" needs extra protection (b/73226436)
@Override
public void addSessionTokensListener(ISessionTokensListener listener, int userId,
String packageName) {
@@ -1603,7 +1593,7 @@
}
}
- // TODO(jaewan): Protect this API with permission
+ // TODO(jaewan): Protect this API with permission (b/73226436)
@Override
public void removeSessionTokensListener(ISessionTokensListener listener) {
synchronized (mLock) {
@@ -2028,7 +2018,7 @@
}
@Override
- public void onDisconnected() {
+ public void onDisconnected(MediaController2 controller) {
destroySession2Internal(mToken);
}
};
@@ -2039,7 +2029,8 @@
public SessionTokensListenerRecord(ISessionTokensListener listener, int userId) {
mListener = listener;
- mUserId = userId; // TODO should userId be mapped through mFullUserIds?
+ // TODO should userId be mapped through mFullUserIds? (b/73597722)
+ mUserId = userId;
}
@Override
@@ -2060,6 +2051,7 @@
for (SessionToken2 token : mSessionRecords.keySet()) {
// TODO(jaewan): Remove the check for UserHandle.USER_ALL (shouldn't happen).
// This happens when called form buildMediaSessionService2List(...).
+ // (b/73760382)
if (UserHandle.getUserId(token.getUid()) == userId
|| UserHandle.USER_ALL == userId) {
tokens.add(token.toBundle());
@@ -2067,7 +2059,7 @@
}
for (SessionTokensListenerRecord record : mSessionTokensListeners) {
- // TODO should userId be mapped through mFullUserIds?
+ // TODO(jaewan): Should userId be mapped through mFullUserIds? (b/73760382)
if (record.mUserId == userId || record.mUserId == UserHandle.USER_ALL) {
try {
record.mListener.onSessionTokensChanged(tokens);
diff --git a/services/core/java/com/android/server/om/OverlayManagerSettings.java b/services/core/java/com/android/server/om/OverlayManagerSettings.java
index 0b9412b..863045c 100644
--- a/services/core/java/com/android/server/om/OverlayManagerSettings.java
+++ b/services/core/java/com/android/server/om/OverlayManagerSettings.java
@@ -180,12 +180,14 @@
List<OverlayInfo> getOverlaysForTarget(@NonNull final String targetPackageName,
final int userId) {
return selectWhereTarget(targetPackageName, userId)
+ .filter((i) -> !i.isStatic())
.map(SettingsItem::getOverlayInfo)
.collect(Collectors.toList());
}
ArrayMap<String, List<OverlayInfo>> getOverlaysForUser(final int userId) {
return selectWhereUser(userId)
+ .filter((i) -> !i.isStatic())
.map(SettingsItem::getOverlayInfo)
.collect(Collectors.groupingBy(info -> info.targetPackageName, ArrayMap::new,
Collectors.toList()));
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 98fb18a..6513683 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -2981,6 +2981,9 @@
}
}
}
+ // Adjust seInfo to ensure apps which share a sharedUserId are placed in the same
+ // SELinux domain.
+ setting.fixSeInfoLocked();
}
// Now that we know all the packages we are keeping,
@@ -6853,6 +6856,10 @@
resolveInfos.remove(i);
continue;
}
+ if (blockInstant && isInstantApp(info.activityInfo.packageName, userId)) {
+ resolveInfos.remove(i);
+ continue;
+ }
// requested activity is defined in a split that hasn't been installed yet.
// add the installer to the resolve list
if (DEBUG_INSTALL) {
@@ -6867,8 +6874,6 @@
info.activityInfo.packageName,
info.activityInfo.applicationInfo.versionCode,
info.activityInfo.splitName);
- installerInfo.match = IntentFilter.MATCH_CATEGORY_SCHEME_SPECIFIC_PART
- | IntentFilter.MATCH_ADJUSTMENT_NORMAL;
// add a non-generic filter
installerInfo.filter = new IntentFilter();
@@ -6878,11 +6883,6 @@
installerInfo.resolvePackageName = info.getComponentInfo().packageName;
installerInfo.labelRes = info.resolveLabelResId();
installerInfo.icon = info.resolveIconResId();
-
- // propagate priority/preferred order/default
- installerInfo.priority = info.priority;
- installerInfo.preferredOrder = info.preferredOrder;
- installerInfo.isDefault = info.isDefault;
installerInfo.isInstantAppAvailable = true;
resolveInfos.set(i, installerInfo);
continue;
@@ -7620,10 +7620,6 @@
info.serviceInfo.packageName,
info.serviceInfo.applicationInfo.versionCode,
info.serviceInfo.splitName);
- // make sure this resolver is the default
- installerInfo.isDefault = true;
- installerInfo.match = IntentFilter.MATCH_CATEGORY_SCHEME_SPECIFIC_PART
- | IntentFilter.MATCH_ADJUSTMENT_NORMAL;
// add a non-generic filter
installerInfo.filter = new IntentFilter();
// load resources from the correct package
@@ -7742,10 +7738,6 @@
info.providerInfo.packageName,
info.providerInfo.applicationInfo.versionCode,
info.providerInfo.splitName);
- // make sure this resolver is the default
- installerInfo.isDefault = true;
- installerInfo.match = IntentFilter.MATCH_CATEGORY_SCHEME_SPECIFIC_PART
- | IntentFilter.MATCH_ADJUSTMENT_NORMAL;
// add a non-generic filter
installerInfo.filter = new IntentFilter();
// load resources from the correct package
@@ -10381,20 +10373,24 @@
pkg.applicationInfo.flags |= ApplicationInfo.FLAG_UPDATED_SYSTEM_APP;
}
- // SELinux sandboxes become more restrictive as targetSdkVersion increases.
- // To ensure that apps with sharedUserId are placed in the same selinux domain
- // without breaking any assumptions about access, put them into the least
- // restrictive targetSdkVersion=25 domain.
- // TODO(b/72290969): Base this on the actual targetSdkVersion(s) of the apps within the
- // sharedUserSetting, instead of defaulting to the least restrictive domain.
- final int targetSdk = (sharedUserSetting != null) ? 25
- : pkg.applicationInfo.targetSdkVersion;
+ // Apps which share a sharedUserId must be placed in the same selinux domain. If this
+ // package is the first app installed as this shared user, set seInfoTargetSdkVersion to its
+ // targetSdkVersion. These are later adjusted in PackageManagerService's constructor to be
+ // the lowest targetSdkVersion of all apps within the shared user, which corresponds to the
+ // least restrictive selinux domain.
+ // NOTE: As new packages are installed / updated, the shared user's seinfoTargetSdkVersion
+ // will NOT be modified until next boot, even if a lower targetSdkVersion is used. This
+ // ensures that all packages continue to run in the same selinux domain.
+ final int targetSdkVersion =
+ ((sharedUserSetting != null) && (sharedUserSetting.packages.size() != 0)) ?
+ sharedUserSetting.seInfoTargetSdkVersion : pkg.applicationInfo.targetSdkVersion;
// TODO(b/71593002): isPrivileged for sharedUser and appInfo should never be out of sync.
// They currently can be if the sharedUser apps are signed with the platform key.
final boolean isPrivileged = (sharedUserSetting != null) ?
sharedUserSetting.isPrivileged() | pkg.isPrivileged() : pkg.isPrivileged();
- SELinuxMMAC.assignSeInfoValue(pkg, isPrivileged, targetSdk);
+ pkg.applicationInfo.seInfo = SELinuxMMAC.getSeInfo(pkg, isPrivileged,
+ pkg.applicationInfo.targetSandboxVersion, targetSdkVersion);
pkg.mExtras = pkgSetting;
pkg.applicationInfo.processName = fixProcessName(
diff --git a/services/core/java/com/android/server/pm/SELinuxMMAC.java b/services/core/java/com/android/server/pm/SELinuxMMAC.java
index a9f1528..b47d966 100644
--- a/services/core/java/com/android/server/pm/SELinuxMMAC.java
+++ b/services/core/java/com/android/server/pm/SELinuxMMAC.java
@@ -64,6 +64,8 @@
/** Required MAC permissions files */
private static List<File> sMacPermissions = new ArrayList<>();
+ private static final String DEFAULT_SEINFO = "default";
+
// Append privapp to existing seinfo label
private static final String PRIVILEGED_APP_STR = ":privapp";
@@ -307,45 +309,56 @@
}
/**
- * Applies a security label to a package based on an seinfo tag taken from a matched
- * policy. All signature based policy stanzas are consulted and, if no match is
- * found, the default seinfo label of 'default' (set in ApplicationInfo object) is
- * used. The security label is attached to the ApplicationInfo instance of the package
- * in the event that a matching policy was found.
+ * Selects a security label to a package based on input parameters and the seinfo tag taken
+ * from a matched policy. All signature based policy stanzas are consulted and, if no match
+ * is found, the default seinfo label of 'default' is used. The security label is attached to
+ * the ApplicationInfo instance of the package.
*
* @param pkg object representing the package to be labeled.
+ * @param isPrivileged boolean.
+ * @param targetSandboxVersion int.
+ * @param targetSdkVersion int. If this pkg runs as a sharedUser, targetSdkVersion is the
+ * greater of: lowest targetSdk for all pkgs in the sharedUser, or
+ * MINIMUM_TARGETSDKVERSION.
+ * @return String representing the resulting seinfo.
*/
- public static void assignSeInfoValue(PackageParser.Package pkg, boolean isPrivileged,
- int targetSdkVersion) {
+ public static String getSeInfo(PackageParser.Package pkg, boolean isPrivileged,
+ int targetSandboxVersion, int targetSdkVersion) {
+ String seInfo = null;
synchronized (sPolicies) {
if (!sPolicyRead) {
if (DEBUG_POLICY) {
Slog.d(TAG, "Policy not read");
}
- return;
- }
- for (Policy policy : sPolicies) {
- String seInfo = policy.getMatchedSeInfo(pkg);
- if (seInfo != null) {
- pkg.applicationInfo.seInfo = seInfo;
- break;
+ } else {
+ for (Policy policy : sPolicies) {
+ seInfo = policy.getMatchedSeInfo(pkg);
+ if (seInfo != null) {
+ break;
+ }
}
}
}
- if (pkg.applicationInfo.targetSandboxVersion == 2)
- pkg.applicationInfo.seInfo += SANDBOX_V2_STR;
-
- if (isPrivileged) {
- pkg.applicationInfo.seInfo += PRIVILEGED_APP_STR;
+ if (seInfo == null) {
+ seInfo = DEFAULT_SEINFO;
}
- pkg.applicationInfo.seInfo += TARGETSDKVERSION_STR + targetSdkVersion;
+ if (targetSandboxVersion == 2) {
+ seInfo += SANDBOX_V2_STR;
+ }
+
+ if (isPrivileged) {
+ seInfo += PRIVILEGED_APP_STR;
+ }
+
+ seInfo += TARGETSDKVERSION_STR + targetSdkVersion;
if (DEBUG_POLICY_INSTALL) {
Slog.i(TAG, "package (" + pkg.packageName + ") labeled with " +
- "seinfo=" + pkg.applicationInfo.seInfo);
+ "seinfo=" + seInfo);
}
+ return seInfo;
}
}
diff --git a/services/core/java/com/android/server/pm/SharedUserSetting.java b/services/core/java/com/android/server/pm/SharedUserSetting.java
index 2446131..1d9afd9 100644
--- a/services/core/java/com/android/server/pm/SharedUserSetting.java
+++ b/services/core/java/com/android/server/pm/SharedUserSetting.java
@@ -39,6 +39,10 @@
int uidFlags;
int uidPrivateFlags;
+ // The lowest targetSdkVersion of all apps in the sharedUserSetting, used to assign seinfo so
+ // that all apps within the sharedUser run in the same selinux context.
+ int seInfoTargetSdkVersion;
+
final ArraySet<PackageSetting> packages = new ArraySet<PackageSetting>();
final PackageSignatures signatures = new PackageSignatures();
@@ -84,6 +88,11 @@
}
void addPackage(PackageSetting packageSetting) {
+ // If this is the first package added to this shared user, temporarily (until next boot) use
+ // its targetSdkVersion when assigning seInfo for the shared user.
+ if ((packages.size() == 0) && (packageSetting.pkg != null)) {
+ seInfoTargetSdkVersion = packageSetting.pkg.applicationInfo.targetSdkVersion;
+ }
if (packages.add(packageSetting)) {
setFlags(this.pkgFlags | packageSetting.pkgFlags);
setPrivateFlags(this.pkgPrivateFlags | packageSetting.pkgPrivateFlags);
@@ -107,4 +116,26 @@
public boolean isPrivileged() {
return (this.pkgPrivateFlags & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0;
}
+
+ /**
+ * Determine the targetSdkVersion for a sharedUser and update pkg.applicationInfo.seInfo
+ * to ensure that all apps within the sharedUser share an SELinux domain. Use the lowest
+ * targetSdkVersion of all apps within the shared user, which corresponds to the least
+ * restrictive selinux domain.
+ */
+ public void fixSeInfoLocked() {
+ final List<PackageParser.Package> pkgList = getPackages();
+
+ for (PackageParser.Package pkg : pkgList) {
+ if (pkg.applicationInfo.targetSdkVersion < seInfoTargetSdkVersion) {
+ seInfoTargetSdkVersion = pkg.applicationInfo.targetSdkVersion;
+ }
+ }
+ for (PackageParser.Package pkg : pkgList) {
+ final boolean isPrivileged = isPrivileged() | pkg.isPrivileged();
+ pkg.applicationInfo.seInfo = SELinuxMMAC.getSeInfo(pkg, isPrivileged,
+ pkg.applicationInfo.targetSandboxVersion, seInfoTargetSdkVersion);
+ }
+ }
+
}
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 2ece2b2..062a6b8 100644
--- a/services/core/java/com/android/server/pm/dex/ArtManagerService.java
+++ b/services/core/java/com/android/server/pm/dex/ArtManagerService.java
@@ -203,8 +203,6 @@
Slog.w(TAG, "Could not open snapshot profile for " + packageName + ":"
+ snapshotProfile, e);
postError(callback, packageName, ArtManager.SNAPSHOT_FAILED_INTERNAL_ERROR);
- } finally {
- IoUtils.closeQuietly(fd);
}
}
@@ -283,6 +281,8 @@
} catch (RemoteException e) {
Slog.w(TAG,
"Failed to call onSuccess after profile snapshot for " + packageName, e);
+ } finally {
+ IoUtils.closeQuietly(fd);
}
});
}
diff --git a/services/core/java/com/android/server/policy/GlobalActions.java b/services/core/java/com/android/server/policy/GlobalActions.java
index 108b6b2..e146135 100644
--- a/services/core/java/com/android/server/policy/GlobalActions.java
+++ b/services/core/java/com/android/server/policy/GlobalActions.java
@@ -20,33 +20,33 @@
import com.android.server.LocalServices;
import com.android.server.policy.WindowManagerPolicy.WindowManagerFuncs;
-import com.android.server.statusbar.StatusBarManagerInternal;
-import com.android.server.statusbar.StatusBarManagerInternal.GlobalActionsListener;
+import com.android.server.policy.GlobalActionsProvider;
-class GlobalActions implements GlobalActionsListener {
+class GlobalActions implements GlobalActionsProvider.GlobalActionsListener {
private static final String TAG = "GlobalActions";
private static final boolean DEBUG = false;
private final Context mContext;
- private final StatusBarManagerInternal mStatusBarInternal;
+ private final GlobalActionsProvider mGlobalActionsProvider;
private final Handler mHandler;
private final WindowManagerFuncs mWindowManagerFuncs;
private LegacyGlobalActions mLegacyGlobalActions;
private boolean mKeyguardShowing;
private boolean mDeviceProvisioned;
- private boolean mStatusBarConnected;
+ private boolean mGlobalActionsAvailable;
private boolean mShowing;
public GlobalActions(Context context, WindowManagerFuncs windowManagerFuncs) {
mContext = context;
mHandler = new Handler();
mWindowManagerFuncs = windowManagerFuncs;
- mStatusBarInternal = LocalServices.getService(StatusBarManagerInternal.class);
- // Some form factors do not have a status bar.
- if (mStatusBarInternal != null) {
- mStatusBarInternal.setGlobalActionsListener(this);
+ mGlobalActionsProvider = LocalServices.getService(GlobalActionsProvider.class);
+ if (mGlobalActionsProvider != null) {
+ mGlobalActionsProvider.setGlobalActionsListener(this);
+ } else {
+ Slog.i(TAG, "No GlobalActionsProvider found, defaulting to LegacyGlobalActions");
}
}
@@ -58,15 +58,15 @@
public void showDialog(boolean keyguardShowing, boolean deviceProvisioned) {
if (DEBUG) Slog.d(TAG, "showDialog " + keyguardShowing + " " + deviceProvisioned);
- if (mStatusBarInternal != null && mStatusBarInternal.isGlobalActionsDisabled()) {
+ if (mGlobalActionsProvider != null && mGlobalActionsProvider.isGlobalActionsDisabled()) {
return;
}
mKeyguardShowing = keyguardShowing;
mDeviceProvisioned = deviceProvisioned;
mShowing = true;
- if (mStatusBarConnected) {
- mStatusBarInternal.showGlobalActions();
+ if (mGlobalActionsAvailable) {
mHandler.postDelayed(mShowTimeout, 5000);
+ mGlobalActionsProvider.showGlobalActions();
} else {
// SysUI isn't alive, show legacy menu.
ensureLegacyCreated();
@@ -88,11 +88,12 @@
}
@Override
- public void onStatusBarConnectedChanged(boolean connected) {
- if (DEBUG) Slog.d(TAG, "onStatusBarConnectedChanged " + connected);
- mStatusBarConnected = connected;
- if (mShowing && !mStatusBarConnected) {
- // Status bar died but we need to be showing global actions still, show the legacy.
+ public void onGlobalActionsAvailableChanged(boolean available) {
+ if (DEBUG) Slog.d(TAG, "onGlobalActionsAvailableChanged " + available);
+ mGlobalActionsAvailable = available;
+ if (mShowing && !mGlobalActionsAvailable) {
+ // Global actions provider died but we need to be showing global actions still, show the
+ // legacy global acrions provider.
ensureLegacyCreated();
mLegacyGlobalActions.showDialog(mKeyguardShowing, mDeviceProvisioned);
}
diff --git a/services/core/java/com/android/server/policy/GlobalActionsProvider.java b/services/core/java/com/android/server/policy/GlobalActionsProvider.java
new file mode 100644
index 0000000..d414314
--- /dev/null
+++ b/services/core/java/com/android/server/policy/GlobalActionsProvider.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2018, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.server.policy;
+
+/** Used with LocalServices to add custom handling to global actions. */
+public interface GlobalActionsProvider {
+ /** @return {@code true} if the dialog is enabled. */
+ boolean isGlobalActionsDisabled();
+ /** Set the listener that will handle various global actions evetns. */
+ void setGlobalActionsListener(GlobalActionsListener listener);
+ /** Show the global actions UI to the user. */
+ void showGlobalActions();
+
+ /** Listener to pass global actions events back to system. */
+ public interface GlobalActionsListener {
+ /**
+ * Called when sysui starts and connects its status bar, or when the status bar binder
+ * dies indicating sysui is no longer alive.
+ */
+ void onGlobalActionsAvailableChanged(boolean available);
+
+ /**
+ * Callback from sysui to notify system that global actions has been successfully shown.
+ */
+ void onGlobalActionsShown();
+
+ /**
+ * Callback from sysui to notify system that the user has dismissed global actions and
+ * it no longer needs to be displayed (even if sysui dies).
+ */
+ void onGlobalActionsDismissed();
+ }
+}
diff --git a/services/core/java/com/android/server/policy/LegacyGlobalActions.java b/services/core/java/com/android/server/policy/LegacyGlobalActions.java
index 96d062d..9cb2441 100644
--- a/services/core/java/com/android/server/policy/LegacyGlobalActions.java
+++ b/services/core/java/com/android/server/policy/LegacyGlobalActions.java
@@ -17,18 +17,24 @@
package com.android.server.policy;
import com.android.internal.app.AlertController;
-import com.android.internal.app.AlertController.AlertParams;
+import com.android.internal.globalactions.Action;
+import com.android.internal.globalactions.ActionsAdapter;
+import com.android.internal.globalactions.ActionsDialog;
+import com.android.internal.globalactions.LongPressAction;
+import com.android.internal.globalactions.SinglePressAction;
+import com.android.internal.globalactions.ToggleAction;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
-import com.android.internal.util.EmergencyAffordanceManager;
+import com.android.internal.R;
import com.android.internal.telephony.TelephonyIntents;
import com.android.internal.telephony.TelephonyProperties;
-import com.android.internal.R;
+import com.android.internal.util.EmergencyAffordanceManager;
import com.android.internal.widget.LockPatternUtils;
+import com.android.server.policy.PowerAction;
+import com.android.server.policy.RestartAction;
import com.android.server.policy.WindowManagerPolicy.WindowManagerFuncs;
import android.app.ActivityManager;
-import android.app.Dialog;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.DialogInterface;
@@ -40,7 +46,6 @@
import android.media.AudioManager;
import android.net.ConnectivityManager;
import android.os.Build;
-import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.os.RemoteException;
@@ -55,23 +60,14 @@
import android.telephony.PhoneStateListener;
import android.telephony.ServiceState;
import android.telephony.TelephonyManager;
-import android.text.TextUtils;
import android.util.ArraySet;
import android.util.Log;
-import android.util.TypedValue;
-import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.view.WindowManagerGlobal;
-import android.view.accessibility.AccessibilityEvent;
import android.widget.AdapterView;
-import android.widget.BaseAdapter;
-import android.widget.ImageView;
-import android.widget.ImageView.ScaleType;
-import android.widget.ListView;
-import android.widget.TextView;
import java.util.ArrayList;
import java.util.List;
@@ -107,12 +103,12 @@
private final Runnable mOnDismiss;
private ArrayList<Action> mItems;
- private GlobalActionsDialog mDialog;
+ private ActionsDialog mDialog;
private Action mSilentModeAction;
private ToggleAction mAirplaneModeOn;
- private MyAdapter mAdapter;
+ private ActionsAdapter mAdapter;
private boolean mKeyguardShowing = false;
private boolean mDeviceProvisioned = false;
@@ -217,7 +213,7 @@
* Create the global actions dialog.
* @return A new dialog.
*/
- private GlobalActionsDialog createDialog() {
+ private ActionsDialog createDialog() {
// Simple toggle style if there's no vibrator, otherwise use a tri-state
if (!mHasVibrator) {
mSilentModeAction = new SilentModeToggleAction();
@@ -232,7 +228,7 @@
R.string.global_actions_airplane_mode_off_status) {
@Override
- void onToggle(boolean on) {
+ public void onToggle(boolean on) {
if (mHasTelephony && Boolean.parseBoolean(
SystemProperties.get(TelephonyProperties.PROPERTY_INECM_MODE))) {
mIsWaitingForEcmExit = true;
@@ -282,7 +278,7 @@
continue;
}
if (GLOBAL_ACTION_KEY_POWER.equals(actionKey)) {
- mItems.add(new PowerAction());
+ mItems.add(new PowerAction(mContext, mWindowManagerFuncs));
} else if (GLOBAL_ACTION_KEY_AIRPLANE.equals(actionKey)) {
mItems.add(mAirplaneModeOn);
} else if (GLOBAL_ACTION_KEY_BUGREPORT.equals(actionKey)) {
@@ -307,7 +303,7 @@
} else if (GLOBAL_ACTION_KEY_ASSIST.equals(actionKey)) {
mItems.add(getAssistAction());
} else if (GLOBAL_ACTION_KEY_RESTART.equals(actionKey)) {
- mItems.add(new RestartAction());
+ mItems.add(new RestartAction(mContext, mWindowManagerFuncs));
} else {
Log.e(TAG, "Invalid global action key " + actionKey);
}
@@ -319,14 +315,15 @@
mItems.add(getEmergencyAction());
}
- mAdapter = new MyAdapter();
+ mAdapter = new ActionsAdapter(mContext, mItems,
+ () -> mDeviceProvisioned, () -> mKeyguardShowing);
- AlertParams params = new AlertParams(mContext);
+ AlertController.AlertParams params = new AlertController.AlertParams(mContext);
params.mAdapter = mAdapter;
params.mOnClickListener = this;
params.mForceInverseBackground = true;
- GlobalActionsDialog dialog = new GlobalActionsDialog(mContext, params);
+ ActionsDialog dialog = new ActionsDialog(mContext, params);
dialog.setCanceledOnTouchOutside(false); // Handled by the custom class.
dialog.getListView().setItemsCanFocus(true);
@@ -350,71 +347,6 @@
return dialog;
}
- private final class PowerAction extends SinglePressAction implements LongPressAction {
- private PowerAction() {
- super(com.android.internal.R.drawable.ic_lock_power_off,
- R.string.global_action_power_off);
- }
-
- @Override
- public boolean onLongPress() {
- UserManager um = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
- if (!um.hasUserRestriction(UserManager.DISALLOW_SAFE_BOOT)) {
- mWindowManagerFuncs.rebootSafeMode(true);
- return true;
- }
- return false;
- }
-
- @Override
- public boolean showDuringKeyguard() {
- return true;
- }
-
- @Override
- public boolean showBeforeProvisioning() {
- return true;
- }
-
- @Override
- public void onPress() {
- // shutdown by making sure radio and power are handled accordingly.
- mWindowManagerFuncs.shutdown(false /* confirm */);
- }
- }
-
- private final class RestartAction extends SinglePressAction implements LongPressAction {
- private RestartAction() {
- super(R.drawable.ic_restart, R.string.global_action_restart);
- }
-
- @Override
- public boolean onLongPress() {
- UserManager um = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
- if (!um.hasUserRestriction(UserManager.DISALLOW_SAFE_BOOT)) {
- mWindowManagerFuncs.rebootSafeMode(true);
- return true;
- }
- return false;
- }
-
- @Override
- public boolean showDuringKeyguard() {
- return true;
- }
-
- @Override
- public boolean showBeforeProvisioning() {
- return true;
- }
-
- @Override
- public void onPress() {
- mWindowManagerFuncs.reboot(false /* confirm */);
- }
- }
-
-
private class BugReportAction extends SinglePressAction implements LongPressAction {
public BugReportAction() {
@@ -693,330 +625,12 @@
mAdapter.getItem(which).onPress();
}
- /**
- * The adapter used for the list within the global actions dialog, taking
- * into account whether the keyguard is showing via
- * {@link LegacyGlobalActions#mKeyguardShowing} and whether the device is provisioned
- * via {@link LegacyGlobalActions#mDeviceProvisioned}.
- */
- private class MyAdapter extends BaseAdapter {
-
- @Override
- public int getCount() {
- int count = 0;
-
- for (int i = 0; i < mItems.size(); i++) {
- final Action action = mItems.get(i);
-
- if (mKeyguardShowing && !action.showDuringKeyguard()) {
- continue;
- }
- if (!mDeviceProvisioned && !action.showBeforeProvisioning()) {
- continue;
- }
- count++;
- }
- return count;
- }
-
- @Override
- public boolean isEnabled(int position) {
- return getItem(position).isEnabled();
- }
-
- @Override
- public boolean areAllItemsEnabled() {
- return false;
- }
-
- @Override
- public Action getItem(int position) {
-
- int filteredPos = 0;
- for (int i = 0; i < mItems.size(); i++) {
- final Action action = mItems.get(i);
- if (mKeyguardShowing && !action.showDuringKeyguard()) {
- continue;
- }
- if (!mDeviceProvisioned && !action.showBeforeProvisioning()) {
- continue;
- }
- if (filteredPos == position) {
- return action;
- }
- filteredPos++;
- }
-
- throw new IllegalArgumentException("position " + position
- + " out of range of showable actions"
- + ", filtered count=" + getCount()
- + ", keyguardshowing=" + mKeyguardShowing
- + ", provisioned=" + mDeviceProvisioned);
- }
-
- @Override
- public long getItemId(int position) {
- return position;
- }
-
- @Override
- public View getView(int position, View convertView, ViewGroup parent) {
- Action action = getItem(position);
- return action.create(mContext, convertView, parent, LayoutInflater.from(mContext));
- }
- }
-
// note: the scheme below made more sense when we were planning on having
// 8 different things in the global actions dialog. seems overkill with
// only 3 items now, but may as well keep this flexible approach so it will
// be easy should someone decide at the last minute to include something
// else, such as 'enable wifi', or 'enable bluetooth'
- /**
- * What each item in the global actions dialog must be able to support.
- */
- private interface Action {
- /**
- * @return Text that will be announced when dialog is created. null
- * for none.
- */
- CharSequence getLabelForAccessibility(Context context);
-
- View create(Context context, View convertView, ViewGroup parent, LayoutInflater inflater);
-
- void onPress();
-
- /**
- * @return whether this action should appear in the dialog when the keygaurd
- * is showing.
- */
- boolean showDuringKeyguard();
-
- /**
- * @return whether this action should appear in the dialog before the
- * device is provisioned.
- */
- boolean showBeforeProvisioning();
-
- boolean isEnabled();
- }
-
- /**
- * An action that also supports long press.
- */
- private interface LongPressAction extends Action {
- boolean onLongPress();
- }
-
- /**
- * A single press action maintains no state, just responds to a press
- * and takes an action.
- */
- private static abstract class SinglePressAction implements Action {
- private final int mIconResId;
- private final Drawable mIcon;
- private final int mMessageResId;
- private final CharSequence mMessage;
-
- protected SinglePressAction(int iconResId, int messageResId) {
- mIconResId = iconResId;
- mMessageResId = messageResId;
- mMessage = null;
- mIcon = null;
- }
-
- protected SinglePressAction(int iconResId, Drawable icon, CharSequence message) {
- mIconResId = iconResId;
- mMessageResId = 0;
- mMessage = message;
- mIcon = icon;
- }
-
- @Override
- public boolean isEnabled() {
- return true;
- }
-
- public String getStatus() {
- return null;
- }
-
- @Override
- abstract public void onPress();
-
- @Override
- public CharSequence getLabelForAccessibility(Context context) {
- if (mMessage != null) {
- return mMessage;
- } else {
- return context.getString(mMessageResId);
- }
- }
-
- @Override
- public View create(
- Context context, View convertView, ViewGroup parent, LayoutInflater inflater) {
- View v = inflater.inflate(R.layout.global_actions_item, parent, false);
-
- ImageView icon = (ImageView) v.findViewById(R.id.icon);
- TextView messageView = (TextView) v.findViewById(R.id.message);
-
- TextView statusView = (TextView) v.findViewById(R.id.status);
- final String status = getStatus();
- if (!TextUtils.isEmpty(status)) {
- statusView.setText(status);
- } else {
- statusView.setVisibility(View.GONE);
- }
- if (mIcon != null) {
- icon.setImageDrawable(mIcon);
- icon.setScaleType(ScaleType.CENTER_CROP);
- } else if (mIconResId != 0) {
- icon.setImageDrawable(context.getDrawable(mIconResId));
- }
- if (mMessage != null) {
- messageView.setText(mMessage);
- } else {
- messageView.setText(mMessageResId);
- }
-
- return v;
- }
- }
-
- /**
- * A toggle action knows whether it is on or off, and displays an icon
- * and status message accordingly.
- */
- private static abstract class ToggleAction implements Action {
-
- enum State {
- Off(false),
- TurningOn(true),
- TurningOff(true),
- On(false);
-
- private final boolean inTransition;
-
- State(boolean intermediate) {
- inTransition = intermediate;
- }
-
- public boolean inTransition() {
- return inTransition;
- }
- }
-
- protected State mState = State.Off;
-
- // prefs
- protected int mEnabledIconResId;
- protected int mDisabledIconResid;
- protected int mMessageResId;
- protected int mEnabledStatusMessageResId;
- protected int mDisabledStatusMessageResId;
-
- /**
- * @param enabledIconResId The icon for when this action is on.
- * @param disabledIconResid The icon for when this action is off.
- * @param message The general information message, e.g 'Silent Mode'
- * @param enabledStatusMessageResId The on status message, e.g 'sound disabled'
- * @param disabledStatusMessageResId The off status message, e.g. 'sound enabled'
- */
- public ToggleAction(int enabledIconResId,
- int disabledIconResid,
- int message,
- int enabledStatusMessageResId,
- int disabledStatusMessageResId) {
- mEnabledIconResId = enabledIconResId;
- mDisabledIconResid = disabledIconResid;
- mMessageResId = message;
- mEnabledStatusMessageResId = enabledStatusMessageResId;
- mDisabledStatusMessageResId = disabledStatusMessageResId;
- }
-
- /**
- * Override to make changes to resource IDs just before creating the
- * View.
- */
- void willCreate() {
-
- }
-
- @Override
- public CharSequence getLabelForAccessibility(Context context) {
- return context.getString(mMessageResId);
- }
-
- @Override
- public View create(Context context, View convertView, ViewGroup parent,
- LayoutInflater inflater) {
- willCreate();
-
- View v = inflater.inflate(R
- .layout.global_actions_item, parent, false);
-
- ImageView icon = (ImageView) v.findViewById(R.id.icon);
- TextView messageView = (TextView) v.findViewById(R.id.message);
- TextView statusView = (TextView) v.findViewById(R.id.status);
- final boolean enabled = isEnabled();
-
- if (messageView != null) {
- messageView.setText(mMessageResId);
- messageView.setEnabled(enabled);
- }
-
- boolean on = ((mState == State.On) || (mState == State.TurningOn));
- if (icon != null) {
- icon.setImageDrawable(context.getDrawable(
- (on ? mEnabledIconResId : mDisabledIconResid)));
- icon.setEnabled(enabled);
- }
-
- if (statusView != null) {
- statusView.setText(on ? mEnabledStatusMessageResId : mDisabledStatusMessageResId);
- statusView.setVisibility(View.VISIBLE);
- statusView.setEnabled(enabled);
- }
- v.setEnabled(enabled);
-
- return v;
- }
-
- @Override
- public final void onPress() {
- if (mState.inTransition()) {
- Log.w(TAG, "shouldn't be able to toggle when in transition");
- return;
- }
-
- final boolean nowOn = !(mState == State.On);
- onToggle(nowOn);
- changeStateFromPress(nowOn);
- }
-
- @Override
- public boolean isEnabled() {
- return !mState.inTransition();
- }
-
- /**
- * Implementations may override this if their state can be in on of the intermediate
- * states until some notification is received (e.g airplane mode is 'turning off' until
- * we know the wireless connections are back online
- * @param buttonOn Whether the button was turned on or off
- */
- protected void changeStateFromPress(boolean buttonOn) {
- mState = buttonOn ? State.On : State.Off;
- }
-
- abstract void onToggle(boolean on);
-
- public void updateState(State state) {
- mState = state;
- }
- }
-
private class SilentModeToggleAction extends ToggleAction {
public SilentModeToggleAction() {
super(R.drawable.ic_audio_vol_mute,
@@ -1027,7 +641,7 @@
}
@Override
- void onToggle(boolean on) {
+ public void onToggle(boolean on) {
if (on) {
mAudioManager.setRingerMode(AudioManager.RINGER_MODE_SILENT);
} else {
@@ -1226,71 +840,4 @@
mAirplaneState = on ? ToggleAction.State.On : ToggleAction.State.Off;
}
}
-
- private static final class GlobalActionsDialog extends Dialog implements DialogInterface {
- private final Context mContext;
- private final AlertController mAlert;
- private final MyAdapter mAdapter;
-
- public GlobalActionsDialog(Context context, AlertParams params) {
- super(context, getDialogTheme(context));
- mContext = getContext();
- mAlert = AlertController.create(mContext, this, getWindow());
- mAdapter = (MyAdapter) params.mAdapter;
- params.apply(mAlert);
- }
-
- private static int getDialogTheme(Context context) {
- TypedValue outValue = new TypedValue();
- context.getTheme().resolveAttribute(com.android.internal.R.attr.alertDialogTheme,
- outValue, true);
- return outValue.resourceId;
- }
-
- @Override
- protected void onStart() {
- super.setCanceledOnTouchOutside(true);
- super.onStart();
- }
-
- public ListView getListView() {
- return mAlert.getListView();
- }
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- mAlert.installContent();
- }
-
- @Override
- public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {
- if (event.getEventType() == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED) {
- for (int i = 0; i < mAdapter.getCount(); ++i) {
- CharSequence label =
- mAdapter.getItem(i).getLabelForAccessibility(getContext());
- if (label != null) {
- event.getText().add(label);
- }
- }
- }
- return super.dispatchPopulateAccessibilityEvent(event);
- }
-
- @Override
- public boolean onKeyDown(int keyCode, KeyEvent event) {
- if (mAlert.onKeyDown(keyCode, event)) {
- return true;
- }
- return super.onKeyDown(keyCode, event);
- }
-
- @Override
- public boolean onKeyUp(int keyCode, KeyEvent event) {
- if (mAlert.onKeyUp(keyCode, event)) {
- return true;
- }
- return super.onKeyUp(keyCode, event);
- }
- }
}
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index eaa17ca..ab0779b 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -541,6 +541,7 @@
volatile boolean mGoingToSleep;
volatile boolean mRequestedOrGoingToSleep;
volatile boolean mRecentsVisible;
+ volatile boolean mNavBarVirtualKeyHapticFeedbackEnabled;
volatile boolean mPictureInPictureVisible;
// Written by vr manager thread, only read in this class.
volatile private boolean mPersistentVrModeEnabled;
@@ -4368,6 +4369,11 @@
}
@Override
+ public void setNavBarVirtualKeyHapticFeedbackEnabledLw(boolean enabled) {
+ mNavBarVirtualKeyHapticFeedbackEnabled = enabled;
+ }
+
+ @Override
public int adjustSystemUiVisibilityLw(int visibility) {
mStatusBarController.adjustSystemUiVisibilityLw(mLastSystemUiFlags, visibility);
mNavigationBarController.adjustSystemUiVisibilityLw(mLastSystemUiFlags, visibility);
@@ -5892,8 +5898,12 @@
return result;
}
+ // Enable haptics if down and virtual key without multiple repetitions. If this is a hard
+ // virtual key such as a navigation bar button, only vibrate if flag is enabled.
+ final boolean isNavBarVirtKey = ((event.getFlags() & KeyEvent.FLAG_VIRTUAL_HARD_KEY) != 0);
boolean useHapticFeedback = down
&& (policyFlags & WindowManagerPolicy.FLAG_VIRTUAL) != 0
+ && (!isNavBarVirtKey || mNavBarVirtualKeyHapticFeedbackEnabled)
&& event.getRepeatCount() == 0;
// Handle special keys.
diff --git a/services/core/java/com/android/server/policy/PowerAction.java b/services/core/java/com/android/server/policy/PowerAction.java
new file mode 100644
index 0000000..d2de58e
--- /dev/null
+++ b/services/core/java/com/android/server/policy/PowerAction.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.server.policy;
+
+import android.content.Context;
+import android.os.UserManager;
+import com.android.internal.globalactions.LongPressAction;
+import com.android.internal.globalactions.SinglePressAction;
+import com.android.internal.R;
+import com.android.server.policy.WindowManagerPolicy;
+
+public final class PowerAction extends SinglePressAction implements LongPressAction {
+ private final Context mContext;
+ private final WindowManagerPolicy.WindowManagerFuncs mWindowManagerFuncs;
+
+ public PowerAction(Context context,
+ WindowManagerPolicy.WindowManagerFuncs windowManagerFuncs) {
+ super(R.drawable.ic_lock_power_off, R.string.global_action_power_off);
+ mContext = context;
+ mWindowManagerFuncs = windowManagerFuncs;
+ }
+
+ @Override
+ public boolean onLongPress() {
+ UserManager um = mContext.getSystemService(UserManager.class);
+ if (!um.hasUserRestriction(UserManager.DISALLOW_SAFE_BOOT)) {
+ mWindowManagerFuncs.rebootSafeMode(true);
+ return true;
+ }
+ return false;
+ }
+
+ @Override
+ public boolean showDuringKeyguard() {
+ return true;
+ }
+
+ @Override
+ public boolean showBeforeProvisioning() {
+ return true;
+ }
+
+ @Override
+ public void onPress() {
+ // shutdown by making sure radio and power are handled accordingly.
+ mWindowManagerFuncs.shutdown(false /* confirm */);
+ }
+}
diff --git a/services/core/java/com/android/server/policy/RestartAction.java b/services/core/java/com/android/server/policy/RestartAction.java
new file mode 100644
index 0000000..0f13da8
--- /dev/null
+++ b/services/core/java/com/android/server/policy/RestartAction.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.server.policy;
+
+import android.content.Context;
+import android.os.UserManager;
+import com.android.internal.globalactions.LongPressAction;
+import com.android.internal.globalactions.SinglePressAction;
+import com.android.internal.R;
+import com.android.server.policy.WindowManagerPolicy;
+
+public final class RestartAction extends SinglePressAction implements LongPressAction {
+ private final Context mContext;
+ private final WindowManagerPolicy.WindowManagerFuncs mWindowManagerFuncs;
+
+ public RestartAction(Context context,
+ WindowManagerPolicy.WindowManagerFuncs windowManagerFuncs) {
+ super(R.drawable.ic_restart, R.string.global_action_restart);
+ mContext = context;
+ mWindowManagerFuncs = windowManagerFuncs;
+ }
+
+ @Override
+ public boolean onLongPress() {
+ UserManager um = mContext.getSystemService(UserManager.class);
+ if (!um.hasUserRestriction(UserManager.DISALLOW_SAFE_BOOT)) {
+ mWindowManagerFuncs.rebootSafeMode(true);
+ return true;
+ }
+ return false;
+ }
+
+ @Override
+ public boolean showDuringKeyguard() {
+ return true;
+ }
+
+ @Override
+ public boolean showBeforeProvisioning() {
+ return true;
+ }
+
+ @Override
+ public void onPress() {
+ mWindowManagerFuncs.reboot(false /* confirm */);
+ }
+}
diff --git a/services/core/java/com/android/server/policy/WindowManagerPolicy.java b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
index a07f5eb..ab331a5 100644
--- a/services/core/java/com/android/server/policy/WindowManagerPolicy.java
+++ b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
@@ -1531,6 +1531,11 @@
void setPipVisibilityLw(boolean visible);
/**
+ * Called by System UI to enable or disable haptic feedback on the navigation bar buttons.
+ */
+ void setNavBarVirtualKeyHapticFeedbackEnabledLw(boolean enabled);
+
+ /**
* Specifies whether there is an on-screen navigation bar separate from the status bar.
*/
public boolean hasNavigationBar();
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java b/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java
index 3ab771b..095eaa5 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java
@@ -79,10 +79,6 @@
void setCurrentUser(int newUserId);
- boolean isGlobalActionsDisabled();
- void setGlobalActionsListener(GlobalActionsListener listener);
- void showGlobalActions();
-
/**
* Set whether the top app currently hides the statusbar.
*
@@ -98,23 +94,4 @@
* @param rotation rotation suggestion
*/
void onProposedRotationChanged(int rotation, boolean isValid);
-
- public interface GlobalActionsListener {
- /**
- * Called when sysui starts and connects its status bar, or when the status bar binder
- * dies indicating sysui is no longer alive.
- */
- void onStatusBarConnectedChanged(boolean connected);
-
- /**
- * Callback from sysui to notify system that global actions has been successfully shown.
- */
- void onGlobalActionsShown();
-
- /**
- * Callback from sysui to notify system that the user has dismissed global actions and
- * it no longer needs to be displayed (even if sysui dies).
- */
- void onGlobalActionsDismissed();
- }
}
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
index 343fb91..59fce64 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
@@ -47,8 +47,8 @@
import com.android.internal.util.DumpUtils;
import com.android.server.LocalServices;
import com.android.server.notification.NotificationDelegate;
+import com.android.server.policy.GlobalActionsProvider;
import com.android.server.power.ShutdownThread;
-import com.android.server.statusbar.StatusBarManagerInternal.GlobalActionsListener;
import com.android.server.wm.WindowManagerService;
import java.io.FileDescriptor;
@@ -74,7 +74,7 @@
// for disabling the status bar
private final ArrayList<DisableRecord> mDisableRecords = new ArrayList<DisableRecord>();
- private GlobalActionsListener mGlobalActionListener;
+ private GlobalActionsProvider.GlobalActionsListener mGlobalActionListener;
private IBinder mSysUiVisToken = new Binder();
private int mDisabled1 = 0;
private int mDisabled2 = 0;
@@ -162,6 +162,7 @@
mWindowManager = windowManager;
LocalServices.addService(StatusBarManagerInternal.class, mInternalService);
+ LocalServices.addService(GlobalActionsProvider.class, mGlobalActionsProvider);
}
/**
@@ -375,26 +376,6 @@
}
@Override
- public boolean isGlobalActionsDisabled() {
- return (mDisabled2 & DISABLE2_GLOBAL_ACTIONS) != 0;
- }
-
- @Override
- public void setGlobalActionsListener(GlobalActionsListener listener) {
- mGlobalActionListener = listener;
- mGlobalActionListener.onStatusBarConnectedChanged(mBar != null);
- }
-
- @Override
- public void showGlobalActions() {
- if (mBar != null) {
- try {
- mBar.showGlobalActionsMenu();
- } catch (RemoteException ex) {}
- }
- }
-
- @Override
public void setTopAppHidesStatusBar(boolean hidesStatusBar) {
if (mBar != null) {
try {
@@ -427,6 +408,28 @@
}
};
+ private final GlobalActionsProvider mGlobalActionsProvider = new GlobalActionsProvider() {
+ @Override
+ public boolean isGlobalActionsDisabled() {
+ return (mDisabled2 & DISABLE2_GLOBAL_ACTIONS) != 0;
+ }
+
+ @Override
+ public void setGlobalActionsListener(GlobalActionsProvider.GlobalActionsListener listener) {
+ mGlobalActionListener = listener;
+ mGlobalActionListener.onGlobalActionsAvailableChanged(mBar != null);
+ }
+
+ @Override
+ public void showGlobalActions() {
+ if (mBar != null) {
+ try {
+ mBar.showGlobalActionsMenu();
+ } catch (RemoteException ex) {}
+ }
+ }
+ };
+
// ================================================================================
// From IStatusBarService
// ================================================================================
@@ -892,7 +895,7 @@
private void notifyBarAttachChanged() {
mHandler.post(() -> {
if (mGlobalActionListener == null) return;
- mGlobalActionListener.onStatusBarConnectedChanged(mBar != null);
+ mGlobalActionListener.onGlobalActionsAvailableChanged(mBar != null);
});
}
diff --git a/services/core/java/com/android/server/wm/Session.java b/services/core/java/com/android/server/wm/Session.java
index 2c3c5d2..94b8518 100644
--- a/services/core/java/com/android/server/wm/Session.java
+++ b/services/core/java/com/android/server/wm/Session.java
@@ -509,14 +509,10 @@
// on-going notification for the user to control their visibility.
if (visible) {
changed = mAlertWindowSurfaces.add(surfaceController);
- if (changed) {
- MetricsLoggerWrapper.logAppOverlayEnter(mUid, mPackageName, true);
- }
+ MetricsLoggerWrapper.logAppOverlayEnter(mUid, mPackageName, changed, type, true);
} else {
changed = mAlertWindowSurfaces.remove(surfaceController);
- if (changed) {
- MetricsLoggerWrapper.logAppOverlayExit(mUid, mPackageName, true);
- }
+ MetricsLoggerWrapper.logAppOverlayExit(mUid, mPackageName, changed, type, true);
}
if (changed) {
@@ -537,14 +533,10 @@
if (visible) {
changed = mAppOverlaySurfaces.add(surfaceController);
- if (changed) {
- MetricsLoggerWrapper.logAppOverlayEnter(mUid, mPackageName, false);
- }
+ MetricsLoggerWrapper.logAppOverlayEnter(mUid, mPackageName, changed, type, false);
} else {
changed = mAppOverlaySurfaces.remove(surfaceController);
- if (changed) {
- MetricsLoggerWrapper.logAppOverlayExit(mUid, mPackageName, false);
- }
+ MetricsLoggerWrapper.logAppOverlayExit(mUid, mPackageName, changed, type, false);
}
if (changed) {
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 0c6429a..78c04e8 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -5922,6 +5922,18 @@
}
}
+ public void setNavBarVirtualKeyHapticFeedbackEnabled(boolean enabled) {
+ if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.STATUS_BAR)
+ != PackageManager.PERMISSION_GRANTED) {
+ throw new SecurityException("Caller does not hold permission "
+ + android.Manifest.permission.STATUS_BAR);
+ }
+
+ synchronized (mWindowMap) {
+ mPolicy.setNavBarVirtualKeyHapticFeedbackEnabledLw(enabled);
+ }
+ }
+
// TODO(multidisplay): StatusBar on multiple screens?
private boolean updateStatusBarVisibilityLocked(int visibility) {
if (mLastDispatchedSystemUiVisibility == visibility) {
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 2f6a6e0..6259926 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -206,6 +206,8 @@
"com.google.android.clockwork.lefty.WearLeftyService";
private static final String WEAR_TIME_SERVICE_CLASS =
"com.google.android.clockwork.time.WearTimeService";
+ private static final String WEAR_GLOBAL_ACTIONS_SERVICE_CLASS =
+ "com.android.clockwork.globalactions.GlobalActionsService";
private static final String ACCOUNT_SERVICE_CLASS =
"com.android.server.accounts.AccountManagerService$Lifecycle";
private static final String CONTENT_SERVICE_CLASS =
@@ -1547,6 +1549,10 @@
mSystemServiceManager.startService(WEAR_LEFTY_SERVICE_CLASS);
traceEnd();
}
+
+ traceBeginAndSlog("StartWearGlobalActionsService");
+ mSystemServiceManager.startService(WEAR_GLOBAL_ACTIONS_SERVICE_CLASS);
+ traceEnd();
}
if (!disableSlices) {
diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityRecordTests.java b/services/tests/servicestests/src/com/android/server/am/ActivityRecordTests.java
index f2f1b10..5b1f5c1 100644
--- a/services/tests/servicestests/src/com/android/server/am/ActivityRecordTests.java
+++ b/services/tests/servicestests/src/com/android/server/am/ActivityRecordTests.java
@@ -24,7 +24,9 @@
import static com.android.server.am.ActivityStack.ActivityState.DESTROYED;
import static com.android.server.am.ActivityStack.ActivityState.DESTROYING;
+import static com.android.server.am.ActivityStack.ActivityState.FINISHING;
import static com.android.server.am.ActivityStack.ActivityState.INITIALIZING;
+import static com.android.server.am.ActivityStack.ActivityState.PAUSED;
import static com.android.server.am.ActivityStack.ActivityState.PAUSING;
import static com.android.server.am.ActivityStack.ActivityState.STOPPED;
import static com.android.server.am.ActivityStack.REMOVE_TASK_MODE_MOVING;
@@ -135,6 +137,16 @@
mActivity.makeVisibleIfNeeded(null /* starting */);
assertTrue(mActivity.isState(INITIALIZING));
+
+ // Make sure the state does not change if we are not the current top activity.
+ mActivity.setState(STOPPED, "testPausingWhenVisibleFromStopped behind");
+
+ // Make sure that the state does not change when we have an activity becoming translucent
+ final ActivityRecord topActivity = new ActivityBuilder(mService).setTask(mTask).build();
+ mStack.mTranslucentActivityWaiting = topActivity;
+ mActivity.makeVisibleIfNeeded(null /* starting */);
+
+ assertTrue(mActivity.isState(STOPPED));
}
@Test
@@ -218,4 +230,19 @@
assertTrue(mActivity.isState(DESTROYED));
assertTrue(mActivity.finishing);
}
+
+ @Test
+ public void testSetInvalidState() throws Exception {
+ mActivity.setState(DESTROYED, "testInvalidState");
+
+ boolean exceptionEncountered = false;
+
+ try {
+ mActivity.setState(FINISHING, "testInvalidState");
+ } catch (IllegalArgumentException e) {
+ exceptionEncountered = true;
+ }
+
+ assertTrue(exceptionEncountered);
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityStackTests.java b/services/tests/servicestests/src/com/android/server/am/ActivityStackTests.java
index a98d5a1..32a29a2 100644
--- a/services/tests/servicestests/src/com/android/server/am/ActivityStackTests.java
+++ b/services/tests/servicestests/src/com/android/server/am/ActivityStackTests.java
@@ -24,6 +24,8 @@
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
+import static com.android.server.am.ActivityStack.ActivityState.DESTROYED;
+import static com.android.server.am.ActivityStack.ActivityState.DESTROYING;
import static com.android.server.am.ActivityStack.REMOVE_TASK_MODE_DESTROYING;
import static org.junit.Assert.assertEquals;
@@ -31,8 +33,13 @@
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
-import android.content.ComponentName;
+import android.app.servertransaction.DestroyActivityItem;
import android.content.pm.ActivityInfo;
import android.os.UserHandle;
import android.platform.test.annotations.Presubmit;
@@ -457,4 +464,26 @@
.setCreateTask(true).build();
return stack;
}
+
+ @Test
+ public void testSuppressMultipleDestroy() throws Exception {
+ final ActivityRecord r = new ActivityBuilder(mService).setTask(mTask).build();
+ final ClientLifecycleManager lifecycleManager = mock(ClientLifecycleManager.class);
+ final ProcessRecord app = r.app;
+
+ // The mocked lifecycle manager must be set on the ActivityStackSupervisor's reference to
+ // the service rather than mService as mService is a spy and setting the value will not
+ // propagate as ActivityManagerService hands its own reference to the
+ // ActivityStackSupervisor during construction.
+ ((TestActivityManagerService) mSupervisor.mService).setLifecycleManager(lifecycleManager);
+
+ mStack.destroyActivityLocked(r, true, "first invocation");
+ verify(lifecycleManager, times(1)).scheduleTransaction(eq(app.thread),
+ eq(r.appToken), any(DestroyActivityItem.class));
+ assertTrue(r.isState(DESTROYED, DESTROYING));
+
+ mStack.destroyActivityLocked(r, true, "second invocation");
+ verify(lifecycleManager, times(1)).scheduleTransaction(eq(app.thread),
+ eq(r.appToken), any(DestroyActivityItem.class));
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java b/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java
index 10253c5..ff7b1d0 100644
--- a/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java
+++ b/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java
@@ -273,6 +273,8 @@
* {@link ActivityStackSupervisor}.
*/
protected static class TestActivityManagerService extends ActivityManagerService {
+ private ClientLifecycleManager mLifecycleManager;
+
TestActivityManagerService(Context context) {
super(context);
mSupportsMultiWindow = true;
@@ -284,6 +286,18 @@
}
@Override
+ public ClientLifecycleManager getLifecycleManager() {
+ if (mLifecycleManager == null) {
+ return super.getLifecycleManager();
+ }
+ return mLifecycleManager;
+ }
+
+ void setLifecycleManager(ClientLifecycleManager manager) {
+ mLifecycleManager = manager;
+ }
+
+ @Override
final protected ActivityStackSupervisor createStackSupervisor() {
final ActivityStackSupervisor supervisor = spy(createTestSupervisor());
diff --git a/services/tests/servicestests/src/com/android/server/am/MemoryStatUtilTest.java b/services/tests/servicestests/src/com/android/server/am/MemoryStatUtilTest.java
index a7e3810..8005bc7 100644
--- a/services/tests/servicestests/src/com/android/server/am/MemoryStatUtilTest.java
+++ b/services/tests/servicestests/src/com/android/server/am/MemoryStatUtilTest.java
@@ -16,10 +16,11 @@
package com.android.server.am;
-import static com.android.server.am.MemoryStatUtil.parseMemoryStat;
+import static com.android.server.am.MemoryStatUtil.parseMemoryStatFromMemcg;
import static com.android.server.am.MemoryStatUtil.MemoryStat;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
@@ -31,44 +32,44 @@
@SmallTest
public class MemoryStatUtilTest {
private String MEMORY_STAT_CONTENTS = String.join(
- "\n",
- "cache 96", // keep different from total_cache to catch reading wrong value
- "rss 97", // keep different from total_rss to catch reading wrong value
- "rss_huge 0",
- "mapped_file 524288",
- "writeback 0",
- "swap 95", // keep different from total_rss to catch reading wrong value
- "pgpgin 16717",
- "pgpgout 5037",
- "pgfault 99", // keep different from total_pgfault to catch reading wrong value
- "pgmajfault 98", // keep different from total_pgmajfault to catch reading wrong value
- "inactive_anon 503808",
- "active_anon 46309376",
- "inactive_file 876544",
- "active_file 81920",
- "unevictable 0",
- "hierarchical_memory_limit 18446744073709551615",
- "hierarchical_memsw_limit 18446744073709551615",
- "total_cache 4",
- "total_rss 3",
- "total_rss_huge 0",
- "total_mapped_file 524288",
- "total_writeback 0",
- "total_swap 5",
- "total_pgpgin 16717",
- "total_pgpgout 5037",
- "total_pgfault 1",
- "total_pgmajfault 2",
- "total_inactive_anon 503808",
- "total_active_anon 46309376",
- "total_inactive_file 876544",
- "total_active_file 81920",
- "total_unevictable 0");
+ "\n",
+ "cache 96", // keep different from total_cache to catch reading wrong value
+ "rss 97", // keep different from total_rss to catch reading wrong value
+ "rss_huge 0",
+ "mapped_file 524288",
+ "writeback 0",
+ "swap 95", // keep different from total_rss to catch reading wrong value
+ "pgpgin 16717",
+ "pgpgout 5037",
+ "pgfault 99", // keep different from total_pgfault to catch reading wrong value
+ "pgmajfault 98", // keep different from total_pgmajfault to catch reading wrong value
+ "inactive_anon 503808",
+ "active_anon 46309376",
+ "inactive_file 876544",
+ "active_file 81920",
+ "unevictable 0",
+ "hierarchical_memory_limit 18446744073709551615",
+ "hierarchical_memsw_limit 18446744073709551615",
+ "total_cache 4",
+ "total_rss 3",
+ "total_rss_huge 0",
+ "total_mapped_file 524288",
+ "total_writeback 0",
+ "total_swap 5",
+ "total_pgpgin 16717",
+ "total_pgpgout 5037",
+ "total_pgfault 1",
+ "total_pgmajfault 2",
+ "total_inactive_anon 503808",
+ "total_active_anon 46309376",
+ "total_inactive_file 876544",
+ "total_active_file 81920",
+ "total_unevictable 0");
@Test
public void testParseMemoryStat_parsesCorrectValues() throws Exception {
- MemoryStat stat = parseMemoryStat(MEMORY_STAT_CONTENTS);
+ MemoryStat stat = parseMemoryStatFromMemcg(MEMORY_STAT_CONTENTS);
assertEquals(stat.pgfault, 1);
assertEquals(stat.pgmajfault, 2);
assertEquals(stat.rssInBytes, 3);
@@ -78,18 +79,10 @@
@Test
public void testParseMemoryStat_emptyMemoryStatContents() throws Exception {
- MemoryStat stat = parseMemoryStat("");
- assertEquals(stat.pgfault, 0);
- assertEquals(stat.pgmajfault, 0);
- assertEquals(stat.rssInBytes, 0);
- assertEquals(stat.cacheInBytes, 0);
- assertEquals(stat.swapInBytes, 0);
+ MemoryStat stat = parseMemoryStatFromMemcg("");
+ assertNull(stat);
- stat = parseMemoryStat(null);
- assertEquals(stat.pgfault, 0);
- assertEquals(stat.pgmajfault, 0);
- assertEquals(stat.rssInBytes, 0);
- assertEquals(stat.cacheInBytes, 0);
- assertEquals(stat.swapInBytes, 0);
+ stat = parseMemoryStatFromMemcg(null);
+ assertNull(stat);
}
}
diff --git a/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java b/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java
index 206ee7a..34c5db3 100644
--- a/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java
+++ b/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java
@@ -637,6 +637,10 @@
}
@Override
+ public void setNavBarVirtualKeyHapticFeedbackEnabledLw(boolean enabled) {
+ }
+
+ @Override
public void onSystemUiStarted() {
}
diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java
index 69b2c63..a302578 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsService.java
@@ -465,6 +465,23 @@
}
}
+ /**
+ * Called by the Binder stub.
+ */
+ UsageEvents queryEventsForPackage(int userId, long beginTime, long endTime,
+ String packageName) {
+ synchronized (mLock) {
+ final long timeNow = checkAndGetTimeLocked();
+ if (!validRange(timeNow, beginTime, endTime)) {
+ return null;
+ }
+
+ final UserUsageStatsService service =
+ getUserDataAndInitializeIfNeededLocked(userId, timeNow);
+ return service.queryEventsForPackage(beginTime, endTime, packageName);
+ }
+ }
+
private static boolean validRange(long currentTime, long beginTime, long endTime) {
return beginTime <= currentTime && beginTime < endTime;
}
@@ -661,6 +678,26 @@
}
@Override
+ public UsageEvents queryEventsForPackage(long beginTime, long endTime,
+ String callingPackage) {
+ final int callingUid = Binder.getCallingUid();
+ final int callingUserId = UserHandle.getUserId(callingUid);
+
+ if (mPackageManagerInternal.getPackageUid(callingPackage, PackageManager.MATCH_ANY_USER,
+ callingUserId) != callingUid) {
+ throw new SecurityException("Calling uid " + callingPackage + " cannot query events"
+ + "for package " + callingPackage);
+ }
+ final long token = Binder.clearCallingIdentity();
+ try {
+ return UsageStatsService.this.queryEventsForPackage(callingUserId, beginTime,
+ endTime, callingPackage);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
+ @Override
public boolean isAppInactive(String packageName, int userId) {
try {
userId = ActivityManager.getService().handleIncomingUser(Binder.getCallingPid(),
diff --git a/services/usage/java/com/android/server/usage/UserUsageStatsService.java b/services/usage/java/com/android/server/usage/UserUsageStatsService.java
index 7f060b3..29c5ee8 100644
--- a/services/usage/java/com/android/server/usage/UserUsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UserUsageStatsService.java
@@ -355,6 +355,47 @@
return new UsageEvents(results, table);
}
+ UsageEvents queryEventsForPackage(final long beginTime, final long endTime,
+ final String packageName) {
+ final ArraySet<String> names = new ArraySet<>();
+ names.add(packageName);
+ final List<UsageEvents.Event> results = queryStats(UsageStatsManager.INTERVAL_DAILY,
+ beginTime, endTime, (stats, mutable, accumulatedResult) -> {
+ if (stats.events == null) {
+ return;
+ }
+
+ final int startIndex = stats.events.closestIndexOnOrAfter(beginTime);
+ if (startIndex < 0) {
+ return;
+ }
+
+ final int size = stats.events.size();
+ for (int i = startIndex; i < size; i++) {
+ if (stats.events.keyAt(i) >= endTime) {
+ return;
+ }
+
+ final UsageEvents.Event event = stats.events.valueAt(i);
+ if (!packageName.equals(event.mPackage)) {
+ continue;
+ }
+ if (event.mClass != null) {
+ names.add(event.mClass);
+ }
+ accumulatedResult.add(event);
+ }
+ });
+
+ if (results == null || results.isEmpty()) {
+ return null;
+ }
+
+ final String[] table = names.toArray(new String[names.size()]);
+ Arrays.sort(table);
+ return new UsageEvents(results, table);
+ }
+
void persistActiveStats() {
if (mStatsChanged) {
Slog.i(TAG, mLogPrefix + "Flushing usage stats to disk");
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 96eb23d..f0c120b 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -1000,8 +1000,13 @@
"wfc_emergency_address_carrier_app_string";
/**
- * Boolean to decide whether to use #KEY_CARRIER_NAME_STRING from CarrierConfig app.
- * @hide
+ * Unconditionally override the carrier name string using #KEY_CARRIER_NAME_STRING.
+ *
+ * If true, then the carrier display name will be #KEY_CARRIER_NAME_STRING, unconditionally.
+ *
+ * <p>If false, then the override will be performed conditionally and the
+ * #KEY_CARRIER_NAME_STRING will have the lowest-precedence; it will only be used in the event
+ * that the name string would otherwise be empty, allowing it to serve as a last-resort.
*/
public static final String KEY_CARRIER_NAME_OVERRIDE_BOOL = "carrier_name_override_bool";
@@ -1009,7 +1014,6 @@
* String to identify carrier name in CarrierConfig app. This string overrides SPN if
* #KEY_CARRIER_NAME_OVERRIDE_BOOL is true; otherwise, it will be used if its value is provided
* and SPN is unavailable
- * @hide
*/
public static final String KEY_CARRIER_NAME_STRING = "carrier_name_string";
@@ -1575,6 +1579,14 @@
"notify_international_call_on_wfc_bool";
/**
+ * Flag specifying whether to show an alert dialog for video call charges.
+ * By default this value is {@code false}.
+ * @hide
+ */
+ public static final String KEY_SHOW_VIDEO_CALL_CHARGES_ALERT_DIALOG_BOOL =
+ "show_video_call_charges_alert_dialog_bool";
+
+ /**
* An array containing custom call forwarding number prefixes that will be blocked while the
* device is reporting that it is roaming. By default, there are no custom call
* forwarding prefixes and none of these numbers will be filtered. If one or more entries are
@@ -2119,6 +2131,7 @@
sDefaults.putBoolean(KEY_DISPLAY_VOICEMAIL_NUMBER_AS_DEFAULT_CALL_FORWARDING_NUMBER_BOOL,
false);
sDefaults.putBoolean(KEY_NOTIFY_INTERNATIONAL_CALL_ON_WFC_BOOL, false);
+ sDefaults.putBoolean(KEY_SHOW_VIDEO_CALL_CHARGES_ALERT_DIALOG_BOOL, false);
sDefaults.putStringArray(KEY_CALL_FORWARDING_BLOCKS_WHILE_ROAMING_STRING_ARRAY,
null);
sDefaults.putInt(KEY_LTE_EARFCNS_RSRP_BOOST_INT, 0);
diff --git a/telephony/java/android/telephony/CellIdentityCdma.java b/telephony/java/android/telephony/CellIdentityCdma.java
index 2e1d1dc..105ddb0 100644
--- a/telephony/java/android/telephony/CellIdentityCdma.java
+++ b/telephony/java/android/telephony/CellIdentityCdma.java
@@ -103,8 +103,12 @@
mNetworkId = nid;
mSystemId = sid;
mBasestationId = bid;
- mLongitude = lon;
- mLatitude = lat;
+ if (!isNullIsland(lat, lon)) {
+ mLongitude = lon;
+ mLatitude = lat;
+ } else {
+ mLongitude = mLatitude = Integer.MAX_VALUE;
+ }
mAlphaLong = alphal;
mAlphaShort = alphas;
}
@@ -119,6 +123,18 @@
}
/**
+ * Take the latitude and longitude in 1/4 seconds and see if
+ * the reported location is on Null Island.
+ *
+ * @return whether the reported Lat/Long are for Null Island
+ *
+ * @hide
+ */
+ private boolean isNullIsland(int lat, int lon) {
+ return Math.abs(lat) <= 1 && Math.abs(lon) <= 1;
+ }
+
+ /**
* @return Network Id 0..65535, Integer.MAX_VALUE if unknown
*/
public int getNetworkId() {
diff --git a/telephony/java/android/telephony/CellIdentityGsm.java b/telephony/java/android/telephony/CellIdentityGsm.java
index f948f81..d35eb60 100644
--- a/telephony/java/android/telephony/CellIdentityGsm.java
+++ b/telephony/java/android/telephony/CellIdentityGsm.java
@@ -120,7 +120,7 @@
/**
* @return 3-digit Mobile Country Code, 0..999, Integer.MAX_VALUE if unknown
- * @deprecated Use {@link #getMccStr} instead.
+ * @deprecated Use {@link #getMccString} instead.
*/
@Deprecated
public int getMcc() {
@@ -129,7 +129,7 @@
/**
* @return 2 or 3-digit Mobile Network Code, 0..999, Integer.MAX_VALUE if unknown
- * @deprecated Use {@link #getMncStr} instead.
+ * @deprecated Use {@link #getMncString} instead.
*/
@Deprecated
public int getMnc() {
@@ -176,14 +176,14 @@
/**
* @return Mobile Country Code in string format, null if unknown
*/
- public String getMccStr() {
+ public String getMccString() {
return mMccStr;
}
/**
* @return Mobile Network Code in string format, null if unknown
*/
- public String getMncStr() {
+ public String getMncString() {
return mMncStr;
}
diff --git a/telephony/java/android/telephony/CellIdentityLte.java b/telephony/java/android/telephony/CellIdentityLte.java
index 5f1f448..2b8eb5f 100644
--- a/telephony/java/android/telephony/CellIdentityLte.java
+++ b/telephony/java/android/telephony/CellIdentityLte.java
@@ -125,7 +125,7 @@
/**
* @return 3-digit Mobile Country Code, 0..999, Integer.MAX_VALUE if unknown
- * @deprecated Use {@link #getMccStr} instead.
+ * @deprecated Use {@link #getMccString} instead.
*/
@Deprecated
public int getMcc() {
@@ -134,7 +134,7 @@
/**
* @return 2 or 3-digit Mobile Network Code, 0..999, Integer.MAX_VALUE if unknown
- * @deprecated Use {@link #getMncStr} instead.
+ * @deprecated Use {@link #getMncString} instead.
*/
@Deprecated
public int getMnc() {
@@ -179,14 +179,14 @@
/**
* @return Mobile Country Code in string format, null if unknown
*/
- public String getMccStr() {
+ public String getMccString() {
return mMccStr;
}
/**
* @return Mobile Network Code in string format, null if unknown
*/
- public String getMncStr() {
+ public String getMncString() {
return mMncStr;
}
diff --git a/telephony/java/android/telephony/CellIdentityTdscdma.java b/telephony/java/android/telephony/CellIdentityTdscdma.java
index 001d19f..992545d 100644
--- a/telephony/java/android/telephony/CellIdentityTdscdma.java
+++ b/telephony/java/android/telephony/CellIdentityTdscdma.java
@@ -86,7 +86,7 @@
* Get Mobile Country Code in string format
* @return Mobile Country Code in string format, null if unknown
*/
- public String getMccStr() {
+ public String getMccString() {
return mMccStr;
}
@@ -94,7 +94,7 @@
* Get Mobile Network Code in string format
* @return Mobile Network Code in string format, null if unknown
*/
- public String getMncStr() {
+ public String getMncString() {
return mMncStr;
}
diff --git a/telephony/java/android/telephony/CellIdentityWcdma.java b/telephony/java/android/telephony/CellIdentityWcdma.java
index 1aa1715..a5fd7dd 100644
--- a/telephony/java/android/telephony/CellIdentityWcdma.java
+++ b/telephony/java/android/telephony/CellIdentityWcdma.java
@@ -118,7 +118,7 @@
/**
* @return 3-digit Mobile Country Code, 0..999, Integer.MAX_VALUE if unknown
- * @deprecated Use {@link #getMccStr} instead.
+ * @deprecated Use {@link #getMccString} instead.
*/
@Deprecated
public int getMcc() {
@@ -127,7 +127,7 @@
/**
* @return 2 or 3-digit Mobile Network Code, 0..999, Integer.MAX_VALUE if unknown
- * @deprecated Use {@link #getMncStr} instead.
+ * @deprecated Use {@link #getMncString} instead.
*/
@Deprecated
public int getMnc() {
@@ -160,14 +160,14 @@
/**
* @return Mobile Country Code in string version, null if unknown
*/
- public String getMccStr() {
+ public String getMccString() {
return mMccStr;
}
/**
* @return Mobile Network Code in string version, null if unknown
*/
- public String getMncStr() {
+ public String getMncString() {
return mMncStr;
}
diff --git a/telephony/java/android/telephony/CellSignalStrengthCdma.java b/telephony/java/android/telephony/CellSignalStrengthCdma.java
index ece1ee3..183f96d 100644
--- a/telephony/java/android/telephony/CellSignalStrengthCdma.java
+++ b/telephony/java/android/telephony/CellSignalStrengthCdma.java
@@ -41,14 +41,36 @@
setDefaultValues();
}
- /** @hide */
+ /**
+ * SignalStrength constructor for input from the HAL.
+ *
+ * Note that values received from the HAL require coersion to be compatible here. All values
+ * reported through IRadio are the negative of the actual values (which results in a positive
+ * input to this method.
+ *
+ * <p>Note that this HAL is inconsistent with UMTS-based radio techs as the value indicating
+ * that a field is unreported is negative, rather than a large(r) positive number.
+ * <p>Also note that to keep the public-facing methods of this class consistent with others,
+ * unreported values are coerced to Integer.MAX_VALUE rather than left as -1, which is
+ * a departure from SignalStrength, which is stuck with the values it currently reports.
+ *
+ * @param cdmaDbm negative of the CDMA signal strength value or -1 if invalid.
+ * @param cdmaEcio negative of the CDMA pilot/noise ratio or -1 if invalid.
+ * @param evdoDbm negative of the EvDO signal strength value or -1 if invalid.
+ * @param evdoEcio negative of the EvDO pilot/noise ratio or -1 if invalid.
+ * @param evdoSnr an SNR value 0..8 or -1 if invalid.
+ * @hide
+ */
public CellSignalStrengthCdma(int cdmaDbm, int cdmaEcio, int evdoDbm, int evdoEcio,
int evdoSnr) {
- mCdmaDbm = cdmaDbm;
- mCdmaEcio = cdmaEcio;
- mEvdoDbm = evdoDbm;
- mEvdoEcio = evdoEcio;
- mEvdoSnr = evdoSnr;
+ // The values here were lifted from SignalStrength.validateInput()
+ // FIXME: Combine all checking and setting logic between this and SignalStrength.
+ mCdmaDbm = ((cdmaDbm > 0) && (cdmaDbm < 120)) ? -cdmaDbm : Integer.MAX_VALUE;
+ mCdmaEcio = ((cdmaEcio > 0) && (cdmaEcio < 160)) ? -cdmaEcio : Integer.MAX_VALUE;
+
+ mEvdoDbm = ((evdoDbm > 0) && (evdoDbm < 120)) ? -evdoDbm : Integer.MAX_VALUE;
+ mEvdoEcio = ((evdoEcio > 0) && (evdoEcio < 160)) ? -evdoEcio : Integer.MAX_VALUE;
+ mEvdoSnr = ((evdoSnr > 0) && (evdoSnr <= 8)) ? evdoSnr : Integer.MAX_VALUE;
}
/** @hide */
@@ -303,13 +325,10 @@
@Override
public void writeToParcel(Parcel dest, int flags) {
if (DBG) log("writeToParcel(Parcel, int): " + toString());
- // Need to multiply CdmaDbm, CdmaEcio, EvdoDbm and EvdoEcio by -1
- // to ensure consistency when reading values written here
- // unless the value is invalid
- dest.writeInt(mCdmaDbm * (mCdmaDbm != Integer.MAX_VALUE ? -1 : 1));
- dest.writeInt(mCdmaEcio * (mCdmaEcio != Integer.MAX_VALUE ? -1 : 1));
- dest.writeInt(mEvdoDbm * (mEvdoDbm != Integer.MAX_VALUE ? -1 : 1));
- dest.writeInt(mEvdoEcio * (mEvdoEcio != Integer.MAX_VALUE ? -1 : 1));
+ dest.writeInt(mCdmaDbm);
+ dest.writeInt(mCdmaEcio);
+ dest.writeInt(mEvdoDbm);
+ dest.writeInt(mEvdoEcio);
dest.writeInt(mEvdoSnr);
}
@@ -322,13 +341,9 @@
// the parcel as positive values.
// Need to convert into negative values unless the value is invalid
mCdmaDbm = in.readInt();
- if (mCdmaDbm != Integer.MAX_VALUE) mCdmaDbm *= -1;
mCdmaEcio = in.readInt();
- if (mCdmaEcio != Integer.MAX_VALUE) mCdmaEcio *= -1;
mEvdoDbm = in.readInt();
- if (mEvdoDbm != Integer.MAX_VALUE) mEvdoDbm *= -1;
mEvdoEcio = in.readInt();
- if (mEvdoEcio != Integer.MAX_VALUE) mEvdoEcio *= -1;
mEvdoSnr = in.readInt();
if (DBG) log("CellSignalStrengthCdma(Parcel): " + toString());
}
diff --git a/telephony/java/android/telephony/SignalStrength.java b/telephony/java/android/telephony/SignalStrength.java
index 47a7d5f..5ed5afe 100644
--- a/telephony/java/android/telephony/SignalStrength.java
+++ b/telephony/java/android/telephony/SignalStrength.java
@@ -319,11 +319,11 @@
// BER no change;
mCdmaDbm = mCdmaDbm > 0 ? -mCdmaDbm : -120;
- mCdmaEcio = (mCdmaEcio > 0) ? -mCdmaEcio : -160;
+ mCdmaEcio = (mCdmaEcio >= 0) ? -mCdmaEcio : -160;
mEvdoDbm = (mEvdoDbm > 0) ? -mEvdoDbm : -120;
- mEvdoEcio = (mEvdoEcio >= 0) ? -mEvdoEcio : -1;
- mEvdoSnr = ((mEvdoSnr > 0) && (mEvdoSnr <= 8)) ? mEvdoSnr : -1;
+ mEvdoEcio = (mEvdoEcio >= 0) ? -mEvdoEcio : -160;
+ mEvdoSnr = ((mEvdoSnr >= 0) && (mEvdoSnr <= 8)) ? mEvdoSnr : -1;
// TS 36.214 Physical Layer Section 5.1.3, TS 36.331 RRC
mLteSignalStrength = (mLteSignalStrength >= 0) ? mLteSignalStrength : 99;
diff --git a/tests/net/java/android/net/NetworkCapabilitiesTest.java b/tests/net/java/android/net/NetworkCapabilitiesTest.java
index ec6a5ec..c866371 100644
--- a/tests/net/java/android/net/NetworkCapabilitiesTest.java
+++ b/tests/net/java/android/net/NetworkCapabilitiesTest.java
@@ -17,18 +17,24 @@
package android.net;
import static android.net.NetworkCapabilities.LINK_BANDWIDTH_UNSPECIFIED;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_CAPTIVE_PORTAL;
import static android.net.NetworkCapabilities.NET_CAPABILITY_CBS;
import static android.net.NetworkCapabilities.NET_CAPABILITY_EIMS;
import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_MMS;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED;
import static android.net.NetworkCapabilities.NET_CAPABILITY_OEM_PAID;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VPN;
import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_WIFI_P2P;
import static android.net.NetworkCapabilities.RESTRICTED_CAPABILITIES;
import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
import static android.net.NetworkCapabilities.UNRESTRICTED_CAPABILITIES;
+import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals;
@@ -268,6 +274,120 @@
assertFalse(nc.hasCapability(NET_CAPABILITY_NOT_RESTRICTED));
}
+ @Test
+ public void testUnwantedCapabilities() {
+ NetworkCapabilities network = new NetworkCapabilities();
+
+ NetworkCapabilities request = new NetworkCapabilities();
+ assertTrue("Request: " + request + ", Network:" + network,
+ request.satisfiedByNetworkCapabilities(network));
+
+ // Adding capabilities that doesn't exist in the network anyway
+ request.addUnwantedCapability(NET_CAPABILITY_WIFI_P2P);
+ request.addUnwantedCapability(NET_CAPABILITY_NOT_METERED);
+ assertTrue(request.satisfiedByNetworkCapabilities(network));
+ assertArrayEquals(new int[] {NET_CAPABILITY_WIFI_P2P, NET_CAPABILITY_NOT_METERED},
+ request.getUnwantedCapabilities());
+
+ // This is a default capability, just want to make sure its there because we use it below.
+ assertTrue(network.hasCapability(NET_CAPABILITY_NOT_RESTRICTED));
+
+ // Verify that adding unwanted capability will effectively remove it from capability list.
+ request.addUnwantedCapability(NET_CAPABILITY_NOT_RESTRICTED);
+ assertTrue(request.hasUnwantedCapability(NET_CAPABILITY_NOT_RESTRICTED));
+ assertFalse(request.hasCapability(NET_CAPABILITY_NOT_RESTRICTED));
+
+
+ // Now this request won't be satisfied because network contains NOT_RESTRICTED.
+ assertFalse(request.satisfiedByNetworkCapabilities(network));
+ network.removeCapability(NET_CAPABILITY_NOT_RESTRICTED);
+ assertTrue(request.satisfiedByNetworkCapabilities(network));
+
+ // Verify that adding capability will effectively remove it from unwanted list
+ request.addCapability(NET_CAPABILITY_NOT_RESTRICTED);
+ assertTrue(request.hasCapability(NET_CAPABILITY_NOT_RESTRICTED));
+ assertFalse(request.hasUnwantedCapability(NET_CAPABILITY_NOT_RESTRICTED));
+
+ assertFalse(request.satisfiedByNetworkCapabilities(network));
+ network.addCapability(NET_CAPABILITY_NOT_RESTRICTED);
+ assertTrue(request.satisfiedByNetworkCapabilities(network));
+ }
+
+ @Test
+ public void testEqualsNetCapabilities() {
+ int CAPABILITY = NET_CAPABILITY_MMS; // An arbitrary not mutable capability.
+
+ NetworkCapabilities nc1 = new NetworkCapabilities();
+ NetworkCapabilities nc2 = new NetworkCapabilities();
+ assertTrue(nc1.equalsNetCapabilities(nc2));
+ assertEquals(nc1, nc2);
+
+ nc1.addCapability(CAPABILITY);
+ assertFalse(nc1.equalsNetCapabilities(nc2));
+ assertNotEquals(nc1, nc2);
+ nc2.addCapability(CAPABILITY);
+ assertTrue(nc1.equalsNetCapabilities(nc2));
+ assertEquals(nc1, nc2);
+
+ nc1.addUnwantedCapability(CAPABILITY);
+ assertFalse(nc1.equalsNetCapabilities(nc2));
+ nc2.addUnwantedCapability(CAPABILITY);
+ assertTrue(nc1.equalsNetCapabilities(nc2));
+
+ nc1.removeCapability(CAPABILITY);
+ assertFalse(nc1.equalsNetCapabilities(nc2));
+ nc2.removeCapability(CAPABILITY);
+ assertTrue(nc1.equalsNetCapabilities(nc2));
+ }
+
+ @Test
+ public void testCombineCapabilities() {
+ NetworkCapabilities nc1 = new NetworkCapabilities();
+ NetworkCapabilities nc2 = new NetworkCapabilities();
+
+ nc1.addUnwantedCapability(NET_CAPABILITY_CAPTIVE_PORTAL);
+ nc1.addCapability(NET_CAPABILITY_NOT_ROAMING);
+ assertNotEquals(nc1, nc2);
+ nc2.combineCapabilities(nc1);
+ assertEquals(nc1, nc2);
+ assertTrue(nc2.hasCapability(NET_CAPABILITY_NOT_ROAMING));
+ assertTrue(nc2.hasUnwantedCapability(NET_CAPABILITY_CAPTIVE_PORTAL));
+
+ // This will effectively move NOT_ROAMING capability from required to unwanted for nc1.
+ nc1.addUnwantedCapability(NET_CAPABILITY_NOT_ROAMING);
+
+ nc2.combineCapabilities(nc1);
+ // We will get this capability in both requested and unwanted lists thus this request
+ // will never be satisfied.
+ assertTrue(nc2.hasCapability(NET_CAPABILITY_NOT_ROAMING));
+ assertTrue(nc2.hasUnwantedCapability(NET_CAPABILITY_NOT_ROAMING));
+ }
+
+ @Test
+ public void testSetCapabilities() {
+ final int[] REQUIRED_CAPABILITIES = new int[] {
+ NET_CAPABILITY_INTERNET, NET_CAPABILITY_NOT_VPN };
+ final int[] UNWANTED_CAPABILITIES = new int[] {
+ NET_CAPABILITY_NOT_RESTRICTED, NET_CAPABILITY_NOT_METERED
+ };
+
+ NetworkCapabilities nc1 = new NetworkCapabilities();
+ NetworkCapabilities nc2 = new NetworkCapabilities();
+
+ nc1.setCapabilities(REQUIRED_CAPABILITIES, UNWANTED_CAPABILITIES);
+ assertArrayEquals(REQUIRED_CAPABILITIES, nc1.getCapabilities());
+
+ // Verify that setting and adding capabilities leads to the same object state.
+ nc2.clearAll();
+ for (int cap : REQUIRED_CAPABILITIES) {
+ nc2.addCapability(cap);
+ }
+ for (int cap : UNWANTED_CAPABILITIES) {
+ nc2.addUnwantedCapability(cap);
+ }
+ assertEquals(nc1, nc2);
+ }
+
private void assertEqualsThroughMarshalling(NetworkCapabilities netCap) {
Parcel p = Parcel.obtain();
netCap.writeToParcel(p, /* flags */ 0);
diff --git a/tools/aapt2/Android.bp b/tools/aapt2/Android.bp
index eb3a99a..2ff92e6 100644
--- a/tools/aapt2/Android.bp
+++ b/tools/aapt2/Android.bp
@@ -101,6 +101,7 @@
"io/ZipArchive.cpp",
"link/AutoVersioner.cpp",
"link/ManifestFixer.cpp",
+ "link/NoDefaultResourceRemover.cpp",
"link/ProductFilter.cpp",
"link/PrivateAttributeMover.cpp",
"link/ReferenceLinker.cpp",
diff --git a/tools/aapt2/OWNERS b/tools/aapt2/OWNERS
index d76233e..23ec5ab 100644
--- a/tools/aapt2/OWNERS
+++ b/tools/aapt2/OWNERS
@@ -1,2 +1,2 @@
set noparent
-adamlesinski@google.com
+toddke@google.com
diff --git a/tools/aapt2/ResourceTable.cpp b/tools/aapt2/ResourceTable.cpp
index 95bf921..d0faac3 100644
--- a/tools/aapt2/ResourceTable.cpp
+++ b/tools/aapt2/ResourceTable.cpp
@@ -162,7 +162,7 @@
const StringPiece& product;
};
-bool ltConfigKeyRef(const std::unique_ptr<ResourceConfigValue>& lhs, const ConfigKey& rhs) {
+bool lt_config_key_ref(const std::unique_ptr<ResourceConfigValue>& lhs, const ConfigKey& rhs) {
int cmp = lhs->config.compare(*rhs.config);
if (cmp == 0) {
cmp = StringPiece(lhs->product).compare(rhs.product);
@@ -172,8 +172,8 @@
ResourceConfigValue* ResourceEntry::FindValue(const ConfigDescription& config,
const StringPiece& product) {
- auto iter =
- std::lower_bound(values.begin(), values.end(), ConfigKey{&config, product}, ltConfigKeyRef);
+ auto iter = std::lower_bound(values.begin(), values.end(), ConfigKey{&config, product},
+ lt_config_key_ref);
if (iter != values.end()) {
ResourceConfigValue* value = iter->get();
if (value->config == config && StringPiece(value->product) == product) {
@@ -185,8 +185,8 @@
ResourceConfigValue* ResourceEntry::FindOrCreateValue(const ConfigDescription& config,
const StringPiece& product) {
- auto iter =
- std::lower_bound(values.begin(), values.end(), ConfigKey{&config, product}, ltConfigKeyRef);
+ auto iter = std::lower_bound(values.begin(), values.end(), ConfigKey{&config, product},
+ lt_config_key_ref);
if (iter != values.end()) {
ResourceConfigValue* value = iter->get();
if (value->config == config && StringPiece(value->product) == product) {
@@ -220,15 +220,16 @@
return results;
}
-std::vector<ResourceConfigValue*> ResourceEntry::FindValuesIf(
- const std::function<bool(ResourceConfigValue*)>& f) {
- std::vector<ResourceConfigValue*> results;
- for (auto& configValue : values) {
- if (f(configValue.get())) {
- results.push_back(configValue.get());
+bool ResourceEntry::HasDefaultValue() const {
+ const ConfigDescription& default_config = ConfigDescription::DefaultConfig();
+
+ // The default config should be at the top of the list, since the list is sorted.
+ for (auto& config_value : values) {
+ if (config_value->config == default_config) {
+ return true;
}
}
- return results;
+ return false;
}
// The default handler for collisions.
diff --git a/tools/aapt2/ResourceTable.h b/tools/aapt2/ResourceTable.h
index 374fe1e..8534eaa 100644
--- a/tools/aapt2/ResourceTable.h
+++ b/tools/aapt2/ResourceTable.h
@@ -104,13 +104,26 @@
explicit ResourceEntry(const android::StringPiece& name) : name(name.to_string()) {}
ResourceConfigValue* FindValue(const ConfigDescription& config);
+
ResourceConfigValue* FindValue(const ConfigDescription& config,
const android::StringPiece& product);
+
ResourceConfigValue* FindOrCreateValue(const ConfigDescription& config,
const android::StringPiece& product);
std::vector<ResourceConfigValue*> FindAllValues(const ConfigDescription& config);
- std::vector<ResourceConfigValue*> FindValuesIf(
- const std::function<bool(ResourceConfigValue*)>& f);
+
+ template <typename Func>
+ std::vector<ResourceConfigValue*> FindValuesIf(Func f) {
+ std::vector<ResourceConfigValue*> results;
+ for (auto& config_value : values) {
+ if (f(config_value.get())) {
+ results.push_back(config_value.get());
+ }
+ }
+ return results;
+ }
+
+ bool HasDefaultValue() const;
private:
DISALLOW_COPY_AND_ASSIGN(ResourceEntry);
diff --git a/tools/aapt2/cmd/Link.cpp b/tools/aapt2/cmd/Link.cpp
index 12ab883..0839f6f 100644
--- a/tools/aapt2/cmd/Link.cpp
+++ b/tools/aapt2/cmd/Link.cpp
@@ -55,6 +55,7 @@
#include "java/ProguardRules.h"
#include "link/Linkers.h"
#include "link/ManifestFixer.h"
+#include "link/NoDefaultResourceRemover.h"
#include "link/ReferenceLinker.h"
#include "link/TableMerger.h"
#include "link/XmlCompatVersioner.h"
@@ -1785,6 +1786,14 @@
util::make_unique<FeatureSplitSymbolTableDelegate>(context_));
}
+ // Before we process anything, remove the resources whose default values don't exist.
+ // We want to force any references to these to fail the build.
+ if (!NoDefaultResourceRemover{}.Consume(context_, &final_table_)) {
+ context_->GetDiagnostics()->Error(DiagMessage()
+ << "failed removing resources with no defaults");
+ return 1;
+ }
+
ReferenceLinker linker;
if (!linker.Consume(context_, &final_table_)) {
context_->GetDiagnostics()->Error(DiagMessage() << "failed linking references");
diff --git a/tools/aapt2/compile/InlineXmlFormatParser.cpp b/tools/aapt2/compile/InlineXmlFormatParser.cpp
index 238e339..79b0933 100644
--- a/tools/aapt2/compile/InlineXmlFormatParser.cpp
+++ b/tools/aapt2/compile/InlineXmlFormatParser.cpp
@@ -65,10 +65,6 @@
}
const ResourceName& name = ref.value().name.value();
-
- // Use an empty string for the compilation package because we don't want to default to
- // the local package if the user specified name="style" or something. This should just
- // be the default namespace.
Maybe<xml::ExtractedPackage> maybe_pkg = TransformPackageAlias(name.package);
if (!maybe_pkg) {
context_->GetDiagnostics()->Error(DiagMessage(src)
@@ -83,8 +79,15 @@
InlineDeclaration decl;
decl.el = el;
decl.attr_name = name.entry;
- if (!pkg.package.empty()) {
- decl.attr_namespace_uri = xml::BuildPackageNamespace(pkg.package, private_namespace);
+
+ // We need to differentiate between no-namespace defined, or the alias resolves to an empty
+ // package, which means we must use the res-auto schema.
+ if (!name.package.empty()) {
+ if (pkg.package.empty()) {
+ decl.attr_namespace_uri = xml::kSchemaAuto;
+ } else {
+ decl.attr_namespace_uri = xml::BuildPackageNamespace(pkg.package, private_namespace);
+ }
}
inline_declarations_.push_back(std::move(decl));
diff --git a/tools/aapt2/compile/InlineXmlFormatParser_test.cpp b/tools/aapt2/compile/InlineXmlFormatParser_test.cpp
index 2b4ab96..ca4e01a 100644
--- a/tools/aapt2/compile/InlineXmlFormatParser_test.cpp
+++ b/tools/aapt2/compile/InlineXmlFormatParser_test.cpp
@@ -184,4 +184,42 @@
// Confirm that all of the nested inline xmls are parsed out.
ASSERT_THAT(parser.GetExtractedInlineXmlDocuments(), SizeIs(8u));
}
+
+TEST(InlineXmlFormatParserTest, ExtractIntoAppAttribute) {
+ std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build();
+ std::unique_ptr<xml::XmlResource> doc = test::BuildXmlDom(R"(
+ <parent xmlns:app="http://schemas.android.com/apk/res-auto"
+ xmlns:aapt="http://schemas.android.com/aapt">
+ <aapt:attr name="app:foo">
+ <child />
+ </aapt:attr>
+ </parent>)");
+
+ doc->file.name = test::ParseNameOrDie("layout/main");
+
+ InlineXmlFormatParser parser;
+ ASSERT_TRUE(parser.Consume(context.get(), doc.get()));
+
+ ASSERT_THAT(doc->root, NotNull());
+ EXPECT_THAT(doc->root->FindAttribute(xml::kSchemaAuto, "foo"), NotNull());
+}
+
+TEST(InlineXmlFormatParserTest, ExtractIntoNoNamespaceAttribute) {
+ std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build();
+ std::unique_ptr<xml::XmlResource> doc = test::BuildXmlDom(R"(
+ <parent xmlns:aapt="http://schemas.android.com/aapt">
+ <aapt:attr name="foo">
+ <child />
+ </aapt:attr>
+ </parent>)");
+
+ doc->file.name = test::ParseNameOrDie("layout/main");
+
+ InlineXmlFormatParser parser;
+ ASSERT_TRUE(parser.Consume(context.get(), doc.get()));
+
+ ASSERT_THAT(doc->root, NotNull());
+ EXPECT_THAT(doc->root->FindAttribute({}, "foo"), NotNull());
+}
+
} // namespace aapt
diff --git a/tools/aapt2/link/NoDefaultResourceRemover.cpp b/tools/aapt2/link/NoDefaultResourceRemover.cpp
new file mode 100644
index 0000000..cfb4b26
--- /dev/null
+++ b/tools/aapt2/link/NoDefaultResourceRemover.cpp
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "link/NoDefaultResourceRemover.h"
+
+#include <algorithm>
+
+#include "ResourceTable.h"
+
+namespace aapt {
+
+static bool IsDefaultConfigRequired(const ConfigDescription& config) {
+ // We don't want to be overzealous with resource removal, so have strict requirements.
+ // If a resource defines a value for a locale-only configuration, the default configuration is
+ // required.
+ if (ConfigDescription::DefaultConfig().diff(config) == ConfigDescription::CONFIG_LOCALE) {
+ return true;
+ }
+ return false;
+}
+
+static bool KeepResource(const std::unique_ptr<ResourceEntry>& entry) {
+ if (entry->visibility.level == Visibility::Level::kPublic) {
+ // Removing a public API without the developer knowing is bad, so just leave this here for now.
+ return true;
+ }
+
+ if (entry->HasDefaultValue()) {
+ // There is a default value, no removal needed.
+ return true;
+ }
+
+ // There is no default value defined, check if removal is required.
+ for (const auto& config_value : entry->values) {
+ if (IsDefaultConfigRequired(config_value->config)) {
+ return false;
+ }
+ }
+ return true;
+}
+
+bool NoDefaultResourceRemover::Consume(IAaptContext* context, ResourceTable* table) {
+ const ConfigDescription default_config = ConfigDescription::DefaultConfig();
+ for (auto& pkg : table->packages) {
+ for (auto& type : pkg->types) {
+ const auto end_iter = type->entries.end();
+ const auto new_end_iter =
+ std::stable_partition(type->entries.begin(), end_iter, KeepResource);
+ for (auto iter = new_end_iter; iter != end_iter; ++iter) {
+ const ResourceName name(pkg->name, type->type, (*iter)->name);
+ IDiagnostics* diag = context->GetDiagnostics();
+ diag->Warn(DiagMessage() << "removing resource " << name
+ << " without required default value");
+ if (context->IsVerbose()) {
+ diag->Note(DiagMessage() << " did you forget to remove all definitions?");
+ for (const auto& config_value : (*iter)->values) {
+ if (config_value->value != nullptr) {
+ diag->Note(DiagMessage(config_value->value->GetSource()) << "defined here");
+ }
+ }
+ }
+ }
+
+ type->entries.erase(new_end_iter, type->entries.end());
+ }
+ }
+ return true;
+}
+
+} // namespace aapt
diff --git a/tools/aapt2/link/NoDefaultResourceRemover.h b/tools/aapt2/link/NoDefaultResourceRemover.h
new file mode 100644
index 0000000..7582ef3
--- /dev/null
+++ b/tools/aapt2/link/NoDefaultResourceRemover.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef AAPT_LINK_NODEFAULTRESOURCEREMOVER_H
+#define AAPT_LINK_NODEFAULTRESOURCEREMOVER_H
+
+#include "android-base/macros.h"
+
+#include "process/IResourceTableConsumer.h"
+
+namespace aapt {
+
+// Removes any resource for which there exists no definition for the default configuration, where
+// for that resource type, a definition is required.
+//
+// The obvious example is when defining localized strings. If a string in the default configuration
+// has its name changed, the translations for that string won't be changed but will still cause
+// the generated R class to contain the old string name. This will cause breakages in apps that
+// still rely on the old name when the translations are updated.
+class NoDefaultResourceRemover : public IResourceTableConsumer {
+ public:
+ NoDefaultResourceRemover() = default;
+
+ bool Consume(IAaptContext* context, ResourceTable* table) override;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(NoDefaultResourceRemover);
+};
+
+} // namespace aapt
+
+#endif // AAPT_LINK_NODEFAULTRESOURCEREMOVER_H
diff --git a/tools/aapt2/link/NoDefaultResourceRemover_test.cpp b/tools/aapt2/link/NoDefaultResourceRemover_test.cpp
new file mode 100644
index 0000000..943709a
--- /dev/null
+++ b/tools/aapt2/link/NoDefaultResourceRemover_test.cpp
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "link/NoDefaultResourceRemover.h"
+
+#include "test/Test.h"
+
+namespace aapt {
+
+TEST(NoDefaultResourceRemoverTest, RemoveEntryWithNoDefaultAndOnlyLocales) {
+ std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build();
+ std::unique_ptr<ResourceTable> table =
+ test::ResourceTableBuilder()
+ .SetPackageId("android", 0x01)
+ .AddSimple("android:string/foo")
+ .AddSimple("android:string/foo", test::ParseConfigOrDie("en-rGB"))
+ .AddSimple("android:string/foo", test::ParseConfigOrDie("fr-rFR"))
+ .AddSimple("android:string/bar", test::ParseConfigOrDie("en-rGB"))
+ .AddSimple("android:string/bar", test::ParseConfigOrDie("fr-rFR"))
+ .AddSimple("android:string/bat", test::ParseConfigOrDie("en-rGB-xhdpi"))
+ .AddSimple("android:string/bat", test::ParseConfigOrDie("fr-rFR-hdpi"))
+ .AddSimple("android:string/baz", test::ParseConfigOrDie("en-rGB"))
+ .AddSimple("android:string/baz", test::ParseConfigOrDie("fr-rFR"))
+ .SetSymbolState("android:string/baz", ResourceId(0x01020002), Visibility::Level::kPublic)
+ .Build();
+
+ NoDefaultResourceRemover remover;
+ ASSERT_TRUE(remover.Consume(context.get(), table.get()));
+
+ EXPECT_TRUE(table->FindResource(test::ParseNameOrDie("android:string/foo")));
+ EXPECT_FALSE(table->FindResource(test::ParseNameOrDie("android:string/bar")));
+ EXPECT_TRUE(table->FindResource(test::ParseNameOrDie("android:string/bat")));
+ EXPECT_TRUE(table->FindResource(test::ParseNameOrDie("android:string/baz")));
+}
+
+} // namespace aapt
diff --git a/tools/aapt2/xml/XmlDom_test.cpp b/tools/aapt2/xml/XmlDom_test.cpp
index 486b53a..ca46d53 100644
--- a/tools/aapt2/xml/XmlDom_test.cpp
+++ b/tools/aapt2/xml/XmlDom_test.cpp
@@ -154,6 +154,12 @@
EXPECT_THAT(TransformPackageAlias("two"), Eq(make_value(ExtractedPackage{"com.two", false})));
EXPECT_THAT(TransformPackageAlias("three"),
Eq(make_value(ExtractedPackage{"com.three", false})));
+ } else if (el->name == "View4") {
+ EXPECT_THAT(TransformPackageAlias("one"), Eq(make_value(ExtractedPackage{"com.one", false})));
+ EXPECT_THAT(TransformPackageAlias("two"), Eq(make_value(ExtractedPackage{"com.two", false})));
+ EXPECT_THAT(TransformPackageAlias("three"),
+ Eq(make_value(ExtractedPackage{"com.three", false})));
+ EXPECT_THAT(TransformPackageAlias("four"), Eq(make_value(ExtractedPackage{"", true})));
}
}
};
@@ -162,7 +168,9 @@
std::unique_ptr<XmlResource> doc = test::BuildXmlDom(R"(
<View1 xmlns:one="http://schemas.android.com/apk/res/com.one">
<View2 xmlns:two="http://schemas.android.com/apk/res/com.two">
- <View3 xmlns:three="http://schemas.android.com/apk/res/com.three" />
+ <View3 xmlns:three="http://schemas.android.com/apk/res/com.three">
+ <View4 xmlns:four="http://schemas.android.com/apk/res-auto" />
+ </View3>
</View2>
</View1>)");
diff --git a/tools/incident_section_gen/main.cpp b/tools/incident_section_gen/main.cpp
index 9183918..e396a63 100644
--- a/tools/incident_section_gen/main.cpp
+++ b/tools/incident_section_gen/main.cpp
@@ -203,6 +203,18 @@
getMessageDest(field->message_type(), fieldDest);
}
+// Converts Destination to a string.
+static inline string getDestString(const Destination dest) {
+ switch (dest) {
+ case DEST_AUTOMATIC: return "AUTOMATIC";
+ case DEST_LOCAL: return "LOCAL";
+ case DEST_EXPLICIT: return "EXPLICIT";
+ // UNSET is considered EXPLICIT by default.
+ case DEST_UNSET: return "EXPLICIT";
+ default: return "UNKNOWN";
+ }
+}
+
// Get Names ===========================================================================================
static inline string getFieldName(const FieldDescriptor* field) {
// replace . with double underscores to avoid name conflicts since fields use snake naming convention
@@ -218,7 +230,7 @@
// IsDefault ============================================================================================
// Returns true if a field is default. Default is defined as this field has same dest as its containing message.
-// For message fields, it only looks at its field tag and own default mesaage tag, doesn't recursively go deeper.
+// For message fields, it only looks at its field tag and own default message tag, doesn't recursively go deeper.
static inline bool isDefaultField(const FieldDescriptor* field, const Destination containerDest) {
Destination fieldDest = getFieldDest(field);
if (field->type() != FieldDescriptor::TYPE_MESSAGE) {
@@ -503,11 +515,12 @@
return result;
}
-static void generateCsv(Descriptor const* descriptor, const string& indent, set<string>* parents) {
+static void generateCsv(Descriptor const* descriptor, const string& indent, set<string>* parents, const Destination containerDest = DEST_UNSET) {
DebugStringOptions options;
options.include_comments = true;
for (int i=0; i<descriptor->field_count(); i++) {
const FieldDescriptor* field = descriptor->field(i);
+ const Destination fieldDest = getFieldDest(field);
stringstream text;
if (field->type() == FieldDescriptor::TYPE_MESSAGE) {
text << field->message_type()->name();
@@ -515,11 +528,18 @@
text << field->type_name();
}
text << " " << field->name();
+ text << " (PRIVACY=";
+ if (isDefaultField(field, containerDest)) {
+ text << getDestString(containerDest);
+ } else {
+ text << getDestString(fieldDest);
+ }
+ text << ")";
printf("%s%s,\n", indent.c_str(), replace_string(text.str(), '\n', ' ').c_str());
if (field->type() == FieldDescriptor::TYPE_MESSAGE &&
parents->find(field->message_type()->full_name()) == parents->end()) {
parents->insert(field->message_type()->full_name());
- generateCsv(field->message_type(), indent + ",", parents);
+ generateCsv(field->message_type(), indent + ",", parents, fieldDest);
parents->erase(field->message_type()->full_name());
}
}
@@ -548,7 +568,7 @@
|| field->number() == sectionId) {
set<string> parents;
printf("%s\n", field->name().c_str());
- generateCsv(field->message_type(), "", &parents);
+ generateCsv(field->message_type(), "", &parents, getFieldDest(field));
break;
}
}